Get multiple value in single row using join - mysql

I want to get multiple values in a single row which matches with primary table. Below are the example tables:
members:
- id
- name
- status
address:
- id
- ref_id(member id)
- address1
- state
contacts:
- id
- ref_id(member id)
- phone
- email
mem_cc
- id
- ref_id(member id)
- category_id
- coverage_id
I'm using below query to create view to get all the records in single view so I can query that view to display a list page:
SELECT a.id, a.name, a.status, b.address1, b.state, c.phone, d.category_id, d.coverage_id
FROM members a LEFT JOIN address b
ON a.id = b.ref_id
LEFT JOIN contacts c
ON a.id = c.ref_id
LEFT JOIN mem_cc d
ON a.id = d.ref_id
Now case like Member A is subscribed with 3 coverages or 3 categories then it'll show me Member A's record three times, I want to get Member A record in table single time with covering all categories and coverages in that single row. Question is how to do that?

I believe you need function "group_concat" when selecting the category:
select a.id,a.name,a.status,b.address1,b.state,c.phone,
group_concat(d.category_id, d.coverage_id)
from members a left join address b on a.id = b.ref_id
left join contacts c on a.id = c.ref_id and left join mem_cc d on a.id = d.ref_id
group by a.id

As DMorillo already said you will have to use grouping. In this way you will get one record for the user and in the different columns you can then group the results as necessary.
If you were thinking of extra columns popping up based on your joins then I don't think this is possible. See if the query below works for your case.
SELECT a.id,
a.name,
a.status,
-- This group_concat will produce something like "5th street - Alabama"
-- separated with newlines
-- Check for NULL values since you are using left joins
GROUP_CONCAT(IFNULL(CONCAT(b.address1, ' - ', b.state), ''))
DELIMITER '\n') AS address,
-- Same goes for phone numbers. Default delimiter is comma.
GROUP_CONCAT(IFNULL(c.phone, '') DELIMITER ','),
-- Now you can group your categories.
GROUP_CONCAT(IFNULL(CONCAT(d.category_id,' ', JOINEDCATEGORYNAME), '') AS category,
GROUP_CONCAT(IFNULL(CONCAT(d.coverage_id,' ', JOINEDCOVERAGENAME), '') AS coverage
FROM members a
LEFT JOIN address b ON a.id = b.ref_id
LEFT JOIN contacts c ON a.id = c.ref_id
LEFT JOIN mem_cc d ON a.id = d.ref_id
-- Here probably your inner joins to categories table and coverage table
GROUP BY a.id

Related

how to use full outer join by removing inner join

I am new to MySQL I have one query which works perfectly fine with inner join but with inner join some records got missing I want all the data from both the table but when i use full outer join or full join it gives error unknown column classroom.id in field list
here is the query
SELECT
classroom.id as id,
classroom.grade as grade,
classroom.status as status,
teacher.id as tid,
teacher.name as tname
FROM classroom
FULL JOIN teacher on classroom.teacherId = teacher.id
ORDER BY grade ASC
these are my two tables you can see in the picture enter image description here
and also I mention in column
classroom
id,grade,teacherid,status
teacher
id,email,password,name,status,role
MySQL does not support a FULL OUTER JOIN or FULL JOIN, you have to emulate it using UNION with LEFT JOIN and RIGHT JOIN.
Read more about it here: Why does MySQL report a syntax error on FULL OUTER JOIN?
So your syntax should look like this:
SELECT * FROM
(SELECT
a.id as id,
a.grade as grade,
a.status as status,
b.id as tid,
b.name as tname
FROM classroom a
LEFT JOIN teacher b ON a.teacherId = b.id
UNION
SELECT
a.id as id,
a.grade as grade,
a.status as status,
b.id as tid,
b.name as tname
FROM classroom a
RIGHT JOIN teacher b ON a.teacherId = b.id) c
WHERE c.grade != '' AND c.grade IS NOT NULL
ORDER BY c.grade ASC
UPDATE: Per your comments below, I've include a WHERE clause to remove NULL values AND empty '' values. You could also write a WHERE clause in each of the UNION queries above but I find it easier to put it in a subquery and write the WHERE clause once in the outer query. I've also added aliases a, b, c so its easier to read vs. using the table names.
Demo here.

mysql counts with group by to show all types per country include where no record is present as 0

I have the following mysql query and attempting to do group by country and type, however for all countries not all types are available but would still like to see all types for every country populated with 0.
select distinct
t1.Country,
t2.sectype,
count(t1.secid) AS SecID
from test.t2
left outer join test.t1 on test.t2.sectype= test.t1.sectype
group by t1.Country, t2.sectype;
t1 has country, sectype and secid fields and have created another table t2 which has all sectype's possible.
I get the following output:
https://i.stack.imgur.com/VAdyj.png
As you can see Germany only has 3 sectype's attached to that country but would like to see all sectype's like Canada - to be like the following output:
https://i.stack.imgur.com/ZC73H.png
Is this possible to do? Thanks
Consider a cross join of your distinct country and sectype tables. Then left join this all possible pairings to your actual data table. Finally, use a SUM condition over COUNT. Below uses table names that should be updated to your actual tables:
select cj.Country,
cj.sectype,
sum(d.secid IS NOT NULL) AS Count_SecID
from
(select n.country, s.sectype
from sectypes_table s
cross join countries_table n) cj
left outer join actual_data d
on d.sectype = cj.sectype AND d.country = cj.country
group by cj.Country,
cj.sectype;
To avoid the cross join should you have many distinct values, create such a table beforehand and replace subquery with this new table:
create table country_sectypes as (
select n.country, s.sectype
from sectypes_table s
cross join countries_table n
);
select cs.Country,
cs.sectype,
sum(d.secid IS NOT NULL) AS Count_SecID
from country_sectypes cs
left outer join actual_data d
on d.sectype = cs.sectype AND d.country = cs.country
group by cs.Country,
cs.sectype;
Rextester Demo (using actual_data for distinct country and sectype)

Return all data from 1st Table, and only 1 data from 2nd Table if exist

I am using MySql.
I have 2 tables, one is a list of names and data with primary key propertyId.
table 2 contains images with primary key propertyImageId.
Each propertyId may have multiple images or NO images at all.
I need to get a list of all the propertyId that belongs to agentId = 1, regardless whether it has images or not.
'SELECT a.*, b.*
FROM property a LEFT OUTER JOIN property_images b
ON a.propertyId = b.propertyId
INNER JOIN
( SELECT propertyId, MAX(created) maxCreated
FROM property_images
GROUP BY propertyId) c
ON b.propertyId = c.propertyId ANd b.created = c.maxCreated
WHERE agentId = 1 ');
I'm trying a similar solution provided here MySQL INNER JOIN select only one row from second table
However, it only returns propertyId if images exist. What can I do so that it will return all the propertyId from property regardless whether property_images exist or not?
Been working on this, any help will be deeply appreciated. Thank you!!
You can rewrite your query as below, The inner query gets single image per property id with highest created column value
SELECT
a.*,
b.*
FROM
property a
LEFT JOIN
(SELECT
c.*
FROM
property_images c
LEFT JOIN property_images d
ON c.propertyId = d.propertyId
AND c.created < d.created
WHERE d.propertyId IS NULL) b
ON a.propertyId = b.propertyId
WHERE a.agentId = 1

SQL - How can i get the last two characters from a column?

I have three tables.
users - user_info - districts
And I built a Inner join to get the user_id and the user_info.
Select * from users a inner join user_info b on a.id = b.user_id
But i have a column called location, inside the user_info, which returns the ID from a specific location. Just like this:
00;11
And to get the location, I have to Inner Join the user_info table, to another table called districts, because the two last characters got the ID from the district.
Thats why I would like to Inner Join all three tables, like this:
Select * from users a inner join user_info b on a.id = b.user_id inner join districts c on b.location = c.District_id
The problem is that, i want to get only the two last characters from the Location column. But i'm getting
00;11 //I would like to only get the 11
I will output everything later, using Json, and I would like to get the User info, and his location.
Is it possible to "substring" a column in SQL?
Thanks.
You could use SUBSTRING_INDEX in MySQL to get the string after the semi-colon
SELECT SUBSTRING_INDEX('00;11', ';', 2);
Or in your case:
Select SUBSTRING_INDEX(Location, ';', 2),* from users a inner join user_info b on a.id = b.user_id inner join districts c on b.location = c.District_id
Alternatively you can take the last two characters of your string using RIGHT
SELECT RIGHT('00;11', 2);
Yes, it is. See: MySQL String Functions
mysql> SELECT RIGHT('foobarbar', 4);
-> 'rbar'
For further information, please see:
SUBSTR
RIGHT

MySQL Find and show all duplicates

I'm looking to find duplicates in a DB - but also show ALL the duplicate records. My current query:
SELECT 'duplicate' as dup,c.Id, c.CreatedDate, c.email, c.Lead_Grade__c, count(c.email)
FROM contact as c
Inner Join (select c.Id, c.email FROM contact as c group by c.email having count(c.email) > 1) as dup
ON c.email = dup.email
WHERE Lead_Grade__c is null;
This works to provide 1 row for each duplicate record. I want 2 (or more) rows for each duplicate record. So, if record X AND record Y both have the same email, then I'd like to show both.
Any thoughts?
Thanks!
This will join contact to itself and only show records where the email is the same that have more than 1 record (Assuming ID is a unique value)
This results set therefor should only be duplicates.
SELECT A.*
FROM contact A
INNER JOIN CONTACT B
on A.email = B.email
and a.id <> b.ID
ORDER BY A.Email