Почему ссылка на столбец (как левый операнд), который не является частью запрашиваемой таблицы, не является ошибкой в ​​операторе EXISTS? - PullRequest
0 голосов
/ 18 апреля 2019

Учитывая этот пакет SQL:

CREATE TABLE #source
(
  ID int,
  SourceDescr varchar(255)
)
INSERT INTO #source
VALUES
(1, 'first'),
(2, 'second')


CREATE TABLE #target
(
  ID int,
  TargetDescr varchar(255)
)
INSERT INTO #target
SELECT * FROM #source

INSERT INTO #target
SELECT * FROM #source S
WHERE NOT EXISTS
(
  SELECT 1
  FROM #target
  WHERE SourceDescr = S.SourceDescr
  --       /\ How is this not an error?
)

Почему предложение WHERE в операторе EXISTS работает? Конечно, в таблице #target нет столбца SourceDescr.

Я даже попробовал это, и это также работает:

INSERT INTO #target
SELECT * FROM #source S
WHERE NOT EXISTS
(
  SELECT SourceDescr -- ??
  FROM #target
  WHERE SourceDescr = S.SourceDescr
)

Чтение официальной документации для EXISTS не прояснило это для меня.

Спасибо.

Ответы [ 2 ]

3 голосов
/ 18 апреля 2019

Поскольку это объясняется в документации: Подзапросы (SQL Server) :

Имена столбцов в операторе неявно уточняются таблицей, указанной в предложении FROM на том же уровне. Если столбец не существует в таблице, указанной в предложении FROM подзапроса, он неявно определяется таблицей, указанной в предложении FROM внешнего запроса.

3 голосов
/ 18 апреля 2019

Это интерпретируется как:

INSERT INTO #target
    SELECT S.*
    FROM #source S
    WHERE NOT EXISTS
    (
      SELECT 1
      FROM #target
      WHERE S.SourceDescr = S.SourceDescr
    );

Он работает, но не выполняет то, что вы собираетесь.

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

INSERT INTO #target
    SELECT S.*
    FROM #source S
    WHERE NOT EXISTS
    (
      SELECT 1
      FROM #target t
      WHERE t.SourceDescr = S.SourceDescr
    );

вызовет ошибку во время компиляции и никогда не выполнится.

...