Sum from different fields in different MySQL tables - mysql

I have these 2 tables:
table1
uid points
5 13
7 9
12 5
17 3
1 1
2 2
3 1
table2
uid points
9 21
13 17
15 11
17 7
12 6
2 2
1 3
22 1
I need a query to return top 5 users have points
Target result:
uid points
9 21
13 17
5 13
12 11
15 11
What I tried:
select uid, count(points) c from table1 order by c limit 5
union all
select uid, count(points) c from table2 order by c limit 5
But I did not get what I want.

SELECT al.uid as UID , SUM(al.points) AS total_points FROM (SELECT points, uid FROM table1
UNION ALL
SELECT points,uid FROM table2) al group by al.uid

Try This
select uid, (table1.points + table2.points) as c from table1
Left join table2 on table1.uid = table2.uid
order by (table1.points + table2.points) desc limit 5

You can try this query
Select
t3.uid , SUM(t3.points) As points
From
(SELECT * from Table1 UNION ALL SELECT * from Table2) t3
GROUP by
t3.uid
Order by
SUM(t3.points) DESC
LIMIT 5
demo at http://sqlfiddle.com/#!2/5605d/23

Try this:
SELECT Uid,SUM(Points)
FROM
(
SELECT Uid,Points FROM Table1
UNION ALL
SELECT Uid,Points FROM Table2
) as T
GROUP BY Uid
ORDER BY SUM(Points) DESC
LIMIT 5
SQLFiddle demo

If you want the top 5 overall, you need to use an order by and limit over a subquery:
select uid, sum(points) points from (
select uid, points from table1
union all
select uid, points from table2
) x
group by uid
order by sum(points) desc
limit 5

Related

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.

select id from table with max date and max id if dates are the same

For an example I have MySQL table like:
id category date value
1 a 2013-01-02 7
2 a 2013-01-01 2
3 a 2013-01-01 3
4 b 2013-01-01 1
5 b 2013-01-02 4
6 b 2013-01-03 5
7 c 2013-01-03 4
8 c 2013-01-03 8
I need select records with MAX(date) for each category, but if date is the same, with MAX(id).
So, expected result must be:
id category date value
1 a 2013-01-02 7
6 b 2013-01-03 5
8 c 2013-01-03 8
As you can see, dates for same category can be not sorted (like id=4,5).
I tried query like:
SELECT * FROM mytable t1
INNER JOIN
(
SELECT category, MAX(date) AS MAXDATE
FROM mytable
GROUP BY category
) t2
ON t1.category = t2.category
AND t1.date = t2.MAXDATE
It works fine, when we have no same dates in table. But for my case, it will return records with lowest ids:
id category date value
1 a 2013-01-01 7
6 b 2013-01-03 5
7 c 2013-01-03 4
You are on the right track but you need to change your join.
I think what you want is the following:
SELECT * FROM mytable t1
INNER JOIN
(
SELECT MAX(id) AS ID, MAX(date) AS MAXDATE
FROM mytable
GROUP BY category
) t2
ON t1.id = t2.ID
AND t1.date = t2.MAXDATE
As mentioned, the previous wont work for every use case. The following might.
SELECT a.*
FROM mytable AS a,
(
SELECT category, date, MAX(id) AS ID
FROM mytable
GROUP BY category, date
) AS b,
(
SELECT category, MAX(date) AS date
FROM mytable
GROUP BY category
) AS c
WHERE b.category = c.category
AND b.date = c.date
AND a.id = b.id

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

Selecting record from two tables with INNER join limit 3

I have records in two tables as shown below
Table1
userid email
1 123#qwe.com
4 qwe#sdf.cok
5 sad#fgdf.sdf
7 dsvh#dsf.we
9 fdsdf#fgh.hh
.
Table 2
userid values
1 15
1 45
1 76
1 15345
4 4545
4 76788
4 15879
5 4534
5 76345
5 15678
5 4567
5 7667789
7 15
7 456786
7 76678
7 15678
9 45789
9 76789
9 15789
9 4557
9 7667
9 1556
9 4556
9 764
Now I want the first 3 records from table1 with userid in descending order along with the table2 records related to them
SELECT *
FROM (SELECT TOP 3 * FROM Table1) AS Table1 INNER JOIN
Table2 ON Table1.userid = Table2.userid
ORDER BY Table1.userid
SELECT a.userid, a.email, b.values
FROM table1 a
INNER JOIN table2 b ON a.userid = b.userid
ORDER BY a.userid asc
LIMIT 0,3
SELECT * FROM (
SELECT t1.userid, t1.email, group_concat(t2.`values`) as t2values
FROM table1 t1
INNER JOIN table2 t2 ON (t1.userid = t2.userid)
GROUP BY t1.userid
ORDER BY t1.userid ASC
LIMIT 3 ) subselect
ORDER BY subselect.userid DESC
Explanation:
Group_concat is an aggregate function that will make a list of comma separated values.
Because you are using an aggregate function you need to group on userid.
The limit 3 selects the first 3 userid's (because you've ordered ASC)
Then the outer select picks up all 3 rows and reverses the order to DESC.
Links
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat