简体   繁体   English

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

[英]By day sql query not returning same results as a date range sql query over same range

I am writing some sql to create reports. 我正在写一些SQL创建报告。 For the purpose of the reports, I need to get results by day, vs results over the entire date range. 就报告而言,我需要按天获取结果,而不是整个日期范围内的结果。 However, for many data samples, I am actually getting slightly different results (with the by day results always being the larger value). 但是,对于许多数据样本,实际上我得到的结果略有不同(按日计算的结果始终是较大的值)。 Perhaps someone can elucidate an edge case I am missing or some such. 也许有人可以阐明我所缺少的一些极端情况。 From what I can tell both queries cover the exact same time period. 据我所知,两个查询都覆盖了完全相同的时间段。

By Day: 按天:

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

Regular Date Range: 常规日期范围:

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

EDIT: I actually need to use both of these methods for different options in the report. 编辑:我实际上需要在报表中的不同选项中使用这两种方法。 To clarify, the crux of my question is if anyone can tell me why these two queries would return different "Loads" totals for a different count of rows returned in total aggregate? 需要澄清的是,我的问题的症结在于,是否有人可以告诉我为什么对于总计返回的不同行数,这两个查询将返回不同的“负载”总数?

The actual issue was SQL Server was rounding '23:59:59.999' up, and thus counting '00:00:00.000' twice, which is what was counting these values twice, hence the larger values. 实际的问题是SQL Server将'23:59:59.999'向上取整,因此对'00:00:00.000'进行了两次计数,这就是对这些值进行了两次计数,因此是较大的值。 Not sure why the SQL is rounding the number up, but I hope this helps someone. 不确定SQL为什么将数字四舍五入,但是我希望这对某人有帮助。

If you need daily result between date range, you don't need to do WHILE. 如果您需要日期范围之间的每日结果,则无需进行WHILE操作。 Also, how you will present this report? 另外,您将如何呈现此报告?

As much as I understand I have created a sample : 据我了解,我已经创建了一个样本:

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);

I can't replicate the issue, however, if your goal is to have a row for every date, then the likely answer is the final example here. 我无法重复这个问题,但是,如果您的目标是每个日期都有一行,那么可能的答案是这里的最后一个示例。 All 3 of these methods give different results. 这三种方法均给出不同的结果。 The first (a WHILE ) gives a dataset for each day; 第一个( WHILE )提供了每天的数据集; likely far from ideal. 可能远非理想。 The WHILE is also (in many people's opinion) the worst solution here as it is an iterative task on a product designed specifically for dataset based tasks (which an iterative task is not). WHILE也是(在很多人看来)最糟糕的解决方案,因为它是针对专门为基于数据集的任务(不是迭代任务)设计的产品上的迭代任务。 The second, using BETWEEN gives a single dataset, but only for days that appear in the table. 第二个,使用BETWEEN给出单个数据集,但仅适用于表中显示的日期。 The last gives a row for every date in the date range, even if they are not in the table. 即使日期不在表中,最后一个也会为日期范围内的每个日期提供一行。

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;

It is worth noting that I created the Calendar "table" on the fly in this example. 值得注意的是,在此示例中,我即时创建了日历“表”。 You would likely want to create a table with dates on your SQL Server. 您可能希望在SQL Server上创建一个带有日期的表。 There are 100's of examples on out there on how to create one. 关于如何创建一个例子,这里有100多个例子。 They are a staple for a DBMS, and I suggest implementing one if you don't already have one. 它们是DBMS的主要内容,如果您还没有DBMS,我建议您实施它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM