Sql-Server

嵌套在 STUFF 函式中的 CASE 語句中可空的 smallint 列的使用

  • November 20, 2019

我在編寫在 STUFF 函式中使用 CASE 語句的儲存過程時遇到問題。我認為我的問題可能與 Restricted 是可空的 smallint 有關。我嘗試將其轉換(您甚至可以將 smallint 轉換為字元串嗎?),但我仍然沒有得到預期的結果。我希望 WHEN 和 ELSE 在它們滿足我的查詢中的特定條件時結合起來,但它完全從我的結果中消除了這一行。

在 STUFF 中,如果該行是 Restricted,我想在 ItemStatus 上添加“(Restricted)”。如果不是 Restricted(0 或 NULL),我只想添加 ItemStatus。

我嘗試將 CASE 語句中的 WHEN 替換為以下內容:

WHEN CONVERT(varchar(100),  ISNULL(Statuses2.Restricted, 0) ) = 0 THEN ', ' + dmStatuses2.ItemStatus + ' (Restricted)'

如果我將 WHEN 更改為:

WHEN Statuses2.Restricted IS NOT NULL THEN ', ' + dmStatuses2.ItemStatus + ' (Restricted)'

…我得到顯示的行(但只有 ItemStatus。此列應該有 2 個字元串連接,因為至少有一個 Restricted 和 non-Restricted 值)…但是一旦我添加了一個附加條件來嘗試檢查Restricted(Restricted = 0Restricted = 1)的值,我開始根本沒有得到任何結果。

關於我做錯了什麼的任何想法?

SELECT
   StatusList
   --etc...
FROM
(
   SELECT
       StatusList
       --etc...
   FROM
   (
       SELECT
           StatusList,
           [Count] = ISNULL(COUNT(*), 0)
           --etc...
       FROM
           Items
       INNER JOIN
       (
           SELECT ROW_NUMBER() OVER (PARTITION BY /* some stuff */ ) as RowNum, Statuses.*,
               STUFF((
                   SELECT
                       CASE
                           WHEN Statuses2.Restricted = 1 THEN ', ' + dmStatuses2.ItemStatus + ' (Restricted)'
                           ELSE ', ' + dmStatuses2.ItemStatus
                       END
                   FROM Statuses Statuses2 
                   WHERE
                       Statuses2.StatusId = Statuses.StatusId
                    FOR XML PATH('')
               ), 1, 2, '')
                    AS StatusList
           FROM Statuses
           INNER JOIN dmStatuses ON
               dmStatuses.StatusId = Statuses.StatusId
           WHERE
               Statuses.TableId = @TableId
       ) AS Statuses2 ON
           Statuses2.TableId = Items.TableId
           AND Statuses2.EndDt IS NULL
           AND RowNum = 1
       INNER JOIN dmStatuses dmStatuses2 ON
           dmStatuses2.StatusId = Statuses2.StatusId
       LEFT JOIN dmItems dmItems2 ON
           dmItems2.ItemId = Items.ItemId
       WHERE
           Items.TableId = @TableId
       GROUP BY
           Items.TableId,
           dmItems2.ItemId,
           Statuses2.StatusList
   ) AS ItemCounts
   LEFT JOIN dmItems ON
       dmItems.ItemId = ItemCounts.ItemId
) AS ItemCountsAndLimits
WHERE
   ItemCountsAndLimits.[Count] > ItemCountsAndLimits.Limit

另一種創建方法StatusList是使用STRING_AGG(來自 SQL Server 2017):

SELECT STRING_AGG(x.status,',') FROM (
  SELECT
     ROW_NUMBER() OVER (PARTITION BY StatusId) as RowNum,
     CASE WHEN Status.Rescriced = 1 THEN ItemStatus + ' (Restricted)'
          ELSE ItemStatus END AS Status
  FROM Statuses) x

以上查詢未經測試,應根據您的情況進行調整。

我相信如果你改變你的 CASE 語句來評估 a NULL,你應該沒問題,如下所示:

CASE
   WHEN Statuses2.Restricted IS NULL OR Statuses2.Restricted = 0 THEN ', ' + dmStatuses2.ItemStatus
   ELSE ', ' + dmStatuses2.ItemStatus + ' (Restricted)'
END

請注意,我評估的是NULLor 0 而不是 1,基本上顛倒了您的邏輯,因為這應該正確地擷取NULL您的描述。

此外,看起來您正在執行內部連接,dmStatuses2並且Statuses2通過設計過濾掉所有 NULL 欄位,因此您需要將其更改為LEFT JOIN

LEFT JOIN dmStatuses dmStatuses2 ON
       dmStatuses2.StatusId = Statuses2.StatusId

引用自:https://dba.stackexchange.com/questions/253336