2010-06-09 1 views
5

Sto provando a costruire una query PostgreSQL che segue quanto segue, ma finora i miei sforzi sono stati vani.seleziona la riga dalla tabella e sostituisce un campo con una di un'altra colonna se esiste

Problema: ci sono due tabelle: A e B. mi piacerebbe per selezionare tutte le colonne dalla tabella A (con colonne: id, nome, descrizione) e sostituire la colonna "A.name" con il valore della colonna "B.title" dalla tabella B (avente colonne: id, table_A_id title, langcode) dove B.table_A_id è 5 e B.langcode è "nl" (se ci sono righe).

I miei tentativi:

SELECT A.name, 
case when exists(select title from B where table_A_id = 5 and langcode= 'nl') 
then B.title 
else A.name 
END 
FROM A, B 
WHERE A.id = 5 and B.table_A_id = 5 and B.langcode = 'nl' 

-- second try: 
SELECT COALESCE(B.title, A.name) as name 
from A, B 
where A.id = 5 and B.table_A_id = 5 and exists(select title from B where table_A_id = 5 and langcode= 'nl') 

Ho provato con un caso e COALESCE(), ma non è riuscita a causa della mia inesperienza con entrambi i concetti.

Grazie in anticipo.

+0

Non molto chiaro. "se non null" dici nel titolo. Ma la parola "null" non appare nella spiegazione. Vuoi dire "se c'è una riga correlata nell'altra tabella"? "B.table_A_id è 5": questa è davvero una costante o si riferisce al valore A.id corrispondente? Un esempio potrebbe essere d'aiuto – leonbloy

+0

Vuoi solo aggiungere "B.title" se "A.name" è nullo? – rfusca

+0

Ho modificato il titolo e aggiunto un esempio. Dispiace per la confusione. B.table_A_id corrisponde in effetti A.id. E per quanto riguarda la sostituzione, A.name dovrebbe essere sostituito con B.title se B.title esiste con le condizioni WHERE di cui sopra. – EarthMind

risposta

3

araqnid's è la risposta che stai cercando, scommetto.

Tuttavia, se si desidera applicare che non viene restituita più di una riga per ogni riga di corrispondenza originale A, è preferibile eseguire una sottoselezione invece di UN SINISTRA SINISTRA. Per esempio:

SELECT A.id, COALESCE(
    (SELECT max(B.title) FROM B WHERE 
    langcode = 'nl' AND B.table_a_id = A.id), A.name) as name 
FROM A 
WHERE A.id = 5 

io uso "max" qui per selezionare un valore arbitrario, in caso non v'è più di uno. Puoi utilizzare "min" o qualsiasi cosa tu consideri appropriato nel tuo caso.

Forse questo è più facile da capire rispetto al SINISTRA SINISTRO, ma (a parte i due non sono esattamente equivalenti) un JOIN funzionerà meglio di N sottoselezioni (molto meglio è N è grande).

In ogni caso, da un punto di vista dell'apprendimento, è bene comprenderli entrambi.

+0

Questo fa esattamente quello che voglio. Sostituisce A.name con B.title se esiste il secondo, altrimenti usa A.name come valore di ritorno dalla funzione COALESCE. La tabella B avrà sempre solo 1 riga per la condizione WHERE data, ma mi chiedo perché hai usato MAX() (o MIN()) invece di LIMIT 1. Inoltre, solo per curiosità, c'è un modo per sostituire la colonna del nome con il valore della funzione COALESCE()? Io uso A. * per ottenere tutti i valori dalla tabella A e alias il risultato di COALESCE() come nome e aggiunge un nome di colonna aggiuntivo1 nell'array restituito. Grazie ancora. – EarthMind

+0

Puoi usare perfettamente 'LIMIT 1' (è solo un po 'più Postgresql-centrico di MAX/MIN). Ho aggiunto un alias ("nome"). Temo che dovrai sostituire il tuo 'A. *' con l'elenco completo delle colonne (eccetto 'name'). Comunque, usare 'A. *' è considerato una cattiva pratica, di solito. – leonbloy

0

Prova questo

select A.id,B.title,A.description from TableA as A inner join tableB as B 
on A.id=B.id where B.table_A_id = 5 and B.langcode ='nl' 
+0

Questa query non restituirà A.name quando B.title non esiste. – EarthMind

1

Ok, io non sono sicuro di come le tabelle devono essere uniti, ma qualcosa di simile dovrebbe fare il lavoro:

SELECT   yourcolumnlist, 
        CASE WHEN A.name IS NULL THEN B.title ELSE A.name END 
FROM    TableA AS A 
INNER JOIN  TableB AS B 
ON    A.id = B.table_A_id 
WHERE    B.table_A_id = 5 
AND    B.langcode = 'nl' 

Un altro modo per farlo sarebbe quella di utilizzare la COALESCE) funzione (:

SELECT   yourcolumnlist, 
        COALESCE(A.name, B.title) 
FROM    TableA AS A 
INNER JOIN  TableB AS B 
ON    A.id = B.table_A_id 
WHERE    B.table_A_id = 5 
AND    B.langcode = 'nl' 
+0

Entrambe le query non restituiscono alcuna riga. Devo sottolineare che quando la tabella B non ha righe dove langcode = 'nl', dovrebbe comunque restituire tutte le righe dalla tabella A.E se ci sono righe dove langcode = 'nl' allora il campo dovrebbe essere sostituito come menzionato nel mio primo post. – EarthMind

2
select A.id, coalesce(B.title, A.name) 
from TableA AS A 
    left join (select table_a_id, title from TableB where langcode = 'nl') AS B 
     on B.table_a_id = A.id 
WHERE A.id = 5 
+0

Questo è quello che vuoi, immagino. L'unica avvertenza è che questo può potenzialmente dare più di una riga per riga TableA, se ci sono più di una riga di tabella che corrisponde. – leonbloy

+0

Anche questo non si comporta come desiderato. Restituisce A.name ogni volta, indipendentemente dal fatto che B.title esista o meno. – EarthMind

+0

+1 Questo dovrebbe funzionare e, in generale, è meglio della mia risposta. – leonbloy