Can I select rows from two tables using t1 rows as key for t2 rows? - mysql

I have two tables:
id1, id2, ... idX contains id from t2 or null. Can I make such select, which will put params from t2 in t1?
For example i have a t1(name,year,id1,id2,id3,id4) values:
name year id1 id2 id3 id4
------------------------------------------
marko 1999 1 2 null 1
polo 1985 null null 5 3
And t2 values:
id info param
--------------------------------------
1 apple green
2 car yellow
3 bee pink
4 doctor whiskey
5 book small
So I'd like to have such dynamical query results, based on t1 rows:
SELECT name, year, id1-info, id1-param, id2-info, id2-param, id4-info, id4-param
FROM t1 WHERE name = 'marko'
SELECT name, year, id3-info, id3-param, id4-info, id4-param
FROM t1 WHERE name = 'marko'
I googled a lot, but found nothing except nested queries, such as:
SELECT
name,
year,
(SELECT `info` FROM t2 WHERE id = t1.id1) AS id1-info,
(SELECT `param` FROM t2 WHERE id = t1.id1) AS id1-param,
(SELECT `info` FROM t2 WHERE id = t1.id2) AS id2-info...
But I understand, that it is a very bad idea, because I have a lot of id columns in t1, which are not static. Or if it cannot be done dynamically, can I just make SELECT, which will show me all in one row:
SELECT name, year, id1-info, id1-param, id2-info, id2-param, id3-info, id3-param, id4-info, id4-param
FROM t1 WHERE name = 'marko'

To use one select in one row, you can use mulitple left join on t2.
SELECT name,
`year`,
id11.info as `id1-info`,
id11.param as `id1-param`,
id21.info as `id2-info`,
id21.param as `id2-param`,
id31.info as `id3-info`,
id31.param as `id3-param`,
id41.info as `id4-info`,
id41.param as `id4-param`
FROM t1
LEFT JOIN t2 as id11 on t1.id1=id11.id
LEFT JOIN t2 as id21 on t1.id2=id21.id
LEFT JOIN t2 as id31 on t1.id3=id31.id
LEFT JOIN t2 as id41 on t1.id4=id41.id
WHERE name = 'marko';
result:
name year id1-info id1-param id2-info id2-param id3-info id3-param id4-info id4-param
marko 1999 apple green car yellow (null) (null) apple green

Related

SQL Join where column a in table 1 matches a value from 1 of 4 columns (a-d) in table 2

Goal:
Trying to join together two tables
Table structure:
t1:
name | id
t2:
id_a | id_b | id_c | id_d | favorite color
Problem:
I'm trying to find out the favorite color that corresponds to each name, where the t1.id is found in 1 of the 4 id fields in t2. The tricky part is that the non-matching values aren't null, so a coalesce doesn't work.
What I've tried:
Tried a case when statement in the join, but that seems to be creating some endless loop that is never finishing.
Trying a union, but that is creating some unexpected duplication.
Also tried a multi- on condition (like below), but that's not working:
WITH test AS (
SELECT
t1.*
, t2.*
FROM t1
LEFT JOIN t2
ON ( t1.id = t2.id_a
OR t1.id = t2.id_b
OR t1.id = t2.id_c
OR t1.id = t2.id_d
)
)
SELECT COUNT(*) FROM test
;
Here's an example dataset:
WITH names AS(
SELECT
1 as id , 'alfred' as name
UNION ALL SELECT 2, 'becca'
UNION ALL SELECT 3, 'charlie'
UNION ALL SELECT 4, 'dezi'
)
, color AS(
SELECT
1 as id_a, 6 as id_b, 9 as id_c, 7 as id_d, 'green' as fave_color
UNION ALL SELECT 1,2,6,5, 'orange'
UNION ALL SELECT 5,7,9,3, 'blue'
UNION ALL SELECT 9,4,6,8, 'black'
)
SELECT
n.id
, n.name
, c.fave_color
FROM color c
LEFT JOIN names n
ON n.id IN (c.id_a,c.id_b,c.id_c,c.id_d)
GROUP BY 1,2,3
ORDER BY 1,2
;

SQL Combining data from 3 tables to from a 4th table based on some conditions

I have 3 tables:-
table1 :-
ReportType | ResourceId
t2 123
t3 5
table2:-
Id | Name | Created
1 A 10
2 B 11
123 C 12
table3:-
Id | Name | Created
4 D 13
5 E 14
6 F 15
table1's ResourceId and table2 and 3's Id column have same values
I want to create a 4th table like this:-
ReportType | ResourceId | Name | Created
t2 123 C 12
t3 5 E 14
such that wherever table1's ReportType is t2 I want the Name and Created value from table2 for the condition table1.ResourceId = table2.Id and wherever table1's ResourceType is t3 I want the Name and Created value from table3 for the condition table1.ResourceId = table3.Id.
PS: This isn't some sort of HomeWork. I have been stuck at this query for the past 1 hour, I have read various answers and tried a few queries of my own before posting the question. Any help would really be appreciated.
Explanation in comments :)
--here we join first and second table, but we filter results to include only ReportType = t2
select t1.ReportType, t1.ResourceId, t2.Name, t2.Created from table1 as t1 join table2 as t2 on t1.ResourceId = t2.id
where t1.ReportType = 't2'
union all
--here we join first and third table, but we filter results to include only ReportType = t3
select t1.ReportType, t1.ResourceId, t3.Name, t3.Created from table1 as t1 join table3 as t3 on t1.ResourceId = t3.id
where t1.ReportType = 't3'
You can use the below query:
select report_type, resourceid,name, created from dbo.t2, dbo.t1
where report_type='t2' and ResourceId=id
UNION
select report_type, resourceid,name, created from dbo.t3, dbo.t1
where report_type='t3' and ResourceId=id;

Select query except another table

I got 2 tables.
TABLE 1
ID FRANCHISENAME TELEPHONE FRANCHISE_ID
1 BURGER 666-555-999 5
2 JSUBS 666-555-999 7
3 STEAKS 777-888-999 3
TABLE 2
ID NAME TELEPHONE EMAIL FRANCHISE_ ID
5 JOHN 555-444-333 JOHN#GMAIL.COM 5
5 JOHN 555-444-333 JOHN#GMAIL.COM 7
6 EDGARD 555-444-333 EDGARD#GMAIL.COM 9
I want to retrieve all data in table one, except for that data where the user has his email in Table 2. As for example JOHN has franchise_id 5 and 7, so the query would only return
3 STEAKS, 777-888-999, 3
Assuming that TABLE_1 & TABLE_2 relate to each other through TABLE_1.FRANCHISE_ID & TABLE_2.FRANCHISE_ID
You can use NOT EXISTS
SELECT
*
FROM TABLE_1 T1
WHERE NOT EXISTS(
SELECT *
FROM TABLE_2 T2
WHERE T2.FRANCHISE_ID = T1.FRANCHISE_ID
AND T2.EMAIL = 'JOHN#GMAIL.COM'
)
OR
You can use LEFT JOIN along with IS NULL
SELECT
T1.*
FROM TABLE_1 T1
LEFT JOIN TABLE_2 T2 ON T1.FRANCHISE_ID = T2.FRANCHISE_ID
WHERE T2.FRANCHISE_ID IS NULL;
SELECT t1.*
FROM
Table1 t1
LEFT JOIN Table2 t2
ON t1.FRANCHISE_ID = t2.FRANCHISE_ID
AND LEN(IFNULL(t2.EMAIL,'')) > 0
WHERE
t2.ID IS NULL
Even if there is a record in Table 2 if it has no email it will be returned by this query. You can expand say to > 7 or more to check for a minimum level of validity of email address.
This should get you there using the NOT IN function. It will exclude records from Table 1 if there is a matching Franchise ID in Table 2, unless the email field is Table 2 is null:
SELECT * FROM Table1
WHERE Table1.Franchise_ID NOT IN
(SELECT Table2.Franchise_ID FROM Table2
WHERE Table2.Email IS NOT NULL);

Joining two tables on interval basis

In SQL, suppose that I have table A
ID
--
1
3
5
and table B
ID2
---
1
2
3
4
5
6
To get the result similar to:
ID | ID2
----------
1 | 1
1 | 2
3 | 3
3 | 4
5 | 5
5 | 6
For an explanation, an element in column ID2 will be mapped to the highest value in the column ID that is less than or equal to the said element in ID2.
For example, 4 in column ID2 is mapped to 3 from column ID, because 3 is the largest value in column ID which is less than or equal to 4.
Is it possible at all to do this in sql?
What I would do is start by joining the two tables on the condition that the id in the first table is less than or equal to that in the second table, like this:
SELECT t1.id, t2.id AS id2
FROM t1
JOIN t2 ON t2.id >= t1.id;
Once you have that, you can select the maximum id from the first table, and group by the id from the second table to get the largest pairs:
SELECT MAX(t1.id) AS id, t2.id AS id2
FROM t1
JOIN t2 ON t2.id >= t1.id
GROUP BY t2.id;
SQL Fiddle seems to be down but I will update with a link as soon as I can.
SELECT MAX(A.ID) ID, B.ID2
FROM A
INNER JOIN B ON B.ID2 >= A.ID
GROUP BY B.ID2
If you only need the matching ID column:
select b.*,
(select max(ID) from a where a.ID <= b.ID2) as a_Id
from b
If you need more columns:
select *
from a
join
(
select b.*,
(select max(ID) from a where a.ID <= b.ID2) as a_Id
from b
) as b
on a.Id = b.a_Id

SQL count each distinct value in column and add name from another table where the ID matches

My SQL Skills are next to none. After looking around for the past 2 hours trying to figure this out I need some help please.
I have 2 tables as below
Table1 Table2
ID | Name Status_id
----------- ----------
1 | Open 1
2 | Closed 2
3 | On-Hold 1
What I would like to do is count the status_id in table 2 and group by the status_id. Then add the Name where the ID matches in the first column.
What I have at the moment is
SELECT status_id, COUNT(*) AS 'num' FROM table2 GROUP BY status_id
This is great so far and returns
1 | 2
2 | 1
What I need to return is
Open | 2
Closed | 1
I hope that is clear. Can anyone help?
Many thanks!
SELECT a.name, COUNT(*) AS num FROM table2 b
INNER JOIN table1 a
ON b.status_id=a.id
GROUP BY status_id
In the case that you want to also have Zero for On-Hold you'd need to do a LEFT join and count the a column from table2 instead of *
SELECT t1.name,
Count(t2.Status_id) AS num
FROM table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.Status_id
GROUP BY t1.name;
DEMO