Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 根据两对组合的权重,找到最接近的数字_Sql_Sql Server_Sql Server 2008_Tsql - Fatal编程技术网

Sql 根据两对组合的权重,找到最接近的数字

Sql 根据两对组合的权重,找到最接近的数字,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,这是我上一个问题的延续,让我解释一下真实情况,我在寻找什么,为什么 假设我有一张桌子在下面 Declare @t table(Number Int) Insert Into @t Values(10),(20),(30),(40),(18) Number 10 20 30 40 18 我需要找一个数字,比如35(或最接近) 现在将根据两对组合的权重进行搜索。让我解释一下 10+20 = 30 10+30 = 40 10+40 = 50 10+18 = 28 20 + 30 = 50

这是我上一个问题的延续,让我解释一下真实情况,我在寻找什么,为什么

假设我有一张桌子在下面

Declare @t table(Number Int)
Insert Into @t Values(10),(20),(30),(40),(18)

Number
10
20
30
40
18
我需要找一个数字,比如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

事先非常感谢

结果集稍有不同,但如果您只关心如何处理配对,则效率应该会大大提高:

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

对于非常小的集合,要使用蛮力方法一般地求解成对、三元组等,这可能是可行的。更新两个指定位置的编号

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
Declare@t表(数字Int)
插入@t值(10)、(20)、(30)、(40)、(18)
;Cte1(计数器、编号、ID、总重量)为
( 
选择1,数字
,','+强制转换(编号为VARCHAR(最大))
,强制转换(数字为整数)
来自@t
联合所有
选择c.计数器+1,p.编号
,c.Ids+','+强制转换(p.编号为VARCHAR(最大))
,铸造(c.总重量+p.编号为整数)
从@t作为p加入Cte1 c,p.编号其中c.Counter<2——NP完全问题是相当困难的。你需要做一些研究并实现一个合适的多项式解,而不是你的蛮力方法。顺便说一句,我不相信有人会仅仅为你在SQL中实现它。如果你想处理三元组,那么是的,需要另一个内部连接。如果你想改变从涉及的数字来看,Richard的解决方案可能更适合你,但正如他在评论中指出的,解决这个问题通常是一个NP完全问题。
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
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