Sql 基于多个子项配对的父项计数
在下面的例子中,我试图根据每个酒吧的食材供应情况来计算我可以制作的饮料数量 进一步澄清,如以下示例所示:基于下图中突出显示的数字;我知道,如果我将供应品运送到该地点,我只能在2018年6月30日在DC或FL生产一瓶玛格丽塔 数据表样本 请使用以下代码输入上述相关数据:Sql 基于多个子项配对的父项计数,sql,sql-server,parent-child,cross-apply,outer-apply,Sql,Sql Server,Parent Child,Cross Apply,Outer Apply,在下面的例子中,我试图根据每个酒吧的食材供应情况来计算我可以制作的饮料数量 进一步澄清,如以下示例所示:基于下图中突出显示的数字;我知道,如果我将供应品运送到该地点,我只能在2018年6月30日在DC或FL生产一瓶玛格丽塔 数据表样本 请使用以下代码输入上述相关数据: CREATE TABLE #drinks ( a_date DATE, loc NVARCHAR(2), parent NVAR
CREATE TABLE #drinks
(
a_date DATE,
loc NVARCHAR(2),
parent NVARCHAR(20),
line_num INT,
child NVARCHAR(20),
avail_amt INT
);
INSERT INTO #drinks VALUES ('6/26/2018','CA','Long Island','1','Vodka','7');
INSERT INTO #drinks VALUES ('6/27/2018','CA','Long Island','2','Gin','5');
INSERT INTO #drinks VALUES ('6/28/2018','CA','Long Island','3','Rum','26');
INSERT INTO #drinks VALUES ('6/26/2018','DC','Long Island','1','Vodka','15');
INSERT INTO #drinks VALUES ('6/27/2018','DC','Long Island','2','Gin','18');
INSERT INTO #drinks VALUES ('6/28/2018','DC','Long Island','3','Rum','5');
INSERT INTO #drinks VALUES ('6/26/2018','FL','Long Island','1','Vodka','34');
INSERT INTO #drinks VALUES ('6/27/2018','FL','Long Island','2','Gin','14');
INSERT INTO #drinks VALUES ('6/28/2018','FL','Long Island','3','Rum','4');
INSERT INTO #drinks VALUES ('6/30/2018','DC','Margarita','1','Tequila','6');
INSERT INTO #drinks VALUES ('7/1/2018','DC','Margarita','2','Triple Sec','3');
INSERT INTO #drinks VALUES ('6/29/2018','FL','Margarita','1','Tequila','1');
INSERT INTO #drinks VALUES ('6/30/2018','FL','Margarita','2','Triple Sec','0');
INSERT INTO #drinks VALUES ('7/2/2018','CA','Cuba Libre','1','Rum','1');
INSERT INTO #drinks VALUES ('7/8/2018','CA','Cuba Libre','2','Coke','5');
INSERT INTO #drinks VALUES ('7/13/2018','CA','Cuba Libre','3','Lime','14');
INSERT INTO #drinks VALUES ('7/5/2018','DC','Cuba Libre','1','Rum','0');
INSERT INTO #drinks VALUES ('7/19/2018','DC','Cuba Libre','2','Coke','12');
INSERT INTO #drinks VALUES ('7/31/2018','DC','Cuba Libre','3','Lime','9');
INSERT INTO #drinks VALUES ('7/2/2018','FL','Cuba Libre','1','Rum','1');
INSERT INTO #drinks VALUES ('7/19/2018','FL','Cuba Libre','2','Coke','3');
INSERT INTO #drinks VALUES ('7/17/2018','FL','Cuba Libre','3','Lime','2');
INSERT INTO #drinks VALUES ('6/30/2018','DC','Long Island','3','Rum','4');
INSERT INTO #drinks VALUES ('7/7/2018','FL','Cosmopolitan','5','Triple Sec','7');
预期结果如下:
请注意,正如预期结果所示,儿童是可互换的。例如,2018年7月7日,《世界杯》的三倍秒到达;然而,因为孩子也是朗姆酒,它改变了佛罗里达州玛格丽塔酒的供应
也不是6月30日和6月31日对古巴自由贸易区的更新
请考虑到零件是可互换的,并且每次新项目到达时,都会使以前的任何项目可用
最后,如果我可以添加另一个专栏,显示工具包的可用性,而不考虑位置,这将是非常棒的,仅基于孩子的可用性。例如,如果DC中有一个孩子3,而FL中没有孩子3,那么FL可以假设他们有足够的库存,可以根据其他位置的库存制作饮料 我认为这将给出所需的结果 创建了一个用于获取库存的函数
Create function GetInventoryByDateAndLocation
(@date DATE, @Loc NVARCHAR(2))
RETURNS TABLE
AS
RETURN
(
Select child,avail_amt from
(Select a_date, child,avail_amt,
ROW_NUMBER() over (partition by child order by a_date desc) as ranking
from drinks where loc = @Loc and a_date<=@date)c
where ranking = 1
)
这将使所有的饮料,可以从库存。希望它能解决你的问题
这只是我的2美分。有更好的方法可以做到这一点,我希望更多的人会读到这篇文章并提出更好的建议。不要认为这正是你想要的。。。也许会有帮助
SELECT DISTINCT #drinks.loc,#drinks.parent,avail.Avail
FROM #drinks
LEFT OUTER JOIN (
SELECT DISTINCT #drinks.parent, MIN(availnow.maxavailnow / line_num)
OVER(PARTITION BY parent) as Avail
FROM #drinks
LEFT OUTER JOIN (
SELECT #drinks.child,SUM(avail_amt) maxavailnow
FROM #drinks
LEFT OUTER JOIN (SELECT MAX(a_date) date,loc,child FROM #drinks GROUP BY loc,child) maxx ON #drinks.loc = maxx.loc AND #drinks.child = maxx.child AND maxx.date = #drinks.a_date
GROUP BY #drinks.child
) availnow ON #drinks.child = availnow.child
) avail ON avail.parent = #drinks.parent
我已经创建了两个额外的表来帮助编写查询,但是如果需要,可以从饮料表生成这些表:
CREATE TABLE #recipes
(
parent NVARCHAR(20),
child NVARCHAR(20)
);
INSERT INTO #recipes VALUES ('Long Island', 'Vodka');
INSERT INTO #recipes VALUES ('Long Island', 'Gin');
INSERT INTO #recipes VALUES ('Long Island', 'Rum');
INSERT INTO #recipes VALUES ('Maragrita', 'Tequila');
INSERT INTO #recipes VALUES ('Maragrita', 'Triple Sec');
INSERT INTO #recipes VALUES ('Cuba Libre', 'Coke');
INSERT INTO #recipes VALUES ('Cuba Libre', 'Rum');
INSERT INTO #recipes VALUES ('Cuba Libre', 'Lime');
INSERT INTO #recipes VALUES ('Cosmopolitan', 'Cranberry Juice');
INSERT INTO #recipes VALUES ('Cosmopolitan', 'Triple Sec');
CREATE TABLE #locations
(
loc NVARCHAR(20)
);
INSERT INTO #locations VALUES ('CA');
INSERT INTO #locations VALUES ('FL');
INSERT INTO #locations VALUES ('DC');
然后,查询变成:
DECLARE @StartDateTime DATETIME
DECLARE @EndDateTime DATETIME
SET @StartDateTime = '2018-06-26'
SET @EndDateTime = '2018-07-31';
--First, build a range of dates that the report has to run for
WITH DateRange(a_date) AS
(
SELECT @StartDateTime AS DATE
UNION ALL
SELECT DATEADD(d, 1, a_date)
FROM DateRange
WHERE a_date < @EndDateTime
)
SELECT a_date, parent, loc, avail_amt
FROM (--available_recipes_inventory
SELECT a_date, parent, loc, avail_amt,
LAG(avail_amt, 1, 0) OVER (PARTITION BY loc, parent ORDER BY a_date) AS previous_avail_amt
FROM (--recipes_inventory
SELECT a_date, parent, loc,
--The least amount of the ingredients for a recipe is the most
--amount of drinks we can make for it
MIN(avail_amt) as avail_amt
FROM (--ingredients_inventory
SELECT dr.a_date, r.parent, r.child, l.loc,
--Default ingredients we don't have with a zero amount
ISNULL(d.avail_amt, 0) as avail_amt
FROM DateRange dr CROSS JOIN
#recipes r CROSS JOIN
#locations l OUTER APPLY
(
--Find the total amount available for each
--ingredient at each location for each date
SELECT SUM(d1.avail_amt) as avail_amt
FROM #drinks d1
WHERE d1.a_date <= dr.a_date
AND d1.loc = l.loc
AND d1.child = r.child
) d
) AS ingredients_inventory
GROUP BY a_date, parent, loc
) AS recipes_inventory
--Remove all recipes that we don't have enough ingredients for
WHERE avail_amt > 0
) AS available_recipes_inventory
--Selects the first time a recipe has enough ingredients to be made
WHERE previous_avail_amt = 0
--Selects when the amount of ingredients has changed
OR previous_avail_amt != avail_amt
ORDER BY a_date
--MAXRECURSION needed to generate the date range
OPTION (MAXRECURSION 0)
GO
选择MAXd2.a\u日期
从作为d2的饮料
其中d2.parent=d.parent
d2.loc=d.loc作为一个_日期
,d.loc
,d.父母
,SUMd.avail\u amt AS[avail\u amtSUM]
,COUNTd.avail\u amt为[avail\u amt count]
从饮料中提取d
d.loc分组
,d.父母
按a_日期下单顺便说一句,出色的职位招聘数据、预期输出和所需逻辑的详细信息。我希望每个人在发帖时都能如此小心。做得好!!对我来说,对期望结果的逻辑解释不够。为什么在6月30日你能在华盛顿建造9个长岛?为什么你只能在6月28日在华盛顿建造4个长岛?看起来仍然有问题。。如果你在6月28日那天只有5杯杜松子酒,你怎么能在加州的7个长岛上生产呢?@SMHorus你错过了一份确定的配料表。从这些数据中我们无从得知世界主义者需要什么。正如我在上面的聊天中提到的,你应该制作三张单独的表格:按日期列出的地点清单、地点菜单和饮料配方。关于这个问题,最令人困惑的是,你如何制作一个没有可乐、龙舌兰和三倍秒的长岛?谢谢你的努力和反馈。我在我的系统中的实际表中尝试了这一点。不幸的是,它只返回一条记录。我不认为您在库存函数中考虑了行数。除此之外,您创建的函数可以创建超过2200万条记录,我知道这似乎是错误的。我只是认为行_num用于识别孩子。我将添加对代码的解释,然后您可以尝试进行一些修改
DECLARE @StartDateTime DATETIME
DECLARE @EndDateTime DATETIME
SET @StartDateTime = '2018-06-26'
SET @EndDateTime = '2018-07-31';
--First, build a range of dates that the report has to run for
WITH DateRange(a_date) AS
(
SELECT @StartDateTime AS DATE
UNION ALL
SELECT DATEADD(d, 1, a_date)
FROM DateRange
WHERE a_date < @EndDateTime
)
SELECT a_date, parent, loc, avail_amt
FROM (--available_recipes_inventory
SELECT a_date, parent, loc, avail_amt,
LAG(avail_amt, 1, 0) OVER (PARTITION BY loc, parent ORDER BY a_date) AS previous_avail_amt
FROM (--recipes_inventory
SELECT a_date, parent, loc,
--The least amount of the ingredients for a recipe is the most
--amount of drinks we can make for it
MIN(avail_amt) as avail_amt
FROM (--ingredients_inventory
SELECT dr.a_date, r.parent, r.child, l.loc,
--Default ingredients we don't have with a zero amount
ISNULL(d.avail_amt, 0) as avail_amt
FROM DateRange dr CROSS JOIN
#recipes r CROSS JOIN
#locations l OUTER APPLY
(
--Find the total amount available for each
--ingredient at each location for each date
SELECT SUM(d1.avail_amt) as avail_amt
FROM #drinks d1
WHERE d1.a_date <= dr.a_date
AND d1.loc = l.loc
AND d1.child = r.child
) d
) AS ingredients_inventory
GROUP BY a_date, parent, loc
) AS recipes_inventory
--Remove all recipes that we don't have enough ingredients for
WHERE avail_amt > 0
) AS available_recipes_inventory
--Selects the first time a recipe has enough ingredients to be made
WHERE previous_avail_amt = 0
--Selects when the amount of ingredients has changed
OR previous_avail_amt != avail_amt
ORDER BY a_date
--MAXRECURSION needed to generate the date range
OPTION (MAXRECURSION 0)
GO
+------------+-------------+-----+-----------+
| a_date | parent | loc | avail_amt |
+------------+-------------+-----+-----------+
| 2018-06-28 | Long Island | DC | 5 |
| 2018-06-28 | Long Island | CA | 5 |
| 2018-06-28 | Long Island | FL | 4 |
| 2018-06-30 | Long Island | DC | 9 |
| 2018-07-01 | Maragrita | DC | 3 |
| 2018-07-02 | Long Island | FL | 5 |
| 2018-07-07 | Maragrita | FL | 1 |
| 2018-07-13 | Cuba Libre | CA | 5 |
| 2018-07-19 | Cuba Libre | FL | 2 |
| 2018-07-31 | Cuba Libre | DC | 9 |
+------------+-------------+-----+-----------+