MySQL JOIN / GROUP_CONCAT second table? - sql

So I have this query that works perfectly:
SELECT users.*,
GROUP_CONCAT(categories.category_name) AS categories
FROM users
LEFT OUTER JOIN user_categories ON users.user_id = user_categories.user_id
LEFT OUTER JOIN categories ON user_categories.category_id = categories.category_id
WHERE users.user_city = 'brooklyn'
GROUP BY users.user_id
LIMIT 10;
Say I have another table that holds phone numbers, for the "users" a user can have any number of phone numbers... How would I go about doing round about the exact same thing I am doing wit the categories? In other words, I would like to get another column with ALL of the phone_numbers found in the "phones" table that have the same "user_id" and concat them together(phone1, phone2, phone3)? I have tried:
SELECT users.*,
GROUP_CONCAT(phones.phone_number) AS phone_numbers,
GROUP_CONCAT(categories.category_name) AS categories
FROM users
LEFT OUTER JOIN phones ON users.user_id = phones.user_id
LEFT OUTER JOIN user_categories ON users.user_id = user_categories.user_id
LEFT OUTER JOIN categories ON user_categories.category_id = categories.category_id
WHERE users.user_city = 'brooklyn'
GROUP BY users.user_id
LIMIT 10;
With no luck... or at least the query executes but it does some weird duplication thing... any help would be awesome!
Thanks!

It does weird things, becaue there is a cross product of certain rows. You can use the DISTINCT keyword to get only unique phone numbers:
GROUP_CONCAT(DISTINCT phones.phone_number) AS phone_numbers,
Check the documentation. Alternatively, you can get the phone numbers in another query where you would select only the phone numbers with a condition like WHERE phones.user_id IN (x, x, x, ...) (x are IDs returned from the first query).

This happened to me, I later had to alter my query to this.
SELECT
( SELECT GROUP_CONCAT(`partnumber`) FROM `product_partnumber` AS `n` WHERE `p`.`id`=`n`.`product_id`) as `partnumbers`,
( SELECT GROUP_CONCAT(`oem`) FROM `product_oem` AS `n` WHERE `p`.`id`=`n`.`product_id`) as `oems`
FROM `product` AS `p`
So I had to use sub queries else I had the duplication.

Related

How to create alias from all columns in sql?

The goal of the query here was simplified, but it represents a complex one that I want to select all users fields from the subquery plus computing a SUM. So, this is an example only.
I'm doing a subquery because of a problem with SUM duplicate rows. Like recommended to do with this answer: https://stackoverflow.com/a/7351991/255932
But the problem is that subquery also selects a column "rating" from the table ratings and I can't select all users fields unless describing all users columns on parent select.
SELECT id, name, x, y, z ..., SUM(rating)
FROM
(SELECT users.*, ratings.rating
FROM users
INNER JOIN ratings ON
users.id = ratings.user_id
)
GROUP BY users.id
I would like to know if there is a way to replace (id, name, x, y, z, ...) with a simple (users.*).
Actually, there are two very simple ways.
If users.id is the primary key:
SELECT u.*, sum(r.rating) AS total
FROM users u
JOIN ratings r ON r.user_id = u.id
GROUP BY u.id;
You need Postgres 9.1 or later for this to work. Details in this closely reated answer:
PostgreSQL - GROUP BY clause
If users.id is at least unique:
SELECT u.*, r.total
FROM users u
JOIN (
SELECT user_id, sum(rating) AS total
FROM ratings
GROUP BY 1
) r ON r.user_id = u.id;
Works with any version I know of. When retrieving the whole table or large parts of it, it's also generally faster to group first and join later.
Kind of, but not really. There is a workaround, but you have to approach your subquery differently.
SELECT (c.users).*, SUM(c.rating)
FROM
(SELECT users, ratings.rating
FROM users
INNER JOIN ratings ON
users.id = ratings.user_id
) c
GROUP BY c.users;

sql - How to have multiple select/from statements in one query

I'm trying to pull a report where each column is selecting from a specific table set. However, one of the columns needs to pull from a completely different table set and still be included in the same report. Of course, this doesn't work:
select u.first_name, ticket_work.time_spent
FROM tickets LEFT OUTER JOIN ticket_work ON ticket_work.ticket_id = tickets.id JOIN users u
(select count(tickets.id) FROM tickets JOIN users u)
where tickets.assigned_to = u.id
...
So just the part (select count(tickets.id) FROM tickets JOIN users u) needs to be selecting from the different table set but still be included in the report.
I'm a little confused by your question. Are you wanting to return the user, the count of tickets for that user, and the amount of time spent overall? If so, something like this should work:
select u.id, u.first_name,
SUM(tw.time_spent) summed_time_spent,
COUNT(DISTINCT t.id) count_tickets
FROM users u
LEFT JOIN tickets t
ON u.id = t.assigned_to
LEFT JOIN ticket_work tw
ON tw.ticket_id = t.id
GROUP BY u.id, u.first_name
Your questions is unclear, but just generally, it sounds like you're trying to join to a derived table (i.e., a query). In that case, do this:
SELECT...
FROM...
table_A A LEFT JOIN
(SELECT keyfield, valuefield FROM table_b WHERE ...) B
ON A.keyfield = B.keyfield
Does that make sense? To make a derived table, you put a query inside of parenthesis, give it an alias ('B' in this case), and then join it to your other tables as though it were a regular table.
Don't know about your table structure but you may use a sub query for such requirement
select u.first_name, ticket_work.time_spent,(select count(tickets.id) FROM tickets where ticket.id=ticket_work.ticket_id) as myCount
FROM tickets LEFT OUTER JOIN ticket_work ON ticket_work.ticket_id = tickets.id JOIN users u
where tickets.assigned_to = u.id

How to make this join with a TSQL query?

I have a table called USERS that has a foreign key to the table GROUPS (a user can pertain to one or none GROUPS). The table USERS also contains a column ISDELETED (a char column with T or F).
I need a query to retrieve all the GROUPS and all the USERS that are not deleted, if all the users in a GROUP are deleted or no users are defined I need the query to return NULL for that GROUP.
I tried with the following query:
SELECT GROUPS.*, USERS.*
FROM GROUPS INNER JOIN
USERS ON GROUPS.ID = USERS.GROUPID
WHERE USERS.ISDELETED = 'F'
But this query does not returns the groups that are empty. SQL and me are not the best friends in world, some help will be great, thanks.
If you want all the groups, regardless of a match in the users table, you should use a left outer join:
SELECT GROUPS.*, USERS.*
FROM GROUPS
LEFT OUTER JOIN
USERS
ON GROUPS.ID = USERS.GROUPID AND USERS.ISDELETED = 'F'
You should just need to do a left outer join -
SELECT GROUPS.*, USERS.*
FROM GROUPS LEFT OUTER JOIN
USERS ON GROUPS.ID = USERS.GROUPID
WHERE USERS.ISDELETED = 'F'
Here's a reference I like to use to remind myself of the differences in sql joins.
You need to use the LEFT OUTER JOIN operator instead of the INNER JOIN.

Two left joins and a union in MySQL

I'm trying to do a pretty complex query in MySQL; complex for me, at least.
Here's an example of what I'm trying to do:
SELECT * FROM friends
LEFT JOIN users ON users.uid = friends.fid1
LEFT JOIN users ON users.uid = friends.fid2
WHERE (friends.fid1 = 1) AND (friends.fid2 > 1)
UNION SELECT fid2 FROM friends
WHERE (friends.fid2 = 1) AND (friends.fid1 < 1)
ORDER BY RAND()
LIMIT 6;
I'm getting back: ERROR 1066 (42000): Not unique table/alias: 'users'.
Where am I going wrong, and how should I really be performing this query?
Alias your table, like:
LEFT JOIN users u1 ON u1.uid = friends.fid1
LEFT JOIN users u2 ON u2.uid = friends.fid2
You have written left join two times with different fields of tables, it seems to When it got parse so give them alias and then join them with friends Table
LEFT JOIN users users1 ON users1.uid = friends.fid1
LEFT JOIN users users2 ON users2.uid = friends.fid2

SQL help: COUNT aggregate, list of entries and its comment count

So, what I intended to do is to fetch a list of entries/posts with their category and user details, AND each of its total published comments. (entries, categories, users, and comments are separate tables)
This query below fetches the records fine, but it seems to skip those entries with no comments. As far as I can see, the JOINs are good (LEFT JOIN on the comments table), and the query is correct. What did I miss ?
SELECT entries.entry_id, entries.title, entries.content,
entries.preview_image, entries.preview_thumbnail, entries.slug,
entries.view_count, entries.posted_on, entry_categories.title AS category_title,
entry_categories.slug AS category_slug, entry_categories.parent AS category_parent,
entry_categories.can_comment AS can_comment, entry_categories.can_rate AS can_rate,
users.user_id, users.group_id, users.username, users.first_name, users.last_name,
users.avatar_small, users.avatar_big, users.score AS user_score,
COUNT(entry_comments.comment_id) AS comment_count
FROM (entries)
JOIN entry_categories ON entries.category = entry_categories.category_id
JOIN users ON entries.user_id = users.user_id
LEFT JOIN entry_comments ON entries.entry_id = entry_comments.entry_id
WHERE `entries`.`publish` = 'Y'
AND `entry_comments`.`publish` = 'Y'
AND `entry_comments`.`deleted_at` IS NULL
AND `category` = 5
GROUP BY entries.entry_id, entries.title, entries.content,
entries.preview_image, entries.preview_thumbnail, entries.slug,
entries.view_count, entries.posted_on, category_title, category_slug,
category_parent, can_comment, can_rate, users.user_id, users.group_id,
users.username, users.first_name, users.last_name, users.avatar_big,
users.avatar_small, user_score
ORDER BY posted_on desc
edit: I am using MySQL 5.0
Well, you're doing a left join on entry_comments, with conditions:
`entry_comments`.`publish` = 'Y'
`entry_comments`.`deleted_at` IS NULL
For the entries with no comments, these conditions are false.
I guess this should solve the problem:
WHERE `entries`.`publish` = 'Y'
AND (
(`entry_comments`.`publish` = 'Y'
AND `entry_comments`.`deleted_at` IS NULL)
OR
`entry_comments`.`id` IS NULL
)
AND `category` = 5
In the OR condition, I put entry_comments.id, assuming this is the primary key of the entry_comments table, so you should replace it with the real primary key of entry_comments.
It's because you are setting a filter on columns in the entry_comments table. Replace the first with:
AND IFNULL(`entry_comments`.`publish`, 'Y') = 'Y'
Because your other filter on this table is an IS NULL one, this is all you need to do to allow the unmatched rows from the LEFT JOIN through.
Try changing the LEFT JOIN to a LEFT OUTER JOIN
OR
I'm no expert with this style of SQL joins (more of an Oracle man myself), but the wording of the left join is leading me to believe that it is joining entry_comments on to entries with entry_comments on the left, you really want it to be the other way around (I think).
So try something like:
LEFT OUTER JOIN entries ON entries.entry_id = entry_comments.entry_id