MySQL: Select multiple records with comma separated values - mysql

I have three tables: store_products, store_orders and store_orders_products. store_products contains all of the products, store_orders contains the order information, and store_orders_products contains each individual product in that order.
I'm building an Orders page that will list each order placed. It will have the username of the person who placed the order, the date, the total amount and the name of each product.
This query gets me everything I want, except it returns only ONE product name. I want to have each product in a comma separated string. I've tried subqueries, COALESCE, CONCAT, IN(), etc, but I'm not getting the results I want.
SELECT
o.id AS order_id
, o.order_total
, o.created_at
, u.username
, u.avatar
, sp.name
FROM store_orders o
JOIN store_orders_contents c ON o.id=c.oid
JOIN store_products p ON p.id=c.pid
JOIN users u ON u.id=o.consumer_uid
JOIN store_products sp ON sp.id=c.pid
WHERE p.uid=3
GROUP BY order_id

I think you want group_concat():
SELECT o.id AS order_id, o.order_total, o.created_at, u.username, u.avatar,
group_concat(sp.name )
FROM store_orders o JOIN
store_orders_contents c
ON o.id = c.oid JOIN
store_products p
ON p.id = c.pid JOIN
users u
ON u.id = o.consumer_uid JOIN
store_products sp
ON sp.id = c.pid
WHERE p.uid = 3
GROUP BY order_id;
I don't understand why you are joining to store_products twice, but I assume you know what you are doing with the joins.

Related

Joining multiple tables to show last order date by customer, by product and by vendor

I am trying to solve the following query, there's a few additional parameters, but these are the main attributes required:
Provide the product details, which vendors supply these products, and what was the last date these products were ordered by customers.
I have my original query below which gets me 90% of the way. I just can't seem to figure out how to display the last order date by customer per individual product. I've tried embedding (select max(o.OrderDate) from orders as o) into my select statement, but it only displays the latest order date of all of the products, not the individual per product last order date (e.g., all dates listed are 01/01/2020 when I know other products' last order date was before this date).
Apologies, I do not have enough rep to post pictures in line with text, therefore I have attached pictures of table structure and my query.
SQL Query
Table structure
Query:
select distinct p.ProductNumber, p.ProductName, p.RetailPrice, p.QuantityOnHand, v.VendName,
(select max(o.OrderDate)
from orders as o)
as LastOrderDateByCust
from ((((orders as o
inner join order_details as od
on od.OrderNumber = o.OrderNumber)
inner join products as p
on p.ProductNumber = od.ProductNumber)
inner join product_vendors as pv
on p.ProductNumber = pv.ProductNumber)
inner join vendors as v
on pv.VendorID = v.VendorID)
where p.QuantityOnHand < '10'
order by LastOrderDateByCust DESC;`
figured it out on my own I believe:
select distinct p.ProductNumber, p.ProductName, c.CategoryDescription, p.RetailPrice, pv.WholesalePrice, p.QuantityOnHand, v.VendName, pv.DaysToDeliver, (select max(o.OrderDate)
from orders as o
inner join order_details as od
on o.OrderNumber = od.OrderNumber
where od.ProductNumber = p.ProductNumber)
as LastOrderDateByCust
from (((((orders as o
inner join order_details as od
on o.OrderNumber = od.OrderNumber)
inner join products as p
on p.ProductNumber = od.ProductNumber)
inner join product_vendors as pv
on p.ProductNumber = pv.ProductNumber)
inner join vendors as v
on pv.VendorID = v.VendorID)
inner join categories as c
on p.CategoryID = c.CategoryID)
where od.ProductNumber = p.ProductNumber and p.QuantityOnHand < '10'
order by p.ProductNumber;`

Joining 4 tables in mySQL and including NULL values

I am trying to list all customers’ names with each product that customer has ordered and include customers who don't have an order. Also If a customer has ordered the same product multiple times, only list the product once for that customer.
I have the beginning of the query set up so its showing all customers and each product ordered but I can't seem to figure out how to add customers with NULL value ( meaning they haven't ordered an item.) I know left outer join is supposed to be used somehow. This is what I have so far:
select distinct
c.customerName, p.productName
from
products p, customers c, orders o, orderDetails d
left join
When using a left join a syntax like:
select distinct
c.customerName, p.productName
from customers c
left join order o on c.id = o.customer_id
left join orderDetails d on o.id = d.order_id
left join products p on p.id = d.product_id AND
p.productName = 'cow'

MySQL: Ranking from multiple tables, sub queries?

This is a MySQL question. I have three tables with the following columns:
transactions (table): transact_id, customer_id, transact_amt, product_id,
products (table): product_id, product_cost, product_name, product_category
customers (table): customer_id, joined_at, last_login_at, state, name, email
I'd like a query that finds out the most popular item in every state and the state. One of the tricky parts is that some product_name have multiple product_id. Therefore I though joining the three tables that generate an output with two columns: state and product_name. Until here that worked fine doing this:
SELECT p.product_name, c.state
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
This selects all the products, and the states from where the customer is. The problem is that I can't find the way to rank the mos popular product per state. I tried different group by, order by and using subqueries without success. I suspect I need to do subqueries, but I can't find the way to resolve it. The expected outcome should look like this:
most_popular_product | state
Bamboo | WA
Walnut | MO
Any help will be greatly appreciated.
Thank you!
You need a subquery that gets the count of transactions for each product in each state.
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
Then write another query that has this as a subquery, and gets the highest count for each state.
SELECT state, MAX(count) AS maxcount
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t
GROUP BY state
Finally, join them together:
SELECT t1.product_name AS most_popular_product, t1.state
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t1
JOIN (
SELECT state, MAX(count) AS maxcount
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t
GROUP BY state
) AS t2 ON t1.state = t2.state AND t1.count = t2.maxcount
This is basically the same pattern as SQL select only rows with max value on a column, just using the first grouped query as the table you're trying to group.

MySQL statement returning too many rows

I am trying to return all the orders from a particular person, I have two tables, a person and an order and using a join, it does return orders of the person but for each order it returns the square amount of that order, for example if there two orders that are the same it will return 4 of those orders.
SELECT
o.*
FROM
orderr o
LEFT JOIN person p
ON p.personID = o.personID
WHERE p.first_name = ?
try this
SELECT DISTINCT
o.*
FROM
orderr o
LEFT JOIN person p
ON p.personID = o.personID
WHERE p.first_name = ?

MySQL Join Question

Hi i'm struggling to write a particular MySQL Join Query.
I have a table containing product data, each product can belong to multiple categories. This m:m relationship is satisfied using a link table.
For this particular query I wish to retrieve all products belonging to a given category, but with each product record, I also want to return the other categories that product belongs to.
Ideally I would like to achieve this using an Inner Join on the categories table, rather than performing an additional query for each product record, which would be quite inefficient.
My simplifed schema is designed roughly as follows:
products table:
product_id, name, title, description, is_active, date_added, publish_date, etc....
categories table:
category_id, name, title, description, etc...
product_category table:
product_id, category_id
I have written the following query, which allows me to retrieve all the products belonging to the specified category_id. However, i'm really struggling to work out how to retrieve the other categories a product belongs to.
SELECT p.product_id, p.name, p.title, p.description
FROM prod_products AS p
LEFT JOIN prod_product_category AS pc
ON pc.product_id = p.product_id
WHERE pc.category_id = $category_id
AND UNIX_TIMESTAMP(p.publish_date) < UNIX_TIMESTAMP()
AND p.is_active = 1
ORDER BY p.name ASC
I'd be happy just retrieving the category id's releated to each returned product row, as I will have all category data stored in an object, and my application code can take care of the rest.
Many thanks,
Richard
SELECT p.product_id, p.name, p.title, p.description,
GROUP_CONCAT(otherc.category_id) AS other_categories
FROM prod_products AS p
JOIN prod_product_category AS pc
ON pc.product_id = p.product_id
LEFT JOIN prod_product_category AS otherc
ON otherc.product_id = p.product_id AND otherc.category_id != pc.category_id
WHERE pc.category_id = $category_id
AND UNIX_TIMESTAMP(p.publish_date) < UNIX_TIMESTAMP()
AND p.is_active = 1
GROUP BY p.product_id
ORDER BY p.name ASC
You would use an inner join to the product_category table, doing a left join there is pointless as you are using the value from it in the condition. Then you do a left join on the product_category table to get the other categories, and join in the categories for the data:
select
p.product_id, p.name, p.title, p.description,
c.category_id, c.name, c.title
from
prod_products p
inner join prod_product_category pc on pc.product_id = p.product_id
left join prod_product_category pc2 on pc2.product_id = p.product_id
left join prod_categories c on c.category_id = pc2.category_id
where
pc.category_id = #category_id and
unix_timestamp(p.publish_date) < unix_timestamp() and
p.is_active = 1
order by
p.name