FIND_IN_SET() vs IN() : dévoilement de l'énigme des requêtes
Dans le domaine des requêtes de bases de données, comprendre les nuances entre les différentes fonctions est crucial. Une telle distinction apparaît lors de la comparaison de FIND_IN_SET() et IN(), en particulier lors de l'interrogation de valeurs stockées sous forme de chaînes séparées par des virgules.
L'écart de requête
Considérez deux tableaux : "commandes" avec une colonne "attachedCompanyIDs" contenant des identifiants d'entreprise séparés par des virgules et "company" avec une colonne "companyID" et les noms de sociétés correspondants. La requête suivante récupère efficacement les noms de sociétés associés à une commande à l'aide de FIND_IN_SET() :
SELECT name FROM orders, company WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)
Cependant, une requête similaire utilisant IN() donne des résultats inattendus :
SELECT name FROM orders, company WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)
Le piège caché
La cause première réside dans la façon dont MySQL gère les valeurs séparées par des virgules lors de la conversion des attachmentCompanyIDs en un entier. Le casting tronque les nombres au premier chiffre non-chiffre, réduisant ainsi la chaîne à la première valeur séparée par des virgules.
Par exemple, avec attachmentCompanyIDs défini sur « 1,2,3 », la requête IN() est incorrecte. devient :
companyID IN (1)
Cela explique pourquoi la requête IN() ne renvoie que le premier nom de l'entreprise, tandis que FIND_IN_SET() renvoie tous trois.
Surmonter les limitations
Pour résoudre ce problème, envisagez des approches alternatives qui gèrent de manière appropriée les chaînes séparées par des virgules. Dans PostgreSQL, les tableaux peuvent être utilisés :
SELECT name FROM orders JOIN company ON companyID = ANY(('{' || attachedCompanyIDs || '}')::INT[]) WHERE orderID = 1
Malheureusement, les tableaux ne sont pas pris en charge dans MySQL. Pour un nombre limité de valeurs (disons, moins de 5), une solution de contournement est possible en utilisant la jointure croisée et la manipulation de chaînes :
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)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!