SQL Server - 使用基于集合的解决方案而不是行迭代解决此问题

时间:2011-11-15 19:56:22

标签: sql-server cursor set loops

我正在尝试将我的一些业务逻辑从我的程序中移出并存储到存储过程中。我真的是一名VB.NET程序员,而不是SQL专家,但我正在学习更多SQL并发现在很多情况下,让SQL进行处理并返回少量数据而不是给我更快大量的东西,并让我的程序通过它。

所以,我目前的问题是:

我正在创建一个从数据库中的几个不同来源发生的事情的时间表。我提到的相关信息是:

  1. 用户名
  2. 与行动相关的时间
  3. 我想利用这个时间表最终弄清楚谁在给定时间对某件事负责。因此,如果1个用户在新用户登录之前连续记录400个动作,我真的不在乎;我只是想看看用户1何时开始记录以及用户2何时接管记录。

    更多图形示例:

    用户|时间

    User1 | 12:00
    User1 | 12:01
    User1 | 12:02
    User1 | 12:03
    User1 | 12:04
    User1 | 12:05
    User1 | 12:06
    User2 | 12:07
    User2 | 12:08
    User2 | 12:09
    User2 | 12:10
    User2 | 12:11
    User1 | 12:12
    User1 | 12:13

    我想要的是什么:

    用户时间

    User1 | 12:00
    User2 | 12:07
    User1 | 12:12

    现在,在代码中,我将结果集放入DataTable并迭代表中的每一行。然后,我将检查当前行的[用户名]值与前一行的[用户名]值,如果[用户名]不同,则仅添加当前行的值。真正的SQL专家似乎普遍厌恶使用游标,但我不确定我是否仍然以这种方式思考,所以有人可以帮助我吗?

    到目前为止,我已经成功地将未经过滤的原始数据放入查询中的表变量中。所以,我只需要知道如何“折叠”数据并只返回一小部分。

    谢谢!

4 个答案:

答案 0 :(得分:4)

编辑需要1个以上的间接级别才能按排名进行过滤:

select 
  User,Time
from
(
  select *
  from
  (
      Select 
        User,Time, rank() over (partition by u.User order by u.Time) as User_Rank
      from 
        your_table u
  ) UserRanks
) x
where User_Rank = 1
order by Time

与araqnid和Royi的答案类似,但使用WHERE NOT EXISTS而不是JOIN。

with CTE  as (
    select user, time, row_number() over (order by time) rn from MyTable
)  
select    CTE.user, CTE.time
from CTE CTE1
where not exists (select user, time from CTE CTE2 where CTE1.rn = CTE2.rn - 1 and CTE1.user = CTE2.user)

答案 1 :(得分:0)

最后:

;with CTE  as (
    select user, time, row_number() over (order by time) rn from MyTable
)  
select    CTE.user, CTE.time
from CTE left join CTE other on other.rn = CTE .rn - 1
where other.user is null or CTE .user <> other.user

答案 2 :(得分:0)

基于行的迭代可能是SQL Server中最好的解决方案。其他数据库风格允许您从上一行/下一行(laglead窗口函数)中获取示例值,但SQL Server不支持这些值。

你可以像这样一起躲起来:

with x as (
    select user, time, row_number() over (order by time) rn from source
)
select x.user, x.time
from x left join x prev on prev.rn = x.rn - 1
where prev.user is null or x.user <> prev.user

然而,我怀疑这是不方便的,并且表现恶劣。

答案 3 :(得分:0)

这是光标可能是您最好的选择之一。只是尝试尽可能多地限制您要迭代的数据子集。