2009-08-20 5 views
0

Comment puis-je récupérer les résultats suivants(SQL Server 2008) - question SQL concernant CTE et s'associe :-(

user | date | login time | logoff time 

Je souhaite imprimer tous les jours dans une période de temps donnée avec connexion correspondante et la fermeture de session? le temps qui est écrit est l'histoire de la table S'il y a une connexion multiple pour un même utilisateur et le même jour, puis SQL doit choisir la date minimale pour la connexion et la date maximale pour la fermeture de session

C'est une table utilisateur:..

CREATE TABLE [dbo].[User](
[id] [int] IDENTITY(1,1) NOT NULL, 
[username] [varchar](25) NOT NULL, 
[firstname] [nvarchar](50) NOT NULL, 
[lastname] [nvarchar](50) NOT NULL, 
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
[id] ASC 
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

C'est une table d'historique:

CREATE TABLE [dbo].[History](
[id] [int] IDENTITY(1,1) NOT NULL, 
[user_id] [int] NOT NULL, 
[login_time] [datetime] NOT NULL, 
[logoff_time] [datetime] NOT NULL, 
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED 
( 
[id] ASC 
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

Jusqu'à présent, je peut imprimer, mais pour un seul utilisateur:

date | login time | logoff time 

Ceci est un SQL (en utilisant CTE sur SQL Server 2008):

with CTE(d) as 
(
select d = convert(datetime, '20090801') 
union all 
select d = d + 1 from CTE where d < '20090831' 
) 

select 
d as date, 
(
    select min(h.login_time) 
    from history h 
    where 
     h.user_id = 1 and 
     h.login_time >= d and 
     h.login_time < dateadd(d, 1, d) 
) as login_time, 
(
    select max(h.logoff_time) 
    from history h 
    where 
     h.user_id = 1 and 
     h.logoff_time >= d and 
     h.logoff_time < dateadd(d, 1, d) 
) as logoff_time 
from CTE 
option (maxrecursion 370) 

Je dois inclure une certaine façon, mais je suis coincé :-(

select * 
from [user] u 
where 
exists (
    select * 
    from history h 
    where 
     h.user_id = u.id and 
     h.login_time >= '20090801' and 
     h.login_time < '20090901' 
) 

est ici l'exemple des données dans le tableau de l'histoire:

id user_id login_time   logoff_time 
1 1 2009-08-20 06:00:01.000 2009-08-20 22:07:58.230 
2 1 2009-08-20 22:10:15.137 2009-08-20 23:15:15.000 
3 2 2009-08-20 22:08:20.103 2009-08-20 22:08:20.103 
4 2 2009-08-20 22:08:23.340 2009-08-20 22:08:23.340 
5 2 2009-08-21 14:30:30.120 2009-08-21 19:20:30.000 

sortie souhaitée serait la suivante:

user date  login_time    logoff_time 
john 2009-08-01 NULL      NULL 
john 2009-08-02 NULL      NULL 
... 
john 2009-08-08 2009-08-20 06:00:01.000 2009-08-20 23:15:15.000 
... 
john 2009-08-31 NULL      NULL 
merry 2009-08-01 NULL      NULL 
merry 2009-08-02 NULL      NULL 
... 
merry 2009-08-20 2009-08-20 22:08:20.103 2009-08-20 22:08:23.340 
merry 2009-08-21 2009-08-21 14:30:30.120 2009-08-21 19:20:30.000 
... 
merry 2009-08-31 NULL      NULL 

Répondre

0

Je l'ai résolu le problème avec l'aide d'un ami. Ceci est une solution:

with dates(a_date) as (
select a_date = convert(datetime, '20090801') 
union all 
select a_date = a_date + 1 from dates where a_date < '20090831' 
) 

select 
    u.username   as username, 
    d.a_date   as a_date, 
    min(h.login_time) as login_time, 
    max(h.logoff_time) as logoff_time 
from 
    dates d 
    cross join dbo.[User] u 
    left join dbo.History h ON 
u.id = h.user_id and 
h.login_time >= d.a_date and 
h.login_time < dateadd(d, 1, d.a_date)  
group by 
    u.username, 
    d.a_date 
order by 
    u.username 

De plus, le second, peu plus:

with CTE(d) as 
(
select d = convert(datetime, '20090801') 
union all 
select d = d + 1 from CTE where d < '20090831' 
) 

select 
u.username, 
d as date, 
(
    select min(h.login_time) 
    from history h 
    where 
     h.user_id = u.id and 
     h.login_time >= d and 
     h.login_time < dateadd(d, 1, d) 
) as login_time, 
(
    select max(h.logoff_time) 
    from history h 
    where 
     h.user_id = u.id and 
     h.logoff_time >= d and 
     h.logoff_time < dateadd(d, 1, d) 
) as logoff_time 
from CTE 
cross join [User] u 
order by username, date