I'm a SQL newbie, here is my Table:
+----+--------+---------+------------+
| ID | Person | Success | Message |
+----+--------+---------+------------+
| 1 | Alice | 1 | Hello |
+----+--------+---------+------------+
| 2 | Bob | 0 | World |
+----+--------+---------+------------+
| 3 | Alice | 0 | Foo |
+----+--------+---------+------------+
| 4 | Clark | 1 | Bar |
+----+--------+---------+------------+
And I want to select latest (MAX ID assuming ID is incremental) records which is success for each person
Expected result:
+----+--------+---------+------------+
| ID | Person | Success | Message |
+----+--------+---------+------------+
| 4 | Clark | 1 | Bar |
+----+--------+---------+------------+
// Alice's latest record is not success, ignore
// Bob has no success record, ignore
Here is my current approach:
SELECT *
FROM test AS t1
RIGHT JOIN (
SELECT MAX(id) AS max_id
FROM test
GROUP BY Person
) AS t2
ON t1.id = t2.max_id
WHERE t1.success = 1
// Select Max ID group by person, join with original table, then filter by success
And I'm wondering if there are better approach or neater SQL lines for this?
Thank you so much!
SELECT *
FROM test t1
WHERE Success
AND NOT EXISTS ( SELECT NULL
FROM test t2
WHERE t2.id > t1.id
AND t1.person = t2.person
AND NOT Success );
SELECT t1.*
FROM test t1
LEFT JOIN t2 ON t1.person = t2.person
AND t2.id > t1.id
AND NOT t2.Success
WHERE t1.Success
AND t2.id IS NULL;
Use ROW_NUMBER to filter down to the latest record for each person. Then, subquery and retain only success records:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Person ORDER BY ID DESC) rn
FROM test
)
SELECT ID, Person, Success, Message
FROM cte
WHERE Success = 1;
For an old school way of doing this, if perhaps you are still using MySQL 5.7, we can try:
SELECT t1.ID, t1.Person, t1.Success, t1.Message
FROM test t1
INNER JOIN
(
SELECT Person, MAX(ID) AS MAX_ID
FROM test
GROUP BY Person
) t2
ON t2.Person = t1.Person AND
t2.MAX_ID = t1.ID
WHERE
t1.Success = 1;
You could use:
select * from test t1
where exists (
select 1 from test
where success
having max(id) = t1.id
)
Sql fiddle
Alternative query:
select * from test t1
where id = (
select max(id) from test
where success
)
Sql fiddle
And I want to select latest (MAX ID assuming ID is incremental) records which is success for each person
One way to do this uses a correlated subquery like this:
select t.*
from test t
where t.status = 'success' and
t.id = (select max(t2.id) from test t2 where t2.person = t.person);
This is pretty much a direct translation of what you are asking. The condition on id is the "latest record" for each person. The status = 'success' is the filter you want.
Related
I have 2 table
Table 1
id | value
-----------
1 | a
2 | b
3 | c
4 | d
Table 2
id | table1_id | date
------------------------
1 | 1 | 01-01-2020 1:00:00
2 | 1 | 01-01-2020 2:00:00
3 | 1 | 05-01-2020 1:00:00 (*)
4 | 2 | 05-01-2020 1:00:00
5 | 3 | 06-01-2020 1:00:00
6 | 3 | 06-01-2020 2:00:00 (*)
7 | 2 | 07-01-2020 1:00:00 (*)
I want to join table 1 to table 2. get row of table 2 is max value date and group by table1_id
Like exxample, i want get data like this
id | value | table1_id | date
-------------------------------------------------
1 | a | 1 | 05-01-2020 1:00:00
2 | b | 2 | 07-01-2020 1:00:00
3 | c | 1 | 06-01-2020 2:00:00
4 | d | NULL | NULL
I tryed like this, but not work true
SELECT tb1.*, tb2.* FROM table1 AS tb1
LEFT JOIN
( SELECT * FROM table2 ORDER BY date DESC ) AS tb2
ON tb1.id = tb2.table1_id
GROUP BY table1_id
Can someone help me ? Thanks all <3
The old school way of doing this in MySQL might be to join to a subquery which finds the maximum date in the second table for each table1_id:
SELECT
t1.id,
t1.value,
t2.table1_id,
t2.date
FROM table1 t1
LEFT JOIN
(
SELECT t2.table1_id, t2.date
FROM table2 t2
INNER JOIN
(
SELECT table1_id, MAX(date) AS max_date
FROM table2
GROUP BY table1_id
) t
ON t.table1_id = t2.table1_id AND
t.max_date = t2.date
) t2
ON t2.table1_id = t1.id;
Demo
You can try this:
SELECT id, value, table1_id, max(date) date
FROM
(SELECT t1.id, t1.value, t2.table1_id, t2.date
FROM table1 t1 LEFT JOIN table2 t2
ON t1.id = t2.table1_id
) qry
GROUP BY id, value, table1_id
You can also use window function as below
SELECT tb1.*, tb2.table1_id, tb2.date
FROM table1 AS tb1
LEFT JOIN
( SELECT table2.*,
row_number() over(partition by table1_id ORDER BY date DESC) as seq_num
FROM table2 ) AS tb2
ON tb1.id = tb2.table1_id
Where tb2.seq_num = 1 ;
Here is a demo - https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f52a5a930411dcc04900a1a5bacfe6e9. The demo contains both NULL and not NULL versions.
I strongly recommend that you use window functions for this -- assuming you want mulple columns. This looks like:
select t1.*, t2.*
from table1 t1 left join
(select t2.*,
row_number() over (partition by table1_id order by date DESC) as seqnum
from table2 t2
) t2
on t1.id = t2.table1_id and seq_num = 1 ;
However, if you just want one column -- and the table1_id is redundant so I see no need to include it -- then a correlated subquery is often the fastest method:
select t1.*,
(select max(t2.date) from table2 t2 where t1.id = t2.table1_id)
from table1 t1;
In particular, this can take advantage of an index on table2(table1_id, date).
For example, I have two tables:
ID | Name
------------
1 | test 1
2 | test 2
ID2| ID | Age
--------------
1 | 1 | 18
2 | 1 | 18
3 | 1 | 19
4 | 2 | 18
5 | 2 | 19
I want to have all records that have columns which are multiple in name with age but I don't know how to do that.
I want an output like this:
Name | Age
--------------------
test 1 | 18
test 1 | 18
Can anyone help me?
Try following query:
Select t1.*, t2.*
from table1 t1
join table2 t2
on t1.id = t2.id
join (select id, age
from table2
group by id, age
having count(*) > 1
) t3
on t1.id = t2.id and t2.id = t3.id and t2.age = t3.age
Use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.name = t.name and t2.age = t.age and
t2.id <> t.id
);
With an index on (name, age, id), this should be the fastest approach.
You can also use an IN on tupples.
And a GROUP BY can be combined with a HAVING to only get those that have duplicate (name, age).
SELECT t1.Name, t2.Age
FROM YourTable2 t2
LEFT JOIN YourTable1 t1 ON t1.ID = t2.ID
WHERE (t2.ID, t2.Age) IN (
SELECT ID, Age
FROM YourTable2
GROUP BY ID, Age
HAVING COUNT(*) > 1
);
My table:
id | request | subject | date
1 | 5 | 1 | 576677
2 | 2 | 3 | 576698
3 | 5 | 1 | 576999
4 | 2 | 3 | 586999
5 | 2 | 7 | 596999
Need to select unique records by two columns(request,subject). But if we have different pairs of request-subject(2-3, 2-7), this records should be excluded from resulted query.
My query now is:
SELECT MAX(id), id, request, subject, date
FROM `tbl`
GROUP BY request, subject
having count(request) > 1
order by MAX(id) desc
How to exclude record with id=4, id=5 from this query? Thanks!
You may group by request, and then check for every group if all subjects in it are equal. You could do it using MIN() and MAX():
SELECT request, MIN(subject) AS subject
FROM table_1
GROUP BY request
HAVING MIN(subject) = MAX(subject)
As for your update, I assume you want all the fields for the max ID in the group (in your example, ID 3). The query would then look like this one:
SELECT *
FROM table_1 t
WHERE t.id IN (SELECT MAX(s.id)
FROM table_1 s
GROUP BY s.request
HAVING MIN(s.subject) = MAX(s.subject))
ORDER BY t.id
You can try this.
select * from MyTable T1
WHERE NOT EXISTS( SELECT * FROM MyTable T2
WHERE T1.id <> T2.id
and T1.request = T2.request
and T1.subject <> T2.subject)
Sql Fiddle
I have two tables.
table1:
| ID | NAME |
|----|------|
| 1 | aaa |
| 2 | aaa |
| 3 | aaa |
| 4 | bbb |
| 5 | bbb |
table2:
| ID | DATE |
|----|----------|
| 1 | 12/07/10 |
| 2 | 12/07/13 |
| 3 | 12/07/16 |
| 4 | 12/07/08 |
| 5 | 12/07/20 |
Help me pls, I don't know how to SELECT MAX ID in table1 by date in table2.
For example result should be:
for "aaa": ID 3 from table2
for "bbb": ID 5 from table2
I'm trying something like that:
DATE = (SELECT MAX(DATE) FROM table2 t2, table1 t1 WHERE t1.NAME = "aaa")
But it's not working... Have you got some idea?
You need to add an additional condition (t1.id = t2.id) for the join:
SELECT MAX(DATE)
FROM table2 t2, table1 t1
WHERE t1.NAME = "aaa"
AND t1.id = t2.id
But please - don't join with comma - use explicit JOIN syntax instead:
SELECT MAX(DATE)
FROM table2 t2
JOIN table1 t1
ON t1.id = t2.id
WHERE t1.NAME = "aaa"
You can also get all max dates for all names at once using GROUP BY name:
SELECT t1.NAME, MAX(t2.DATE)
FROM table2 t2
JOIN table1 t1
ON t1.id = t2.id
GROUP BY t1.NAME
I have tried to take the MAX Date using this query.
Note: In the table the date format should be (Y-m-d) and the field should be set to date in order to manipulate the operations
Table - 1(Name: test1)
Table - 2(Name: test2)
QUERY TO GET MAX FROM OTHER TABLE
SELECT MAX(dates) FROM test2 JOIN test1 WHERE test1.name='aaa'
OUTPUT
Hope so this query will solve your problem.
select ID from Table1 where date= (select max(date) from T2 where name= 'aaa'
i didn't fully got you. But I think this is how you want it.... If you had these two table as one table then it would work as charm.
Or THIS ,with Two Table like you asked for
SELECT T1.Id FROM T1 INNER JOIN T2
ON T1.Id = T2.Id
where T2.date = (select max(T2.date) from T1 where T1.name= 'aaa')
So i have the following table:
userid | name | referralcode
When users register on the website they put the referralcode of someone else (the referral code is the same number as the userid of someone else)
so im looking for a sql query that will output something like this
20 (this means 20 users have this userid on their referral code) , Gerardo Bastidas, Valencia
10 , Juan Bastidas, Valencia
I want to get all info on user. its all located in the same table.
Try this query:
SELECT yt1.*, COALESCE(yt2.referral_count, 0)
FROM yourtable yt1 LEFT JOIN
(
SELECT t1.userid, COUNT(*) AS referral_count
FROM yourtable t1 INNER JOIN yourtable t2
ON t1.userid = t2.referralcode
GROUP BY t1.userid
) yt2
ON yt1.userid = yt2.userid;
This query does a self-join and will list every user along with the number of referral codes where his userid appears.
This code will do the work in one query. Replace your table name with 'tbName'
Tested and working
SELECT countval, userid, email, address
FROM tbName t1 LEFT JOIN
(
SELECT COUNT(t2.userid) ASs countval, tt.userid AS xx
FROM tbName t2
GROUP BY t2.referralcode
) t3
ON t3.xx = t1.userid
Output:
+-------+-----+------+
| count | uid | name |
+-------+-----+------+
| 3 | 1 | abc |
| 2 | 2 | xyz |
| 5 | 3 | kmn |
+-------+-----+------+