简体   繁体   English

每个组的SQL迭代

[英]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。

  • If there is a record with precisely that date 7/31/2011, then a single record will be returned for that group. 如果有确切的日期为7/31/2011的记录,则将返回该组的单个记录。
  • If all records of a group are either before or after 7/31/2011, then a single record will be returned for that group. 如果某个组的所有记录都在2011年7月31日之前或之后,则将为该组返回一条记录。
  • If the table contains duplicate combinations of GroupID and Date, then more than two rows may be returned. 如果表包含GroupID和Date的重复组合,则可能会返回两行以上。 This is inherent to the fact that no 'correct' way to choose between the duplicates has been defined. 这是以下事实所固有的,即尚未定义在重复项之间进行选择的“正确”方法。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM