【问题标题】:SQL query not returning correct date rangeSQL 查询未返回正确的日期范围
【发布时间】:2018-03-15 14:50:04
【问题描述】:

我在 VS 2017 中创建了一个简单的视图。这里是:

CREATE VIEW [dbo].[ApplicantStat]
    AS SELECT ISNULL(CONVERT(VARCHAR(50), NEWID()), '') AS ID,
    ISNULL(AVG(ApplicationTime), 0) AS 'AvgApplicationTime',
    ISNULL(AVG(ResponseTime), 0) AS 'AvgResponseTime',
    ISNULL(CAST(COUNT(CASE WHEN [IsAccepted] = 1 THEN 1 END) / COUNT(CASE WHEN [IsValid] = 1 THEN 1 END) AS float), 0) AS 'PctAccepted'
    FROM [Application]
    WHERE CreatedOn BETWEEN CAST(GETDATE()-30 AS date) AND CAST(GETDATE()-1 AS date)

如您所见,它获取两个日期之间的数据并进行一些简单的聚合。

演员的想法是,我想忽略时间并获取日期范围内的所有内容 - 因此,从今天 3 月 15 日开始,我希望获取 3 月 14 日 00:00:00 - 23 的所有内容: 59:59 和 29 天前。

这不会发生 - 它拾取 3 行(第 13 行) - 它应该拾取所有 5 行。是的,我的系统日期目前是 15/03/2018 14:44(英国时间)。

这是表格和数据:

CREATE TABLE [dbo].[Application] (
    [Id]              INT            NOT NULL,
    [ApplicantId]     INT            NOT NULL,
    [LoanAmount]      INT            NOT NULL,
    [LoanTerm]        SMALLINT       NOT NULL,
    [EmailAddress]    VARCHAR (254)  NOT NULL,
    [MobilePhone]     VARCHAR (11)   NOT NULL,
    [House]           VARCHAR (25)   NOT NULL,
    [Street]          VARCHAR (50)   NOT NULL,
    [TownCity]        VARCHAR (50)   NOT NULL,
    [Postcode]        VARCHAR (7)    NOT NULL,
    [IpAddress]       VARCHAR (39)   NOT NULL,
    [IsValid]         BIT            NOT NULL,
    [IsAccepted]      BIT            NOT NULL,
    [Commission]      DECIMAL (9, 2) NOT NULL,
    [Processors]      VARCHAR (500)  NOT NULL,
    [ResponseTime]    SMALLINT       NOT NULL,
    [ApplicationTime] SMALLINT       NOT NULL,
    [CreatedOn]       DATETIME       NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (1, 1, 300, 3, N'john.doe@tmail.com', N'07957000000', N'1', N'Acacia Avenue', N'Suburbia', N'SB1 2RB', N'100.100.100.100', 1, 1, CAST(3.20 AS Decimal(9, 2)), N'1,2,3,4,5', 90, 600, N'2018-03-13 08:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (2, 2, 500, 12, N'a@b.com', N'0', N'1', N'a', N's', N's', N'1', 0, 1, CAST(5.00 AS Decimal(9, 2)), N'1', 60, 300, N'2018-03-14 16:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (3, 3, 1000, 6, N'a@b.com', N'0', N'1', N'a', N's', N's', N'1', 1, 1, CAST(7.00 AS Decimal(9, 2)), N'1', 75, 360, N'2018-03-13 10:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (4, 4, 2000, 24, N'a@b.com', N'0', N'1', N'a', N's', N's', N'1', 1, 1, CAST(20.00 AS Decimal(9, 2)), N'1', 30, 365, N'2018-03-14 11:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (5, 5, 3000, 18, N'a@b.com', N'0', N'1', N'a', N's', N's', N'1', 1, 1, CAST(40.00 AS Decimal(9, 2)), N'1', 45, 330, N'2018-03-13 12:00:00')

【问题讨论】:

  • 无法在我的本地创建示例数据:外键“FK_Application_ToTable”引用无效表“dbo.Applicant”。
  • 为什么您希望 id 2 和 4 返回? '2018-03-14T16:00:00.000''2018-03-14T11:00:00.000'AFTER '2018-03-14T00:00:00.000',因此不符合您的 WHERE 子句的要求(实际上是 BETWEEN '2018-02-13T00:00:00.000' AND '2018-03-14T00:00:00.000'
  • 由于您的日期逻辑,您已过滤掉 3 月 14 日的行。这是您的谓词值。选择 CAST(GETDATE()-30 AS 日期)、CAST(GETDATE()-1 AS 日期)。顺便说一句,您应该小心使用数学与日期。最好使用 DATEADD。 sqlblog.org/2011/09/20/…
  • 或者只是 CAST CreatedOn 到一个日期。
  • @ErayBalkanli - 抱歉,我以为我已经摆脱了它。已修改。

标签: sql sql-server sql-server-2014


【解决方案1】:

您可以将CAST 您的CreatedOn 字段作为DATE 删除时间部分,这会妨碍您在这里...

也许

WHERE CAST(CreatedOn AS DATE) BETWEEN CAST(GETDATE()-30 AS date) AND CAST(GETDATE()-1 AS date)

但是 - CASTing WHERE 表达式中的字段可能 使其不可搜索。见here。因此,除非您知道表达式将是 SARGable,否则请避免在大型或生产环境中使用此解决方案。仅用作改进您的逻辑和选项的测试。 (即使 CreatedOn 上没有显式索引 - 它可能仍然会受到影响,因为如果没有显式存在索引,SQL 会一直构建自己的索引。 总是值得确认它是否是 SARGable,所以你肯定知道。)

查看正在发生的事情 - 在 SELECT 中查看您的值 - 只是为了了解正在发生的事情

例如:

SELECT TOP 1000
CreatedOn 
,CAST(GETDATE()-30 AS date)
,CAST(GETDATE()-1 AS date)
FROM [Application]

或者查看从数据时间字段中删除时间值的其他选项here 因为您可能想要强制或舍入时间值

【讨论】:

  • 不要这样做;将您的列转换为 date 会使查询成为非 SARGable。
  • @Larnu 好点谢谢。我会留下答案,因为它可能会帮助 OP 使用不同的技术通过选项工作......但我会将这一点添加到我的答案中
  • @Larnu 实际上将日期时间转换为日期是少数情况之一,其中 where 谓词中的函数是可搜索的,但并不总是一个好主意。 dba.stackexchange.com/questions/34047/…
【解决方案2】:

试试这个:

WHERE 
    CreatedOn >= CAST(GETDATE()-30 AS date) AND 
    CreatedOn < CAST(GETDATE() AS date)

问题是您转换为前一天的日期。

【讨论】:

  • @JuanCarlosOropeza 这里的用户没有使用过CAST(GETDATE()-1 AS date)。他们的查询中没有-1。 (他们使用了正确的语法并使用了&gt;=,然后使用了&lt;)。
  • @Larnu 我不知道你在说什么,但我认为这不对。 OP 发布的查询肯定在其 where 子句中显示了该确切表达式。
  • @JacobH 在 Juan 提供的链接中,他们有 CAST(GETDATE()-1 AS date) as dt3。这不是 Ezequiel 使用的语法。 (我的评论是关于答案的,因为我们在答案的 cmets 中,而不是问题;))
  • @Larnu 是的,我还没关注你。唯一的区别是列别名。 Juan 说“这就是你要调试的方式”。
  • @JacobH 是的,我的错。我应该明确 Ezequiel 的答案是正确的,我的测试代码是向 OP 展示为什么他的答案首先不起作用。
【解决方案3】:

不要试图忽略时间价值,只需确保您的搜索词对其准确无误。另外,不要盲目地将ISNULL 之类的内容添加到每一列。花几秒钟思考它是否相关。例如,NEWID() 永远不会向您返回 NULL 值。添加这种代码是糟糕的编程,这将导致代码的可读性降低。

我会这样写来说明时间部分:

CREATE VIEW dbo.ApplicantStat
AS
SELECT
    CONVERT(VARCHAR(50), NEWID()) AS ID,
    COALESCE(AVG(ApplicationTime), 0) AS AvgApplicationTime,
    COALESCE(AVG(ResponseTime), 0) AS AvgResponseTime,
    COALESCE(CAST(COUNT(CASE WHEN [IsAccepted] = 1 THEN 1 END) / COUNT(CASE WHEN [IsValid] = 1 THEN 1 END) AS float), 0) AS PctAccepted
FROM
    dbo.Application
WHERE
    CreatedOn >= DATEADD(DAY, -30, CAST(GETDATE() AS DATE)) AND
    CreatedOn <  CAST(GETDATE() AS DATE)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    相关资源
    最近更新 更多