SQL chọn phạm vi số


19

Tôi thấy khá khó khăn để đạt được một loạt các số như các hàng trong MySQL.

Ví dụ, phạm vi 1-5 đạt được bằng cách:

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

sẽ cho kết quả:

1
2
3
4
5

cho 0-99 tôi có thể tham gia hai bảng 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

Tôi mệt mỏi với việc viết tất cả những điều này UNIONvà tìm cách thu nhỏ mã.

Bất kỳ ý tưởng làm thế nào để chơi nó (ví dụ phạm vi 0-1.000.000) trong MySQL hoặc bất kỳ cú pháp SQL nào?

Thêm điểm được cho:

  • tuyên bố duy nhất
  • không có thủ tục
  • không có biến
  • không có báo cáo DDL
  • chỉ báo cáo DQL

2
Không chắc chắn nếu điều này thuộc về meta, hoặc trong dba.stackexchange.com hoặc có thể trong các mẹo để chơi Golf trong luồng SQL .
BradC

8
Để đóng cử tri: Đây là một thách thức về chủ đề; những câu hỏi không phải là những thách thức liên quan đến mã chơi gôn được coi là những câu hỏi về chủ đề.
HyperNeutrino

3
Tôi thích câu trả lời này từ SO . Hackish tốt nhất, nhưng bạn đã yêu cầu một giải pháp chơi golf sau khi tất cả.
Arnauld

@Arnauld thật tuyệt vời!
Dimgold

2
Nếu bất kỳ SQL SQL nào bao gồm PostgreSQL, hãy xem generate_series(). Chúng tôi có một vài ví dụ sử dụng ở đây.
thao tác

Câu trả lời:


9

Đối với các phương ngữ SQL hỗ trợ các CTE đệ quy như sqlite, bạn có thể làm một số thứ như sau:

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

Điều này không phụ thuộc vào bất kỳ bảng hiện có nào và bạn có thể thay đổi mệnh đề LIMIT như mong muốn. Ban đầu tôi thấy một biến thể của cái này trên StackOverflow.


2
Xuất sắc. Đây là phiên bản chơi gôn hoạt động trong MS SQL: WITH t AS(SELECT 1n UNION ALL SELECT n+1FROM t WHERE n<36)SELECT n FROM t Đối với các điểm cuối khác nhau, chỉ cần thay đổi 136thành bất cứ điều gì bạn muốn.
BradC

1
Rất tiếc, nếu bạn muốn có hơn 100 hàng trong MS SQL, bạn có thể cần thêm option (maxrecursion 0)vào cuối câu lệnh trên của tôi, nếu không, nó sẽ bị lỗi khi đệ quy trên 100. (Hoặc được đặt maxrecursionthành một giá trị cụ thể hoặc thành 0 để cho phép vô hạn) .
BradC

6

Tương tự như phương pháp của @ BradC .

Tôi đã sử dụng MS SQL, có một bảng [master]với phạm vi số từ -1 đến 2048. Bạn có thể sử dụng BETWEENtoán tử để tạo phạm vi của mình.

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

Nếu bạn muốn chơi gôn này, bạn có thể làm:

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

1
Để chơi gôn, bạn tiết kiệm 2 byte vớiWHERE number>0AND number<21
BradC

Tại sao bạn sử dụng riêng biệt? Có vẻ dư thừa.
Bạch tuộc ma thuật Urn

1
@MagicOctopusUrn Vì có số trùng lặp trong bảng đó.
Oliver

1
Đúng, bạn cần sử dụng DISTINCT hoặc sử dụng WHERE type = 'P'. Khác biệt là hơi ngắn.
BradC

1
@BradC, hoặcSELECT DISTINCT(number+2)... WHERE number<19
Peter Taylor


4

Tùy chọn tuyệt vời từ bài đăng này (được tìm thấy bởi @Arnauld):

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

Đối với tôi - đó là khá nhiều giải quyết thách thức.


Điều này dường như đang dựa vào một bảng hiện có đã có một idtrường được điền thông qua các giá trị rất lớn. Cơ sở dữ liệu khá cụ thể và bạn có thể bỏ lỡ một hàng nếu ai đó đã xóa ID sản phẩm = 4021.
BradC

Đúng, nhưng nó thực sự tốt cho các phạm vi tương đối nhỏ (1-7 cho nhiều ngày, 1-12 cho nhiều tháng, v.v ...)
Dimgold

4

PostgreQuery cụ thể

generate_series()tạo ra một tập hợp, vì vậy bạn có thể sử dụng nó không chỉ trong frommệnh đề, mà bất cứ nơi nào có thể xảy ra một tập hợp:

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

Bạn cũng có thể thực hiện các thao tác trực tiếp trên bộ:

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

Nếu nhiều bộ có cùng độ dài, bạn có thể di chuyển chúng song song:

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

Đối với các bộ có độ dài khác nhau, sản phẩm của Cartesian được tạo:

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)

Nhưng nếu bạn sử dụng chúng trong frommệnh đề, bạn cũng nhận được sản phẩm của Cartesian cho cùng một bộ chiều dài:

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)

Nó cũng có thể tạo ra bộ dấu thời gian. Ví dụ: bạn sinh vào ngày 2000-06-30 và muốn biết năm nào bạn tổ chức sinh nhật vào cuối tuần:

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 có một bảng hệ thống không có giấy tờ trong mastercơ sở dữ liệu được gọi spt_values. Trong số những thứ khác, nó chứa một dãy số từ 0 đến 2047:

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

Chỉ hữu ích như một bảng số, nhưng trong CTE, bạn có thể nhận được một số số lớn khá nhanh:

--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

(Chúng hoạt động trong MS-SQL, không chắc chúng hoạt động cho myQuery hay các nền tảng khác.)

Đối với các bộ nhỏ hơn (có thứ tự hoặc không theo thứ tự), sử dụng hàm VALUEStạo:

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

(Điều này hoạt động cho bất cứ điều gì, mặc dù các chuỗi có thể trở nên khá dài với tất cả các dấu ngoặc đơn lặp đi lặp lại.)

Sau đó, bạn có thể nhân chéo bằng cách sử dụng CTE có tên (biểu thức bảng chung) để bạn không phải lặp lại:

--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

Có rất nhiều kỹ thuật khác, hãy tìm "SQL tạo bảng số", mặc dù hầu hết không được tối ưu hóa cho việc chơi gôn.


1
Điều này sẽ làm việc với một limit Yđể làm cho phạm vi tùy ý?
Rod

1
@Rod Trong MS-SQL bạn phải sử dụngSELECT TOP 250 ...
BradC

Ồ, tôi đã không thấy tiêu đề MSSQL = X
Rod

không hoạt động trên MySQL, nhưng vẫn hữu ích :)
Dimgold

2

Thêm một tùy chọn, tùy chọn này dành riêng cho MS SQL 2016 trở lên:

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

Tôi có thể sẽ thấy điều này tiện dụng hơn cho danh sách các chuỗi, nhưng tôi có thể thấy cách nó cũng hữu ích với các số.


2

T-SQL, 98 byte

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
  • ✓ tuyên bố duy nhất
  • Không có thủ tục
  • ✓ không có biến
  • ✓ không có tuyên bố DDL
  • Chỉ báo cáo DQL

Đây là một phiên bản T-SQL gọn gàng của câu trả lời của langelgjm . Các số mũ là một thủ thuật gọn gàng, là tốt.
BradC

1

Một cái khác cho 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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.