i have query like this
SELECT COALESCE(p.name, 'total') AS `product name`,
SUM(omd.quantity) AS `Qty(kg)`,
SUM(omd.quantity) / any_value(total_sum) * 100 AS `Qty(%)`,
COUNT(om.id) AS `COunt Order`,
COUNT(om.id) / any_value(total_count) * 100 AS `Count Order(%)`
FROM order_match om
INNER JOIN order_match_detail omd
ON om.id = omd.order_match_id
INNER JOIN product p
on omd.product_id = p.id
INNER JOIN (select SUM(omd1.quantity) total_sum,
count(om1.id) total_count
FROM order_match om1
INNER JOIN
order_match_detail omd1
ON om1.id = omd1.order_match_id
where om1.order_status_id in
(4, 5, 6, 8)) totals
where om.order_status_id in (4, 5, 6, 8)
group by p.name with rollup;
and after running that query the result was this (this is just dummy)
+--------------+---------+--------+-------------+-----------------+
| Product Name | Qty(kg) | Qty(%) | COunt Order | Count Order (%) |
+--------------+---------+--------+-------------+-----------------+
| Product A | 20 | 20 | 10 | 10 |
| Product B | 30 | 30 | 10 | 10 |
| Product C | 45 | 45 | 30 | 30 |
| Product D | 5 | 5 | 50 | 50 |
| TOtal | 100 | 100 | 100 | 100 |
+--------------+---------+--------+-------------+-----------------+
i want to put order by and order based on the Qty(kg)
the expected result was this
+--------------+---------+--------+-------------+-----------------+
| Product Name | Qty(kg) | Qty(%) | COunt Order | Count Order (%) |
+--------------+---------+--------+-------------+-----------------+
| Product C | 45 | 45 | 30 | 30 |
| Product B | 30 | 30 | 10 | 10 |
| Product A | 20 | 20 | 10 | 10 |
| Product D | 5 | 5 | 50 | 50 |
| TOtal | 100 | 100 | 100 | 100 |
+--------------+---------+--------+-------------+-----------------+
so this is my query after i put order by
SELECT COALESCE(p.name, 'total') AS `product name`,
SUM(omd.quantity) AS `Qty(kg)`,
SUM(omd.quantity) / any_value(total_sum) * 100 AS `Qty(%)`,
COUNT(om.id) AS `COunt Order`,
COUNT(om.id) / any_value(total_count) * 100 AS `Count Order(%)`
FROM order_match om
INNER JOIN order_match_detail omd
ON om.id = omd.order_match_id
INNER JOIN product p
on omd.product_id = p.id
INNER JOIN (select SUM(omd1.quantity) total_sum,
count(om1.id) total_count
FROM order_match om1
INNER JOIN
order_match_detail omd1
ON om1.id = omd1.order_match_id
where om1.order_status_id in
(4, 5, 6, 8)) totals
where om.order_status_id in (4, 5, 6, 8)
group by p.name with rollup
order by omd.quantity DESC;
but after i run it, the notification just like this
Error COde :1221. Incorrect usage of CUBE/R0LLUP and ORDER BY
so which part i should edit or add so it can be ordered by what i want
Do not add ORDER BY after GROUP BY WITH ROLLUP. Convert your query to subquery (or CTE if its version is 8+) and sort its output in outer query storing rollup result last:
SELECT *
FROM ( SELECT COALESCE(p.name, 'Total') AS `product name`,
SUM(omd.quantity) AS `Qty(kg)`,
SUM(omd.quantity) / ANY_VALUE(total_sum) * 100 AS `Qty(%)`,
COUNT(om.id) AS `Count Order`,
COUNT(om.id) / ANY_VALUE(total_count) * 100 AS `Count Order(%)`
FROM order_match AS om
INNER JOIN order_match_detail AS omd ON om.id = omd.order_match_id
INNER JOIN product AS p ON omd.product_id = p.id
CROSS JOIN ( SELECT SUM(omd1.quantity) AS total_sum,
COUNT(om1.id) AS total_count
FROM order_match AS om1
INNER JOIN order_match_detail AS omd1 ON om1.id = omd1.order_match_id
WHERE om1.order_status_id IN (4, 5, 6, 8)
) AS totals
WHERE om.order_status_id IN (4, 5, 6, 8)
GROUP BY p.name WITH ROLLUP
) AS subquery
ORDER BY `product name`='Total', `Qty(kg)` DESC;
Related
It's possible left join only one row without sub query?
I need to get product statistics and some of products have multiple groups.
Therefore, the amount of products is incorrect.
SELECT COUNT(p.id) AS total_product, SUM(p.price) AS total_price
FROM product p
LEFT JOIN attribute_group a ON
a.product_id = p.id
WHERE p.created_at >= "2018-01-01" AND (a.id = 1 OR a.id = 2)
GROUP BY p.id
LIMIT 0, 30;
product
id | price
1 | 100
2 | 150
3 | 250
attribute_group
id | product_id | title
1 | 1 | a1
2 | 1 | a2
3 | 2 | a3
4 | 3 | a4
Should be:
1| 100
But i get:
2 | 200
You appear to want all products or the counts/sum of them that have attributes of both 1 and 2. Here is one method:
SELECT COUNT(*) as num_products, SUM(p.price) as total_price
FROM product p
WHERE p.created_at >= '2018-01-01' AND
EXISTS (SELECT 1
FROM attribute_group ag
WHERE ag.product_id = p.id AND ag.id = 1
) AND
EXISTS (SELECT 1
FROM attribute_group ag
WHERE ag.product_id = p.id AND ag.id = 2
);
I have the table definition below.
CREATE TABLE IF NOT EXISTS ranking (
user_id int(11) unsigned NOT NULL,
create_date date NOT NULL,
score double(8,2),
PRIMARY KEY (user_id, create_date)
)
insert into ranking (user_id, create_date, score) values
(1, '2017-03-01', 100),
(1, '2017-03-02', 90),
(1, '2017-03-03', 80),
(1, '2017-03-04', 100),
(1, '2017-03-05', 90),
(2, '2017-03-01', 90),
(2, '2017-03-02', 80),
(2, '2017-03-03', 100),
(2, '2017-03-5', 100),
(3, '2017-03-01', 80),
(3, '2017-03-02', 100),
(3, '2017-03-03', 90),
(3, '2017-03-6', 100);
select * from ranking;
user_id | create_date | score
1 | 2017-03-01 | 100
1 | 2017-03-02 | 90
1 | 2017-03-03 | 80
1 | 2017-03-04 | 100
1 | 2017-03-05 | 90
2 | 2017-03-01 | 90
2 | 2017-03-02 | 80
2 | 2017-03-03 | 100
2 | 2017-03-05 | 100
3 | 2017-03-01 | 80
3 | 2017-03-02 | 100
3 | 2017-03-03 | 90
3 | 2017-03-06 | 100
What I want is for each user_id, get the most recent create_date on which the score is maximum. For example, in the example above, for user_id = 1, when create_date = 2017-03-01 and create_date = 2017-03-04, the maximum score is 100, but I just want the most recent date with the maximum score, i.e., create_date = 2017-03-04 and score = 100. The query result is as follows:
user_id | create_date | score
1 | 2017-03-04 | 100
2 | 2017-03-05 | 100
3 | 2017-03-06 | 100
Below is my solution, which returns the expected result but I believe there exist better solutions.
SELECT a.* from
(
SELECT s1.user_id , s1.create_date, s1.score FROM ranking AS s1
INNER JOIN
(SELECT user_id , FORMAT(max(score), 0) as best_score FROM ranking GROUP BY user_id ) AS s2
ON s1.user_id = s2.user_id AND s1.score = s2.best_score
) a
NATURAL LEFT JOIN
(
SELECT s1.user_id , s1.create_date, s1.score FROM ranking AS s1
INNER JOIN
(
SELECT user_id , create_date, score FROM ranking
) s2
WHERE s1.user_id = s2.user_id AND s1.score = s2.score AND s1.create_date < s2.create_date
) b
WHERE b.user_id IS NULL;
Can someone provide better solutions? Thanks.
SELECT t1.user_id,
MAX(t1.create_date) AS max_date,
t2.max_score
FROM ranking t1
INNER JOIN
(
SELECT user_id, MAX(score) AS max_score
FROM ranking
GROUP BY user_id
) t2
ON t1.user_id = t2.user_id AND
t1.score = t2.max_score
GROUP BY t1.user_id
Output:
Demo here:
Rextester
Try this:
select user_id, max(create_date),max(score) from ranking GROUP BY user_id
result:
1 2017-03-04 100.00
2 2017-03-05 100.00
3 2017-03-06 100.00
or
select user_id, max(create_date),cast(max(score) as UNSIGNED) as maxscore from ranking GROUP BY user_id
result:
1 2017-03-04 100
2 2017-03-05 100
3 2017-03-06 100
Try this query -
SELECT r1.* FROM ranking r1
JOIN (SELECT user_id, MAX(score) max_score FROM ranking GROUP BY user_id) r2
ON r1.user_id = r2.user_id AND r1.score = r2.max_score
JOIN (SELECT user_id, score, MAX(create_date) max_create_date FROM ranking GROUP BY user_id, score) r3
ON r1.user_id = r3.user_id AND r1.score = r3.score AND r1.create_date = r3.max_create_date;
1 04-Mar-17 100
2 05-Mar-17 100
3 06-Mar-17 100
I have such query that gives me results about bestseller items from shops, at the moment it works fine, but now I want to get only one product from each shop so to have a distinct si.shop_id only one bestseller product from a shop
SELECT `si`.`id`, si.shop_id,
(SELECT COUNT(*)
FROM `transaction_item` AS `tis`
JOIN `transaction` as `t`
ON `t`.`id` = `tis`.`transaction_id`
WHERE `tis`.`shop_item_id` = `si`.`id`
AND `t`.`added_date` >= '2014-02-26 00:00:00')
AS `count`
FROM `shop_item` AS `si`
INNER JOIN `transaction_item` AS `ti`
ON ti.shop_item_id = si.id
GROUP BY `si`.`id`
ORDER BY `count` DESC LIMIT 7
and that gives mu a result like:
+--------+---------+-------+
| id | shop_id | count |
+--------+---------+-------+
| 425030 | 38027 | 111 |
| 291974 | 5368 | 20 |
| 425033 | 38027 | 18 |
| 291975 | 5368 | 12 |
| 142776 | 5368 | 10 |
| 397016 | 38027 | 9 |
| 291881 | 5368 | 8 |
+--------+---------+-------+
any ideas?
EDIT
so I created a fiddle for it
http://sqlfiddle.com/#!2/cfc4c/1
Now the query returns best selling products I want it to return only one product from shopso the result of fiddle should be
+----+---------+-------+
| ID | SHOP_ID | COUNT |
+----+---------+-------+
| 1 | 222 | 3 |
| 4 | 333 | 2 |
| 8 | 555 | 1 |
| 9 | 777 | 1 |
+----+---------+-------+
Possibly something like this:-
SELECT si.shop_id,
SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(':', si.id, sub1.item_count) ORDER BY sub1.item_count DESC), ',', 1) AS `count`
FROM shop_item AS si
INNER JOIN
(
SELECT tis.shop_item_id, COUNT(*) AS item_count
FROM transaction_item AS tis
JOIN `transaction` as t
ON t.id = tis.transaction_id
AND t.added_date >= '2014-02-26 00:00:00'
GROUP BY tis.shop_item_id
) sub1
ON sub1.shop_item_id = si.id
GROUP BY si.shop_id
ORDER BY `count` DESC LIMIT 7
The sub query gets the count of items for each shop. Then the main query concatenates the item id and the item count together, group concatenates all those for a single shop together (ordered by the count descending) and then uses SUBSTRING_INDEX to grab the first one (ie, everything before the first comma).
You will have to split up the count field to get the item id and count separately (the separator is a : ).
This is taking a few guesses about what you really want, and with no table declares or data it isn't tested.
EDIT - now tested with the SQL fiddle example:-
SELECT SUBSTRING_INDEX(`count`, ':', 1) AS ID,
shop_id,
SUBSTRING_INDEX(`count`, ':', -1) AS `count`
FROM
(
SELECT si.shop_id,
SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(':', si.id, sub1.item_count) ORDER BY sub1.item_count DESC), ',', 1) AS `count`
FROM shop_item AS si
INNER JOIN transaction_item AS ti
ON ti.shop_item_id = si.id
INNER JOIN
(
SELECT tis.shop_item_id, COUNT(*) AS item_count
FROM transaction_item AS tis
JOIN `transaction` as t
ON t.id = tis.transaction_id
AND t.added_date >= '2014-02-26 00:00:00'
GROUP BY tis.shop_item_id
) sub1
ON sub1.shop_item_id = si.id
GROUP BY si.shop_id
) sub2
ORDER BY `count` DESC LIMIT 7;
Query below currently shows the total as item by item but what I want is to calculate subtotal of all items in a purchase order.
Thanks
Output should be:
POID Item ItemQTY ItemPrice ItemTotal SubTotal
1 A 1 15.00 15.00 80.50
1 B 1 25.50 25.50 80.50
1 C 2 20.00 40.00 80.50
2 X 6 5.00 30.00 50.00
2 Y 2 10.00 20.00 50.00
Relationship: purchase_order 1 - N purchase_order_items
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal
/* Here, Subtotal should be calculated and displayed */
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
I looked at MySQL finding subtotals and Subtotals and SQL but couldn't apply to my query.
You can use the WITH ROLLUP feature to get subtotals:
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
SUM(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
GROUP BY POID, Item WITH ROLLUP
This will create a result set that has Item = NULL for the PO subtotal, and POID = NULL for a grand total. These subtotals and grand totals go in the ItemTotal column of those rows.
Try
SELECT i.fk_purchase_order POID,
description Item,
quantity ItemQTY,
price ItemPrice,
quantity * price ItemTotal,
s.subtotal SubTotal
FROM purchase_order_items i JOIN
(
SELECT fk_purchase_order, SUM(quantity * price) subtotal
FROM purchase_order_items
GROUP BY fk_purchase_order
) s ON i.fk_purchase_order = s.fk_purchase_order
Output:
| POID | ITEM | ITEMQTY | ITEMPRICE | ITEMTOTAL | SUBTOTAL |
------------------------------------------------------------
| 1 | A | 1 | 15 | 15 | 80.5 |
| 1 | B | 1 | 25.5 | 25.5 | 80.5 |
| 1 | C | 2 | 20 | 40 | 80.5 |
| 2 | X | 6 | 5 | 30 | 50 |
| 2 | Y | 2 | 10 | 20 | 50 |
Here is SQLFiddle demo
Afraid I think the best solution is to cross join against a subselect:-
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal,
Sub1.FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
CROSS JOIN
(
SELECT SUM(purchase_order_items.quantity*purchase_order_items.price) AS FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
) Sub1
To bring it back for grouped purchase order ids
SELECT
purchase_order.id AS POID,
purchase_order_items.description AS Item,
purchase_order_items.quantity AS ItemQTY,
purchase_order_items.price AS ItemPrice,
(purchase_order_items.quantity*purchase_order_items.price) AS ItemTotal,
Sub1.FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
INNER JOIN
(
SELECT purchase_order.id, SUM(purchase_order_items.quantity*purchase_order_items.price GROUP BY purchase_order.id) AS FullTotal
FROM purchase_order
INNER JOIN purchase_order_items ON purchase_order.id = purchase_order_items.fk_purchase_order
) Sub1
ON purchase_order.id = Sub1.id
I got a "Empresas" table
dbo.empresas
id | name | delegacion_id
-------------------------
1 | A | 3
2 | B | 3
3 | C | 3
4 | D | 4
a "pagos" table
dbo.pagos
id | id_empresa | monto | periodo
----------------------------------
1 | 1 | 120 | 2012-11-01
2 | 1 | 125 | 2012-12-01
3 | 2 | 150 | 2012-11-01
4 | 1 | 200 | 2013-01-01
5 | 2 | 151 | 2012-12-01
I have a value X that is a percentage.
I need to show the "empresas" that, comparing the "montos" of their two last "pagos" (ordered by periodo), have changed at least +X% or -X%, from an especific id_delegacion
For example, if we run this query with these example values, considering
X = 10
id_delegacion = 3
the output expected will be:
name | periodo | monto
---------------------------
A | 2012-12-01 | 125
A | 2013-01-01 | 200
empresa A is from delegacion_id = 3, and the comparison between the last two pagos, ordered by periodo desc (200 => 125) is bigger than 10%.
B is not showed because the comparison is smaller than 10%.
C is not showed because has no row in "pagos" table
D is from another delegation.
How can I get this desired output? For the record, using MySQL 5.5.8.
What I've done
I got this
select P.id_empresa, max(periodo) as periodo from
pagos P
where id_empresa in(
select e.id
from empresa E
where E.id_delegacion = 3
)
group by p.id_empresa, p.periodo
having count(*) > 1
with these I got the "empresas" that have more than one "pago" row, and got id_delegation = 3.
Also get the first period (the maximum), but I don't know how to get the second for each empresa, and compare them.
thanks
This is my query:
SELECT
empresas.name,
pagos.periodo,
pagos.monto
FROM
pagos INNER JOIN (
SELECT
lst.id id1,
prc.id id2
FROM (
SELECT
p1.id_empresa,
MAX(p1.periodo) last_p,
MAX(p2.periodo) prec_p
FROM
pagos p1 INNER JOIN pagos p2
ON p1.id_empresa = p2.id_empresa
AND p2.periodo < p1.periodo
GROUP BY
id_empresa) latest
INNER JOIN
pagos lst ON lst.id_empresa = latest.id_empresa AND lst.periodo=latest.last_p
INNER JOIN
pagos prc ON prc.id_empresa = latest.id_empresa AND prc.periodo=latest.prec_p
WHERE
lst.monto > prc.monto * 1.1) ids
ON pagos.id IN (ids.id1, ids.id2)
INNER JOIN
empresas
ON pagos.id_empresa = empresas.id
WHERE
delegacion_id=3
I think it can be simplified if you want to have values on the same row, e.g.
name | ultimo_periodo | ultimo_monto | anterior_periodo | anterior_monto
Please see fiddle here.
I still wondering if it can be simplified a little, but I am not sure if it is. Here's another solution:
SELECT
empresas.name,
pagos.periodo,
pagos.monto
FROM
pagos INNER JOIN empresas
ON pagos.id_empresa = empresas.id
INNER JOIN (
SELECT
id_empresa,
MAX(CASE WHEN row=1 THEN monto END) lst_monto,
MAX(CASE WHEN row=2 THEN monto END) prc_monto,
MAX(id) id1, MIN(id) id2
FROM (
SELECT
p1.*, COUNT(*) row
FROM
pagos p1 INNER JOIN pagos p2
ON p1.id_empresa = p2.id_empresa
AND p1.periodo <= p2.periodo
INNER JOIN empresas
ON p1.id_empresa = empresas.id
WHERE
empresas.delegacion_id = 3
GROUP BY
p1.id, p1.id_empresa, p1.monto, p1.periodo
HAVING
COUNT(*)<=2
ORDER BY
p1.id_empresa, p1.periodo desc
) s
GROUP BY
id_empresa
HAVING
lst_monto>prc_monto*1.1
) l ON pagos.id IN (l.id1, l.id2)
Please see fiddle here.