我想弄清楚网站访问。 30分钟内的每次访问都应算作该用户的一次访问。
我的表格看起来像这样
TimeUser, Userid, OrderID
10/7/2013 14:37:14 _26Tf-0PjaS0dpiZXB61Rg 151078706
10/7/2013 14:39:59 _26Tf-0PjaS0dpiZXB61Rg 151078706
10/7/2013 14:40:35 _26Tf-0PjaS0dpiZXB61Rg 151078706
10/11/2013 0:09:23 _2MrGz4L_d5AF3UHpP-oJQ 151078706
10/2/2013 20:55:05 _4Pb2wEwiQomUny_XwVuvQ 151078706
10/2/2013 20:55:06 _4Pb2wEwiQomUny_XwVuvQ 151078706
10/2/2013 20:55:06 _4Pb2wEwiQomUny_XwVuvQ 151078706
在这种情况下,151078706应该返回3次访问。 我认为我的SQL查询看起来是正确的,但当我用Excel创建的访问号码检查我的答案时,一些订单减少了5%。我百分百肯定Excel数字是正确的。
这是我到目前为止所拥有的。如果有人发现我的查询有任何问题,请纠正我。还有其他更好的方法可以找到访问吗?
SET @row_num=0,
@temp_row=1;
SELECT orderidtable.orders,
count(orderidtable.users)
FROM
(SELECT temptab.temprow,
temptab.userid users,
temptab.orderid orders,
temptab.TimeUser
FROM
(SELECT @row_num := @row_num + 1 AS rownumber, TimeUser,
userid,
orderid
FROM order.order_dec
ORDER BY orderid,
userid,
timeuser) subtable ,
(SELECT @temp_row:= @temp_row+1 AS temprow, Timeuser,
userid,
orderid
FROM
ORDER.order_dec
ORDER BY orderid,
userid,
timeuser) temptab
WHERE (subtable.rownumber=temptab.temprow
AND abs(Time_To_Sec(subtable.TimeUser)-Time_To_Sec(temptab.TimeUser))>=1800)
OR (subtable.rownumber=temptab.temprow
AND subtable.userid<>temptab.userid)
OR (subtable.rownumber=temptab.temprow
AND subtable.orderid<>temptab.orderid)) orderidtable
GROUP BY orderidtable.orders
答案 0 :(得分:1)
对行进行编号是正确的策略;您的查询在where
条件中出错了。
解决它的算法是:
orderid, userid, timeuser
排序的行数。正如您所做的那样,制作此数据集的两个副本(子表和临时表)。 在以下条件下加入这些表:
subtable.rownumber =temptab.temprow + 1
我们在这里尝试做的是以一种方式加入表格,使subtable
行与temptable
行连接,其中rownumber 1比自己的小1。我们这样做是为了能够将用户的连续访问时间与广告进行比较。 (您已经通过设置@ row_num = 0,@ temp_row = 1来完成此操作)。这是我们应该应用于JOIN的唯一条件。
现在在SELECT
语句中使用CASE
语句,如下所示
(CASE WHEN subtable.orderid = temptable.orderid AND subtable.userid = temptable.userid AND (Time_To_Sec(subtable.TimeUser)-Time_To_Sec(temptab.TimeUser))< 1800 THEN 0
ELSE 1) As IsVisit
现在在外部查询GROUP BY order_id
和SELECT
总结IsVisit。
如果您需要更清晰或让我知道它是否有效,请告诉我。
附录:
从上一个查询中,您可以尝试将where
条件替换为subtable.rownumber = temptab.temprow + 4,并在SELECT语句中使用以下内容替换上述查询的CASE
语句:
(CASE WHEN subtable.orderid = temptable.orderid AND subtable.userid = temptable.userid AND (Time_To_Sec(subtable.TimeUser)-Time_To_Sec(temptab.TimeUser))< 900 THEN 1
ELSE 0) As IsVisit
获取上一个查询和此查询返回的结果集的UNION
,然后应用GROUP BY
。
答案 1 :(得分:0)
我看到一个问题:您的查询过于复杂。 那怎么样?
现在,当您在午夜附近访问时,您的原始查询和此查询都会出错,并且在此之后不久就会再次访问 - 在这种情况下,两个查询都会将它们计为2次访问,当它们真的应该被计为一次时,如果我理解你的要求。但是,从这个简化的查询中,您可以轻松地进行必要的更改。
SELECT orderidtable.OrderID, COUNT(orderidtable.UserID) visits
FROM (
SELECT Timeuser, Userid, OrderID
FROM order.order_dec SubTab1
WHERE NOT EXISTS (
SELECT 1 FROM order.order_dec SubTab2
WHERE SubTab1.OrderID = SubTab2.OrderID
AND SubTab2.TimeUser > SubTab2.TimeUser
AND Time_To_Sec(SubTab2.TimeUser)
BETWEEN Time_To_Sec(SubTab1.OrderID)
AND Time_To_Sec(SubTab1.OrderID)+1800
)
) orderidtable
GROUP BY orderidtable.OrderID
答案 2 :(得分:0)
我认为只需一次表格全扫描即可满足您的需求。
你可以在这里测试。 http://www.sqlfiddle.com/#!2/a5dbcd/1
虽然我的查询未在许多样本数据上进行测试,但我认为如果它有错误则需要进行微小的更改。
SELECT MAX(current_uv) AS uv
FROM (
SELECT orderid, userid, timeuser,
IF(orderid != @prev_orderid, @prev_timeuser := 0, @prev_timeuser) AS prev_timeuser,
@prev_orderid := orderid AS prev_orderid,
IF(userid != @prev_userid, @prev_timeuser := 0, @prev_timeuser) AS prev_timeuser2,
@prev_userid := userid AS prev_userid,
IF(TO_SECONDS(timeuser) - @prev_timeuser > 1800, @current_uv := @current_uv + 1, @current_uv) AS current_uv,
@prev_timeuser := TO_SECONDS(timeuser) AS prev_timeuser3
FROM order_dec,
(SELECT @prev_orderid := 0, @prev_userid = '', @prev_timeuser := 0, @current_uv := 0) init
ORDER BY orderid, userid, timeuser
) x;