SQL Server: с выбором в НЕ В

У меня проблема с этим кодом. У меня есть дерево в моей базе данных, и мне нужно выбрать все узлы, кроме узла и его дочерних элементов, внука и т. д. Я сделал запрос WITH - он работает. Я могу выделить все большое семейство The Node. Но когда я пытаюсь сделать SELECT ... WHERE id NOT ID (а здесь большая семья), у меня возникают ошибки ...

КОД:

Select * from TALBE 
where id NOT IN
(
    WITH TempTable 
    AS
    (
        SELECT ...
        UNION ALL
        SELECT ...
    )
    Select id from TempTable;
);

или другая версия

Select * from TALBE 
where id NOT IN
(
    select id from
    (
        WITH TempTable 
        AS
        (
            SELECT ...
            UNION ALL
            SELECT ...
        )
        Select id from TempTable
    )
);

В этом коде мне нужно иметь первые 2 строки. Это не мое решение - просто должно быть.

Ошибки:

Msg 156, Level 15, State 1, Line 4

Неправильный синтаксис рядом с ключевым словом 'WITH'.

Msg 319, Level 15, State 1, Line 4

Неверный синтаксис рядом с ключевым словом with. Если этот оператор является обычным табличным выражением, предложением xmlnamespaces или предложением контекста отслеживания изменений, предыдущий оператор должен заканчиваться точкой с запятой.

Msg 102, Level 15, State 1, Line 14

Неправильный синтаксис рядом с ')'.


person Mr.Qbs    schedule 06.08.2014    source источник
comment
Вы не можете вложить cte в качестве подзапроса. Просто уберите cte, здесь он не нужен.   -  person Sean Lange    schedule 06.08.2014
comment
AFAIK WITH всегда должен предшествовать ; (или, конечно, быть самым первым оператором в вашем скрипте) - как упоминал @SeanLange, не пытайтесь вложить свой WITH во что-то еще   -  person DrCopyPaste    schedule 06.08.2014


Ответы (3)


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

http://technet.microsoft.com/en-us/library/ms190766(v=sql.105).aspx

WITH TempTable 
AS
(
     SELECT ...
     UNION ALL
     SELECT ...
)
Select * from TALBE 
where id NOT IN
(
    select id from TempTable
);
person jtimperley    schedule 06.08.2014

В соответствии с тем, как написан этот код, запрос CTE будет выполняться для каждой тестируемой строки, поскольку CTE на самом деле является не результирующим набором, а оператором. Это очень вероятно вызовет проблемы с производительностью в будущем. Лучшим способом было бы кэшировать результаты вашего запроса в таблице в памяти и использовать их при фактическом выборе, например так:

DECLARE @badIds TABLE
(
    Id INT NOT NULL --replace the INT with whatever type your Id column is
)

INSERT INTO @badIds
SELECT someId
FROM someTable
UNION ALL
SELECT someOtherId
FROM someOtherTable
...

SELECT * FROM Table WHERE id NOT IN (SELECT Id FROM @badIds)
person Radu Porumb    schedule 06.08.2014

Что-то вроде этого. Вам, вероятно, следует прочитать документацию о CTE, чтобы понять, что они из себя представляют и как они используются.

Select * from TALBE 
where id NOT IN
(
    SELECT ID from someTable
    UNION ALL
    SELECT ID from SomeOtherTable
);

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

WITH TempTable 
AS
(
    SELECT ...
    UNION ALL
    SELECT ...
)

Select * from TALBE 
where id NOT IN
(
    SELECT ID from TempTable
);
person Sean Lange    schedule 06.08.2014
comment
Это обрабатывает только два уровня, а не n уровней, это не рекурсивно. - person jtimperley; 06.08.2014
comment
То, что вы изначально опубликовали, также не оказалось рекурсивным. Если вам нужен рекурсивный cte, переместите его за пределы вашего запроса. - person Sean Lange; 06.08.2014