我的数据库中有2个表。一个是订单,一个是公司。
订单具有以下结构:
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
为什么这样,为什么第一个查询会返回所有公司,但第二个查询只返回第一个查询?
答案 0 :(得分:91)
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
):
<强>更新强>
如果逗号分隔列表中的值数量有一些合理的限制(例如,不超过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)
答案 1 :(得分:13)
attachedCompanyIDs是一个大字符串,所以mysql尝试在其中找到公司将其强制转换为整数
当你在
中使用时所以如果comapnyid = 1:
companyID IN ('1,2,3')
这是真的
但如果数字1不在第一位
companyID IN ('2,3,1')
返回false
答案 2 :(得分:3)
获取所有相关公司名称,而不是基于特定ID。
SELECT
(SELECT GROUP_CONCAT(cmp.cmpny_name)
FROM company cmp
WHERE FIND_IN_SET(cmp.CompanyID, odr.attachedCompanyIDs)
) AS COMPANIES
FROM orders odr
答案 3 :(得分:1)
因为第二个查询正在查找id为1 OR 2 OR 3的行, 第一个查询正在寻找一个以逗号分隔的值存在于companyID
中这里的另一个问题是你没有加入你所在位置的公共密钥表,所以你会得到一个行变异= count(table1)* count(table2);
我的答案的第2部分确实存在您的问题。 (使用您的第二个查询)
答案 4 :(得分:-1)
让我解释何时使用FIND_IN_SET和何时使用IN。
让我们选择表A,其中包含名为&#34; aid&#34;,&#34; aname&#34;的列。 让我们选择表B,其中包含名为&#34; bid&#34;,&#34; bname&#34;,&#34; aids&#34;。
现在表A和表B中有虚拟值,如下所示。
援助aname
1 Apple
2香蕉
3芒果
bid bname aids
1 Apple 1,2
2香蕉2,1
3芒果3,1,2
enter code here
案例1:如果你想从表b中获取那些在aids列中有1个值的记录,那么你必须使用FIND_IN_SET。
查询:选择*来自A JOIN B ON FIND_IN_SET(A.aid,b.aids),其中A.aid = 1;
案例2:如果您想从表a中获取那些在援助列中存在1 OR 2 OR 3值的记录,那么您必须使用IN。
查询:从A JOIN B ON A.aid IN(b.aids)中选择*;
现在通过mysql查询了解你所需要的东西。
答案 5 :(得分:-2)
SELECT o.*, GROUP_CONCAT(c.name) FROM Orders AS o , Company.c
WHERE FIND_IN_SET(c.CompanyID , o.attachedCompanyIDs) GROUP BY o.attachedCompanyIDs