我正在尝试将我的一些业务逻辑从我的程序中移出并存储到存储过程中。我真的是一名VB.NET程序员,而不是SQL专家,但我正在学习更多SQL并发现在很多情况下,让SQL进行处理并返回少量数据而不是给我更快大量的东西,并让我的程序通过它。
所以,我目前的问题是:
我正在创建一个从数据库中的几个不同来源发生的事情的时间表。我提到的相关信息是:
我想利用这个时间表最终弄清楚谁在给定时间对某件事负责。因此,如果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专家似乎普遍厌恶使用游标,但我不确定我是否仍然以这种方式思考,所以有人可以帮助我吗?
到目前为止,我已经成功地将未经过滤的原始数据放入查询中的表变量中。所以,我只需要知道如何“折叠”数据并只返回一小部分。
谢谢!
答案 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中最好的解决方案。其他数据库风格允许您从上一行/下一行(lag
和lead
窗口函数)中获取示例值,但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)
这是光标可能是您最好的选择之一。只是尝试尽可能多地限制您要迭代的数据子集。