tags:

views:

84

answers:

3

Hello,

this is my table :


-------------------------------------
| user | item   | date_time         |
|   10 |     01 | 10-10-10 20:10:05 |
|   10 |     02 | 10-10-10 20:10:10 |
|   10 |     03 | 10-10-10 20:10:10 |
|   20 |     02 | 10-10-10 20:15:10 |
|   20 |     02 | 10-10-10 20:20:10 |
|   30 |     10 | 10-10-10 20:01:10 |
|   30 |     20 | 10-10-10 20:01:20 |
|   30 |     30 | 10-10-10 20:05:20 |
-------------------------------------

i want to do a query that return a user that took multiple items in a 1min interval, like this result :


-------------------------------------
| user | item   | date_time         |
|   10 |     01 | 10-10-10 20:10:05 |
|   10 |     02 | 10-10-10 20:10:10 |
|   10 |     03 | 10-10-10 20:10:10 |
|   30 |     10 | 10-10-10 20:01:10 |
|   30 |     20 | 10-10-10 20:01:20 |
-------------------------------------

how i do this ?

--- edit ---

and if i want to only display users that appear 2 or more times on this output ? example :


-------------------------------------
| user | item   | date_time         |
|   10 |     01 | 10-10-10 20:10:05 |
|   10 |     02 | 10-10-10 20:10:10 |
|   10 |     03 | 10-10-10 20:10:10 |
-------------------------------------
+1  A: 

You'll have to join the table against itself (let's call the table aliases T1 and T2). Then write a WHERE clause to filter only rows where T1.user is equal T2.user and the absolute value of the difference between T1.date_time and T2.date_time is less than a minute.

But the problem is that every row will get selected, because you have no primary key on your table, thus there's no way to detect when a row is getting joined with itself. Create a primary key (an autonumber sequence will work just fine), and add a condition to the WHERE clause that says T1.id <> T2.id.

So in (untested) code form:

SELECT *
FROM stuff T1, stuff T2
WHERE T1.user = T2.user
  AND ABS(UNIX_TIMESTAMP(T1.date_time) - UNIX_TIMESTAMP(T2.date_time)) < 60
  AND T1.id <> T2.id;
Will
This returns too many rows when the user buys more than 2 items within the 1-minute window. On the sample data given, it returns 8 rows, not 5.
David Gelhar
A: 

let's try that one:

SELECT * FROM myTable  
JOIN (SELECT MAX(date_time) AS maxi, MIN(date_time) AS mini, user AS uid FROM myTable GROUP BY uid) AS otherTable  
ON date_time<=maxi AND date_time>=mini AND user = uid AND UNIX_TIMESTAMP(maxi) - UNIX_TIMESTAMP(mini) < 60  
GROUP BY uid, date_time
PierrOz
David Gelhar
@David: you're right I was wrong with the operator... I have edited my answer to change that
PierrOz
But that's not going to work either (try it with the sample data). You can't solve this by looking at just the max and min for a given user: for example, user 30 has 2 transactions within 1 minute, but max-min > 60.
David Gelhar
yes my bad... I missed that point. I give up as you give a satisfying answer...
PierrOz
+1  A: 

Yes, you need to add a primary key (id) as suggested by @Will.

To get each item once (and only once) regardless of how many matches there were within the 1-minute window, try a subquery instead of a full join:

Select user,item,date_time from my_table t1
  where id in (select t2.id from my_table t2,my_table t3
      where t2.id <> t3.id and t2.user = t3.user 
           and abs(t2.date_time - t3.date_time) < 60)

--edit-- For your edited question, that depends on exactly what you mean. Do you mean "users who bought 3 or more items within 60 seconds" or "users who appear more than 2 times in the output". The latter is easy to do: assume the results of the above query are saved in a temporary table (or view) "temp1":

select * from my_table where user in 
    (select user from temp1 group by user having count(*) > 2);
David Gelhar
very very nice ! this work well !but, now i need this result only appear users that have 2 or more itens in this condition, output example:-------------------------------------| user | item | date_time || 10 | 01 | 10-10-10 20:10:05 || 10 | 02 | 10-10-10 20:10:10 || 10 | 03 | 10-10-10 20:10:10 |-------------------------------------
fabriciols