2009-03-16 5 views
4

J'ai deux tables, une destination pour la mise à jour:Pourquoi SQL Server échoue-t-il lorsque le résultat d'un UPDATE est ambigu?

create table dest (value int) 
insert into dest values (0) 

et une source:

create table source (value int) 
insert into source values (4) 
insert into source values (1) 

Si je lance cette requête:

UPDATE dest SET value = (select value from source WHERE 1=1) 

SQL Server échoue avec:

Subquery returned more than 1 value. This is not permitted when 
the subquery follows =, !=, <, <= , >, >= ... 

qui est parfait. Mais si je lance cette requête:

UPDATE dest SET value = source.value FROM dest INNER JOIN Source ON 1=1 

... il choisit au hasard une des valeurs de la source et des mises à jour dest avec elle.

Effrayant? Y a-t-il une explication à cela?

Répondre

11

Oui la raison pour laquelle votre première requête échoue n'a rien à voir avec une déclaration de mise à jour exécuter cette requête:

select * from dest 
where value = (select value from source) 

Lorsque vous avez un sous-requête qui utilise l'un des opérateurs tels que =, = etc! ... vous ne pouvez pas retourner plus d'un résultat. Si vous voulez dire me donner toutes les valeurs dans dest où une valeur correspondante est dans la source, vous devez utiliser la clause suivante:

select * from dest 
where value in (select value from source) 

Quant à votre deuxième partie de votre question, bien une cellule ne peut avoir valeur unique alors ce que vous faites est de le remplacer encore et encore. Ceci est parfaitement valide. Comme vous l'avez indiqué il n'y a aucun moyen de déterminer quelle ligne sera choisie, ce qui rend cela intéressant, d'autant plus que si la mémoire sert différentes versions de SQL, choisissez des lignes différentes (les anciennes versions utilisaient la dernière rangée comme maintenant ils utilisent la première rangée).

+0

+1: Bonne explication. –

0

Dans le premier exemple, la sous-requête renvoie plusieurs lignes et la mise à jour échoue. Dans le second exemple, la jointure aboutit, de sorte que la mise à jour peut continuer. Les résultats sont imprévisibles car la jointure n'est pas contrainte.

2

Oracle n'interdit les requêtes comme ceci:

UPDATE dest SET value = source.value FROM dest INNER JOIN Source ON 1=1 

, si la table source n'est pas une table key-preserved (vous joindre dest sur un champ de source qui ne sont pas explicitement déclaré UNIQUE (par un UNIQUE INDEX ou un PRIMARY KEY).

Ceci est une méthode pour faire en sorte que tout au plus une ligne de dest sera sélectionné dans la vue.

S'il n'existe aucune contrainte UNIQUE, la mise à jour échouera quand même, même s'il n'y a pas de doublons réels dans source.

SQL Server n'a pas cette limitation, et met à jour juste à la première valeur dans les rencontres, en sautant les autres.

La première valeur dépend de plusieurs conditions, y compris la méthode de jointure choisie par l'optimiseur.

+0

Presque à droite, mais une CLÉ UNIQUE est assez bonne, elle n'a pas besoin d'être primaire. – erikkallen

Questions connexes