按日期sql查询不会返回与日期范围相同范围内的日期sql查询相同的结果

时间:2018-12-05 18:34:35

标签: sql sql-server

我正在编写一些SQL创建报告。就报告而言,我需要按天获取结果,而不是整个日期范围内的结果。但是,对于许多数据样本,实际上我得到的结果略有不同(按日计算的结果始终是较大的值)。也许有人可以阐明我所缺少的一些极端情况。据我所知,两个查询都覆盖了完全相同的时间段。

按天:

DECLARE @VarDate Datetime;
   SET @VarDate = '2018-07-01';
   WHILE @VarDate <= '2018-07-05'
   BEGIN
      IF EXISTS(SELECT CName, OrderNum, ODescription,
    PDescription, SUM(Qty) as TotalQty, Count(Qty) as Loads
    FROM TICKET
    WHERE TicketDate BETWEEN @VarDate + '00:00:00.00'
    AND @VarDate + '23:59:59.999' GROUP BY CName, OrderNum, ODescription, PDescription)
        SELECT CName, OrderNum, ODescription,
    PDescription, SUM(Qty) as TotalQty, Count(Qty) as Loads
    FROM TICKET
    WHERE TicketDate BETWEEN @VarDate + '00:00:00.00'
    AND @VarDate + '23:59:59.999' GROUP BY CName, OrderNum, ODescription, PDescription
   ELSE
      SELECT @VarDate as Date;
      SET @VarDate = DATEADD(DAY, 1, @VarDate);
   END

常规日期范围:

SELECT CName, OrderNum, ODescription, PDescription,
       SUM(Qty) as TotalQty, Count(Qty) as Loads
    from TICKET WHERE TicketDate BETWEEN '2018-07-01 00:00:00.00'
     AND '2018-07-05 23:59:59.999' GROUP BY CName, OrderNum, ODescription, PDescription

编辑:实际上,我需要对报告中的不同选项使用这两种方法。要澄清的是,我的问题的症结在于,是否有人可以告诉我为什么对于总返回的不同行数,这两个查询将返回不同的“负载”总数?

3 个答案:

答案 0 :(得分:1)

实际问题是SQL Server将'23:59:59.999'向上取整,因此将'00:00:00.000'计数了两次,这就是对这些值进行了两次计数,因此是较大的值。不确定SQL为什么将数字四舍五入,但是我希望这对某人有帮助。

答案 1 :(得分:0)

如果您需要日期范围之间的每日结果,则无需进行WHILE操作。另外,您将如何呈现此报告?

据我了解,我已经创建了一个示例:

DECLARE @DateFrom   DATETIME='2018-07-01';
DECLARE @DateTo     DATETIME='2018-07-05';

SELECT    CName
        , OrderNum
        , ODescription
        , PDescription
        , CAST(TicketDate AS DATE)
        , SUM(Qty) as TotalQty
        , Count(Qty) as Loads
FROM TICKET
WHERE CAST(TicketDate AS DATE) BETWEEN @DateFrom and @DateTo
GROUP BY  CName
        , OrderNum
        , ODescription
        , PDescription
        , CAST(TicketDate AS DATE);

答案 2 :(得分:0)

我无法重复这个问题,但是,如果您的目标是每个日期都有一行,那么可能的答案是这里的最后一个例子。这三种方法均给出不同的结果。第一个(WHILE)给出了每天的数据集;可能远非理想。 WHILE也是(在很多人看来)最糟糕的解决方案,因为它是针对专门为基于数据集的任务设计的产品上的迭代任务(不是迭代任务)。第二个使用BETWEEN给出一个数据集,但仅适用于表中显示的日期。即使日期不在表中,最后一个也会为日期范围内的每个日期提供一行。

CREATE TABLE dbo.SomeTable (ID int IDENTITY(1,1),
                            SomeDate date,
                            SomeNumber int);
INSERT INTO dbo.SomeTable (SomeDate,SomeNumber)
VALUES ('20181201',12),
       ('20181201',10),
       ('20181203',9),
       ('20181204',8),
       ('20181205',1),
       ('20181205',19);

GO

--Cursor
DECLARE @StartDate date, @EndDate date, @CurrDate date;
SET @StartDate = '20181201';
SET @EndDate = '20181205';
SET @CurrDate = @StartDate;

WHILE @CurrDate <= @EndDate BEGIN
    SELECT SomeDate,
           SUM(SomeNumber) AS TotalSomeNumber
    FROM dbo.SomeTable
    WHERE SomeDate = @CurrDate
    GROUP BY SomeDate;

    SET @CurrDate = DATEADD(DAY, 1, @CurrDate);
END

GO

--BETWEEN

DECLARE @StartDate date, @EndDate date;
SET @StartDate = '20181201';
SET @EndDate = '20181205';

SELECT SomeDate,
        SUM(SomeNumber) AS TotalSomeNumber
FROM dbo.SomeTable
WHERE SomeDate BETWEEN @StartDate AND @EndDate
GROUP BY SomeDate;

GO
--Calendar Table
DECLARE @StartDate date, @EndDate date;
SET @StartDate = '20181201';
SET @EndDate = '20181205';

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 AS I
    FROM N),
Dates AS(
    SELECT DATEADD(DAY, I, @StartDate) AS [Date]
    FROM Tally
    WHERE DATEADD(DAY, I, @StartDate) <= @EndDate)
SELECT D.[Date] AS SomeDate,
       ISNULL(SUM(SomeNumber),0) AS TotalSomeNumber
FROM Dates D
     LEFT JOIN dbo.SomeTable ST ON D.[Date] = ST.SomeDate
GROUP BY D.[Date];


GO
DROP TABLE dbo.SomeTable;

值得注意的是,在此示例中,我即时创建了日历“表”。您可能希望在SQL Server上创建一个带有日期的表。关于如何创建一个例子,这里有100多个例子。它们是DBMS的主要内容,如果您还没有DBMS,我建议您实施。