Synapse 专用池中的动态 SQL 失败,但非动态查询有效

Dynamic SQL in Synapse dedicated pool fails, but non-dynamic query works

下面的动态 SQL 查询,我通过 EXECUTE sp_executesql @sql; 在 Azure Synapse 专用 SQL 池中通过 SSMS 执行,returns 随机语法错误,例如

Parse error at line: 105, column: 44: Incorrect syntax near 'log_Case'.

但是,如果我在 SSMS 中执行此查询的非动态版本,它就可以正常工作。我considered/tried没有成功的事情:

有人知道我的动态查询有什么问题以及为什么会失败吗?这让我很头疼。

DECLARE @sql nvarchar(max);
DECLARE @clientstaging nvarchar(50) = 'staging';

SET @SQL = 'insert into ' + @clientstaging + '.log_CaseSLAChanges (
    id,
    caseDocumentType,
    clientOrganisation,
    billDate,
    billNumber,
    serviceDescription,
    positionChanged,
    servicePeriod,
    currency,
    prices,
    totalPrice,
    netPrice,
    vatPrice,
    vatRate,
    vatNr,
    taxNr,
    creditor
)

SELECT
        c.id id,
        t.title,
        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''clientOrganisation'') > 0
            THEN 1
        ELSE 0 END "clientOrganisation",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''billDate'') > 0
            THEN 1
        ELSE 0 END "billDate",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''billNumber'') > 0
            THEN 1
        ELSE 0 END "billNumber",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''serviceDescription'') > 0
            THEN 1
        ELSE 0 END "serviceDescription",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND ((l.fieldKey = ''Position'') OR (
                       l.fieldKey in (''description'', ''amount'', ''unit'', ''unitPrice'', ''totalPrice'', ''vatPrice'', ''vatRate'')
                       AND l.typeID = 1))) > 0
            THEN 1
        ELSE 0 END "positionChanged",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''servicePeriod'') > 0
            THEN 1
        ELSE 0 END "servicePeriod",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''currency'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "currency",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey IN (''totalPrice'', ''netPrice'', ''vatPrice'', ''vatRate'') AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "prices",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''totalPrice'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "totalPrice",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''netPrice'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "netPrice",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''vatPrice'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "vatPrice",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''vatRate'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "vatRate",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''vatNr'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "vatNr",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + @clientstaging + '.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''taxNr'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "taxNr",

        CASE WHEN (select COUNT(*)
                   FROM ' + @clientstaging + '.backend_CaseData d
                       JOIN ' + @clientstaging + '.backend_CaseCreditorData cdc on d.capturedCaseDataCreditorID = cdc.id
                       JOIN ' + @clientstaging + '.backend_CaseCreditorData cdd on d.caseCreditorDataID = cdd.id
                   WHERE d.caseID = c.id AND (cdc.normalizedReducedName != cdd.normalizedReducedName OR
                                              cdc.normalizedStreetAndNumber != cdd.normalizedStreetAndNumber)
                  ) > 0
            THEN 1
        ELSE 0 END "creditor"

FROM ' + @clientstaging + '.backend_Case c
        JOIN ' + @clientstaging + '.backend_CaseProcess p ON p.caseID = c.id
        JOIN ' + @clientstaging + '.backend_CaseData d on c.id = d.caseID
        JOIN ' + @clientstaging + '.md_CaseDocumentType t ON t.id = d.caseDocumentTypeID
WHERE c.uploadedByFastLane = 0
  AND p.processStepID != 0
  and c.deleted = 0
  and c.archived = 1';
EXECUTE sp_executesql @sql;

调试动态 SQL 最简单的方法是先 PRINT/SELECT 语句。然后您可以调试 SQL 并在将解决方案传播到生成动态语句的 SQL 之前解决问题。通常您会发现问题非常简单,例如难以在文字字符串中发现的打字错误;例如缺少 whitespace/linebreak 或 leading/trailing 分隔符。花时间让 non-dynamic 语句首先工作非常重要,如果它不起作用,动态语句将没有机会正常工作。

如果您执行了 PRINT/SELECT 语句,您会注意到它被截断为 4,000 个字符,因为您的文字只是一个 nvarchar(4000)CAST/CONVERT 的一部分到 MAX:

DECLARE @sql nvarchar(max);
DECLARE @clientstaging sysname = N'staging';

SET @SQL = CONVERT(nvarchar(MAX),N'insert into ') + QUOTENAME(@clientstaging) + N'.log_CaseSLAChanges (
    id,
    caseDocumentType,
    clientOrganisation,
    billDate,
    billNumber,
    serviceDescription,
    positionChanged,
    servicePeriod,
    currency,
    prices,
    totalPrice,
    netPrice,
    vatPrice,
    vatRate,
    vatNr,
    taxNr,
    creditor
)

SELECT
        c.id id,
        t.title,
        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''clientOrganisation'') > 0
            THEN 1
        ELSE 0 END "clientOrganisation",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''billDate'') > 0
            THEN 1
        ELSE 0 END "billDate",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''billNumber'') > 0
            THEN 1
        ELSE 0 END "billNumber",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''serviceDescription'') > 0
            THEN 1
        ELSE 0 END "serviceDescription",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND ((l.fieldKey = ''Position'') OR (
                       l.fieldKey in (''description'', ''amount'', ''unit'', ''unitPrice'', ''totalPrice'', ''vatPrice'', ''vatRate'')
                       AND l.typeID = 1))) > 0
            THEN 1
        ELSE 0 END "positionChanged",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND l.fieldKey = ''servicePeriod'') > 0
            THEN 1
        ELSE 0 END "servicePeriod",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''currency'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "currency",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey IN (''totalPrice'', ''netPrice'', ''vatPrice'', ''vatRate'') AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "prices",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''totalPrice'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "totalPrice",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''netPrice'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "netPrice",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''vatPrice'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "vatPrice",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''vatRate'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "vatRate",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''vatNr'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "vatNr",

        CASE WHEN (SELECT COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.log_CaseChangesLog l
                   WHERE l.caseID = c.id AND l.caseProcessStepID != 1 AND
                         l.fieldKey = ''taxNr'' AND l.typeID = 0) > 0
            THEN 1
        ELSE 0 END "taxNr",

        CASE WHEN (select COUNT(*)
                   FROM ' + QUOTENAME(@clientstaging) + N'.backend_CaseData d
                       JOIN ' + QUOTENAME(@clientstaging) + N'.backend_CaseCreditorData cdc on d.capturedCaseDataCreditorID = cdc.id
                       JOIN ' + QUOTENAME(@clientstaging) + N'.backend_CaseCreditorData cdd on d.caseCreditorDataID = cdd.id
                   WHERE d.caseID = c.id AND (cdc.normalizedReducedName != cdd.normalizedReducedName OR
                                              cdc.normalizedStreetAndNumber != cdd.normalizedStreetAndNumber)
                  ) > 0
            THEN 1
        ELSE 0 END "creditor"

FROM ' + QUOTENAME(@clientstaging) + N'.backend_Case c
        JOIN ' + QUOTENAME(@clientstaging) + N'.backend_CaseProcess p ON p.caseID = c.id
        JOIN ' + QUOTENAME(@clientstaging) + N'.backend_CaseData d on c.id = d.caseID
        JOIN ' + QUOTENAME(@clientstaging) + N'.md_CaseDocumentType t ON t.id = d.caseDocumentTypeID
WHERE c.uploadedByFastLane = 0
  AND p.processStepID != 0
  and c.deleted = 0
  and c.archived = 1';

EXECUTE sys.sp_executesql @sql;

此外,作为旁注,我怀疑您是否需要所有这些子查询;他们的表现会很糟糕。