我有这张桌子:
CREATE TABLE `page` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`sortorder` SMALLINT(5) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
这是我的数据:
id sortorder
1 0
2 1
我想运行此查询:
select id from page where (sortorder = (select sortorder from page where id = 1) - 1)
(我试图找到上一页,即具有较低排序顺序的页面,如果它存在。如果不存在,我想要一个空的结果集。)
我从mysql收到的错误:
SQL Error (1690): BIGINT UNSIGNED value is out of range in '((select '0' from `page` where 1) - 1)'
更具体地说,当我跑步时:
select sortorder - 1 from page where id = 1
我明白了:
SQL Error (1690): BIGINT UNSIGNED value is out of range in '('0' - 1)'
我该怎么做才能防止这种情况发生?
答案 0 :(得分:1)
尝试在' NO_UNSIGNED_SUBTRACTION'
中设置您的SQL模式SET sql_mode = 'NO_UNSIGNED_SUBTRACTION'
答案 1 :(得分:1)
我通常使用JOIN
来实现此目标,因为它们可以比子查询更好地进行优化。此查询应该产生与您相同的结果,但可能更快:
SELECT pp.*
FROM page cp # 'cp' from 'current page'
LEFT JOIN page pp # 'pp' from 'previous page'
ON pp.sortorder = cp.sortorder - 1
WHERE cp.id = 1
不幸的是,它失败了,但-1
UNSIGNED
不是JOIN
的错误消息。
可以通过将 ON pp.sortorder + 1 = cp.sortorder
条件写为:
-1
我将+1
移到了等号的另一边,然后转向-1
。
您还可以使用相同的技巧修复原始查询:将+1
移动到等号的另一侧;这样它变成select id
from page
where (sortorder + 1 = (select sortorder from page where id = 1)
并且不再有任何错误:
sortorder
现在两个查询的问题在于,由于列WHERE
上没有索引,因此MySQL必须逐个检查所有行,直到找到与ON
匹配的行(或{ {1}})条件,这需要花费大量时间并使用大量资源。
幸运的是,可以通过在列sortorder
上添加索引来轻松修复此问题:
ALTER TABLE page ADD INDEX(sortorder);
现在可以使用两个查询。使用JOIN
(和ON
条件+1
)的那个稍快一些。
当不满足条件时,原始查询不返回任何行。 JOIN
查询返回一行NULL
秒。通过将LEFT JOIN
替换为INNER JOIN
,可以将其修改为不返回任何行。
您可以通过从UNSIGNED
列移除sortorder
属性来完全绕过错误(并使用这些查询的任何版本):
ALTER TABLE page
CHANGE COLUMN `sortorder` `sortorder` SMALLINT(5) UNSIGNED NOT NULL;