2

私はメッセージベースのシステムを管理しています。このシステムでは、一意の整数IDのシーケンスが一日の終わりに完全に表されますが、必ずしも順番に到着するとは限りません。

SQLを使用して、このシリーズで欠落しているIDを見つけるためのヘルプを探しています。列の値が次のようなものである場合、このシーケンスで欠落しているIDを見つけるにはどうすればよいですか?この場合はどうすればよい6ですか?

シーケンスは毎日任意の時点で開始および終了するため、実行ごとに最小値と最大値が異なります。Perlのバックグラウンドから来て、そこにある正規表現を使用します。

ids
1
2
3
5
4
7
9
8
10

助けていただければ幸いです。

編集:オラクルを実行します

Edit2:ありがとう。来週、オフィスでソリューションを実行します。

Edit3:とりあえず、ORIG_IDが元のID列、MY_TABLEがソーステーブルのようなものに落ち着きました。私のデータを詳しく見ると、文字列内の数値データだけでなく、さまざまなケースがあります。場合によっては、数字以外の文字の接頭辞または接尾辞があります。その他の場合、数値IDにダッシュまたはスペースが混在しています。これを超えて、IDは定期的に複数回表示されるため、個別に含めました。

特に非数字文字を取り除く最良のルートに関して、さらに入力をいただければ幸いです。

SELECT 
   CASE
      WHEN NUMERIC_ID + 1 = NEXT_ID - 1
         THEN TO_CHAR( NUMERIC_ID + 1 )
      ELSE TO_CHAR( NUMERIC_ID + 1 ) || '-' || TO_CHAR( NEXT_ID - 1 )
   END
   MISSING_SEQUENCES
   FROM
   (
      SELECT
         NUMERIC_ID,
         LEAD (NUMERIC_ID, 1, NULL)
            OVER 
            (
               ORDER BY
                 NUMERIC_ID
                 ASC
            )
            AS NEXT_ID
         FROM 
         (
             SELECT
                DISTINCT TO_NUMBER( REGEXP_REPLACE(ORIG_ID,'[^[:digit:]]','') ) 
                AS NUMERIC_ID
             FROM MY_TABLE
         )
    ) WHERE NEXT_ID != NUMERIC_ID + 1
4

6 に答える 6

6

そこに行ったことがある。

FOR ORACLE:

しばらく前にネット上でこの非常に便利なクエリを見つけて書き留めましたが、今はサイトを覚えていません"GAP ANALYSIS"。Googleで検索してください。

SELECT   CASE
             WHEN ids + 1 = lead_no - 1 THEN TO_CHAR (ids +1)
          ELSE TO_CHAR (ids + 1) || '-' || TO_CHAR (lead_no - 1)
         END
             Missing_track_no
   FROM   (SELECT   ids,
                    LEAD (ids, 1, NULL)
                     OVER (ORDER BY ids ASC)
                        lead_no
             FROM   YOURTABLE
             )
   WHERE   lead_no != ids + 1

ここで、結果は次のとおりです。

MISSING _TRACK_NO
-----------------
       6

複数のギャップがある場合、たとえば2、6、7、9の場合、次のようになります。

MISSING _TRACK_NO
-----------------
        2
       6-7
        9
于 2011-12-03T15:40:11.930 に答える
4

これは、除外結合と呼ばれることもあります。つまり、結合を実行して、一致する行のみを返すようにします。

SELECT t1.value-1
FROM ThisTable AS t1
LEFT OUTER JOIN ThisTable AS t2
  ON t1.id = t2.value+1
WHERE t2.value IS NULL

これは常に少なくとも1つの行を報告することに注意してください。これがMINになりvalueます。

また、2つ以上の数値のギャップがある場合、1つの欠落値のみが報告されます。

于 2011-12-03T00:14:07.617 に答える
2

あなたはDBMSを述べていなかったので、私はPostgreSQLを想定しています。

select aid as missing_id
from generate_series( (select min(id) from message), (select max(id) from message)) as aid
  left join message m on m.id = aid
where m.id is null;  

これにより、テーブル内の最小IDと最大IDの間のシーケンスで欠落している値が報告されます(1より大きいギャップを含む)

psql(9.1.1)
ヘルプを表示するには、「help」と入力してください。

postgres => select * from message;
 id
--------
  1
  2
  3
  4
  5
  7
  8
  9
 11
 14
(10行)


postgres=>missing_idとしてaidを選択します
postgres-> from generate_series((select min(id)from message)、(select max(id)from message))as aid
postgres->m.idの左参加メッセージm=援助
postgres->ここで、m.idはnullです。
 missing_id
------------
          6
         10
         12
         13
(4行)
postgres =>
于 2011-12-03T00:51:37.620 に答える
0

私はそれをmysqlに適用しました、それは働きました..

mysql> select * from sequence;
+--------+
| number |
+--------+
|      1 |
|      2 |
|      4 |
|      6 |
|      7 |
|      8 |
+--------+
6 rows in set (0.00 sec)

mysql> SELECT t1.number - 1 FROM sequence AS t1 LEFT OUTER JOIN sequence AS t2 O
N t1.number = t2.number +1 WHERE t2.number IS NULL;
+---------------+
| t1.number - 1 |
+---------------+
|             0 |
|             3 |
|             5 |
+---------------+
3 rows in set (0.00 sec)
于 2011-12-03T00:24:06.367 に答える
0
SET search_path='tmp';

DROP table tmp.table_name CASCADE;
CREATE table tmp.table_name ( num INTEGER NOT NULL PRIMARY KEY);
-- make some data
INSERT INTO tmp.table_name(num) SELECT generate_series(1,20);
-- create some gaps
DELETE FROM tmp.table_name WHERE random() < 0.3 ;

SELECT * FROM table_name;

-- EXPLAIN ANALYZE
WITH zbot AS (
    SELECT 1+tn.num  AS num
    FROM table_name tn
    WHERE NOT EXISTS (
        SELECT * FROM table_name nx
        WHERE nx.num = tn.num+1
        )
    )
, ztop AS (
    SELECT -1+tn.num  AS num
    FROM table_name tn
    WHERE NOT EXISTS (
        SELECT * FROM table_name nx
        WHERE nx.num = tn.num-1
        )
    )
SELECT zbot.num AS bot
    ,ztop.num AS top
FROM zbot, ztop
WHERE zbot.num <= ztop.num
AND NOT EXISTS ( SELECT *
    FROM table_name nx
    WHERE nx.num >= zbot.num
    AND nx.num <= ztop.num
    )
ORDER BY bot,top
    ;

結果:

CREATE TABLE
INSERT 0 20
DELETE 9
 num 
-----
   1
   2
   6
   7
  10
  11
  13
  14
  15
  18
  19
(11 rows)

 bot | top 
-----+-----
   3 |   5
   8 |   9
  12 |  12
  16 |  17
(4 rows)

注:再帰CTEも可能です(おそらくそれよりも短くなります)。

更新:ここに再帰CTEがあります...:

WITH RECURSIVE tree AS (
    SELECT 1+num AS num
    FROM table_name t0
    UNION
    SELECT 1+num FROM tree tt
    WHERE EXISTS ( SELECT *
        FROM table_name xt
        WHERE xt.num > tt.num
        )
    )
SELECT * FROM tree
WHERE NOT EXISTS (
    SELECT *
    FROM table_name nx
    WHERE nx.num = tree.num
    )
ORDER BY num
    ;

結果:(同じデータ)

 num 
-----
   3
   4
   5
   8
   9
  12
  16
  17
  20
 (9 rows)
于 2011-12-03T15:40:19.953 に答える
0
select student_key, next_student_key
      from (
    select student_key, lead(student_key) over (order by student_key) next_fed_cls_prgrm_key
      from student_table
           )
where student_key <> next_student_key-1;
于 2013-07-31T15:38:02.933 に答える