Создание "Not Exists" / Вставка в операторы - ничем не озадачен (NULL) - PullRequest
0 голосов
/ 27 мая 2019

Мне нужен скрипт, который генерирует операторы вставки, но с проверкой, если данные еще не существуют, это потому, что он должен периодически запускаться в системах Parallell, где в системы будут добавляться разные данные, но мы хотим, чтобы их таблицы были в синхронизации. У меня есть базовые идентификаторы и заимствованные части кода, но я получаю синтаксическую ошибку, которую мне не удается решить.

Я основываю свой код на коде, показанном Парам Ядавом на Преобразование результатов выбора в сценарий вставки - SQL Server , но мне нужно проверить данные, уже находящиеся в таблице. (Мне нужно добавить еще «свистки», но сделайте это шаг за шагом)

Моим главным дополнением является часть @NOT_EXISTS, которая должна быть в предложении WHERE проверки NOT EXISTS. Если я заменим это простым WHERE 0 = 1, я не получу синтаксическую ошибку, поэтому это означает, что ошибка находится в моей строке @NOT_EXISTS.

Редактировать: Вчера я думал, что у меня есть ответ на свой вопрос, но при работе с «реальными данными» я увидел, что некоторые строки слишком длинны для QUOTENAME, я должен исправить эти кавычки «вручную» (concats в скрипте) вместо ...


SET NOCOUNT ON

DECLARE @CSV_COLUMN VARCHAR(MAX),
    @QUOTED_DATA VARCHAR(MAX),
    @NOT_EXISTS VARCHAR(MAX),
    @SQL_KOD VARCHAR(MAX),
    @TABLE_NAME VARCHAR(MAX),
    @FILTER_CONDITION VARCHAR(MAX)='',
    @FIRST_COL INT,
    @LAST_COL INT

/* INPUT DATA */
SELECT @TABLE_NAME = 'WorkflowError'
SELECT @FIRST_COL = 2
SELECT @LAST_COL = 4
/* */

SELECT @CSV_COLUMN=STUFF
(
    (
     SELECT ',['+ NAME +']' FROM sys.all_columns 
     WHERE OBJECT_ID=OBJECT_ID(@TABLE_NAME) AND 
     is_identity!=1 FOR XML PATH('')
    ),1,1,''
)

--SELECT @CSV_COLUMN

SELECT @QUOTED_DATA=STUFF
(
    (
     SELECT ' ISNULL(QUOTENAME('+NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+')+'','''+'+' FROM sys.all_columns 
     WHERE OBJECT_ID=OBJECT_ID(@TABLE_NAME) AND 
     is_identity!=1 FOR XML PATH('')
    ),1,1,''
)

SELECT @QUOTED_DATA=SUBSTRING(@QUOTED_DATA,1,LEN(@QUOTED_DATA)-5)

SELECT @QUOTED_DATA

SELECT @NOT_EXISTS=STUFF
(
    (
     SELECT ' ['+ COLUMN_NAME +']=', 'ISNULL(QUOTENAME('+COLUMN_NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+') AND '
     FROM information_schema.columns 
     WHERE table_name = @TABLE_NAME AND 
     ordinal_position BETWEEN @FIRST_COL AND @LAST_COL
     FOR XML PATH('')
    ),1,1,''
)

SELECT @NOT_EXISTS=SUBSTRING(@NOT_EXISTS,1,LEN(@NOT_EXISTS)-4)

SELECT @NOT_EXISTS
--SELECT @NOT_EXISTS=' 0=1 '

SELECT @SQL_KOD='SELECT ''
    IF NOT EXISTS(SELECT 1 
    FROM ' + @TABLE_NAME + ' WHERE ' + @NOT_EXISTS + ')
    BEGIN
        INSERT INTO '+@TABLE_NAME+'('+@CSV_COLUMN+')
        VALUES('''+'+'+@QUOTED_DATA+'+'+''')
    END
    GO '''+' Insert_Scripts 
FROM '+@TABLE_NAME + @FILTER_CONDITION

SELECT @SQL_KOD
EXECUTE (@SQL_KOD)

GO

[stackoverflow won't let me post code unless it's formatted, but then the strings below won't be as they are created in the script...]
When I do SELECT @NOT_EXISTS=' 0=1 ' I get an INSERT line for each row in my table:

IF NOT EXISTS(SELECT 1 FROM WorkflowError WHERE  0=1 )
    BEGIN
        INSERT INTO WorkflowError([TargetSystem],[ErrorCode],[ErrorText],[RetryMaxCount],[RetryStrategyName],[ErrorDescription])
        VALUES('EttLiv','800','Value cannot be null.  Parameter name: source','0',NULL,'Value cannot be null.  Parameter name: source')
    END
GO 

With my @NOT_EXISTS code the @SQL_KOD string becomes this:

SELECT 'IF NOT EXISTS(SELECT 1 FROM WorkflowError
                      WHERE [TargetSystem]=ISNULL(QUOTENAME(TargetSystem,''''),'NULL'))
BEGIN
    INSERT INTO WorkflowError([TargetSystem],[ErrorCode],[ErrorText],[RetryMaxCount],[RetryStrategyName],[ErrorDescription])
    VALUES('+ISNULL(QUOTENAME(TargetSystem,''''),'NULL')+','
    + ISNULL(QUOTENAME(ErrorCode,''''),'NULL')+','
    + ISNULL(QUOTENAME(ErrorText,''''),'NULL')+','
    + ISNULL(QUOTENAME(RetryMaxCount,''''),'NULL')+','
    + ISNULL(QUOTENAME(RetryStrategyName,''''),'NULL')+','
    + ISNULL(QUOTENAME(ErrorDescription,''''),'NULL')+')
END
GO ' Insert_Scripts FROM WorkflowError
However, trying to execute that @SQL_KOD line just gives:

Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'NULL'.

...and I can't find out where I have done wrong, if it's in my thinking or if it's just a misplaced quotation mark...

Ответы [ 2 ]

0 голосов
/ 27 мая 2019

Изначально я использовал QUOTENAME, как в скрипте Param Yadav, у которого я позаимствовал, но эта функция не может обрабатывать длинные строки.Он не жалуется, просто возвращает NULL, если строка слишком длинная.Теперь сценарий стал менее читаемым (длинные строки кавычек), но теперь работает.


SET NOCOUNT ON

DECLARE @CSV_COLUMN VARCHAR(MAX),
        @QUOTED_DATA VARCHAR(MAX),
        @NOT_EXISTS VARCHAR(MAX),
        @SQL_KOD VARCHAR(MAX),
        @TABLE_NAME VARCHAR(MAX),
        @FILTER_CONDITION VARCHAR(MAX),
        @FIRST_COL INT,
        @LAST_COL INT


/* INPUT DATA */
SELECT @TABLE_NAME = 'WorkflowError'
SELECT @FIRST_COL = 2
SELECT @LAST_COL = 4
SELECT @FILTER_CONDITION = ''
/* */

SELECT @CSV_COLUMN=STUFF
(
    (
     SELECT ',['+ NAME +']' FROM sys.all_columns 
     WHERE OBJECT_ID=OBJECT_ID(@TABLE_NAME) AND 
     is_identity!=1 FOR XML PATH('')
    ),1,1,''
)

SELECT @QUOTED_DATA=STUFF
(
    (
     SELECT ' ISNULL('''''''' + REPLACE('+NAME+','''''''','''''''''''') + '''''''','''+'NULL'''+''+')+'',''+'
     FROM sys.all_columns 
     WHERE OBJECT_ID=OBJECT_ID(@TABLE_NAME) AND 
     is_identity!=1 FOR XML PATH('')
    ),1,1,''
)

SELECT @QUOTED_DATA=SUBSTRING(@QUOTED_DATA,1,LEN(@QUOTED_DATA)-5)

SELECT @NOT_EXISTS=STUFF
(
    (
     SELECT ' ['+ COLUMN_NAME +']='' + ', 'ISNULL('''''''' + REPLACE('+COLUMN_NAME+','''''''','''''''''''') + '''''''','''+'NULL'''+''+')+'' AND '
     FROM information_schema.columns 
     WHERE table_name = @TABLE_NAME AND 
     ordinal_position BETWEEN @FIRST_COL AND @LAST_COL
     FOR XML PATH('')
    ),1,1,''
)

SELECT @NOT_EXISTS=SUBSTRING(@NOT_EXISTS,1,LEN(@NOT_EXISTS)-6)

SELECT @SQL_KOD='SELECT ''IF NOT EXISTS(SELECT 1 FROM ' + @TABLE_NAME + ' WHERE ' + @NOT_EXISTS + ' + ' + ''') BEGIN INSERT INTO '+@TABLE_NAME+'('+@CSV_COLUMN+')VALUES('''+'+'+@QUOTED_DATA+'+'+''') END '''+' Insert_Scripts FROM ' + @TABLE_NAME + ' ' + @FILTER_CONDITION

EXECUTE (@SQL_KOD)

SET NOCOUNT OFF

0 голосов
/ 27 мая 2019

Откуда вы ожидаете, что @SQL_KOD получит свои значения?Потому что, если вы извлекаете свои значения для TargetSystem / ErrorCode / ... / ErrorDescription где-то за пределами вашего оператора вставки, я бы ожидал оператора "from".Если вы хотите ввести переменные, вам не хватает как определения переменных, так и знака @ перед именем переменной.

Что касается поддержания кавычек: попробуйте написать свой код с выключенным QUOTED_IDENTIFIER - вы можете создать всю переменную @SQL_KOD, записав между двойными кавычками ("), и одинарные кавычки будут вести себя как обычные кавычки.

Очень базовая перезапись вашего кода может выглядеть следующим образом:

SET QUOTED_IDENTIFIER OFF 

DECLARE @SQL_KOD VARCHAR(MAX)

SET @SQL_KOD = 

"DECLARE @WorkFlowError TABLE ([TargetSystem] NVARCHAR(200),[ErrorCode] NVARCHAR(200))

IF NOT EXISTS ( SELECT 1 FROM @WorkFlowError )
BEGIN
    INSERT INTO @WorkFlowError ([TargetSystem],[ErrorCode])
    SELECT ISNULL(QUOTENAME([TargetSystem],''''),'NULL')
        , ISNULL(QUOTENAME([ErrorCode],''''),'NULL')
    FROM (
        SELECT [TargetSystem]='Foo'
            , [ErrorCode]='Bar'
    ) src
END";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...