Combine two selects into one - mysql

I have a couple of tables. I'll try to make it simple: Table_1 ID is unique. Table_2 ID is not unique. The table_2 stores the ID from a row on table_1 and a value, resulting in, for instance, this:
table_1
ID | A
------
1 | a
2 | b
3 | c
table_2
ID | B
------
1 | x
1 | y
3 | z
I want to count how many of each ID is there on table_2, so I do
select t1.id, count(*)
from table_1 t1
group by t1.id
id | count
----------
1 | 2
3 | 1
And I want to list every row on table_2 and its corresponding value on table_1.A, so I do
select t1.id, t1.A, t2.B
from table_2 t2
left join table_1 t1
on t1.id = t2.id
ID | A | B
----------
1 | a | x
1 | a | y
3 | c | z
Is there a way to combine those 2 selections into one, to get a result like this?
ID | A | B | count
------------------
1 | a | x | 2
1 | a | y | 2
3 | c | z | 1

You can combine the results by joining the count result.
Fiddle with sample data
select t1.id, t1.A, t2.B, x.cnt as count
from t2
left join t1
on t1.id = t2.id
join (select t2.id, count(*) as cnt
from t2
group by t2.id
) x
on x.id = t1.id

Besides the generic Derived Table solution posted by #vkp you might also utilize a Scalar Subquery to return a single value:
select t1.id, t1.A, t2.B,
(select count(*)
from t2 as x
where x.id = t2.id
) cnt
from t2
http://www.sqlfiddle.com/#!9/07a3a/6

Related

Join table group by with sort desc

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).

Join two tables on specific condition

I need help in joining two tables with a specific condition. I want to left join Table_1 with Table_2 on the nearest Table_A.Col_A <= Table.Col_B
So I have two tables
Table_1
Col_A
1
2
6
Table_2
Col_A | Col_B
1 | p1
4 | p2
5 | p3
Result Table
Col_A | Col_B
1 | p1
2 | p1
6 | p3
A correlated subquery handles this:
select t1.col_a,
(select t2.col_b
from table2 t2
where t2.col_A <= t1.col_A
order by t2.col_A desc
limit 1
)
from table1 t1;
I would try doing something like this.
SELECT DISTINCT t1.col1, t2.col2
FROM Table_1 t1 JOIN Table_2 t2 on t1.col1 <= t2.col1
WHERE --something matches
However there is not much information on this post, the more details you can provide should allow us to help you better.
You can put the condition in the ON clause like this:
select
t1.Col_A, t2.Col_B
from Table_1 t1 left join Table_2 t2
on t2.Col_A = (select max(Col_A) from Table_2 where Col_A <= t1.Col_A)
See the demo.
Results:
| Col_A | Col_B |
| ----- | ----- |
| 1 | p1 |
| 2 | p1 |
| 6 | p3 |

Count records in one table where there are no records in linked table matching certain criteria

I have 2 tables:
T1:
id | name
------ | ------
1 | Bob
2 | John
3 | Joe
T2:
id | T1_id | type
------ | ------ | ------
1 | 1 | call
2 | 1 | email
3 | 1 | fax
4 | 2 | call
5 | 2 | email
6 | 2 | fax
7 | 3 | call
8 | 3 | email
I want to count the number of records in T1 which do not have a record in T2 with a type of 'fax'.
So the answer in this case would be 1 (3|Joe)
Currently I have:
SELECT count(*)
FROM `T1`
JOIN `T2` on `T1`.`id` = `T2`.`T1_id`
WHERE `T2`.`type` != 'fax'
But this is obviously counting all the records which are not 'fax'. I just cant get the logic in my head.
Any help would be appreciated!
A subquery is unnecessary:
SELECT COUNT(DISTINCT t1.id)
FROM t1
LEFT
JOIN t2
ON t2.t1_id = t1.id
AND t2.type = 'fax'
WHERE t2.id IS NULL;
select count(*)
from
(
SELECT t1.id
FROM T1
LEFT JOIN T2 on T1.id = T2.T1_id
GROUP BY t1.id
HAVING sum(T2.type = 'fax') = 0
) tmp
The answers given by Strawberry and juergen d are correct, but for completeness, here's another example using NOT EXISTS. All the queries will have different execution plans, so depending on your data in T1 and T2 YMMV:
SELECT COUNT(*)
FROM `T1`
WHERE NOT EXISTS (
SELECT *
FROM `T2`
WHERE `T2`.`T1_id` = `T1`.`id`
AND `T2`.`type` = 'fax'
)

SQL to group a similar table by name

I have two similar tables
Table 1
| id | name | amount|
| 2 | Mike | 1000 |
| 3 | Dave | 2500 |
Table 2
| id | name | amount|
| 2 | Mike | 1200 |
| 4 | James| 2500 |
I want to query the tables to get a result like this:
| id | name | amount_table1| amount_table2|
| 2 | Mike | 1000 | 1200 |
| 3 | Dave | 2500 | |
| 4 | james| | 2500 |
UNION ALL the tables. Do GROUP BY to get one row per id/name combo.
select id, name, sum(amount1), sum(amount2)
from
(
select id, name, amount as amount1, null as amount2 from table1
union all
select id, name, null, amount from table2
) dt
group by id, name
You need to do union with left and right join
select a.id , a.name , a.amount amount_table1,b.amount amount_table2 from table1 a left join table2 b on (a.id=b.id)
union
select b.id , b.name ,a.amount,b.amount from table1 a right join table2 b on (a.id=b.id)
MySql doesn't support FULL OUTER JOIN.
But it supports LEFT & RIGHT joins and UNION.
select
t1.id, t1.name, t1.amount as amount_table1, t2.amount as amount_table2
from Table1 t1
left join Table2 t2 on t1.id = t2.id
union all
select t2.id, t2.name, t1.amount, t2.amount
from Table2 t2
left join Table1 t1 on t2.id = t1.id
where t1.id is null
The first select will get those only in Table1 and those in both.
The second select will get those only in Table2.
And the UNION glues those resultsets together.
If this were for a database that supports FULL JOIN then it would be simplified to:
select
coalesce(t1.id, t2.id) as id,
coalesce(t1.name, t2.name) as name,
t1.amount as amount_table1,
t2.amount as amount_table2
from Table1 t1
full join Table2 t2 on t1.id = t2.id

SQL select MAX from other table

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')