2012-08-28 27 views
6

Ho molti-a-molti tra foo e bar modellato come una tabella foo_bar con foo_id e bar_id.Conversione di una relazione molti-a-molti a uno-a-molti in PostgreSQL

Vorrei ora modellare questo come uno-a-molti (che i miei dati consentono).

Ho aggiunto una colonna foo_id a bar ma ora desidero eseguire la migrazione dei miei dati. Quindi, voglio

UPDATE bar SET foo_id = f where id = b; 

in cui ogni coppia f e b sono provenienti da

SELECT foo_id AS f, bar_id AS b FROM foo_bar; 

E 'possibile fare questo in SQL (e in particolare PostgreSQL 9.0)?

So come eseguire i sub-SELECT in UPDATE quando c'è un solo valore, ma in questo caso non riesco a capire come farlo.

risposta

5
UPDATE bar b 
SET foo_id = fb.foo_id 
FROM foo_bar fb 
WHERE fb.bar_id = b.bar_id; 

Se si dovrebbe avere più righe per un bar (che non si dovrebbe, in base alla descrizione) l'una riga verranno aggiornati più volte e il risultato è arbitrario.

Questa forma della query generalmente funziona meglio di una sottoquery correlata.

Si noti che la chiave primaria di bar deve essere effettivamente denominata bar_id - Io uso quel nome nella query.

+0

dovrebbe durare linea essere fb.bar_id = b.id? –

+0

@JamesTauber: No. Non ci dovrebbe essere un 'id' nel modello. L'uso del nome colonna non descrittivo 'id' è un anti-pattern. La chiave primaria dovrebbe essere chiamata 'bar_id'. –

+0

abbastanza giusto, era solo mappandolo alle specifiche della mia domanda –

2

Se si dispone di una relazione 1-molti, non importa quale valore si prenda per una determinata barra: ce n'è solo uno o sono tutti uguali.

È possibile effettuare le seguenti operazioni:

update bar 
    set foo_id = (select max(foo_id) from foo_bar where foo_bar.bar_id = bar.id) 

La sottoquery limita i risultati in un unico valore.

3

È ancora possibile unire le tabelle in UPDATE dichiarazioni, prova a

UPDATE bar a 
SET  foo_id = c.foo_id 
FROM (
      SELECT foo_id, bar_id 
      FROM foo_bar 
     ) c 
WHERE a.id = c.bar_id 

o semplicemente come

UPDATE bar a 
SET  foo_id = c.foo_id 
FROM foo_bar c 
WHERE a.id = c.bar_id 
+0

'SET' non accetta nomi di colonne qualificate per tabella. –

+0

@ErwinBrandstetter in realtà questo non è testato. Postgre è abbastanza severo? hehe, quindi in questo caso dovrei riscriverlo a 'SET foo_id = c.foo_id'?" –

+0

Esattamente: 'SET foo_id = c.foo_id', come nella mia risposta. Cito il manuale [qui] (http: // www.postgresql.org/docs/current/interactive/sql-update.html): 'Non includere il nome della tabella nelle specifiche di una colonna di destinazione - ad esempio, scheda UPDATE SET tab.col = 1 non è valido. –

Problemi correlati