2010-01-20 124 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的错误,还是由于某种原因的预期行为?

更新:

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

如果你在子查询中用'user_id'替换'id',它是否会返回一个错误的'user_id'(既不是'NULL'也不是'9917')? – Quassnoi 2010-01-20 14:36:43

+0

如果我用user_id替换id,它会给我一个错误的user_id(它给我的user_id属于最初列出的不正确的id)。 – Blake 2010-01-20 14:40:25

+0

你可以发布SHOW CREATE TABLE users_value和EXPLAIN SELECT ...查询的结果吗? – Quassnoi 2010-01-20 14:48:34

回答

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上进行筛选,因此子查询可以将值返回到主查询定义的范围之外。

更新:

这绝对是MySQL的错误。

最可能的原因是为UsersValues选择的访问路径是index_intersect

这将从两个索引中选择合适的范围并构建它们的交集。

由于该错误,在相交完成前评估相关子查询,这就是为什么您使用正确的another_id而不是user_id得到结果。

能否请您检查,当你用力的UsersValuesPRIMARY扫描问题仍然存在:

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_idanother_id创建(user_id, another_id, 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上的索引时,它按预期工作。当我添加索引时,它返回无效的ID。 – Blake 2010-01-20 15:06:25

+0

这可能是一个真正的bug。你可以发布'MySQL'版本,'SHOW CREATE TABLE'和'EXPLAIN'吗? – Quassnoi 2010-01-20 15:09:19

+0

'@ Blake':当然,阿尔法绝对是这里的原因。你可以发布'EXPLAIN'的结果吗?如果您愿意,最好将它作为您帖子的更新而不是评论。 – Quassnoi 2010-01-20 15:21:13

0

你尝试运行子查询只看到如果你得到正确的结果?你能告诉我们你的users_values表的模式吗?

此外,尝试更换您在您的子查询SELECT id通过SELECT ParentUsersValue.id

+0

当我只运行子查询时,填充3个适当的ID,它返回0行(因为它应该)。 放入ParentUsersValue.id没有任何区别。 模式是: id是int(11),自动编号,不可为空。 user_id和another_id都是int(11),默认为null。 myvalue是一个双精度型,默认为null。创建并修改的 都是日期时间,默认为空。 – Blake 2010-01-20 14:49:01