SQL查询找不到正确的答案

时间:2014-01-31 23:00:33

标签: mysql sql

我想弄清楚网站访问。 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

3 个答案:

答案 0 :(得分:1)

对行进行编号是正确的策略;您的查询在where条件中出错了。

解决它的算法是:

  1. orderid, userid, timeuser排序的行数。正如您所做的那样,制作此数据集的两个副本(子表和临时表)。
  2. 在以下条件下加入这些表:

    subtable.rownumber =temptab.temprow + 1 
    

    我们在这里尝试做的是以一种方式加入表格,使subtable行与temptable行连接,其中rownumber 1比自己的小1。我们这样做是为了能够将用户的连续访问时间与广告进行比较。 (您已经通过设置@ row_num = 0,@ temp_row = 1来完成此操作)。这是我们应该应用于JOIN的唯一条件。

  3. 现在在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

  4. 现在在外部查询GROUP BY order_idSELECT总结IsVisit。

  5. 如果您需要更清晰或让我知道它是否有效,请告诉我。

    附录: 从上一个查询中,您可以尝试将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;