2010-11-29 11 views
5

No puedo pensar en este. Tengo esta consulta:Ayuda de consulta SQL con duplicados no exclusivos

SELECT 
    p.person_id, 
    p.first_nm, 
    p.last_nm, 
    pu.purchase_dt, 
    pr.sku, 
    pr.description, 
    a.address_type_id, 
    a.city_cd, 
    a.state_cd, 
    a.postal_cd 
FROM 
    person p 
    INNER JOIN address a ON p.person_id = a.person_id 
    INNER JOIN purchase pu ON pu.person_id = p.person_id 
    INNER JOIN product pr ON pr.product_id = pu.product_id 

Bastante simple, solo necesito obtener la información de los clientes a los que les enviamos devoluciones. Sin embargo, a causa de la tabla AddressType

AddressType 

address_type_id address_type_desc 
------------------------------------ 
1   Home 
2   Shipping 

algunos clientes tienen múltiples direcciones en la tabla de direcciones, la creación de entradas duplicadas no únicos como este.

1,Smith, John, 12/01/2009, A12345, Purple Widget, 1, Anywhere, CA, 12345 
1,Smith, John, 12/01/2009, A12345, Purple Widget, 2, Somewhere, ID, 54321 

me gustaría obtener la consulta para devolver sólo una fila/persona y devolver la dirección de su casa si está disponible en caso contrario, devolver la dirección de envío.

Esto parece bastante simple, y tal vez solo sea mi resfriado, pero esto me está haciendo rascar la cabeza.

+0

¿Qué motor DB? – Lex

+0

Y cuántas direcciones pueden ser: 0..N, 1..N o 1..2? – Lex

Respuesta

5
SELECT 
    p.person_id, 
    p.first_nm, 
    p.last_nm, 
    pu.purchase_dt, 
    pr.sku, 
    pr.description, 
    COALESCE(ha.address_type_id, sa.address_type_id) AS address_type_id 
    CASE WHEN ha.address_type_id IS NOT NULL THEN ha.city_cd ELSE sa.city_cd END AS city_cd, 
    CASE WHEN ha.address_type_id IS NOT NULL THEN ha.state_cd ELSE sa.state_cd END AS state_cd, 
    CASE WHEN ha.address_type_id IS NOT NULL THEN ha.postal_cd ELSE sa.postal_cd END AS postal_cd 
FROM 
    person p 
    LEFT JOIN address ha ON p.person_id = ha.person_id AND ha.address_type_id = 1 
    LEFT JOIN address sa ON p.person_id = sa.person_id AND sa.address_type_id = 2 
    INNER JOIN purchase pu ON pu.person_id = p.person_id 
    INNER JOIN product pr ON pr.product_id = pu.product_id 
6

que desee cambiar su unen por lo que devuelve el min (AddressID) en lugar de todos ellos:

 INNER JOIN address a ON p.person_id = a.person_id 
     inner join (select person_id, min(address_type_id) as min_addr 
from address group by person_id) a_min 
on a.person_id = a_min.person_id and a.address_type_id = a_min.min_addr 
1

Si SQL Server, u otra versión con expresiones de tabla común (CTE), que podría hacer lo siguiente. El CTE agrega una columna de número de fila que está agrupada por persona y ordenada por la dirección_type_id. La consulta principal se altera para devolver la fila número 1 para cada persona del CTE.

WITH cte AS 
    (
    SELECT 
     a.person_id, 
     a.address_type_id, 
     a.city_cd, 
     a.state_cd, 
     a.postal_cd, 
     ROW_NUMBER() over (PARTITION BY person_id ORDER BY address_type_id) AS sequence 
    FROM address a 
    INNER JOIN AddressType at ON a.address_type_id = at.address_type_id 
    ) 

    SELECT 
     p.person_id, 
     p.first_nm, 
     p.last_nm, 
     pu.purchase_dt, 
     pr.sku, 
     pr.description, 
     a.address_type_id, 
     a.city_cd, 
     a.state_cd, 
     a.postal_cd 
    FROM 
     person p 
     INNER JOIN cte a ON p.person_id = a.person_id 
     INNER JOIN purchase pu ON pu.person_id = p.person_id 
     INNER JOIN product pr ON pr.product_id = pu.product_id 
    WHERE 
     a.sequence = 1 

Por cierto, si tiene registros de personas que no tienen direcciones, es posible que desee cambiar en la unión interna de una combinación externa en la tabla de direcciones (CTE en mi respuesta). Esto también puede ser apropiado para combinaciones para comprar y producto si sus requisitos así lo indican.