Ajouter une liste à un paramètre mysql

j'ai cette question au sujet du paramètre MySQL du connecteur .NET.

j'ai cette requête:

SELECT * FROM table WHERE id IN (@parameter)

Et la MySqlParameter est:

intArray = new List<int>(){1,2,3,4};

...connection.Command.Parameters.AddWithValue("parameter", intArray);

est-Ce possible? Est - il possible de passer un tableau de int à un seul MySqlParameter? L'autre solution sera de convertir le tableau de int en une chaîne telle que "1,2,3,4", mais ceci, quand je le passe au MySqlParameter et ceci est reconnu comme une chaîne, il met dans la requête sql comme "1,2,3,4" et ce ne retournez pas les valeurs attendues.

<!-Mise à jour: il semble que l'équipe du connecteur mysql devrait travailler un peu plus dur.

17
demandé sur Stecya 2011-04-15 23:18:39

8 réponses

quand je le passe au MySqlParameter et que ceci est reconnu comme une chaîne, il met dans la requête sql comme "1\,2\,3\,4" et cela ne renvoie pas les valeurs attendues.

je suis tombé sur cette dernière nuit. J'ai trouvé que FIND_IN_SET fonctionne ici:

SELECT * FROM table WHERE FIND_IN_SET(id, @parameter) != 0
...
intArray = new List<int>(){1,2,3,4};
conn.Command.Parameters.AddWithValue("parameter", string.Join(",", intArray));

apparemment cela a quelques limites de longueur (j'ai trouvé votre post à la recherche d'une solution alternative), mais cela peut fonctionner pour vous.

15
répondu Mud 2011-04-19 20:34:33

les paramètres ne fonctionnent pas avec IN. J'ai toujours intégré des choses comme une chaîne de caractères dans la requête elle-même. Bien que cela soit généralement considéré comme une mauvaise forme parce que L'injection SQL, si vous construisez la requête à partir d'une liste numérique fortement dactylographiée, alors il ne devrait y avoir aucune possibilité d'aucune entrée externe la corrompant d'une manière significative.

5
répondu Jamie Treworgy 2011-04-15 19:22:54

vous allez devoir itérer sur votre tableau et créer la liste vous-même

// no parameters
var sb = new StringBuilder();
for(int i=0;i<intArray.Length;i++)
{
    sb.Append(intArray[i] + ",");// no SQL injection they are numbers
}
if (sb.Length>0) {sb.Length-=1;}
string sql = "SELECT * FROM table WHERE id IN (" + sb.ToString() + ")";

mise à jour: après avoir réfléchi à ce sujet, je vais revenir à ma réponse originale (ci-dessous) qui est d'utiliser des paramètres. Les Optimisations des requêtes construites et tout ce que le moteur de base de données peut rassembler dépendent de vous.

// no parameters
var sb = new StringBuilder();
for(int i=0;i<intArray.Length;i++)
{
    sb.AppendFormat("p{0},", i);// no SQL injection they are numbers
    connection.Command.Parameters.AddWithValue("p"+i, intArray[i]);
}
if (sb.Length>0) {sb.Length-=1;}
string sql = "SELECT * FROM table WHERE id IN (" + sb.ToString() + ")";
3
répondu Adam Straughan 2011-04-16 08:39:26

Vous avez quelques options ici (dans l'ordre de préférence):

  1. utilisez une base de données qui supporte table des paramètres. C'est le moyen pour obtenir la syntaxe exacte que vous souhaitez.
  2. les données doivent provenir de quelque part: soit de votre base de données, soit de l'action de l'utilisateur, soit de la source générée par la machine.

    • si les données sont déjà dans votre base de données, utilisez une sous-requête à la place.
    • pour les autres données générées par la machine, utilisez BULK INSERT, SqlBulkCopy, ou les outils d'importation en vrac préférés de votre base de données.
    • si elle est créée par l'utilisateur, ajoutez-la à une table séparée sur chaque action de l'utilisateur, puis utiliser une requête secondaire.

      Un exemple de ceci est un panier d'achat. Un utilisateur peut sélectionner plusieurs articles à acheter. Plutôt que de garder ceux-ci dans l'application et besoin d'ajouter tous les éléments à un ordre en une seule fois quand ils vérifient, ajouter chaque élément à une table dans le db comme l'utilisateur sélectionne ou modifie.

  3. avoir une fonction définie par l'utilisateur sql qui décompose un paramètre string dans une table et retourne cette table comme un ensemble que vous pouvez utiliser avec une expression IN (). Voir l'article lié ci-dessous pour plus de détails sur la façon dont cela fonctionne.
  4. construisez une liste de chaînes ou de paramètres dynamiquement sur le client (comme indiqué dans les autres réponses). Notez que ceci est mon le moins option préférée.

le définitive (et je veux dire définitives) le travail sur le sujet est ici:

http://www.sommarskog.se/arrays-in-sql.html

Le long article, mais dans le bon sens. L'auteur est un expert du serveur sql, mais les concepts dans l'ensemble s'appliquent aussi à MySQL.

2
répondu Joel Coehoorn 2011-04-15 20:40:04

comme je le sais, Vous ne pouvez pas fournir n'importe quel tableau comme paramètre à la déclaration préparée. IN () ne supporte pas les paramètres comme un tableau.

1
répondu Vladislav Rastrusny 2011-04-15 19:20:26

Cela ne fonctionne pas bien pour les listes énormes, mais c'est le chose que j'ai trouvé qui fonctionne si vous pour passer une liste en paramètre.

au Lieu de

SELECT * FROM table WHERE id IN (@parameter)

Vous devez faire ceci:

SELECT *
FROM table
WHERE INSTR(','+@parameter+',', ','+CAST(the_column AS CHAR) + ',')

Ensuite, vous pouvez passer dans votre liste avec string.Join(",", intArray)

c'est un kludge, mais ça marche.

0
répondu Matt Ellen 2011-04-16 09:17:29

réponse de Mud ne fonctionne que pour le premier int dans la liste des paramètres. Cela signifie que '2,1,3,4' ne fonctionnera pas si id est 1 par exemple.

Voir FIND_IN_SET () vs IN () .

aucun commentaire possible à ce jour, mais Voir aussi la réponse de Matt Ellen. Il modifierait sa réponse mais ne peut pas. INSTR ne semble pas fonctionner dans un cas où il y a plus d'un id (retourne seulement sur le résultat).

Mais en remplaçant INSTRLOCATE faire fonctionner sa solution (avec String.Join(",", intArray) comme ajout du paramétrage) ... JUSQU'VOTER de moi:

LOCATE(CONCAT(',' , CAST(id AS CHAR) , ',') , CONCAT(',' , CAST(@paramter AS CHAR) , ',')) <> 0
0
répondu Lolblack 2017-05-23 12:32:26

Je ne pense pas qu'il y ait un moyen de les ajouter comme ça, mais peut-être que vous pourriez itérer à travers la liste et générer la requête dynamiquement.

Par exemple:

var intArray = new List<int>(){1,2,3,4};
if (intArray.Count > 0) {
    var query = "SELECT * FROM table WHERE id IN (";
    for (int i = 0; i < intArray.Count; i++) {
        //Append the parameter to the query
        //Note: I'm not sure if mysql uses "@" but you can replace this if needed
        query += "@num" + i + ",";
        //Add the value to the parameters collection
        ...connection.Command.Parameters.AddWithValue("num" + i, intArray[i]);
    }
    //Remove the last comma and add the closing bracket
    query = query.Substring(0, query.Length - 1) + ");";
    //Execute the query here
}

de cette façon, vous pouvez même utiliser une liste dactylographiée différemment et récolter les avantages des requêtes paramétrées. Cependant, je ne sais pas s'il y aurait des problèmes de rendement avec des listes plus importantes, mais je soupçonne que ce serait le cas.

-1
répondu Richard Marskell - Drackir 2011-04-15 19:30:50