Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 复杂/算法SQL查询_C#_Sql Server_Sql - Fatal编程技术网

C# 复杂/算法SQL查询

C# 复杂/算法SQL查询,c#,sql-server,sql,C#,Sql Server,Sql,我想知道是否有可能实现一个SQL查询,它将像一种算法一样,根据下表为我计算某个数字: 这是初始查询 SELECT Activity, TimeOfAction, Requestor FROM EventLog WHERE Requestor = 0 ORDER BY Requestor, TimeOfAction; 以及返回的数据样本 Login 2010-05-28 15:52:50.590 0 Login 2010-05-28 15:52:50.873 0 Logout 20

我想知道是否有可能实现一个SQL查询,它将像一种算法一样,根据下表为我计算某个数字:

这是初始查询

SELECT Activity, TimeOfAction, Requestor
FROM EventLog
WHERE Requestor = 0
ORDER BY Requestor, TimeOfAction;
以及返回的数据样本

Login   2010-05-28 15:52:50.590 0

Login   2010-05-28 15:52:50.873 0

Logout  2010-05-28 15:52:50.890 0

Logout  2010-05-28 16:22:57.983 0

Login   2010-05-29 11:29:36.967 0

Logout  2010-05-29 11:29:37.640 0
如您所见,此数据集中存在重复的登录和注销。我需要通过第一次登录和最后一次注销来计算会话的长度,如果存在重复的会话。因此,给出上述数据的第一次会议将来自

5-28 15:52:50.590 to 5-28 16:22:57.983
算法大致是

1按用户名,然后按操作时间,订购登录/注销列表

2如果条目是登录,则搜索下一次注销,然后立即登录,以确认它是所有重复项的最后一次注销

3使用第一次登录和最后一次注销创建新会话长度为注销时间-登录时间

4重复


目前我只是在代码中实现这一点,但我不太熟悉SQL,我想知道它是否可能在SQL中实现

当然。。。试试这样的

select e1.Requestor, 
       e1.TimeOfAction as LoginTime, 
       (select min(ActivityTime)
        from EventLog where TimeOfAction > e1.TimeOfAction 
        and Activity = 'Logout') as LogoutTime
from EventLog e1
where e1.ActivityType = 'Login'
order by Requestor, LoginTime
第二个解决方案。。。看看这对你是否更有效

select requestor,
    (select min(activitytime)
     from eventlog 
     where activitytime < e.activitytime
     and activity = 'Login' and e.activity = 'Logout') as LoginTime, 
    (select max(activitytime)
     from eventlog 
     where activitytime > e.activitytime
     and activity = 'Logout' and e.activity = 'Login') as LogoutTime, 
from eventlog e
order by requestor, logintime

这里有一个选项供您使用一些CTE和行号。基本上,它为每个用户排序事件,然后查找在注销或不注销之后的登录列表,然后查找继续登录或不登录的注销列表,然后将它们成对关联

;with events as (
  select *,
         row_number() over(partition by Requestor order by TimeOfAction) row
  from EventLog
), logins as (
  select e1.Activity, e1.TimeOfAction, e1.Requestor,
         row_number() over(partition by e1.Requestor order by e1.TimeOfAction) row
  from events e1
    left join events e2 on e1.Requestor=e2.Requestor
                       and e1.row=e2.row+1
  where e1.Activity='Login'
    and e1.Activity!=isnull(e2.Activity, 'Logout')
), logouts as (
  select e1.Activity, e1.TimeOfAction, e1.Requestor,
         row_number() over(partition by e1.Requestor order by e1.TimeOfAction) row
  from events e1
    left join events e2 on e1.Requestor=e2.Requestor
                       and e1.row=e2.row-1
  where e1.Activity='Logout'
    and e1.Activity!=isnull(e2.Activity, 'Login')
)
select i.Requestor, i.TimeOfAction as loginTime, o.TimeOfAction as logoutTime
from logins i
  left join logouts o on i.Requestor=o.Requestor
                     and i.row=o.row
注意:查询性能可能会急剧下降?通过将部分或全部CTE查询拆分为临时表而增加。i、 e.类似于以下内容:

select *,
       row_number() over(partition by Requestor order by TimeOfAction) row
into #events
from EventLog

select e1.Activity, e1.TimeOfAction, e1.Requestor,
       row_number() over(partition by e1.Requestor order by e1.TimeOfAction) row
into #logins
from #events e1
  left join #events e2 on e1.Requestor=e2.Requestor
                     and e1.row=e2.row+1
where e1.Activity='Login'
  and e1.Activity!=isnull(e2.Activity, 'Logout')

select e1.Activity, e1.TimeOfAction, e1.Requestor,
       row_number() over(partition by e1.Requestor order by e1.TimeOfAction) row
into #logouts
from #events e1
  left join #events e2 on e1.Requestor=e2.Requestor
                     and e1.row=e2.row-1
where e1.Activity='Logout'
  and e1.Activity!=isnull(e2.Activity, 'Login')

select i.Requestor, i.TimeOfAction as loginTime, o.TimeOfAction as logoutTime
from #logins i
  left join #logouts o on i.Requestor=o.Requestor
                      and i.row=o.row

drop table #logouts
drop table #logins
drop table #events

我尝试了类似的方法,并意识到它只会为每个请求者返回一行。我认为报告需要包含每个请求者的每个登录注销记录。谢谢,这非常接近。唯一的问题是EventLog中的minTimeOfAction部分,其中TimeOfAction>e1.TimeOfAction和Activity='Logout'返回下一次的第一次注销。如果有重复的注销,我需要重复的最后一个,但是很明显,将min更改为max只会得到整个数据集中最大的注销。是否可以在where子句中封装下一次注销的逻辑,然后是一次登录,而不仅仅是下一次注销大于当前登录记录?因为我认为两者都必须。因为如果存在重复的注销,而不仅仅是重复的登录,我需要抓取这些重复的最后一次注销,而不仅仅是集中的下一次注销。IE如果我们有:登入登出登出重复登出。在这种情况下,将其更改为max将不起作用。查询只是将每个登录记录与注销记录进行匹配。如果我理解正确,您希望最后一次注销记录正好在另一次登录记录之前,因为可能会发生多次注销?这对我来说没有太大意义,一个用户怎么能在不再次登录的情况下多次注销?这是日志系统中的一个缺陷,正在处理中,但尚未修复,因此这是一个临时解决方案。这非常有效,速度惊人。不太清楚CTE/事件是什么,但我会调查一下。谢谢,没问题。CTE Common Table Expressions本质上是一种语法,用于分离子查询并只键入一次。。。至少这就是它在这里真正要做的,但它也可以做其他事情,比如递归查询。我正试图将其转换为使用临时表,正如你所说的。对于每个表,我基本上都会使用SELECT而不是WITH关键字,因为其他一切都很相似?我在尝试从我刚创建的临时表中执行操作时,遇到一个错误“对象名称无效”。@sean,我已编辑了我的答案,以包含一种可能的方法,即使用临时表而不是CTE。使用我放在一起的示例表,实际查询计划的百分比稍微好一些。。。但这在亚秒级的查询中并不意味着什么……在执行from-on事件时会出现一些错误,例如“无效对象名称事件”,而且“多部分标识符”在任何时候都不能绑定到e1.column。似乎表一创建就被删除了-drop table命令也显示错误b/c表不存在。我在网上读到,它说这可能是权限问题或临时表作用域的问题。是否有需要更改的设置?我正在使用SQL server management studio w/SQL Express 2008 R2。
select *,
       row_number() over(partition by Requestor order by TimeOfAction) row
into #events
from EventLog

select e1.Activity, e1.TimeOfAction, e1.Requestor,
       row_number() over(partition by e1.Requestor order by e1.TimeOfAction) row
into #logins
from #events e1
  left join #events e2 on e1.Requestor=e2.Requestor
                     and e1.row=e2.row+1
where e1.Activity='Login'
  and e1.Activity!=isnull(e2.Activity, 'Logout')

select e1.Activity, e1.TimeOfAction, e1.Requestor,
       row_number() over(partition by e1.Requestor order by e1.TimeOfAction) row
into #logouts
from #events e1
  left join #events e2 on e1.Requestor=e2.Requestor
                     and e1.row=e2.row-1
where e1.Activity='Logout'
  and e1.Activity!=isnull(e2.Activity, 'Login')

select i.Requestor, i.TimeOfAction as loginTime, o.TimeOfAction as logoutTime
from #logins i
  left join #logouts o on i.Requestor=o.Requestor
                      and i.row=o.row

drop table #logouts
drop table #logins
drop table #events