Get Last First Inserted zero entry mysql - mysql

Have three columns
ID User Quantity Date
1 x 0 2016-01-01
2 x 2 2016-01-02
3 x 0 2016-01-03
4 x 0 2016-01-04
5 xx 0 2016-01-01
6 xx 2 2016-01-02
7 xx 0 2016-01-03
8 xx 8 2016-01-04
9 xx 0 2016-01-06
10 xx 0 2016-01-04
Now How do i get user wise first of the latest sequence of 0 entry for x user ID=3,xx ID=9.

It's a bit complex, because we need to find the last not 0 entry for a name. (I would naturally tend to sort by date, but you said ID is what to go for.)
SELECT t1.name, max(t1.id) as check_id FROM table t1 WHERE quantity > 0 GROUP BY name
Now you can get the lowest number for each name that is higher than the given check_id:
SELECT name, min(t2.id) FROM table t2
JOIN (SELECT t1.name, max(t1.id) as check_id FROM table t1 WHERE quantity > 0 GROUP BY name) as a ON a.name=t2.name
WHERE t2.quantity = 0 AND t2.id > a.id
GROUP BY t2.name
There's one problem. It will exclude everyone with only 0 quantity. If this could happen you need another query with the following code (to get only 0 values)
SELECT name, min(id) as check_id, sum(quantity) as qty_sum FROM table
GROUP BY name
HAVING qty_sum = 0

As already mentioned, the first step is to identify the last dataset with a positive quantity by each user. The lowest ID of all following datasets would be what you seek. In other words, you need to look for MAX(ID) of all positive entries and apply MIN(ID) on all entries with a higher ID. In one query:
SELECT `User`, MIN(`ID`) FROM t `mainquery`
WHERE `ID` > (
SELECT MAX(`ID`) FROM t `subquery`
WHERE `Quantity` > 0 AND `mainquery`.`User` = `subquery`.`User`
GROUP BY `User`
)
GROUP BY `User`
With the data from your example, this query returns:
User MIN(`ID`)
x 3
xx 9
Test it here: http://sqlfiddle.com/#!9/3c487/1/0

Try This:
SELECT t1.user,min(t1.id) as ID,quantity,date from tablename t1
JOIN
(SELECT MAX(id) as qid,user FROM tablename WHERE Quantity>0 GROUP BY user) t2
ON t2.user=t1.user
WHERE t1.id>t2.qid
AND t1.Quantity=0
GROUP BY t1.user

Related

Updating table based on same table with a max value

Have a table data structure like below:
id
regid
docid
archived
1
1000
1
0
2
1000
2
0
3
1000
3
0
4
2000
1
0
5
2000
2
0
6
3000
1
0
7
3000
2
0
8
3000
3
0
9
3000
4
0
What I'm trying to do update the archived column to 1 where the docid is less than the max docid, by each regid group.
So I should end up with id's 3, 5 & 9 not being set to 1
Have tried:
update table t1
join (select max(docid) as maxdocid, regid from table) t2 on t1.docid < t2.maxdocid and t1.regid = t2.regid
set t1.archived = 1
But doesn't work, only does the first regid group.
Here's a solution (in MySQL 8.0+) using a CTE:
WITH numbered_table AS (
SELECT id, ROW_NUMBER() OVER (PARTITION BY regid ORDER BY docid DESC) AS rownum
FROM mytable
)
UPDATE mytable JOIN numbered_table USING (id)
SET archived = 1
WHERE rownum > 1
AND archived = 0;
Second solution, if you use an older version of MySQL that doesn't support CTE syntax:
You don't really need to compute the max docid value. If you want to update all rows except for the row with the max docid value, then you can check if a row can be matched to any other row with a greater docid value.
UPDATE mytable AS t1
INNER JOIN mytable AS t2 ON t1.regid = t2.regid AND t1.docid < t2.docid
SET t1.archived = 1
WHERE t1.archived = 0;
This will be true for all rows except the row with the max value. That row will be excluded automatically by the join.
In steps:
Create a query with the MAX value, per docid:
SELECT
ID,
regid,
docid,
(SELECT MAX(docid) FROM t1 te where te.regid=t.regid) as M
FROM t1 t
Join the result, and update:
UPDATE t1
JOIN (
SELECT
ID,
regid,
docid,
(SELECT MAX(docid) FROM t1 te where te.regid=t.regid) as M
FROM t1 t
) x ON t1.id=x.id
SET archived = 1
WHERE t1.docid<x.M AND t1.archived=0;
see: DBFIDDLE
You could try:
update test_tbl t1
set t1.archived = 1
where t1.archived = 0
and t1.id not in ( select t2.id
from (select max(id) as id,
regid,
max(docid)
from test_tbl
group by regid
) as t2
) ;
Result:
id regid docid archived
1 1000 1 1
2 1000 2 1
3 1000 3 0
4 2000 1 1
5 2000 2 0
6 3000 1 1
7 3000 2 1
8 3000 3 1
9 3000 4 0
Demo
Or you can use a LEFT JOIN
update test_tbl t1
left join ( select max(id) as id,
regid,
max(docid) as docid
from test_tbl
group by regid
) as t2 on t1.id=t2.id
set t1.archived = 1
where t1.archived = 0
and t2.id IS NULL
Demo
Use a self join in the update statement:
UPDATE tablename t1
INNER JOIN tablename t2
ON t2.regid = t1.regid AND t2.docid > t1.docid
SET t1.archived = 1;
See the demo.

On average, how many times a user came before making first purchase?

id(pk) user_id(int) came_to_site(date_time) purchases(int)
1 1 27-8-2016:10:12:23 0
2 2 27-8-2016:10:20:23 0
3 1 28-8-2016:10:12:23 1
4 3 29-8-2016:10:12:23 0
5 4 29-8-2016:11:40:23 0
6 4 30-8-2016:10:12:23 0
7 4 30-8-2016:12:12:23 1
8 1 30-8-2016:12:30:23 1
I have this table, I want to know, on average, how many times a user came before making first purchase.
We can ignore user 2 and 3 because they never made a purchase.
User 1 came 2 times before making a purchase.
User 4 came 3 times before making a purchase.
So average would be (2 + 3)/2 = 2.5
Any idea how can I write such a query?
select avg(cnt)
from
(
select user_id, 1 + count(*) as cnt
from tablename t1
where purchases = 0
and exists (select 1 from tablename t2
where t2.user_id = t1.user_id
and t2.purchases = 1)
and not exists (select 1 from tablename t3
where t3.user_id = t1.user_id
and t3.purchases = 1
and t3.came_to_site < t1.came_to_site)
group by user_id
)
The sub-query counts each user_id that has made a purchase (EXISTS), but not before current row (NOT EXISTS).
At main level, do AVG() to get average number.
Perhaps, depending on dbms, you need to do avg(cnt * 1.0) to avoid integer result.
Find the first purchase date of all users that made a purchase, then join to that:
select avg(visits)
from (select t.user_id, count(*) visits
from (select user_id, min(came_to_site) first
from mytable
where purchases > 0
group by user_id) fpd
join mytable t on t.user_id = fpd.user_id and t.came_to_site < fpd.came_to_site) x
With an index on user_id this will perform pretty well.
You could do :
SELECT AVG(cpt) FROM (
SELECT sales_user.user_id, COUNT(*) AS cpt
FROM (
SELECT *
FROM users
WHERE purchases=1) sales_user
JOIN users ON sales_user.user_id=users.user_id
WHERE users.came_to_site < sales_user.came_to_site
GROUP BY sales_user.user_id);

Get distinct values in union all in hive

I have a table in hive that looks something like this
cust_id prod_id timestamp
1 11 2011-01-01 03:30:23
2 22 2011-01-01 03:34:53
1 22 2011-01-01 04:21:03
2 33 2011-01-01 04:44:09
3 33 2011-01-01 04:54:49
so on and so forth.
For each record I want to check that how many unique products has this customer bought within the last 24 hrs excluding the current transaction. So the output should look something like this -
1 0
2 0
1 1
2 1
3 0
My hive query looks something like this
select * from(
select t1.cust_id, count(distinct t1.prod_id) as freq from temp_table t1
left outer join temp_table t2 on (t1.cust_id=t2.cust_id)
where t1.timestamp>=t2.timestamp
and unix_timestamp(t1.timestamp)-unix_timestamp(t2.timestamp) < 24*60*60
group by t1.cust_id
union all
select t.cust_id, 0 as freq from temp_table t2
)unioned;
Just get all the rows for last 24 hours do a group by on custid and count(distinct productid) -1 as the output. Overall query would look something like this.
select cust_id, COUNT(distinct prod_id) - 1 from table_name where
unix_timestamp(t1.timestamp)-unix_timestamp(t2.timestamp) < 24*60*60
GROUP BY cust_id
*I am subtracting 1 here to exclude the latest transactionid of the user. (hope this is what you meant)
You can join to a derived table that contains the distinct # of products purchased in the past 24 hours for each customer/timestamp pair.
select t1.cust_id, t1.prod_id, t1.timestamp, t2.count_distinct_prod_id - 1
from mytable t1
join (
select t2.cust_id, t2.timestamp, count(distinct t3.prod_id) count_distinct_prod_id
from mytable t2
join mytable t3 on t3.cust_id = t2.cust_id
where unix_timestamp(t2.timestamp) - unix_timestamp(t3.timestamp) < 24*60*60
group by t2.cust_id, t2.timestamp
) t2 on t1.cust_id = t2.cust_id and t1.timestamp = t2.timestamp

Group dates based on variable periods

i have two tables as follows------
table-1
CalenderType periodNumber periodstartdate
1 1 01-01-2013
1 2 11-01-2013
1 3 15-01-2013
1 4 25-01-2013
2 1 01-01-2013
2 2 15-01-2013
2 3 20-01-2013
2 4 25-01-2013
table2
Incidents Date
xyz 02-01-2013
xxyyzz 03-01-2013
ccvvb 12-01-2013
vvfg 16-01-2013
x3 17-01-2013
x5 24-01-2013
Now i want to find out the number of incidents took place in a given period(the Calendar type may change on runtime like)
the query should look something like this
select .......
from ......
where CalendarType=1
which should return
CalendarType PeriodNumber Incidents
1 1 2
1 2 1
1 3 3
1 4 0
can someone suggest me an approach or any method how this can be achieved.
Note:each period is variable in size.peroid1 may have 10 days period2 may have 5 days etc.
I think this does what you want, although I don't understand how you arrived at your sample output:
select t.CalenderType, t.periodNumber, count(*) as Incidents
from Table1 t
inner join (
select t2.Date, t2.Incidents, max(t1.periodstartdate) as PeriodStartDate
from Table2 t2
inner join Table1 t1 on t2.Date >= t1.periodstartdate
where CalenderType = 1
group by t2.Date, t2.Incidents
) a on t.periodstartdate = a.PeriodStartDate
where CalenderType=1
group by t.CalenderType, t.periodNumber
SQL Fiddle Example
Try this, a bit more general solution,SQLFiddle (Thanks RedFilter for schema):
SELECT t1.CalenderType, t1.periodNumber, count(Incidents)
FROM Table1 t1, Table1 t11, Table2
WHERE
(
(
t1.CalenderType = t11.CalenderType
AND t1.periodNumber = t11.periodNumber - 1
AND Date BETWEEN t1.periodstartdate AND t11.periodstartdate
)
OR
(
t1.periodNumber = (SELECT MAX(periodNumber) FROM Table1 WHERE t1.CalenderType = CalenderType)
AND Date > t1.periodstartdate
)
)
GROUP BY t1.CalenderType, t1.periodNumber
ORDER BY t1.CalenderType, t1.periodNumber

Select distinct values from two columns

I have a table with the following structure:
itemId | direction | uid | created
133 0 17 1268497139
432 1 140 1268497423
133 0 17 1268498130
133 1 17 1268501451
I need to select distinct values for two columns - itemId and direction, so the output would be like this:
itemId | direction | uid | created
432 1 140 1268497423
133 0 17 1268498130
133 1 17 1268501451
In the original table we have two rows with the itemId - 133 and direction - 0, but we need only one of this rows with the latest created time.
Thank you for any suggestions!
Use:
SELECT t.itemid,
t.direction,
t.uid,
t.created
FROM TABLE t
JOIN (SELECT a.itemid,
MAX(a.created) AS max_created
FROM TABLE a
GROUP BY a.itemid) b ON b.itemid = t.itemid
AND b.max_created = t.created
You have to use an aggregate (IE: MAX) to get the largest created value per itemid, and join that onto an unaltered copy of the table to get the values associated with the maximum created value for each itemid.
select t1.itemid, t1.direction, t1.uid, t1.created
from (select t2.itemid, t2.direction, t2.created as maxdate
from tbl t2
group by itemid, direction) x
inner join tbl t1
on t1.itemid = x.itemid
and t1.direction = x.direction
and t1.created = x.maxdate