MySQL query with several values in one result - mysql

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()

Related

MySQL select row with two matching joined rows from another table

Hey I try to select a row from a table with two matching entries on another one.
The structure is as following:
----------------- ---------------------
| messagegroups | | user_messagegroup |
| | | |
| - id | | - id |
| - status | | - user_id |
| | | - messagegroup_id |
----------------- | |
---------------------
There exist two rows in user_messagegroup with the ids of two users and both times the same messagegroup_id.
I would like to select the messagegroup where this two users are inside.
I dont get it.. so I would appreciate some help ;)
The specification you provide isn't very clear.
You say "with the ids of two users"... if we take that to mean you have two user_id values you want to supply in the query, then one way to to find the messagegroups that contain these two specific users:
SELECT g.id
, g.status
FROM messagegroups g
JOIN ( SELECT u.messagegroup_id
FROM user_messagegroup u
WHERE u.user_id IN (42, 11)
GROUP BY u.messagegroup_id
HAVING COUNT(DISTINCT u.user_id) = 2
) c
ON c.messagegroup_id = g.id
The returned messagegroups could also contain other users, besides the two that were specified.
If you want to return messagegroups that contain ONLY these two users, and no other users...
SELECT g.id
, g.status
FROM messagegroups g
JOIN ( SELECT u.messagegroup_id
FROM user_messagegroup u
WHERE u.user_id IS NOT NULL
GROUP BY u.messagegroup_id
HAVING COUNT(DISTINCT IF(u.user_id IN (42,11),u.user_id,NULL)) = 2
AND COUNT(DISTINCT u.user_id) = 2
) c
ON c.messagegroup_id = g.id
For improved performance, you'll want suitable indexes on the tables, and it may be possible to rewrite these to eliminate the inline view.
Also, if you only need the messagegroup_id value, you could get that from just the inline view query, without the need for the outer query and the join operation to the messagegroups table.

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

MySQL join multiple rows from one table while selecting only a single row from the others

Maybe a bit of a strange title description, but i basically want to achieve something the GROUP_CONCAT() function does, only then keep the double entries.
I have four tables i want to join, client, doctor, physio and records
Depending on the variable $client i want to get the client details, attending doctor and therapist (one single row from three tables) and join all records for that user.
Say that in this case the $client = 1. The records table has five records where the column r_client_id = 1. If i run a query like below i only get one record from the records table, namely the first occurrence where r_client_id = 1 (which makes sense of course):
SELECT
client.c_id, client.c_name
doctor.d_name,
physio.p_name,
records.r_record
FROM
adm_clients AS client
INNER JOIN
norm_client_doctor AS ncd ON ncd.ncd_client_id = client.c_id
INNER JOIN
adm_doctor AS doctor ON doctor.d_id = ncd.ncd_doctor_id
INNER JOIN
norm_client_physio AS ncp ON ncp.ncp_client_id = client.c_id
INNER JOIN
adm_physio AS physio ON physio.p_id = ncp.ncp_physio_id
LEFT JOIN
adm_doctor_records AS records ON records.r_client_id = client.c_id
WHERE
client.c_id = '".$client."'
Now assume the five records where r_client_id = 1 are like so:
+------+-------------+-------------------+----------+
| r_id | r_client_id | r_record | r_date |
+------+-------------+-------------------+----------+
| 1 | 1 | regular visit | 10/10/12 |
+------+-------------+-------------------+----------+
| 3 | 1 | emergency control | 24/10/12 |
+------+-------------+-------------------+----------+
| 7 | 1 | regular visit | 08/09/12 |
+------+-------------+-------------------+----------+
| 18 | 1 | delivery | 03/01/12 |
+------+-------------+-------------------+----------+
| 20 | 1 | health checkup | 10/12/11 |
+------+-------------+-------------------+----------+
I want my output to be in an array like so:
Client 1
- Name Doctor
- Name Physio
Records
- Emergency control, 24/10/12
- Regular visit, 10/10/12
- Regular visit, 08/09/12
- Delivery, 03/01/12
- Health checkup, 10/12/11
The closest one i can image is a to add a GROUP_CONCAT() on the records, but that, of course, groups the 'regular visit', so i'll get 4 rows instead of 5
GROUP_CONCAT(DISTINCT records.r_record SEPARATOR '|')
[..]
echo(str_replace("|","<br>",$show->r_record));
Anybody an idea how to display all the matching records? I have the feeling i'm close, but i'm out of options by now..
Edit:
I forgot to mention that when i remove the DISTINCT, it displays all the records twice..
SOLVED:
Got it working like so:
GROUP_CONCAT(DISTINCT
CONCAT (records.r_date, '~', records.r_record, '~', records.r_paraph)
SEPARATOR '|') AS clientDoctorRecords,
Try:
SELECT
client.c_id, client.c_name
doctor.d_name,
physio.p_name,
GROUP_CONCAT(records.r_record)
FROM
adm_clients AS client
INNER JOIN
norm_client_doctor AS ncd ON ncd.ncd_client_id = client.c_id
INNER JOIN
adm_doctor AS doctor ON doctor.d_id = ncd.ncd_doctor_id
INNER JOIN
norm_client_physio AS ncp ON ncp.ncp_client_id = client.c_id
INNER JOIN
adm_physio AS physio ON physio.p_id = ncp.ncp_physio_id
LEFT JOIN
adm_doctor_records AS records ON records.r_client_id = client.c_id
WHERE
client.c_id = '".$client."'
GROUP BY
client.c_id
If you want r_date to come along with record in one column, then you can use plain CONCAT first and then do a GROUP_CONCAT on it.

How to count the number of instances of each foreign-key ID in a table?

Here's my simple SQL question...
I have two tables:
Books
-------------------------------------------------------
| book_id | author | genre | price | publication_date |
-------------------------------------------------------
Orders
------------------------------------
| order_id | customer_id | book_id |
------------------------------------
I'd like to create a query that returns:
--------------------------------------------------------------------------
| book_id | author | genre | price | publication_date | number_of_orders |
--------------------------------------------------------------------------
In other words, return every column for ALL rows in the Books table, along with a calculated column named 'number_of_orders' that counts the number of times each book appears in the Orders table. (If a book does not occur in the orders table, the book should be listed in the result set, but "number_of_orders" should be zero.
So far, I've come up with this:
SELECT
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date,
count(*) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date
That's almost right, but not quite, because "number_of_orders" will be 1 even if a book is never listed in the Orders table. Moreover, given my lack of knowledge of SQL, I'm sure this query is very inefficient.
What's the right way to write this query? (For what it's worth, this needs to work on MySQL, so I can't use any other vendor-specific features).
Your query is almost right and it's the right way to do that (and the most efficient)
SELECT books.*, count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id
COUNT(*) could include NULL values in the count because it counts all the rows, while COUNT(orders.book_id) does not because it ignores NULL values in the given field.
SELECT b.book_id,
b.author,
b.genre,
b.price,
b.publication_date,
coalesce(oc.Count, 0) as number_of_orders
from books b
left join (
select book_id, count(*) as Count
from Order
group by book_id
) oc on (b.book_id = oc.book_id)
Change count(*) to count(orders.book_id)
You're counting the wrong thing. You want to count the non-null book_id's.
SELECT
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date,
count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date
select author.aname,count(book.author_id) as "number_of_books"
from author
left join book
on(author.author_id=book.author_id)
GROUP BY author.aname;

MySQL Count Items In Category

I don't understand MySQL very well, here are the table structures I am using.
users
id | first_name | last_name | username
| password
categories
id | user_id | name | description
links
id | user_id | category_id | name |
url | description | date_added |
hit_counter
I am trying to return a result set like this, to give information about the category for a user that includes how many links are in it.
id | user_id | name | description | link_count
At the moment I have this query, but it only returns rows for categories that have links. It should return rows for categories that do not have any links (empty categories).
SELECT categories.*, COUNT(links.id)
FROM categories LEFT JOIN links ON
categories.id=links.category_id;
How to do this query? Thanks.
we can't do select table dot "star" with an aggregate.
what you wanna do is something like (pseudocode):
select
categories.field1,
categories.field2,
{etc.}
count(links.id)
from categories
left join links
on categories.id = links.category_id
group by
categories.field1,
categories.field2,
{etc.}
iow: you're missing the group by code-block to get the right aggregate in your query result set.
To mold alien052002's answer to fit your specific question, the following (untested) should work:
select c.id,
c.user_id,
c.name,
c.description,
count(l.link_count)
from categories c
left join links l on l.category_id = c.id
group by c.id, c.user_id, c.name, c.description
try this
SELECT categories.*, COUNT(links.id) FROM categories LEFT JOIN links ON categories.id=links.category_id group by categories.id;