2009-07-28 7 views
1

J'ai essayé d'effectuer ce qui suit afin de mettre à jour une valeur d'identité de pseudo en même temps que l'utilisation de la valeur pour créer de nouvelles lignes, mais APPLY n'aime pas les instructions UPDATE comme source de la table de droite. Quelle est l'alternative la plus élégante en dehors de la simple utilisation d'une colonne d'identité?Utilisez APPLY avec une instruction UPDATE comme source de ligne

create table Temp1(
    id int not null identity(1,1) primary key 
    ,data nvarchar(max) null) 
create table Temp2(
    id int not null primary key 
    ,fkTemp1 int not null references Temp1(id) 
    ,data nvarchar(max) null) 
create table Numbering(
    ObjectCode int not null primary key 
    ,AutoKey int) 

insert into Temp1(data) values('test string') 
insert into Temp1(data) values('another test string') 
insert into Numbering(ObjectCode, AutoKey) values(4, 1) 

insert into Temp2(id, fkTemp1, data) 
select n.AutoKey, t1.id, t1.data 
from Temp1 t1 
left join Temp2 t2 on t2.fkTemp1 = t1.id 
cross apply (update Numbering set AutoKey = AutoKey + 1 output inserted.AutoKey where ObjectCode = 4) n 
where t2.id is null -- only insert where a target row does not already exist 
+0

Même en admettant APPLIQUER, votre demande de ne pas me donner un sens. Vous avez "où t2.id est nul" sur votre insert..select, mais la colonne id de Temp2 ne peut jamais être nulle (par définition), donc vous ne devriez jamais avoir de résultats à insérer. – RBarryYoung

Répondre

1

Vous ne pouvez pas faire une INSERT et UPDATE sur deux tables différentes dans une déclaration SQL Server 2005.

En SQL Server 2008 il y a MERGE construction, cependant, cela ne fonctionne que sur une seule table.

Il suffit de lancer deux déclarations dans une transaction:

BEGIN TRANSACTION 
     DECLARE @AutoKey INT 

     SELECT @AutoKey = AutoKey 
     FROM Numbering WITH (UPDLOCK) 
     WHERE ObjectCode = 4 

     INSERT 
     INTO temp2 
     SELECT @AutoKey + ROW_NUMBER() OVER (ORDER BY id), id, data 
     FROM temp1 
     WHERE id NOT IN 
       (
       SELECT fkTemp1 
       FROM temp2 
       ) 
     UPDATE Numbering 
     SET  AutoKey = AutoKey + @@ROWCOUNT 
     WHERE ObjectCode = 4 
COMMIT 

Mise à jour:

Comme @Remus Rusanu souligné, vous pouvez réellement pipeline UPDATE clause de sortie dans une table SQL Server 2005.

Toutefois, il semble que vous ne pouvez pas JOIN ni CROSS APPLY le résultat OUTPUT pour le résultat d'autres requêtes.

+0

En fait, vous pouvez faire INSERT et UPDATE sur deux tables dans SQL Server 2005 à l'aide de la clause OUTPUT, cependant, la clause OUTPUT n'est pas très flexible. Cependant, vous ne pouvez certainement pas utiliser UPDATE dans un opérateur APPLY. – RBarryYoung

+0

@RBarryYoung: vous voulez dire: 'INSERT INTO SELECT * FROM (MISE À JOUR ... OUTPUT INSERTED. *)'? N'est-il pas disponible uniquement dans 'SQL Server 2008'? – Quassnoi

+0

@Quassnoi: Vous pouvez enchaîner la sortie UPDATE dans un INSERT: http://rusanu.com/2008/04/09/chained-updates/ –

0

Cela le fera, mais vous devrez fixer le « T2.ID IS NULL » problème ...

Declare @Key as int 
Declare @cnt as int 
Begin Transaction 
    Set @cnt = (Select count(*) 
     from Temp1 t1 left join Temp2 t2 on t2.fkTemp1 = t1.id 
     --where t2.id is null -- note: does not work, not sure what is intended 
     ) 
    update Numbering set @Key = AutoKey = AutoKey + @cnt where ObjectCode = 4 

    insert into Temp2(id, fkTemp1, data) 
     select @Key+ROW_NUMBER() over (Order By t1.id) 
      , t1.id, t1.data 
     from Temp1 t1 
      left join Temp2 t2 on t2.fkTemp1 = t1.id 
     --where t2.id is null -- note: does not work, 
Commit Transaction 
+0

Rats, je pense que Quassoni ont essentiellement la même réponse, juste devant moi .. – RBarryYoung

Questions connexes