2011-09-11 7 views
6

La seguente query restituisce 2036 righe:Sono pazzo: PostgreSQL IN all'operatore di query nidificate restituire risultati inattesi

SELECT "FooUID" from "Foo" f 
LEFT JOIN "Bar" b ON f."BarUID" = b."BarUID" 
WHERE f."BarUID" IS NOT NULL AND b."BarUID" IS NULL 

Ma la seguente dichiarazione unica aggiornato 1870 Righe:

UPDATE "Foo" f1 set "BarUID" = 'aNewUID' 
WHERE f1."FooUID" IN (
    SELECT f2."FooUID" from "Foo" f2 
    LEFT JOIN "Bar" b ON f2."BarUID" = b."BarUID" 
    WHERE f2."BarUID" IS NOT NULL AND b."BarUID" IS NULL 
) 

come è possibile ?

MODIFICA 1: La prima query continua a restituire 166 righe e la seconda continua ad aggiornare 0 righe.

EDIT 2:

Nel seguito, l'interrogazione nidificata restituisce una riga contenente un UID, ma query esterna restituisce 0 righe.

SELECT * from "Foo" f1 
WHERE f1."FooUID" = (
    SELECT f2."FooUID" FROM "Foo" f2 
    LEFT JOIN "Bar" b ON f2."BarUID" = b."BarUID" 
    WHERE f2."BarUID" IS NOT NULL AND b."BarUID" IS NULL 
    LIMIT 1 
) 

Sono pazzo?

EDIT 3:

l'istruzione che segue, fornito da @wildplasser è riuscito a aggiornare i restanti 166 righe:

UPDATE "Foo" ff 
SET "BarUID" = 'aNewUID' 
WHERE ff."BarUID" IS NOT NULL 
AND NOT EXISTS (
    SELECT * FROM "Bar" bb 
    WHERE bb."BarUID"= ff."BarUID" 
) 

Tuttavia, ancora non capisco perché l'originale non ha preso loro. Se la query nidificata è stata selezionata 166 "FooUID" s, perché non dovrebbero corrispondere alle righe nella tabella "Foo" utilizzando IN?

EDIT 4: Più ci penso, questo scenario potrebbe essere importante:

Tutto questo ha avuto luogo su un server di database che è stato recentemente clonato da un altro. Ho parlato con il tizio IT che ha fatto la clonazione, e si scopre che non ha chiuso un'applicazione in esecuzione sul DB originale prima di ridurla per clonarla. Ciò significa che il DB è stato per lo più probabilmente abbattuto a metà transazione (non so quanto vergognosamente). È possibile che qualcosa nel database sia stato lasciato in uno stato corrotto, portandomi a vedere queste righe fantasma?

Sfortunatamente non riesco più a ripeterlo, da quando è in esecuzione la correzione di wildplasser. Il DB originale (di nuovo disponibile e in grado di servire l'applicazione) non ha nessuno dei dati non validi che stavo cercando di correggere sulla copia, tanto meno nessuna traccia degli shenanigans che ho visto.

Devo dire che prima di eseguire la correzione, ho ridotto la questione al l'assurdità più elementare: in primo luogo ho scelto il FooUID dalla query nidificate in Modifica 2, copiato negli appunti, poi corse una query scegliendo tra Foo dove FooUID uguale al valore incollato - questo è ancora ha restituito 0 righe.

+0

Che tipo è 'FooUID' e quale viene restituito dalla query interna in EDIT 2? Non ho idea di cosa stia succedendo, solo spiando un po '. –

+0

@mu è troppo breve - 'FooUID' è di tipo' uuid'. Non sono sicuro di aver capito la seconda parte della tua domanda. –

+0

Il tuo EDIT 2 mi ha bloccato. Deve essere un valore che non è paragonabile a se stesso. Sei sicuro che la parte interna restituisca un 'FooUID 'non Null? –

risposta

2

Cosa succede se si riscrive questo con non esiste, come

UPDATE Foo ff 
SET baruid = 'aNewUID' 
WHERE ff.baruid IS NOT NULL 
AND NOT EXISTS (SELECT * FROM bar bb 
    WHERE bb.baruid = ff.baruid 
    ); 

sembra molto più pulito per me che selezionare la gamba arto di un outer join.

+0

Inoltre, un vincolo di chiave esterna probabilmente eviterebbe questo pasticcio. – wildplasser

+0

Divertente dovresti dirlo, questo sono io che sto cercando di ripulire i dati cattivi per aggiungere chiavi esterne. –

+0

Gheghe. Prova ad aggiungere un nome di correlazione alla sottoquery. Forse qualcuno si è confuso vedendo le due cose. Puoi anche controllare i piani wuery (i nomi delle correlazioni sono utili anche lì) – wildplasser