web-dev-qa-db-ja.com

MySQL-テーブルのidフィールドに対応するものがない番号のリストから選択します

{2,4,5,6,7}などの数値のリストがあります。たとえば、{1,2,3,4,8,9}など、foos.IDを持つテーブルfoosがあります。

数字のリストを取得して、テーブルのIDフィールドに対応するものがないものを見つけたいと思います。

これを実現する1つの方法は、IDフィールドに{2,4,5,6,7}をロードしたテーブルバーを作成することです。その後、私はやります

バーを選択します。*バーからFROMバーを左に結合します。bars.ID= foos.ID WHERE foos.ID IS NULL 

ただし、このsans tempテーブルを実現したいと思います。

誰がそれがどのように起こるのかについて何か意見がありますか?

36
SocialCensus

これは非常に一般的な問題です。テーブルを作成せずにオンザフライでリレーションを生成します。この問題のSQLソリューションはかなり厄介です。派生テーブルを使用した1つの例:

SELECT n.id
FROM
  (SELECT 2 AS id 
   UNION SELECT 3 
   UNION SELECT 4 
   UNION SELECT 5 
   UNION SELECT 6 
   UNION SELECT 7) AS n
  LEFT OUTER JOIN foos USING (id)
WHERE foos.id IS NULL;

ただし、6つではなく多くの値を持っている可能性があるため、これはあまりうまくスケールしません。値ごとに1つのUNIONが必要な長いリストを作成するのは面倒です。

別の解決策は、10桁の汎用テーブルを手元に保持し、複数の目的で繰り返し使用することです。

CREATE TABLE num (i int);
INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

SELECT n.id
FROM 
  (SELECT n1.i + n10.i*10 AS id
   FROM num AS n1 CROSS JOIN num AS n10
   WHERE n1.i + n10.i*10 IN (2, 3, 4, 5, 6, 7)) AS n
  LEFT OUTER JOIN foos USING (id)
WHERE foos.id IS NULL;

この場合は必要ありませんが、0..99から値を生成する内部クエリを示します。ただし、リストに10を超える値がある場合があります。ポイントは、1つのテーブルnumを使用すると、値ごとに1つのUNIONを持つ非常に長いチェーンに頼らずに大きな数値を生成できることです。また、必要な値のリストを1か所で指定できるため、より便利で読みやすくなります。

33
Bill Karwin

一時テーブルを使用しない正確な問題の解決策は見つかりませんが、結合の代わりに副選択を使用してクエリを実行する別の方法は次のとおりです。

SELECT bars.* FROM bars WHERE bars.ID NOT IN (SELECT ID FROM foos)

私が最初に書いた他のポスターのように:

SELECT * FROM foos WHERE foos.ID NOT IN (2, 4, 5, 6, 7)

しかし、私はこれがあなたが望むものの反対を作り出していることに気づきました。

20
Alnitak

PHPを使用する場合、一時テーブルを作成せずにこの作業を行うことができます。

SELECT ID FROM foos WHERE foos.ID IN (2, 4, 5, 6, 7)

PHPのarray_diff()関数を使用して、これを目的の結果に変換できます。リスト(2,4,5,6,7)が$ listという配列にあり、上記のクエリの結果が配列$ resultにある場合、

$no_counterparts = array_diff($list, $result);

...データベーステーブルに対応するものがないリストのすべての数値を返します。このソリューションはクエリ内の操作全体を実行しませんが、PHPで行う必要がある後処理は、必要なものを取得するために最小限であり、一時テーブルを作成します。

6
Alex Matulich

同様の問題がありました。自動インクリメントの主キーにいくつかの欠損値がある範囲があったので、最初にいくつあるかを見つけました:select count(*) from node where nid > 1962。この数値を最高値と比較すると、数値が欠落しています。次に、このクエリを実行しました:select n2.nid from node n1 right join node n2 on n1.nid = (n2.nid - 1) where n1.nid is null and n2.nid > 1962これは、連続していないレコードの数を見つけます。連続するものは表示されず、ON句を変更して緯度を大きくする(JOINテーブルが大幅に大きくなる)ことを超えて、その方法は完全にはわかりません。いずれにせよ、これにより、合計7つの欠落のうち5つの結果が得られ、他の2つは5つのうち少なくとも1つに隣接することが保証されました。不足している数が多い場合は、残りの不足を見つける他の方法がおそらく必要になります。

1
Daniel

Alnitakの(そしてあなたの)ソリューションは動作するはずです。SQL言語でしか動作しない他のことについては、私には何もできません。

しかし、ここで質問があります-値のリストをどのように渡しますか?呼び出しコードでこれを処理する方が良いのではありません-つまり、IDを要求し、この種の操作により適した言語である可能性のある照合コードで比較します。

0
Sunny Milenov