-2

一連の数字で不足しているすべての数字を取得したいと思います。
以下よりも良いアプローチがあるかどうか疑問に思っていますか?

SELECT x
  FROM 
  (
    SELECT x,
           LAG(x,1) OVER ( ORDER BY x ) prev_x
      FROM 
       ( SELECT * FROM
        ( SELECT 1 AS x ),
        ( SELECT 2 AS x ),
        ( SELECT 3 AS x ),
        ( SELECT 4 AS x ),
        ( SELECT 5 AS x ),
        ( SELECT 6 AS x ),
        ( SELECT 8 AS x ),
        ( SELECT 10 AS x ),
        ( SELECT 11 AS x )
       )
  ) 
 WHERE x-prev_x > 1;
4

3 に答える 3

2

正直に言いましょう!
別の実用的な解決策は、問題に提示されているよりも優れています-1つの単純な理由で-それは間違っています! 欠落している数値はまったく返されません。むしろ、次のギャップの後に番号が表示されます。それだけです(私がこれに目を向けてくれたことに感謝してください)

さて、より良い解決策について - 追求すべき選択肢はたくさんあります。
注: 以下のオプションは BigQuery 専用です。

オプション1

BigQuery 標準 SQL -標準 SQLを有効にする方法を参照

WITH YourTable AS (
  SELECT 1 AS x UNION ALL
  SELECT 2 AS x UNION ALL
  SELECT 3 AS x UNION ALL
  SELECT 6 AS x UNION ALL
  SELECT 8 AS x UNION ALL
  SELECT 10 AS x UNION ALL
  SELECT 11 AS x
),
nums AS (
  SELECT num 
  FROM UNNEST(GENERATE_ARRAY((SELECT MIN(x) FROM YourTable), (SELECT MAX(x) FROM YourTable))) AS num
)
SELECT num FROM nums
LEFT JOIN YourTable ON num = x
WHERE x IS NULL
ORDER BY num

オプション 2

以下で試すことができるBigQuery レガシー SQL (ここでは、nums テーブルの select 式内に start/min および end/max 値を設定する必要があります

SELECT num FROM (
  SELECT num FROM (
    SELECT ROW_NUMBER() OVER() AS num, * 
    FROM (FLATTEN((SELECT SPLIT(RPAD('', 11, '.'),'') AS h FROM (SELECT NULL)), h))
  ) WHERE num BETWEEN 1 AND 11
) AS nums
LEFT JOIN (
  SELECT x FROM
    (SELECT 1 AS x),
    (SELECT 2 AS x),
    (SELECT 3 AS x),
    (SELECT 6 AS x),
    (SELECT 8 AS x),
    (SELECT 10 AS x),
    (SELECT 11 AS x)
) AS YourTable
ON num = x
WHERE x IS NULL

オプション 3

BigQuery レガシー SQL - 最小値と最大値に依存せず、それらの値を設定する必要がある場合は、以下のソリューションを使用できます。必要なのは、予想される成長に対応するのに十分な最大値を設定することだけです (たとえば、1000 を入れます)。

SELECT num FROM (
  SELECT num FROM (
    SELECT ROW_NUMBER() OVER() AS num, * 
    FROM (FLATTEN((SELECT SPLIT(RPAD('', 1000, '.'),'') AS h FROM (SELECT NULL)), h))
  ) WHERE num BETWEEN 1 AND 1000
) AS nums
LEFT JOIN YourTable
ON num = x
WHERE x IS NULL
AND num BETWEEN (SELECT MIN(x) FROM YourTable) AND (SELECT MAX(x) FROM YourTable) 

オプション 4 (何らかの理由で - これまでのお気に入り)

BigQuery 標準 SQL - 明示的な結合なし

WITH YourTable AS (
  SELECT 1 AS x UNION ALL
  SELECT 2 AS x UNION ALL
  SELECT 3 AS x UNION ALL
  SELECT 6 AS x UNION ALL
  SELECT 8 AS x UNION ALL
  SELECT 10 AS x UNION ALL
  SELECT 11 AS x
)
SELECT num
FROM (SELECT x, LEAD(x) OVER(ORDER BY x) AS next_x FROM YourTable),  
     UNNEST(GENERATE_ARRAY(x + 1,next_x - 1)) AS num
WHERE next_x - x > 1
ORDER BY x
于 2016-09-11T04:37:04.190 に答える
1

Your query can be written much more succinctly like so:

SELECT x
FROM (
    SELECT x,
           lag(x, 1) OVER ( ORDER BY x ) prev_x
    FROM ( VALUES (1), (2), (3), (4), (5), (6), (8), (10), (11) ) v(x)
) sub
WHERE x-prev_x > 1;

This will return the next highest value after a miss (8, 10), not the missing values themselves (7, 9). But of course you do not have the values handy.

If you know the range of values in the sequence, then you can use this:

SELECT s.x
FROM generate_series(<<min>>, <<max>>) s(x)
LEFT JOIN my_table t ON s.x = t.x
WHERE t.x IS NULL;

This returns the actual missing values.

If you do not know the range of values, you need to add a sub-query:

SELECT s.x
FROM ( SELECT min(x), max(x) FROM my_table ) r
JOIN generate_series(r.min, r.max) s(x) ON true
LEFT JOIN my_table t ON s.x = t.x
WHERE t.x IS NULL;

Alternatively, instead of a LEFT JOIN:

SELECT x
FROM ( SELECT min(x), max(x) FROM my_table ) r,
     generate_series(r.min, r.max) s(x)
WHERE NOT EXISTS (SELECT 1 FROM my_table t WHERE t.x = s.x);
于 2016-09-11T04:05:29.680 に答える
1

Postgresでの最短の解決策は、標準 SQL を使用することです。EXCEPT

WITH tbl(x) AS (SELECT unnest ('{1,2,3,4,5,6,8,10,11}'::int[]))
-- the CTE provides a temp table - might be an actual table instead
SELECT generate_series(min(x), max(x)) FROM tbl
EXCEPT ALL
TABLE  tbl;

セットを返す関数unnest()は Postgres 固有のものであり、一連の数値をテーブルとして提供するための最短の構文です。

データ内の重複または NULL 値でも機能します。

TABLE tblは (標準 SQL!) の短い構文ですSELECT * FROM tbl:

関連(詳細な説明付き):

于 2016-09-11T14:48:21.883 に答える