如何在时间戳之间选择状态为的记录?T-SQL
我有一个T-SQL Quotes表,需要能够计算在过去几个月中有多少引号处于打开状态 我必须处理的日期是“添加日期”时间戳和“更新日期”时间戳。报价单一旦进入“1”的“关闭状态”,就不能再进行更新。因此,“更新日期”实际上成为关闭状态时间戳 我被困住了,因为我不知道如何选择在特定月份打开的所有未平仓报价 以下是一些示例记录:如何在时间戳之间选择状态为的记录?T-SQL,sql,sql-server,tsql,datetime,Sql,Sql Server,Tsql,Datetime,我有一个T-SQL Quotes表,需要能够计算在过去几个月中有多少引号处于打开状态 我必须处理的日期是“添加日期”时间戳和“更新日期”时间戳。报价单一旦进入“1”的“关闭状态”,就不能再进行更新。因此,“更新日期”实际上成为关闭状态时间戳 我被困住了,因为我不知道如何选择在特定月份打开的所有未平仓报价 以下是一些示例记录: Quote_No Add_Date Update_Date Open_Status Closed_Status 001 01-01-2016 N
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
我在这个问题上遇到了心理障碍,我尝试过在过滤时做一些案例,但我似乎无法解决这个难题。理想情况下,我不会硬编码日期,因为这跨越了几年,我不想在写完之后维护它
提前感谢您的帮助。您可以使用提取日期的某些部分,例如:
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的使用。您是按月进行的。因此,我想到了三个选择: 使用左联接的所有月份的列表。 递归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;
这确实假设每个月至少有一个公开记录。这似乎是合理的。由于误解了最初的请求而更新 考虑以下测试数据:
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]
报表较长,可读性也更高,并列出了迄今为止的所有年/月组合
看看SQL Server 2008+的
和即使计数器为0,您是否希望显示月份?请注意,您可能指的是DateTime、DateTime2或Date,而不是Timestamp,因为Timestamp实际上是一个自动递增的二进制值,与实际日期/时间无关。正如OP提到的,请选择所有*已*打开的打开报价,这并不能解决问题。正如OP提到的,选择所有*曾经*开放的开放报价,这并不能解决问题。开始时没有明确说明。在读了戈登的答案后,我才意识到这是什么意思。更新了我的脚本。@Gordon_Linoff,它成功地解决了我的问题。我很感激,但我想了解按节排列的行号顺序是如何工作的/为什么工作的。你有什么推荐信吗?你的技术给我留下了深刻的印象。master..spt_values是一个包含数千行的大型表,通常用于在SQL中生成数字。事实上,其中一列是连续的,但我不记得是哪一列,所以我只使用row_number生成一个连续值。如果你只运行CTE,你可以看到它只产生一系列数字,从0开始。我已经用了几个月了,结果发现有一个问题。基本上这是一个累积的数字,所以一月是好的,但是二月实际上是一月+二月,三月是一月+二月+三月,等等。现在我们在七月,我们已经发现了这个问题。关于如何纠正这个问题有什么建议吗?谢谢大家!@SDS。你能用示例数据和期望的结果问另一个问题吗?我在这里发布了一个新问题,其中包含完整的数据集和期望的结果:谢谢你的帮助!