繁体   English   中英

为选择的项目确定相关的主餐

[英]Identify an associated main meal for choice items

我有一个餐厅的 MS SQL 服务器数据库。 有一张交易表显示订购的餐点,如果适用,还显示每餐订购的可选(选择)项目,例如“带薯条”、“带豆子”。

我正在尝试确定,对于每个选择项,订购的主餐是什么。

我怎样才能以这样一种方式编写查询,无论特定主餐有多少选择项目,它总能找到合适的主餐? 我们可以假设每个选择项目都属于同一主餐,直到出现新的主餐。

预期结果可能看起来像这样(查询创建的第一列和最后一列,表中存在中间列):-

RowWithinTxn 事务编号 电话号码 课程类别 项目名 关联主餐
1个 123 123456 主要的 牛扒 NULL
2个 123 123457 选择 筹码 牛扒
3个 123 123458 选择 豆子 牛扒
1个 124 124567 主要的 NULL
2个 124 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,因为这会将表分割成单独的 TransactionID

非常感谢!

你想在这里使用条件聚合:

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

假设您可以在每次交易中吃很多主餐,那么实际上需要一个可以忽略某些行的LAG function。 在某些 RDMBS 中有一个IGNORE NULLS选项,您可以在其中使用类似以下内容的选项:

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

不幸的是 SQL 服务器不支持此功能,但Itzik Ben-Gan 使用窗口函数提出了一个很好的解决方法 本质上,如果您将排序列和数据列组合成一个二进制值,则可以以与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 个字符(来自行号)并转换回 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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM