Come gestire il MERGE tra dataset con l’opzione IN =

Ok, devi unire la tabella dei clienti con quella degli ordini selezionando solo i clienti che non hanno effettuato ordini e non sai come fare? È molto semplice cavarsela in questa e molti altre situazioni simili utilizzando l’opzione IN= dei dataset che vuoi unire con lo statement MERGE. Come si fa? Ti illustro 7 esempi.

Supponiamo di avere due tabelle:

tab1 tab2

Nella prima sono registrati i nomi di alcuni dei nostri migliori amici, nella seconda qualche informazione anagrafica che li riguarda.

Avrai forse notato che le due tabelle hanno una variabile in comune: “CODICE”. Utilizzeremo proprio questa variabile come chiave per unire i due dataset per mezzo dello statement MERGE.

Prima  di cominciare, occorre fare due precisazioni. Quando vogliamo utilizzare lo statement MERGE per unire due (o più dataset) per mezzo di una chiave in comune occorre che:

  1. tutti i dataset siano ordinati per quella chiave (oppure abbiamo un indice su quella chiave…ma di questo parleremo in un altro post…😉 ). Se così non è, occorre ordinarli prima di procedere ad unirli.
  2. la variabile utilizzata per come chiave deve avere lo stesso in tutti i dataset. Se così non è occorre rinominarla prima di effettuare il merge.

I nostri due dataset soddisfano entrambe le condizioni quindi siamo pronti per cominciare con i nostri esperimenti.

Vogliamo utilizzare lo statement MERGE per unire le due tabelle e selezionare…

Caso 1 – Tutte le osservazioni appartenenti a TAB1

Tecnicamente, parliamo di LEFT OUTER JOIN in quanto desideriamo che il MERGE restituisca tutte le chiavi presenti nella TAB1 (…che metteremo “a sinistra” nell’elenco delle tabelle da unire, di qui il termine LEFT) indipendentemente dal fatto che siano presenti o meno nella TAB2. Possiamo ricorrere ai digrammi di Venn per dare una rappresentazione visuale a questo concetto:

left-join

Bene, siamo fortunati, perché realizzare questa cosa in SAS è straordinariamente facile grazie all’utilizzo combinato dello statement MERGE, dell’opzione IN= e di un istruzione IF.

Ecco il codice SAS da utilizzare in un caso come questo:

data TABELLA_UNITA;
   merge tab1 (IN = A)
         tab2;
   by codice;
   IF A;
run;

e questo è il risultato:

Merge_Left_join

Come vedi, nella tabella di output sono presenti tutte le chiavi presenti nella TAB1 (i codici 1, 3 e 4) indipendentemente dal fatto che siano presenti o meno nella TAB2. PAPERINO, ad esempio, non è presente in TAB2 ma è comunque presente nella tabella finale…ma, ovviamente, senza informazioni anagrafiche annesse.

Viceversa, avendo chiesto tutte le osservazioni appartenenti a TAB1, il codice 2, presente in TAB2 ma assente in TAB1, non risulta nella tabella finale.

Ora, analizziamo velocemente il codice per capire in che modo è stato ottenuto questo risultato.

Avrai notato che nello statement MERGE in corrispondenza di TAB1 ho inserito un’opzione (IN = A). In questo modo, ho “istruito” SAS su quali fossero le osservazioni “appartenenti” al dataset TAB1. L’opzione IN = A, infatti, ha fatto sì che SAS si creasse nel PDV, una variabile temporanea A che assume il valore 1 in corrispondenza delle osservazioni di TAB1, il valore 0 altrimenti.

La variabile A è, come detto, temporanea (infatti non ho dovuto “dropparla” nell’ambito del passo di data) e, inoltre, avrei potuto chiamarla in qualsiasi altro modo rispettoso della naming convention di SAS per i nomi delle variabili. Diciamo che A, in questo caso, è un nome di variabile adeguato per un programmatore pigro come me che ama scrivere codici “sintetici” 😊.

Fatto questo, un paio di righe di codice più sotto, ho potuto sfruttare un IF subsetting per selezionare le osservazioni appartenenti a TAB1 (e per le quali A = 1).

Infatti, scrivere:

IF A;

equivale a scrivere:

IF A = 1;

e anche, volendo essere più “espliciti”, a scrivere:

IF A = 1 THEN OUTPUT;

il ché è come dire a SAS:  “scrivi nel dataset di output solo le osservazioni per le quali la variabile A = 1“, ossia quelle appartenenti a TAB1.

OK, se tutto è chiaro fin qui, affrontare gli altri casi possibili sarà un passeggiata…proseguiamo.

Caso 2 – Tutte le osservazioni appartenenti a TAB2

Tecnicamente, parliamo di RIGHT OUTER JOIN in quanto desideriamo che il MERGE restituisca tutte le chiavi presenti nella TAB2 indipendentemente dal fatto che siano presenti o meno nella TAB1:

right-join

Anche in questo caso, sulla falsariga del precedente, utilizzeremo l’opzione IN = in combinazione con un IF subsetting, per ottenere il risultato desiderato:

data TABELLA_UNITA; 
   merge tab1
         tab2 (IN = B);
   by codice;
   IF B;
run;

e questo è il risultato:

Merge_Right_join

Come vedi, nella tabella di output sono presenti tutte le chiavi presenti nella TAB2 (i codici 1, 2 e 3) indipendentemente dal fatto che siano presenti o meno nella TAB1. Il codice 2, ad esempio, non è presente in TAB1 ma è comunque presente nella tabella finale…ma, ovviamente, in maniera “anonima”.

Viceversa, avendo chiesto tutte le osservazioni appartenenti a TAB2, PAPERINO, presente in TAB1 ma assente in TAB2, non risulta nella tabella finale.

Caso 3 – Tutte le osservazioni appartenenti sia a TAB1 che a TAB2

Qui vogliamo ottenere un INNER JOIN in quanto desideriamo che il MERGE restituisca solo le chiavi presenti in entrambe le tabelle:

inner-join

Il codice da utilizzare in un caso questo potrebbe essere del tipo:

data TABELLA_UNITA; 
   merge tab1 (IN = A)
         tab2 (IN = B);
   by codice;
   IF A and B;
run;

e questo è il risultato che si otterrebbe:

Merge_Inner_join

Come vedi, nella tabella di output sono presenti solo le chiavi presenti sia nella TAB1 che nella TAB2 (i codici 1, e 3) .

Andiamo avanti.

Caso 4 – Tutte le osservazioni che appartengano a TAB1 o a TAB2 indifferentemente

Questo è un caso diverso dal precedente, in quanto vogliamo che nell’output finale siano presenti tutte le osservazioni delle due tabelle di input, indipendentemente dal fatto che appartengano ad una sola di esse o ad entrambe. Tecnicamente si parla di FULL OUTER JOIN :

full-join

Il codice da utilizzare in un caso questo potrebbe essere del tipo:

data TABELLA_UNITA; 
   merge tab1 
         tab2 ;
   by codice;
run;

e questo è il risultato che si otterrebbe:

Merge_Full_join

Esattamente quello che volevamo.

Ma, ritorniamo per un attimo al codice utilizzato. Noti qualcosa di “strano”? In effetti, qui non abbiamo utilizzato né l’opzione IN= né l’istruzione IF subsetting.

Beh, non lo abbiamo fatto perché, se ci pensi, non ne abbiamo bisogno: dato che vogliamo in output TUTTE le osservazioni dei dataset di input…non c’è bisogno di “marcarle” in qualche modo particolare (con l’opzione IN=) per poi selezionarle (con un IF subsetting).

Comunque, se proprio avessimo voluto uniformaci al codice scritto negli esempi precedenti, avremmo potuto utilizzare il seguente script:

data TABELLA_UNITA; 
   merge tab1 (IN = A)
         tab2 (IN = B);
   by codice;
   IF A or B;
run;

Caso 5 – Tutte le osservazioni che appartengano a TAB1 ma non a TAB2

Questo è un caso simile al primo. Tuttavia qui vogliamo selezionare tutte le osservazioni di TAB1 ad esclusione di quelle che sono presenti anche in TAB2:

exclleft-join

Scommetto che ormai sei sufficientemente esperto per capire che il codice da utilizzare in questo caso è:

data TABELLA_UNITA; 
   merge tab1 (IN = A)
         tab2 (IN = B);
   by codice;
   IF A AND NOT B;
run;

Questo è il risultato:

Merge_Left_Anti_join

Caso 6 – Tutte le osservazioni che appartengano a TAB2 ma non a TAB1

Possiamo dire che questo è il caso “opposto” al precedente. Qui vogliamo selezionare tutte le osservazioni di TAB2 ad esclusione di quelle che sono presenti anche in TAB1:

exclright-join

Il codice da utilizzare in questo caso è:

data TABELLA_UNITA; 
   merge tab1 (IN = A)
         tab2 (IN = B);
   by codice;
   IF B AND NOT A;
run;

Questo è il risultato:

Merge_Right_Anti_join

Caso 7 – Tutte le osservazioni che non appartengano sia a TAB1 sia a TAB2

Infine, analizziamo il caso in cui si desideri avere tutte le osservazioni che non appartengano ad entrambe le tabelle TAB1 e TAB2:

exclfull-join

di fatto, si tratta del “complemento” dell’INNER JOIN che abbiamo visto nel caso 3. Il codice da utilizzare in questo caso è:

data TABELLA_UNITA; 
   merge tab1 (IN = A)
         tab2 (IN = B);
   by codice;
   IF NOT (A AND B);
run;

Se ci fai caso, in effetti, si tratta della “negazione” dell’INNER JOIN visto sopra. Questo è il risultato:

Merge_Anti_join

Ecco conclusa la disamina delle varie possibilità di JOIN “a chiave” effettuabili per mezzo dello statement MERGE. I casi che abbiamo visto riguardavano tutti una situazione “semplice” di relazione 1:1 tra le due tabelle. Ovviamente, i concetti espressi valgono anche per situazioni in cui la relazione tra le tabelle è del tipo 1:N…ma anche di questo parleremo in un altro post…

SAS e tutti gli altri nomi di prodotti e servizi di SAS Institute Inc. sono marchi registrati di SAS Institute Inc. negli USA e in altri paesi. ® indica la registrazione negli USA.

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...