Группа По этой цепочке взад и вперед через два поля - PullRequest
2 голосов
/ 29 марта 2012

У меня есть установка, которая выглядит следующим образом:

CREATE TABLE MessageGrouping(MessageGroupingId bigint IDENTITY(1,1),
                             StoredMessageId bigint, MessageGroupId bigint)

INSERT INTO [MessageGrouping]([StoredMessageId], [MessageGroupId])
SELECT 1, 301 UNION ALL
SELECT 1, 302 UNION ALL
SELECT 2, 302 UNION ALL
SELECT 3, 303 UNION ALL
SELECT 4, 304 UNION ALL
SELECT 2, 305 UNION ALL
SELECT 6, 305 UNION ALL
SELECT 7, 303
GO

Мне нужно это, чтобы вернуть группы (из StoredMessageId s), как это:

[1,2,6], [3, 7], [4]

Обновление: Логика для первой группировки выглядит следующим образом: StoredMessageId 1 имеет MessageGroupId 301 и 302 на нем.Но MessageGroupId 302 также имеет StoredMessageId 2.Поэтому StoredMessageId 2 должен быть включен в группу.

Но StoredMessageId 2 также имеет MessageGroupId 305.И MessageGroupId 305 имеет StoredMessageId 6, поэтому он также включен в группу.

Я попробовал это в LinqPad и вышел пустым.Простой MessageGroupings.GroupBy(x=>x.MessageGroupId) только группирует по MessageGroupId (как и ожидалось).

Добавление в StoredMessageId s (MessageGroupings.GroupBy(x=>new {x.MessageGroupId, x.StoredMessageId}) просто помещает каждую строку в свою группу.

Есть лиспособ сделать цепочечную группировку в Linq, как я ищу? Я также в порядке, чтобы сделать это в SQL.

Я хотел бы иметь возможность использовать это в микро ORM, как Dapper , но если мне понадобится Entity Framework, я тоже могу это сделать.

1 Ответ

3 голосов
/ 29 марта 2012

Хорошо - вопреки тому, что я думал, вы можете сделать это с помощью одного рекурсивного CTE.
Не то чтобы это красиво ...

Обратите внимание, что все тестирование проводилось в DB2, у которой нет способа вернуть массивы в ряд. Я не знаю, может ли SQL Server (поэтому вам, возможно, придется анализировать результаты). Я НЕ рекомендую попытаться сделать это с Linq - во всяком случае, это должно быть выполнено непосредственно в базе данных.

WITH Mappings(beginId, storedId, groupId, storedPath, groupPath) as (
     SELECT a.StoredMessageId, a.StoredMessageId, a.MessageGroupId,
            a.StoredMessageId + "|", a.MessageGroupId + "|"
     FROM MessageGrouping as a
     WHERE NOT EXISTS (SELECT 1
                       FROM MessageGrouping as b
                       WHERE b.StoredMessageId < a.StoredMessageId
                       AND b.MessageGroupId = a.MessageGroupId)
     AND NOT EXISTS (SELECT 1
                     FROM MessageGrouping as b
                     WHERE b.MessageGroupId < a.MessageGroupId
                     AND b.StoredMessageId = a.StoredMessageId)
     UNION ALL
     SELECT a.beginId, a.storedId, b.MessageGroupId,
            a.storedPath, a.groupPath + b.MessageGroupId + "|"
     FROM Mappings as a
     JOIN MessageGrouping as b
     ON b.StoredMessageId = a.storedId
     AND b.MessageGroupId <> a.groupId
     AND a.groupPath NOT LIKE "%" + b.MessageGroupId + "%"
     UNION ALL
     SELECT a.beginId, a.StoredMessageId, a.groupId,
            a.storedPath + b.StoredMessageId + "|", a.groupPath
     FROM Mappings as a
     JOIN MessageGrouping as b
     ON b.MessageGroupId = a.groupId
     AND b.StoredMessageId <> a.storedId
     AND a.storedPath NOT LIKE "%" + b.StoredMessageId + "%"),

     Result_Rows (ids, num) as (
     SELECT storedPath, 
            ROW_NUMBER() OVER(PARTITION BY beginId
                              ORDER BY LENGTH(storedPath) DESC)
     FROM Mappings)
SELECT ids
FROM Result_Rows
WHERE num = 1

Выход ids из:

1|2|6|
3|7|  
4|                                
...