MySQL: concatenate columns of tables one-to-many - mysql

I have 2 tables (person + person_products)
where each person has at least 1 product.
Sample person table:
person_id | name
------------------
1 | Alice
2 | Peter
3 | James
Sample person_products table:
id | person_id | description | price
------------------------------------
1 | 1 | iphone 5 | 100
2 | 1 | iphone 6 | 200
3 | 1 | samsung | 300
4 | 2 | tv | 110
5 | 3 | oven | 250
6 | 3 | microwave | 260
I want to do the following:
SELECT p.person_id,
some_concat_product_descriptions,
some_concat_product_prices
FROM person p
LEFT JOIN person_products p on p.person_id = pp.person_id
Expected result:
person_id | concat_product_descriptions | concat_product_prices
---------------------------------------------------------------
1 | iphone 5, iphone 6, samsung | 100, 200, 300
2 | tv | 110
3 | oven, microwave | 250, 260
How can I achieve this?

Use group_concat
SELECT p.person_id,
group_concat(pp.description order by pp.description) as concat_product_descriptions,
group_concat(pp.price order by pp.description) as concat_product_prices
FROM person p
LEFT JOIN person_products pp on p.person_id = pp.person_id
GROUP BY p.person_id

Use group_concat aggregation function. A join is is not needed at all.
select
person_id,
group_concat(description) separator ', ' as concat_product_descriptions,
group_concat(price) separator ', ' as concat_product_prices
group by
person_id

Related

How to use Mysql SUM with JOIN

I have the following tables:
purchase_tbl
id | productId | purchaseQuantity
---+-----------+-----------------
1 | 1 | 30
2 | 2 | 30
3 | 1 | 10
4 | 2 | 10
sale_tbl
id | productId | saleQuantity
---+-----------+-------------
1 | 1 | 10
2 | 2 | 10
3 | 1 | 10
4 | 2 | 10
5 | 1 | 10
6 | 2 | 10
I need to get the output as this one:
productId | totalPurchasedQuantity| totalSaleQuantity
----------+-----------------------+------------------
1 | 40 | 30
2 | 40 | 30
I'm using this query and how to get the desired result?
SELECT purchase_tbl.productId
, SUM(purchase_tbl.purchaseQuantity) AS totalPurchaseQuantity
, SUM(sale_tbl.saleQuantity) AS totalSaleQuantity
FROM purchase_tbl
JOIN sale_tbl
ON purchase_tbl.productId = sale_tbl.productId
GROUP BY purchase_tbl.productId
Current output
productId | totalPurchaseQuantity | totalSaleQuantity
----------+-----------------------+------------------
1 | 120 | 60
2 | 120 | 60
You better group then in separate query, as table have multiple records for each product, which getting cross product.
SELECT purchase.productId, totalPurchaseQuantity, totalSaleQuantity
FROM
(SELECT purchase_tbl.productId
, SUM(purchase_tbl.purchaseQuantity) AS totalPurchaseQuantity
FROM purchase_tbl
GROUP BY purchase_tbl.productId) purchase
INNER JOIN
(SELECT sale_tbl.productId
, SUM(sale_tbl.saleQuantity) AS totalSaleQuantity
FROM sale_tbl
GROUP BY sale_tbl.productId
) sale ON sale.productId= purchase.productId;
To obtain your expected result you have to do the aggregation on the individual table before joining them. Your query with be like:
SELECT A.productId, A.totalpurchaseQuantity, B.totalsaleQuantity
FROM
(SELECT productId, SUM(purchaseQuantity)
totalpurchaseQuantity FROM purchase_tbl
GROUP BY productId) A JOIN
(SELECT productId, SUM(saleQuantity)
totalsaleQuantity FROM sale_tbl
GROUP BY productId) B ON
A.productId=B.productId;

MySQL combine 2 tables in 1 than combine it with another one

i have 2 tables (Titles and Episodes).
Table Titles
id | title | type | views
------------------------------
1 | Lucy | movie | 300
2 | Narcos | series | 2600
3 | Ip Man | movie | 120
4 | Creed | movie | 460
Table Episodes
id | title_id | title | episode | views
----------------------------------------------
1 | 2 | episode1 | 1 | 100
2 | 2 | episode2 | 2 | 260
3 | 2 | episode3 | 3 | 96
4 | 2 | episode4 | 4 | 210
Now i use this query to get most viewed episodes.
SELECT titles.id, titles.title, episodes.title_id, episodes.episode, episodes.views FROM titles, episodes WHERE titles.id = episodes.title_id ORDER BY episodes.views DESC LIMIT 0, 16
And i use this query for movies.
SELECT titles.id, titles.title, titles.views WHERE type = 'movie' ORDER BY titles.views DESC LIMIT 0, 16
I want to combine this two last queries into 1 temporary table to show most viewed movies and episodes.
Temporary Table
id | title_id | title | views
----------------------------------------------
1 | 4 | Creed | 460
2 | 1 | Lucy | 300
3 | 2 | Narcos Episode 2 | 260
4 | 2 | Narcos Episode 4 | 210
How can i do that ?
Thank you.
you can use view
see this page to more information
http://dev.mysql.com/doc/refman/5.7/en/create-view.html
I got it, thank you #sagi
(SELECT titles.id as title_id, concat(titles.title,' ',episodes.title) as
title,episodes.views as views
FROM titles, episodes
WHERE titles.id = episodes.title_id and type = 'series'
ORDER BY episodes.views DESC LIMIT 0, 16)
UNION ALL
(SELECT titles.id, titles.title, titles.views as views
FROM titles
WHERE type = 'movie'
ORDER BY titles.views DESC LIMIT 0, 16) ORDER BY views DESC

Addition of the SUM of two independant tables

i have two tables
td_sell
|----------|----------------|------------------|
| id | user_id | price |
|----------------------------------------------|
| 1 | 2 | 10 |
|----------------------------------------------|
| 2 | 1 | 5 |
|----------------------------------------------|
| 3 | 2 | 3 |
|----------------------------------------------|
and td_commsion
|----------|----------------|------------------|
| id | user_id | price |
|----------------------------------------------|
| 1 | 1 | 3 |
|----------------------------------------------|
| 2 | 1 | 5 |
|----------------------------------------------|
| 3 | 2 | 3 |
|----------------------------------------------|
now i want a sql query like this
SELECT (SUM(td_sell.price) + SUM(td_comission.price)) AS his_earning
FROM td_sell, td_comission
WHERE td_sell.user_id='1'
AND td_comission.user_id='1'
but its showing abnormal result
the result should be 13, but its showing 29
This will work:
SELECT (SELECT SUM(s.price) FROM td_sell s WHERE s.user_id = 1)
+
(SELECT SUM(c.price) FROM td_comission c WHERE c.user_id = 1)
DEMO: SqlFiddle
You are getting the sum of the Cartesian join of the two tables.
http://en.wikipedia.org/wiki/Cartesian_product
SELECT sum(price)
FROM (
SELECT * FROM td_sell
UNION ALL
SELECT * FROM td_commission
) a
where a.user_id=1
Here's a SQL Fiddle:
Fiddle
You need to do the sum separately on each table, before combining the results. Here is one way:
select (sell + commission) as his_earning
from (select SUM(td_sell.price) as sell
from td_sell
where td_sell.user_id='1'
) s cross join
(select SUM(td_comission.price) as commission
from td_comission
where td_comission.user_id='1'
) c

select query to calculate number of occurrence as well as total cost

I have one report page which displays summarized data of other report.I have used php and mysqli. Let me explain you in deep.
I have a web application of store, where you can add product details. Using these product details you can generate packaging list report of products. And based on the generated packaging list report I need to generate one other report which contains summarized data of the packaging list.
below are my tables:
product table:
id | name | desc_id | purity | style_no | type | duty
1 | ABC | 1 | 18 | TEST123 | R | 100
2 | XYZ | 2 | 14 | TEST456 | B | 80
3 | DEF | 1 | 14 | TEST122 | R | 80
4 | PQR | 1 | 18 | TEST124 | R | 120
5 | HJK | 3 | 18 | TEST134 | B | 300
Description table:
id | descrip
1 | Gold Diamond Ring
2 | Gold Diamond Pendant
3 | Gold Diamond Earring
packaging_master table
id | name
1 | pkg_1
2 | pkg_2
packging_details table
id | pkg_id | prod_id
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 1 | 4
5 | 1 | 5
I have used below query to generate the packaging list report for specific id, which works correctly.
SELECT id, (SELECT descrip FROM description WHERE id = desc_id ) AS descrip,
style_no, type , purity, duty FROM product WHERE id IN ( SELECT prod_id FROM packaging_list_details WHERE pkg_id =1 ) ORDER BY descrip ASC , purity ASC
which displays below result:
id | descrip | style_no | type | purity | duty
1 |Gold Diamond Ring | TEST123 | R | 18 | 100
4 |Gold Diamond Ring | TEST124 | R | 18 | 120
3 |Gold Diamond Ring | TEST122 | R | 14 | 80
2 |Gold Diamond Pendant| TEST456 | B | 14 | 80
5 |Gold Diamond Earring| TEST134 | B | 18 | 300
Now I want summarized data of above result using query.
Like:
id | descrip | purity | qty | duty
1 |Gold Diamond Ring | 18 | 2 | 220
2 |Gold Diamond Ring | 14 | 1 | 80
3 |Gold Diamond Pendant| 14 | 1 | 80
4 |Gold Diamond Earring| 18 | 1 | 300
How can I achieve this?
You need to use the GROUP_BY statement - See MySql docs for more info.
This will translate the query to such
SELECT d.descrip, p.purity, count(p.purity) as qty, sum(p.duty)
FROM product p
INNER JOIN Description d ON p.desc_id = d.id
LEFT OUTER JOIN packaging_details pg on pg.prod_id = p.id
GROUP BY d.descrip, p.purity
ORDER BY d.descrip desc, p.purity desc
You can also use the sub select methodology you were using, but I prefer using joins. INNER JOIN will link both tables so that all their records are returned. OUTER JOIN will return all rows from the tables on the LEFT of the statement and matches them to values from the tables on the RIGHT.
See a full SQL Fiddle sample.
NOTE: I am not sure where you are getting the values for Id in your sample - Are they simply row numbers?
I think you should rewrite your query using JOINs:
SELECT
P.id
,D.descrip
,P.style_no
,P.type
,P.purity
,P.duty
FROM
packaging_list_details PLD
JOIN
product P ON
(P.id = PLD.prod_id)
LEFT JOIN
description D on
(D.desc_id = P.id)
WHERE
(PLID.pkg_id = 1)
That should give you the same result you already have. To get the totals, you can write a new query, similar to the above:
SELECT
P.id
,D.descrip
,P.type
,P.purity
,COUNT(p.id) as total_products
,SUM(P.duty) as total_duty
FROM
packaging_list_details PLD
JOIN
product P ON
(P.id = PLD.prod_id)
LEFT JOIN
description D on
(D.desc_id = P.id)
WHERE
(PLID.pkg_id = 1)
GROUP BY
P.id
,D.descrip
,P.type
,P.purity
The second query gives you the totals you are looking for.

Querying specific data from 3 tables

I'm having trouble coming up with a query that returns the player's id, name along with the player's first match date, matchid and opponent.
I want the same information for player's last match as well.
`players`
id | name
1 | playername10
2 | playername22
3 | playername33
4 | playername45
5 | playername55
`matches`
id | gamedate | opponent
1 | 2011-01-01 | opponent1
2 | 2011-01-02 | opponent2
3 | 2011-01-03 | opponent3
4 | 2011-01-04 | opponent4
5 | 2011-01-05 | opponent5
`playermatchscores`
id | matchid | player | goals
1 | 1 | playername10 | 1
2 | 1 | playername22 | 2
3 | 2 | playername10 | 1
4 | 1 | playername33 | 1
5 | 3 | playername45 | 2
6 | 4 | playername55 | 1
7 | 2 | playername55 | 1
8 | 3 | playername22 | 2
9 | 5 | playername55 | 1
Where matchid is a foreign key to the id in table matches.
I tried several queries but I may be approaching it the the wrong way. How can I write a way to get the information I want?
Information about LEFT JOIN: http://www.w3schools.com/sql/sql_join_left.asp
SELECT players.id, MAX(matches.gamedate) AS first_match, MIN(matches.gamedate) AS last_match
FROM playermatchscores
LEFT JOIN players ON players.player = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
GROUP BY players.player
I haven't tested this select.
P.S. You should use foreign key for players table too with player_id in playermatchscores.
After the changes in question:
SELECT players.*, matches.*,
FROM playermatchscores
LEFT JOIN players ON players.name = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
ORDER BY matches.gamedate ASC
WHERE players.id = 3
LIMIT 1
For the last match replace ASC with DESC.
P.S. This is not the best way to do it but it should work.