Почему не работает cte `NOT IN`, но работает подзапрос `NOT IN`?

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я пытаюсь решить проблему с командировками и пользователями SQL Leetcode. Если я правильно читаю, NOT IN cte не работает, но NOT IN подзапрос работает. Почему?

Работает следующий код.

 select request_at as Day, 
        cast(sum(iif(status like 'cancelled%', 1.0, 0.0))/count(status) as decimal(4,2)) as [Cancellation Rate]
from trips 
where (request_at between '2013-10-01' and '2013-10-03')
        and client_id not in (SELECT USERS_ID FROM USERS WHERE BANNED='Yes')
        and driver_id not in (SELECT USERS_ID FROM USERS WHERE BANNED='Yes')
group by request_at
  

Но приведенный ниже не работает. Я получаю сообщение об ошибке:

 Runtime Error
[42000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Incorrect syntax near 'BANNED_USRS'. (102) (SQLExecDirectW)
  
 with 
banned_usrs as 
(select users_id from users where banned = 'Yes')

select request_at as Day, 
        cast(sum(iif(status like 'cancelled%', 1.0, 0.0))/count(status) as decimal(4,2)) as [Cancellation Rate]
from trips 
where (request_at between '2013-10-01' and '2013-10-03')
        and client_id not in banned_usrs
        and driver_id not in banned_usrs
group by request_at
  

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

1. banned_usrs — это таблица в вашем cte. Если вы попытаетесь присоединиться к banne_usrs, а затем выполнить фильтрацию после присоединения, это будет иметь смысл.

2. Как объяснялось, CTE — это виртуальная таблица , а не подзапрос. Вы не можете использовать формат, подобный «in имя_таблицы», поскольку таблица может иметь несколько столбцов, и нет встроенного синтаксиса для проверки наличия значения во всех строках и во всех столбцах таблицы. Синтаксис, который вы должны использовать, примерно такой: » in (select column_Name From Table_Name) »

3. Ооо … спасибо!

Ответ №1:

Вам нужно явно выбрать из CTE:

 with banned_usrs as (select users_id from users where banned = 'Yes')

select
    request_at as Day, 
    cast(sum(iif(status like 'cancelled%', 1.0, 0.0))/count(status) as decimal(4,2)) as [Cancellation Rate]
from trips 
where
    request_at between '2013-10-01' and '2013-10-03' and
    client_id not in (select users_id from banned_usrs) and
    driver_id not in (select users_id from banned_usrs);
group by
    request_at;
  

CTE сам по себе является просто кодом SQL и не формирует подзапрос, если вы явно не пишете его как таковой.