Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在时间戳之间选择状态为的记录?T-SQL_Sql_Sql Server_Tsql_Datetime - Fatal编程技术网

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

如何在时间戳之间选择状态为的记录?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

我有一个T-SQL Quotes表,需要能够计算在过去几个月中有多少引号处于打开状态

我必须处理的日期是“添加日期”时间戳和“更新日期”时间戳。报价单一旦进入“1”的“关闭状态”,就不能再进行更新。因此,“更新日期”实际上成为关闭状态时间戳

我被困住了,因为我不知道如何选择在特定月份打开的所有未平仓报价

以下是一些示例记录:

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。你能用示例数据和期望的结果问另一个问题吗?我在这里发布了一个新问题,其中包含完整的数据集和期望的结果:谢谢你的帮助!