2010-11-29 7 views
5

Je ne peux pas penser à travers celui-ci. J'ai cette requête:Aide de requête SQL avec des doublons non uniques

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 

assez simple - j'ai juste besoin d'obtenir les informations pour les clients que nous avons livré retourne. Toutefois, en raison de la table AddressType

AddressType 

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

certains clients ont plusieurs adresses dans la table d'adresses, en créant des entrées en double non uniques comme celui-ci.

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 

Je voudrais obtenir la requête pour renvoyer une seule ligne/personne et retourner l'adresse du domicile si disponible sinon, retourner l'adresse de livraison.

Cela semble assez simple, et peut-être que c'est juste mon rhume, mais cela me fait me gratter un peu la tête.

+0

Quel moteur DB? – Lex

+0

Et combien d'adresses peuvent être: 0..N, 1..N ou 1..2? – Lex

Répondre

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

vous voulez changer votre rejoindre il retourne le min (AddressID) au lieu de tous:

 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, ou une autre version avec des expressions de table commune (CTE), vous pourrait faire ce qui suit. Le CTE ajoute une colonne de numéro de ligne qui est groupée par personne et triée par l'adresse_type_id. La requête principale est modifiée pour renvoyer la ligne numéro 1 pour chaque personne du 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 

Par ailleurs, si vous avez des enregistrements de personne qui ont aucune adresse, vous pouvez modifier l'INNER JOIN à une OUTER JOIN sur la table des adresses (cte dans ma réponse). Cela peut également être approprié pour les jointures à l'achat et le produit si vos besoins l'indiquent.