Как использовать результаты запроса CTE внутри другого запроса

#sql #sql-server #tsql #common-table-expression

#sql #sql-сервер #tsql #common-table-expression

Вопрос:

Я хочу взять результат запроса CTE и использовать его внутри другого запроса.

В этом упрощенном примере для возврата списка идентификаторов используется запрос CTE.

 with test_cte (id,name) as (
    select id, name
    from test
)
select id
from test_cte
where name = 'john'
 

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

 delete from test
where id in (
    with test_cte (id,name) as (
        select id, name
        from test
    )
    select id
    from test_cte
    where name = 'john'
)
 

Есть ли способ сделать это?

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

1. CTE определяется в начале вашего оператора, а не в середине.

2. Итак, я не могу использовать его как подзапрос, правильно?

3. Это не подзапрос, @Madison, это CTE (общее табличное выражение): С common_table_expression (Transact-SQL) . CTE всегда определяется в начале инструкции, как показано в связанной документации.

4. Да, я этого боялся.

5. Это не значит, что вы не можете использовать его в инструкции DML, @Madison320 , вы просто используете его неправильно…

Ответ №1:

Ты просто имеешь в виду это:

 ;with test_cte(id,name) as
(
  select id,name from dbo.test
)
delete test_cte where name='john';
 

Вы хотите удалить строки и показать строки, которые вы удалили?

 ;with test_cte(id,name) as
(
  select id,name from dbo.test
)
delete test_cte 
output deleted.id, deleted.name
where name='john';
 

Чтобы взять ваш явный пример:

 delete from test
where id in (
    with test_cte (id,name) as (
        select id, name
        from test
    )
    select id
    from test_cte
    where name = 'john'
)
 

Вы получаете синтаксическую ошибку, потому что, ну, в вашем синтаксисе есть ошибка. CTE должен быть определен заранее, а не в какой-либо случайной или произвольной точке вашего запроса.

 ;with test_cte (id,name) as (
    select id, name
    from test
)
delete from test
where id in (
    select id
    from test_cte
    where name = 'john'
)
 

Но это все еще кажется ужасно сложным по сравнению с более простыми примерами, которые я показал.

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

1. Я должен признать, меня действительно все еще смущает, что вы находитесь на стороне того забора, который рассматривает точку с запятой как «beginninator».

2. @Larnu, потому что все равно скопирует и вставит это в процедуру, которая имеет DECLARE @name varchar(32) = 'john' , а затем кричит на меня, что я нарушил их код. Считайте это постоянным.

3. Тогда, возможно, вам следует привести более репрезентативный пример, @Madison320 .

4. @ThomasDoconski Посмотрите ветку комментариев. Причина в том, что люди берут WITH ... образцы кода и вставляют его в свой существующий код без точек с запятой в предыдущих операторах. Затем нас обвиняют в том, что мы даем им плохой код. У вас может быть столько операторов с запятой до и после, сколько вы хотите, поэтому нет никакого вреда в том, чтобы изолировать себя от этого заранее, за исключением необходимости объяснять себя. Я начинаю задаваться вопросом, что хуже.

5. В этом случае у @AaronBertrand есть очень веская точка зрения: вы задали неправильный вопрос, то есть вы слишком упростили, и, следовательно, лучший ответ на ваш вопрос не будет работать в вашем реальном случае использования…