Así que tengo la tarea de encontrar el retraso en semanas para cada pedido. He usado la función DATEDIFF y me gustaría creer que estoy en el camino correcto, pero cuando la uso obtengo NULL como resultado. El tipo de datos para cada columna son ambos fecha.

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;

Estoy usando MS SQL Server Management Studio 2016.

0
Icodin 9 sep. 2018 a las 11:05

4 respuestas

La mejor respuesta

Intente reescribir su consulta de esta manera:

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;

Creo que desea verificar si la diferencia está en un rango particular (de 7 a 14, etc.).

Entonces corregí la primera condición:

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

No puede usar BETWEEN aquí, ya que su rango incluye también los ampliadores de un conjunto.

Para otros casos, no necesita verificar si la diferencia es mayor que, por ejemplo. en el segundo WHEN sabes que la diferencia es >=14, ya que falló la primera condición, etc.

1
Michał Turczyn 9 sep. 2018 a las 08:55

Estás buscando exactamente 7, 14, 21, etc. Necesitas> = 7 en su lugar (y repite el resto ...).

0
PKCS12 9 sep. 2018 a las 08:15

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

DATEDIFF (datepart, startdate, enddate)

Supongo que en su sistema shippeddate es principalmente más tarde o igual a orderdate, por lo que en lugar de

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

Podrías querer

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

Para verificar esta suposición, es posible que desee agregar ca.Order_Delay (según el código sugerido por @Used_by_already) a la lista de columnas seleccionadas y ver qué valores hay. Mi apuesta es que todos son negativos.

1
Ivan Starostin 9 sep. 2018 a las 09:30

FROM Sales.Orders, Sales.Customers es una forma anticuada de formar un cross join. Probablemente esto sea accidental, pero el impacto de esto puede ser terrible tanto en términos de rendimiento como de resultados, pero también pueden ser erróneos, y están en su ejemplo. Es por esta razón que siempre recomiendo que use una sintaxis de unión explícita como inner join y deje de usar comas como una forma de definir la cláusula from.

Simplemente tiene que unir correctamente las 2 tablas, de lo contrario, cada pedido se aplica a cada cliente y los resultados serían bastante incorrectos. He adivinado esa unión, pero debería parecerse a la que se ve a continuación:

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
;

En SQL Server es posible usar cross apply como una forma de realizar un cálculo, y darle a ese cálculo un alias que luego puede usar en la cláusula select. Esto puede tener el efecto de hacer que su código sea algo más fácil de leer, pero esto es opcional.

Arriba he sugerido una forma de usar floor() sobre la cual deberías leer aquí: https: //docs.microsoft.com/en-us/sql/t-sql/functions/floor-transact-sql?view=sql-server-2017

Nb: si desea mostrar datos de pedidos no enviados, es posible que deba cambiar a outer apply, y si un pedido no se envía, la función datediff() devolverá NULL y su case expression necesita atender explícitamente NULL

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'
        WHEN ca.Order_Delay IS NULL then 'Unshipped'
        ELSE 'Unknown'
    END AS order_delay
FROM Sales.Orders AS o
INNER JOIN Sales.Customers AS c ON o.custid = c.id
OUTER APPLY (
    SELECT
        FLOOR(DATEDIFF(DAY, o.shippeddate, o.orderdate) / 7)
    ) ca (order_delay)
ORDER BY
    order_delay ASC
;
2
Used_By_Already 9 sep. 2018 a las 08:51