C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: SQLレコード内の重複チェック


(過去ログ 172 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■99160 / inTopicNo.1)  SQLレコード内の重複チェック
  
□投稿者/ OA (1回)-(2022/02/13(Sun) 22:52:43)

分類:[データベース全般] 

【環境】SQL Server(SSMS v18.6)

SQLについて、教えてください。

{1〜N}の組み合わせを求めるのに、N個のテーブルをクロス結合しました。
こちらは、簡単にできたのですが、今度は順列を求めようと以下のSQLを考えたのですが、
{1〜4}、{1〜5}と組み合わせが増えるとWHERE句が冗長な表現になります。
WHERE句を、もっと簡単な表現で書けないでしょうか?

{1〜3}(↓のTable1)なら
SELECT * FROM Table1 WHERE A<>B AND A<>C AND B<>C ORDER BY A, B, C
このWHERE句が
{1〜4}なら
WHERE A<>B AND A<>C AND A<>D AND B<>C AND B<>D AND C<>D
{1〜5}なら
WHERE A<>B AND A<>C AND A<>D AND A<>E AND B<>C AND B<>D AND B<>E AND C<>D AND C<>E AND D<>E
と爆発的に増加する。


以下は{1,2,3}の組み合わせ27通りのテーブル(Table1)です。
この中から順列の6通り(○印)を抽出する。
(要はレコード内に1つでも重複があれば抽出しない。)


Table1
      
   A   B   C    
├─┼─┼─┤    
│ 1│ 1│ 1│    
├─┼─┼─┤    
│ 1│ 1│ 2│    
├─┼─┼─┤    
│ 1│ 1│ 3│    
├─┼─┼─┤    
│ 1│ 2│ 1│    
├─┼─┼─┤    
│ 1│ 2│ 2│    
├─┼─┼─┤    
│ 1│ 2│ 3│○  
├─┼─┼─┤    
│ 1│ 3│ 1│    
├─┼─┼─┤    
│ 1│ 3│ 2│○  
├─┼─┼─┤    
│ 1│ 3│ 3│    
├─┼─┼─┤    
│ 2│ 1│ 1│    
├─┼─┼─┤    
│ 2│ 1│ 2│    
├─┼─┼─┤    
│ 2│ 1│ 3│○  
├─┼─┼─┤    
│ 2│ 2│ 1│    
├─┼─┼─┤    
│ 2│ 2│ 2│    
├─┼─┼─┤    
│ 2│ 2│ 3│    
├─┼─┼─┤    
│ 2│ 3│ 1│○  
├─┼─┼─┤    
│ 2│ 3│ 2│    
├─┼─┼─┤    
│ 2│ 3│ 3│    
├─┼─┼─┤    
│ 3│ 1│ 1│    
├─┼─┼─┤    
│ 3│ 1│ 2│○  
├─┼─┼─┤    
│ 3│ 1│ 3│    
├─┼─┼─┤    
│ 3│ 2│ 1│○  
├─┼─┼─┤    
│ 3│ 2│ 2│    
├─┼─┼─┤    
│ 3│ 2│ 3│    
├─┼─┼─┤    
│ 3│ 3│ 1│    
├─┼─┼─┤    
│ 3│ 3│ 2│    
├─┼─┼─┤    
│ 3│ 3│ 3│    
└─┴─┴─┘   

引用返信 編集キー/
■99162 / inTopicNo.2)  Re[1]: SQLレコード内の重複チェック
□投稿者/ 魔界の仮面弁士 (3293回)-(2022/02/14(Mon) 00:26:45)
No99160 (OA さん) に返信
> {1〜N}の組み合わせを求めるのに、N個のテーブルをクロス結合しました。
> こちらは、簡単にできたのですが、今度は順列を求めようと以下のSQLを考えたのですが、
> {1〜4}、{1〜5}と組み合わせが増えるとWHERE句が冗長な表現になります。
> WHERE句を、もっと簡単な表現で書けないでしょうか?

たとえば P(n, k) の順列だと、自分なら「再帰 SQL」を使ってこう書きます。

WITH TBL (NUM) AS (
  SELECT NUM = 1 UNION ALL
  SELECT NUM + 1 FROM TBL WHERE NUM < n
) SELECT
  T1.NUM AS C1
, T2.NUM AS C2
, T3.NUM AS C3
    :
    :
, Tk.NUM AS Ck
FROM TBL T1
JOIN TBL T2 ON T2.NUM <> T1.NUM
JOIN TBL T3 ON T3.NUM <> T2.NUM AND T3.NUM <> T1.NUM
    :
    :
JOIN TBL Tk ON Tk.NUM <> T[k-1].NUM AND Tk.NUM <> T[k-2].NUM …… AND Tk.NUM <> T1.NUM



具体例として P(6, 6) の順列の場合はこうなります。720 パターンが列挙されるはず。
ORDER BY するかはお好みで。

WITH TBL (NUM) AS (
  SELECT NUM = 1 UNION ALL
  SELECT NUM + 1 FROM TBL WHERE NUM < 6
) SELECT
  T1.NUM AS C1
, T2.NUM AS C2
, T3.NUM AS C3
, T4.NUM AS C4
, T5.NUM AS C5
, T6.NUM AS C6
FROM TBL T1
JOIN TBL T2 ON T2.NUM <> T1.NUM
JOIN TBL T3 ON T3.NUM <> T2.NUM AND T3.NUM <> T1.NUM
JOIN TBL T4 ON T4.NUM <> T3.NUM AND T4.NUM <> T2.NUM AND T4.NUM <> T1.NUM
JOIN TBL T5 ON T5.NUM <> T4.NUM AND T5.NUM <> T3.NUM AND T5.NUM <> T2.NUM AND T5.NUM <> T1.NUM
JOIN TBL T6 ON T6.NUM <> T5.NUM AND T6.NUM <> T4.NUM AND T6.NUM <> T3.NUM AND T6.NUM <> T2.NUM AND T6.NUM <> T1.NUM



P(6, 3) の順列だと 120パターンですね。

WITH TBL (NUM) AS (
  SELECT NUM = 1 UNION ALL
  SELECT NUM + 1 FROM TBL WHERE NUM < 6
) SELECT
  T1.NUM AS C1
, T2.NUM AS C2
, T3.NUM AS C3
FROM TBL T1
JOIN TBL T2 ON T2.NUM <> T1.NUM
JOIN TBL T3 ON T3.NUM <> T2.NUM AND T3.NUM <> T1.NUM

引用返信 編集キー/
■99163 / inTopicNo.3)  Re[2]: SQLレコード内の重複チェック
□投稿者/ ぶなっぷ (283回)-(2022/02/14(Mon) 09:11:14)
私自身もあまり理解できていませんが(^^;

[Recursive CTE]というものがあるそうです。
  https://zenn.dev/indigo13love/articles/b04f8f2973fee3

引用返信 編集キー/
■99164 / inTopicNo.4)  Re[3]: SQLレコード内の重複チェック
□投稿者/ OA (2回)-(2022/02/14(Mon) 10:06:37)
No99162 (魔界の仮面弁士 さん) に返信

いやー、すごい!!期待通りの結果が出ました。
{1〜10}の3628800通りでも出力含め1分10秒程でした。

SQLは一夜漬で「再帰 SQL」、初耳です。
もともとプログラムコードで再帰を書いていたのですが、データーベースのクロス結合を使ってもできるというのを知りやってみたものの、所詮一夜漬の初心者レベル....

少し調査時間をください。不明点があれば、再度ご教示、お願いします。

No99163 (ぶなっぷ さん) に返信
ありがとうございます。
同じ「再帰 SQL」のようですね。調べてみます。
引用返信 編集キー/
■99167 / inTopicNo.5)  Re[4]: SQLレコード内の重複チェック
□投稿者/ OA (3回)-(2022/02/14(Mon) 14:54:32)
ありがとうございます。なんとか理解できたと思います。
以下が自分なりのWITH句に対する「まとめ」です。

一応、解決済みにしますが、何かお気づきの点があれば、ご指摘下さい。


●WITH句はSQL内に置かれた関数のような感じで、文頭に置かれるが
最初は評価されずに、メインクエリで呼び出された段階で初めて評価される。

●特殊な使い方としてFROM句でWITH句の関数を呼び出し、別名を付けると
テンプレートテーブルとして利用でき、同じテーブルをいくつでも作成できる。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -