[英]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.