使用DATEDIFF函数减去日期并获得NULL作为结果

时间:2018-09-09 08:05:55

标签: sql sql-server

所以我的任务是查找每个订单的延迟时间(以周为单位)。我使用过DATEDIFF函数,但我想我走在正确的轨道上,但是当我使用它时,得到的结果就是NULL。每列的数据类型均为日期。

SELECT DISTINCT Sales.Orders.custid, Sales.Customers.companyname,
CASE
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 7 AND  DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 14 THEN '1 Week'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 14 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 21 THEN '2 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 21 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 28 THEN '3 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 28 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 35 THEN '4 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 35 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 42 THEN '5 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 42 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 49 THEN '6 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) > 49 THEN '7+ Weeks'
    ELSE 'Unknown'
END AS Order_Delay
FROM Sales.Orders, Sales.Customers
ORDER BY 
Order_Delay ASC;

我正在使用MS SQL Server Management Studio 2016。

4 个答案:

答案 0 :(得分:2)

FROM Sales.Orders, Sales.Customers是形成cross join的老式方法。这可能是偶然的,但是这样做对性能的影响可能是可怕的,但结果可能是完全错误的-在您的示例中。因此,我始终建议您使用显式联接语法(例如inner join使用逗号停止作为定义from子句的方式。

您只需要正确地连接2个表,否则每个订单都将应用到每个客户,结果将是非常错误的。我猜想该联接,但是它看起来应该类似于下面看到的联接:

SELECT /* DISTINCT ?? */
    Sales.Orders.custid
  , Sales.Customers.companyname
  , CASE
        WHEN ca.Order_Delay >= 7 THEN '7+ Weeks'
        WHEN ca.Order_Delay >= 1 AND ca.Order_Delay < 7 THEN CAST(ca.Order_Delay AS varchar) + ' Weeks'
        ELSE 'Unknown'
    END AS order_delay
FROM Sales.Orders AS o
INNER JOIN Sales.Customers AS c ON o.custid = c.id
CROSS APPLY (
    SELECT
        FLOOR(DATEDIFF(DAY, o.shippeddate, o.orderdate) / 7)
    ) ca (order_delay)
ORDER BY
    order_delay ASC
;

在SQL Server中,可以使用cross apply作为执行计算的方式,并为该计算提供一个别名,然后可以在select子句中使用它。这样可以使您的代码更易于阅读,但这是可选的。

以上,我建议了一种使用floor()的方法,您应该在此处阅读以下内容: https://docs.microsoft.com/en-us/sql/t-sql/functions/floor-transact-sql?view=sql-server-2017

nb:如果要显示未发货订单的数据,则可能需要更改为outer apply,如果未发货订单,则datediff()函数将返回NULL,而您的{{1 }}需要显式地满足NULL

case expression

答案 1 :(得分:1)

尝试像这样重写查询:

SELECT DISTINCT Sales.Orders.custid, Sales.Customers.companyname,
CASE
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) >= 7 AND  DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 14 THEN '1 Week'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 21 THEN '2 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 28 THEN '3 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 35 THEN '4 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 42 THEN '5 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 49 THEN '6 Weeks'
    WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) >= 49 THEN '7+ Weeks'
    ELSE 'Unknown'
END AS Order_Delay
FROM Sales.Orders, Sales.Customers
ORDER BY 
Order_Delay ASC;

我认为您想检查差异是否在特定范围内(从7到14,等等)。

所以我更正了第一个条件:

WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) >= 7 AND  DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 14 THEN '1 Week'

您不能在此处使用BETWEEN,因为它的范围还包括一组的兄弟。

对于其他情况,您无需检查差异是否大于例如。在第二WHEN中,您知道差异为>=14,因为它在第一个条件下失败,等等。

答案 2 :(得分:1)

https://docs.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql?view=sql-server-2017

  

DATEDIFF(datepart,startdate,enddate)

我的猜测是,您系统中的shippeddate主要是以后或等于orderdate,因此不是

FLOOR(DATEDIFF(DAY, o.shippeddate, o.orderdate) / 7)

您可能想要

FLOOR(DATEDIFF(DAY, o.orderdate, o.shippeddate) / 7)

要检查此假设,您可能想将ca.Order_Delay(按照@Used_by_already建议的代码)添加到所选列的列表中,并查看其中有什么值。我敢打赌,他们都是负面的。

答案 3 :(得分:0)

您要查找的恰好是7、14、21等。您需要> = 7(然后重复其余步骤...)。