如何在时间戳之间的状态中选择记录? T-SQL

时间:2017-02-23 13:18:21

标签: sql sql-server tsql datetime

我有一个T-SQL报价表,需要能够计算过去几个月中有多少报价处于未结状态。

我必须使用的日期是' Add_Date'时间戳和' Update_Date'时间戳。将报价添加到&{39; Closed_Status' ' 1'它无法再更新。因此,' Update_Date'有效地成为Closed_Status时间戳。

我被卡住了,因为我无法弄清楚如何选择在特定月份开放的所有公开引语。

以下是一些示例记录:

Quote_No   Add_Date   Update_Date  Open_Status  Closed_Status
001        01-01-2016  NULL         1            0
002        01-01-2016  3-1-2016     0            1
003        01-01-2016  4-1-2016     0            1

期望的结果是:

Year  Month  Open_Quote_Count
2016  01     3
2016  02     3
2016  03     2
2016  04     1

我已经在这个问题上遇到了心理障碍,我试图进行一些case when过滤,但我似乎无法解决这个难题。理想情况下,我不会在日期中进行硬编码,因为这需要多年,我不想在编写之后保持这一点。

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:6)

你这个月是这样做的。因此,我想到了三种选择:

  • 使用left join
  • 的所有月份的列表
  • 递归CTE。
  • 数字表。

让我展示一下:

with n as (
      select row_number() over (order by (select null)) - 1 as n
      from master..spt_values
     )
select format(dateadd(month, n.n, q.add_date), 'yyyy-MM') as yyyymm,
       count(*) as Open_Quote_Count
from quotes q join
     n
     on (closed_status = 1 and dateadd(month, n.n, q.add_date) <= q.update_date) or
        (closed_status = 0 and dateadd(month, n.n, q.add_date) <= getdate()) 
group by format(dateadd(month, n.n, q.add_date), 'yyyy-MM')
order by yyyymm;

这假设每个月至少有一个开放记录。这似乎是合理的。

答案 1 :(得分:0)

您可以使用datepart来提取日期的部分内容,例如:

select datepart(year, add_date) as 'year',
       datepart(month, date_date) as 'month',
       count(1)
from theTable
where open_status = 1
group by datepart(year, add_date), datepart(month, date_date)

注意:这会计入起始月份,主要用于显示datepart的使用情况。

答案 2 :(得分:0)

更新为误解了初始请求。

考虑以下测试数据:

DECLARE @test TABLE 
(
    Quote_No VARCHAR(3),
    Add_Date DATE,
    Update_Date DATE,
    Open_Status INT,
    Closed_Status INT
)

INSERT INTO @test (Quote_No, Add_Date, Update_Date, Open_Status, Closed_Status)
VALUES ('001', '20160101', NULL, 1, 0)
     , ('002', '20160101', '20160301', 0, 1)
     , ('003', '20160101', '20160401', 0, 1)

这是一个递归解决方案,它不依赖于系统表,但也表现得更差。正如我们所说的月份和年份组合一样,递归次数不会超额。

;WITH YearMonths AS
(
    SELECT YEAR(MIN(Add_Date)) AS [Year]
        , MONTH(MIN(Add_Date)) AS [Month]
        , MIN(Add_Date) AS YMDate
    FROM @test
    UNION ALL
    SELECT YEAR(DATEADD(MONTH,1,YMDate))
        , MONTH(DATEADD(MONTH,1,YMDate))
        , DATEADD(MONTH,1,YMDate)
    FROM YearMonths
    WHERE YMDate <= SYSDATETIME()
)
SELECT [Year]
    , [Month]
    , COUNT(*) AS Open_Quote_Count
FROM YearMonths ym
INNER JOIN @test t
ON (
    [Year] * 100 + [Month] <= CAST(FORMAT(t.Update_Date, 'yyyyMM') AS INT)
    AND t.Closed_Status = 1
    )
OR (
    [Year] * 100 + [Month] <= CAST(FORMAT(SYSDATETIME(), 'yyyyMM') AS INT)
    AND t.Closed_Status = 0
    )
GROUP BY [Year], [Month]
ORDER BY [Year], [Month]

声明更长,更具可读性,并列出了迄今为止的所有年/月组合。

查看Date and Time Data Types and Functions的SQL-Server 2008+

Recursive Queries Using Common Table Expressions