【问题标题】:Recursion? How can I group orders by common items递归?如何按常见项目对订单进行分组
【发布时间】:2020-06-06 05:16:33
【问题描述】:

设置是这样的。我有 Orders 和 OrderDetails 并且 OrderDetails 有一个项目编号。订单有很多 OrderDetails。在具有约 10,000 个 OrderDetail 行的约 1000 个订单中,我需要具有最多共同项目的前 16 个订单。

经过一周的研究,这是我的尝试。当我到达第 8 次迭代时,我不得不停下来。这是一个循环,但我不知道如何动态设置临时表名称。我也不知道如何确定我何时拥有 16 个最佳订单。


IF OBJECT_ID('tempdb..#PartNums') IS NOT NULL DROP Table #PartNums
--Gets the part number that is in the most orders
CREATE TABLE #PartNums (ctr int Identity, PartNum varchar(50), CONT int)
INSERT INTO #PartNums SELECT TOP(1) D.PartNum, Count(D.PartNum) AS CONT FROM OrderDetails D
group by  D.PartNum
order by CONT desc

--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders') IS NOT NULL DROP Table #Orders
CREATE TABLE #Orders ( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         Orders O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 1)

-- Using just the orders that have the number 1 part number
-- Get the part number that is next most popular in the orders
--Exclude the first part number from the grouping

INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc


--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders2') IS NOT NULL DROP Table #Orders2
CREATE TABLE #Orders2 ( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders2 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 2)


INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders2 O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc


--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders3') IS NOT NULL DROP Table #Orders3
CREATE TABLE #Orders3 ( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders3 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders2 O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 3)


INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders3 O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc


--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders4') IS NOT NULL DROP Table #Orders4
CREATE TABLE #Orders4 ( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders4 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders3 O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 4)


INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders4 O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc


--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders5') IS NOT NULL DROP Table #Orders5
CREATE TABLE #Orders5 ( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders5 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders4 O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 5)

INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders5 O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc


--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders6') IS NOT NULL DROP Table #Orders6
CREATE TABLE #Orders6 ( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders6 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders5 O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 6)

INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders6 O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc

--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders7') IS NOT NULL DROP Table #Orders7
CREATE TABLE #Orders7( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders7 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders6 O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 7)


INSERT INTO #PartNums SELECT TOP(1)  D.PartNum, Count(D.PartNum) as CONT from OrderDetails D inner join #Orders7 O ON O.Id = D.OrderId
where NOT D.PartNum IN (SELECT partNum from #PartNums)
group by D.PartNum
order by CONT desc


--Gets the orders that have the number one part number in it
IF OBJECT_ID('tempdb..#Orders8') IS NOT NULL DROP Table #Orders8
CREATE TABLE #Orders8( Id int, Ord1 varchar(50), Ord2 varchar(50),PartNum varchar(50))
INSERT INTO #Orders8 SELECT O.Id,O.Ord1,O.Ord2, D.PartNum
FROM            OrderDetails D INNER JOIN
                         #Orders7 O ON D.OrderId = O.Id
                         where D.PartNum IN (SELECT partNum from #PartNums WHERE ctr = 7)

SELECT DISTINCT OrderId FROM OrderDetails where PartNum in (SELECT partNum from #PartNums);

SELECT * FROM #Orders8;

【问题讨论】:

标签: sql sql-server recursion grouping rollup


【解决方案1】:

因为没有给出 DDL,所以我在这个 FIDDLE 上创建了一个“简单”示例

SELECT 
    Parts, 
    STRING_AGG(id,',') WITHIN GROUP (ORDER BY Id) as PartsCombinationInOrder,
    COUNT(*)           as NumberOfTimes
FROM (
  SELECT
     Orders.Id, STRING_AGG(Order_details.Part_no,',') WITHIN GROUP (ORDER BY Order_details.Part_no) as Parts
  FROM Orders
  INNER JOIN Order_Details on Order_Details.Order_id = Orders.Id
  GROUP BY Orders.Id
) x
GROUP BY x.Parts
ORDER BY COUNT(*) DESC;

有关 ho STRING_AGG() 作品的简短说明,请参阅:STRING_AGG

这将首先获取每个订单上的所有文章,然后对这些文章的组合进行分组,然后按降序排列它们。最喜欢的组合应该放在首位。

编辑:

再次尝试查找订单中的所有文章组合

WITH Orders as(
    SELECT * FROM (VALUES(1),(2),(3),(4)) Orders(Order_Id)
    )
    , Order_Details as (
    SELECT * FROM (VALUES
            (1,1,1),(1,2,2),(1,3,3),(1,4,4),(1,5,5),(1,6,6),
            (2,1,1),(2,2,2),(2,3,3),(2,4,4),(2,5,5),(2,6,6),
            (3,1,1),(3,2,2),(3,3,3),(3,4,4),(3,5,5),(3,6,6), 
            (4,1,1),(4,2,2),(4,3,7),(4,4,3),(4,5,5),(4,6,6)
        ) Order_Details(Order_id,Line_no,Part_no) 
    ),combinations as (
    SELECT o.Order_Id, 
        od1.Line_no as Line1, od1.Part_no as Part1, 
        od2.Line_no as Line2, od2.Part_no as Part2, 
        od3.Line_no as Line3, od3.Part_no as Part3
    FROM Orders o
    INNER JOIN Order_Details od1 ON od1.Order_id = o.Order_Id       
    INNER JOIN Order_Details od2 ON od2.Order_id = o.Order_Id AND od2.Line_no > od1.Line_no
    INNER JOIN Order_Details od3 ON od3.Order_id = o.Order_Id AND od3.Line_no > od2.Line_no AND od3.Line_no > od1.Line_no
    )
SELECT c.Order_Id, c.Part1, c.Part2, c.Part3, q.count
FROM combinations c
CROSS APPLY (SELECT count(*) as count FROM combinations q WHERE q.Part1=c.Part1 and q.Part2=c.Part2 and q.Part3=c.Part3) q
ORDER BY q.count DESC,c.Part1,c.Part2,c.Part3, c.Order_Id;

输出:

Order_Id    Part1       Part2       Part3       count
----------- ----------- ----------- ----------- -----------
1           1           2           3           4
2           1           2           3           4
3           1           2           3           4
4           1           2           3           4
1           1           2           5           4
2           1           2           5           4
✂✂✂✂✂
4           3           5           6           4
1           1           2           4           3
2           1           2           4           3
3           1           2           4           3
1           1           3           4           3
2           1           3           4           3
3           1           3           4           3
1           1           4           5           3
✂✂✂✂✂
2           4           5           6           3
3           4           5           6           3
4           1           2           7           1
4           1           7           3           1
4           1           7           5           1
4           1           7           6           1
4           2           7           3           1
4           2           7           5           1
4           2           7           6           1
4           7           3           5           1
4           7           3           6           1
4           7           5           6           1

(80 rows affected)

我认为这篇文章很容易扩展为'Part4','Part5'等,它允许组合以上显示的3篇文章。

【讨论】:

  • 该示例返回“完全相同”的订单列表。这些命令不相同,但有许多共同点。我需要知道哪些订单具有最常见的零件编号,并且最少。我已经在FIDDLE 上工作,并在其中添加了 cmets 来描述我想要实现的目标。
  • 好的,我明白了,会解决这个问题的.....,您发布的小提琴链接与我发布的链接相同...(您的更改丢失了吗?)跨度>
  • 这里是更新的Fiddle
  • 注意:Step2返回与Step1相同的记录(除了article3),还要注意,在第2步中,您不仅应该省略article3,而且那里选择的订单也应该与article3有一行不会有article3与找到的文章的组合....(很难解释这是....)
  • 是的,你说的都是真的,尤其是(很难解释)。我确定问题在于我如何尝试通过尝试使用我现在肯定的解决方案来解释问题是错误的。当您帮助寻找解决方案时,您不应该使用我之前的任何尝试。因此,考虑到这一点,我想重新构建问题,以便在下一条评论中尽可能清楚。
猜你喜欢
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 2013-03-12
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多