15

在下面的示例中,我试图根据我拥有的每个酒吧位置的原料供应情况来计算我可以制作的饮料数量。

为了进一步澄清,如下例所示:基于下表中突出显示的数字;我知道我只能在 2018 年 6 月 30 日制作 1 杯玛格丽塔酒(如果我将用品运送到该地点,则在华盛顿或佛罗里达州)。

数据表样本

按位置组按饮料分类的库存示例图

请使用以下代码输入以上相关数据:

    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 日,Triple Sec 抵达了饮品 cosmopolitan;然而,因为孩子也是朗姆酒,它改变了佛罗里达州玛格丽塔酒的供应。

也不是 06/30 和 06/31 对 Cuba Libre 的 DC 地区的更新。

请考虑到零件是可互换的,并且每次有新物品到货时,它现在都可以使用以前的任何物品。

最后 - 如果我可以添加另一列显示套件可用性,而不管位置如何,这将是非常棒的,仅基于孩子的可用性。对于前。如果在 DC 有一个孩子 #3 而在 FL 没有孩子,他们 FL 可以假设他们有足够的库存来根据另一个位置的库存来制作饮料!

4

4 回答 4

1

我创建了几个额外的表来帮助编写查询,但如果您愿意,可以从 #drinks 表生成这些表:

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

最里面的 SELECT 创建一个由位置、成分、日期和可用数量组成的伪库存表 (ingredients_inventory)。当某个地点在特定日期没有可用的成分时,则使用零。

下一个 SELECT 查询找出每个位置/日期可以制作多少个食谱(同样,这可能为零)。

下一个 SELECT 查询输出是一个中间表,用于收集前一天每个位置的每种配方可以制作多少(同时还删除任何无法制作的饮料)。

最后,最外面的 SELECT 查询使用前一天的数据来查找可以制作的每个特定配方的数量何时发生变化。

此查询产生的数字与您的表格略有不同,但我认为这是因为您的表格错了?以佛罗里达州为例,7 月 2 日会有额外的朗姆酒进入,因此可以制造的长岛数量会增加到 5 个。到 19 日可以制造 2 个自由古巴。

结果:

+------------+-------------+-----+-----------+
| 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         |
+------------+-------------+-----+-----------+
于 2018-09-06T11:42:30.460 回答
0

SELECT ( SELECT MAX(d2.a_date) FROM #drinks AS d2 WHERE d2.parent = d.parent AND d2.loc = d.loc) AS a_date ,d.loc ,d.parent ,SUM(d.avail_amt) AS [avail_amt(SUM)] ,COUNT(d.avail_amt) AS [avail_amt(COUNT)] FROM #drinks AS d GROUP BY d.loc ,d.parent ORDER BY a_date

于 2018-11-05T09:42:00.977 回答
0

我认为这将给出所需的结果。

创建了一个获取库存的函数。

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
)

然后查询:

with parentChild as 
(Select distinct parent, line_num, child from drinks),
ParentChildNo as
(Select parent, max(line_num) as ChildNo from parentChild group by parent)
,Inventory as
(Select a_date,loc,s.* from drinks d cross apply
GetInventoryByDateAndLocation(d.a_date, d.loc)s)
, Available as
(Select a_date,parent,loc,count(*) as childAvailable,min(avail_amt) as quantity 
from Inventory i 
join parentChild c 
on i.child = c.child 
group by parent,loc,a_date)
Select a_date,a.parent,loc,quantity from available a 
join ParentChildNo pc 
on a.parent = pc.parent and a.childAvailable = pc.ChildNo 
where quantity > 0 order by 1

这将提供所有可以从库存中制造的饮料。希望它能解决你的问题。

这些只是我的 2 美分。有更好的方法可以做到这一点,我希望更多的人会阅读并提出更好的建议。

于 2018-06-29T18:15:13.053 回答
0

不要认为这正是您要寻找的……也许它会有所帮助。

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
于 2018-07-10T21:42:16.183 回答