2009-09-25 13 views
12

Potrzebuję uzyskać zestaw wyników zawierający pierwszych N liczb całkowitych. Czy można użyć tylko standardowej instrukcji SQL SELECT, aby je uzyskać (bez dostarczonej tabeli liczników)?SQL SELECT, aby uzyskać pierwsze N ​​liczb całkowitych dodatnich

Jeśli nie jest to możliwe, czy istnieje konkretny sposób, aby to osiągnąć?

+0

Po pierwsze w jakiej definicji? –

Odpowiedz

15

Wydaje się, że to, co chcesz to dummy rowset.

W przypadku MySQL jest to niemożliwe bez stołu.

Większość głównych systemów zapewnić sposób to zrobić:

  • W Oracle:

    SELECT level 
    FROM dual 
    CONNECT BY 
         level <= 10 
    
  • W SQL Server:

    WITH q AS 
         (
         SELECT 1 AS num 
         UNION ALL 
         SELECT num + 1 
         FROM q 
         WHERE num < 10 
         ) 
    SELECT * 
    FROM q 
    
  • W PostgreSQL:

    SELECT num 
    FROM generate_series(1, 10) num 
    

MySQL brakuje czegoś takiego i jest to poważna wada.

napisałem prosty skrypt do generowania danych testowych dla przykładowych tabel w moim blogu, może to będzie użycia:

CREATE TABLE filler (
     id INT NOT NULL PRIMARY KEY AUTO_INCREMENT 
) ENGINE=Memory; 

CREATE PROCEDURE prc_filler(cnt INT) 
BEGIN 
     DECLARE _cnt INT; 
     SET _cnt = 1; 
     WHILE _cnt <= cnt DO 
       INSERT 
       INTO filler 
       SELECT _cnt; 
       SET _cnt = _cnt + 1; 
     END WHILE; 
END 
$$ 

wywołać procedurę i tabela zostanie wypełnione z numerami.

Możesz użyć go ponownie podczas trwania sesji.

+0

Świetna odpowiedź. To na pewno jest pomocne. – monn

2

Zakładając, że masz na myśli pobranie ich z tabeli, tutaj N wynosi 10, zakładając, że intcolumn to kolumna z liczbami.

SELECT intcolumn FROM numbers WHERE intcolumn > 0 LIMIT 10 

Edit: W przypadku, gdy zostały faktycznie chce uzyskać matematyczny zbiór liczb dodatnich bez stole, chciałbym rozważyć, może być intensywny (w zależności od wykonania). Powszechnie akceptowaną praktyką wydaje się tworzenie tabeli odnośników pełnych liczb, a następnie użycie powyższego zapytania.

+0

wystarczy zmienić> = na>, aby uzyskać tylko pozytywne wyniki. – dusoft

+0

Czy 0 uważa się za pozytywne czy negatywne? – rahul

+0

Właśnie sprawdziłem, najwyraźniej definicja liczb dodatnich jest większa niż 0. Pozornie zero nie jest ani (zgodnie z wikipedia). – Kazar

0

Spójrz na The followhing SO pytania:

Edit:

Innym aproach jest utworzyć procedurę przechowywaną, która to robi dla Ciebie. PostgreSQL zawiera funkcję generate_series (start, stop), która robi to, co chcesz.

select * from generate_series(2,4); 
generate_series 
----------------- 
       2 
       3 
       4 
(3 rows) 

Nie jestem obeznanym z MySQL, ale somthing tak powinno być łatwe do wykonania, jeśli są w porządku z SPS. This strona pokazuje impozycję.

+0

Wyglądałoby to tak, jakby obie te metody wymagały tabeli odnośników o pewnej formie (przy użyciu AUTO_INCREMENT) – Kazar

0

Jestem pewna, że ​​nie możesz tego zrobić, jeśli dobrze zrozumiem twoje pytanie.

Jak rozumiem twoje pytanie, chcesz listę, z pojedynczego polecenia SQL, bez odniesienia do konkretnej tabeli?

Jestem prawie pewien, że nie jest to możliwe w żadnym dialekcie SQL. Gdyby uzyskać sekwencyjnie rosnącą liczbę wraz z wynikami innego zapytania, byłoby to możliwe (w zależności od dialektu SQL, w mssql byłaby to rownumber(), ale nie wiem jak w MySql, ale prawdopodobnie tam)

Ale nie o to pytam?

+0

W PostgreSQL istnieje funkcja o nazwie generate_series (start, stop), która wykonuje dokładnie to, co chce OP. –

1

może pomóc

Aby uzyskać liczbę losową R w zakresie i < = R < J użyciu podłoga wyrażeniu (i + RAND() * (J - i)). Na przykład, aby uzyskać losową liczbę całkowitą w zakresie zakres 7 < = R < 12, można wykorzystać następujące oświadczenie:

SELECT FLOOR(7 + (RAND() * 5));

+0

Pyta o sekwencyjne liczby całkowite dodatnie. Nie o losowych. –

4

rozwiązanie dziwne, ale ...

SELECT 1 UNION SELECT 2 UNION SELECT 3.... 
2

Sekwencja proponuję pozwala programiście wykonać następujące zapytanie:

select value from sequence where value>=15 and value<100; 

i uzyskania oczekiwanych rezultatów: sekwencja liczb całkowitych między 15 (włącznie) i 100 (wyłączne).

Jeśli to, co chcesz, musisz utworzyć dwa następujące widoki, widoki, które będzie można zadeklarować tylko raz:

create view digits as select 0 n 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; 

create view sequence as select u.n+t.n*10+h.n*100 as value from digits as u cross join digits as t cross join digits as h; 

ten sposób masz swoją sekwencję z intuicyjnym SELECT ...

Mam nadzieję, że to pomaga.

+0

Crazy! ... i to działa. Potrzebowałem czegoś, co działało w widoku - użycie przypisania do zmiennej jest blokowane dla widoków. Miły. –

9

Możliwe rozwiązanie (wprawdzie niezbyt eleganckie) jest użycie dowolnej tabeli z wystarczająco dużą liczbą rekordów.

Dla pierwszych 10 liczb całkowitych (z wykorzystaniem mysql.help_relation, ale każdy stół zrobi), można użyć następującego zapytania:

SELECT @N := @N +1 AS integers 
FROM mysql.help_relation , (SELECT @N:=0) dum LIMIT 10; 

To może być także umieszczony w funkcji biorąc MIN i MAX.

+1

Dzięki za cynk. z powodzeniem użył następujących opcji, aby uzyskać zakres dat: SELECT @i: = DATE_SUB (@i, INTERVAL 1 DAY) date FROM mysql.help_relation, (SELECT @i: = CURRENT_DATE) v WHERE @i> DATE_SUB (CURRENT_DATE, INTERVAL 3 MIESIĄCE); –

+0

To nie jest ogólne rozwiązanie. Działa, pod warunkiem, że używana tabela ma co najmniej taką ilość wierszy, jaką chcesz uzyskać. Stwórzmy fikcyjną tabelę bez wierszy i SELECT @N: = @ N + 1 AS z liczb całkowitych FROM manekina, (SELECT @N: = 0) dum LIMIT 10 nie tworzy żadnych wierszy. – user1645975

+0

Może być stary, ale to jest niesamowite. Coś takiego musiało istnieć. – slicedtoad

1

Jeśli wiesz, że N jest ograniczona (i zwykle jest), można użyć konstrukcji takich jak:

select (a.digit + (10 * b.digit) + (100 * c.digit) + (1000 * d.digit) + (10000 * e.digit) + (100000 * f.digit)) as n 
    from (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as e 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as f; 

który wygeneruje pierwszy milion cyfr. Jeśli potrzebujesz tylko liczb dodatnich, po prostu dodaj + 1 do wyrażenia.

Należy zauważyć, że w szczególności w MySQL wyniki nie mogą być sortowane.Musisz dodać końcówkę order by n do końca, jeśli potrzebujesz uporządkowanych numerów. To znacznie wydłuży czas wykonywania, ale (na mojej maszynie podskoczył z 5 ms do 500 ms).

przypadku prostych zapytań, oto zapytanie do tylko pierwszy 10000 liczbach:

select (a.digit + (10 * b.digit) + (100 * c.digit) + (1000 * d.digit)) as n 
    from (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d; 

Ta odpowiedź jest adaptacją następującej kwerendy, która zwraca Zakres dat: https://stackoverflow.com/a/2157776/2948

0

Jeśli baza danych obsługuje analityczną okienkowania funkcje następujące proste działa bardzo dobrze:

SELECT row_number() over (partition by 1 order by 1) numbers 
FROM SOME_TABLE 
LIMIT 2700; 

To polecenie zwraca zestaw liczb od 1 do 2700.

Powiązane problemy