【问题标题】:Querying a many-to-many table by grouping通过分组查询多对多表
【发布时间】:2020-08-25 01:37:58
【问题描述】:

我有一个多对多关系表,我正在尝试像字典一样对其进行查找。

项目

|---------------------|------------------|-----------------|
|          Id         |       Name       |      Desc       |
|---------------------|------------------|-----------------|
|          1          |       One        |   First Item    |
|          2          |       Two        |   Second Item   |
|          3          |       Three      |   Third Item    |
|          4          |       Four       |   Fourth Item   |
|          5          |       Five       |   Fifth Item    |
|---------------------|------------------|-----------------|

收藏

|---------------------|------------------|
|          Id         |       Name       |
|---------------------|------------------|
|          1          | First Collection |
|          2          | Second Collecton |
|---------------------|------------------|

库存

|---------------------|------------------|--------------|
|     CollectionId    |       ItemId     |    Amount    |
|---------------------|------------------|--------------|
|          1          |         1        |       14     |
|          1          |         2        |       4      |
|          1          |         5        |       4      |
|          2          |         1        |       2      |
|          2          |         5        |       9      |
|---------------------|------------------|--------------|

我正在尝试设计一个查询来获取所有 CollectionId,其中某些 CollectionId 与某些输入集中的每个 ItemId 都有关系?

很难找到描述我的意图的词,但伪代码看起来像这样

SearchFromIncludes(HashSet<Item> list)
{
  Dictionary<HashSet<Item>, ItemContainer> lookupTable = MakeTable();
  List<ItemContainer> matches = [];
  for (key in getKeys(lookupTable))
  {
     // if all items in the item list exist in the lookup key, add it for return
     if (AllItemsExist(key, list))
     {
       matches.Add(lookupTable.getValue(key));
     }
     return matches;
  }
}

所以如果MakeTable 将上述关系创建为字典

{
  [1, 2, 3]: 1,
  [1, 5]: 2
}

SearchFromIncludes([1, 5]) 会返回

[1]

SearchFromIncludes([1, 3, 5]) 会返回

[1, 2]

是否有一种 SQL 策略可以以这种方式从多对多表中查询信息,您想从关系中获取一个项目,该关系的相关项目与输入集完全匹配?我认为 GROUP BY 在这里可能会有所帮助,但我还没有成功地工作

最终我将使用 Entity Framework Core/LINQ 来执行此操作,但我也想知道它在 SQL 中的外观

【问题讨论】:

  • 首先,你的sql表schema不正确。集合是在其中输入两个表(项目和库存)ID 的表。它对于多对多关系至关重要。
  • 我会尝试计算与任何项目 ID 匹配的库存记录的数量,然后将计数与预期的 ID 数进行比较。

标签: c# sql postgresql linq


【解决方案1】:

尝试以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DataTable itemTable = new DataTable();
            itemTable.Columns.Add("Id", typeof(int));
            itemTable.Columns.Add("Name", typeof(string));
            itemTable.Columns.Add("Desc", typeof(string));

            itemTable.Rows.Add(new object[] { 1, "One", "First Item" });
            itemTable.Rows.Add(new object[] { 2, "Two", "Second Item" });
            itemTable.Rows.Add(new object[] { 3, "Three", "Third Item" });
            itemTable.Rows.Add(new object[] { 4, "Four", "Fourth Item" });
            itemTable.Rows.Add(new object[] { 5, "Five", "Fifth Item" });

            DataTable collectionTable = new DataTable();
            collectionTable.Columns.Add("Id", typeof(int));
            collectionTable.Columns.Add("Name", typeof(string));

            collectionTable.Rows.Add(new object[] { 1, "First Collection" });
            collectionTable.Rows.Add(new object[] { 2, "Second Collection" });

            DataTable inventoryTable = new DataTable();
            inventoryTable.Columns.Add("CollectionId", typeof(int));
            inventoryTable.Columns.Add("ItemId", typeof(int));
            inventoryTable.Columns.Add("Amount", typeof(int));

            inventoryTable.Rows.Add(new object[] { 1, 1, 14 });
            inventoryTable.Rows.Add(new object[] { 1, 2, 4 });
            inventoryTable.Rows.Add(new object[] { 1, 5, 4 });
            inventoryTable.Rows.Add(new object[] { 2, 1, 2 });
            inventoryTable.Rows.Add(new object[] { 2, 5, 9 });

            Dictionary<int, List<object>> dict = (from inTable in inventoryTable.AsEnumerable()
                                            join cTable in collectionTable.AsEnumerable() on inTable.Field<int>("CollectionId") equals cTable.Field<int>("Id")
                                            join iTable in itemTable.AsEnumerable() on inTable.Field<int>("ItemId") equals iTable.Field<int>("Id")
                                            select new { inTable = inTable, cTable = cTable, iTable = iTable }
                                           ).ToList()
                                           .GroupBy(x => x.cTable.Field<int>("Id"), y => new  { itemTableRow = y.iTable, amount = y.inTable.Field<int>("Amount") })
                                           .ToDictionary(x => x.Key, y => y.ToList<object>());
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 2014-05-27
    • 2021-04-04
    • 1970-01-01
    • 2021-09-08
    • 2013-07-13
    • 2010-09-12
    相关资源
    最近更新 更多