How can I create a Group_Concat field per table using values from other records - mysql

Suppose a table of First and Last Names and for each record I want to do comma-delimited list of relatives.
1ST | LAST | RELATIVES
Bob | Smith | Alice,Andrew
Alice | Smith | Bob,Andrew
Andrew |Smith | Bob,Alice
Alex | Jones | Anny, Ricky
Anny | Jones | Alex, Ricky
Ricky | Jones | Alex, Anny
As per this sqlFiddle
http://sqlfiddle.com/#!9/25d80c/1
I know how to group_contact manually for any last name but am unclear how for each record I could have it go find the records with matching last name and run the same group_concat

You can do it with a self LEFT join and aggregation:
SELECT s1.First, s1.Last,
GROUP_CONCAT(s2.First) Relatives
FROM Surnames s1 LEFT JOIN Surnames s2
ON s2.Last = s1.Last AND s2.First <> s1.First
GROUP BY s1.First, s1.Last;
See the demo.

You can put the aggregation in a lateral join, like so:
select s.First, s.Last, r.Relatives
from Surnames s,
lateral (
select group_concat(First) Relatives
from Surnames r
where s.Last = r.Last AND s.First != r.First
)r
DB<>Fiddle

Related

MySQL count records matching distinct column values

My database includes a column for people's names. Unfortunately, the column includes slight variations of people's name. I would like a query that returns a distinct list of names and the count of records for each variation.
Here is what the column looks like:
+---------------+
| Customer |
+---------------+
| Stan c. Smith |
| Stan c Smith |
| Stan c. Smith |
| Stan c Smith |
| Stan c, Smith |
| Stan c Smith |
+---------------+
I want this result:
Stan c. Smith 2
Stan c Smith 3
Stan c, Smith 1
This is my query:
SELECT
DISTINCT(`Customer`) as aCustomer, COUNT(`Customer`)
FROM
`customerTable`
where
`Customer` like "%Stan%c%Smith%"
But it only returns:
Stan c Smith 6
I have two questions:
Why does MySQL only list one result?
What do I need to do to get the results I am looking for?
Thank you.
To answer your questions:
1) Count is an aggregate function, which returns the total number of rows, by default this will return 1 value unless you use a GROUP BY
2) Use GROUP BY Customer this will group all Customers with the same name together, then running a count should result in a count of each unique instance:
SELECT
`Customer`, COUNT(`Customer`)
FROM
`customerTable`
WHERE
`Customer` like "%Stan%c%Smith%"
GROUP BY `Customer`
See the SQLFiddle for a demo
You should use group by, the below query should give you the result
SELECT
`Customer` as aCustomer, COUNT(`Customer`) as count
FROM
`customerTable`
where
`Customer` like "%Stan%c%Smith%"
group by aCustomer

How to get hobbies in student lists with subquery mysql

well, i have 100 student lists and every student has more than a hooby.
i have 2 tables,
table name = students
attribute = student_id,name,dob,address
and
table name = hobbies
attribute = hobby_id, student_id, hoby_name.
how do i get result like below.
.student_id | name | dob | address | hobby.
1 | Jordan | 12-12-1998 | 23 avenue |reading, dota2, football
2 | Bela | 13-01-1997 | 12 hills |swimming, badminton
3 | Jack | 01-02-1999 | 07 clinton|dota2
once i try to use subquery it says "subquery returns more than 1 row".
thank u guys.
select sa.student_id,name,dob,address, GROUP_CONCAT(hoby_name)
from students_attribute sa
left join hobbies_attribute ha
on sa.student_id = ha.student_id
group by sa.student_id
This will provide to required result.

Distinct values of grouped attributes in SQL

I have two tables:
Table1 name object Table2 name_old name_corr
------|-----| ---------|-----------
John | A | John | John
Ben | B | Ben | Ben
Jon | B | Jon | John
Be n | B | Be n | Ben
Peter | B | Peter | Peter
Petera| C | Petera | Peter
In my Example I have three persons, in Table1 there are some typing errors, so Table2 assigns every name to the correct name.
Now I want for every Person (John, Ben, Peter) their distinct objects.
This would be the outcome:
John A
B
Ben B
Peter B
C
This was my try, but I get an error:
Select b.name_corr, distinct(a.object) from Table1 as a join Table2 as b on (a.name=b.name_old) group by b.name_corr
Without the grouping, meaning if I select a specific name via 'where' my query works.
distinct isn't a function. It is a qualifier on select:
Select distinct b.name_corr, a.object
from Table1 a join
Table2 b
on a.name = b.name_old;
use group_concat:
Select b.name_corr, group_concat(distinct a.object) from Table1 as a join Table2 as b on (a.name=b.name_old) group by b.name_corr;
I figured out a solution for my problem. -> Double 'group by'. So simple..
Thanks for the help anyway.

Retrieve all row data using a GROUP_CONCAT

I'm using a GROUP_CONCAT() in mysql to retrieve data from a list of ID stored like this :
**Table : Visitor**
ID | name | id_visited_place
--------------------------
1 | tom | 222,235,455
**Table : Places**
ID | Country | City | Date
--------------------------------------
222 | France | Paris | 2010-08-11
235 | Belgium | Antwerp | 2009-04-24
455 | Germany | Berlin | 2009-03-17
The problem is that this query only returns one field :
SELECT visitor.*, GROUP_CONCAT(places.country) AS country FROM visitor
LEFT JOIN Places ON FIND_IN_SET(places.id, visitor.id_visited_place)
GROUP BY visitor.id
But for each ID in id_visited_place, I would like to return each fields associated to this ID, like : "I visited Paris in France on 2010-08-11"
Then just leave out the group by:
SELECT concat('I visited ', p.city, ', ', p.country, ' on ', date)
FROM visitor v left outer join
Places p
ON FIND_IN_SET(p.id, v.id_visited_place)
GROUP BY v.id
Your join is multiplying the rows to get a separate row for each place. The group by is then reducing it back to one row per visitor.
That said, your data structure should not be using sets for this purpose. The number of places visited might grow beyond the maximum set size. Also, the join is rather difficult to follow and can't take advantage of indexes.

Join 2 tables, print data from 2nd table when joined rows occur

The case:
I have 2 tables, 'contracts' and 'members' tied with contract.id = members.cid.
Each contract has one main member and several secondary members (usually the children and spouse of the main member). The main member's details (name, address etc) are stored in table contracts whereas, extra members details are kept in table members. (bad logic, i know but this was a mess to begin with and i need time to redesign the db and website)
The desired output:
When I run a batch print of all contracts (lets say, every Friday) I need to also print a copy of the contract for each member, too but with the member's details on the contract instead of the main member.
The question:
How does this translate into a mysql query? Ok, its a left join, but how do I say "print data from table members instead of contracts for the joined rows"?
Main fields that occur in the 2 tables are name + surname, those should be enough for a draft query example.
Example tables and data:
contracts
-------------------------
id | name | surname |
-------------------------
1 | Tom | Jones |
2 | Jamie | Oliver |
members
--------------------------------
id | cid | name | surname |
--------------------------------
1 | 1 | Jack | Jones |
2 | 1 | Anne | Jones |
3 | 2 | Cathy | Wilson |
So the results I want shoudld be:
cid | name | surname |
--------------------------
1 | Tom | Jones |
1 | Jack | Jones |
1 | Anne | Jones |
2 | Jamie | Oliver |
2 | Cathy | Wilson |
If i write
SELECT c.name as name, c.surname as surname, m.name as name, m.surname as surname
FROM contracts c
join members m on c.id = m.cid
I simply end up with
name and name_1, surname and surname_1 but I want ALL names to fall under name and likewise for all other matching columns.
Hope this works :::
select c1.id, c1.name, c1.surname
from contracts c1
union
(Select m.id, m.name, m.surname
from
members m left join contracts c on (c.id = m.cid))
This is what I finally did and it worked (field names are different but the syntax is what matters):
SELECT u.id, u.onoma_u, u.name_u,
coalesce(u.programa, aa.programa) as programa,
coalesce(u.barcode, aa.barcode) as barcode,
coalesce(u.plan, aa.plan) as plan,
coalesce(u.im_exp, aa.im_exp) as im_exp,
coalesce(u.symb, aa.symb) as symb
FROM (SELECT a1.id, a1.onoma_u, a1.name_u, a1.programa, a1.barcode, a1.plan, a1.im_exp, a1.symb
FROM aitisi a1
UNION
SELECT a2.id, m.name, m.surname, NULL, NULL, NULL, NULL, NULL
FROM members m
JOIN aitisi a2 ON a2.id = m.symbid) u
JOIN aitisi aa ON aa.id = u.id;
I used aliases and NULLS as dummy fields to fill in the blanks.