生成所有行分组,其SUM值在两个给定值之间。

3

我有一个如下的表格(products)

id  name      quality  weight
1   Demir-1   ST-1     10
2   Demir-2   ST-2      7
3   Demir-3   ST-1     20
4   Demir-2   ST-3      8
5   Demir-1   ST-3      6
6   Demir-4   ST-2     10
7   Demir-2   ST-2     12
8   Demir-1   ST-1     15
9   Demir-1   ST-3     10
10  Demir-3   ST-3      5
11  Demir-2   ST-2      5

现在,如果用户想要获取权重总和在20到25之间且名称为“Result-2”的产品列表,则结果应如下所示。所有组合都必须显示在其中,其重量总和在20到25之间。
 id name      quality  weight    
  4 Demir-2   ST-3      8   
  7 Demir-2   ST-2     12   
 11 Demir-2  ST-2       5
------------------------------
  2 Demir-2   ST-2      7
  4 Demir-2   ST-3      8
 11 Demir-2   ST-2      5
------------------------------ 
------------------------------ 
  1 Demir-1   ST-1     10
  8 Demir-1   ST-1     15

您可以看到sum(weight)的总和为25。

根据你的示例,是必须所有名称在该组合中都相同,还是你只需要权重在20到25之间的总和? - Simon Wang
1
我仍然不清楚。即使id = 1和id = 8(名称:Demir-1)也会给你25。那么,你的最终输出如何包括id 4、7和11的组合?请解释一下。 - Niladri Biswas
1
请问您能否更新最终结果集?此外,组合是否仅限于相同的“名称”组中,还是可以跨越例如ID 3和11...这将是一个有效的组合吗? - Niladri Biswas
是的,你说得对,最终我更新了最终结果。它必须包括where id = 1和i = 8。 - AEMLoviji
嗨,总记录将为10条,请确认我的答案。我制定了自己的格式,请检查并让我知道有关组合的情况。我们可以稍后决定最终格式。请先检查输出并尽快回复我。 - Niladri Biswas
显示剩余5条评论
5个回答

4
DECLARE @tblProducts TABLE(Id INT IDENTITY, ProductName varchar(50),Quality varchar(50), ProductWeight int)
INSERT INTO @tblProducts SELECT 'Demir-1','ST-1',10
INSERT INTO @tblProducts SELECT 'Demir-2','ST-2',7
INSERT INTO @tblProducts SELECT 'Demir-3','ST-1',20
INSERT INTO @tblProducts SELECT 'Demir-2','ST-3',8
INSERT INTO @tblProducts SELECT  'Demir-1','ST-3',6
INSERT INTO @tblProducts SELECT  'Demir-4','ST-2',10
INSERT INTO @tblProducts SELECT 'Demir-2','ST-2' ,12
INSERT INTO @tblProducts SELECT  'Demir-1','ST-1',15
INSERT INTO @tblProducts SELECT  'Demir-1','ST-3',10
INSERT INTO @tblProducts SELECT 'Demir-3','ST-3' ,5
INSERT INTO @tblProducts SELECT 'Demir-2' ,'ST-2 ',5

 ;WITH Cte (Id,ProductQuality,ProductIds,ProductNames,ProductQualities,ProductTotalWeight,ProductWeights,ProductName1,ProductName2) AS
(
    SELECT  Id
            ,Quality            
            , ',' + CAST(Id AS VARCHAR(MAX))  
            ,',' + CAST(ProductName AS VARCHAR(MAX))
            ,',' + CAST(Quality AS VARCHAR(MAX)) 
            ,ProductWeight
            , ',' + CAST(ProductWeight AS VARCHAR(MAX)) 
            ,ProductName
            ,CAST(ProductName AS VARCHAR(MAX))
    FROM @tblProducts
    UNION ALL
    SELECT p.Id
            , p.Quality            
            ,c.ProductIds + ',' +  CAST(p.Id AS VARCHAR(MAX))
            ,c.ProductNames + ',' +  CAST(p.ProductName AS VARCHAR(MAX)) 
             ,c.ProductQualities + ',' + CAST(p.Quality AS VARCHAR(MAX)) 
             ,c.ProductTotalWeight + p.ProductWeight          
            ,c.ProductWeights + ',' + CAST(p.ProductWeight AS VARCHAR(MAX))
            ,p.ProductName
            ,c.ProductName2
    FROM @tblProducts AS p JOIN Cte c ON p.Id < c.Id
    WHERE  p.ProductName = c.ProductName2
    )
SELECT 
        ProductIds = STUFF(ProductIds,1,1,'')
        ,ProductNames = STUFF(ProductNames,1,1,'')
        ,ProductQualities = STUFF(ProductQualities,1,1,'')
        ,ProductTotalWeight
        ,ProductWeights = STUFF(ProductWeights,1,1,'')
FROM CTE 
WHERE ProductTotalWeight BETWEEN 20 AND 25

结果

ProductIds  ProductNames             ProductQualities   ProductTotalWeight  ProductWeights
3           Demir-3                 ST-1                20                  20
11,7,2      Demir-2,Demir-2,Demir-2 ST-2 ,ST-2,ST-2     24                  5,12,7
11,7,4      Demir-2,Demir-2,Demir-2 ST-2 ,ST-2,ST-3     25                  5,12,8
11,4,2      Demir-2,Demir-2,Demir-2 ST-2 ,ST-3,ST-2     20                  5,8,7
10,3        Demir-3,Demir-3         ST-3,ST-1           25                  5,20
9,1         Demir-1,Demir-1         ST-3,ST-1           20                 10,10
9,8         Demir-1,Demir-1         ST-3,ST-1           25                 10,15
8,1         Demir-1,Demir-1         ST-1,ST-1           25                 15,10
8,5         Demir-1,Demir-1         ST-1,ST-3           21                  15,6
7,4         Demir-2,Demir-2         ST-2,ST-3           20                  12,8

我确信@Nat的答案在我的情况下非常有用,它给出了我想要的结果。你的答案给出了不同的结果。+1,但这是针对另一种情况的。算法很好。 - AEMLoviji
你怎么能说呢..我正在获取每个ProductName组的正确组合和totalProduct重量。如果有不同,请告诉我。我会检查结果。但是,等待您的回复。 - Niladri Biswas
我看到你更新了你的Result。实际上,我运行了@Nats脚本,并得到了我需要的结果。然后我查看了你的响应,但没有运行你的脚本。我发现结果与我所需的不同。 - AEMLoviji
这就是我所询问的...因为如果您查看ProductWeights并进行求和,它会落在范围内。请告知您的顾虑。 - Niladri Biswas
非常感谢,这正是我需要的。请查看@Nat的脚本,它没有显示你结果的第一行(3 Demir-3 ST-1 20 20)。 - AEMLoviji

2

很遗憾,SQL不是从给定计算的表中生成所有组合的正确编码引擎,正如我拼凑出来的SQL代码所示。

通常情况下,考虑到它的性质,我建议使用过程化语言进行编码。此外,请注意,对于更大的输入数据集,这里的解决方案可能会迅速耗尽SQL的递归限制。可能的产品数量也可能增长到足够大的数字,导致运行非常缓慢。

drop table products
drop table #MinW
drop table #Products
go
create table products
(
id  int,
name  varchar(20),  
quality varchar(20),
[weight] int
) 
go
insert into products
select
1,   'Demir-1',   'ST-1',     10 
union
select 2,   'Demir-2',   'ST-2',      7 
union
select 3,   'Demir-3',   'ST-1',     20 
union
select 4,   'Demir-2',   'ST-3',      8 
union
select 5,   'Demir-1',   'ST-3',      6 
union
select 6,   'Demir-4',   'ST-2',     10 
union
select 7,   'Demir-2',   'ST-2',     12 
union
select 8,   'Demir-1',   'ST-1',     15 
union
select 9,   'Demir-1',   'ST-3',     10 
union
select 10,  'Demir-3',   'ST-3',      5 
union
select 11,  'Demir-2',   'ST-2',      5 
go
select 
p.id, p.name, p.quality, p.weight
into #MinW
from products p
inner join
(
select name,min(weight) as weight
from products group by name having min(weight) < 25
) as minW
on p.name = minW.name and p.weight = minW.weight

go
with weightProducts (id, name, [weight],history)
as
( 
select id, name,[weight],convert(varchar(1024),'"'+convert(varchar(10),id)+'",') from #minW
union all
select products.id, products.name,products.[weight] + weightProducts.[weight],convert(varchar(1024),weightProducts.history+'"'+convert(varchar(10),products.id)+'",') from products, weightProducts where products.name = weightproducts.name and  charindex('"'+convert(varchar(10),products.id)+'",',weightProducts.history)<=0 and (products.weight + weightProducts.weight) < 25
)
-- Statement using the CTE
select *
into #Products
from weightProducts
where weight between 20 and 25

go

select 
p1.history,
p2.id,
p2.quality,
p2.weight,
p1.weight as totalWeight
from #Products p1
inner join
products p2 on p1.name = p2.name and charindex('"'+convert(varchar(10),p2.id)+'",',p1.history)>0
order by 
p1.history,
p2.id 

结果在哪里:3 Demir-3 ST-1 20 20 - AEMLoviji
1
@Nat,"11","2","7"和"11","7","2"是重复的。如果我错了,请纠正我。 - Niladri Biswas

0
SELECT * FROM tablename
WHERE name IN (
 SELECT name FROM tablename 
 GROUP BY name
 HAVING SUM(weight) BETWEEN 20 AND 25)

不,这不是我想要的结果。@Niladri Biswas 理解了我的问题,我更新了我的结果集,请看一下。 - AEMLoviji
不是被要求的内容。 - Dan Dascalescu
@DanDascalescu 在修订历史中多次编辑了该问题。我根据原始帖子中提供的所有信息回答了这个问题。如果问题以后被澄清或更改,那么显然答案可能就不再有效。 - Aziz Shaikh

0

这个查询怎么样?

select id, name, quality, weight from PRODUCTS
group by id, name, quality, weight
having sum(weight) between 20 and 25

0

试试这个:

SELECT * FROM products
WHERE name IN (
              SELECT name FROM products
              GROUP BY name
              HAVING SUM(weight) BETWEEN 20 AND 25)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接