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

これで、2 つのペアの組み合わせの重みに基づいて検索が行われます。説明させてください。

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

したがって、任意の 2 つの数値の重みが候補であることがわかります (例: (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 では完全な順列を見つけ、2 番目の CTE では 2 つの要素のみが関与する値を選択しているためです。

そのため、値が大きくなると、最初の 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

非常に小さなセットに対して総当り法を使用してペア、トリプレットなどを一般的に解くには、これが機能する場合があります。示された 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
于 2012-10-17T09:58:22.540 に答える