如何创建一个Linq Select语句

4

我需要帮助创建一个LINQ查询,我的表格中有一些列,但只有两列与这个问题有关。

userid, type

现在这个表有成千上万的条目,我只想要前50个。目前为止都还好,但是困难的部分是成功中有很多行应该只被计算为1次。

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

我希望在限制行数的情况下,仅将此内容视为2行,但仍希望输出所有行。是否可以通过单个SQL请求实现此目的,还是应该找到其他方法来解决?
编辑:如果这可以解决问题,我可以向表中添加列和值。 编辑2:存储过程也是一种解决方案。
例子2:这应被视为3行。
Type  UserId
============
Add   1
Add   1
Add   2
Add   1

2
我认为这很难。Linq和SQL很擅长集合操作,但不适用于顺序处理。经典的foreach在这里更加合适。 - Gert Arnold
是的,但我不想从数据库中获取超过所需的数据,在理论上可能会有超过1000行的序列。 - Androme
我看到一个存储过程正在酝酿中... - Gert Arnold
一个存储过程就可以了,我只是不知道怎么写:D - Androme
好的,你可能想要重新表述你的问题,并添加 SQL 和存储过程标签来吸引数据库专家。 - Gert Arnold
显示剩余2条评论
4个回答

1

我现在离电脑比较远,所以语法方面不确定是否正确,但我认为你正在寻找像这样的东西:

data.Select(x => new {x.Type, x.UserId})
    .GroupBy(x => x.UserId)
    .Take(50);

我已经很久没有使用groupby了,但是据我记得它不会将所有条目分组为一个单独的条目吗? - Androme
你说得对,我没有注意到它只应该将相邻的数字分组,我会仔细考虑解决方案并回来进行编辑。 - Xtian Macedo

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

这就是我想要避免的,因为理论上表格可能会有成千上万条记录! - Androme
嗯,我无法使你编写的SQL代码正常工作,但如果我读得正确,它是否只返回不同的值? - Androme
它应该返回任何与下一行不同的行。最后一行应该包括在内,因为此时'b2'值将为NULL。你是遇到错误还是只是得到了错误的结果? - D Stanley

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 }));

1

你是否在LINQ上遇到了困难?

添加一个PK身份。
按PK排序。
使用DataReader并仅计算更改次数。
当更改计数达到最大值时停止。

如果您不在.NET环境中,则可以使用光标进行相同的操作。

由于LINQ是延迟的,因此您可能只需在LINQ中排序,然后在ForEach上退出即可。


我想坚持使用我的代码库,但这可能是最好的解决方案。 - Androme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接