[英]SQL iterate for each group
i have this table: 我有这张桌子:
|ID| GruopID | Status | Date |
| 2| 1 | S1 | 7/29/2011 |
| 3| 1 | S2 | 7/30/2011 |
| 9| 1 | S1 | 8/02/2011 |
| 7| 1 | S1 | 8/03/2011 |
| 8| 1 | S1 | 8/04/2011 |
| 1| 2 | S1 | 7/28/2011 |
| 4| 2 | S2 | 7/30/2011 |
| 5| 2 | S3 | 8/01/2011 |
| 6| 3 | S1 | 8/02/2011 |
and also a specific date from an outside source: 7/31/2011 以及来自外部的具体日期:2011年7月31日
I need a query which will give me for each groupID the closest upper and lower date, so the result will be: 我需要一个查询,该查询将为每个groupID提供 最接近的上,下日期,因此结果将是:
|ID| GruopID | Status | Date |
| 3| 1 | S2 | 7/30/2011 |
| 9| 1 | S1 | 8/02/2011 |
| 4| 2 | S2 | 7/30/2011 |
| 5| 2 | S3 | 8/01/2011 |
| 6| 3 | S1 | 8/02/2011 |
Can someone please help me and show me the query? 有人可以帮助我并向我显示查询吗?
Straightforward approach: 简单的方法:
SELECT t1.ID, t1.GroupID, t1.Status, t1.Date
FROM MyTable t1
WHERE t1.Date IN (
SELECT MAX(t2.Date)
FROM MyTable t2
WHERE t2.GroupID = t1.GroupID
AND t2.Date <= '7/31/2011'
UNION
SELECT MIN(t3.Date)
FROM MyTable t3
WHERE t3.GroupID = t1.GroupID
AND t3.Date >= '7/31/2011'
)
Please note that the number of rows per group may not always be two. 请注意,每个组的行数可能并不总是为2。
This is a classic greatest-n-per-group
query. 这是一个经典
greatest-n-per-group
查询。 I would use CROSS APPLY
here. 我会在这里使用
CROSS APPLY
。
Make sure that you have index on (GroupID, dt, ID)
. 确保在
(GroupID, dt, ID)
上具有索引。
Most likely you have a table Groups
that has a list of all GroupIDs
. 您很可能有一个表
Groups
,其中包含所有GroupIDs
的列表。 In the query below I use CTE to get a list of all distinct GroupIDs
. 在下面的查询中,我使用CTE获取所有不同
GroupIDs
的列表。
Sample data 样本数据
I added few rows to show how the query works in various cases. 我添加了几行以显示查询在各种情况下的工作方式。
DECLARE @VarDate date = '2011-07-31';
DECLARE @T TABLE (ID int, GroupID int, Status varchar(2), dt date);
INSERT INTO @T (ID, GroupID, Status, dt) VALUES
(2, 1, 'S1', '2011-07-29'),
(3, 1, 'S2', '2011-07-30'),
(9, 1, 'S1', '2011-08-02'),
(7, 1, 'S1', '2011-08-03'),
(8, 1, 'S1', '2011-08-04'),
(1, 2, 'S1', '2011-07-28'),
(4, 2, 'S2', '2011-07-30'),
(5, 2, 'S3', '2011-08-01'),
(6, 3, 'S1', '2011-08-02'),
(11, 4, 'S1', '2011-08-04'),
(12, 4, 'S2', '2011-08-02'),
(13, 4, 'S3', '2011-08-02'),
(21, 4, 'S1', '2011-07-04'),
(22, 4, 'S2', '2011-07-04'),
(23, 4, 'S3', '2011-07-04'),
(31, 5, 'S1', '2011-07-31'),
(32, 5, 'S2', '2011-07-31'),
(33, 5, 'S3', '2011-07-31'),
(34, 5, 'S1', '2011-07-31'),
(35, 5, 'S2', '2011-07-31'),
(36, 5, 'S3', '2011-07-31'),
(41, 6, 'S1', '2011-07-31');
Query 询问
For each GroupID
we find the upper and lower row using CROSS APPLY
, then UNION ALL
upper and lower results together. 对于每个
GroupID
我们使用CROSS APPLY
找到上下一行,然后将UNION ALL
上下结果一起找到。
WITH
CTE_Groups
AS
(
SELECT DISTINCT GroupID
FROM @T
)
SELECT
CA.ID
,Groups.GroupID
,CA.Status
,CA.dt
FROM
CTE_Groups AS Groups
CROSS APPLY
(
SELECT TOP(1)
T.ID
,T.Status
,T.dt
FROM @T AS T
WHERE
T.GroupID = Groups.GroupID
AND T.dt >= @VarDate
ORDER BY T.dt, ID
) AS CA
UNION ALL
SELECT
CA.ID
,Groups.GroupID
,CA.Status
,CA.dt
FROM
CTE_Groups AS Groups
CROSS APPLY
(
SELECT TOP(1)
T.ID
,T.Status
,T.dt
FROM @T AS T
WHERE
T.GroupID = Groups.GroupID
AND T.dt <= @VarDate
ORDER BY T.dt DESC, ID DESC
) AS CA
ORDER BY GroupID, dt;
Result 结果
+----+---------+--------+------------+
| ID | GroupID | Status | dt |
+----+---------+--------+------------+
| 3 | 1 | S2 | 2011-07-30 |
| 9 | 1 | S1 | 2011-08-02 |
| 4 | 2 | S2 | 2011-07-30 |
| 5 | 2 | S3 | 2011-08-01 |
| 6 | 3 | S1 | 2011-08-02 |
| 23 | 4 | S3 | 2011-07-04 |
| 12 | 4 | S2 | 2011-08-02 |
| 31 | 5 | S1 | 2011-07-31 |
| 36 | 5 | S3 | 2011-07-31 |
| 41 | 6 | S1 | 2011-07-31 |
| 41 | 6 | S1 | 2011-07-31 |
+----+---------+--------+------------+
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.