形成SQL/LINQ查询-跨不同行的有序元素共享逻辑分组
本文关键字:元素 共享 LINQ SQL 查询 形成 | 更新日期: 2023-09-27 18:26:23
这有点抽象,但我有一个这样的方法:
private int[] ReturnLogicalGroupingAForOrderedElements(List<int> elements) {
//sql query or linq query
//returns an int[] in case there are more than one matching set.
}
假设传递的List包含以下元素:3,6和9。我需要从数据表源中找到完全相同的列表,相同顺序的元素,共享相同的逻辑分组(无论是什么)。
我有一个包含以下列的数据表(所有列都是int值):
LogicalGroupingA, LogicalGroupingB, Element, ElementOrder
我需要找到并确定以上所有元素(3,6,9)都存在于多行中,共享相同的逻辑分组。示例:
7,1,3,1
7,1,6,2
7,1,9,3
如果所有这些都找到了,那么我想从LogicalGroupingA返回值,即7。但考虑一下,可能有一组不同的行(共享相同的逻辑组):
4,1,3,1
4,1,6,2
4,1,9,3
4,1,5,4
只有当完整的一系列元素正是所要求的时,查询才应该返回所需的值(这里的前三个元素与查询的列表相等,但由于这里有第四个元素,所以不相等)。假设数据表的行是混合的。LogicalGroupingA可以包含许多LogicalGrouping B,后者也可以包含许多元素。
最初,我有一个非常简单的数据表设置,其中一个列包含一个类似"3,6,9"的字符串,我必须在逻辑中解析它。创建这个新的数字数据表的目的是使其尽可能快(理论上)。如果可以改进的话,我愿意使用另一种数据表结构,但主要是寻求帮助,为上表形成所需的查询(sql或linq)。
编辑:也许发布这个问题的时机有点糟糕,因为我将在接下来的两天离开我的开发机器,但请放心,我会给出正确的分数;投票(和评论)一旦我回来并测试了这些建议。谢谢你的耐心。
public class Grouping
{
public int LGA{get;set;}
public int LGB{get;set;}
public int El {get;set;}
public int ElO {get;set;}
}
void Main()
{
var dbValues = new List<Grouping>
{
new Grouping { LGA =7, LGB = 1, El=6, ElO=2 },
new Grouping { LGA =7, LGB = 1, El=3, ElO=1 },
new Grouping { LGA =4, LGB = 1, El=3, ElO=1 },
new Grouping { LGA =4, LGB = 1, El=6, ElO=2 },
new Grouping { LGA =4, LGB = 1, El=7, ElO=3 },
};
var dbGroups = dbValues.Select(dbData => new {Group = dbData.LGA, Element = dbData.El, ElO = dbData.ElO})
.OrderBy(item => item.ElO)
.GroupBy(item => item.Group);
var elements = new List<int>{3, 6};
foreach(var dbGroup in dbGroups)
{
if (dbGroup.Select(el => el.Element).SequenceEqual(elements))
{
Console.WriteLine(dbGroup.First().Group);
}
}
}
更新:过滤具有指定元素以上的组
假设这4列是唯一的
SELECT
LogicalGroupingA
FROM
(
-- get all Groupings that have the specified order
SELECT
LogicalGroupingA, LogicalGroupingB
FROM
table
WHERE
(element = :listelement1 AND ElementOrder = 1) OR
(element = :listelement2 AND ElementOrder = 2) OR
...
GROUP BY
LogicalGroupingA, LogicalGroupingB
HAVING
COUNT(*) = :listcount
) as candidates
WHERE
-- filter all Groupings that have more than the specified elements
Count(SELECT COUNT(*) FROM table WHERE LogicalGroupingA = candidates.LogicalGroupingA AND LogicalGroupingB = candidates.LogicalGroupingB) = :listcount
作为LINQ,不知道是否每个Linqprovider都理解它
public class Row
{
public int GroupA { get; set; }
public int GroupB { get; set; }
public int Element { get; set; }
public int ElementOrder { get; set; }
}
private IEnumerable<int> ReturnLogicalGroupingAForOrderedElements(IList<int> elements)
{
Expression parameter = Expression.Parameter(typeof(Row), "x");
Expression propElement = Expression.Property(parameter, "Element");
Expression propElementOrder = Expression.Property(parameter, "ElementOrder");
Expression where;
for (int i = 0; i < elements.Count; i++)
{
var restriction = Expression.AndAlso(
Expression.Equal(propElement, elements[i]),
Expression.Equal(propElementOrder, i + 1));
if (where == null)
where = restriction;
else
where = Expression.Or(where, restriction);
}
var groupsWithSameOrder = Rows.Where(where)
.GroupBy(r => new { r.GroupA, r.GroupB })
.Where(g => g.Count() == elements.Count)
.Select(g => g.Key);
return groupsWithSameOrder.Except(Rows
.Where(r => groupsWithSameOrder.Contains(new { r.GroupA, r.GroupB }))
.GroupBy(r => new { r.GroupA, r.GroupB })
.Where(g => g.Count() != elements.Count)
.Select(g => g.Key))
.Select(key => key.GroupA);
}