2017-07-28 2 views
1

Je me demande si vous pouvez m'aider s'il vous plaît? Je suis nouveau à SQL et je suis vraiment aux prises avec cette requête. J'ai regardé autour de moi, mais étant nouveau, je me suis vite embrouillé!Création d'une requête SQL pour combiner plusieurs lignes liées ensemble

J'ai hérité d'un tableau d'adresses différentes pour un groupe de clients professionnels. La table est sur un serveur Oracle 12c et j'utilise SQL Developer.

Je souhaite ajouter ces informations à la fin d'une autre requête afin que les utilisateurs puissent voir plus facilement toutes les informations pertinentes pour un seul client dans le rapport final.

Le tableau est aménagé comme ceci:

| CUST_ID | ADDRESS_TYPE | CONTACT_NAME | ADDRESS | CITY | ... | 
------------------------------------------------------------------ 
|  1000|   SITE |  A SMITH | A ROAD | A TOWN | 
|  1000|  BUILDER |  B JONES | B ROAD | B TOWN | 
|  1000| ARCHITECT |  A BROWN | C ROAD | A CITY | 
|  1001|   SITE |  B SMITH | A LANE | C TOWN | 
|  1001| ARCHITECT |  D BROWN | D ROAD | B CITY | 
|  1002|   SITE |  E SMITH | B LANE | D TOWN | 
|  1002| ARCHITECT |  C JONES | B ROAD | A CITY | 
|  1002|  BUILDER |  F SMITH | C LANE | B TOWN | 

Ce que je voudrais créer est:

| CUST_ID | SITE_NAME | SITE_ADDRESS | SITE_TOWN | BUILDER_NAME | BUILDER_ADDRESS | BUILDER_TOWN | ... | 
| 1000 | A SMITH |  A ROAD | A TOWN |  B JONES |   B ROAD |  B TOWN | ... | 
| 1001 | B SMITH |  A LANE | A TOWN |   NULL |   NULL |   NULL | ... | 
| 1002 | E SMITH |  B LANE | D TOWN |  F SMITH |   C LANE |  B TOWN | ... | 

Il y a 3 ADDRESS_TYPE que je suis intéressé par: SITE, BUILDER et ARCHITECT. Donc, plutôt que d'avoir une ligne par ADDRESS_TYPE par CUST_ID, je voudrais obtenir une ligne par CUST_ID avec les informations d'adressage pour chaque ADDRESS_TYPE comme colonnes supplémentaires. J'utiliserais le CUST_ID pour joindre le résultat à une autre requête.

Je ne sais pas si je devrais essayer quelque chose avec plusieurs jointures ou si je peux faire une sorte de sous-requête?

Merci beaucoup pour votre temps et votre aide, j'apprécie vraiment!

Répondre

1

Vous pouvez également utiliser les jointures

SELECT 
    BASE.CUST_ID, 
    SITE.CONTACT_NAME AS SITE_NAME, 
    SITE.ADDRESS AS SITE_ADDRESS, 
    SITE.CITY AS SITE_CITY, 
    BUILDER.CONTACT_NAME AS BUILDER_NAME, 
    BUILDER.ADDRESS AS BUILDER_ADDRESS, 
    BUILDER.CITY AS BUILDER_CITY, 
    ARCHITECT.CONTACT_NAME AS ARCHITECT_NAME, 
    ARCHITECT.ADDRESS AS ARCHITECT_ADDRESS, 
    ARCHITECT.CITY AS ARCHITECT_CITY 
FROM (SELECT DISTINCT CUST_ID FROM TABLE_YOU_DID_NOT_NAME) BASE 
LEFT JOIN TABLE_YOU_DID_NOT_NAME SITE ON BASE.CUST_ID = SITE.CUST_ID AND SITE.ADDRESS_TYPE = 'SITE' 
LEFT JOIN TABLE_YOU_DID_NOT_NAME BUILDER ON BASE.CUST_ID = BUILDER.CUST_ID AND BUILDER.ADDRESS_TYPE = 'BUILDER' 
LEFT JOIN TABLE_YOU_DID_NOT_NAME ARCHITECT ON BASE.CUST_ID = ARCHITECT.CUST_ID AND ARCHITECT.ADDRESS_TYPE = 'ARCHITECT' 
+0

Merci Hogan, je ne savais pas si les jointures étaient une bonne chose à utiliser pour référencer la même table encore et encore. Je pensais que ça pourrait être vraiment inefficace mais maintenant je sais que je vais essayer! Merci encore pour votre aide – Nikkunaku

+0

@Nikkunaku - en fonction de la taille de la table et des index définis et cela peut être plus rapide que l'utilisation de l'agrégation – Hogan

+0

J'ai finalement essayé les deux méthodes et votre version de jointure a obtenu 380k résultats en 1.74 secondes contre un peu moins de 10 secondes pour la méthode agrégée conditionnelle. Changé le vôtre à la réponse car il est plus facile de voir ce qui se passe et beaucoup plus vite. Merci encore pour votre aide: D – Nikkunaku

1

Vous pouvez utiliser l'agrégation conditionnelle:

select cust_id, 
     max(case when address_type = 'Site' then Contact_Name end) as site_name, 
     max(case when address_type = 'Site' then Town end) as site_town, 
     max(case when address_type = 'Site' then Address end) as site_address, 
     max(case when address_type = 'Builder' then Contact_Name end) as builder_name, 
     max(case when address_type = 'Builder' then Town end) as builder_town, 
     max(case when address_type = 'Builder' then Address end) as builder_address, 
     . . . 
from t 
group by cust_id; 
+0

Oooh c'est totalement nouveau pour moi, merci! Ça a marché et ça a marché très vite! Merci pour votre aide Gordon, je vais ajouter des agrégats conditionnels à ma liste de choses pour en savoir plus sur: D – Nikkunaku

0

Ou vous pouvez utiliser PIVOT (Juste pour être exhaustif dans les différentes solutions)

Link to SQLFiddle

select * from addresses 
pivot ( 
    MAX(CONTACT_NAME) CONTACT_NAME, 
    MAX(ADDRESS) ADDRESS, 
    MAX(CITY) CITY 
    FOR ADDRESS_TYPE IN ('SITE','BUILDER','ARCHITECT')); 

@OP: Je serais curieux de connaître l'heure. Je suppose que doit être comme la méthode d'agrégation