AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 159340
Accepted
McNets
McNets
Asked: 2016-12-29 06:43:34 +0800 CST2016-12-29 06:43:34 +0800 CST 2016-12-29 06:43:34 +0800 CST

如何获取分层列表的最后一级,按某些字段分组

  • 772

给定架构:

create table containers (
    id int primary key, 
    name text, 
    product_id int, 
    lot int, 
    qty int, 
    parent_id int);

create table orders_items (
    id int,
    position int,
    container_id int);

Wherecontainers是一个层数未知的层级表。

containers.parent_id = containers.id OR null

一个容器可以容纳其他容器,这是一个容器树结构:

  23 Box 40 Parent  [ID: NULL, Lot: NULL, Qty: SUM(20+20)=40]
   |
   |--22 Bag 20     [Parent ID: 23, Lot: NULL, Qty: SUM(10+10)=20]
   |   |--21 Bag 10 [Parent ID: 22, Lot: 701, Qty: 10]
   |   |--22 Bag 10 [Parent ID: 22, Lot: 703, Qty: 10]
   | 
   |--19 Bag 20     [Parent ID: 23, Lot: NULL, Qty: SUM(10+10)=20]
       |--17 Bag 10 [Parent ID: 19, Lot: 700, Qty: 10]
       |--18 Bag 10 [Parent ID: 19, Lot: 701, Qty: 10] 

对我们来说,一个集装箱被视为一个远征单位,根据客户要求,一个集装箱可以是一个简单的 10 件塑料袋,也可以是一个完整的托盘,有 10 箱,每箱 5000 件。只有最后一层的容器有批次分配,父容器可以容纳不同的批次,但始终属于同一产品。

我们需要按批次列出单个订单中包含的所有产品。

  • 不同的产品不能有相同的批次。
  • 一个容器只能装同一产品的容器。

样本数据:

insert into containers values
  (23, 'Box 40',  2, null, 40,  null)
, (16, 'Pallet',  1, null, 120, null)
, (12, 'Bag 20',  1, null, 20,  14)
, (13, 'Bag 20',  1, null, 20,  14)
, (14, 'Box 40',  1, null, 40,  16)
, (19, 'Bag 20',  2, null, 20,  23)
, (22, 'Bag 20',  2, null, 20,  23)
, (5,  'Bag 20',  1, null, 20,  7)
, (6,  'Bag 20',  1, null, 20,  7)
, (7,  'Box 40',  1, null, 40,  16)
, (1,  'Bag 10',  1, 500,  10,  5)
, (2,  'Bag 10',  1, 501,  10,  5)
, (3,  'Bag 10',  1, 502,  10,  6)
, (4,  'Bag 10',  1, 500,  10,  6)
, (8,  'Bag 10',  1, 600,  10,  12)
, (9,  'Bag 10',  1, 601,  10,  12)
, (10, 'Bag 10',  1, 502,  10,  13)
, (11, 'Bag 10',  1, 501,  10,  13)
, (15, 'Box 40',  1, 600,  40,  16)
, (17, 'Bag 10',  2, 700,  10,  19)
, (18, 'Bag 10',  2, 701,  10,  19)
, (20, 'Bag 10',  2, 703,  10,  22)
, (21, 'Bag 10',  2, 701,  10,  22);

insert into orders_items values
(1, 1, 16),
(1, 2, 23);

订单号1有两个详细信息行,容器16& 23,我需要获取这些容器中包含的所有批次。

在此示例中,结果应显示以下行:

+----+------------+-------------+------+------+------------+
| id |    name    |  product_id |  lot |  qty |  parent_id |
+----+------------+-------------+------+------+------------+
|  1 |  'Bag 10'  |           1 |  500 |   10 |          5 |
|  2 |  'Bag 10'  |           1 |  501 |   10 |          5 |
|  3 |  'Bag 10'  |           1 |  502 |   10 |          6 |
|  4 |  'Bag 10'  |           1 |  500 |   10 |          6 |
|  8 |  'Bag 10'  |           1 |  600 |   10 |         12 |
|  9 |  'Bag 10'  |           1 |  601 |   10 |         12 |
| 10 |  'Bag 10'  |           1 |  502 |   10 |         13 |
| 11 |  'Bag 10'  |           1 |  501 |   10 |         13 |
| 15 |  'Box 40'  |           1 |  600 |   40 |         16 |
| 17 |  'Bag 10'  |           2 |  700 |   10 |         19 |
| 18 |  'Bag 10'  |           2 |  701 |   10 |         19 |
| 20 |  'Bag 10'  |           2 |  703 |   10 |         22 |
| 21 |  'Bag 10'  |           2 |  701 |   10 |         22 |
+----+------------+-------------+------+------+------------+

按批次分组:

|----------|---------|-----|----------|
| Order ID | Product | Lot | Quantity |
|----------|---------|-----|----------|
|    1     |    1    | 500 |    20    |
|    1     |    1    | 501 |    20    |
|    1     |    1    | 502 |    20    |
|    1     |    1    | 600 |    50    |
|    1     |    1    | 601 |    10    |
|    1     |    2    | 700 |    10    |
|    1     |    2    | 701 |    20    |
|    1     |    2    | 703 |    10    |
|----------|---------|-----|----------|

我用这个值创建了一个rextester示例。

sql-server sql-server-2012
  • 1 1 个回答
  • 1007 Views

1 个回答

  • Voted
  1. Best Answer
    Hannah Vernon
    2016-12-29T10:26:55+08:002016-12-29T10:26:55+08:00

    此代码显示如何使用递归 CTE 返回您要查找的结果。

    IF OBJECT_ID('dbo.OrdersItems') IS NOT NULL DROP TABLE dbo.OrdersItems;
    IF OBJECT_ID('dbo.Containers') IS NOT NULL DROP TABLE dbo.Containers;
    
    CREATE TABLE dbo.Containers
    (
        ContainerID int NOT NULL
            CONSTRAINT PK_containers
            PRIMARY KEY CLUSTERED
        , ContainerName text NOT NULL
        , ProductID int NOT NULL
        , Lot int NULL
        , Quantity int NOT NULL
        , ParentContainerID int NULL
            CONSTRAINT FK_Containers_ContainerID
            FOREIGN KEY 
            REFERENCES dbo.Containers (ContainerID)
            ON UPDATE NO ACTION
            ON DELETE NO ACTION
    );
    
    CREATE TABLE dbo.OrdersItems 
    (
          OrderID INT NOT NULL
        , Position int NOT NULL
        , ContainerID int NULL
            CONSTRAINT FK_OrdersItems_ContainerID
            FOREIGN KEY
            REFERENCES dbo.Containers (ContainerID)
            ON UPDATE NO ACTION
            ON DELETE NO ACTION
        , CONSTRAINT PK_OrdersItems 
            PRIMARY KEY CLUSTERED (OrderID, Position)
    );
    

    插入示例数据:

    INSERT INTO dbo.Containers (ContainerID, ContainerName, ProductID
                                 , Lot, Quantity, ParentContainerID)
    VALUES 
          (23, 'Box 40',  2, null, 40,  null)
        , (16, 'Pallet',  1, null, 120, null)
        , (12, 'Bag 20',  1, null, 20,  14)
        , (13, 'Bag 20',  1, null, 20,  14)
        , (14, 'Box 40',  1, null, 40,  16)
        , (19, 'Bag 20',  2, null, 20,  23)
        , (22, 'Bag 20',  2, null, 20,  23)
        , (5,  'Bag 20',  1, null, 20,  7)
        , (6,  'Bag 20',  1, null, 20,  7)
        , (7,  'Box 40',  1, null, 40,  16)
        , (1,  'Bag 10',  1, 500,  10,  5)
        , (2,  'Bag 10',  1, 501,  10,  5)
        , (3,  'Bag 10',  1, 502,  10,  6)
        , (4,  'Bag 10',  1, 500,  10,  6)
        , (8,  'Bag 10',  1, 600,  10,  12)
        , (9,  'Bag 10',  1, 601,  10,  12)
        , (10, 'Bag 10',  1, 502,  10,  13)
        , (11, 'Bag 10',  1, 501,  10,  13)
        , (15, 'Box 40',  1, 600,  40,  16)
        , (17, 'Bag 10',  2, 700,  10,  19)
        , (18, 'Bag 10',  2, 701,  10,  19)
        , (20, 'Bag 10',  2, 703,  10,  22)
        , (21, 'Bag 10',  2, 701,  10,  22);
    
    INSERT INTO dbo.OrdersItems (OrderID, Position, ContainerID)
    VALUES (1, 1, 16)
        , (1, 2, 23);
    

    这是递归 CTE:

    ;WITH RecursiveCTE AS
    (
        SELECT c1.ContainerID
            , c1.ContainerName
            , c1.Lot
            , c1.ParentContainerID
            , c1.ProductID
            , c1.Quantity
            , Level = 1
        FROM dbo.Containers c1
        WHERE c1.ParentContainerID IS NULL
        UNION ALL
        SELECT c2.ContainerID
            , c2.ContainerName
            , c2.Lot
            , c2.ParentContainerID
            , c2.ProductID
            , c2.Quantity
            , Level = RecursiveCTE.Level + 1
        FROM dbo.Containers c2
            INNER JOIN RecursiveCTE ON RecursiveCTE.ContainerID = c2.ParentContainerID
    )
    SELECT r.ProductID
        , r.Lot
        , QuantityTotal = SUM(r.Quantity)
    FROM RecursiveCTE r 
    WHERE r.Lot IS NOT NULL
        AND r.Level > 1
    GROUP BY r.ProductID
        , r.Lot;
    

    结果:

    ProductID | Lot | QuantityTotal
    --------: | --: | ------------:
            1 | 500 |            20
            1 | 501 |            20
            1 | 502 |            20
            1 | 600 |            50
            1 | 601 |            10
            2 | 700 |            10
            2 | 701 |            20
            2 | 703 |            10
    

    从上面的代码可以看出,我已经重命名了一些列以更清楚地反映它们的内容,并添加了一些小的格式以及外键引用。

    db<>在这里摆弄

    • 1

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve