2010-01-20 6 views
1

У меня есть следующий запрос MySQL/подзапрос:Подзапрос MySQL возвращает неверный результат?

SELECT id, user_id, another_id, myvalue, created, modified, 
(
    SELECT id 
    FROM users_values AS ParentUsersValue 
    WHERE ParentUsersValue.user_id = UsersValue.user_id 
    AND ParentUsersValue.another_id = UsersValue.another_id 
    AND ParentUsersValue.id < UsersValue.id 
    ORDER BY id DESC 
    LIMIT 1 
) AS old_id 

FROM users_values AS UsersValue 
WHERE created >= '2009-12-20' 
AND created <= '2010-01-21' 
AND user_id = 9917 
AND another_id = 23 

Учитывая перечисленные критерии, результат подзапроса (old_id) должен быть нулевым (совпадений не будет найдено в моей таблице). Вместо того, чтобы MySQL возвращал значение null, он просто отбрасывает предложение WHERE ParentUsersValue.user_id = UsersValue.user_id и выбирает первое значение, соответствующее двум другим полям. Это ошибка MySQL, или это почему-то ожидаемое поведение?

Update:

CREATE TABLE users_values (
    id int(11) NOT NULL AUTO_INCREMENT, 
    user_id int(11) DEFAULT NULL, 
    another_id int(11) DEFAULT NULL, 
    myvalue double DEFAULT NULL, 
    created datetime DEFAULT NULL, 
    modified datetime DEFAULT NULL, 
    PRIMARY KEY (id) 
) ENGINE=InnoDB AUTO_INCREMENT=2801 DEFAULT CHARSET=latin1 

EXPLAIN EXTENDED:

id select_type table type possible_keys key key_len ref rows filtered Extra 
1 PRIMARY UsersValue index_merge user_id,another_id user_id,another_id 5,5 NULL 1 100.00 Using intersect(user_id,another_id); Using where 
2 DEPENDENT SUBQUERY ParentUsersValue index PRIMARY,user_id,another_id PRIMARY 4 NULL 1 100.00 Using where 

EXPLAIN EXTENDED Warning 1003:

select `mydb`.`UsersValue`.`id` AS `id`,`mydb`.`UsersValue`.`user_id` AS `user_id`,`mydb`.`UsersValue`.`another_id` AS `another_id`,`mydb`.`UsersValue`.`myvalue` AS `myvalue`,`mydb`.`UsersValue`.`created` AS `created`,`mydb`.`UsersValue`.`modified` AS `modified`,(select `mydb`.`ParentUsersValue`.`id` AS `id` from `mydb`.`users_values` `ParentUsersValue` where ((`mydb`.`ParentUsersValue`.`user_id` = `mydb`.`UsersValue`.`user_id`) and (`mydb`.`ParentUsersValue`.`another_id` = `mydb`.`UsersValue`.`another_id`) and (`mydb`.`ParentUsersValue`.`id` < `mydb`.`UsersValue`.`id`)) order by `mydb`.`ParentUsersValue`.`id` desc limit 1) AS `old_id` from `mydb`.`users_values` `UsersValue` where ((`mydb`.`UsersValue`.`another_id` = 23) and (`mydb`.`UsersValue`.`user_id` = 9917) and (`mydb`.`UsersValue`.`created` >= '2009-12-20') and (`mydb`.`UsersValue`.`created` <= '2010-01-21')) 
+0

Если вы замените 'id'' user_id' в подзапросе, вернет ли он неправильный 'user_id' (ни' NULL', ни '9917')? – Quassnoi

+0

Если я заменю id на user_id, это дает мне неправильный user_id (user_id, который он мне дает, относится к некорректному идентификатору, указанному вначале). – Blake

+0

Не могли бы вы вывести результаты запроса 'SHOW CREATE TABLE users_value' и' EXPLAIN SELECT ... 'для запроса? – Quassnoi

ответ

0

Это возвращает правильные результаты (NULL) для меня:

CREATE TABLE users_values (id INT NOT NULL PRIMARY KEY, user_id INT NOT NULL, another_id INT NOT NULL, created DATETIME NOT NULL); 

INSERT 
INTO users_values VALUES (1, 9917, 23, '2010-01-01'); 

SELECT *, 
     (
     SELECT id 
     FROM users_values AS ParentUsersValue 
     WHERE ParentUsersValue.user_id = UsersValue.user_id 
       AND ParentUsersValue.another_id = UsersValue.another_id 
       AND ParentUsersValue.id < UsersValue.id 
     ORDER BY id 
       DESC 
     LIMIT 1 
     ) AS old_id 
FROM users_values AS UsersValue 
WHERE created >= '2009-12-20' 
     AND created <= '2010-01-21' 
     AND user_id = 9917 
     AND another_id = 23 

Не могли бы вы выполнить этот запрос:

SELECT COUNT(*) 
FROM users_values AS UsersValue 
WHERE user_id = 9917 
     AND another_id = 23 

и убедитесь, что он возвращает 1?

Обратите внимание, что ваш подзапрос не фильтрует по created, поэтому подзапрос может возвращать значения из диапазона, определяемого основным запросом.

Update:

Это, безусловно, ошибка в MySQL.

Скорее всего, причина в том, что путь доступа, выбранный для UsersValues, составляет index_intersect.

Это позволяет выбрать подходящие диапазоны из обоих индексов и построить их пересечение.

Из-за ошибки зависимый подзапрос оценивается до завершения пересечения, поэтому вы получаете результаты с правильным another_id, но неправильно user_id.

Не могли бы вы, пожалуйста, проверьте, сохраняется ли проблема, когда вы вынуждаете PRIMARY сканирование на UsersValues:

SELECT *, 
     (
     SELECT id 
     FROM users_values AS ParentUsersValue 
     WHERE ParentUsersValue.user_id = UsersValue.user_id 
       AND ParentUsersValue.another_id = UsersValue.another_id 
       AND ParentUsersValue.id < UsersValue.id 
     ORDER BY id 
       DESC 
     LIMIT 1 
     ) AS old_id 
FROM users_values AS UsersValue FORCE INDEX (PRIMARY) 
WHERE created >= '2009-12-20' 
     AND created <= '2010-01-21' 
     AND user_id = 9917 
     AND another_id = 23 

Кроме того, для этого запроса вы должны создать составной индекс на (user_id, another_id, id), а не два отдельных индексов на user_id и another_id ,

Создание индекса и переписать запрос немного:

SELECT *, 
     (
     SELECT id 
     FROM users_values AS ParentUsersValue 
     WHERE ParentUsersValue.user_id = UsersValue.user_id 
       AND ParentUsersValue.another_id = UsersValue.another_id 
       AND ParentUsersValue.id < UsersValue.id 
     ORDER BY 
       user_id DESC, another_id DESC, id DESC 
     LIMIT 1 
     ) AS old_id 
FROM users_values AS UsersValue 
WHERE created >= '2009-12-20' 
     AND created <= '2010-01-21' 
     AND user_id = 9917 
     AND another_id = 23 

В user_id DESC, another_id DESC положении логически лишний, но они будут делать индекс будет использоваться для заказа.

+0

Запрос счет возвращает 1. Я могу по-прежнему опубликовать SHOW CREATE TABLE, если вы хотите, но я только что обнаружил, что заставляет его перестать работать. Когда я удаляю индекс на user_id и another_id, он работает так, как ожидалось. Когда я добавляю индекс назад, он возвращает неверный идентификатор. – Blake

+0

Это может быть действительно ошибка. Не могли бы вы разместить версию 'MySQL',' SHOW CREATE TABLE' и 'EXPLAIN'? – Quassnoi

+0

'@ Blake': Конечно, альфа определенно является причиной здесь. Не могли бы вы опубликовать результаты 'EXPLAIN'? Если хотите, лучше сделайте это как обновление своего сообщения, а не как комментарий. – Quassnoi

0

ли вы попробовать запустить подзапрос только чтобы увидеть, если вы получаете правильные результаты? Не могли бы вы показать нам схему для вашей таблицы ?

Кроме того, попробуйте заменить ваш SELECT id в вашем подзапрос по SELECT ParentUsersValue.id

+0

Когда я запускаю только подзапрос, заполняя 3 соответствующих идентификатора, он возвращает 0 строк (как и должно). Помещение ParentUsersValue.id не имеет значения. Схема: id is int (11), autonumber, не может быть недействительным. user_id и another_id оба являются int (11), значение по умолчанию null. myvalue - это двойной, по умолчанию null. Созданы и изменены как datetime, default null. – Blake

Смежные вопросы