2010-01-20 126 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