FOR XML PATH 只产生第一项

FOR XML PATH produces only first item

我有两个表:Reservations 和 ReservationNights(每个预订都有很多晚)。

在存储过程中,我有一个如下所示的变量:@roomTypeList = '2;3;4;5;' -> 它是一个 RoomUseId 列表。

我只需要显示具有其中一个 ID 的预订晚数的预订(在此示例中,它应该只显示预订 14105,因为存在 RoomUseId = 3 和 '2;3;4;5;'变量包含 3.

我试过使用类似的方法,但效果不佳 - 有时应该显示多个预订时它只显示 1 个预订,通常它什么都不显示。

SELECT DISTINCT r.Id, r.BookingStatus, r.CurrencyId
        FROM Reservations r
        --JOIN ReservationNights rn ON rn.ReservationId = r.Id
        WHERE
(@roomTypeListLocal IS NULL OR (@roomTypeListLocal LIKE ('%' + CAST((SELECT STUFF((SELECT ';' + CAST(rn.RoomUseId as nvarchar(MAX))
                FROM ReservationNights rn
                WHERE rn.ReservationId = r.Id AND rn.RoomUseId IS NOT NULL
                FOR XML PATH('')), 1, 1, '')) as nvarchar(MAX)) + ';%')))

我建议另一种方法:确保变量在每个值前后都有分隔符(例如:';2;3;4;5;'),并使用 EXISTS 查询:

SELECT DISTINCT r.Id, r.BookingStatus, r.CurrencyId
FROM Reservations r
WHERE
(
    @roomTypeListLocal IS NULL
OR
    EXISTS
    (
        SELECT 1
        FROM ReservationNights rn
        WHERE rn.ReservationId = r.Id
        AND rn.RoomUseId IS NOT NULL
        AND @roomTypeListLocal LIKE ';' + CAST(rn.RoomUseId As varchar(10)) + ';'
    )
)

你的关键问题是缺乏规范化。如果您有列表,请将其存储为列表。

因此您需要一个 table 变量或 Table 值参数。 在紧要关头,您可以拆分现有的字符串,但最好首先让数据采用正确的格式。

DECLARE @roomTypeList TABLE (roomType int PRIMARY KEY);
INSERT @roomTypeList (roomType)
SELECT *
FROM STRING_SPLIT(@roomTypeListLocal, ';');

SELECT
  r.Id,
  r.BookingStatus,
  r.CurrencyId
FROM Reservations r
WHERE
    @roomTypeListLocal IS NULL
    OR EXISTS (SELECT 1
        FROM ReservationNights rn
        JOIN @roomTypeList rl ON rl.roomType = rn.RoomUseId
        WHERE rn.ReservationId = r.Id
    );

如果您真的想要坚持使用逗号分隔的列表,您可以将 STRING_SPLIT 合并到上述查询中,而不是尝试构建等效的聚合字符串.