find_in_set ejemplo mysql

mysql - ejemplo - FIND_IN_SET() vs IN()



in mysql (6)

Tengo 2 tablas en mi base de datos. Una es para pedidos y otra para empresas.

Pedidos tiene esta estructura:

OrderID | attachedCompanyIDs ------------------------------------ 1 1,2,3 2 2,4

Y la compañía tiene esta estructura:

CompanyID | name -------------------------------------- 1 Company 1 2 Another Company 3 StackOverflow 4 Nothing

Para obtener los nombres de las compañías de una orden, puedo hacer una consulta como tal:

SELECT name FROM orders,company WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)

Esa consulta funciona bien, pero la siguiente consulta no.

SELECT name FROM orders,company WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)

¿Por qué funciona la primera consulta pero no la segunda?

La primera consulta regresa:

name --------------- Company 1 Another Company StackOverflow

La segunda consulta solo devuelve:

name --------------- Company 1

¿Por qué es esto? ¿Por qué la primera consulta devuelve todas las compañías, pero la segunda consulta solo devuelve la primera?


Para obtener el nombre de todas las empresas relacionadas, no se basa en un Id específico.

SELECT (SELECT GROUP_CONCAT(cmp.cmpny_name) FROM company cmp WHERE FIND_IN_SET(cmp.CompanyID, odr.attachedCompanyIDs) ) AS COMPANIES FROM orders odr


Permítanme explicar cuándo usar FIND_IN_SET y cuándo usar IN.

Tomemos la tabla A que tiene columnas llamadas "aid", "aname". Tomemos la tabla B que tiene columnas llamadas "bid", "bname", "aid".

Ahora hay valores ficticios en la Tabla A y la Tabla B como se muestra a continuación.

Tabla A

ayuda aname

1 Apple

2 Plátano

3 Mango

Tabla B

bid bname aid

1 manzana 1,2

2 Plátano 2,1

3 Mango 3,1,2

enter code here

Caso 1: si desea obtener esos registros de la tabla b que tiene 1 valor presente en las columnas de ayudas, entonces debe usar FIND_IN_SET.

Consulta: seleccionar * de A UNIR B EN FIND_IN_SET (A.aid, b.aids) donde A.aid = 1;

Caso2: si desea obtener los registros de la tabla a que tiene 1 OR 2 O 3 valor presente en las columnas de ayuda, entonces debe usar IN.

Consulta: selecciona * de A UNE B EN A.aid IN (b.aids);

Ahora aquí hasta usted que lo que necesita a través de la consulta mysql.


attachedCompanyIDs es una gran cadena, por lo que tratar de encontrar la empresa en este mysql es un número entero

cuando usas donde en

entonces si comapnyid = 1:

companyID IN (''1,2,3'')

esto es verdadero retorno

pero si el número 1 no está en primer lugar

companyID IN (''2,3,1'')

su devolución es falsa


porque la segunda consulta busca filas con el id 1 OR 2 OR 3, la primera consulta busca uno de los valores delimitados por comas para existir en companyID,

y otro problema aquí es que no está uniendo las tablas en una clave común en su lugar, de modo que obtendrá una mutación de filas que = cuente (tabla1) * recuento (tabla2);

Tu problema realmente existe con la parte 2 de mi respuesta. (con su segunda consulta)


SELECT name FROM orders,company WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)

attachedCompanyIDs es un valor escalar que se convierte en INT (tipo de companyID de la companyID ).

El elenco solo devuelve números hasta el primer dígito que no sea (una coma en tu caso).

Así,

companyID IN (''1,2,3'') ≡ companyID IN (CAST(''1,2,3'' AS INT)) ≡ companyID IN (1)

En PostgreSQL , podría convertir la cadena en una matriz (o almacenarla como una matriz en primer lugar):

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

y esto incluso usaría un índice en companyID .

Desafortunadamente, esto no funciona en MySQL ya que este último no admite matrices.

Puede encontrar interesante este artículo (vea el n #2 ):

Actualizar:

Si hay un límite razonable en el número de valores en las listas separadas por comas (por ejemplo, no más de 5 ), entonces puede intentar usar esta consulta:

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)


SELECT o.*, GROUP_CONCAT(c.name) FROM Orders AS o , Company.c WHERE FIND_IN_SET(c.CompanyID , o.attachedCompanyIDs) GROUP BY o.attachedCompanyIDs