FIND_IN_SET()vs IN()

Roc*_*mat 121 mysql

我的数据库中有2个表.一个是订单,一个是公司.

订单具有以下结构:

OrderID     |     attachedCompanyIDs
------------------------------------
   1                     1,2,3
   2                     2,4
Run Code Online (Sandbox Code Playgroud)

公司有这样的结构:

CompanyID      |        name
--------------------------------------
    1                 Company 1
    2                 Another Company
    3                 StackOverflow
    4                 Nothing
Run Code Online (Sandbox Code Playgroud)

要获得订单的公司名称,我可以这样查询:

SELECT name FROM orders,company
WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)
Run Code Online (Sandbox Code Playgroud)

该查询工作正常,但以下查询没有.

SELECT name FROM orders,company
WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)
Run Code Online (Sandbox Code Playgroud)

为什么第一个查询有效但第二个查询无效?

第一个查询返回:

name
---------------
Company 1
Another Company
StackOverflow
Run Code Online (Sandbox Code Playgroud)

第二个查询只返回:

name
---------------
Company 1
Run Code Online (Sandbox Code Playgroud)

为什么这样,为什么第一个查询返回所有公司,但第二个查询只返回第一个查询?

Qua*_*noi 97

SELECT  name
FROM    orders,company
WHERE   orderID = 1
        AND companyID IN (attachedCompanyIDs)
Run Code Online (Sandbox Code Playgroud)

attachedCompanyIDs是一个标量值,它被转换为INT(类型companyID).

演员表仅返回第一个非数字(在您的情况下为逗号)的数字.

从而,

companyID IN ('1,2,3') ? companyID IN (CAST('1,2,3' AS INT)) ? companyID IN (1)
Run Code Online (Sandbox Code Playgroud)

PostgreSQL,您可以将字符串转换为数组(或首先将其存储为数组):

SELECT  name
FROM    orders
JOIN    company
ON      companyID = ANY (('{' | attachedCompanyIDs | '}')::INT[])
WHERE   orderID = 1
Run Code Online (Sandbox Code Playgroud)

这甚至会使用索引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)
Run Code Online (Sandbox Code Playgroud)

  • 竖起(y)表示MySQL中的"10件事(不会按预期工作)" (8认同)
  • 感谢您的解释.我没有意识到attachCompanyIDs字段被转换为INT.在MySQL中有没有办法解决这个问题?`FIND_IN_SET`有效,但不使用索引,并且在Company表中有大量信息可能会很慢. (3认同)

Hai*_*vgi 13

attachedCompanyIDs是一个大字符串,所以mysql尝试在其中找到公司的强制转换为整数

当你在哪里使用

所以如果comapnyid = 1:

companyID IN ('1,2,3')
Run Code Online (Sandbox Code Playgroud)

这是真的

但如果数字1不在第一位

 companyID IN ('2,3,1')
Run Code Online (Sandbox Code Playgroud)

它的回报是假的


小智 5

获取所有相关公司名称,而不是基于特定 ID。

SELECT 
    (SELECT GROUP_CONCAT(cmp.cmpny_name) 
    FROM company cmp 
    WHERE FIND_IN_SET(cmp.CompanyID, odr.attachedCompanyIDs)
    ) AS COMPANIES
FROM orders odr
Run Code Online (Sandbox Code Playgroud)