Sql 按行分组查找最小值
在SQL空间(特别是T-SQL、SQL Server 2008)中,给定以下值列表:Sql 按行分组查找最小值,sql,sql-server,tsql,group-by,Sql,Sql Server,Tsql,Group By,在SQL空间(特别是T-SQL、SQL Server 2008)中,给定以下值列表: Status Date ------ ----------------------- ACT 2012-01-07 11:51:06.060 ACT 2012-01-07 11:51:07.920 ACT 2012-01-08 04:13:29.140 NOS 2012-01-09 04:29:16.873 ACT
Status Date
------ -----------------------
ACT 2012-01-07 11:51:06.060
ACT 2012-01-07 11:51:07.920
ACT 2012-01-08 04:13:29.140
NOS 2012-01-09 04:29:16.873
ACT 2012-01-21 12:39:37.607 <-- THIS
ACT 2012-01-21 12:40:03.840
ACT 2012-05-02 16:27:17.370
GRAD 2012-05-19 13:30:02.503
GRAD 2013-09-03 22:58:48.750
此特定对象的状态从ACT开始,然后更改为NOS,然后返回ACT,再更改为GRAD
从状态为'ACT'的最新记录“组”中获取最短日期的最佳方法是什么
SELECT [Status], MIN([Date])
FROM Table_Name
WHERE [Status] = (SELECT [Status]
FROM Table_Name
WHERE [Date] = (SELECT MAX([Date])
FROM Table_Name)
)
GROUP BY [Status]
试试这里
请尝试此处以下是一个查询,通过识别学生状态相同的组,然后使用简单的聚合:
select top 1 StudentStatus, min(WhenLastChanged) as WhenLastChanged
from (SELECT StudentStatus, WhenLastChanged,
(row_number() over (order by "date") -
row_number() over (partition by studentstatus order by "date)
) as grp
FROM Account_History
WHERE AccountNumber = '1234'
) t
where StudentStatus = 'ACT'
group by StudentStatus, grp
order by WhenLastChanged desc;
row\u number()
函数根据日期在一组行中分配序号。对于您的数据,两个行编号()
和它们的区别是:
Status Date
------ -----------------------
ACT 2012-01-07 11:51:06.060 1 1 0
ACT 2012-01-07 11:51:07.920 2 2 0
ACT 2012-01-08 04:13:29.140 3 3 0
NOS 2012-01-09 04:29:16.873 4 1 3
ACT 2012-01-21 12:39:37.607 5 4 1
ACT 2012-01-21 12:40:03.840 6 5 1
ACT 2012-05-02 16:27:17.370 7 6 1
GRAD 2012-05-19 13:30:02.503 8 1 7
GRAD 2013-09-03 22:58:48.750 9 2 7
请注意,对于具有相同状态的行,最后一行是常量
聚合将这些数据集合在一起,并选择第一个日期(min(date)
)中最新的(top 1…order by date desc
)
编辑:
对于多个帐号,查询很容易调整。我可能应该这样开始写,除非最后的选择比较棘手。此操作的结果具有每个状态和帐户的日期:
select StudentStatus, min(WhenLastChanged) as WhenLastChanged
from (SELECT StudentStatus, WhenLastChanged, AccountNumber
(row_number() over (partition by AccountNumber order by WhenLastChanged) -
row_number() over (partition by AccountNumber, studentstatus order by WhenLastChanged)
) as grp
FROM Account_History
) t
where StudentStatus = 'ACT'
group by AccountNumber, StudentStatus, grp
order by WhenLastChanged desc;
但是你不可能很容易地得到每个帐户的最后一个。另一级子查询:
select AccountNumber, StudentStatus, WhenLastChanged
from (select AccountNumber, StudentStatus, min(WhenLastChanged) as WhenLastChanged,
row_number() over (partition by AccountNumber, StudentStatus order by min(WhenLastChanged) desc
) as seqnum
from (SELECT AccountNumber, StudentStatus, WhenLastChanged,
(row_number() over (partition by AccountNumber order by WhenLastChanged) -
row_number() over (partition by AccountNumber, studentstatus order by WhenLastChanged)
) as grp
FROM Account_History
) t
where StudentStatus = 'ACT'
group by AccountNumber, StudentStatus, grp
) t
where seqnum = 1;
这将使用聚合以及窗口函数row\u number()
。这是将序号分配给组(聚合后),每个帐户的最后日期的值为1(orderbymin(WhenLastChanged)desc
)。最外面的选择
,然后只为每个帐户选择该行。下面是一个查询,通过识别学生状态相同的组,然后使用简单的聚合来实现这一点:
select top 1 StudentStatus, min(WhenLastChanged) as WhenLastChanged
from (SELECT StudentStatus, WhenLastChanged,
(row_number() over (order by "date") -
row_number() over (partition by studentstatus order by "date)
) as grp
FROM Account_History
WHERE AccountNumber = '1234'
) t
where StudentStatus = 'ACT'
group by StudentStatus, grp
order by WhenLastChanged desc;
row\u number()
函数根据日期在一组行中分配序号。对于您的数据,两个行编号()
和它们的区别是:
Status Date
------ -----------------------
ACT 2012-01-07 11:51:06.060 1 1 0
ACT 2012-01-07 11:51:07.920 2 2 0
ACT 2012-01-08 04:13:29.140 3 3 0
NOS 2012-01-09 04:29:16.873 4 1 3
ACT 2012-01-21 12:39:37.607 5 4 1
ACT 2012-01-21 12:40:03.840 6 5 1
ACT 2012-05-02 16:27:17.370 7 6 1
GRAD 2012-05-19 13:30:02.503 8 1 7
GRAD 2013-09-03 22:58:48.750 9 2 7
请注意,对于具有相同状态的行,最后一行是常量
聚合将这些数据集合在一起,并选择第一个日期(min(date)
)中最新的(top 1…order by date desc
)
编辑:
对于多个帐号,查询很容易调整。我可能应该这样开始写,除非最后的选择比较棘手。此操作的结果具有每个状态和帐户的日期:
select StudentStatus, min(WhenLastChanged) as WhenLastChanged
from (SELECT StudentStatus, WhenLastChanged, AccountNumber
(row_number() over (partition by AccountNumber order by WhenLastChanged) -
row_number() over (partition by AccountNumber, studentstatus order by WhenLastChanged)
) as grp
FROM Account_History
) t
where StudentStatus = 'ACT'
group by AccountNumber, StudentStatus, grp
order by WhenLastChanged desc;
但是你不可能很容易地得到每个帐户的最后一个。另一级子查询:
select AccountNumber, StudentStatus, WhenLastChanged
from (select AccountNumber, StudentStatus, min(WhenLastChanged) as WhenLastChanged,
row_number() over (partition by AccountNumber, StudentStatus order by min(WhenLastChanged) desc
) as seqnum
from (SELECT AccountNumber, StudentStatus, WhenLastChanged,
(row_number() over (partition by AccountNumber order by WhenLastChanged) -
row_number() over (partition by AccountNumber, studentstatus order by WhenLastChanged)
) as grp
FROM Account_History
) t
where StudentStatus = 'ACT'
group by AccountNumber, StudentStatus, grp
) t
where seqnum = 1;
这将使用聚合以及窗口函数row\u number()
。这是将序号分配给组(聚合后),每个帐户的最后日期的值为1(orderbymin(WhenLastChanged)desc
)。最外层的选择,然后为每个帐户选择该行
霍根:基本上,是的。我只想知道飞机起飞的日期/时间
帐户最后更改为ACT。以上各点之后的记录
这是额外的
我们可以查找第一次状态更改并从中选择act(和max),而不只是查找act
所以。。。每次状态更改时:
with rownumb as
(
select *, row_number() OVER (order by date asc) as rn
)
select status, date
from rownumb A
join rownumb B on A.rn = B.rn-1
where a.status != b.status
现在查找act项目的最大值
with rownumb as
(
select *, row_number() OVER (order by date asc) as rn
), statuschange as
(
select status, date
from rownumb A
join rownumb B on A.rn = B.rn-1
where a.status != b.status
)
select max(date)
from satuschange
where status='Act'
霍根:基本上,是的。我只想知道飞机起飞的日期/时间
帐户最后更改为ACT。以上各点之后的记录
这是额外的
我们可以查找第一次状态更改并从中选择act(和max),而不只是查找act
所以。。。每次状态更改时:
with rownumb as
(
select *, row_number() OVER (order by date asc) as rn
)
select status, date
from rownumb A
join rownumb B on A.rn = B.rn-1
where a.status != b.status
现在查找act项目的最大值
with rownumb as
(
select *, row_number() OVER (order by date asc) as rn
), statuschange as
(
select status, date
from rownumb A
join rownumb B on A.rn = B.rn-1
where a.status != b.status
)
select max(date)
from satuschange
where status='Act'
这里缺少一些组。如果按“最短日期”OP表示最早,这就是您需要的want@Hogan少了什么?看起来不错me@MBarnett如前所述,这将得到他毕业时的最短日期,而不是毕业时的最短日期act@M.Ali我不是问/修改问题的人,但是的,要求可能已经改变。这里缺少一些组。如果在“最短日期”前OP表示最早,这就是你想要的want@Hogan少了什么?看起来不错me@MBarnett如前所述,这将得到他毕业时的最短日期,而不是毕业时的最短日期act@M.Ali我不是问/修改这个问题的人,但是的,要求可能已经改变了。我不明白,是什么促使人们需要行动——投入?霍根:基本上,是的。我只想知道账户最后更改为ACT的日期/时间。上面标记这一点后的记录只是额外的。我不明白,是什么驱动了ACT——输入的需要?霍根:基本上,是的。我只想知道账户最后更改为ACT的日期/时间。上面标记这一点后的记录只是额外的。在看到您的编辑(添加WHERE子句)之前,我调整了您的查询,它对我非常有效。我很想更好地理解这个答案,所以我将对此进行研究。为了提高效率,如果我想通过加入一个具有多个帐号的表来实现最后的多个更改,我应该如何实现这一点?换句话说,我有一个有3个帐号的表,我想知道每个帐号的相同信息。(请原谅,如果问这个问题的地方不对,请告诉我,我很乐意搬走。)@TSFroggy-看看我的答案,使用CTEs可能更容易摸索。我不确定哪一个会更快。霍根,对不起,我无法让你的查询运行。@Gordon我希望我能投赞成票,但正如你所看到的,我是一个长期潜伏者,很少有时间。感谢您提供了非常详细和全面的答案。@Gordon对您的最终查询进行了一些编辑以使其运行。在看到您的编辑(添加WHERE子句)之前,我对您的查询进行了调整,它非常适合我。我很想更好地理解这个答案,所以我将对此进行研究。为了提高效率,如果我想通过加入一个具有多个帐号的表来实现最后的多个更改,我应该如何实现这一点?换句话说,我有一个有3个帐号的表,我想知道相同的帐号