2

这是我之前的问题的延续在 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) 

提前谢谢了

4

2 回答 2

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
于 2012-10-17T09:47:39.627 回答
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
于 2012-10-17T09:58:22.540 回答