J'essaie d'insérer d'une table dans une autre en utilisant
DECLARE @IDOffset int;
SELECT @IDOffset = MAX(ISNULL(ID,0)) FROM TargetTable
INSERT INTO TargetTable(ID, FIELD)
SELECT [Increment] + @IDOffset ,FeildValue
FROM SourceTable
WHERE [somecondition]
TargetTable.ID n'est pas une colonne d'identité, c'est pourquoi je dois trouver un moyen de l'incrémenter automatiquement moi-même.
Je sais que je peux utiliser un curseur ou créer une variable de table avec une colonne d'identité et un champ FieldValue, remplissez-le, puis utilisez-le dans mon insert into...select
, mais ce n'est pas très efficace. J'ai essayé d'utiliser la fonction ROW_NUMBER pour incrémenter, mais je n'ai vraiment pas de champ ORDER BY légitime dans le SourceTable que je puisse utiliser, et je voudrais conserver l'ordre d'origine du SourceTable (si possible).
Quelqu'un peut-il suggérer quelque chose?
Vous pouvez éviter de spécifier un ordre explicite comme suit:
INSERT dbo.TargetTable (ID, FIELD)
SELECT
Row_Number() OVER (ORDER BY (SELECT 1))
+ Coalesce(
(SELECT Max(ID) FROM dbo.TargetTable WITH (TABLOCKX, HOLDLOCK)),
0
),
FieldValue
FROM dbo.SourceTable
WHERE {somecondition};
Cependant, veuillez noter que c'est simplement un moyen d'éviter de spécifier une commande et ne garantit PAS que toute commande de données d'origine sera conservée. Il existe d'autres facteurs pouvant entraîner le classement du résultat, tels qu'un ORDER BY
dans la requête externe. Pour bien comprendre cela, il faut comprendre que le concept "non ordonné (d'une manière particulière)" n'est pas la même chose que "conserver l'ordre d'origine" (qui IS ordonné d'une manière particulière!) . Je crois que du point de vue de la base de données relationnelle pure, ce dernier concept n'existe pas, par définition (bien qu'il puisse y avoir implémentations de base de données qui violent cela, SQL Server n'est pas l'un d'eux).
La raison des conseils de verrouillage est d'empêcher le cas où certains autres processus insèrent en utilisant la valeur que vous prévoyez d'utiliser, entre les parties de l'exécution de la requête.
Remarque: de nombreuses personnes utilisent (SELECT NULL)
pour contourner la restriction "aucune constante autorisée dans la clause ORDER BY d'une fonction de fenêtrage". Pour une raison quelconque, je préfère 1
sur NULL
.
Aussi: je pense qu'une colonne d'identité est de loin supérieure et devrait être utilisée à la place. Il n'est pas bon pour la concurrence de verrouiller exclusivement des tables entières. Euphémisme.
Vous pouvez ignorer l'ordre en utilisant order by (select null)
comme ceci:
declare @IDOffset int;
select @IDOffset = max(isnull(ID, 0)) from TargetTable
insert into TargetTable(ID, FIELD)
select row_number() over (order by (select null)) + @IDOffset, FeildValue
from SourceTable
where [somecondition]