我有一个包含以下列的表:
[ChatID] [用户] [LogID] [CreatedOn] [文字]
我需要找到的是给定用户ID与另一个特定用户ID的平均响应时间。所以,如果我的数据如下:
[1] [john] [20] [1/1/11 3:00:00] [Hello]
[1] [john] [21] [1/1/11 3:00:23] [Anyone there?]
[1] [susan] [22] [1/1/11 3:00:43] [Hello!]
[1] [susan] [23] [1/1/11 3:00:53] [What's up?]
[1] [john] [24] [1/1/11 3:01:02] [Not much]
[1] [susan] [25] [1/1/11 3:01:08] [Cool]
...然后我需要看到Susan的平均响应时间为(20 + 6)/ 2 =>约翰13秒,约翰平均(9/1)=>苏珊花了9秒钟。
我甚至不确定可以在基于集合的逻辑中完成,但如果有人有任何想法,他们会非常感激!
答案 0 :(得分:7)
我没有PC来验证语法或任何东西,但我认为这应该给你一个起点:
WITH ChatWithRownum AS (
SELECT ChatID, User, LogID, CreatedOn, ROW_NUMBER() OVER(ORDER BY ChatID, CreatedOn) AS rownum
FROM ChatLog
)
SELECT First.ChatID, Second.User,
AVG(DATEDIFF(seconds, First.CreatedOn, Second.CreatedOn)) AS AvgElapsedTime
FROM ChatWithRownum First
JOIN ChatWithRownum Second ON First.ChatID = Second.ChatID
AND First.rownum = Second.rownum - 1
WHERE First.User != Second.User
GROUP BY First.ChatID, Second.User
本质上,我们的想法是为数据添加行号,这样您就可以将一行连接到下一行(因此您有一个语句,后面跟着它的立即响应)。加入行后,您可以获得两个条目之间经过的时间,然后按ChatID(我假设单独聊天之间的时间不相关)和两个用户对数据进行分组。就像我说的那样,这只是一个起点,因为我确信在我的查询中可能存在一些额外的标准和/或错误:)
答案 1 :(得分:3)
在进入游标之前,尝试使用以下简单的内容。
select ChatId, User, datediff('second', min(CreatedOn, max(CreatedOn))/count(*)
from ChatLog
group by ChatId, User
这个工作并且不涉及使用游标。如果我有更多的时间,我甚至可以消除临时表,但是嘿......它有效。
declare @operator varchar(50)
set @operator = 'john'
declare @customer varchar(50)
set @customer = 'susan'
declare @chatid int
set @chatid = 1
declare @t table (chatid int, username varchar(50), responsetime int)
insert @t (chatid, username, responsetime)
select ChatId,
Username,
datediff(second,
CreatedOn,
(
select min(createdon)
from chatlog
where createdon > cl.createdon
and username = @customer
and chatid = @chatid
))
from ChatLog cl
where chatid = @chatid and username = @operator
insert @t (chatid, username, responsetime)
select ChatId,
Username,
datediff(second,
CreatedOn,
(
select min(createdon)
from chatlog
where createdon > cl.createdon
and username = @operator
and chatid = @chatid
))
from ChatLog cl
where chatid = @chatid and username = @customer
select chatid, username, avg(responsetime) as avgresponsetime
from @t
group by chatid, username
order by username
答案 2 :(得分:2)
好像你需要一个游标来逐步浏览每一行并检查记录中用户的变化,并获得该时间的差异,并将其存储在某处(临时表可能),并在以后聚合。
我相信它可以在TSQL中完成,逻辑就像是:
DECLARE delta CURSOR FOR SELECT user, createdon from table order by createdon --or logid OPEN delta fetch next from delta into @username, @time while @@fetch_status = 0 begin FETCH PRIOR FROM delta into @username_prior, @time_prior IF @username_prior @username BEGIN @timedelta = @time - @time_prior @total = @total + @timedelta insert into #average (@username, @total) END fetch next from delta into @username, @time END CLOSE delta DEALLOCATE delta SELECT user, AVG(time) from #average group by user
我相信你可以弄清楚如何申报所有参数。
答案 3 :(得分:1)
WITH TableWithOrderings AS (
SELECT DateTime, ROW_NUMBER() OVER (ORDER BY DateTime) AS Ordering
FROM myTable
)
WITH Intervals As (
SELECT DATEDIFF(second, A.DateTime, B.DateTime) AS IntervalSeconds
FROM TableWithOrderings A
INNER JOIN TableWithOrderings B ON B.Ordering = A.Ordering + 1
)
SELECT AVG(IntervalSeconds) FROM Intervals
答案 4 :(得分:1)
试试这个:
create table chats
(
chat_id int not null,
user_name text not null,
log_id int not null primary key,
created_on timestamp not null,
message text not null
);
insert into chats(chat_id, user_name, log_id, created_on, message)
values(1, 'john', 20, '1/1/11 3:00:00', 'Hello'),
(1, 'john',21, '1/1/11 3:00:23', 'Anyone there?'),
(1, 'susan',22, '1/1/11 3:00:43', 'Hello!'),
(1, 'susan', 23, '1/1/11 3:00:53', 'What''s up?'),
(1, 'john', 24, '1/1/11 3:01:02', 'Not much'),
(1, 'susan', 25, '1/1/11 3:01:08', 'Cool')
示例数据:
select c.*, 'x', next.*
from chats c
left join chats next on next.log_id = c.log_id + 1
order by c.log_id
输出:
chat_id | user_name | log_id | created_on | message | ?column? | chat_id | user_name | log_id | created_on | message
---------+-----------+--------+---------------------+---------------+----------+---------+-----------+--------+---------------------+---------------
1 | john | 20 | 2011-01-01 03:00:00 | Hello | x | 1 | john | 21 | 2011-01-01 03:00:23 | Anyone there?
1 | john | 21 | 2011-01-01 03:00:23 | Anyone there? | x | 1 | susan | 22 | 2011-01-01 03:00:43 | Hello!
1 | susan | 22 | 2011-01-01 03:00:43 | Hello! | x | 1 | susan | 23 | 2011-01-01 03:00:53 | What's up?
1 | susan | 23 | 2011-01-01 03:00:53 | What's up? | x | 1 | john | 24 | 2011-01-01 03:01:02 | Not much
1 | john | 24 | 2011-01-01 03:01:02 | Not much | x | 1 | susan | 25 | 2011-01-01 03:01:08 | Cool
1 | susan | 25 | 2011-01-01 03:01:08 | Cool | x | | | | |
分组:
select c.*, 'x', next.*, count(case when next.user_name is null or next.user_name <> c.user_name then 1 end) over(order by c.log_id)
from chats c
left join chats next on next.log_id + 1 = c.log_id
order by c.log_id
输出:
chat_id | user_name | log_id | created_on | message | ?column? | chat_id | user_name | log_id | created_on | message | count
---------+-----------+--------+---------------------+---------------+----------+---------+-----------+--------+---------------------+---------------+-------
1 | john | 20 | 2011-01-01 03:00:00 | Hello | x | | | | | | 1
1 | john | 21 | 2011-01-01 03:00:23 | Anyone there? | x | 1 | john | 20 | 2011-01-01 03:00:00 | Hello | 1
1 | susan | 22 | 2011-01-01 03:00:43 | Hello! | x | 1 | john | 21 | 2011-01-01 03:00:23 | Anyone there? | 2
1 | susan | 23 | 2011-01-01 03:00:53 | What's up? | x | 1 | susan | 22 | 2011-01-01 03:00:43 | Hello! | 2
1 | john | 24 | 2011-01-01 03:01:02 | Not much | x | 1 | susan | 23 | 2011-01-01 03:00:53 | What's up? | 3
1 | susan | 25 | 2011-01-01 03:01:08 | Cool | x | 1 | john | 24 | 2011-01-01 03:01:02 | Not much | 4
(6 rows)
分组结果:
with grouped_result as
(
select c.log_id, c.user_name, count(case when next.user_name is null or next.user_name <> c.user_name then 1 end) over(order by c.log_id) as the_grouping
from chats c
left join chats next on next.log_id + 1 = c.log_id
order by c.log_id
)
select user_name, max(log_id) as last_chat_of_each_user
from grouped_result
group by the_grouping
,user_name
order by last_chat_of_each_user
输出:
user_name | last_chat_of_each_user
-----------+------------------------
john | 21
susan | 23
john | 24
susan | 25
(4 rows)
聊天和回复:
with grouped_result as
(
select c.log_id, c.user_name, count(case when next.user_name is null or next.user_name <> c.user_name then 1 end) over(order by c.log_id) as the_grouping
from chats c
left join chats next on next.log_id + 1 = c.log_id
order by c.log_id
),
last_chats as
(
select user_name as responded_to, max(log_id) as last_chat_of_each_user
from grouped_result
group by the_grouping
,responded_to
)
select lc.responded_to, lc.last_chat_of_each_user as responded_to_log_id, lc_the_chat.created_on as responded_to_timestamp, 'x', answered_by.user_name as responded_by, answered_by.created_on as response_created_on
from last_chats lc
join chats lc_the_chat on lc_the_chat.log_id = lc.last_chat_of_each_user
join chats answered_by on answered_by.log_id = lc.last_chat_of_each_user + 1
order by lc.last_chat_of_each_user
输出:
responded_to | responded_to_log_id | responded_to_timestamp | ?column? | responded_by | response_created_on
--------------+---------------------+------------------------+----------+--------------+---------------------
john | 21 | 2011-01-01 03:00:23 | x | susan | 2011-01-01 03:00:43
susan | 23 | 2011-01-01 03:00:53 | x | john | 2011-01-01 03:01:02
john | 24 | 2011-01-01 03:01:02 | x | susan | 2011-01-01 03:01:08
(3 rows)
聊天的平均响应时间:
with grouped_result as
(
select c.log_id, c.user_name, count(case when next.user_name is null or next.user_name <> c.user_name then 1 end) over(order by c.log_id) as the_grouping
from chats c
left join chats next on next.log_id + 1 = c.log_id
order by c.log_id
),
last_chats as
(
select user_name as responded_to, max(log_id) as last_chat_of_each_user
from grouped_result
group by the_grouping
,responded_to
),
responses as
(
select lc.responded_to, lc.last_chat_of_each_user as responded_to_log_id, lc_the_chat.created_on as responded_to_timestamp, answered_by.user_name as responded_by, answered_by.created_on as response_created_on
from last_chats lc
join chats lc_the_chat on lc_the_chat.log_id = lc.last_chat_of_each_user
join chats answered_by on answered_by.log_id = lc.last_chat_of_each_user + 1
order by lc.last_chat_of_each_user
)
select responded_by, responded_to, sum(response_created_on - responded_to_timestamp), count(*), avg(response_created_on - responded_to_timestamp) as average_response_to_person
from responses
group by responded_by, responded_to
输出:
responded_by | responded_to | sum | count | average_response_to_person
--------------+--------------+----------+-------+----------------------------
susan | john | 00:00:26 | 2 | 00:00:13
john | susan | 00:00:09 | 1 | 00:00:09
(2 rows)
将在Postgresql上开箱即用。要使它在Sql Server上运行,只需将response_created_on - responded_to_timestamp
更改为相应的Sql Server DATEDIFF构造(我无法回想起我的头脑是什么,DATEDIFF是几秒钟)
答案 5 :(得分:1)
这将完成工作,但我不确定它将如何扩展:
select spoke, responded, count(*) responses, avg(time_diff) avg_seconds from (
select a.user_name spoke, b.user_name responded, a.created_on spoke_at, min(b.created_on) responded_at, datediff(ss, a.created_on, min(b.created_on)) time_diff
from chats a, chats b
where a.chat_id = b.chat_id
and a.log_id < b.log_id
and not exists (select 1 from chats c where c.chat_id = a.chat_id and c.log_id < b.log_id and c.log_id > a.log_id)
group by a.user_name, b.user_name, a.created_on
) users group by spoke, responded
spoke responded responses avg_seconds
-------- ------------ ------------ --------------
john john 1 23
susan john 1 9
john susan 2 13
susan susan 1 10
选择了4条记录[获取元数据:0ms] [获取数据:0ms]
索引就可以了(chat_id,log_id)。
如果您想要消除相同的响应,那么您需要的只是外部where子句中的!=:
select spoke, responded, count(*) responses, avg(time_diff) avg_seconds from (
select a.user_name spoke, b.user_name responded, a.created_on spoke_at, min(b.created_on) responded_at, datediff(ss, a.created_on, min(b.created_on)) time_diff
from chats a, chats b
where a.chat_id = b.chat_id
and a.log_id < b.log_id
and not exists (select 1 from chats c where c.chat_id = a.chat_id and c.log_id < b.log_id and c.log_id > a.log_id)
group by a.user_name, b.user_name, a.created_on
) users
where spoke != responded
group by spoke, responded