2012-04-01 14 views
6

Qualcuno può dirmi che cosa il risultato al seguente dovrebbe essere secondo lo standard (un riferimento alla parte corretta dello standard sarebbe il benvenuto)Cosa dice lo standard SQL sui condizionali "dipendenti" in UPDATE?

> select * from t1; 
+------+ 
| col1 | 
+------+ 
| 9 | 
| 8 | 
| 10 | 
+------+ 
> update t1 
    set col1 = col1 * 2 
    where col1 <= (select avg(col1) from t1); 

il punto è: L'ultima riga si aggiorna, dal momento che se le righe vengono aggiornate in ordine e la media viene ricalcolata per ogni riga, soddisferà la condizione o non verrà aggiornata in quanto qualsiasi dato modificato da questa dichiarazione sarà leggibile solo dopo l'esecuzione dell'intera istruzione?

EDIT E che dire di questo caso?

> select * from t1; 
+------+------+ 
| col1 | col2 | 
+------+------+ 
| 9 | 1 | 
| 8 | 2 | 
| 10 | 2 | 
+------+------+ 
> update t1 p1 
    set col1 = col1 * 2 
    where col1 <= (select avg(col1) 
        from t1 
        where col2=p1.col2); 
+0

Qui viene eseguita prima la sottoquery. Quindi la media non cambia. –

+0

@Shiplu Grazie. E che dire di questo secondo caso, in cui la subquery non può essere pre-eseguita? – baruch

+1

@baruch - Può essere pre-eseguito in quanto un'operazione di lettura separata identifica le righe da aggiornare e memorizza gli identificatori di riga in uno spool o simili, quindi l'aggiornamento viene eseguito leggendo da quello spool al termine della lettura. Questo è il piano che mi aspetto in SQL Server. Non sono sicuro di poter essere disturbato a scavare attraverso lo standard SQL per trovare i bit rilevanti. Un paio di concetti correlati sono "operazioni tutto in una volta" e protezione di Halloween. –

risposta

4

Per quanto posso dire, lo standard (Capitolo 14.11, SQL 2003 - Fondazione) è abbastanza chiaro su questo:

Il è effettivamente valutata per ogni fila di T prima sono aggiornati ogni fila di T

(sottolineatura mia)

La mia comprensione di questa frase è che qualsiasi condizione (se co-correlata o meno) viene valutata prima di ogni riga viene aggiornata.

+0

... e un popolare (se non il solo DBMS) che NON è conforme allo standard - e simile alle query di esempio può portare a risultati non standard - è MySQL. –

+0

@ypercube: perché non sono sorpreso? –

+1

Per essere onesti, questa è una delle più gravi, se non la più seria, deviazione dagli standard. Anche il semplice 'UPDATE t SET id = id + 1' viene eseguito in modo seriale e non come un'operazione impostata e causerà violazioni PK. –

2

L'ultima riga non viene aggiornata. perché "select avg (col1) from t1" è una sottoquery, che verrà eseguita inizialmente e memorizzerà il risultato nella tabella temporanea, quindi verrà eseguita l'istruzione di aggiornamento.

+0

Grazie. Puoi dare un'occhiata alla mia modifica? – baruch

4

Circa la prima domanda, il subquery eseguito prima in modo, non v'è alcun cambiamento nella media ...

Chi seconda query, si sta utilizzando alias UPDATE affermazione, ma si sta utilizzando alias approccio sbagliato.

modo corretto e standard da utilizzare alias UPDATE affermazione è:

UPDATE p1 
    set col1 = col1 * 2 
from t1 p1 
    where col1 <= (select avg(col1) 
        from t1 
        where col2=p1.col2); 
+2

Lo standard SQL non consente una clausola 'FROM' per un'istruzione' UPDATE'. Quindi il tuo esempio non è "il modo standard". Inoltre nello standard SQL l'alias di tabella è definito nella parte 'UPDATE':' UPDATE [[AS] ] '. La sintassi precedente è valida solo per MySQL se non sbaglio –

+0

@ a_horse_with_no_name: Grazie .... Funziona su MS-SQL Server .. Ho già testato la query sopra in MSSQL Ma quando eseguo la seconda query di OP, genera errore ... –

+0

grazie per l'aggiornamento. –