Sql 查询以查找行中的特定总和

Posted

技术标签:

【中文标题】Sql 查询以查找行中的特定总和【英文标题】:Sql Query to find specific sum in rows 【发布时间】:2021-12-31 06:39:58 【问题描述】:

这是由该查询生成的调色板列表:

select STO_COD_ART PRODUCT_NAME,STO_NUMPAL PALETTE_NUMBER,STO_PNET NET_WEIGHT
from GCSTOCK
where STO_COD_ART = '739155VPFK500'
and STO_OUTDATE is null;
PRODUCT_NAME PALETTE_NUMBER NET_WEIGHT
739155VPFK500 227881 770
739155VPFK500 241691 894
739155VPFK500 246221 975
739155VPFK500 246471 861
739155VPFK500 246531 882

(derived from this image)

我正在尝试选择总和 sum(NET_WEIGHT) 在 1600 和 1700 之间的最小行数。 我已尝试使用以下查询,但未返回预期结果:

select STO_COD_ART PRODUCT_NAME,STO_NUMPAL PALETTE_NUMBER,STO_PNET NET_WEIGHT
from GCSTOCK
where STO_COD_ART = '739155VPFK500'
and STO_OUTDATE is null
group by STO_COD_ART, STO_NUMPAL, STO_PNET
having (SUM(STO_PNET) >= 1600 and SUM(STO_PNET) <= 1700);

我相信尝试将 GROUP BYHAVING CLAUSE 一起使用是行不通的,因为我需要原始形式的结果,而不是分组结果的 1 条记录,我需要某种方法来验证最少的数字可能的记录用于创建组。

The expected result would be:

PRODUCT_NAME PALETTE_NUMBER NET_WEIGHT
739155VPFK500 227881 770
739155VPFK500 241691 894

感谢您的帮助

【问题讨论】:

你能澄清一下“在这个列表中搜索一个 这不起作用,因为您在 group by 子句中添加了自动增量字段 你的意思是,如果托盘 STO_PNET 为 n,则找到另一个 STO_PNET 在列表中,查询将选择一个二或三个...(我们不知道)STO_ID 和 sum(STO_PNET) 尽可能与 1500 最接近。 请根据您提供的源数据使用您期望的结果更新问题 【参考方案1】:

拣选最少数量的托盘以满足数量的概念是基于这样一种理念,即抓取和移动托盘是劳动/时间密集型的,应尽量减少以实现最佳的整个过程。

如果这是一个测试问题那么很好,这个答案会起作用,但这个概念在现实中是有缺陷的,因为理论上它需要在仓库的整个生命周期内无限量的存储,如果它也将接收库存。实际上,我们要么先选择整个托盘(如果不需要重新包装),要么先从数量最少的托盘中挑选,以最大限度地利用存储空间并为新到货的仓库腾出空间。如果需要尽量减少货物的变质或老化,那么您将首先从最旧的托盘中挑选。

要获得最少的托盘数量,我们确实需要评估所有或至少许多托盘组合,然后选择具有最少托盘的组合。在 SQL 中,我们可以使用递归 CTE 来构建我们想要考虑的所有可能组合的矩阵,然后我们可以根据您的业务逻辑对这些结果进行排序,并将该列表中的第一个结果作为 最佳 组合。

然后,您将采用 最佳 组合并从原始来源重新查询以产生您的应用程序所期望的结果。

在可以用 C#、Python、javascript 甚至在存储过程中执行的程序代码过程中,我们通常会使用一种算法,首先选择最大的托盘,然后遍历剩余的托盘并选择下一个最大的托盘仍然满足标准的托盘。递归 CTE 可以产生相同的结果,但它以不同的方式表示。

MS Sql Server version of a Recursive CTE for this can be viewed here,在该示例中,我添加了一些额外的托盘定义,并允许最多 4 个托盘组合。您可以根据需要选择允许更多或更少的组合。

假设最佳标准是由托盘形成的矩阵是具有最大组合重量的组合,如下表所示:

PIndex Pallet_1 Pallet_2 Pallet_3 Pallet_4 NET_WEIGHT
2 241691 227881 (null) (null) 1664
2 246531 227881 (null) (null) 1652
2 246471 227881 (null) (null) 1631

但如果最佳标准是首先挑选最旧的托盘(托盘编号越低表示旧托盘),则矩阵中的项目顺序不同:http://sqlfiddle.com/#!18/201c3/6

PIndex Pallet_1 Pallet_2 Pallet_3 Pallet_4 NET_WEIGHT
2 241691 227881 (null) (null) 1664
2 246471 227881 (null) (null) 1631
2 246531 227881 (null) (null) 1652

微妙,并且不会改变此特定数据集中的结果,而是更改具有不同托盘和数量的数据集,或者实际上如果您在移除之前的托盘后再次运行此程序,那么排序对您来说可能很重要。

您可能可以使用第一条记录,因此在您的应用程序中从该集合中选择TOP 1,但如果从原始数据集中选择其他属性很重要,我们可以简单地使用此输出来过滤(或连接)源数据:

查看完整的小提琴:http://sqlfiddle.com/#!18/201c3/7

WITH FilteredPallets as (
    SELECT STO_COD_ART,STO_NUMPAL,STO_PNET
    FROM GCSTOCK
    WHERE STO_COD_ART = '739155VPFK500'
      AND STO_OUTDATE is null
      AND STO_PNET <= 1700
), PalletHierarchy as (
    SELECT 1 as PIndex
         , STO_NUMPAL as Pallet_1, CAST(null as int) as Pallet_2, CAST(null as int) as Pallet_3, CAST(null as int) as Pallet_4
         , STO_PNET as NET_WEIGHT, STO_PNET as Last_Weight
    FROM FilteredPallets
    UNION ALL
    SELECT 2
         , P1.Pallet_1, P2.STO_NUMPAL as Pallet_2, null, null
         , P2.STO_PNET + P1.NET_WEIGHT as NET_WEIGHT, P2.STO_PNET as Last_Weight
    FROM PalletHierarchy P1, FilteredPallets P2
    WHERE P1.PIndex = 1
      AND P2.STO_NUMPAL <> P1.Pallet_1
      AND P2.STO_PNET <= P1.Last_Weight 
      AND (P2.STO_PNET + P1.NET_WEIGHT) <= 1700
    UNION ALL
    SELECT 3
         , P1.Pallet_1, P1.Pallet_2, P2.STO_NUMPAL as Pallet_3, null
         , P2.STO_PNET + P1.NET_WEIGHT as NET_WEIGHT, P2.STO_PNET as Last_Weight
    FROM PalletHierarchy P1, FilteredPallets P2
    WHERE P1.PIndex = 2
      AND P2.STO_NUMPAL <> P1.Pallet_1 AND P2.STO_NUMPAL <> P1.Pallet_2
      AND P2.STO_PNET <= P1.Last_Weight 
      AND (P2.STO_PNET + P1.NET_WEIGHT) <= 1700
      UNION ALL
    SELECT 4
         , P1.Pallet_1, P1.Pallet_2, P1.Pallet_3, P2.STO_NUMPAL as Pallet_4
         , P2.STO_PNET + P1.NET_WEIGHT as NET_WEIGHT, P2.STO_PNET as Last_Weight
    FROM PalletHierarchy P1, FilteredPallets P2
    WHERE P1.PIndex = 3
      AND P2.STO_NUMPAL <> P1.Pallet_1 AND P2.STO_NUMPAL <> P1.Pallet_2 AND P2.STO_NUMPAL <> P1.Pallet_3
      AND P2.STO_PNET <= P1.Last_Weight 
      AND (P2.STO_PNET + P1.NET_WEIGHT) <= 1700
 ), Optimal as (
    SELECT TOP 1 * FROM PalletHierarchy   
    WHERE NET_WEIGHT >= 1600
    --ORDER BY PIndex ASC, NET_WEIGHT DESC
    -- sort by age
    ORDER BY PIndex ASC, Pallet_1, Pallet_2, Pallet_3, Pallet_4
)
SELECT STO_COD_ART as PRODUCT_NAME,STO_NUMPAL as PALETTE_NUMBER,STO_PNET as NET_WEIGHT
FROM GCSTOCK
INNER JOIN Optimal P1 ON P1.Pallet_1 = GCSTOCK.STO_NUMPAL 
                      OR P1.Pallet_2 = GCSTOCK.STO_NUMPAL 
                      OR P1.Pallet_3 = GCSTOCK.STO_NUMPAL 
                      OR P1.Pallet_4 = GCSTOCK.STO_NUMPAL  

结果:

PRODUCT_NAME PALETTE_NUMBER NET_WEIGHT
739155VPFK500 227881 770
739155VPFK500 241691 894

【讨论】:

以上是关于Sql 查询以查找行中的特定总和的主要内容,如果未能解决你的问题,请参考以下文章

如何查询我的所有视图设计以查找 SQL Server 中的特定字符串?

需要Tricky sql查询,查找子查询的总和

如何让 sql 排名查询工作以查找特定 id 的排名

SQL 查询以查找遵循特定模式的字符串

sql SQL查询SSISDB以查找与特定SSIS包相关的错误消息

将 SQL 查询转换为 JPQL 查询 - 总和具有特定文本值的属性数