我在访问数据库中有 3 个表:
Item
(带有 itemId
和 itemName
),Recipe
(带有 recipeId
)和 ItemInRecipe
- 其中包含 recipeId
和 itemId
(项目在食谱中)。
例如:
配方编号 | itemId |
---|---|
1 | 3 |
1 | 6 |
2 | 6 |
我想找到包含列表中所有项目的食谱(对于具有 6 作为 itemId 的列表,它将返回 1 和 2)
我尝试使用带有
itemId
的 SQL 查询来完成它:
public static List<int> RecipesWithAllItems(List<int> itemIdList)
{
List<int> recipeIdList = new List<int>();
// SQL query that gets the recipe IDs that have all of the items in itemIdList
string query = string.Format("SELECT recipeId FROM ItemInRecipe WHERE itemId IN " +
"(SELECT itemId FROM Item WHERE itemId IN (" + string.Join(",", itemIdList) + "))
GROUP BY recipeId HAVING COUNT(itemId) = " + itemIdList.Count);
DataTable dt = Dbf.GetInfo_fromTable(query); //returns the information as a dataTable
foreach (DataRow dr in dt.Rows)
{
int recipeId = int.Parse(dr["recipeId"].ToString());
recipeIdList.Add(recipeId);
}
return recipeIdList;
}
也尝试过
itemName
:
public static List<int> GetTheRecipesIdsWithAllItems(List<string> itemList)
{
List<int> recipeIdList = new List<int>();
// SQL query that gets the recipe IDs that have all of the items in itemList
string query = string.Format("SELECT recipeId FROM ItemInRecipe WHERE itemId IN " +
"(SELECT itemId FROM Item WHERE itemName IN (" +
string.Join(",", itemList.ConvertAll(i => "'" + i + "'")) +
")) GROUP BY recipeId HAVING COUNT(itemId) = " + itemList.Count);
DataTable dt = Dbf.GetInfo_fromTable(query);
foreach (DataRow dr in dt.Rows)
{
int recipeId = int.Parse(dr["recipeId"].ToString());
recipeIdList.Add(recipeId);
}
return recipeIdList;
}
但是,两者都不起作用/返回不正确的结果。 我怎样才能找到包含所有物品的食谱?
我建议
group by
加上having
:
select recipeId
group by recipeId
from ItemInRecipe
where itemId in (list items here)
having count(1) = (list.Count() here)
代码:
public static List<int> RecipesWithAllItems(List<string> itemList) {
if (itemList is null)
throw new ArgumentNullException(nameof(itemList));
var ids = itemList
.Where(item => item != null)
.Distinct()
// .OrderBy(id => id) // ordering can be helpful if itemList is short
.ToList();
//TODO: What should we return in case of empty list?
if (ids.Count == 0)
return new List<int>();
// I've hardcoded ids and ids.Count
// Since I have to call Dbf.GetInfo_fromTable
//TODO: Try to parametrize the query
var sql = @$"select recipeId
group by recipeId
from ItemInRecipe
where itemId in {string.Join(", ", ids)}
having count(1) = {ids.Count}";
List<int> recipeIdList = new List<int>();
DataTable dt = Dbf.GetInfo_fromTable(query);
foreach (DataRow dr in dt.Rows)
recipeIdList.Add(Convert.ToInt32(dr["recipeId"]));
return recipeIdList;
}
如果不能使用参数并且
itemList
很短,排序可以帮助优化:你会有更少的不同查询。