MYSQL - Select row even if row does not join - mysql

I am trying to find one query that returns all people including the company they belong to and companies that do not have any person assigned yet.
Company
cid | cname
--------------
1 Company 1
2 Company 2
Person
pid | pname | fk_company
---------------------------
1 Person 1 1
2 Person 2 1
desired result
pid | pname | fk_company | cid | cname
----------------------------------------------
1 Person 1 1 1 Company 1
2 Person 2 1 1 Company 1
NULL NULL NULL 2 Company 2
Thanks in advance

If you want everything from both tables, regardless of match left AND right, you need a FULL JOIN:
SELECT *
FROM person
FULL JOIN company
ON person.fk_company = company.cid
edit: Apparently mysql doesn't support FULL JOIN. You'll have to do both LEFT JOINS by hand and UNION ALL them.

You should mention something you tried. Anyway, I will explain the method so you can work on it.
SELECT <column_names>FROM <table1_name> LEFT JOIN <table2_name>ON
<table1.column_name> = <table2.column_name>;
For more explanations please refer this link.
SQL Left Join

Related

Left Join and remove duplicates

I have three tables, clients, job_allocations and jobs table. I want to select all clients that are not in a particular job, below are my tables.
Clients table
id
Fullname
1
John Doe
2
Jane Doe
3
King James
4
Jere Gray
Jobs table
id
Title
1
Road Construction
2
Repair of Engines
job_allocations table
id
client_id
job_id
1
2
1
2
2
2
3
1
2
4
3
2
I want to select all clients that are not in job_id=2, but when I ran my query, I am getting client id: 2 - Jane Doe again, please how do I solve this?
I did this:
LEFT JOIN job_allocations ON job_allocations.client_id = clients.id
WHERE job_id <> 2 OR job_id IS NULL```
You can use a NOT IN clause as follows:
SELECT *
FROM clients
WHERE id NOT IN (SELECT client_id
FROM job_allocations
WHERE job_id = 2)
Check the demo here.
So you will fetch all clients, but only jobs related to job_id <> 2
This query should work for you:
SELECT client.*
FROM clients
LEFT JOIN job_allocations ON job_allocations.client_id = clients.id and job_id <> 2
Use DISTINCT keyword for selecting unique values

SQL Select parent as column name and child as value

I am creating a database to store music.
There are different categories that each have sub categories. Example:
id name parentID
1 instrumentation null
2 solo_instrument null
3 Concert Band 1
4 Brass Band 1
5 Fanfare Band 1
6 Clarinet 2
7 Saxophone 2
8 Trumpet 2
On the other hand I have a table that stores the musicID that is linked to a categoryID
id categoryID musicID
1 4 1
2 8 1
3 3 2
4 6 2
I need the following result from a query:
musicID instrumentation solo_instrument
1 Brass Band Trumpet
2 Concert Band Clarinet
I have been told to use a tree structure as in the future it is likely that other categories are added and this should be able to support that. However, I am not able to figure out how to write a query to get the result above.
I kind of get the result I want when selecting first the instrumentation, second the solo_instrument, but this is all hardcoded and does not allow for music tracks to only have one parentID as I select them individually.
Is this even possible or should I overhaul my database structure? I'd like to see your recommendations.
You should be able to tackle this using conditional aggregation.
Query :
SELECT
mu.musicID,
MAX(CASE WHEN cp.name = 'instrumentation' THEN ca.name END) instrumentation,
MAX(CASE WHEN cp.name = 'solo_instrument' THEN ca.name END) solo_instrument
FROM
musics mu
INNER JOIN categories ca ON ca.id = mu.categoryID
INNER JOIN categories cp ON cp.id = ca.parentID
GROUP by mu.musicID
The INNER JOINs pull up the corresponding category, and then goes up one level to find the parent category. If new root categories are created, you would just need to add more MAX() columns to the query.
In this DB Fiddle demo with your sample data, the query returns :
| musicID | instrumentation | solo_instrument |
| ------- | --------------- | --------------- |
| 1 | Brass Band | Trumpet |
| 2 | Concert Band | Clarinet |
First you group by musicid in table_music and the join twice to table_categories:
select t.musicid, c1.name instrumentation, c2.name solo_instrument
from (
select musicid, min(categoryid) instrumentationid, max(categoryid) solo_instrumentid
from table_music
group by musicid
) t inner join table_categories c1
on c1.id = t.instrumentationid
inner join table_categories c2
on c2.id = t.solo_instrumentid
order by t.musicid

mysql using limit in a left join not working properly

I have two tables looking like this
Patient (table 1)
id | name
------------
1 | robel
2 | dave
Patient_followup (table 2)
id | Patient_id | date_created
-----------------------
1 | ---- 1 -- | 01/01/2015
2 | -----1 -- | 01/07/2016
I want to display all the patients with their perspective latest followup data. so i tried using this query
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.date_created
Limit 1
but this is giving me only the first patient robel. i tryed removing the limit and its giving me two records of robel and one record of dave because robel has two followup data. so what should i do to get only one record of each patient ?
Try this:
Select
*
from
patient
left join
(SELECT
id as pf_id,
MAX(date_created) as latest_followup_date,
Patient_id
FROM
Patient_followup
GROUP BY
Patient_id) as pf
ON pf.Patient_id = patient.id
As mentioned by anton in the first comment, you need to use aggregation to get one record per patient.
Select patient.*,MAX(pf.date_created) as followupdate,group_concat(pf.date_created) from patient
left join Patient_followup pf on pf.Patient_id = p.patient.id
group by patient.id
order by pf.date_created
Here, you will get your values comma separated.
1) "Limit 1" will only return the first result. Typically this is used if the query will result in a very large result set and you only want the first few results.
Ex:
"LIMIT 30" will show the first 30 rows of the query.
2) I would change to setup of the tables so the query is smoother. Right now, you create a new line for each follow-up date even if the patient is already created. You could add another column in the table named "FollowUpDate". That way each patient record has the table id, patient id, creation date and followup date in the same row. That way, each patient has only one row.
EX:
Patient (table 1)
id | name | created_date | next_followup_date |
1 | Robel | 01/01/2015 | 01/01/2016 |
2 | Dave |[created_date]| [next_follup_date] |
Patient_followup (table 2)
id | Patient_id | date_created | followUpDate |
1 | 1 | 01/01/2015 | 06/01/2016 | // example date
2 | 1 | 01/01/2015 | 01/01/2016 |
3 | 2 |[date created]| [FollowUpDate] |
3) Change query to:
Use this select statement to get all patient records.
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.Patient_id
Use this select statement to get the specific patient record information.
Select * from patient
inner join Patient_followup pf on pf.Patient_id = patient.id
where patient.id = 1 //to get robel. Edit this line as necessary, perhaps by user input...
order by pf.followUpDate
NOTE: When you insert a new record in Patient_followup, make sure you update Patient.next_followup_date.
I hope this helps!

How can I join these MYSQL tables?

I'm having 2 tables. Table A contains a list of people who booked for an event, table B has a list of people the booker from table A brings with him/her. Both tables have many colums with unique data that I need to do certain calculations on in PHP , and as of now I do so by doing queries on the tables with a recursive PHP function to resolve it. I want to simplify the PHP and reduce the amount of queries that come from this recursive function by doing better MYSQL queries but I'm kind of stuck.
Because the table has way to many columns I will give an Excerpt of table A instead:
booking_id | A_customer | A_insurance
1 | 134 | 4
Excerpt of table B:
id | booking_id | B_insurance
1 | 1 | 0
2 | 1 | 1
3 | 1 | 1
4 | 1 | 3
The booking_id in table A is unique and set to auto increment, the booking_id in table b can occur many times (depending on how many guests the client from table A brings with him). Lets say I want to know every selected insurance from customer 134 and his guests, then I want the output like this:
booking_id | insurance
1 | 4
1 | 0
1 | 1
1 | 1
1 | 3
I have tried a couple of joins and this is the closest I've came yet, unfortunately this fails to show the row from A and only shows the matching rows in B.
SELECT a.booking_id,a.A_customer,a.A_insurance,b.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134
Can someone point me into the right direction ?
Please note: I have altered the table and column names for stackoverflow so it's easy for you guys to read, so it's possible that there is a typo that would break the query in it right now.
I think you need a union all for this:
select a.booking_id, a.insurance
from a
where a.a_customer = 134
union all
select b.booking_id, b.insurance
from a join
b
on a.booking_id = b.booking_id
where a.a_customer = 134;
The simplest way I can think of to achieve this is to use a UNION:
SELECT booking_id, A_insurance insurance
FROM A
WHERE booking_id = 134
UNION
SELECT booking_id, B_insurance insurance
FROM B
WHERE booking_id = 134
As my understanging of your isso is right, that should give you the result you need:
SELECT a.booking_id,a.insurance FROM a WHERE a.booking_id = 134
union
SELECT a.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134

SQL use of conditional AND on a join table to ensure at least two or multiple values are matched

I have a join table named languages_services that basically joins the table services and languages.
I need to find a service that is able to serve both ENGLISH (language_id=1) and ESPANOL (language_id=2).
table languages_services
------------------------
service_id | language_id
------------------------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 3
With the data provided above, I want to test for language_id=1 AND language_id=2 where the result would look like this
QUERY RESULT
------------
service_id
------------
1
Obviously it doesn't return the one with service_id=2 because it doesn't service Espanol.
Any tips on this is greatly appreciated!
SELECT
service_id
FROM
language_services
WHERE
language_id = 1
OR language_id = 2
GROUP BY
service_id
HAVING
COUNT(*) = 2
Or...
WHERE
lanaguage_id IN (1,2)
GROUP BY
service_id
HAVING
COUNT(*) = 2
If you're always looking at 2 languages you could do it with joins, but the aggregate version is easier to adapt to differing numbers of language_ids. (Add an OR, or add an item to the IN list, and change the COUNT(*) = 2 to COUNT(*) = 3, etc, etc).
Be aware, however, that this scales very poorly. And with this table structure there isn't much you can do about that.
EDIT Example using a join for 2 languages
SELECT
lang1.service_id
FROM
language_services AS lang1
INNER JOIN
language_services AS lang2
ON lang1.service_id = lang2.service_id
WHERE
lang1.language_id = 1
AND lang2.language_id = 2