我的设置如下:
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)
的{{1}}组(正如预期的那样)。
添加MessageGroupId
s(StoredMessageId
只会将每一行放在自己的组中。
有没有办法在Linq中进行链式分组,就像我在找?我也可以在SQL中完成它。
我希望能够在像Dapper这样的微型ORM中使用它,但如果我需要实体框架,我也可以这样做。
答案 0 :(得分:3)
好的 - 与我的想法相反,你可以使用一个递归CTE来做到这一点。
不是很漂亮......
请注意,所有测试都是在DB2上完成的,它没有办法在行中返回数组。我不知道SQL Server是否可以(因此您可能需要解析结果)。我 NOT 建议尝试使用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|