#sql-server #tsql
#sql-сервер #tsql
Вопрос:
У меня есть T-SQL, показанный ниже. @Results — это табличная переменная, а ‘CTE’ — обычное табличное выражение. Я хочу вставлять строки в таблицу @Results только в том случае, если идентификатор SubID, который я собираюсь вставить, еще не был вставлен в таблицу. Приведенный ниже код не выполняет эту работу, и я не уверен, почему. Кто-нибудь видит проблему?
Insert Into @Results (
Cell,
CellSettings,
RecipeInstanceId,
BiasStartTime,
SubId
RuleInstanceId)
Select
Cell,
CellSettings,
RecipeInstanceId,
BiasStartTime,
SubId,
RuleInstanceId
From CTE
Where CTE.SubId NOT IN (Select SubId From @Results)
Комментарии:
1. в чем проблема? Сообщение об ошибке?
2. возможно, вам также придется опубликовать cte — или даже лучше: сведите его к демонстрации меньшего размера. Возможно, ваша проблема даже решится сама собой, если вы сделаете это … 😉
3. Получаете ли вы сообщение об ошибке при добавлении дубликата?
4. Приведенный вами код выполняет работу точно так, как указано. Я могу только предположить, что ваш вопрос связан с ошибками PK или последующим поиском дубликатов. ПРИМЕЧАНИЕ: Дубликаты вызваны дубликатами в исходном CTE , а не ошибкой в предложении WHERE. Возможно, вы ожидали, что это устранит дубликаты, проверив соответствие более поздних строк строкам, добавленным ранее во вставке…. Это не так работает SQL. Вся вставка вычисляется как одна операция. Значения, которые уже есть в
Results
начале , не будут вставлены; но в противном случае все 5 строк с одинаковыми значениями будут вставлены. ……….SubId
Ответ №1:
Сначала вам нужно проверить наличие:
IF NOT EXISTS(SELECT * FROM @Results WHERE SubId = .......)
INSERT INTO @Results (Cell, CellSettings, RecipeInstanceId,
BiasStartTime, SubId, RuleInstanceId)
SELECT
Cell, CellSettings, RecipeInstanceId,
BiasStartTime, SubId, RuleInstanceId
FROM CTE
Возможно, вы могли бы включить это требование (возвращать только те строки, которые еще не существуют) в свой CTE, чтобы вам не пришлось снова фильтровать выходные данные из CTE…
Комментарии:
1. Не лучше ли использовать соединение?
2. @Hogan: нет — почему? Как вы думаете, что вы можете получить от использования JOIN вместо этого??
3. потому что эта проверка должна выполняться для каждой строки (нового выбора), где соединение оптимизировано в SQL для быстрой работы с наборами даты. Это разница между O (n) оптимизированным и O (1) O (1) … O (1) n раз. (Смотрите мой ответ для примера использования объединения.)
4. @Hogan: Я бы подумал, что лучшим подходом было бы отфильтровать те строки, которые уже существуют в целевой таблице в CTE, и не возвращать их вообще.
Ответ №2:
Я бы сделал это следующим образом (предположение — у вас нет дублирующегося SubID в вашем CTE, то есть вы вставляете SubID из X, а затем позже в этом же запросе вставляете тот же самый.)
WITH CTE AS
(
blah
), CTENEW AS
(
SELECT CTE.*
FROM CTE
LEFT JOIN @Results R ON CTE.SubID = R.SubID
WHERE R.SubID IS NULL
)
Insert Into @Results (
Cell,
CellSettings,
RecipeInstanceId,
BiasStartTime,
SubId
RuleInstanceId)
Select
Cell,
CellSettings,
RecipeInstanceId,
BiasStartTime,
SubId,
RuleInstanceId
From CTENEW
Или вы могли бы перенести соединение, которое я сделал, в свой CTE.
Ответ №3:
Попробуйте использовать предложение `except:
insert MyTable(c1, c2, c3)
select ot.c1, ot.c2, ot.c3
from OtherTable ot
except
select mt.c1, mt.c2, mt.c3
from MyTable
Ответ №4:
Проверьте, существует запись или нет, используя «Exists»
If Not Exists(Select SubId From @Results)
Insert Into @Results (
Cell,
CellSettings,
RecipeInstanceId,
BiasStartTime,
SubId
RuleInstanceId)
Select
Cell,
CellSettings,
RecipeInstanceId,
BiasStartTime,
SubId,
RuleInstanceId
From CTE
Where CTE.SubId NOT IN (Select SubId From @Results)