SQL迭代为每个组

时间:2016-02-28 10:03:57

标签: sql sql-server

我有这张桌子:

|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   |

以及来自外部来源的具体日期:2011年7月31日

我需要一个查询,它会为每个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   |

有人可以帮助我并向我显示查询吗?

2 个答案:

答案 0 :(得分:1)

直截了当的方法:

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'
)

请注意,每组的行数可能不一定是两行。

  • 如果有一个记录恰好是该日期7/31/2011,那么将为该组返回一条记录。
  • 如果某个组的所有记录都在2011年7月31日之前或之后,那么将为该组返回一条记录。
  • 如果表包含GroupID和Date的重复组合,则可能返回两行以上。这是固定的事实,即没有定义重复的“正确”方式。

答案 1 :(得分:1)

这是一个经典的import sys from PyQt4 import QtGui, QtCore class MyDelegate(QtGui.QItemDelegate): def __init__(self, parent, table): super(MyDelegate, self).__init__(parent) self.table = table def sizeHint(self, option, index): # Get full viewport size table_size = self.table.viewport().size() gw = 1 # Grid line width rows = self.table.rowCount() or 1 cols = self.table.columnCount() or 1 width = (table_size.width() - (gw * (cols - 1))) / cols height = (table_size.height() - (gw * (rows - 1))) / rows return QtCore.QSize(width, height) class Window(QtGui.QWidget): def __init__(self, rows, columns): super(Window, self).__init__() self.lay = QtGui.QVBoxLayout() self.setLayout(self.lay) self.table = QtGui.QTableWidget(rows, columns, self) self.table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.lay.addWidget(self.table) self.delegate = MyDelegate(self, self.table) self.table.setItemDelegate(self.delegate) def showEvent(self, event): super(Window, self).showEvent(event) self.resizeTable() def resizeTable(self): self.table.resizeRowsToContents() self.table.resizeColumnsToContents() def resizeEvent(self, event): super(Window, self).resizeEvent(event) self.resizeTable() 查询。我会在这里使用greatest-n-per-group

确保您在CROSS APPLY上有索引。

您很可能有一个表(GroupID, dt, ID),其中包含所有Groups的列表。在下面的查询中,我使用CTE获取所有不同GroupIDs的列表。

示例数据

我添加了几行来显示查询在各种情况下的工作方式。

GroupIDs

<强>查询

对于每个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'); ,我们使用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;