FIND_IN_SET()vs IN()
我有两个表在我的数据库。 一个是订单,一个是公司。
订单有这样的结构:
OrderID | attachedCompanyIDs ------------------------------------ 1 1,2,3 2 2,4
公司有这样的结构:
CompanyID | name -------------------------------------- 1 Company 1 2 Another Company 3 StackOverflow 4 Nothing
要获取订单的公司名称,我可以这样查询:
SELECT name FROM orders,company WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)
该查询工作正常,但以下查询不。
SELECT name FROM orders,company WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)
为什么第一个查询工作,而不是第二个?
第一个查询返回:
name --------------- Company 1 Another Company StackOverflow
第二个查询只返回:
name --------------- Company 1
为什么这是为什么第一个查询返回所有的公司,但第二个查询只返回第一个查询?
SELECT name FROM orders,company WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)
attachedCompanyIDs
是投入INT
( companyID
类型)的标量值。
演员只返回数字,直到第一个非数字(在你的情况下逗号)。
从而,
companyID IN ('1,2,3') ≡ companyID IN (CAST('1,2,3' AS INT)) ≡ companyID IN (1)
在PostgreSQL
,您可以将字符串转换为数组(或者将其存储为数组):
SELECT name FROM orders JOIN company ON companyID = ANY (('{' | attachedCompanyIDs | '}')::INT[]) WHERE orderID = 1
这甚至会在companyID
上使用索引。
不幸的是,这在MySQL
不起作用,因为后者不支持数组。
你可能会觉得这篇文章很有趣(见#2
):
- MySQL中的10件事情(这不会按预期工作)
更新:
如果在逗号分隔列表中的值的数量有一些合理的限制(比如不超过5
),那么你可以尝试使用这个查询:
SELECT name FROM orders CROSS JOIN ( SELECT 1 AS pos UNION ALL SELECT 2 AS pos UNION ALL SELECT 3 AS pos UNION ALL SELECT 4 AS pos UNION ALL SELECT 5 AS pos ) q JOIN company ON companyID = CAST(NULLIF(SUBSTRING_INDEX(attachedCompanyIDs, ',', -pos), SUBSTRING_INDEX(attachedCompanyIDs, ',', 1 - pos)) AS UNSIGNED)
attachedCompanyIDs是一个大字符串,所以mysql试图在这里找到公司,把它转换成整数
当你在哪里使用
所以如果comapnyid = 1:
companyID IN ('1,2,3')
这是真的
但是如果数字1不在第一位
companyID IN ('2,3,1')
其返回错误
要获得所有相关的公司名称,不要根据特定的ID。
SELECT (SELECT GROUP_CONCAT(cmp.cmpny_name) FROM company cmp WHERE FIND_IN_SET(cmp.CompanyID, odr.attachedCompanyIDs) ) AS COMPANIES FROM orders odr
由于第二个查询正在查找ID为1或2或3的行,因此第一个查询正在查找companyID中存在的逗号分隔值之一,
这里的另一个问题是你没有加入一个共同的关键在你的位置,所以你会得到= count(table1)* count(table2)行的突变;
你的问题真的存在于我的答案的第二部分。 (用你的第二个查询)
让我来解释何时使用FIND_IN_SET和何时使用IN。
我们来看一个名为“aid”,“aname”的列表。 我们来看一下名为“bid”,“bname”,“aids”的列表B。
现在在表A和表B中有如下的虚拟值。
表A
援助aname
1苹果
2香蕉
3芒果
表B
投标bname艾滋病
1苹果1,2
2香蕉2,1
3芒果3,1,2
enter code here
情况1:如果你想从表b中得到这些记录,这些记录在艾滋病列中有1个值,那么你必须使用FIND_IN_SET。
查询:select * from A JOIN B ON FIND_IN_SET(A.aid,b.aids)where A.aid = 1;
情况2:如果你想从表格a中获得那些1或2或3的数值出现在援助栏中的记录,那么你必须使用IN。
查询:select * from A JOIN B ON A.aid IN(b.aids);
现在在这里,你通过mysql查询你需要什么。
SELECT o.*, GROUP_CONCAT(c.name) FROM Orders AS o , Company.c WHERE FIND_IN_SET(c.CompanyID , o.attachedCompanyIDs) GROUP BY o.attachedCompanyIDs