我正在编写一些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
编辑:实际上,我需要对报告中的不同选项使用这两种方法。要澄清的是,我的问题的症结在于,是否有人可以告诉我为什么对于总返回的不同行数,这两个查询将返回不同的“负载”总数?
答案 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,我建议您实施。