SQLセレクト番号範囲


19

の数の範囲を行として達成するのは非常に難しいことがわかりましたMySQL

たとえば、1〜5の範囲は以下によって達成されます。

SELECT 1 
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5

結果は次のとおりです。

1
2
3
4
5

0-99の場合、2つの0-9テーブルをクロス結合できます。

CREATE TABLE nums as
SELECT 0 as num
UNION
SELECT 1 
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6 
UNION
SELECT 7
UNION
SELECT 8
UNION
SELECT 9
;

Select n.num*10+nums.num v 
From nums n cross join nums

これらすべてを書いてUNION、コードを縮小する方法を探しているのはうんざりです。

MySQLまたはSQL構文でそれゴルフする方法(たとえば、0-1,000,000の範囲)はありますか?

余分なポイントが与えられます:

  • 一言
  • 手順なし
  • 変数なし
  • DDLステートメントなし
  • DQLステートメントのみ

2
これがメタに属しているのか、dba.stackexchange.comに属しているのか、またはSQLスレッドでのゴルフヒントに属しているのかはわかりません。
BradC

8
投票者を閉鎖するには:これは話題の課題です。ゴルフのコードに関連するチャレンジではない質問は、トピックに関するヒントの質問と見なされます。
ハイパーニュートリノ

3
はSOからのこの答えがちょっと好きです。せいぜいハックですが、結局あなたはゴルフの解決策を求めました。
アーナルド

@Arnauldすごい!
ディムゴールド

2
「任意のSQL」にPostgreSQLが含まれる場合は、を参照してくださいgenerate_series()。ここに使用例がいくつかあります。
マナトワーク

回答:


9

sqliteのような再帰CTEをサポートするSQL ダイアレクトの場合、次のようなことができます。

WITH RECURSIVE f(x) AS
(
  SELECT 1 UNION ALL SELECT x + 1 FROM f LIMIT 1000000
)
SELECT x
FROM f;

これは既存のテーブルに依存せず、必要に応じてLIMIT句を変更できます。私はもともとStackOverflowでこれのバリアントを見ました。


2
優れた。MS SQLで機能するゴルフバージョンを次に示します。WITH t AS(SELECT 1n UNION ALL SELECT n+1FROM t WHERE n<36)SELECT n FROM t さまざまなエンドポイントについては136必要なものに変更します。
BradC

1
MS SQLで100行を超える場合option (maxrecursion 0)は、上記のステートメントの最後に追加する必要があります。そうしないと、100を超える再帰でエラーが発生します(maxrecursion特定の値に設定するか、0に設定すると無限になります) 。
BradC

6

@BradCのmethodに似ています。

MS SQLを使用し[master]ました。MSSQLには、-1〜2048の数値範囲のテーブルがありますBETWEEN。演算子を使用して範囲を作成できます。

SELECT DISTINCT(number)
FROM master..[spt_values] 
WHERE number BETWEEN 1 AND 5

これをゴルフしたい場合は、次のことができます。

SELECT TOP 5 ROW_NUMBER()OVER(ORDER BY number)FROM master..spt_values

1
ゴルフのためにあなたが2つのバイトを保存WHERE number>0AND number<21
BradC

明確に区別するのはなぜですか?冗長のようです。
魔法のタコUr

1
@MagicOctopusUrnそのテーブルには重複した番号があるため。
オリバー

1
はい、DISTINCTを使用するか、WHERE type = 'P'を使用する必要があります。個別はわずかに短くなります。
BradC

1
@BradC、またはSELECT DISTINCT(number+2)... WHERE number<19
ピーターテイラー


4

この投稿の素晴らしいオプション(@Arnauldにより発見):

SELECT id%1000001 as num
FROM <any_large_table>
GROUP BY num

私にとって-それはほとんど課題を解決します。


これは、既にid非常に大きな値が入力されたフィールドを持つ既存のテーブルに依存しているようです。データベース固有なので、誰かがプロダクトID = 4021を削除した場合、行を見逃す可能性があります
。– BradC

ええ、しかし、比較的狭い範囲(1〜7日、
1〜

4

PostgreSQL固有

generate_series()セットを生成するので、from句内だけでなく、セットが発生する可能性のある場所で使用できます

psql=# select generate_series(10, 20, 3);
 generate_series 
-----------------
              10
              13
              16
              19
(4 rows)

セットに対して直接操作を行うこともできます。

psql=# select 2000 + generate_series(10, 20, 3) * 2;
 ?column? 
----------
     2020
     2026
     2032
     2038
(4 rows)

複数のセットの長さが同じ場合、それらを並行して走査できます。

psql=# select generate_series(1, 3), generate_series(4, 6);
 generate_series | generate_series 
-----------------+-----------------
               1 |               4
               2 |               5
               3 |               6
(3 rows)

長さが異なるセットの場合、デカルト積が生成されます。

psql=# select generate_series(1, 3), generate_series(4, 5);
 generate_series | generate_series 
-----------------+-----------------
               1 |               4
               2 |               5
               3 |               4
               1 |               5
               2 |               4
               3 |               5
(6 rows)

ただし、from句でそれらを使用すると、同じ長さセットのデカルト積も取得されます。

psql=# select * from generate_series(1, 2), generate_series(3, 4) second;
 generate_series | second 
-----------------+--------
               1 |      3
               1 |      4
               2 |      3
               2 |      4
(4 rows)

また、一連のタイムスタンプを生成することもできます。たとえば、2000-06-30に生まれ、週末に誕生日を祝った年を知りたい場合:

psql=# select to_char(generate_series, 'YYYY - Day') from generate_series('2000-06-30', current_date, interval '1 year') where to_char(generate_series, 'D') in ('1', '7');
     to_char      
------------------
 2001 - Saturday 
 2002 - Sunday   
 2007 - Saturday 
 2012 - Saturday 
 2013 - Sunday   
(5 rows)

3

MS SQLには、masterデータベース内にと呼ばれる文書化されていないシステムテーブルがありますspt_values。とりわけ、0〜2047の範囲の数値が含まれています。

--returns 0 to 2,047
SELECT number n 
FROM master..spt_values
WHERE TYPE='P'

単独で数値表として有用ですが、CTEではかなり大きな数値をすばやく取得できます。

--returns 0 to 4,194,304
WITH x AS(SELECT number n FROM master..spt_values WHERE TYPE='P')
SELECT 2048*x.a+*y.a
FROM x,x y
ORDER BY 1

3

(これらはMS-SQLで動作し、mySQLまたは他のプラットフォームで動作するかどうかはわかりません。)

より小さいセット(順序付きまたは順序なし)の場合、VALUESコンストラクターを使用します。

--Generates 0-9
SELECT a 
FROM(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))x(a)

(これは何でも機能しますが、文字列はすべて単一引用符を繰り返すとかなり長くなる可能性があります。)

次に、名前付きCTE(共通テーブル式)を使用して相互乗算できるため、繰り返す必要はありません。

--Generates 0-999
WITH x AS(SELECT a FROM(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))x(a))
SELECT 100*x.a+10*y.a+z.a 
FROM x,x y,x z
ORDER BY 1

他にも多くのテクニックがあります。「数値テーブルを生成するSQL」を探してください。ただし、ほとんどはゴルフに最適化されていません。


1
これlimit Yは任意の範囲を作成するために動作しますか?
ロッド

1
@Rod MS-SQLでは、使用する必要がありますSELECT TOP 250 ...
BradC

ああ、MSSQLヘッダー= Xが表示されませんでした
Rod

MySQLでは動作しませんが、それでも有用です:)
Dimgold

2

もう1つのオプション、これはMS SQL 2016以降に固有のものです。

SELECT value v
FROM STRING_SPLIT('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16', ',')

文字列のリストにはこれがより便利だと思われますが、数値でも同様に役立つ方法がわかります。


2

T-SQL、98バイト

WITH H AS(SELECT 0i UNION ALL SELECT i+1FROM H WHERE i<99)SELECT H.i+1e4*A.i+B.i*1e2FROM H,H A,H B
  • ✓単一のステートメント
  • ✓手順なし
  • ✓変数なし
  • ✓DDLステートメントなし
  • ✓DQLステートメントのみ

これは、langelgjmの回答のきれいなT-SQLバージョンです。指数もきちんとしたトリックです。
20:39のBradC

1

SQL Serverの別の...

WITH 
    cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)),   -- 10
    cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b),                             -- 100
    cte_Tally (n) AS (
        SELECT TOP (<how many ROWS do you want?>)
            ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
        FROM
            cte_n2 a CROSS JOIN cte_n2 b                                                    -- 10,000
        )
SELECT 
    t.n
FROM
    cte_Tally t;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.