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의 경우 두 개의 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
유권자를 마감하려면 : 이것은 주제에 대한 도전입니다. 골프 코드와 관련된 문제가 아닌 질문은 주제별 질문으로 간주됩니다.
HyperNeutrino 2016 년

3
나는 이 답변을 좋아 한다 . 해 키시는 기껏해야하지만 결국 골프 솔루션을 요청했습니다.
Arnauld 2016 년

@Arnauld는 굉장합니다!
Dimgold

2
"모든 SQL"에 PostgreSQL이 포함 된 경우을 참조하십시오 generate_series(). 여기에 몇 가지 사용 예가 있습니다.
manatwork 2016 년

답변:


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의 방법과 유사합니다 .

테이블 [master]범위가 -1에서 2048 사이 인 MS SQL 을 사용했습니다. 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

왜 별개를 사용합니까? 중복 된 것 같습니다.
Magic Octopus Urn

1
@MagicOctopusUrn 해당 테이블에 중복 된 숫자가 있기 때문입니다.
Oliver

1
그러나 DISTINCT를 사용하거나 WHERE type = 'P'를 사용해야합니다. 구별이 약간 짧습니다.
BradC

1
@BradC, 또는SELECT DISTINCT(number+2)... WHERE number<19
Peter Taylor


4

이 게시물의 훌륭한 옵션 (@Arnauld가 제공) :

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

나를 위해-그것은 거의 도전을 해결합니다.


이것은 이미 id매우 큰 값을 통해 필드가 채워진 기존 테이블에 의존하는 것 같습니다 . 예를 들어 누군가가 제품 ID = 4021을 삭제 한 경우 데이터베이스에 따라 다르므로 행을 놓칠 수 있습니다.
BradC

그렇습니다.하지만 상대적으로 작은 범위 (일은 1-7, 달은 1-12)에 정말 좋습니다.
Dimgold

4

PostgreSQL 관련

generate_series()집합을 생성하므로 in 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임의의 범위를 만들기 위해 a와 함께 작동 합니까?
Rod

1
@Rod MS-SQL에서는 다음을 사용해야합니다.SELECT TOP 250 ...
BradC

오, 나는 MSSQL 헤더 = X를 보지 못했다
Rod

MySQL에서는 작동하지 않지만 여전히 유용합니다 :)
Dimgold

2

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 버전입니다 . 지수는 깔끔한 트릭입니다.
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.