Использование оператора INSERT с использованием INNER JOIN с NOT EXISTS дает неверный результат - PullRequest
3 голосов
/ 27 июня 2011

У меня есть база данных Access .mdb. Есть две таблицы с одинаковыми структурами: цены и tmpPrices. Каждая таблица имеет три столбца: [По состоянию на дату std] (Дата / Время), Цена (двойная), CUSIP (текст, 255 символов). tmpPrices содержит новые записи, которые будут добавлены в цены. У меня есть два SQL-запроса для обновления цен из tmpPrices, один использует соединение WHERE, а другой использует INNER JOIN.

Следующая версия A работает правильно:

INSERT INTO [Prices] SELECT * FROM [tmpPrices] WHERE NOT EXISTS 
(SELECT * from [Prices]
  WHERE ([Prices].[As of date std] = [tmpPrices].[As of date std])
  AND ([Prices].CUSIP = [tmpPrices].CUSIP));

, тогда как эта версия B не работает:

INSERT INTO [Prices] SELECT * FROM [tmpPrices] WHERE NOT EXISTS
(SELECT  [Prices].* FROM [Prices] INNER JOIN [tmpPrices] ON 
   ([Prices].[As of Date std] = [tmpPrices].[As of Date std]) 
   AND ([Prices].CUSIP = [tmpPrices].CUSIP));

Оба подзапроса дают один и тот же результат: подмножество записей из tmpPrices, которые уже существуют в ценах.

Использование версии A не имело бы большого значения, если бы мне не пришлось обновлять другие таблицы, а одной другой таблице требуется обновление в течение 45 минут с использованием версии A, но лишь небольшая ее часть с использованием версии B, и, похоже, она работает правильно , Поэтому я хотел бы понять, что здесь происходит.

Ответы [ 3 ]

3 голосов
/ 28 июня 2011

ЛЕВОЕ СОЕДИНЕНИЕ - определенно путь, как предложил @devsh, но вам не нужно использовать подзапрос.Я построил это в конструкторе запросов Access, и он работает в Access 2003 с таблицами, которые вы описали.Я переименовал [По состоянию на дату std], чтобы исключить пробелы.

INSERT INTO Prices ( As_of_Date_std, Price, CUSIP)
SELECT t.As_of_Date_std, t.Price, t.CUSIP
FROM
    tmpPrices AS t
    LEFT JOIN Prices AS p
    ON (t.As_of_Date_std = p.As_of_Date_std) AND (t.CUSIP = p.CUSIP)
WHERE (((p.As_of_Date_std) Is Null));
1 голос
/ 27 июня 2011

Второй запрос не работает, поскольку отсутствует связь между выбранной частью запроса (из которой вы пытаетесь вставить) и содержащимся в нем подзапросом. Если вы хотите использовать этот формат для вставки, вы можете сделать это:

INSERT INTO [Prices]
SELECT [As of Date], Price, CUSIP
FROM 
(SELECT tmpPrices.[As of Date std], tmpPrices.[Price], tmpPrices.[CUSIP]
FROM tmpPrices LEFT JOIN Prices ON
([Prices].[As of date std] = [tmpPrices].[As of date std]) AND ([Prices].CUSIP = [tmpPrices].CUSIP)) WHERE Prices.[As of date std] is null)
0 голосов
/ 27 июня 2011

A занимает так много времени, потому что он в основном выполняет полное сканирование таблицы tmpPrices для каждой записи в ценах, поскольку в подзапросе не определено фактическое соединение.

Давайте посмотрим, сможем ли мы получить васбыстрый запрос, который даст вам то, что вам нужно.

tmpPrices для этого потребуется поле автонумерации, и я предлагаю сделать его pk для tmpPrices.Также уникальный ключ, основанный на 3 других полях, для предотвращения дублирования в tmpPrices (уверен, что вы можете сделать это в Access).

INSERT INTO [Prices] ([As of Date std],[Price],[CUSIP])
SELECT [As of Date std],[Price],[CUSIP] from tmpPrices where autoNumberID not in(
  SELECT autonumberID
  FROM tmpPrices 
  innerJoin prices on [Prices].[As of Date std] = [tmpPrices].[As of Date std] 
   AND [Prices].CUSIP = [tmpPrices].CUSIP
) query1

Это также поможет сохранить скорость, если вы удаляете любые записи в tmpPricesкаждый раз, когда вы обновляете цены с помощью этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...