Requête pour sélectionner une liste de valeurs à partir d'une table en fonction de ce multicritère
-
26-10-2019 - |
Question
J'ai une table avec 2 colonnes, Ex_Id et term_id, les deux types int. Ma table aura beaucoup Ids à terme pour un exercice Id.
Table would look like this:
Ex_Id Term_Id
1 2
1 3
1 4
1 5
2 2
3 2
3 4
etc. Obtenir une liste des Ex_Id est l'exigence principale. Ma fonction serait comme ça.
List<int> Get_ExId_List(List<int> lst_TermId)
{
// return a list of Ex_Id <int>
}
C'est, je vais passer une liste de durée Ids et je dois obtenir une liste des exercices Ids correspondant à certains critères de retour. Les critères de sélection peuvent être mieux expliquées avec ce pseudo-code: SELECT such Ex_Ids FROM table Exercise_Term WHERE Ex_Id has all the corresponding Term_Ids in the lst_TermId
Par exemple, dans le tableau I échantillon fourni ci-dessus,
List<int> Get_ExId_List([2])
{
// return [1,2,3]
}
List<int> Get_ExId_List([2,4])
{
// return [1,3]
}
List<int> Get_ExId_List([2,3,4])
{
// return [1]
}
une partie de requête est ma confusion. Quelle serait la requête dans cette condition comme? Reste que je peux gérer. L'espoir est question claire. Merci ..
La solution
SELECT Ex_ID
FROM TableName
WHERE Term_ID IN (?, ?, ?) --- (2, 3, 4)
GROUP BY Ex_ID
HAVING COUNT(DISTINCT Term_ID) = 3 --- number of terms in the above list
Si la (Ex_ID, Term_ID)
combinaison est unique dans la table, vous pouvez remplacer COUNT(DISTINCT Term_ID)
avec COUNT(*)
Ceci est un problème de division relationnelle. La solution "standard" serait en utilisant deux négatifs (EXISTE NOT):
SELECT DISTINCT Ex_ID
FROM TableName e
WHERE NOT EXISTS
( SELECT *
FROM TableName t
WHERE t.Term_ID IN (?, ?, ?) --- the list of terms
AND NOT EXISTS
( SELECT *
FROM TableName a
WHERE a.Term_ID = t.Term_ID
AND a.Ex_ID = e.Ex_ID
)
)
ou mieux dans votre cas:
SELECT DISTINCT Ex_ID
FROM TableName e
WHERE NOT EXISTS
( SELECT *
FROM
( SELECT ? AS Term_ID
UNION
SELECT ?
UNION
SELECT ?
) AS t
WHERE NOT EXISTS
( SELECT *
FROM TableName a
WHERE a.Term_ID = t.Term_ID
AND a.Ex_ID = e.Ex_ID
)
)
Autres conseils
Vous pouvez utiliser LINQ. Obtenez toute la table dans un IEnumerable de quelque sorte, puis utiliser LINQ. Voici un exemple:
static IEnumerable<int> Get_ExId_List(ICollection<int> lst_TermId)
{
//this is just for the example - get the real data instead
var data = new[] {
new { Ex_Id = 1, Term_Id = 2},
new { Ex_Id = 1, Term_Id = 3},
new { Ex_Id = 1, Term_Id = 4},
new { Ex_Id = 1, Term_Id = 5},
new { Ex_Id = 2, Term_Id = 2},
new { Ex_Id = 3, Term_Id = 2},
new { Ex_Id = 3, Term_Id = 4},
};
return data
.Where(row => lst_TermId.Contains(row.Term_Id))
.GroupBy(row => row.Ex_Id)
.Where(group => group.Count() == lst_TermId.Count())
.Select(group => group.Key);
}
static void Main(string[] args)
{
HashSet<int> lst_TermId = new HashSet<int>();
lst_TermId.Add(2);
Console.WriteLine();
var result = Get_ExId_List(lst_TermId);
foreach (var exid in result)
Console.WriteLine(exid);
lst_TermId.Add(4);
Console.WriteLine();
result = Get_ExId_List(lst_TermId);
foreach (var exid in result)
Console.WriteLine(exid);
lst_TermId.Add(3);
Console.WriteLine();
result = Get_ExId_List(lst_TermId);
foreach (var exid in result)
Console.WriteLine(exid);
}
Notez que vous obtiendrez de meilleures performances si votre lst_TermId est un HashSet<int>
, car la méthode contient sera O(1)
au lieu de O(n)
.