(SQL Server 2008)-有关CTE和联接的SQL问题:-(
如何检索以下结果(SQL Server 2008)-有关CTE和联接的SQL问题:-(,sql,sql-server-2008,join,common-table-expression,Sql,Sql Server 2008,Join,Common Table Expression,如何检索以下结果 user | date | login time | logoff time 我希望在给定的时间段内每天打印出匹配的登录和注销时间,记录为表历史。如果同一用户在同一天有多个登录,SQL应该选择登录的最小日期和注销的最大日期 这是一个用户表: CREATE TABLE [dbo].[User]( [id] [int] IDENTITY(1,1) NOT NULL, [username] [varchar](25) NOT NULL, [firstname] [nvarchar]
user | date | login time | logoff time
我希望在给定的时间段内每天打印出匹配的登录和注销时间,记录为表历史。如果同一用户在同一天有多个登录,SQL应该选择登录的最小日期和注销的最大日期
这是一个用户表:
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]
这是一个历史记录表:
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]
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
到目前为止,我可以打印出来,但只针对一个用户:
date | login time | logoff time
这是一个在SQL Server 2008上使用CTE的SQL:
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)
预期的产出将是:
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
我在朋友的帮助下解决了这个问题。这是一个解决方案:
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
还有第二个,稍微长一点:
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
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