SQL Выберите 'n' записей без таблицы - PullRequest
15 голосов
/ 30 июня 2011

Есть ли способ выбора определенного количества строк без создания таблицы. например если я использую следующее:

SELECT 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Это даст мне 10, я хочу 10 новых рядов.

Спасибо

Ответы [ 8 ]

30 голосов
/ 30 июня 2011

Вы можете использовать рекурсивный CTE для генерации произвольной последовательности чисел в T-SQL, например, так:

DECLARE @start INT = 1;
DECLARE @end INT = 10;

WITH numbers AS (
    SELECT @start AS number
    UNION ALL
    SELECT number + 1 
    FROM  numbers
    WHERE number < @end
)
SELECT *
FROM numbers
OPTION (MAXRECURSION 0);
18 голосов
/ 30 июня 2011

Если у вас фиксированное количество строк, вы можете попробовать:

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
UNION
SELECT 10
7 голосов
/ 28 декабря 2014

Рекурсивный подход CTE - это действительно хорошо.

Просто помните о разнице в производительности.Давайте поиграем с миллионом записей:

Рекурсивный подход CTE.Длительность = 14 секунд

declare @start int = 1;
declare @end int = 999999;

with numbers as 
(
    select @start as number
    union all
    select number + 1 from numbers where number < @end
)
select * from numbers option(maxrecursion 0);

Объединение All + Cross Join подход.Длительность = 6 секунд

with N(n) as 
(
    select 1 union all select 1 union all select 1 union all 
    select 1 union all select 1 union all select 1 union all 
    select 1 union all select 1 union all select 1 union all select 1   
)
select top 999999
    row_number() over(order by (select 1)) as number 
from 
    N n1, N n2, N n3, N n4, N n5, N n6;

Конструктор табличных значений + метод перекрестного соединения.Длительность = 6 секунд

(если SQL Server> = 2008)

with N as 
(
    select n from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) t(n)    
)   
select top 999999
    row_number() over(order by (select 1)) as number
from 
    N n1, N n2, N n3, N n4, N n5, N n6;

Рекурсивный подход CTE + перекрестное соединение.:) Продолжительность = 6 секунд

with N(n) as 
(
    select 1 
    union all
    select n + 1 from N where n < 10    
)   
select top 999999
    row_number() over(order by (select 1)) as number 
from 
    N n1, N n2, N n3, N n4, N n5, N n6;

Мы получим более удивительный эффект, если попытаемся вставить результат в табличную переменную:

Вставить с помощьюРекурсивный подход CTE.Длительность = 17 секунд

declare @R table (Id int primary key clustered);

with numbers as 
(
    select 1 as number
    union all
    select number + 1 from numbers where number < 999999
)
insert into @R 
select * from numbers option(maxrecursion 0);

INSERT INTO с подходом Cross Join.Продолжительность = 1 секунда

declare @C table (Id int primary key clustered);

with N as 
(
    select n from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) t(n)    
) 
insert into @C 
select top 999999
    row_number() over(order by (select 1)) as number
from 
    N n1, N n2, N n3, N n4, N n5, N n6;

Вот интересная статья о Tally Tables

7 голосов
/ 30 июня 2011

Это хороший способ, если вам нужен длинный список (поэтому вам не нужно много UNION утверждений:

WITH CTE_Numbers AS (
    SELECT n = 1
    UNION ALL
    SELECT n + 1 FROM CTE_Numbers WHERE n < 10 
)
SELECT n FROM CTE_Numbers
4 голосов
/ 30 июня 2011
SELECT 1
UNION 
SELECT 2
UNION
...
UNION
SELECT 10 ;
2 голосов
/ 30 июня 2011

Использование PIVOT (в некоторых случаях это будет излишним)

DECLARE @Items TABLE(a int, b int, c int, d int, e int); 

INSERT INTO @Items
VALUES(1, 2, 3, 4, 5)

SELECT Items 
FROM @Items as p 
UNPIVOT     
(Items FOR Seq IN          
([a], [b], [c], [d], [e]) ) AS unpvt 
1 голос
/ 05 октября 2015

Использование таблицы spt_values:

SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY number) 
FROM [master]..spt_values ORDER BY n;

Или, если требуемое значение меньше 1 КБ:

SELECT DISTINCT n = number FROM master..[spt_values] WHERE number BETWEEN 1 AND 1000;

Это таблица, которая используется внутренними хранимыми процедурами для различных целей. Его использование в Интернете кажется довольно распространенным, даже если оно недокументировано, не поддерживается, оно может исчезнуть однажды и потому, что содержит только конечный, неуникальный и несмежный набор значений. В SQL Server 2008 R2 имеется 2164 уникальных и 2,508 общих значений; в 2012 году их было 2167 уникальных и 2,515. Это включает в себя дубликаты, отрицательные значения и даже при использовании DISTINCT, много пробелов, как только вы выйдете за число 2048. Таким образом, обходной путь должен использовать ROW_NUMBER() для генерации непрерывной последовательности, начиная с 1, на основе значений в таблице.

Кроме того, чтобы получить больше значений, чем записи 2k, вы можете объединить таблицу с самим собой, но в обычных случаях этой таблицы достаточно.

С точки зрения производительности, она не должна быть слишком плохой (создание миллиона записей, это заняло 10 секунд на моем ноутбуке), и запрос довольно легко читается.

Источник: http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1

0 голосов
/ 28 декабря 2014
;WITH nums AS
    (SELECT 1 AS value
    UNION ALL
    SELECT value + 1 AS value
    FROM nums
    WHERE nums.value <= 99)
SELECT *
FROM nums  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...