4

我需要一些帮助来创建一个 LINQ 选择,我有一个包含一些列的表,但只有 2 个对这个问题感兴趣。

userid, type

现在这个表有数千个条目,我只想要顶部,比如说 50。到目前为止一切都很好,但困难的部分是有很多成功的行应该只计为 1。示例

Type  UserId
============
Add   1
Add   1
Add   1
Add   2

我希望这在我取出的行数限制中仅计为 2,但我希望所有行仍然输出。这是否可以通过单个 SQL 请求实现,还是我应该找到另一种方法来做到这一点?

编辑:如果这可以解决问题,我可以将列添加到表中。Edit2:Sotred 程序也是一种解决方案

示例 2:这应该算作 3 行

Type  UserId
============
Add   1
Add   1
Add   2
Add   1
4

4 回答 4

1

我现在离电脑不近,所以我不确定语法是否 100% 正确,但我相信你正在寻找这样的东西:

data.Select(x => new {x.Type, x.UserId})
    .GroupBy(x => x.UserId)
    .Take(50);
于 2013-04-04T21:29:12.750 回答
1

可以用 Linq 来做,但它可能比传统的for循环慢很多。一种方法是:

data.Where((s, i) => i == 0 || 
                     !(s.Type == data[i-1].Type && s.UserId == data[i-1].UserId))

这将跳过与“上一个”项目具有相同类型和用户 ID 的任何“重复”项目。

但是,这仅在data具有索引器(数组或实现的东西IList)时才有效。一个IEnumerableIQueryable不会工作。此外,几乎可以肯定它不能转换为 SQL,因此您必须提取所有结果并在内存中进行过滤。

如果您想在 SQL 中执行此操作,我会尝试扫描游标并在其中一个值发生更改时填充临时表,或者使用包含ROW_NUMBER列的公用表表达式,然后执行类似于 Linq 的回顾子查询上面的方法:

WITH base AS
(
SELECT 
    Type,
    UserId, 
    ROW_NUMBER() OVER (ORDER BY ??? ) AS RowNum
    FROM Table
)
SELECT b1.Type, b1.UserId
FROM base b1
LEFT JOIN base b2 ON b1.RowNum = b2.RowNum - 1
WHERE (b1.Type <> b2.Type OR b1.UserId <> b2.UserId)
ORDER BY b1.RowNum
于 2013-04-04T21:58:14.233 回答
1

您可以使用 LINQ 执行此操作,但我认为走“for(each) 循环”路线可能更容易......

data.Select((x, i) => new { x.Type, x.UserId, i })
    .GroupBy(x => x.Type)
    .Select(g => new
    {
        Type = g.Key,
        Items = g
            .Select((x, j) => new { x.UserId, i = x.i - j })
    })
    .SelectMany(g => g.Select(x => new { g.Type, x.UserId, x.i }))
    .GroupBy(x => new { x.Type, x.i })
    .Take(50);
    .SelectMany(g => g.Select(x => new { x.Type, x.UserId }));
于 2013-04-04T22:27:01.387 回答
1

你卡在LINQ上吗?

添加 PK 身份。
按PK订购。
使用 DataReader 并计算更改。
然后在更改计数达到最大值时停止。

如果您不在 .NET 环境中,那么使用游标也是如此。

由于 LINQ 被延迟,您可能只需在 LINQ 中订购,然后在 ForEach 上直接退出即可。

于 2013-04-04T22:53:08.463 回答