Странное поведение SQL с INSERT и WHERE NOT EXISTS - PullRequest
0 голосов
/ 10 июня 2011

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

Я пробовал это под MySQL 5.1 и MSSQL 2k5:

MySQL

INSERT IGNORE INTO test (id, количество) ВЫБЕРИТЕ 6, 50 ОТ теста ГДЕ НЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ ТЕСТА, ГДЕ сумма> = 50 И id = 6) ПРЕДЕЛ 1

MSSQL

INSERT INTO test (id, сумма) ВЫБЕРИТЕ 6, 50 ОТ теста ГДЕ НЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ ТОП 1 1 ИЗ ТЕСТА ГДЕ сумма> = 50 И id = 6)

Этот запрос работает нормально, если в таблице уже есть хотя бы одна запись. Если таблица пуста, она никогда не будет работать. Такое же поведение в MySQL (5.1) и MSSQL (2005). Я не понимаю почему. У кого-нибудь есть объяснение и способ исправить этот запрос для работы, даже если таблица полностью пуста?

РЕДАКТИРОВАТЬ: Мне это нужно в основном для MySQL ...

ОБНОВЛЕНИЕ: Я начал новый вопрос специально для MySQL: MySQL Проблема с вставкой строки с определенными условиями

Ответы [ 4 ]

2 голосов
/ 10 июня 2011

Сбой, потому что оператор select выбирает значения 6 и 50 в зависимости от количества возвращаемых строк.Поскольку ваша таблица пуста - строки, возвращающие эти значения, не возвращаются.

Измените ее на

 INSERT INTO test (id, amount) SELECT 6, 50 WHERE NOT EXISTS (SELECT TOP 1 1 FROM test WHERE amount >= 50 AND id = 6) 
0 голосов
/ 10 июня 2011

хорошо, это реальный вопрос.Попробуйте это, используя вторую таблицу (# test2):

    -- create a test-table with one entry
SELECT id = 1, amount = 50 
into #TEST

-- create a second test-table with one entry
SELECT id = 1, amount = 50 
into #TEST2

-- see if statement works when table is not empty
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 

-- show content of test-table
select * from #test

-- empty the test table
truncate table #test

INSERT INTO #test (id, amount) SELECT 6, 50 WHERE NOT EXISTS (SELECT TOP 1 1 FROM #test WHERE amount >= 50 AND id = 6)  

-- try to insert a first dataentry
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 
union
SELECT id = 6, amount = 50 
from #test2
where (SELECT C = COUNT(*)  FROM #test) = 0


-- show content of test-table
select * from #test

-- remove Test-table
drop table #test

(Предполагая, что вы знаете таблицы с предшествующим #, это временные таблицы в MS-SQL).

BonyT имеетобъяснил причину уже.

0 голосов
/ 10 июня 2011

Я попробовал это шаг за шагом:

    -- create a test-table with one entry
SELECT id = 1, amount = 50 
into #TEST

-- see if statement works when table is not empty
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 

-- show content of test-table
select * from #test

-- empty the test table
truncate table #test

-- try to insert a first dataentry
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 
union
SELECT id = 6, amount = 50 
where (SELECT C = COUNT(*)  FROM #test WHERE amount >= 50 AND id = 6) = 0

-- show content of test-table
select * from #test

-- remove Test-table
drop table #test

Сначала я попытался воспроизвести поведение, и да, это странно.Союз - думаю, управляет делом с пустым столом, и вуаля, это прекрасно работает.

0 голосов
/ 10 июня 2011

Измените ваш запрос следующим образом:

INSERT INTO test (id, amount) 
SELECT 6, 50 FROM test 
WHERE (SELECT count(*) FROM test WHERE amount >= 50 AND id = 6) = 0 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...