使用T-SQL计算并发会话

时间:2016-05-02 14:13:56

标签: sql sql-server tsql concurrency

我在数据时间类型中拥有数据库中的sesions日期(会话的开始和结束)。我需要计算在具体时间和每个用户类型中完成的并发会话数。这意味着我需要计算每个用户和每天的同时会话数。

数据库使用SQL Server,表格如下:

SESSION GRU_ID      SES_INI                 SES_END
233550  Enfermeros  2016-02-10 07:49:32.000 2016-02-10 14:51:46.000
233551  Enfermeros  2016-02-10 07:57:05.000 2016-02-10 12:37:03.000
233552  Enfermeros  2016-02-10 08:03:09.000 2016-02-10 14:44:30.000
233553  Enfermeros  2016-02-10 08:04:49.000 2016-02-10 13:22:58.000
233556  Enfermeros  2016-02-10 08:06:52.000 2016-02-10 14:54:29.000
233559  Enfermeros  2016-02-10 08:08:00.000 2016-02-10 10:49:38.000
233560  Enfermeros  2016-02-10 08:08:09.000 2016-02-10 14:25:19.000
233564  Enfermeros  2016-02-10 08:13:54.000 2016-02-10 14:51:19.000
233565  Enfermeros  2016-02-10 08:14:35.000 2016-02-10 11:46:16.000
233567  Enfermeros  2016-02-10 08:16:01.000 2016-02-10 15:05:20.000
233568  Enfermeros  2016-02-10 08:17:01.000 2016-02-10 12:40:05.000
233569  Enfermeros  2016-02-10 08:19:13.000 2016-02-10 14:46:54.000
233570  Enfermeros  2016-02-10 08:17:50.000 2016-02-10 14:48:10.000
233579  Enfermeros  2016-02-10 08:29:52.000 2016-02-10 14:21:38.000
233580  Enfermeros  2016-02-10 08:31:11.000 2016-02-10 10:09:36.000
233584  Enfermeros  2016-02-10 08:38:52.000 2016-02-10 13:22:06.000
233585  Enfermeros  2016-02-10 08:40:11.000 2016-02-10 11:08:10.000
233589  Enfermeros  2016-02-10 08:48:09.000 2016-02-11 16:59:06.000
233603  Enfermeros  2016-02-10 09:24:56.000 2016-02-10 09:37:29.000
233607  Enfermeros  2016-02-10 09:29:31.000 2016-02-10 16:00:31.000
233623  Enfermeros  2016-02-10 10:08:34.000 2016-02-10 12:16:28.000
233624  Enfermeros  2016-02-10 10:09:36.000 2016-02-10 10:10:27.000
233625  Enfermeros  2016-02-10 10:10:51.000 2016-02-10 10:46:30.000

选择我正在使用的是下一个。问题是这个选择总结了在ses_ini和ses_end之间的这段时间内发生的会话,但它并不意味着同时发生会话。

SELECT  GRU_ID AS TIPO_USUARIO, count(GRU_ID) AS TOTAL
FROM 
        dbo.USUARIOS INNER JOIN
        dbo.SESIONES ON dbo.USUARIOS.CODIGOUSUARIO = dbo.SESIONES.CODIGOUSUARIO INNER JOIN
        dbo.GRUPOS ON dbo.USUARIOS.CODIGOGRUPO = dbo.GRUPOS.CODIGOGRUPO
WHERE 
        SES_FECHAFIN BETWEEN @SES_INI AND @SES_END AND
        DAY(ses_fechainicio) = 10 AND MONTH(ses_INI)= 2 AND YEAR(ses_END) = 2016 AND ses_duracion IS NOT NULL
GROUP BY GRU_ID

我需要某种算法来计算这些数据的所有同步会话。

编辑:

如果我有这样的话:

Session A: 9.00 - 10.00
Session B: 9.00 - 9.30
Session C: 9.30 - 9.45
Session D: 9.40 - 10:00

在第一场A会议之间,有下一个同步会议:A-B和A-C-D(会议B和C我不同时考虑) 通过我所做的选择,我得到了9.00-10.00之间的所有会话,即4,但我真的需要获得最多的同步会话,即3,我需要为每个会话执行相同的操作。

我做的完整脚本是这样的:

一个循环(同时)多年,一个循环几个月,另一个循环(嵌套循环)。然后一个光标选择一天的所有会话(使用循环)。一旦我每天获得所有会话,我进行插入(使用选择我粘贴)填充一个包含5列的表:Simultanious会话,GRU_ID(用户类型:医生,管理员,护士等)日,月和年。问题在于插入,因为我只能得到每个会话之间的会话总数,而不是同时会话。对不起,如果我解释不好,但很难,我的英语不是很好......

3 个答案:

答案 0 :(得分:1)

这个想法是将所有时间放在一个大的列表中,其中+1用于会话开始,-1用于会话结束。然后累积总和非常接近你想要的。

所以:

select gru_id, dt,
       sum(val) over (partition by gru_id order by dt) as concurrent_sessions
from ((select gru_id, ses_ini as dt, 1 as val from t
      ) union all
      (select gru_id, ses_end, -1 as val from t
      )
     ) g;

这给出了数据中每次的数字。你可能想以某种方式总结它。你现有的问题在这一点上并不清楚 - 如果你想指定一个特定的输出,你应该问另一个问题。

这是处理关系意义上的“接近”。如果用户在完全相同的时间启动和停止会话,则可能存在“一个一个”的错误,具体取决于您希望如何计算会话。

答案 1 :(得分:0)

这样的事情......计算在另一个会话期间开始或结束的会话数。然后按日期和最大数量进行汇总。

SELECT
    [GRU_ID]
    ,CAST([Ses_Ini] AS DATE) AS [Date]
    ,MAX([Sessions Count]) AS [Max Connections]
FROM (
    SELECT 
        [Data].[Session]
        ,[Data].[GRU_ID]
        ,[Data].[Ses_Ini]
        ,[Data].[Ses_End]
        ,COUNT(DISTINCT [D2].[Session]) AS [Sessions Count]
    FROM [Data]
    INNER JOIN [Data] AS [D2]
        ON ([d2].[Ses_Ini] BETWEEN [Data].[Ses_Ini] AND [Data].[Ses_End])
            OR ([d2].[Ses_End] BETWEEN [Data].[Ses_Ini] AND [Data].[Ses_End])
    GROUP BY 
        [Data].[Session]
        ,[Data].[GRU_ID]
        ,[Data].[Ses_Ini]
        ,[Data].[Ses_End]
) AS [SessionCounts]
GROUP BY
    [GRU_ID]
    ,CAST([Ses_Ini] AS DATE)

答案 2 :(得分:0)

如果新会话的ses_ini位于另一个会话的ses_inises_end之间,那么会话就是并发的。
这是实施:

create table #sess([session] int,gru_id varchar(20),ses_ini datetime,ses_end datetime)

insert #sess
values
(233550,  'Enfermeros',  '2016-02-10 07:49:32.000', '2016-02-10 14:51:46.000'),
(233551  ,'Enfermeros',  '2016-02-10 07:57:05.000', '2016-02-10 12:37:03.000'),
(233552  ,'Enfermeros',  '2016-02-10 08:03:09.000', '2016-02-10 14:44:30.000'),
(233553  ,'Enfermeros',  '2016-02-10 08:04:49.000', '2016-02-10 13:22:58.000'),
(233556  ,'Enfermeros',  '2016-02-10 08:06:52.000', '2016-02-10 14:54:29.000'),
(233559  ,'Enfermeros',  '2016-02-10 08:08:00.000', '2016-02-10 10:49:38.000'),
(233560  ,'Enfermeros',  '2016-02-10 08:08:09.000', '2016-02-10 14:25:19.000'),
(233564  ,'Enfermeros',  '2016-02-10 08:13:54.000', '2016-02-10 14:51:19.000'),
(233565  ,'Enfermeros',  '2016-02-10 08:14:35.000', '2016-02-10 11:46:16.000'),
(233567  ,'Enfermeros',  '2016-02-10 08:16:01.000', '2016-02-10 15:05:20.000'),
(233568  ,'Enfermeros',  '2016-02-10 08:17:01.000', '2016-02-10 12:40:05.000'),
(233569  ,'Enfermeros',  '2016-02-10 08:19:13.000', '2016-02-10 14:46:54.000'),
(233570  ,'Enfermeros',  '2016-02-10 08:17:50.000', '2016-02-10 14:48:10.000'),
(233579  ,'Enfermeros',  '2016-02-10 08:29:52.000', '2016-02-10 14:21:38.000'),
(233580  ,'Enfermeros',  '2016-02-10 08:31:11.000', '2016-02-10 10:09:36.000'),
(233584  ,'Enfermeros',  '2016-02-10 08:38:52.000', '2016-02-10 13:22:06.000'),
(233585  ,'Enfermeros',  '2016-02-10 08:40:11.000', '2016-02-10 11:08:10.000'),
(233589  ,'Enfermeros',  '2016-02-10 08:48:09.000', '2016-02-11 16:59:06.000'),
(233603  ,'Enfermeros',  '2016-02-10 09:24:56.000', '2016-02-10 09:37:29.000'),
(233607  ,'Enfermeros',  '2016-02-10 09:29:31.000', '2016-02-10 16:00:31.000'),
(233623  ,'Enfermeros',  '2016-02-10 10:08:34.000', '2016-02-10 12:16:28.000'),
(233624  ,'Enfermeros',  '2016-02-10 10:09:36.000', '2016-02-10 10:10:27.000'),
(233625  ,'Enfermeros',  '2016-02-10 10:10:51.000', '2016-02-10 10:46:30.000')

--select all concurrent sessions
select s.session,s1.session s1_sess,s.ses_ini,s.ses_end,s1.ses_ini s1_ini
from #sess s
inner join #sess s1 on s1.ses_ini >= s.ses_ini and s1.ses_ini < s.ses_end and s.session<>s1.session
order by 1

-- calculate the number of concurrent sessions
;with ss as (
select s.session,s1.session s1_sess,s.ses_ini,s.ses_end,s1.ses_ini s1_ini
from #sess s
inner join #sess s1 on s1.ses_ini >= s.ses_ini and s1.ses_ini < s.ses_end and s.session<>s1.session
)
select session, count(s1_sess) cnt
from ss
group by session
order by 2 desc

我希望这就是你要找的东西。

更新+添加:

declare @dtStart datetime, @dtEnd datetime

select @dtStart= convert(varchar(13),(select min(ses_ini) from #sess), 120)+':00:00' 
,@dtEnd= convert(varchar(13),dateadd(hh,1,(select max(ses_end) from #sess)), 120)+':00:00' 

;with tm as (
select 1 num, @dtStart sesStart, dateadd(hh,1,@dtStart) sesEnd
union all
select num+1,dateadd(hh,1,sesStart),dateadd(hh,1,sesEnd)
from tm where tm.sesStart<@dtEnd
)
select 'sess '+cast(num as varchar) sess,sesStart,sesEnd, count(session) cnt
from tm
inner join #sess s on (s.ses_ini>=tm.sesStart and s.ses_ini < tm.sesEnd) or 
(s.ses_end>tm.sesStart and s.ses_end <= tm.sesEnd)
group by num,sesStart,sesEnd

结果:

sess    sesStart                sesEnd                  cnt
sess 1  2016-02-10 07:00:00.000 2016-02-10 08:00:00.000 2
sess 2  2016-02-10 08:00:00.000 2016-02-10 09:00:00.000 16
sess 3  2016-02-10 09:00:00.000 2016-02-10 10:00:00.000 2
sess 4  2016-02-10 10:00:00.000 2016-02-10 11:00:00.000 5
sess 5  2016-02-10 11:00:00.000 2016-02-10 12:00:00.000 2
sess 6  2016-02-10 12:00:00.000 2016-02-10 13:00:00.000 3
sess 7  2016-02-10 13:00:00.000 2016-02-10 14:00:00.000 2
sess 8  2016-02-10 14:00:00.000 2016-02-10 15:00:00.000 8
sess 9  2016-02-10 15:00:00.000 2016-02-10 16:00:00.000 1
sess 10 2016-02-10 16:00:00.000 2016-02-10 17:00:00.000 1
sess 34 2016-02-11 16:00:00.000 2016-02-11 17:00:00.000 1

更新2:每个时间间隔内存在的会话

declare @dtStart datetime, @dtEnd datetime

select @dtStart= convert(varchar(13),(select min(ses_ini) from #sess), 120)+':00:00' 
,@dtEnd= convert(varchar(13),dateadd(hh,1,(select max(ses_end) from #sess)), 120)+':00:00' 

;with tm as (
select 1 num, @dtStart sesStart, dateadd(hh,1,@dtStart) sesEnd
union all
select num+1,dateadd(hh,1,sesStart),dateadd(hh,1,sesEnd)
from tm where tm.sesStart<@dtEnd
)
select 'sess '+cast(num as varchar) sess,sesStart,sesEnd, count(session) cnt
from tm
inner join #sess s on (s.ses_end > tm.sesStart and s.ses_ini <= tm.sesEnd) 
group by num,sesStart,sesEnd

结果:

sess    sesStart            sesEnd              cnt
sess 1  2016-02-10 07:00:00 2016-02-10 08:00:00 2
sess 2  2016-02-10 08:00:00 2016-02-10 09:00:00 18
sess 3  2016-02-10 09:00:00 2016-02-10 10:00:00 20
sess 4  2016-02-10 10:00:00 2016-02-10 11:00:00 22
sess 5  2016-02-10 11:00:00 2016-02-10 12:00:00 18
sess 6  2016-02-10 12:00:00 2016-02-10 13:00:00 16
sess 7  2016-02-10 13:00:00 2016-02-10 14:00:00 13
sess 8  2016-02-10 14:00:00 2016-02-10 15:00:00 11
sess 9  2016-02-10 15:00:00 2016-02-10 16:00:00 3
sess 10 2016-02-10 16:00:00 2016-02-10 17:00:00 2
sess 11 2016-02-10 17:00:00 2016-02-10 18:00:00 1
sess 12 2016-02-10 18:00:00 2016-02-10 19:00:00 1
sess 13 2016-02-10 19:00:00 2016-02-10 20:00:00 1
sess 14 2016-02-10 20:00:00 2016-02-10 21:00:00 1
sess 15 2016-02-10 21:00:00 2016-02-10 22:00:00 1
sess 16 2016-02-10 22:00:00 2016-02-10 23:00:00 1
sess 17 2016-02-10 23:00:00 2016-02-11 00:00:00 1
sess 18 2016-02-11 00:00:00 2016-02-11 01:00:00 1
sess 19 2016-02-11 01:00:00 2016-02-11 02:00:00 1
sess 20 2016-02-11 02:00:00 2016-02-11 03:00:00 1
sess 21 2016-02-11 03:00:00 2016-02-11 04:00:00 1
sess 22 2016-02-11 04:00:00 2016-02-11 05:00:00 1
sess 23 2016-02-11 05:00:00 2016-02-11 06:00:00 1
sess 24 2016-02-11 06:00:00 2016-02-11 07:00:00 1
sess 25 2016-02-11 07:00:00 2016-02-11 08:00:00 1
sess 26 2016-02-11 08:00:00 2016-02-11 09:00:00 1
sess 27 2016-02-11 09:00:00 2016-02-11 10:00:00 1
sess 28 2016-02-11 10:00:00 2016-02-11 11:00:00 1
sess 29 2016-02-11 11:00:00 2016-02-11 12:00:00 1
sess 30 2016-02-11 12:00:00 2016-02-11 13:00:00 1
sess 31 2016-02-11 13:00:00 2016-02-11 14:00:00 1
sess 32 2016-02-11 14:00:00 2016-02-11 15:00:00 1
sess 33 2016-02-11 15:00:00 2016-02-11 16:00:00 1
sess 34 2016-02-11 16:00:00 2016-02-11 17:00:00 1