2017-02-09 6 views
2

Я хочу, чтобы генерировать номер для каждых трех строкСформировать номер строки на каждые 3 ряда

CREATE TABLE #test(period INT) 

INSERT INTO #test 
VALUES  (602),(603),(604),(605),(606),(607),(608),(609) 

Я знаю, что мы можем генерировать последовательность, используя функцию row_number окна или while петли или cursor

SELECT period, 
     (Row_number()OVER(ORDER BY period) - 1)/3 + 1 
FROM #test 

Результат;

+--------+-----+ 
| period | seq | 
+--------+-----+ 
| 602 | 1 | 
| 603 | 1 | 
| 604 | 1 | 
| 605 | 2 | 
| 606 | 2 | 
| 607 | 2 | 
| 608 | 3 | 
| 609 | 3 | 
+--------+-----+ 

Есть ли другой способ достичь этого математически. Там не будет никаких зазоров между периодами

+0

Насколько мне известно, нет лучшего способа сделать это. В конце концов, это то, для чего был разработан ROW_NUMBER, нет? Почему вы хотите использовать другой подход? – Tyron78

+0

Почему вы хотите использовать другой метод, если это работает нормально? Есть ли причина, по которой вы хотите сделать это более математически? – Saypontigohe

+0

@Saypontigohe & @ Tyron78 ​​- Исходный путь требования более сложный, чем этот.Я использую эту последовательность в 'partition by 'другой функции окна. Из-за запроса 'Row_Number' становится очень медленным –

ответ

6

математическая или арифметическая подход может быть использовать номера периода сами:

-- table init here 
DECLARE @MIN_PERIOD INT = (SELECT MIN(period) FROM #test) 

SELECT period, 
     (period - @MIN_PERIOD)/3 + 1 AS seq 
FROM #test 

Это работает до тех пор, пока «не будет пробелов между периодами» остается правдой.

Если вам нужен пункт WHERE основного запроса, также примените его к запросу SELECT MIN(). Будет работать до тех пор, пока WHERE не вызывает периодов пробелов.

+0

Nice one ... didn ' t вычеркните это. – Tyron78

+0

Отличный .. это было полезно –

1

А что-то вроде этого ...

WITH X AS (
SELECT * 
    ,ROW_NUMBER() OVER (ORDER BY [period] ASC) rn 
FROM #test 
) 
SELECT [period] 
     ,ROW_NUMBER() OVER (PARTITION BY (X.rn % 3) ORDER BY rn ASC) rn 
FROM X 
ORDER BY [period] 
+1

Спасибо .. Я не хочу использовать 'Row_Number' –

+0

Вопрос был о другом подходе без row_number ... – Tyron78

2

Это можно сделать с помощью функции NTILE(), но я не думаю, что она более эффективна, чем ROW_NUMBER(), главным образом потому, что этот метод должен получить общее количество, чтобы определить количество групп.

Создание тестовой среды:

/* -- SQL 2016 
DROP TABLE IF EXISTS #test; 
GO 
*/ 

IF OBJECT_ID('tempdb.dbo.#test') IS NOT NULL DROP TABLE #test 

CREATE TABLE #test(period INT); 
GO 

INSERT INTO #test -- Make it bigger 
VALUES  (602),(603),(604),(605),(606),(607),(608),(609); 
GO 51 

ROW_NUMBER Метод:

SELECT /*ROW_NUM*/ period, 
     (Row_number()OVER(ORDER BY period) - 1)/3 + 1 
FROM #test; 
GO 

ROW_NUMBER

IO и время выступления: укороченные для удобства чтения

(400 строк (а)) Таблица «Рабочий стол». Число сканирования 0, логическое чтение 0, физическое значение 0 '# test_00000000000E'. Количество сканирования 1, логического чтения 1, физических чтений 0

(1 строку (ы) пострадавших)

SQL-сервера Выполнение Время: процессорного времени = 0 мс, затраченное время = 85 мс .

NTILE Метод

DECLARE @ntile_var int; 

SELECT @ntile_var = COUNT(*) FROM #test; 

SELECT /*NTILE*/period 
    , NTILE(@ntile_var/3) OVER (ORDER BY period) 
FROM #test 

IO и времени выступления: Укороченные для удобочитаемости

SQL Server синтаксического анализа и время компиляции: процессорного времени = 0 мс, затраченное время = 0 мс.

Время выполнения SQL Server: время процессора = 0 мс, прошедшее время = 0 мс.

SQL Server анализирует и компилирует время: CPU time = 0 мс, прошедшее время = 0 мс.

Таблица '# test__00000000000E'. Количество сканирования 1, логического чтения 1, физических чтений 0

(1 строку (ы) пострадавших)

SQL-сервера Выполнение Время: процессорного времени = 0 мс, прошедшее время = 0 мс.

(400 строк (а)) Таблица «Рабочий стол». Число сканирования 3, логические значения 811, физические данные 0 Таблица '#test ___ 00000000000E'. Количество сканирования 1, логического чтения 1, физических чтений 0

(1 строку (ы) пострадавших)

SQL Выполнение сервера Время: процессорного времени = 0 мс, затраченное время = 93

NTILE

Оба они дают те же результаты:

Results_GroupsOf3

Но есть предостережение! MSDN положить его в достаточной степени, как (подчеркивание добавлено)

Если число строк в разделе не делится на integer_expression, это вызовет группу из двух размеров, отличающихся один членом. Большие группы относятся к меньшим группам в порядке , указанном в предложении OVER. Например, если общее число строк равно 53, а число групп равно пяти, первые три группы будут имеют 11 строк, а две оставшиеся группы будут иметь по 10 строк.

Так с помощью метода NTILE, вы могли бы получить несколько групп 4, так что остальные из них могут быть 3.