这是我上一个问题的延续What is the efficient way to generate combination of items in SQL Server?让我解释一下我正在寻找的真实场景以及为什么......
假设我有一个
下的表格Declare @t table(Number Int)
Insert Into @t Values(10),(20),(30),(40),(18)
Number
10
20
30
40
18
我需要找一个35(或最近)的数字。
Declare @NumberToLookfor = 35
现在搜索将根据两对组合的重量进行。让我解释一下。
10+20 = 30
10+30 = 40
10+40 = 50
10+18 = 28
20 + 30 = 50
20 + 40 = 60
20 + 18 = 38
30 + 40 = 70
30 + 18 = 48
40 + 18 = 58
所以我们可以弄清楚任何两个数字的权重在这里是候选者,例如(10,20),(10,30)......(40,18)
一旦我们得到了,在这种情况下,前3个最接近的对将是(20,18),(10,20),(10,30)。因为35到38(20 + 18)之间的污垢是3,其他对(10,20),(10,30)是5。
我认为解释清楚明白我在寻找什么。(如果不是,请告诉我)
最有效的方式是什么?
我的尝试
Declare @t table(Number Int)
Insert Into @t Values(10),(20),(30),(40),(18)
;WITH Cte1 (Number,Ids,TotalWeight) AS
(
SELECT Number
, ',' + CAST(Number AS VARCHAR(MAX))
,CAST(Number AS INT)
FROM @t
UNION ALL
SELECT p.Number
,c.Ids + ',' + CAST(p.Number AS VARCHAR(MAX))
,CAST(c.TotalWeight + p.Number AS INT)
FROM @t AS p JOIN Cte1 c ON p.Number < c.Number
),Cte2 AS(
SELECT
*
,DENSE_RANK() OVER(ORDER BY ABS(TotalWeight - 35)) [rank]
FROM Cte1
WHERE (LEN(Ids) - LEN(REPLACE(Ids, ',', '')))/LEN(',') = 2
)
select *
from Cte2 where [rank] <= 2
有效。
但是如果价值增长很大,说超过50左右,那么它变得非常有效。因为在第一次CTE中,我发现完全排列,在第二次Cte中选择那些只有两个元素参与的值。
因此,当值变大时,第一个Cte表现得非常缓慢。
即使是大桌子,还有其他方法吗?
提供DDL
Declare @t table(Number Int)
Insert Into @t Values
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),
(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),(40),
(41),(42),(43),(44),(45),(46),(47),(48),(49),(50),(51),(52),(53),(54),(55),(56),(57),(58),(59),(60),
(61),(62),(63),(64),(65),(66),(67),(68),(69),(70),(71),(72),(73),(74),(75),(76),(77),(78),(79),(80),
(81),(82),(83),(84),(85),(86),(87),(88),(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100)
非常感谢提前
答案 0 :(得分:1)
稍微不同的结果集,但如果您关心的只是处理对,那么应该效率更高:
Declare @t table(Number Int)
Insert Into @t Values(10),(20),(30),(40),(18)
;WITH Pairs AS
(
SELECT t1.Number as p1,t2.Number as p2,t1.Number + t2.Number as TotalWeight
FROM
@t t1
inner join
@t t2
on
t1.Number < t2.Number
),Cte2 AS(
SELECT
*
,DENSE_RANK() OVER(ORDER BY ABS(TotalWeight - 35)) [rank]
FROM Pairs
)
select *
from Cte2 where [rank] <= 2
结果:
p1 p2 TotalWeight rank
----------- ----------- ----------- --------------------
18 20 38 1
10 30 40 2
10 20 30 2
答案 1 :(得分:1)
对于非常小的集合,使用强力方法一般求解对,三元组等,这可能有效。更新两个指定位置的数字。
Declare @t table(Number Int)
Insert Into @t Values(10),(20),(30),(40),(18)
;WITH Cte1 (Counter,Number,Ids,TotalWeight) AS
(
SELECT 1,Number
, ',' + CAST(Number AS VARCHAR(MAX))
,CAST(Number AS INT)
FROM @t
UNION ALL
SELECT c.Counter+1,p.Number
,c.Ids + ',' + CAST(p.Number AS VARCHAR(MAX))
,CAST(c.TotalWeight + p.Number AS INT)
FROM @t AS p JOIN Cte1 c ON p.Number < c.Number
WHERE c.Counter < 2 --<<** we need only up to 2 numbers
),Cte2 AS(
SELECT
*
,DENSE_RANK() OVER(ORDER BY ABS(TotalWeight - 35)) [rank]
FROM Cte1
WHERE Counter = 2 --<<** use only the pairs
)
select *
from Cte2 where [rank] <= 2