2012-03-02 7 views
6
tiempo

Tengo una tabla de pedidos que sé que tienen duplicadosórdenes Encontrar duplicados (por proximidad)

customer order_number order_date 
    ---------- ------------ ------------------- 
      1    1  2012-03-01 01:58:00 
      1    2  2012-03-01 02:01:00 
      1    3  2012-03-01 02:03:00 
      2    4  2012-03-01 02:15:00 
      3    5  2012-03-01 02:18:00 
      3    6  2012-03-01 04:30:00 
      4    7  2012-03-01 04:35:00 
      5    8  2012-03-01 04:38:00 
      6    9  2012-03-01 04:58:00 
      6   10  2012-03-01 04:59:00 

Quiero encontrar todos los duplicados (ordenar antes de un mismo cliente dentro de los 60 minutos de entre si). O un conjunto de resultados que consta de las filas "duplicadas" o un conjunto de todos los clientes con un recuento de cuántos duplicados.

Aquí es lo que he tratado

SELECT 
    customer, 
    count(*) 
FROM 
    orders 
GROUP BY 
    customer, 
    DATEPART(HOUR, order_date) 
HAVING (count(*) > 1) 

Esto no funciona cuando son duplicados dentro de los 60 minutos de diferencia, pero están en diferentes horas es decir, 1:58 y 2:02

I' también hemos probado este

SELECT 
    o1.customer, 
    o1.order_number, 
    o2.order_number, 
    DATEDIFF(MINUTE,o1.order_date, o2.order_date) AS [diff] 
FROM 
    orders o1 LEFT OUTER JOIN 
    orders o2 ON o1.customer = o2.customer AND o1.order_number <> o2.order_number 
WHERE 
    ABS(DATEDIFF(MINUTE,o1.order_date, o2.order_date)) < 60 

Ahora bien, esto me da todos los duplicados, pero también me da múltiples filas por orden duplicado. es decir, (o1, o2) y (o2, o1) que no sería tan malo si no hubiera algunos pedidos con múltiples duplicados. En esos casos obtengo (o1, o2), (o1, o3), (o2, o1), (o2, o3), (o3, o1), (o3, o2) etc. Obtengo todas las permutaciones.

¿Alguien tiene alguna idea? No necesariamente estoy buscando la mejor respuesta, solo una que funcione.

+0

Usted tiene una dependencia en cascada. Si tiene pedidos que ocurren en '(0, 59, 118, 177, 236, etc.) * [todos los 59 minutos appart] *, ¿cuál quiere que sea el resultado de su búsqueda? – MatBailie

+0

@Dems interesante. Consideraría todos esos duplicados. Sin embargo, estaría contento con el resultado en cualquier caso. –

Respuesta

3
SELECT 
    *, 
    CASE WHEN EXISTS (SELECT * 
         FROM orders AS lookup 
        WHERE customer = orders.customer 
         AND order_date < orders.order_date 
         AND order_date >= DATEADD(hour, -1, order_date) 
        ) 
     THEN 'Principle Order' 
     ELSE 'Duplicate Order' 
    END as Order_Status 
FROM 
    orders 

Usando EXISTS y una sub-consulta correlacionada las pueda c diablos si hubo pedidos anteriores en la última hora.

+0

Supone que no hay dos pedidos al mismo tiempo. Puede cambiarse a '<= AND >' en lugar de '< AND > =' y luego agregar 'id MatBailie

+0

Gracias. Tuve que retocar un par de cosas menores, pero conceptualmente esto funciona para mí. Esto es más o menos lo que estaba pensando como una solución, pero después de mirarlo por tanto tiempo me di por vencido. Gracias de nuevo. –

1

Tal vez algo como esto:

datos de prueba:

DECLARE @tbl TABLE(customer INT,order_number INT,order_date DATETIME) 

INSERT INTO @tbl 
VALUES 
    (1,1,'2012-03-01 01:58:00'), 
    (1,2,'2012-03-01 02:01:00'), 
    (1,3,'2012-03-01 02:03:00'), 
    (2,4,'2012-03-01 02:15:00'), 
    (3,5,'2012-03-01 02:18:00'), 
    (3,6,'2012-03-01 04:30:00'), 
    (4,7,'2012-03-01 04:35:00'), 
    (5,8,'2012-03-01 04:38:00'), 
    (6,9,'2012-03-01 04:58:00'), 
    (6,10,'2012-03-01 04:59:00') 

consulta

;WITH CTE 
AS 
(
    SELECT 
     MIN(datediff(minute,'1990-1-1',order_date)) OVER(PARTITION BY customer) AS minDate, 
     datediff(minute,'1990-1-1',order_date) AS DateTicks, 
     tbl.customer 
    FROM 
     @tbl AS tbl 
) 
SELECT 
    CTE.customer, 
    SUM(CASE WHEN (CTE.DateTicks-CTE.minDate)<60 THEN 1 ELSE 0 END) 
FROM 
    CTE 
GROUP BY 
    CTE.customer 
+0

¿Esto solo se compara con el primer pedido? ¿Qué pasa con las órdenes que ocurren en minutos '(0,1,2,65,66,67)'? Los pedidos en '(1,2,66,67)' son duplicados, pero ¿esto no solo encontrará '(1,2)'? – MatBailie

+0

+1 Le doy una oportunidad a mis datos reales, gracias por la respuesta. –

+0

@Dems: no te sigo. Esto tomará el mínimo del grupo de clientes y luego restará la fecha actual. Esto también tomará la fecha completa en minutos (tics). – Arion

1

La siguiente consulta identifica todas las posibles permutaciones de órdenes dentro de la proximidad de 60 minutos el uno del otro:

DECLARE @orders TABLE (CustomerId INT, OrderId INT, OrderDate DATETIME) 

INSERT INTO @orders 
VALUES 
    (1, 1, '2012-03-01 01:58:00'), 
    (1, 2, '2012-03-01 02:01:00'), 
    (1, 3, '2012-03-01 02:03:00'), 
    (2, 4, '2012-03-01 02:15:00'), 
    (3, 5, '2012-03-01 02:18:00'), 
    (3, 6, '2012-03-01 04:30:00'), 
    (4, 7, '2012-03-01 04:35:00'), 
    (5, 8, '2012-03-01 04:38:00'), 
    (6, 9, '2012-03-01 04:58:00'), 
    (6, 10, '2012-03-01 04:59:00'); 

with ProximityOrderCascade(CustomerId, OrderId, ProximateOrderId, MinutesDifference, OrderDate, ProximateOrderDate) 
as 
(
    select o.customerid, o.orderid, null, null, o.orderdate, o.orderdate 
    from @orders o 
    union all 
    select o.customerid, o.orderid, p.orderid, datediff(minute, p.OrderDate, o.OrderDate), o.OrderDate, p.OrderDate 
    from ProximityOrderCascade p 
    inner join @orders o 
     on p.customerid = o.customerid 
     and abs(datediff(minute, p.OrderDate, o.OrderDate)) between 0 and 60 
     and o.orderid <> p.orderid 
    where proximateorderid is null 
) 
select * from ProximityOrderCascade 
where 
    not ProximateOrderId is null 

A partir de ahí, se puede transformar los resultados en una consulta de su elección. Los resultados de esta función identifican solo a los clientes 1 y 6 como pedidos 'duplicados'.

CustomerId OrderId  ProximateOrderId MinutesDifference OrderDate    ProximateOrderDate 
----------- ----------- ---------------- ----------------- ----------------------- ----------------------- 
6   9   10    -1    2012-03-01 04:58:00.000 2012-03-01 04:59:00.000 
6   10   9    1     2012-03-01 04:59:00.000 2012-03-01 04:58:00.000 
1   1   3    -5    2012-03-01 01:58:00.000 2012-03-01 02:03:00.000 
1   2   3    -2    2012-03-01 02:01:00.000 2012-03-01 02:03:00.000 
1   1   2    -3    2012-03-01 01:58:00.000 2012-03-01 02:01:00.000 
1   3   2    2     2012-03-01 02:03:00.000 2012-03-01 02:01:00.000 
1   2   1    3     2012-03-01 02:01:00.000 2012-03-01 01:58:00.000 
1   3   1    5     2012-03-01 02:03:00.000 2012-03-01 01:58:00.000 

(8 row(s) affected) 
Cuestiones relacionadas