【问题标题】:Query not working when trying to get last 3 years data尝试获取最近 3 年的数据时查询不起作用
【发布时间】:2021-03-30 18:11:32
【问题描述】:

我的数据库表中有一个单独的列用于一年和一个月,称为日志,我想检索两个日期之间的日志,如下所示:

因此,如果我说检索 01/01/2018 到上个月即 02/01/2021 之间的日志,那么它应该检索所有日志,但我没有得到以下查询的任何结果:

select COUNT(*)
from Logs
where ((LogYear >= YEAR('01/01/2018') and LogMonth >=Month('01/01/2018')) and (LogYear <=YEAR('02/01/2021') and LogMonth < =Month('02/01/2021')))

输出:0 条记录

当我运行此查询时,虽然我有全年的数据,但计数为 0。

这个查询有什么问题?

样本数据:

LogID   LogYear     LogMonth
1       2018           1
2       2018           2
3       2018           3
4       2018           4

我正在尝试从1-Jan-2018 to 1-February-2021 检索数据。

【问题讨论】:

  • @DaleK 我已将示例数据添加到我的问题中。很抱歉造成混乱
  • @DaleK 当然。我将创建一个 plunker。给我一些时间。
  • 就目前而言,由于查询的编写方式,您的查询将仅考虑月份为 1 或 2 的行。您想要 2018 年到 2020 年间的所有行,并且只需要 2021 年的前 2 个月。您知道为什么您的查询现在不起作用了吗?
  • @DaleK 更新了问题以反映这一点
  • @SMor 是的,我明白了。感谢您指出了这一点。你能告诉我如何解决这个问题吗?

标签: sql sql-server tsql


【解决方案1】:

你不能通过比较它的组成部分来比较一个日期,你必须建立一个合适的日期然后比较它们。不幸的是,这是不可分割的,即无法使用索引,您最好存储实际日期而不是日期组件。

顺便说一句,为避免意外行为,请始终使用明确的日期格式。

正如您提到的,您从 C# 传递值只需确保将 SqlParameter 类型设置为 date 而不是 datetime 以避免任何可能的时间组件问题。

declare @Logs table (LogId int, LogYear int, LogMonth int);

declare @StartDate date = '01 Jan 2018', @EndDate date = '01 Feb 2021';

insert into @Logs (LogID, LogYear, LogMonth)
values
(1, 2018, 1),
(2, 2018, 2),
(3, 2018, 3),
(4, 2018, 4),
(5, 2021, 2),
(6, 2021, 3);

SELECT COUNT(*)
FROM @Logs
WHERE DATEFROMPARTS(LogYear, LogMonth, 1) >= @StartDate
AND DATEFROMPARTS(LogYear, LogMonth, 1) <= @EndDate;

样本数据(经过调整以检查结束情况)产生的结果为 5,因为记录 id 5 在窗口中,而 id 6 不在。

【讨论】:

  • 为您在帮助方面所做的努力以及我所了解的其他信息而投票。我想要截至 2021 年 2 月 1 日的数据
  • 抱歉,假设我的 FromDate 和 ToDate 类似于“01/01/2021 12:00:00 AM”和“02/01/2021 12:00:00 AM”,那么会出现有什么问题,因为你正在构建整个日期然后比较?
  • 你不能有一个包含时间组件的起始日期或截止日期 - 那是一个日期时间 - 而且你没有存储一天,更不用说时间了,所以你必须坚持日期比较。
  • 实际上,我将 FromDate 和 ToDate 作为 C# 应用程序的变量传递,并且我有一个 DateTime 变量,其中包括 12:00 AM 的日期,这就是原因
  • @ILoveStackoverflow 那么您需要确保您的问题准确地反映了您的情况 - 否则您将无法得到正确的答案。
【解决方案2】:

我认为您需要先通过转换为DATETIMEINT 以有序形式获取日期。

这里是INT的例子:

WITH Logs2 (ID, LogDate) AS (
    SELECT ID, ((LogYear * 10000) + (LogMonth * 100) + LogDay)
    FROM Logs
)
SELECT COUNT(*)
FROM Logs2
WHERE (LogDate >= 20180101) AND (LogDate < 20210201)

但当然更好的办法是将 3 列转换为 DATETIMEDATETIME2DATETIMEOFFSET

【讨论】:

  • 当 OP 想要日期时,为什么要使用日期时间?并且没有LogDay 列。
  • 不知道,从来没有考虑过(我总是使用时间点)。顺便说一句,我认为您使用DATEFROMPARTS 的解决方案更好,我的解决方案更像是一个黑客......
【解决方案3】:

试试这个:

DECLARE @DateFrom   datetime    =   '01/01/2018'
    ,   @DateTo     datetime    =   '02/01/2021'
    
SELECT 
        COUNT(*)
FROM    Logs
WHERE           LTRIM(LogYear*100 + LogMonth)
        BETWEEN CONVERT(varchar(6), @DateFrom   , 112) 
            AND CONVERT(varchar(6), @DateTo     , 112) 

【讨论】:

    【解决方案4】:

    你检查过 DATEFORMAT -> SET DATEFORMAT (Transact-SQL)

    如果可能的话,我建议使用 ISO 格式的日期值来消除任何区域问题,所以

    where ((LogYear >= YEAR('20180101') and LogMonth >=Month('20180101')) and (LogYear <=YEAR('20210201') and LogMonth < =Month('20210201')))
    

    【讨论】:

    • 虽然日期格式是个问题,但这不是主要问题 - 您无法从组件中获取日期范围。
    【解决方案5】:
    select COUNT(*)
    from Logs
    where (LogYear between 2018 and 2020)
    or (logyear=2021 and logMonth <= 2)
    

    【讨论】:

    • 但不适用于设置日期范围的一般情况。
    • 我同意,但查询成本较低,并且适合提供的数据模型。
    猜你喜欢
    • 2014-03-21
    • 2020-01-22
    • 1970-01-01
    • 2022-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    相关资源
    最近更新 更多