MySQL group_concat and nest with another group_concat - php

Not sure if the title explains the situation right but I will try to do my best explaining here.
I have a table with 3 fields linked to other tables and I want to get all the Rows grouped in the following way:
item_id, user_id, group_id
1 2 3
2 2 3
3 4 5
4 2 4
In my query i want in comma separated format all the items_id grouped by group_id i also have some extra conditions on the WHERE clause that's why the inner join
That i can do like with this query
"SELECT
GROUP_CONCAT( DISTINCT A.item_id ) AS ids
FROM tableA A
INNER JOIN tableB B ON(tableA.id = tableB.id)
WHERE xxxxx
GROUP BY A.group_id
"
Later i can loop the results and using the comma separated to inner loop every id within the result
But i also want to group it by user_id in order to do something like this
foreach( query_results.... ){
foreach( group_id.... ){
foreach( item_id.... ){
// Display info
}
}
}
Any ideas on this?

using subqueries, we can get both itemids, userids as two seperate columns
select T1.group_id, T1.itemids, T2.userids
FROM
(SELECT group_id,
GROUP_CONCAT( DISTINCT A.item_id ) AS itemids
FROM table1 A
group by group_id) T1
INNER JOIN
(
SELECT
group_id, GROUP_CONCAT( DISTINCT A.user_id ) AS userids
FROM table1 A
group by group_id
) T2
on T1.group_id = T2.group_id

Use 2 GROUP_CONCATS
SELECT GROUP_CONCAT( DISTINCT A.item_id ) AS ids,
GROUP_CONCAT( DISTINCT A.group_id ) AS groups
FROM tableA A
INNER JOIN tableB B ON(tableA.id = tableB.id)
WHERE xxxxx
GROUP BY A.group_id
Loop your resource then use Explode on the groups and ids value and loop them both as you want

Related

Sum of a multiplication of two columns grouped by another column in an inner join of three tables returns wrong value

Sum of a multiplication of two columns grouped by another column in an inner join of three tables returns wrong value.
Below are my three tables:
Table1:
Table2:
Table3:
My Query is as below:
SELECT c.price, c.quantity, SUM( c.quantity * c.price ) AS price,
group_concat( a.rate
SEPARATOR '<br>' ) AS rates, c.hsn AS hsn
FROM tax_wa a
INNER JOIN tax_rate_class b ON a.tax_rate_id = b.tax_rate_id
INNER JOIN inv_item c ON b.tax_class_id = c.tax_class_id
WHERE c.invoice_id = '17'
GROUP BY c.hsn
And the result is:
But above one is not correct... To expain it, if you run the below query on the inv_item table (alone, with no joins) you get correct results:
SELECT price, quantity, sum( quantity * price )
FROM `inv_item`
WHERE invoice_id = '17'
GROUP BY hsn
Result is good:
Above result the wrong value calculated
if you add all
Presumably, you want the sum():
SELECT SUM(c.price), SUM(c.quantity), SUM( c.quantity * c.price ) AS price,
group_concat( a.rate SEPARATOR '<br>' ) AS rates, c.hsn AS hsn
FROM tax_wa a INNER JOIN
tax_rate_class b
ON a.tax_rate_id = b.tax_rate_id INNER JOIN
inv_item c
ON b.tax_class_id = c.tax_class_id
WHERE c.invoice_id = 17
GROUP BY c.hsn;

MYSQL use outer select value in inner select

I know that this question asked frequently but i didn't find any answer (or that its not possible):
I'v got this query
SELECT
`items`.`id`,
`items`.`part_number`,
`item_categories`.`name` AS category,
`suppliers`.`name` AS supplier,
`items`.`supplier_id`,
`items`.`name`,
`items`.`inventory`,
`items`.`package_items`,
`items`.`order_step`,
`items`.`price`,
`items`.`discount`,
`items`.`scale`,
`items`.`by_scale`,
`items`.`has_tax`,
`items`.`category_id`,
`items`.`enable`,
orders.last_orders_amount
FROM
`items`
INNER JOIN
`suppliers` ON `items`.`supplier_id` = `suppliers`.`id`
INNER JOIN
`item_categories` ON `items`.`category_id` = `item_categories`.`id`
INNER JOIN (
SELECT
GROUP_CONCAT(
JSON_EXTRACT(
`orders`.`items`,
CONCAT('$."',
"3",
'".amount')
)
ORDER BY
`orders`.`createDate` DESC
) AS last_orders_amount
FROM
`orders`
WHERE
JSON_EXTRACT(`orders`.`items`,
'$."3"') IS NOT NULL
LIMIT 4
) orders ON orders.last_orders_amount IS NOT NULL
WHERE
1
basically i want to get all the 'items' with there last 4 occurrences in 'orders' base on item.id.
I need to replace the number 3 in that query to item.id from the outer join
(i know that there is INNER JOIN cause to get only items that have occurrences in orders)

SQL Join with subquery counting number of records with the same id in a different table

Okay so I have three(3) tables that i want to join together
tableA is the main details and primary key is row_id autoincremented
tableB is the exteded details and primary/foreign key is row_id coming from tableA
tableC stores unordered ratings and comments for a particular row_id
I want to join all these tables so that I can see all details plus the number of instances in tableC for a row_id and the avg rating.
SELECT *
FROM `tableA` A
LEFT JOIN `tableB` B
ON A.`row_id` = B.`row_id`
LEFT JOIN (
SELECT COUNT( 1 ) AS 'count', Avg(`row_rating`) AS 'avg'
FROM `tableC`
GROUP BY tableC.`row_id`
)C
ON C.`row_id` = A.`row_id`
ORDER BY C.`avg` ASC
The result of this query combines all properly but the same count and avg is displayed in all rows.
Looks like you want to group the records by row_id in inner query. In which case, you need to SELECT row_id instead of COUNT(1), try this:
SELECT *
FROM `tableA` A
LEFT JOIN `tableB` B
ON A.`row_id` = B.`row_id`
LEFT JOIN (
SELECT row_id, Avg(`row_rating`) AS 'avg'
FROM `tableC`
GROUP BY tableC.`row_id`
)C
ON C.`row_id` = A.`row_id`
ORDER BY C.`avg` ASC

Mysql group_concat(id) as ids in a left join and using ids to select all columns in id group

i have a table that contains some articles with it's own ID and shared SKU key.
I've tried to make the query with a left join and using group result to take all ids returned from the query.
My data structure is like that:
id - name - sku - ...
1 - felix - cat
2 - tom - cat - ...
3 - sylvester - cat - ...
4 - red - pen - ...
5 - blue - pen - ...
I tried to use this query:
SELECT * FROM `test`
[LEFT/RIGHT/INNER] JOIN
(
SELECT GROUP_CONCAT(DISTINCT id) AS idsgroup FROM `test` WHERE (attribute_name = 'sku') GROUP BY value_name LIMIT 0, 3
) bind
ON id IN (bind.idsgroup);
this query is wrong, it return only 1 id per group instead all ids selected from concat or in LEFT JOIN case, obviously all rows.
Any suggestion workaround to achieve the right result?
EDIT:
here a fiddle with the structure:
http://sqlfiddle.com/#!9/b6747a
And the query i tried into:
SELECT * FROM `view_test`
INNER JOIN
(
SELECT GROUP_CONCAT(DISTINCT entity_id) AS idsgroup FROM `view_test` WHERE (attribute_name = 'sku') GROUP BY value_name LIMIT 0, 3
) bind
ON entity_id IN (bind.idsgroup);
As this pic show, my result lost some ids, part of the group.
EDIT 2:
after i used FIND_IN_SET() suggested by Kickstart the result is the expected:
SELECT * FROM `view_test`
INNER JOIN
(
SELECT GROUP_CONCAT(DISTINCT entity_id) AS idsgroup FROM `view_test` WHERE (attribute_name = 'sku') GROUP BY value_name LIMIT 0, 3
) bind
ON FIND_IN_SET(entity_id, bind.idsgroup);
The simple fix would appear to be to use FIND_IN_SET for the join. But this is a bit of a hack and will not be that quick.
SELECT *
FROM `view_test`
INNER JOIN
(
SELECT GROUP_CONCAT(DISTINCT entity_id) AS idsgroup
FROM `view_test`
WHERE (attribute_name = 'sku')
GROUP BY value_name
LIMIT 0, 3
) bind
ON FIND_IN_SET(entity_id, bind.idsgroup);
Further not sure why you have a LIMIT on the sub query, especially without an order clause.
Possibly better to use a sub query to just get the DISTINCT entity_id with an attribute_name of sku and join against that.
SELECT *
FROM `view_test`
INNER JOIN
(
SELECT DISTINCT entity_id
FROM `view_test`
WHERE (attribute_name = 'sku')
) bind
ON view_test.entity_id = bind.entity_id
Something like this?
SELECT t.*, group_concat(t2.id) FROM `test` t
LEFT JOIN test t2 ON t2.attribute_name = 'sku' and t.id != t2.id
group by t.id;
row, and the list of all ids that have same SKU

Limiting a left join to returning one result?

I currently have this left join as part of a query:
LEFT JOIN movies t3 ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The trouble is that if there are several movies with the same name and same popularity (don't ask, it just is that way :-) ) then duplicate results are returned.
All that to say, I would like to limit the result of the left join to one.
I tried this:
LEFT JOIN
(SELECT t3.movie_name FROM movies t3 WHERE t3.popularity = 0 LIMIT 1)
ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The second query dies with the error:
Every derived table must have its own alias
I know what I'm asking is slightly vague since I'm not providing the full query, but is what I'm asking generally possible?
The error is clear -- you just need to create an alias for the subquery following its closing ) and use it in your ON clause since every table, derived or real, must have its own identifier. Then, you'll need to include movie_id in the subquery's select list to be able to join on it. Since the subquery already includes WHERE popularity = 0, you don't need to include it in the join's ON clause.
LEFT JOIN (
SELECT
movie_id,
movie_name
FROM movies
WHERE popularity = 0
ORDER BY movie_name
LIMIT 1
) the_alias ON t1.movie_id = the_alias.movie_id
If you are using one of these columns in the outer SELECT, reference it via the_alias.movie_name for example.
Update after understanding the requirement better:
To get one per group to join against, you can use an aggregate MAX() or MIN() on the movie_id and group it in the subquery. No subquery LIMIT is then necessary -- you'll receive the first movie_id per name withMIN() or the last with MAX().
LEFT JOIN (
SELECT
movie_name,
MIN(movie_id) AS movie_id
FROM movies
WHERE popularity = 0
GROUP BY movie_name
) the_alias ON t1.movie_id = the_alias.movie_id
LEFT JOIN movies as m ON m.id = (
SELECT id FROM movies mm WHERE mm.movie_id = t1.movie_id
ORDER BY mm.id DESC
LIMIT 1
)
you could try to add GROUP BY t3.movie_id to the first query
Try this:
LEFT JOIN
(
SELECT t3.movie_name, t3.popularity
FROM movies t3 WHERE t3.popularity = 0 LIMIT 1
) XX
ON t1.movie_id = XX.movie_id AND XX.popularity = 0
On MySQL 5.7+ use ANY_VALUE & GROUP_BY:
SELECT t1.id,t1.movie_name, ANY_VALUE(t3.popularity) popularity
FROM t1
LEFT JOIN t3 ON (t3.movie_id=t1.movie_id AND t3.popularity=0)
GROUP BY t1.id
more info
LEFT JOIN only first row
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Easy solution to left join the 1 most/least recent row is using select over ON phrase
SELECT A.ID, A.Name, B.Content
FROM A
LEFT JOIN B
ON A.id = (SELECT MAX(id) FROM B WHERE id = A.id)
Where A.id is the auto-incremental primary key.
LEFT JOIN (
SELECT id,movie_name FROM movies GROUP BY id
) as m ON (
m.id = x.id
)
// Mysql
SELECT SUM(db.item_sales_nsv) as total FROM app_product_hqsales_otc as db
LEFT JOIN app_item_target_otc as it ON
db.id = (SELECT MAX(id) FROM app_item_target_otc as ot WHERE id = db.id)
and db.head_quarter = it.hqcode
AND db.aaina_item_code = it.aaina_item_code AND db.month = it.month
AND db.year = it.year
WHERE db.head_quarter = 'WIN001' AND db.month = '5' AND db.year = '2022' AND db.status = '1'

Categories