programing

MySQL에서 정수 시퀀스 생성

nasanasas 2021. 1. 9. 10:09
반응형

MySQL에서 정수 시퀀스 생성


나는이 그 정수를 가지고 어떤 테이블 / 결과 집합 /에 가입 할 필요가 nm포함. 테이블을 만들지 않고도이를 얻을 수있는 간단한 방법이 있습니까?

(BTW 그 유형의 구성을 " 메타 쿼리 " 라고 부르 겠습니까?)

m-n 합리적인 것 (<1000)


MySQL 에는 시퀀스 번호 생성기 ( CREATE SEQUENCE ) 가 없습니다 . 가장 가까운 것은 AUTO_INCREMENT테이블을 구성하는 데 도움이 될 수있는입니다.


웹에서이 솔루션을 찾았습니다.

SELECT @row := @row + 1 as row, t.*
FROM some_table t, (SELECT @row := 0) r

단일 쿼리, 빠르고, 원하는대로 정확히 수행합니다. 이제 고유 번호가 1부터 시작하고 결과의 각 행에 대해 한 번씩 증가하는 복잡한 쿼리에서 찾은 "선택 항목"에 "번호를 지정할"수 있습니다.

나는 이것이 위에 나열된 문제에도 효과가 있다고 생각합니다.에 대한 초기 시작 값을 조정 @row하고 최대 값을 설정하는 제한 절을 추가합니다.

BTW : "r"은 실제로 필요하지 않다고 생각합니다.

ddsp


다음은 1..10000을 반환하며 그렇게 느리지 않습니다.

SELECT @row := @row + 1 AS row FROM 
(select 0 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) t,
(select 0 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) t2, 
(select 0 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) t3, 
(select 0 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) t4, 
(SELECT @row:=0) numbers;

당신이 사용하는 일이 있다면 MySQL을 MariaDB 포크 , 엔진은 숫자 시퀀스를 직접 생성 할 수 있습니다. 가상 (가짜) 열 테이블을 사용하여이를 수행합니다.SEQUENCE

예를 들어 1에서 1000까지의 정수 시퀀스를 생성하려면 다음을 수행하십시오.

     SELECT seq FROM seq_1_to_1000;

0 ~ 11의 경우 이렇게하십시오.

     SELECT seq FROM seq_0_to_11;

오늘부터 일 주일간 연속 DATE 값을 얻으려면 이렇게하십시오.

SELECT FROM_DAYS(seq + TO_DAYS(CURDATE)) dateseq FROM seq_0_to_6

DATE'2010-01-01'로 시작 하는 10 년치 연속 값에 대해 이렇게합니다.

SELECT FROM_DAYS(seq + TO_DAYS('2010-01-01')) dateseq
  FROM seq_0_to_3800
 WHERE FROM_DAYS(seq + TO_DAYS('2010-01-01')) < '2010-01-01' + INTERVAL 10 YEAR

MariaDB를 사용하지 않는 경우 고려하십시오.


다음과 같이 시도해 볼 수 있습니다.

SELECT @rn:=@rn+1 as n
FROM (select @rn:=2)t, `order` rows_1, `order` rows_2 --, rows_n as needed...
LIMIT 4

order합리적으로 큰 행 집합이있는 일부 테이블의 예는 어디에 있습니까 ?

편집 : 원래 대답은 틀 렸으며 동일한 개념의 작업 예를 제공 한 David Poor에게 모든 크레딧을 제공해야합니다.


1에서 100.000 사이의 숫자 시퀀스 :

SELECT e*10000+d*1000+c*100+b*10+a n FROM
(select 0 a 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) t1,
(select 0 b 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) t2,
(select 0 c 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) t3,
(select 0 d 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) t4,
(select 0 e 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) t5
order by 1

다음과 같이 일부 숫자가 순서를 벗어 났는지 감사하는 데 사용합니다.

select * from (
    select 121 id
    union all select 123
    union all select 125
    union all select 126
    union all select 127
    union all select 128
    union all select 129
) a
right join (
    SELECT e*10000+d*1000+c*100+b*10+a n FROM
    (select 0 a 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) t1,
    (select 0 b 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) t2,
    (select 0 c 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) t3,
    (select 0 d 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) t4,
    (select 0 e 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) t5
    order by 1
) seq on seq.n=a.id
where seq.n between 121 and 129
and   id is null

결과는 121과 129 사이의 시퀀스 번호 122와 124의 간격이됩니다.

id     n
----   ---
null   122
null   124

누군가에게 도움이 될 수도 있습니다!


다음과 같이 합리적으로 큰 세트를 구성 할 수있는 것으로 보입니다.

select 9 union all select 10 union all select 11 union all select 12 union all select 13 ...

5.0.51a에서 5300에서 파서 스택 오버플로가 발생했습니다.


단일 쿼리에서 값 범위를 얻는 방법이 있지만 약간 느립니다. 캐시 테이블을 사용하여 속도를 높일 수 있습니다.

모든 BOOLEAN 값의 범위로 선택을 원한다고 가정하십시오.

SELECT 0 as b UNION SELECT 1 as b;

우리는 볼 수 있습니다

CREATE VIEW ViewBoolean AS SELECT 0 as b UNION SELECT 1 as b;

그런 다음 바이트를 수행 할 수 있습니다.

CREATE VIEW ViewByteValues AS
SELECT b0.b + b1.b*2 + b2.b*4 + b3.b*8 + b4.b*16 + b5.b*32 + b6.b*64 + b7.b*128 as v FROM
ViewBoolean b0,ViewBoolean b1,ViewBoolean b2,ViewBoolean b3,ViewBoolean b4,ViewBoolean b5,ViewBoolean b6,ViewBoolean b7;

다음 당신은 할 수 있습니다

CREATE VIEW ViewInt16 AS
SELECT b0.v + b1.v*256 as v FROM
ViewByteValues b0,ViewByteValues b1;

다음 당신은 할 수 있습니다

SELECT v+MIN as x FROM ViewInt16 WHERE v<MAX-MIN;

이 속도를 높이기 위해 바이트 값 자동 계산을 건너 뛰고

CREATE VIEW ViewByteValues AS
SELECT 0 as v UNION SELECT 1 as v UNION SELECT ...
...
...254 as v UNION SELECT 255 as v;

다양한 날짜가 필요한 경우 할 수 있습니다.

SELECT DATE_ADD('start_date',v) as day FROM ViewInt16 WHERE v<NumDays;

또는

SELECT DATE_ADD('start_date',v) as day FROM ViewInt16 WHERE day<'end_date';

약간 더 빠른 MAKEDATE 함수로 속도를 높일 수 있습니다.

SELECT MAKEDATE(start_year,1+v) as day FRON ViewInt16 WHERE day>'start_date' AND day<'end_date';

이 트릭은 매우 느리며 미리 정의 된 도메인 (예 : int16 = 0 ... 65536)에서만 FINITE 시퀀스 생성을 허용합니다.

계산을 중단 할 위치를 MySQL에 알려줌으로써 쿼리를 약간 수정할 수 있다고 확신합니다.) (WHERE 절 및 이와 유사한 항목 대신 ON 절 사용)

예를 들면 :

SELECT MIN + (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) FROM
ViewByteValues b0,
ViewByteValues b1,
ViewByteValues b2,
ViewByteValues b3
WHERE (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) < MAX-MIN;

SQL 서버를 몇 시간 동안 바쁘게 유지합니다.

하나

SELECT MIN + (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) FROM
ViewByteValues b0
INNER JOIN ViewByteValues b1 ON (b1.v*256<(MAX-MIN))
INNER JOIN ViewByteValues b2 ON (b2.v*65536<(MAX-MIN))
INNER JOIN ViewByteValues b3 ON (b3.v*16777216<(MAX-MIN)
WHERE (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) < (MAX-MIN);

결과를 LIMIT 1,30 또는 그 이상으로 제한하는 한 MAX-MIN이 크더라도 상당히 빠르게 실행됩니다. 그러나 COUNT (*)는 오래 걸리며 MAX-MIN이 100k보다 클 때 ORDER BY를 추가하는 실수를하면 다시 계산하는 데 몇 초가 걸립니다.


m은 얼마나 큽니까?

다음과 같이 할 수 있습니다.

create table two select null foo union all select null;
create temporary table seq ( foo int primary key auto_increment ) auto_increment=9 select a.foo from two a, two b, two c, two d;
select * from seq where foo <= 23;

여기서 auto_increment가 n으로 설정되고 where 절이 m과 비교되며 두 테이블이 반복되는 횟수는 최소한 ceil (log (m-n + 1) / log (2))입니다.

(임시 테이블 생성 시퀀스에서 두 테이블을 (select null foo union all select null)로 대체하여 임시 테이블이 아닌 두 테이블을 생략 할 수 있습니다.)


다음은 다른 답변에서 사용되는 기술의 압축 바이너리 버전입니다.

select ((((((b7.0 << 1 | b6.0) << 1 | b5.0) << 1 | b4.0) 
                  << 1 | b3.0) << 1 | b2.0) << 1 | b1.0) << 1 | b0.0 as n
from (select 0 union all select 1) as b0,
     (select 0 union all select 1) as b1,
     (select 0 union all select 1) as b2,
     (select 0 union all select 1) as b3,
     (select 0 union all select 1) as b4,
     (select 0 union all select 1) as b5,
     (select 0 union all select 1) as b6,
     (select 0 union all select 1) as b7

고유 또는 정렬 단계가없고 문자열에서 숫자로의 변환이 없으며 산술 연산도 없으며 각 더미 테이블에는 2 개의 행만 있으므로 매우 빠릅니다.

이 버전은 8 "비트"를 사용하므로 0에서 255까지 계산되지만 쉽게 조정할 수 있습니다.


이 쿼리는 0에서 1023까지의 숫자를 생성합니다. 모든 SQL 데이터베이스 버전에서 작동 할 것이라고 생각합니다.

select
     i0.i
    +i1.i*2
    +i2.i*4
    +i3.i*8
    +i4.i*16
    +i5.i*32
    +i6.i*64
    +i7.i*128
    +i8.i*256
    +i9.i*512
    as i
from
               (select 0 as i union select 1) as i0
    cross join (select 0 as i union select 1) as i1
    cross join (select 0 as i union select 1) as i2
    cross join (select 0 as i union select 1) as i3
    cross join (select 0 as i union select 1) as i4
    cross join (select 0 as i union select 1) as i5
    cross join (select 0 as i union select 1) as i6
    cross join (select 0 as i union select 1) as i7
    cross join (select 0 as i union select 1) as i8
    cross join (select 0 as i union select 1) as i9

이것을 시도하십시오 .. 그것은 mysql 버전 8.0에서 나를 위해 작동합니다. 필요한 범위에 따라 아래 쿼리를 수정할 수 있습니다.

WITH recursive numbers AS (
    select 0 as Date
   union all
   select Date + 1
   from numbers
   where Date < 10)
select * from numbers;

그리고 네 게시물에 언급 된대로 테이블을 만들지 않고


경고 : 한 번에 한 행씩 숫자를 삽입하면 N 명령을 실행하게됩니다. 여기서 N은 삽입해야하는 행 수입니다.

임시 테이블을 사용하여이 값을 O (log N)로 낮출 수 있습니다 (10000에서 10699 사이의 숫자를 삽입하려면 아래 참조).

mysql> CREATE TABLE `tmp_keys` (`k` INTEGER UNSIGNED, PRIMARY KEY (`k`));
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO `tmp_keys` VALUES (0),(1),(2),(3),(4),(5),(6),(7);
Query OK, 8 rows affected (0.03 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+8 from `tmp_keys`;
Query OK, 8 rows affected (0.02 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+16 from `tmp_keys`;
Query OK, 16 rows affected (0.03 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+32 from `tmp_keys`;
Query OK, 32 rows affected (0.03 sec)
Records: 32  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+64 from `tmp_keys`;
Query OK, 64 rows affected (0.03 sec)
Records: 64  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+128 from `tmp_keys`;
Query OK, 128 rows affected (0.05 sec)
Records: 128  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+256 from `tmp_keys`;
Query OK, 256 rows affected (0.03 sec)
Records: 256  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+512 from `tmp_keys`;
Query OK, 512 rows affected (0.11 sec)
Records: 512  Duplicates: 0  Warnings: 0

mysql> INSERT INTO inttable SELECT k+10000 FROM `tmp_keys` WHERE k<700;
Query OK, 700 rows affected (0.16 sec)
Records: 700  Duplicates: 0  Warnings: 0

edit: fyi, unfortunately this won't work with a true temporary table with MySQL 5.0 as it can't insert into itself (you could bounce back and forth between two temporary tables).

edit: You could use a MEMORY storage engine to prevent this from actually being a drain on the "real" database. I wonder if someone has developed a "NUMBERS" virtual storage engine to instantiate virtual storage to create sequences such as this. (alas, nonportable outside MySQL)


The simplest way to do this is:

SET @seq := 0;
SELECT @seq := FLOOR(@seq + 1) AS sequence, yt.*
FROM your_table yt;

or in one query:

SELECT @seq := FLOOR(@seq + 1) AS sequence, yt.*
FROM (SELECT @seq := 0) s, your_table yt;

The FLOOR() function is used here to get an INTEGER in place of a FLOAT. Sometimes it is needed.

My answer was inspired by David Poor answer. Thanks David!


If you were using Oracle, 'pipelined functions' would be the way to go. Unfortunately, MySQL has no such construct.

Depending on the the scale of the numbers you want sets of, I see two simple ways to go : you either populate a temporary table with just the numbers you need (possibly using memory tables populated by a stored procedure) for a single query or, up front, you build a big table that counts from 1 to 1,000,000 and select bounded regions of it.


Counter from 1 to 1000:

  • no need to create a table
  • time to execute ~ 0.0014 sec
  • can be converted into a view

:

select tt.row from
(
SELECT cast( concat(t.0,t2.0,t3.0,t4.0) + 1 As UNSIGNED) as 'row' FROM 
(select 0 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) t,
(select 0 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) t2, 
(select 0 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) t3
) tt
order by tt.row

Credits: answer, comment by Seth McCauley below the answer.

ReferenceURL : https://stackoverflow.com/questions/304461/generate-an-integer-sequence-in-mysql

반응형