工作日SQL查询

时间:2014-11-19 11:29:53

标签: sql sql-server tsql

我有一个问题,我无法理解。

我有一个事件表和一个用户表。有些活动是收费的,有些则不是。我想要确定的是每个用户每周每月的收费天数。

这是数据......

ID FromDate    ToDate       isChargeable     Username
1  2014-11-03  2014-11-04        Y           AUser 
2  2014-11-04  2014-11-06        Y           AUser
3  2014-11-07  2014-11-07        Y           AUser

我已经编写了一个基本查询来计算from和to日期之间的差异,并将它们加总为1,因为toDate计算为一整天。

SELECT DISTINCT FromDate, ToDate, isChargeable,Username, DATEDIFF(day, FromDate, ToDate) + 1) AS 'count1'
FROM            dbo.vDiary
GROUP BY FromDate, ToDate, isChargeable,Username

这导致......

      FromDate    ToDate       isChargeable     Username   count1
      2014-11-03  2014-11-04        Y           AUser      2
      2014-11-04  2014-11-06        Y           AUser      3
      2014-11-07  2014-11-07        Y           AUser      1

这是不正确的,因为它显示了6个工作日,因为两个事件重叠。

如何允许这种重叠?我需要声明,如果某一天的某个活动是收费的,那么这一天是收费日。

我想我需要一张日历表,但我不确定使用它来获得正确的结果。

任何帮助都会非常感激!!

由于

史蒂夫

编辑:从下面尝试解决方案

        ;WITH cte
     AS (SELECT Row_number()OVER(PARTITION BY Username ORDER BY FromDate) rn,
                FromDate,ToDate,isChargeable,Username
         FROM   #calen)
SELECT a.FromDate,a.ToDate,a.isChargeable,a.Username,
       CASE
         WHEN a.FromDate > b.ToDate
               OR b.ToDate IS NULL THEN Datediff(day, a.FromDate, a.ToDate) + 1
         ELSE Datediff(day, Dateadd(dd, 1, b.ToDate), a.ToDate)+ 1
       END DatDiff,
       *
FROM   cte a
       LEFT JOIN cte b
              ON a.rn = b.rn + 1
                 AND a.username = b.username
WHERE  ( a.ToDate > b.todate
          OR b.ToDate IS NULL ) 

制作(更新)

FromDate    ToDate  isChargeable    Username    DatDiff rn  FromDate    ToDate  isChargeable    Username    rn  FromDate    ToDate  isChargeable    Username
2014-11-03  2014-11-04  Y   AUser                2      1   2014-11-03  2014-11-04  Y   AUser   NULL    NULL    NULL    NULL    NULL
2014-11-04  2014-11-06  Y   AUser                2      2   2014-11-04  2014-11-06  Y   AUser   1   2014-11-03  2014-11-04  Y   AUser
2014-11-07  2014-11-07  Y   AUser                1      3   2014-11-07  2014-11-07  Y   AUser   2   2014-11-04  2014-11-06  Y   AUser
2014-12-03  2014-12-15  Y   AUser                13     4   2014-12-03  2014-12-15  Y   AUser   3   2014-11-07  2014-11-07  Y   AUser
2014-12-10  2014-12-17  Y   AUser                2      5   2014-12-10  2014-12-17  Y   AUser   4   2014-12-03  2014-12-15  Y   AUser
2015-12-04  2015-12-15  Y   AUser                12     6   2015-12-04  2015-12-15  Y   AUser   5   2014-12-10  2014-12-17  Y   AUser
2014-11-03  2014-11-03  Y   BUser                1      1   2014-11-03  2014-11-03  Y   BUser   NULL    NULL    NULL    NULL    NULL
2014-11-04  2014-11-04  Y   BUser                1      2   2014-11-04  2014-11-04  Y   BUser   1   2014-11-03  2014-11-03  Y   BUser

3 个答案:

答案 0 :(得分:1)

试试这个。

如果您有唯一ID,请尝试此操作。

create table #calen(ID int, FromDate   date, ToDate date,isChargeable char(1),Username varchar(20))

INSERT #calen
VALUES (1,'2014-11-03','2014-11-04','Y ','AUser'),
       (2,'2014-11-04','2014-11-06','Y','AUser'),
       (3,'2014-11-07','2014-11-07','Y','AUser') 


SELECT a.FromDate,a.ToDate,a.isChargeable,a.Username,
       CASE
         WHEN a.FromDate > b.ToDate
               OR b.ToDate IS NULL THEN Datediff(day, a.FromDate, a.ToDate) + 1
         ELSE Datediff(day, Dateadd(dd, 1, b.ToDate), a.ToDate)
              + 1
       END DatDiff
FROM   #calen a
       LEFT JOIN #calen b
              ON a.id = b.id + 1
WHERE  ( a.ToDate > b.todate
          OR b.ToDate IS NULL ) 

更新:

对于多个用户。

;WITH cte
     AS (SELECT Row_number()OVER(PARTITION BY Username ORDER BY FromDate) rn,
                FromDate,ToDate,isChargeable,Username
         FROM   #calen)
SELECT a.FromDate,a.ToDate,a.isChargeable,a.Username,
       CASE
         WHEN a.FromDate > b.ToDate
               OR b.ToDate IS NULL THEN Datediff(day, a.FromDate, a.ToDate) + 1
         ELSE Datediff(day, Dateadd(dd, 1, b.ToDate), a.ToDate)+ 1
       END DatDiff
FROM   cte a
       LEFT JOIN cte b
              ON a.rn = b.rn + 1
                 AND a.username = b.username
WHERE  ( a.ToDate > b.todate
          OR b.ToDate IS NULL ) 

输出:

FromDate    ToDate      isChargeable    Username    DatDiff
----------  ----------  ------------    --------    -------
2014-11-03  2014-11-04  Y               AUser           2
2014-11-04  2014-11-06  Y               AUser           2
2014-11-07  2014-11-07  Y               AUser           1

答案 1 :(得分:1)

如果所有ID值都不唯一,我们可以使用以下查询:

SELECT ID, FromDate, ToDate, isChargeable, Username,
 CASE WHEN EXISTS(SELECT ToDate FROM UserTable B WHERE A.FromDate = B.ToDate 
   AND A.UserName = B.UserName AND A.ID <> B.ID) THEN
   DATEDIFF(day, FromDate, ToDate)
 ELSE
   DATEDIFF(day, FromDate, ToDate) + 1
 END  AS 'count1'
FROM UserTable A

否则我们必须创建CTE以创建唯一的ROWID。

;WITH UserTable
     AS (SELECT Row_number() OVER(ORDER BY FromDate) RowID,
                FromDate,ToDate, isChargeable, Username
         FROM #user)

SELECT RowID, FromDate, ToDate, isChargeable, Username,
 CASE WHEN EXISTS(SELECT ToDate FROM UserTable B WHERE A.FromDate = B.ToDate 
       AND A.UserName = B.UserName AND A.RowID <> B.RowID) THEN
   DATEDIFF(day, FromDate, ToDate)
 ELSE
   DATEDIFF(day, FromDate, ToDate) + 1
 END  AS 'count1'
FROM UserTable A

答案 2 :(得分:1)

试试这个:

WITH CTE AS 
(SELECT a.* ,y.flag
FROM EventsTable a
OUTER APPLY 
  (SELECT DATEDIFF(dd, a.ToDate, x.FromDate) as flag 
  FROM EventsTable x 
  WHERE a.id = x.id AND x.FromDate > a.ToDate) y)

SELECT id,FromDate,ToDate,isChargeable,Username,
   CASE WHEN flag = 1 THEN 
      DATEDIFF(dd, FromDate, ToDate) 
   ELSE DATEDIFF(dd, FromDate,ToDate) + 1 
   END AS count1
FROM CTE