Mysql SELECT value compare? - mysql

table like this:
-----------------------------
id pid key value
-----------------------------
1 3 all 120
2 3 today 180
3 9 all 200
4 9 today 150
5 9 others 0
-----------------------------
how to
select * from table if all(120) < today(180) and if they have same pid(3)
I hope the result should be:
---------------------------
id pid key value
---------------------------
1 3 all 120
2 3 today 180

Assuming you want all entries for which another entry with all < today exists for the same pid
select t from table t where exists(
select * from table t2 where t.all < t2.today and t.pid = t2.pid
)

Try this:
select t1.*
from yourtable t1
inner join (
select *
from yourtable
group by pid
having sum(if(`key` = 'all', `value`, 0)) < sum(if(`key` = 'today', `value`, 0))
) t2 on t1.pid = t2.pid
SQLFiddle Demo

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.

select rows with condition in other rows

I want select rows from my table with last status_Id if there is a row with status_Id = 2 for that rows
ticketStatus_Id ticket_Id status_Id
======================================
1 1 1
2 1 2 -
3 1 3 *
4 2 1
5 3 1
6 3 2 - *
7 4 1
8 4 2 -
9 4 3
10 4 4 *
I want select just rows 3, 6, 10. there are another rows with status_Id = 2 (rows 2, 6, 8) for that ticket_Id,
In other word How to select rows 3,6,10 with ticket_Id =1,3,4 that there are another row with these ticket_Ids and status_Id=2 (rows 2,6,8)
If you want the complete row, then I would view this as exists:
select t.*
from t
where exists (select 1
from t t2
where t2.ticket_id = t.ticket_id and t2.status_id = 2
) and
t.status_Id = (select max(t2.status_id)
from t t2
where t2.ticket_id = t.ticket_id
);
If you just want the ticket_id and status_id (and not the whole row), I would recommend aggregation:
select ticket_id, max(status_id)
from t
group by ticket_id
having sum(status_id = 2) > 0;
In your case, ticketStatus_Id seems to increase with status_id, so you can use:
select max(ticketStatus_Id) as ticketStatus_Id, ticket_id, max(status_id) as Status_Id
from t
group by ticket_id
having sum(status_id = 2) > 0;
First, for each ticket we get the row with the highest status. We can do this with a self-join. Each row is joined with the row with the next highest status. We select the rows which have no higher status, those will be the highest. Here's a more detailed explanation.
select ts1.*
from ticket_statuses ts1
left outer join ticket_statuses ts2
on ts1.ticket_Id = ts2.ticket_Id
and ts1.status_Id < ts2.status_Id
where ts2.ticketStatus_Id is null
3 1 3
4 2 1
6 3 2
10 4 4
11 5 3
Note that I've added a curve-ball of 11, 5, 3 to ensure we only select tickets with a status of 2, not greater than 2.
Then we can use that as a CTE (or subquery if you're not using MySQL 8) and select only those tickets who have a status of 2.
with max_statuses as (
select ts1.*
from ticket_statuses ts1
left outer join ticket_statuses ts2
on ts1.ticket_Id = ts2.ticket_Id
and ts1.status_Id < ts2.status_Id
where ts2.ticketStatus_Id is null
)
select ms.*
from max_statuses ms
join ticket_statuses ts
on ms.ticket_id = ts.ticket_id
and ts.status_id = 2;
3 1 3
6 3 2
10 4 4
This approach ensures we select the complete rows with the highest statuses and any extra data they may contain.
dbfiddle
This is basicaly a "last row per group" problem. You will find some solutions here. My prefered solution would be:
select t.*
from (
select max(ticketStatus_Id) as ticketStatus_Id
from mytable
group by ticket_Id
) tmax
join mytable t using(ticketStatus_Id)
The difference in your question is that you have a condition requiring a specific value within the group. This can be solved with a JOIN within the subquery:
select t.*
from (
select max(t1.ticketStatus_Id) as ticketStatus_Id
from mytable t2
join mytable t1 using(ticket_Id)
where t2.status_Id = 2
group by t2.ticket_Id
) tmax
join mytable t using(ticketStatus_Id)
Result:
| ticketStatus_Id | ticket_Id | status_Id |
| --------------- | --------- | --------- |
| 3 | 1 | 3 |
| 6 | 3 | 2 |
| 10 | 4 | 4 |
View on DB Fiddle
A solution using window functions could be:
select ticketStatus_Id, ticket_Id, status_Id
from (
select *
, row_number() over (partition by ticket_Id order by ticketStatus_Id desc) as rn
, bit_or(status_Id = 2) over (partition by ticket_Id) > 0 as has_status2
from mytable
) x
where has_status2 and rn = 1
A quite expressive way is to use EXISTS and NOT EXISTS subquery conditions:
select t.*
from mytable t
where exists (
select *
from mytable t1
where t1.ticket_Id = t.ticket_Id
and t1.status_Id = 2
)
and not exists (
select *
from mytable t1
where t1.ticket_Id = t.ticket_Id
and t1.ticketStatus_Id > t.ticketStatus_Id
)
SELECT a.*
FROM t a
JOIN
(
SELECT ticket_id, MAX(status_id) max_status_id
FROM t
WHERE status_id >= 2
GROUP BY ticket_id
) b
ON a.ticket_id = b.ticket_id
AND a.status_id = b.max_status_id;
SELECT
MAX(m1.ticketstatus_Id) as ticket_status,
m1.ticket_Id as ticket,
MAX(m1.status_Id) as status
FROM mytable m1
WHERE
m1.ticket_Id in (select m2.ticket_Id from mytable m2 where m2.ticket_Id=m1.ticket_Id and m2.status_Id=2)
GROUP BY m1.ticket_Id

How to join same table to check if a>b with 10

Table mytable
id numbers whereonly
1 2 1
2 35 1
3 22 1
4 20 1
5 3 1
6 70 1
7 80.15925 1
8 60 7
9 50 7
I need to order by numbers and to take id 1 to search until I found an id that have numbers row bigger with 10.
Desired result: 2, 20, 35, 70, 80.15925
Only where column whereonly is 1
Is there a way to do this?
You can give this a try:
SELECT DISTINCT t1.id AS id, t1.numbers AS numbers
FROM table AS t1
INNER JOIN table AS t2 ON t1.numbers > t2.numbers - 10
WHERE t1.whereonly = 1
GROUP BY t2.numbers
ORDER BY t1.numbers;
Here is the sqlfiddle.
Edit 1: As strawberry suggested
SELECT DISTINCT x.*
FROM mytable x
JOIN
( SELECT t2.numbers t2n
, MIN(t1.id) id
FROM mytable t1
JOIN mytable t2
ON t1.numbers > t2.numbers - 10
GROUP
BY t2.numbers
) y
ON y.id = x.id
ORDER BY x.numbers
WHERE x.whereonly = 1;
Here is the sqlfiddle.

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

how is this query done in mysql?

Given the following table ...
ID USER NUM
1 1 69
2 2 75
3 3 7
4 1 31
5 2 18
6 3 70
7 1 12
8 2 23
9 3 42
... which query would return rows with the lowest NUM for each USER?
The result should look like ...
ID USER NUM
7 1 12
5 2 18
3 3 7
Can't wrap my head around this one! Assuming it has a GROUP BY, but everything I try fails... Any pointers?
SELECT t.*
FROM tablename t
INNER JOIN (SELECT user, MIN(num) num
FROM tablename
GROUP BY user) x ON t.user = x.user AND t.num = x.num
or
SELECT t1.*
FROM tablename t1
LEFT JOIN tablename t2 ON t1.user = t2.user AND t1.num > t2.num
WHERE t2.id IS NULL
SELECT ID , MIN(NUM) as MIN_NUM , USER FROM usertable GROUP BY USER
Have a look at demo http://sqlfiddle.com/#!2/ce2fd/1
HEre is another method. UPDATED WITH THE CORRECT REREFERENCE
SQLFIDDLE
Query
select b.id, a.user, a.minnum from
mytable as b
join
(select user, min(num) as minnum
from mytable
group by user
) as a
on b.user = a.user
where b.num = a.minnum
order by a.minnum asc
limit 3
;
Results:
ID USER MINNUM
3 3 7
7 1 12
5 2 18