#sql #sql-server #common-table-expression
#sql #sql-server #common-table-expression
Вопрос:
У меня вопрос о CTE. Вы можете запустить инструкцию sql с помощью WITH, а затем вы можете создать один или несколько запросов CTE, которые вы затем в конце можете сделать (в данном случае) select on .
Мой вопрос: будут ли выполняться все запросы CTE или только те, которые используются?
Например.
WITH cte_1
as (
Select * from table1
),
cte_2
as (
Select * from table2
)
Select * from cte_1
Будет ли это означать, что select будет выполняться в table1 и table2?
Комментарии:
1. Я бы предположил, что ранняя «фаза перефразирования запроса» автоматически удалит его, но я могу ошибаться.
2. Я не думаю, что table2 будет доступен в вашем запросе. Будут выбраны только данные из таблицы1, поскольку вы используете их в своем final / select
3. Быстрый тест. План выполнения будет игнорировать 2-й cte
4. Вероятно, вы могли бы создать запрос, который обманул бы оптимизатора. В большинстве случаев это не должно вызывать проблем, и ненужные cte будут игнорироваться. Вы также не должны думать о нем как о «выполняемом» как о каком-либо отдельном шаге в более крупном запросе.
5. Все, что оптимизатор может доказать как не имеющее эффекта, будет удалено. Это включает в себя фактическую выборку столбцов из подзапросов, которые не требуются позже в цепочке, и удаление левых соединений, столбцы которых не требуются и которые не изменяют количество строк.
Ответ №1:
Чтобы завершить ответ мастера Гордона (я смею) :
если вы объявите 2 cte и не используете ни один из них, вы также получите это сообщение об ошибке
with cte as (select 1/0 as val), cte2 as (select 1/0 as val)
select 1
Msg 422 Level 16 State 4 Line 2
Common table expression defined but not used.
Но если вы используете хотя бы один, инструкция принимается :
with cte_divide_by_zero as (select 1/0 as val), cte_legit as (select 'it works' as val)
select * from cte_divide_by_zero
Msg 8134 Level 16 State 1 Line 1
Divide by zero error encountered.
И если вы выберете другой CTE, это докажет, что ваш неиспользуемый CTE никогда не выполняется, поскольку ошибка не возникает :
with cte_divide_by_zero as (select 1/0 as val), cte_legit as (select 'it works' as val)
select * from cte_legit
val
--------
it works
Комментарии:
1. Это также работает, если вы объявляете табличную переменную перед cte и выбираете из нее. Я полагаю, это сработает, если вы также выберете из любой другой таблицы. Cte обрабатываются так же, как подзапрос, и присоединяются к внешнему запросу. Если не к чему присоединяться, это очевидная ошибка. Вы не можете выбрать только из подзапроса
Ответ №2:
Я получаю это сообщение:
Сообщение 422 Уровень 16 Состояние 4 Строка 2
Общее табличное выражение определено, но не используется.
при запуске:
with cte as (select 1/0 as val)
select 1
Вот скрипка db<> .
Комментарии:
1. Интересно, это работает, когда основным запросом является
SELECT * FROM tab
илиOPTION (FORCE ORDER)
применяется db<>demo2. Смотрите мой дальнейший эксперимент, Гордон 🙂