[英]a question about sql group by
我有一個名為Visiting的表,看起來像這樣:
id | visitor_id | visit_time
-------------------------------------
1 | 1 | 2009-01-06 08:45:02
2 | 1 | 2009-01-06 08:58:11
3 | 1 | 2009-01-06 09:08:23
4 | 1 | 2009-01-06 21:55:23
5 | 1 | 2009-01-06 22:03:35
我想設計出一個SQL,它可以使用戶在一個會話中訪問多少次(連續訪問間隔少於1小時)。
因此,對於示例數據,我想得到以下結果:
visitor_id | count
-------------------
1 | 3
1 | 2
順便說一句,我使用PostgreSQL 8.3。 謝謝!
UPDATE :更新了示例數據表中的時間戳。 對困惑感到抱歉。
更新 :我不太在乎解決方案是否是單個sql查詢,使用存儲過程,子查詢等。我只在乎如何完成它:)
這個問題有點模棱兩可,因為您是在進行假設或要求小時數必須在設定點開始,即自然查詢也將指示在兩次訪問之間的所有訪問的結果記錄為(1,2)時間為08:58和09:58。 您將不得不“告知”查詢開始時間是出於某些確定的原因訪問了1和4,否則您將獲得自然的結果集:
visitor_id | count
--------------------
1 | 3
1 | 2 <- extra result starting at visit 2
1 | 1 <- extra result starting at visit 3
1 | 2
1 | 1 <- extra result starting at visit 5
對於我今天脆弱的頭腦來說,額外的邏輯將變得昂貴且過於復雜,Postgres上比我更好的人可能可以解決這個問題。
我通常想通過在表中添加一個sessionkey列來解決此問題,出於性能原因,我可以對其進行廉價地分組,但是我認為這也是一個邏輯問題。 從計時中獲取會話信息對我來說似乎很危險,因為我不認為在一個小時的活動之后用戶肯定會被注銷。 大多數會話系統都是通過在一段時間不活動后使會話期滿來工作的,即,很可能9:45之后的訪問將在同一會話中進行,因為您的時段將在9:08重置。
這個問題似乎有點模糊。
由於id 3在id 1和2的一小時之內,所以情況變得更加復雜,但是如果用戶在9:50進行了訪問,則該時間應該在2的一小時之內,但不是1。
您似乎希望獲得一個平滑的總數-對於一次給定的訪問,接下來的一個小時內有多少次訪問?
也許您應該問問有多少次訪問距離您不到一個小時的訪問? 如果上次訪問不到一個小時,那么它應該“計數”嗎?
因此,您可能想要的是鏈接數少於任意數量的鏈中有多少條鏈(因此,假設9:50的訪問將包含在以id 1開頭的鏈中)。
無法在單個SQL語句中執行此操作。
以下是兩個想法:一個使用循環來計算訪問次數,另一個使用visiting
表的填充方式進行更改。
但是,使用循環可以做到這一點。
(我試圖使PostgreSQL語法正確,但我不是專家)
/* find entries where there is no previous entry for */
/* the same visitor within the previous hour: */
select v1.* , 0 visits
into temp_table
from visiting v1
where not exists ( select 1
from visiting v2
where v2.visitor_id = v1.visitor_id
and v2.visit_time < v1.visit_time
and v1.visit_time - interval '1 hour' < v2.visit_time
)
select @rows = @@rowcount
while @rows > 0
begin
update temp_table
set visits = visits + 1 ,
last_time = v.visit_time
from temp_table t ,
visiting v
where t.visitor_id = v.visitor_id
and v.visit_time - interval '1 hour' < t.last_time
and not exists ( select 1
from visiting v2
where v2.visitor_id = t.visitor_id
and v2.visit_time between t.last_time and v.visit_time
)
select @rows = @@rowcount
end
/* get the result: */
select visitor_id,
visits
from temp_table
這里的想法是這樣做:
我建議:
visiting
表中添加一列: session_id int not null
session_id
設置為與該較早訪問的session id
相同。 如果不是,它將生成一個新的session_id
。 然后,您的原始查詢可以通過以下方式解決:
SELECT session_id, visitor_id, count(*)
FROM visiting
GROUP BY session_id, visitor_id
希望這可以幫助。 如果我犯了錯誤(我確定有),請發表評論,我會予以糾正。
PostgreSQL 8.4將具有窗口功能,屆時我們可以消除僅創建臨時表來模擬行號的目的(順序)
create table visit
(
visitor_id int not null,
visit_time timestamp not null
);
insert into visit(visitor_id, visit_time)
values
(1, '2009-01-06 08:45:02'),
(2, '2009-02-06 08:58:11'),
(1, '2009-01-06 08:58:11'),
(1, '2009-01-06 09:08:23'),
(1, '2009-01-06 21:55:23'),
(2, '2009-02-06 08:59:11'),
(2, '2009-02-07 00:01:00'),
(1, '2009-01-06 22:03:35');
create temp table temp_visit(visitor_id int not null, sequence serial not null, visit_time timestamp not null);
insert into temp_visit(visitor_id, visit_time) select visitor_id, visit_time from visit order by visitor_id, visit_time;
select
reference.visitor_id, count(nullif(reference.visit_time - prev.visit_time < interval '1 hour',false))
from temp_visit reference
left join temp_visit prev
on prev.visitor_id = reference.visitor_id and prev.sequence = reference.sequence - 1
group by reference.visitor_id;
這些之一或兩者都可以工作? 但是,兩者最終都會給您提供比您要求更多的結果列。
SELECT visitor_id,
date_part('year', visit_time),
date_part('month', visit_time),
date_part('day', visit_time),
date_part('hour', visit_time),
COUNT(*)
FROM visiting
GROUP BY 1, 2, 3, 4, 5;
SELECT visitor_id,
EXTRACT(EPOCH FROM visit_time)-(EXTRACT(EPOCH FROM visit_time) % 3600),
COUNT(*)
FROM visiting
GROUP BY 1, 2;
這不可能在單個SQL中完成。 更好的選擇是在存儲過程中處理它
如果是T-SQL,我將編寫為:
SELECT visitor_id, COUNT(id),
DATEPART(yy, visit_time), DATEPART(m, visit_time),
DATEPART(d, visit_time), DATEPART(hh, visit_time)
FROM visiting
GROUP BY
visitor_id,
DATEPART(yy, visit_time), DATEPART(m, visit_time),
DATEPART(d, visit_time), DATEPART(hh, visit_time)
這給了我:
1 3 2009 1 6 8
1 2 2009 1 6 21
我不知道如何或是否可以在postgre中編寫它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.