MySQL(错误子查询返回超过1行)-但我期望超过1行
我希望有多行:MySQL(错误子查询返回超过1行)-但我期望超过1行,mysql,Mysql,我希望有多行: SELECT * FROM OWNER WHERE OWNER.ID IN( ( SELECT ID FROM OWNER WHERE LAST_NAME LIKE '%pickles%' OR FIRST_NAME LIKE '%pickles%'
SELECT * FROM OWNER
WHERE OWNER.ID IN(
(
SELECT
ID
FROM OWNER
WHERE
LAST_NAME LIKE '%pickles%'
OR FIRST_NAME LIKE '%pickles%'
),
(
SELECT
OWNER_ID
FROM VISITOR
WHERE
NAME LIKE '%pickles%'
OR SIZE LIKE '%pickles%'
),
(
SELECT
OWNER_ID
FROM BOARDING
WHERE
COMMENTS LIKE '%pickles%'
OR PERSONAL_BELONGINGS LIKE '%pickles%'
)
)
第二个子查询
FROM VISITOR
WHERE
NAME LIKE '%pickles%'
正在导致错误。
但我希望返回多行?
它应该从找到的行返回多个ID。
那么,为什么它会有这些多行的问题呢
谢谢。我想您正在寻找一个
工会
:
SELECT * FROM OWNER
WHERE OWNER.ID IN(
SELECT ID
FROM OWNER
WHERE LAST_NAME LIKE '%pickles%'
OR FIRST_NAME LIKE '%pickles%'
UNION
SELECT OWNER_ID
FROM VISITOR
WHERE NAME LIKE '%pickles%'
OR SIZE LIKE '%pickles%'
UNION
SELECT OWNER_ID
FROM BOARDING
WHERE COMMENTS LIKE '%pickles%'
OR PERSONAL_BELONGINGS LIKE '%pickles%'
)
说明:
您的子查询在3个列中返回结果,如:
ID OWNER_ID OWNER_ID1
-----------------------------------------------------------------
OWNER_Table_ids Visitor_Table_ids Boarding_Table_ids
使用UNION
,它将返回如下结果:
ID
-------------------
OWNER_table_ids
Visitor_table_ids
Boarding_table_ids
错误“Subquery返回的值超过1”仅仅意味着“超过1列”。接受的答案确实提供了一个有效的解决方案,但对现有查询为什么不能按书面方式工作的解释不正确 子查询有多种类型,返回多种类型的结果 在您的查询中:
WHERE expr IN (( /* subq 1 */ ), ( /* subq 2 */ ), ( /* subq 3 */ ))
…相当于
WHERE expr = ( /* subq 1 */ )
OR expr = ( /* subq 2 */ )
OR expr = ( /* subq 3 */ )
这是而且只能是三个相等比较。以这种方式使用的子查询必须在标量上下文中进行解释。。。而标量子查询只能返回一行或零行,因为子查询的结果将用作一个索引。对于服务器来说,以其他方式解释它是不合逻辑的:您可以使用相等比较将单个值与两个或更多值进行比较吗?没有
您的查询并不像看上去那样,要求服务器构建子查询的所有结果集,并测试OWNER.ID是否在()中IN
该集。您的查询要求服务器构建一个最多包含三个标量值的集合,每个子查询一个标量值,并确定OWNER.ID是否是()中的
那个(可能小得多)集合。这些子查询中的任何一个都返回多行,这使得查询无效。你很幸运,它已经不起作用了。如果您选择了只匹配一行的数据,它现在就可以工作了,但是当您有更多匹配时,它就坏了
ERROR 1242 (21000): Subquery returns more than 1 row
如果您(人为地)将LIMIT 1
添加到三个子查询中的每一个子查询中,您会发现该查询确实有效,这说明了我的观点。结果将是不完整的,但查询是有效的,这推翻了错误是关于“列”的断言。。。但是,正如所写的,它是,而且只能是一组标量
使用UNION
进行重构可以向服务器阐明您的意图
请注意,如果错误是关于列的断言是正确的,则消息将不同:
ERROR 1241 (21000): Operand should contain 1 column(s)
现在,在解释了错误的实际原因之后,我还将提出另一种解决方案。如果你还没有,你应该在访客和登机牌上都有一个(所有者ID)索引。此解决方案与UNION
解决方案之间的性能可能会有所不同,具体取决于各个表中数据的组成以及MySQL服务器的版本。这两种解决方案都不是最优的,因为类似于比较的中开头的需要完整地读取表或至少一个包含列(如果有)的索引。这是全表扫描或全索引扫描,“扫描”是指逐行扫描。结尾%
很好;开头的%
成本很高,因为它从列的左侧取消了模式的锚定,索引就是在左侧执行工作的。如果可以,在应用程序允许的任何地方删除它,以获得更好的性能,并为搜索列编制索引;如果您无法删除前导的%
,至少要了解这是您将看到的性能的一个因素。这是B树索引的一般限制,而不是MySQL。你可能最终还想调查一下
请注意,存在(选择*…)
不存在。特别值得注意的是,*
只是一种惯例。您可以说SELECT 1
或SELECT TRUE
,这并不重要,因为实际上没有选择任何数据,而且EXISTS()
没有返回任何内容,除了TRUE
--子查询匹配目标表中的一行或多行--或者FALSE
--它没有。请注意,这些查询引用外部查询中的一个值o.ID,因此
在这里,我们检查owner表中的匹配条件,然后,如果需要,我们检查VISITOR或BOARDING中是否存在匹配条件的行。如果一个名为“猫”的女人有一只名为“猫”的狗,而你正在搜索“猫”,那么我们将在OWNER中找到它,优化器可能能够避免搜索该用户的其他两个表,因为我们已经知道她是匹配的,无论出于何种原因
另请参见:非常感谢@Ranging Bull。我认为个人选择会结合id。为什么多个ID被视为错误?它是想说它找到了重复项吗?@Kreeverp:当您在操作符中使用
时,子查询必须只返回1列进行查找。使用您的查询,它将返回3列。这就是错误所说的。子查询返回的值超过1表示“超过1列”。错误报告的是“行”而不是列,这有点令人困惑?@kreevp:为了更好地理解:这里一行表示单个值列表。
SELECT o.*
FROM OWNER o
WHERE o.LAST_NAME LIKE '%pickles%'
OR o.FIRST_NAME LIKE '%pickles%'
OR EXISTS(SELECT *
FROM VISITOR v
WHERE v.OWNER_ID = o.ID
AND (v.NAME LIKE '%pickles%' OR v.SIZE LIKE '%pickles%')
)
OR EXISTS(SELECT *
FROM BOARDING b
WHERE b.OWNER_ID = o.ID
AND (COMMENTS LIKE '%pickles%' OR PERSONAL_BELONGINGS LIKE '%pickles%')
);