SQL:如何在 sql 中找到每组的最小值?
Posted
技术标签:
【中文标题】SQL:如何在 sql 中找到每组的最小值?【英文标题】:SQL: How to find min value per group in sql? 【发布时间】:2018-03-04 00:29:23 【问题描述】:我有下表snapshots
:
domain year month day
--- --- --- ---
google 2007 04 15
google 2005 08 31
google 2005 12 01
facebook 2006 04 15
facebook 2006 02 25
facebook 2008 01 01
我要检索的是每个域的第一个(最早)日期。
所以输出应该是:
google 2005 08 31
facebook 2006 02 25
我尝试了以下查询,但它检索了每列的最小值:
select domain, min(year), min(month), min(day) from snapshots group by domain
【问题讨论】:
您使用的是 mysql 还是 SQL Server? 您需要将它们视为连接后的日期并应用 MIN 函数。 @GiorgosBetsos MySQL 如果您可以将date
数据存储在date
类型列中,而不是分隔列...
没有串联的任何其他方式吗?
【参考方案1】:
如前所述,您应该使用串联来创建单个日期,然后选择最小值。
select domain, MIN(CAST(CONCAT(`year`, '-'`,month`,'-',`day`) AS DATE)) from snapshots group by domain
尚未对此进行测试,但这应该会给您一个想法。
【讨论】:
【参考方案2】:您可以连接日期字段中的值,将它们转换为日期并选择最小日期(在这种情况下,我希望值是 varchar):
SELECT domain,
MIN(CAST(CONCAT(year,'-',month,'-',day) AS date))
FROM snapshots
GROUP BY domain;
【讨论】:
谢谢!串联确实简化了它。【参考方案3】:在 MySQL 中:
SELECT
domain,
FROM_UNIXTIME(UNIX_TIMESTAMP(MIN(CONCAT(year,'-',month,'-',day))), '%Y') as y,
FROM_UNIXTIME(UNIX_TIMESTAMP(MIN(CONCAT(year,'-',month,'-',day))), '%m') as m,
FROM_UNIXTIME(UNIX_TIMESTAMP(MIN(CONCAT(year,'-',month,'-',day))), '%d') as d
FROM snapshots
GROUP BY domain;
【讨论】:
【参考方案4】:可能有更简单的解决方案,但您可以从年、月和日三列中创建一个新的日期类型列。然后得到最小日期如下:
SELECT DISTINCT s.domain, s.year, s.month, s.day
FROM
(
SELECT domain, year,month,day,
STR_TO_DATE(CONCAT(`year`,'-',LPAD(`month`,2,'00'),'-',LPAD(`day`,2,'00')) ,'%Y-%m-%d') AS FullDate
FROM snapshots
) AS s
INNER JOIN
(
SELECT domain, MIN(Fulldate) MinDate
FROM
(
SELECT domain, year,month,day,
STR_TO_DATE(CONCAT(`year`,'-',LPAD(`month`,2,'00'),'-',LPAD(`day`,2,'00')) ,'%Y-%m-%d') AS FullDate
FROM snapshots
) AS t
GROUP BY domain
) AS t ON t.MinDate = s.FullDate
AND t.Domain = s.Domain;
demo
这将为您提供您想要的确切结果:
| domain | year | month | day | MinDate |
|----------|------|-------|-----|------------|
| google | 2005 | 8 | 31 | 2005-08-31 |
| facebook | 2006 | 2 | 25 | 2006-02-25 |
【讨论】:
【参考方案5】:你能试试这个,如果它在没有连接的情况下解决你的问题,请告诉我?如有必要,可以通过子查询变得更加健壮。
CREATE TABLE domainDate(domain CHAR(25), `year` INT, `month` INT, `day` INT);
INSERT INTO domainDate VALUES
('google', 2007, 04, 15),
('google', 2005, 08, 31),
('google', 2005, 12, 01),
('facebook', 2006, 04, 15),
('facebook', 2006, 02, 25),
('facebook', 2008, 01, 01);
SET @VDomain := '';
SELECT domain, `year`, `month`, `day` FROM domainDate HAVING @VDomain != @VDomain := domain ORDER BY domain, `year` * 10000 + `month` * 100 + `day`;
谢谢,
詹姆斯
【讨论】:
【参考方案6】:你可以试试排名函数ROW_NUMBER()
CREATE TABLE domainDate(domain CHAR(25), [year] INT, [month] INT, [day] INT);
INSERT INTO domainDate VALUES
('google', 2007, 04, 15),
('google', 2005, 08, 31),
('google', 2005, 12, 01),
('facebook', 2006, 04, 15),
('facebook', 2006, 02, 25),
('facebook', 2008, 01, 01);
SELECT domain
,[year]
,[month]
,[day]
FROM
(
SELECT domain
,[year]
,[month]
,[day]
,ROW_NUMBER() OVER(PARTITION BY domain ORDER BY [year], [month], [day]) AS RN
FROM domainDate
) t
WHERE RN = 1
【讨论】:
以上是关于SQL:如何在 sql 中找到每组的最小值?的主要内容,如果未能解决你的问题,请参考以下文章