SQL Server:group_by选择活动日期

时间:2014-04-25 09:36:52

标签: sql sql-server sql-server-2008

在我的表中,我有两列:

  • leasecontract.[Contract Activation Date]
  • leasecontract.[Contract Ending Date]

对于这两列,我想生成一个表格,例如:

enter image description here

因此第一行的查询可以是(新合同):

SELECT 
   COUNT(leasecontract.Id) AS total,
   YEAR(leasecontract.[Contract Activation Date]) AS jaar  
FROM 
   leasecontract
GROUP BY 
   YEAR(leasecontract.[Contract Activation Date])

但有没有办法对中间行做同样的事情?显示按年份在1个查询中分组的有效合同。谢谢!

SQL版本是2008

2 个答案:

答案 0 :(得分:2)

我会用三个常用的表格表达式来完成这个 每个列一个,您要选择。然后使用年份将它们连接在一起。

我不确定我是否正确理解了有关合同状态(新的,有效的和已关闭的)的条件。但是你可以很容易地调整每个commom表表达式中的WERE - 条件。

WITH    newContracts
          AS ( SELECT   total = COUNT(l.Id) ,
                        [Year] = YEAR(GETDATE())
               FROM     leasecontract l
               WHERE    GETDATE() < l.[Contract Activation Date]
               GROUP BY YEAR(GETDATE())
             ),
        activeContracts
          AS ( SELECT   total = COUNT(l.Id) ,
                        [Year] = YEAR(l.[Contract Activation Date])
               FROM     leasecontract l
               WHERE    GETDATE() >= l.[Contract Activation Date]
                        AND GETDATE() < l.[Contract Ending Date]
               GROUP BY YEAR(l.[Contract Activation Date])
             ),
        closedContracts
          AS ( SELECT   total = COUNT(l.Id) ,
                        [Year] = YEAR(l.[Contract Ending Date])
               FROM     leasecontract l
               WHERE    GETDATE() >= l.[Contract Ending Date]
               GROUP BY YEAR(l.[Contract Ending Date])
             )
    SELECT  n.[Year] ,
            n.total AS [New contracts] ,
            a.total AS [Active contracts] ,
            c.total AS [Closed contracts]
    FROM    newContracts n
            JOIN activeContracts a ON n.[Year] = a.[Year]
            JOIN closedContracts c ON a.[Year] = c.[Year]

答案 1 :(得分:1)

之前从未做过递归CTE。但这是一个学习的好地方。所以,下面的那个应该有效。如果没有结束日期的合同,它将显示为&#34;活动&#34;在其开始日期之后的所有列出年份。假设您的SQL Server版本是2008或更高版本,我认为。

递归可能没有必要,但理论上只是从开始和结束日期开始DISTINCT年,有可能在没有新合同被打开的闰年,或旧的合同被关闭,而它们仍然是活性。这样,即使闰年也会被包括在内,加上最小/最大可能会超过表现性能的DISTINCT / GROUP BY日期。

;WITH DateLimits AS 
    -- Fetching absolute MIN and MAX date
        (SELECT MinDate, CASE WHEN MaxDate < MaxDateCheck THEN MaxDateCheck ELSE MaxDate END AS MaxDate
        FROM
            (SELECT MIN([Contract Activation Date]) MinDate
                , MAX([Contract Ending Date]) MaxDate
                , MAX([Contract Activation Date]) MaxDateCheck
            FROM LEASECONTRACT) SRC)
    -- Creating all years between MIN start and MAX endtime
    , CTESeq AS
        (SELECT YEAR(MinDate) [Year]
        FROM DateLimits
        UNION ALL
        SELECT [Year]+1
        FROM CTESeq 
        JOIN DateLimits ON 1=1
        WHERE [Year] < YEAR(MaxDate))
-- Forming the results based on CTESeq above
SELECT *
FROM CTESeq CTE
OUTER APPLY (SELECT COUNT(*) [New Contracts] FROM LEASECONTRACT WHERE YEAR([Contract Activation Date]) = CTE.Year) OAStarts
OUTER APPLY (SELECT COUNT(*) [Active Contracts] FROM LEASECONTRACT 
    WHERE CTE.Year BETWEEN YEAR([Contract Activation Date]) AND ISNULL(YEAR([Contract Ending Date]),CTE.Year)) OAActive
OUTER APPLY (SELECT COUNT(*) [Closed Contracts] FROM LEASECONTRACT WHERE YEAR([Contract Ending Date]) = CTE.Year) OAEnds
ORDER BY [Year] ASC
OPTION (MAXRECURSION 100);

编辑:添加了一个检查,以确定MAX endtime实际上小于MAX starttime。

编辑2 :神圣的,NePh的多个CTE查询示例非常棒。不知道你可以做到这一点。我通过他的示例将我的响应更改为单个查询,而是使用额外的CTE选择替换先前的变量。