【问题标题】:Need help finding the correct T-SQL Query需要帮助找到正确的 T-SQL 查询
【发布时间】:2011-05-23 15:20:33
【问题描述】:

我不太确定该怎么做。基本上我有一张这样的桌子

UserId       DateRequested           Approved ApprovedBy  Notes
------------ ----------------------- -------- ----------- -----
1            2011-05-26               0        NULL        NULL
1            2011-05-27               0        NULL        NULL
1            2011-05-28               0        NULL        NULL
1            2011-06-05               0        NULL        NULL
1            2011-06-06               0        NULL        NULL
1            2011-06-25               0        NULL        NULL

其中基本上包含员工请求休假的天数。现在,当一天或几天被授予时,需要将此数据复制到表单的表格中

UserId DateFrom DateTo

所以基本上对于我想要的上述数据:

UserId DateFrom DateTo 
-------------------------------
1      2011-05-26 2011-05-28 
1      2011-06-05 2011-06-06 
1      2011-06-25 2011-06-25 

即我希望在 DateFrom 和 DateTo 中连续几天。现在我不确定如何在不使用 while 循环的情况下执行此操作。这是 SQL,所以我更喜欢非迭代解决方案。

请指教!!!

【问题讨论】:

  • 什么版本的 SQL Server?我们可以假设UserId, DateRequested 的唯一约束吗?
  • SQL Server 2005。UserId 是主键,是的(应该!)对 UserId 和 DateRequested 有唯一约束
  • 您以这种方式构建第二张表有什么原因吗?似乎只有一个日期和一个用户 ID,并且每天请求关闭一行会更有意义。
  • 因为其他表的行也需要进入第二个表。其中一张表有一个日期范围(预计其中有很大的日期范围)。选择了一个范围以保持行数最少。希望这是有道理的。
  • @Umair - 不幸的是它没有。我猜你实际上是在用这种方法浪费空间。您是否有很多员工一次请假 20-30 天?根据我的经验,大多数请求都是单天或数周的。一天,您会占用更多空间,因为您需要 2 列包含相同数据的列。一周内,您只需多出 4 行,而且它们更窄,我猜它的频率会低于单日请求。

标签: sql sql-server sql-server-2005 tsql gaps-and-islands


【解决方案1】:
;WITH cte AS
(
SELECT *,
        DATEDIFF(DAY,0,DateRequested)-
        ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY DateRequested) AS Grp
FROM YourTable  
WHERE Approved = 1 /*Presumably - but your example data doesn't show this.*/
)
SELECT UserId, 
       MIN(DateRequested) AS DateFrom, 
       MAX(DateRequested) AS DateTo  
FROM cte 
GROUP BY UserId,Grp

【讨论】:

  • 这在很大程度上取决于 Umair 的目标。如果他们从周四开始预订休息日,周二返回,这仍然有效吗?我认为上述情况会产生两条记录(周四至周五和周一至周二),而不是从周四到周二的一条记录。
  • @hoombar - 如果没有为星期六或星期日输入的行将被视为间隙,是的。 @Umair - 您还需要确保每个 UserId, DateRequested 每天最多有一行。您说这是 PK,但由于您使用的是 SQL Server 2005,因此 datetime 数据类型确保时间部分为午夜的检查约束将确保这一点。
【解决方案2】:

在 Oracle PL/SQL 中会这样写:

WITH cte
        AS (SELECT a.*,
                   daterequested - TRUNC (SYSDATE)
                   - ROW_NUMBER ()
                        OVER (PARTITION BY UserId ORDER BY DateRequested)
                      AS Grp
              FROM yourtable a
             WHERE Approved = 0)
  SELECT UserId, MIN (DateRequested) AS DateFrom, MAX (DateRequested) AS DateTo
    FROM cte
GROUP BY UserId, Grp;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2016-07-04
    • 2016-07-26
    • 1970-01-01
    相关资源
    最近更新 更多