Comma separated MYSQL CONCAT from 2 tables - mysql

How to you group concat 2 simple tables so the the output is:
John | One, Two
Luke | One, Two
I have seem some other examples, but I don't appear to make sense of it. Im a complete NOOB
users table
|name|names|
|John|001|
|John|002|
|Luke|001|
|Luke|002|
servers table
|id|name|
|001|One|
|002|Two|
MYSQL statement
SELECT *
FROM users
INNER JOIN servers
ON users.names = servers.names
Produces:
John | One
John | Two
Luke | One
Luke | Two

Use GROUP_CONCAT as follows:
SELECT u.name, GROUP_CONCAT(s.name ORDER BY s.id) names
FROM users u
LEFT JOIN servers s ON s.id = u.names
GROUP BY u.name;
Demo

Related

How to do a proper Inner join?

I have this app where I need to do a query and have two columns.This are my two columns and respective rows:
Name of table1: Machines(has a row called Machinesnames and a id_group as FK)
Name of table2: Groups (has a row called groupsnames and id_groups as PK)
The problem is that with the query you see below I am getting the following result
**GroupsNames** | **MachinesNames**
1 machine1
1 | machine2
1 | machine3
2 | machine4
I have done this but I think is wrong can you correct my query please?:
SELECT groups.name,Machines. Machinesnames,Groups.groupsnames FROM Machines INNER JOIN Groups ON Machines.id_group = Groups.id_group
This is the result I want to see
**GroupsNames** | **MachinesNames**
1 machine1,machine2,machine3
2 | machine4
You are looking for group_concat:
select g.name,
group_concat(m.Machinesnames)
from Machines m
inner join Groups g on m.id_group = g.id_group
group by g.name;
Your query is correct for a inner join, but from looking at your expected output you are wanting a aggregated list.
Try this answer for MySQL using GROUP_CONCAT()
Aggregate function in MySQL - list (like LISTAGG in Oracle)

Mysql select between two table without limiting if record appear on the joined table

I have been trying to figure out how to select data related to one id between to tables without limit it to the joined table. I tried using UNION, Inner join, JOIN, but it limit me to show records that are only in both tables. By example:
Table 1 (users)
id | name | register
1 | John | 2014-03-01
2 | Kate | 2014-03-02
etc..
Table 2 (birthdays by example)
id | user | birthday
1 | 1 | 1989-09-09
Note that kate dont have a record on the birthdays table, if i do:
SELECT U.id, name, register, B.birthday FROM users as U INNER JOIN birthday as B ON B.user = U.id
it will only shows JOHN data, i would like to select all my users and if the record do not exist on the joined table, still be able to select all my users, sort of:
id | name | register | birthday
1 | John | 2014-03-01 | 1989-09-09
2 | kate | 2014-03-02 | null or ''
3
4
etc.
Sorry if its a stupid question but i dont find the light on this one. I would appreciate the help.
Regards
You need a LEFT OUTER JOIN instead of the plain JOIN (also known as INNER JOIN), like this:
SELECT U.id, name, register, B.birthday
FROM users as U
LEFT JOIN birthday as B
ON B.user = U.id
A LEFT JOIN between users and birthday tables will contain all records of the "left" table (users), even if the join-condition does not find any matching record in the "right" table (birthday).
This excellent article on The Code Project will help you a lot: Visual Representation of SQL Joins.
Summary of all JOIN types:
Note: Mysql does not support FULL OUTER JOIN but it can be emulated. Useful articles:
https://stackoverflow.com/a/4796911
http://www.sql-tutorial.ru/en/book_full_join_and_mysql.html
http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/
Use left outer join instead of inner join..
SELECT U.id, name, register, B.birthday
FROM users as U left join birthday as B ON B.user = U.id

COUNT(*) FROM different tables with LEFT JOIN

I have 1 table of users, and 10 tables (articles, news, ...) where I save user's publications. I want to show how many publications has each user, in one query:
| ID_USER | COUNT(id_article) | COUNT(id_news) | etc...
-------------------------------------------------
| 1 | 0 | 3 |
| 2 | 2 | 9 |
| 3 | 14 | 5 |
| 4 | 0 | 0 |
If I use this query to show the number of articles...
SELECT id_user,COUNT(articles.id_article) FROM users
LEFT JOIN articles ON articles.id_user_article=users.id_user
GROUP BY users.id_user
... it shows the information correctly. But if I start to add the second table...
SELECT id_user,COUNT(articles.id_article),COUNT(news.id_news) FROM users
LEFT JOIN articles ON articles.id_user_article=users.id_user
LEFT JOIN news ON news.id_user_news=users.id_user
GROUP BY users.id_user
... it doesn't show the correct information.. and if I join all the rest tables, if shows really strange result (thousands of articles for first user, and NULL for the rest).
Which is the correct way of show this information using only one query? Thank you!
You can use a subselect instead of a left join for each table. The final result will be the same but maybe in that way is clearer.
SELECT u.id_user,
(SELECT COUNT(a.id_article)
FROM articles a
WHERE a.id_user_article = u.id_user) AS articles,
(SELECT COUNT(n.news)
FROM news n
WHERE n.id_user_news = u.id_user) AS news
FROM users u
Also if you only uses one column of each table, the subselect is a better option than multiple left joins.
Your problem is that you are joining along different dimensions, which creates cartesian products for each user. The solution by #rafa is actually a fine solution in MySQL. The use of count(distinct) works okay, but only when the counts are not very large. Another approach is to pre-aggregate the results along each dimension:
SELECT u.id_user, a.articles, n.news
FROM users u left outer join
(select id_user_article, count(*) as articles
from articles
group by id_user_article
) a
on u.id_user = a.id_user_article left outer join
(select id_user_news, count(*) as news
from news
group by id_user_news
) n
on u.id_user = n.id_user_news;
EDIT:
If you are using the count(distinct) approach, then you are generating a cross product. If every user had 3 articles and 4 news items, then the users would be multiplied by 12. Probably feasible.
If every user had 300 articles and 400 news items, then every user would be multiplied by 120,000. Probably not feasible.

SQL - can I do repeated inner joins again on the same column?

I have two simple tables, one called itineraries that holds details of holiday itineraries and one called users, that holds details of users. Other users create itineraries, and users can copy their itineraries and add travel agents, so the copied_from_id is the ID of the original creating user from users.id.
I've joined itineraries.user_id to users.id using the below query which works perfectly:
SELECT
itineraries.travel_agent_id,
itineraries.copied_from_id,
itineraries.user_id,
users.full_name,
users.username
FROM `gadabouting_gadabouting_production`.`itineraries`
INNER JOIN `gadabouting_gadabouting_production`.`users` ON itineraries.user_id=users.id
WHERE itineraries.travel_agent_id='253'
Giving me the following output:
+-----------------+------------------+---------+-------------+-------------+
| travel_agent_id | original_creator | user_id | full_name | username |
| 253 | 501 | 1465 | John Smithy | j.smithy |
| 253 | 501 | 1465 | John Smithy | j.smithy |
| 253 | 501 | 1474 | Ben Stockes | ben.stockes |
+-----------------+------------------+---------+-------------+-------------+
(The travel_agent_id and original_creator columns are the same as users.id).
What I want to do now is map the itineraries.travel_agent_id and itineraries.original creator to the users.full_name and users.username columns (so have the full_name and username columns printed next to each of the travel_agent_id and original_creator columns, but I just can't work out how to do it. I've spent hours on it now and can't get my head round it. Do I need to do more joins?
I've looked at several other SO questions about multiple joins but as far as I can see, none of them cover the process of 'going back' again and again on the same column as I want to do here.
Is this possible? Would greatly appreciate any help!
Thanks
You can join in the same table over and over, but you need to use an alias for each one so that you can specify which one you want to use. If you access the result by name, you also need alases for some of the field names.
(It's conventient to use aliases on other tables also, to make the query less verbose.)
select
i.travel_agent_id,
i.copied_from_id,
i.user_id,
u.full_name,
u.username,
ut.full_name as travel_agent_full_name,
ut.username as travel_agent_username,
uc.full_name as creator_full_name,
uc.username as creator_username
from
gadabouting_gadabouting_production.itineraries as i
inner join gadabouting_gadabouting_production.users as u on u.id = i.user_id
inner join gadabouting_gadabouting_production.users as ut on u.id = i.travel_agent_id
inner join gadabouting_gadabouting_production.users as uc on u.id = i.original_creator
where
i.travel_agent_id = '253'

MySQL query with several values in one result

I need to get a list of rows with one query where one of the column consists of several values and I couln't figure this out.
I have three tables that logs mailings to people. One table has all the contact data of a person such as first_name, last_name, address etc. Second table consist of list of mailing names with its unique IDs. Like #1 - Mailing_1, #2 Mailing_2 etc. The third table liaise those two by logging mailing id and people id. Now I need to get the full list of people where the last column would show list of mailins each people got.
Here is what I have tried:
SELECT p.fname, p.lname, p.address m.mailing_name FROM people p
JOIN mailings_liaison l ON l.contact_id - p.id
JOIN mailings m ON m.id = l.mailings_id
WHERE 1
ORDER by p.lname ASC
I get what I need by this but if a person had two or more mailings it shows up as additional rows. I would need to unite those rows so each person has only one row in the query result with several mailings listed in the last column, i.e. I get:
| 1. | John | White | john#white.ru | Mailing_1 |
| 2. | John | White | john#white.ru | Mailing_2 |
But somehow instead I want to get:
| 1. | Jhon | White | john#white.ru | Mailing_1 Mailing_2 |
Is this possible?
use GROUP_CONCAT
SELECT p.fname, p.lname, p.address,
GROUP_CONCAT(m.mailing_name SEPARATOR ' ')
FROM people p
JOIN mailings_liaison l ON l.contact_id - p.id
JOIN mailings m ON m.id = l.mailings_id
GROUP BY p.fname, p.lname, p.address
ORDER by p.lname ASC
MySQL GROUP_CONCAT()