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