SQL Server 确定与选择项目相关的主餐

sd2nnvve  于 2023-02-03  发布在  其他
关注(0)|答案(2)|浏览(142)

我有一个餐馆的MS SQL Server数据库。有一个事务表,显示了订购的饭菜,以及在适用的情况下,每顿饭订购的可选(选择)项目,例如“带薯条”,“带豆子”。
我正试图确定,对于每一个选择项目,什么是主食,它是命令与。
如何编写一个查询,使其无论有多少选择项都能找到合适的主餐?我们可以假设每个选择项都属于同一个主餐,直到新的主餐出现。
预期结果可能如下所示(查询创建的第一列和最后一列,中间列出现在表中):-
| 事务处理内的行|交易ID|行号|课程类别|项目名称|关联主餐|
| - ------|- ------|- ------|- ------|- ------|- ------|
| 1个|一百二十三|小行星123456|主要|牛排|零|
| 第二章|一百二十三|小行星123457|选择|芯片|牛排|
| 三个|一百二十三|小行星123458|选择|豆类|牛排|
| 1个|一百二十四|小行星124567|主要|鱼|零|
| 第二章|一百二十四|小行星124568|选择|豆沙|鱼|
由于同一主餐可能有多个选项,因此类似LAST_VALUE()或LAG()(其中我们滞后1)的选项并不总是给予正确答案(例如:- )

CASE WHEN CourseCategory = 'Choice Items' THEN
    LAST_VALUE(ItemName)
    OVER(PARTITION BY TransactionID
        ORDER BY LineNumber ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
    ELSE NULL END AS AssociatedMainMeal

CASE WHEN CourseCategory = 'Choice Items' THEN
    LAG(ItemName,1,0)
    OVER(PARTITION BY TransactionID
        ORDER BY LineNumber)
    ELSE NULL END AS AssociatedMainMeal

我怀疑ROW_NUMBER()可能在某些地方有用,例如:ROW_NUMBER()OVER(PARTITION BY TransactionID ORDER BY LineNumber)AS RowWithinTxn,因为这会将表分割为单独的事务ID
非常感谢!

zaqlnxep

zaqlnxep1#

要在此处使用条件聚集:

MAX(CASE CourseCategory WHEN 'Main' THEN ItemName END) OVER (PARTITION BY TransactionID)
4xrmg8kj

4xrmg8kj2#

假设每个事务可以有很多主餐,那么实际上需要一个LAG函数来忽略某些行。在一些RDMBS中有一个IGNORE NULLS选项,在那里你可以使用如下的内容:

LAG(CASE WHEN CourseCategoruy = 'Main' THEN ItemName END) IGNORE NULLS
    OVER(PARTITION BY TransactionID ORDER BY Linenumber)

不幸的是SQL Server不支持这个,但是Itzik Ben-Gan came up with a nice workaround使用窗口函数。本质上,如果你把你的排序列和数据列组合成一个二进制值,你可以用类似于LAG的方式使用MAX,因为最大二进制值总是前一行,因为排序列是它的一部分。
但是,这确实会让阅读变得非常痛苦,因为您必须将两列转换为二进制并将它们组合起来:

CONVERT(BINARY(4), t.Linenumber) + 
 CONVERT(BINARY(50), CASE WHEN t.CourseCategory = 'Main' THEN t.ItemName END)

那就取最大值

MAX(<result of above expression>) OVER(PARTITION BY t.TransactionID ORDER BY t.LineNumber)

然后删除前4个字符(从linenumber)并转换回varchar:

CONVERT(VARCHAR(50), SUBSTRING(<result of above expression>, 5, 50)

最后,您只需要显示非主餐的此值

CASE WHEN t.CourseCategory <> 'Main' THEN <result of above expression> END

将这些信息结合起来,沿着加上一些示例数据,您最终会得到:

DROP TABLE IF EXISTS #T;
CREATE TABLE #T
(
    RowWithinTxn INT,
    TransactionID INT,
    LineNumber INT,
    CourseCategory VARCHAR(6),
    ItemName VARCHAR(10)
);

INSERT INTO #T
(
    RowWithinTxn,
    TransactionID,
    LineNumber,
    CourseCategory,
    ItemName
)
VALUES
    (1, 123, 123456, 'Main', 'Steak'),
    (2, 123, 123457, 'Choice', 'Chips'),
    (3, 123, 123458, 'Choice', 'Beans'),
    (1, 124, 124567, 'Main', 'Fish'),
    (2, 124, 124568, 'Choice', 'Mushy Peas');

SELECT  t.RowWithinTxn, 
        t.TransactionID,
        t.LineNumber, 
        t.CourseCategory, 
        t.ItemName, 
        AssociatedMainMeal = CASE WHEN t.CourseCategory <> 'Main' THEN 
                                CONVERT(VARCHAR(50), SUBSTRING(MAX(CONVERT(BINARY(4), t.Linenumber) + CONVERT(BINARY(50), CASE WHEN t.CourseCategory = 'Main' THEN t.ItemName END))
                                                                    OVER(PARTITION BY t.TransactionID ORDER BY t.LineNumber), 5, 50)) 
                            END
FROM    #T AS t;

相关问题