Как упорядочить непрерывный серийный номер в двух или нескольких столбцах последовательно в sql Server?

#sql #sql-server #numbers #sequence

#sql #sql-сервер #числа #последовательность #рекурсивный запрос

Вопрос:

Я хочу напечатать или отобразить от 1 до 10 или любое максимальное число в формате двух столбцов, используя запрос MS Sql-Server. Точно так же, как показано на прилагаемом снимке экрана.

введите описание изображения здесь

Поэтому, пожалуйста, дайте какие-либо предложения.

Комментарии:

1. Всегда ли это будет 2 столбца?

Ответ №1:

Мне нравится использовать рекурсивные запросы для этого:

 with cte (num1, num2) as (
    select 1, 2 
    union all
    select num1   2, num2   2 from cte where num2 < 10
)
select * from cte order by num1
  

Вы управляете максимальным числом с условием неравенства в рекурсивном члене cte.

Если вам нужно сгенерировать более 100 строк, вам нужно добавить option(maxrecursion 0) в самом конце запроса.

Ответ №2:

Использование нескольких встроенных подсчетов было бы намного быстрее, чем a WHILE . Эта версия будет содержать до 1000 целых чисел (500 строк):

 DECLARE @Start int = 1,
        @End int = 99;

SELECT TOP(CONVERT(int,CEILING(((@End*1.) - @Start   1)/2)))
       (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1)*2   @Start AS Number1,
       CASE WHEN (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1)*2   @Start  1 <= @End THEN (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1)*2   @Start  1 END AS Number2
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N1(N)
     CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N2(N)
     CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N3(N);
  

Альтернативный способ, который выглядит менее запутанным с CASE помощью и TOP , — использовать пару CTE:

 WITH Tally AS(
    SELECT TOP(@End - @Start   1)
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1   @Start AS I
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N1(N)
         CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N2(N)
         CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N3(N)),
Numbers AS(
    SELECT I AS Number1,
           LEAD(I) OVER (ORDER BY I) AS Number2
    FROM Tally)
SELECT Number1,
       Number2
FROM Numbers 
WHERE Number1 % 2 = @Start % 2;
  

Ответ №3:

Предполагая, что вы начинаете с таблицы с одним столбцом, вы можете использовать:

 select min(number), max(number)
from sample_data
group by floor( (number - 1) / 2);
  

Ответ №4:

В качестве альтернативы, решение на основе набора с использованием оконных функций:

 use tempdb

;with sample_data as (
select 1 as val 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 union all
select 10 
) 

, sample_data_split  as
(
    select 
        val
    ,   2- row_number() over (order by val) % 2 as columnid
    ,  NTILE((select count(*) / 2  from sample_data) ) over (order by val) groupid
    from sample_data
) 
  

промежуточный результат sample_data_split :

 val columnid    groupid
1   1   1
2   2   1
3   1   2
4   2   2
5   1   3
6   2   3
7   1   4
8   2   4
9   1   5
10  2   5

  

а затем получить результирующий набор в желаемом формате:

 select 
    min(case when columnid = 1 then val end) as column1
,   min(case when columnid = 2 then val end) as column2
from sample_data_split
group by groupid
  
 column1 column2
1   2
3   4
5   6
7   8
9   10
  

Эти CTE могут быть объединены в один SELECT:

 select 
    min(case when columnid = 1 then val end) as column1
,   min(case when columnid = 2 then val end) as column2
from 
(
    select 
        val
    ,   2- row_number() over (order by val) % 2 as columnid
    ,  NTILE((select count(*) / 2  from sample_data) ) over (order by val) groupid
    from sample_data
) d
group by groupid
  

Положительная сторона такого подхода в том, что он хорошо масштабируется и не имеет верхней границы количества обрабатываемых строк

Ответ №5:

Итак, я получил это решение, как показано ниже…

 declare @t table
(
id int identity(1,1),
Number_1 int,
Number_2 int
)


declare @min int=1
declare @max int=10
declare @a int=0;
declare @id int=0


while(@min<=@max)
begin

if(@a=0)
begin
insert into @t
select @min,null
set @a=1
end
else if(@a=1)
begin
select top 1 @id=id from @t order by id desc
update @t set Number_2=@min where id=@id
set @a=0
end

set @min=@min 1
end

select Number_1,Number_2 from @t
  

Комментарии:

1. Почему a WHILE ? SQL — это язык, основанный на наборе; это был бы самый медленный способ добиться этого.