2008-09-27 10 views
5

Problème:SQL Server: dynamique clause where

Ajax suggère-recherche sur [n] ingrédients dans les recettes. C'est-à-dire: associer des recettes à plusieurs ingrédients. Par exemple, SELECT Recipes using "flower", "salt" produirait: "Pizza", "Bread", "Saltwater" et ainsi de suite.

Tables:

Ingredients [ 
    IngredientsID INT [PK], 
    IngredientsName VARCHAR 
] 

Recipes [ 
    RecipesID INT [PK], 
    RecipesName VARCHAR 
] 

IngredientsRecipes [ 
    IngredientsRecipesID INT [PK], 
    IngredientsID INT, 
    RecipesID INT 
] 

Requête:

SELECT 
    Recipes.RecipesID, 
    Recipes.RecipesName, 
    Ingredients.IngredientsID, 
    Ingredients.IngredientsName 
FROM 
    IngredientsRecipes 

    INNER JOIN Ingredients 
    ON IngredientsRecipes.IngredientsID = Ingredients.IngredientsID 

    INNER JOIN Recipes 
    ON IngredientsRecipes.RecipesID = Recipes.RecipesID 
WHERE 
    Ingredients.IngredientsName IN ('salt', 'water', 'flower') 

Je construis actuellement ma requête en utilisant ASP.NET C# en raison de la nature dynamique de la clause WHERE.

Je mords que je dois construire la requête dans ma couche de code au lieu d'utiliser une procédure stockée/SQL pur, ce qui en théorie devrait être beaucoup plus rapide. Avez-vous des idées sur la façon dont je déplacerais toute la logique de ma couche de code vers du SQL pur, ou du moins comment optimiser la performance de ce que je fais?

Je pense le long des lignes de tables temporaires:

Première étape: SELECT IngredientsID FROM Ingredients et INSERT INTO temp-table

Étape deux: SELECT RecipesName FROM Recipes rejoint avec IngredientsRecipes joint à temp-table.IngredientsID

Répondre

7

Vous avez deux options. Si vous utilisez SQL Server 2008 (ou Oracle), vous pouvez passer un table value parameter.

Si vous utilisez SQL Server 2005, vous pouvez utiliser XML to simulate this capability

Si vous utilisez quelque chose plus tôt que 2005, vous devez concaténer les ids dans une seule chaîne et de créer une UDF pour les analyser.

+0

Super nouvelles, Mike. Merci beaucoup! :) – roosteronacid

2

Selon la façon dont vous Je traite les ingrédients d'entrée Je pense que cette méthode actuelle a des risques d'injection sql.

Vous pouvez ajouter le nom de l'ingrédient aux conditions de jointure qui peuvent être plus rapides.

Vous pouvez également ajouter des combinaisons d'ingrédients pour les recettes pour une recherche rapide.

+0

Je suis d'accord. Les problèmes d'injection de scripts sont également l'une de mes préoccupations. Pourriez-vous élaborer sur le "hashing"? – roosteronacid

+0

Si vous avez l'utilisateur de choisir parmi une liste d'ingrédients possibles, celui de votre tableau des ingrédients, vous pouvez utiliser par programmation ces ids, dans votre déclaration where et aucun problème d'injection. – Brettski

+0

E.g. Si vous traitez un hachage MD5 ou SHA1 en ajoutant les mots «farine d'eau salée», vous obtiendrez une valeur (votre hachage).Dans votre recherche, vous pourriez alors chercher un objet correspondant à cela. Si vous comparez une valeur plutôt qu'une liste, cela sera plus rapide. – alexmac

3

Vous pouvez au moins où la paramétrisation clausule pour éviter l'injection SQL, quelque chose aussi bien:

using System.Data; 
using System.Data.SqlClient; 
using System.Text; 

class Foo 
{ 
    public static void Main() 
    { 
     string[] parameters = {"salt", "water", "flower"}; 
     SqlConnection connection = new SqlConnection(); 
     SqlCommand command = connection.CreateCommand(); 
     StringBuilder where = new StringBuilder(); 
     for (int i = 0; i < parametes.Length; i++) 
     { 
      if (i != 0) 
       where.Append (","); 
      where.AppendFormat ("@Param{0}", i); 
      command.Parameters.Add (new SqlParameter ("Param" + i, parameters [i])); 
     } 
    } 
} 
+0

Oui. Je prenais soin des injections potentielles. Mike Brown est venu avec un coup de génie. Mais merci pour votre effort mec. – roosteronacid