1

Я играл вокруг отчетов, и оказалось, что row_number не работает в рекурсии.ROW_NUMBER не работает в CTE

!! Я упростил пример!

Из таблицы 3 записей:

declare @sometable table (id int, id2 int) 
insert into @sometable 
select 1 as id, 11 as id2 
union all 
select 2,   22 
union all 
select 3,  33  

В КТР выберите Все и маркируют первую запись должны быть исключены на следующей итерации:

;with cte(iteration, ord, id, id2, deal) as 
(
select ordered.* 
    , deal = (case when ord = 1 then 1 else 0 end) 
from 
    (select 1 iteration, 
     ord = ROW_NUMBER() OVER (ORDER BY id), 
     st.* 
    FROM @sometable st) ordered 

) 
select * from CTE 
union all 
    select 
    ordersinverted.nextIteration, 
    ordersinverted.ord, 
    ordersinverted.id,    
    ordersinverted.id2, 
    deal = (case when ord = 1 then 1 else 0 end) 
from (
    select 
     ROW_NUMBER() OVER (PARTITION BY ord ORDER BY iteration desc) as reversedIteration, 
     ROW_NUMBER() OVER (ORDER BY cte.id) as ord, 
     iteration + 1 as nextIteration,     
     cte.id, 
     cte.id2     
    from cte 
    where cte.deal = 0 
) ordersinverted 

Это дает мне ожидаемый результат для 3-х итераций: Использовать row_number out of CTE result

Мне очень хотелось бы получить аналогичный результат и рекурсивно назвать select. К сожалению, это где подозревается ошибка иметь место:

;with cte(iteration, ord, id, id2, deal) as 
(
    select ordered.* 
     , deal = (case when ord = 1 then 1 else 0 end) 
    from 
     (select 1 iteration, 
      ord = ROW_NUMBER() OVER (ORDER BY id), 
      st.* 
     FROM @sometable st) ordered 
union all 
    select 
     ordersinverted.nextIteration, 
     ordersinverted.ord, 
     ordersinverted.id,    
     ordersinverted.id2, 
     deal = (case when ord = 1 then 1 else 0 end) 
    from (
     select 
      ROW_NUMBER() OVER (PARTITION BY ord ORDER BY iteration desc) as  reversedIteration, 
      ROW_NUMBER() OVER (ORDER BY cte.id) as ord, 
      iteration + 1 as nextIteration,     
      cte.id, 
      cte.id2     
     from cte 
     where cte.deal = 0 
    ) ordersinverted 
) 
select * from CTE 

Используйте row_number within CTE result

Ой, извините. У этого должен быть формат вопроса: Так что мой вопрос: Является ли это признаком или ошибкой?

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

with T (id,grp_id) as (
select 1 as id,1 as grp_id from dual union all 
select 2 as id,1 as grp_id from dual union all 
select 3 as id,1 as grp_id from dual union all 
select 1 as id,2 as grp_id from dual union all 
select 2 as id,2 as grp_id from dual union all 
select 3 as id,2 as grp_id from dual) 
, 
rec (id,grp_id,rn) as (
select id, grp_id, row_number()over(partition by grp_id order by id) rn from T where grp_id=1 
union all 
select t.id, t.grp_id, row_number() over(partition by t.grp_id order by t.id) rn from T inner join rec on t.id=rec.id and t.grp_id=rec.grp_id+1 

) 

PS. Он работает аналогично, если использовать функции max() или min() ...

+0

У меня действительно нет идеи о том, что вы пытаетесь достичь/выбрать, но я подозреваю, ваша проблема заключается в смешении подзапросов, row_number и рекурсивного cte, а SQL-сервер заказа выполняет запрос в Я думаю, что вы чрезмерно злоупотребляете запросом, делая это. Но поскольку я действительно не знаю, что вы на самом деле пытаетесь сделать, на основе ввода, я не могу указать лучше. Вместо того, чтобы пытаться сделать все в одном запросе, разделите его на более мелкие шаги. –

+0

я бы попытался 1) создать CTE без row_number в нем 2) создать CTE2, который является Select CTE с row_number в нем. Я не уверен, что вы могли бы попробовать это – Cato

+0

Спасибо за рекомендации о том, как обходиться. Это, однако, более подробно описывает проблему, существующую в MS SQL. Этот скрипт работает в Oracle. Будет ли добавить образец здесь – user6821153

ответ

2

Это документированное поведение. Следовательно, его следует рассматривать как «особенность». Вот документация для этого случая: https://msdn.microsoft.com/en-us/library/ms175972.aspx

Аналитические и агрегатные функции в рекурсивной части КТР являются применяются к набору для текущего уровня рекурсии, а не к набору для КТР. Такие функции, как ROW_NUMBER, работают только с подмножеством данных , переданных им по текущему уровню рекурсии, а не по всему набору данных , переданным в рекурсивную часть CTE. Для получения дополнительной информации , см. Пример K. Использование аналитических функций в рекурсивном токе CTE.

В параграфе K этой статьи есть хорошая демонстрация поведения ROW_NUMBER в рекурсивном CTE. Так как рекурсивные данные процесса CTE по строкам, ROW_NUMBER в рекурсивной части CTE всегда будут возвращены 1. Вы можете изменить ROW_NUMBER() OVER (ORDER BY id) на COUNT(*) OVER(), чтобы проверить, сколько строк SQL Server обрабатывает сразу для якоря и для рекурсивной части КТР. Там будет 3 и 1 соответственно.