Формирование запроса SQL / LINQ - Упорядоченные элементы в разных строках, совместно использующие логическую группировку - PullRequest
1 голос
/ 02 марта 2012

Это будет немного абстрактно, но у меня есть такой метод:

private int[] ReturnLogicalGroupingAForOrderedElements(List<int> elements) {
    //sql query or linq query
    //returns an int[] in case there are more than one matching set.
}

Допустим, переданный список содержит следующие элементы: 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 может содержать множество LogicalGroupingB, которые также могут содержать много элементов.

Первоначально у меня была очень простая установка данных, в которой столбец содержал строку типа «3,6,9», которую мне пришлось бы анализировать в моей логике. Целью создания этого нового числового набора данных было сделать его как можно быстрее (теоретически). Я открыт для альтернативной структуры данных, если она может улучшить это, но в основном я прошу помощи в формировании желаемого запроса (sql или linq) для приведенной выше таблицы.

РЕДАКТИРОВАТЬ: Может быть, немного плохое время размещения вопроса, так как я уйду из своей машины разработчика в течение следующих двух дней, но будьте уверены, я дам правильные очки и голоса (и комментарии), как только я вернусь и проверил предложения. Спасибо за ваше терпение.

Ответы [ 2 ]

1 голос
/ 02 марта 2012
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);
        }
    }
}
0 голосов
/ 02 марта 2012

Обновление: отфильтровать группы с более чем указанными элементами

при условии, что 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...