MYSQL query display quantity of product from multiple tables - mysql

I have table like this
product :
id_product | product_name | price
560 | AAA | 1500
561 | BBB | 1750
attr :
id_attr | id_product | size | qty
100 | 560 | S | 11
100 | 560 | M | 9
100 | 560 | L | 7
100 | 560 | XL | 21
How to display
product_name | qty_S | qty_M | qty_L | qty_XL | qty_total | price
AAA | 11 | 9 | 7 | 21 | 48 | 1500
BBB | 0 | 0 | 0 | 0 | 0 | 1750
i try to make query like this :
select p.*, a.*,
sum(a.qty) as qty_total,
[how_to_display_query] as qty_S,
[how_to_display_query] as qty_M,
[how_to_display_query] as qty_L,
[how_to_display_query] as qty_XL,
FROM product p LEFT JOIN attr a
ON p.id_product = a.id_product
group by p.id_product;
===============================================
Please help me, sorry for bad english... Thanks

you want to pivot the results.. but you cant pivot in mysql as it doesn't have that functionality.. so you need to "fake" a pivot by using an aggregate and a conditional statement
the way to do that is like this.. MAX(CASE... ) SUM(CASE... ) etc.. can also be done with if MAX(IF... ) SUM(IF... ).
SELECT p.product_name
SUM(a.qty) as qty_total,
MAX(CASE size WHEN 'S' THEN qty ELSE 0 END) as qty_S,
MAX(CASE size WHEN 'M' THEN qty ELSE 0 END) as qty_M,
MAX(CASE size WHEN 'L' THEN qty ELSE 0 END) as qty_L,
MAX(CASE size WHEN 'XL' THEN qty ELSE 0 END) as qty_XL,
p.price
FROM product p
LEFT JOIN attr a ON p.id_product = a.id_product
GROUP BY by p.id_product;
i used MAX() here because you only seem to be getting one number.. if you were wanting to add multiple quantities then you can change MAX to SUM

Related

case when condition with group by query with mysql

Below is my mysql query :
SELECT u.id,
CASE WHEN (p.PaymentType = "FreeCredit") THEN SUM(p.CreditedAmount) ELSE 0 END AS freecredit ,
CASE WHEN (p.PaymentType = "Online") THEN SUM(p.CreditedAmount) ELSE 0 END AS onlinepayment,
CASE WHEN (p.PaymentType = "Cash") THEN SUM(p.CreditedAmount) ELSE 0 END AS Cash
FROM users as u
LEFT JOIN payment as p on u.id = p.UserId AND p.PaymentSucc = "Yes"
WHERE
`u`.`UserType` = 'User'
GROUP BY p.UserId
ORDER BY u.id DESC;
Required result : in payment table I have 3 payment type in result I required to show sum for particular payment type for single user like below,
userid= 1974
PaymentType = FreeCredit,CreditedAmount= 120
PaymentType = Online ,CreditedAmount== 140
PaymentType = cash ,CreditedAmount==100
PaymentType = FreeCredit,CreditedAmount== 100
PaymentType = Online ,CreditedAmount== 120
PaymentType = cash ,CreditedAmount==170
in required result it should be as below,
id freecredit onlinepayment Cash
1972 220 260 270
from my query ,I am not able to get above result ,please can any person help me to resolve my this mysql query issue:
I will appreciate best answer.
This is a good question (y)
So,
Here's table user:
mysql> select * from user;
+----+-----------+
| id | user_type |
+----+-----------+
| 1 | krish |
| 2 | bala |
+----+-----------+
Here's table payment:
mysql> select * from payment;
+------+-------------+----------------+
| id | PaymentType | CreditedAmount |
+------+-------------+----------------+
| 1 | FreeCredit | 120 |
| 1 | Online | 140 |
| 1 | cash | 100 |
| 1 | FreeCredit | 100 |
| 1 | Online | 120 |
| 1 | cash | 170 |
| 2 | FreeCredit | 500 |
| 2 | Online | 450 |
| 2 | FreeCredit | 230 |
+------+-------------+----------------+
The goal is to have - for each ID - the sum of 'FreeCredit' / 'Online' / 'cash'
select u.id, sum(case when PaymentType = "FreeCredit" then
CreditedAmount else 0 end) as freeamnt, sum(case when PaymentType =
'Online' then CreditedAmount else 0 end) as Online, sum(case when
PaymentType = 'cash' then Creditedamount else 0 end) as cash from user
as u left join payment as p on u.id=p.id group by p.id order by u.id
desc;
+----+----------+--------+------+
| id | freeamnt | Online | cash |
+----+----------+--------+------+
| 3 | 0 | 0 | 0 |
| 2 | 730 | 450 | 0 |
| 1 | 220 | 260 | 270 |
+----+----------+--------+------+
3 rows in set (0.03 sec)
Note:
I simulated a sample based upon your examples
The query is based on my sample and it won't have all the 'where' conditions you have given

MySQL Crosstab aggregation with 2 conditions

I have a query which creates a crosstab. The results are a count of the txn_id for branda, and the count of txn_id for brandb.
The txn_id is NOT UNIQUE. This is an example of the transactions table.:
txn_id | nationality_id | sku | sales | units
1 | 1 | 1 | 20 | 2
1 | 1 | 2 | 15 | 1
2 | 4 | 1 | 20 | 2
3 | 2 | 1 | 10 | 1
4 | 3 | 2 | 15 | 1
5 | 4 | 1 | 10 | 1
There are 2 other tables (products) - (sku, brand, product name), and (nationalities) - (nationality_id, nationality).
I would like to add a third column which gets me the count of txn_id where BOTH brands are purchased
The output should be
nationality | branda | brandb | combined
1 | 1 | 1 | 1
2 | 1 | 0 | 0
3 | 0 | 1 | 0
4 | 2 | 0 | 0
Current query.
SELECT
nationalities.nationality,
COUNT((CASE brand WHEN 'branda' THEN txn_id ELSE NULL END)) AS branda,
COUNT((CASE brand WHEN 'brandb' THEN txn_id ELSE NULL END)) AS brandb
<I want my 3rd column here>
FROM
transaction_data
INNER JOIN
products USING (sku)
INNER JOIN
nationalities USING (nationality_id)
GROUP BY nationality
ORDER BY branda DESC
LIMIT 20;
I have tried using:
COUNT((CASE brand WHEN 'brandb' OR 'brandb' THEN txn_id ELSE NULL END)) AS combined - however this obviously returns too many (returns branda or brandb regardless of whether they were purchased together). I know I can't use AND, because obviously no single cell is going to be both branda AND brandb.
I have also tried using:
COUNT((CASE brand WHEN IN('branda', 'brandb') THEN txn_id ELSE NULL END)) AS combined - However this isn't valid syntax.
I feel that I should be using a HAVING clause, but I'm not sure how this would work in the column list.
I think you are going to need two levels of aggregation:
SELECT n.nationality,
sum(branda), sum(brandb), sum(branda * brandb)
FROM (SELECT t.txn_id, n.nationality,
MAX(CASE brand WHEN 'branda' THEN 1 ELSE 0 END) AS branda,
MAX(CASE brand WHEN 'brandb' THEN 1 ELSE 0 END) AS brandb
FROM transaction_data t INNER JOIN
products p
USING (sku) INNER JOIN
nationalities n
USING (nationality_id)
GROUP BY t.txn_id, n.nationality
) tn
GROUP BY n.nationality
ORDER BY max(txn_id) DESC
LIMIT 20;

MySQL How to convert second group by parameter results as a column?

The following MySQL query result set repeats MerchantID:
select MerchantID,Category,SUM(Amount)
group by MerchantID,Category
from merchants
This will produce the following result:
MerchantID | Category | Total |
1 | gold | 450 |
1 | silver | 600 |
2 | gold | 1120 |
2 | bronze | 200 |
I want to get the result set like below:
MerchantID | gold | silver | bronze |
1 | 450 | 600 | 0 |
2 | 1120 | 0 | 200 |
I tried many queries but could not get such result. Please provide a solution for my problem. Thanks.
Use conditional aggregation:
select MerchantID,
SUM(CASE WHEN Category = 'gold' THEN Total ELSE 0 END) AS gold,
SUM(CASE WHEN Category = 'silver' THEN Total ELSE 0 END) AS silver,
SUM(CASE WHEN Category = 'bronze' THEN Total ELSE 0 END) AS bronze
from merchants
group by MerchantID
Demo here
You can use this code for example:
SELECT m.merchantId
sum(if(m.Category='gold',m.total,null)) as gold,
sum(if(m.Category='silver',m.total,null)) as silver,
sum(if(m.Category='bronze',m.total,null)) as bronze
FROM merchants m
GROUP BY m.merchantId

Mind numbing SQL madness

This query runs on an invoices table to help me decide who I need to pay
Here's the base table:
The users table
+---------+--------+
| user_id | name |
+---------+--------+
| 1 | Peter |
| 2 | Lois |
| 3 | Stewie |
+---------+--------+
The invoices table:
+------------+---------+----------+--------+---------------+---------+
| invoice_id | user_id | currency | amount | description | is_paid |
+------------+---------+----------+--------+---------------+---------+
| 1 | 1 | usd | 140 | Cow hoof | 0 |
| 2 | 1 | usd | 45 | Cow tail | 0 |
| 3 | 1 | gbp | 1 | Cow nostril | 0 |
| 4 | 2 | gbp | 1500 | Cow nose hair | 0 |
| 5 | 2 | cad | 1 | eyelash | 1 |
+------------+---------+----------+--------+---------------+---------+
I want a resulting table that looks like this:
+---------+-------+----------+-------------+
| user_id | name | currency | SUM(amount) |
+---------+-------+----------+-------------+
| 1 | Peter | usd | 185 |
| 2 | Lois | gbp | 1500 |
+---------+-------+----------+-------------+
The conditions are:
Only consider invoices that have not been paid, so where is_paid = 0
Group them by user_id, by currency
If the SUM(amount) < $100 for the user_id, currency pair then don't bother showing the result, since we don't pay invoices that are less than $100 (or equivalent, based on a fixed exchange rate).
Here's what I've got so far (not working -- which I guess is because I'm filtering by a GROUP'ed parameter):
SELECT
users.user_id, users.name,
invoices.currency, SUM(invoices.amount)
FROM
mydb.users,
mydb.invoices
WHERE
users.user_id = invoices.user_id AND
invoices.is_paid != true AND
SUM(invoices.amount) >=
CASE
WHEN invoices.currency = 'usd' THEN 100
WHEN invoices.currency = 'gbp' THEN 155
WHEN invoices.currency = 'cad' THEN 117
END
GROUP BY
invoices.currency, users.user_id
ORDER BY
users.name, invoices.currency;
Help?
You can't use SUM in a WHERE. Use HAVING instead.
Use HAVING clause instead of SUM in WHERE condition
Try this:
SELECT u.user_id, u.name, i.currency, SUM(i.amount) invoiceAmount
FROM mydb.users u
INNER JOIN mydb.invoices i ON u.user_id = i.user_id
WHERE i.is_paid = 0
GROUP BY u.user_id, i.currency
HAVING SUM(i.amount) >= (CASE i.currency WHEN 'usd' THEN 100 WHEN 'gbp' THEN 155 WHEN 'cad' THEN 117 END)
ORDER BY u.name, i.currency;
Try something like this:
SELECT
user_id, name, currency, sum(amount) due
FROM
invoice i
JOIN users u ON i.user_id=u.user_id
WHERE
is_paid = 0 AND
GROUP BY user_id, currency
having due >= 100
do you store exchange rates? Multiply rates with amount to get actual amount with respect to base currency.
sum(amount*ex_rate) due

HOW do i filter out the latests runs in and crosstab the rowns into columns?

| product | tests | runs | results |
|---------|-------|------|---------|
| A | AD | 1 | 12 |
| A | AD | 2 | 13 |
| A | AD | 3 | 14 |
| A | SS | 1 | 12 |
| A | TD | 1 | 12 |
| A | TD | 2 | 12 |
| B | AD | 1 | 11 |
| B | SS | 1 | 12 |
| c | AD | 1 | 12 |
| c | AD | 2 | 10 |
| D | AD | 1 | 16 |
| D | SS | 1 | 12 |
I used this query:
select DISTINCT Poduct,
SUM (case param_name when 'AD' then results ELSE 0 END) AS AD,
SUM (case param_name when 'SS' then results ELSE 0 END) AS SS,
SUM (case param_name when 'TD' then results ELSE 0 END) AS TD
FROM [product]
GROUP BY product
ORDER BY product
To get it in this format:
| PRODUCT | AD | SS | TD |
|---------|----|----|----|
| A | 39 | 12 | 24 |
| B | 11 | 12 | 0 |
| C | 22 | 0 | 0 |
| D | 16 | 12 | 0 |
I need it in this format, but the problem is that it's adding up all the test runs on AD, SS, and TD.
What I'm looking for is this:
| PRODUCT | AD | SS | TD |
|---------|----|----|----|
| A | 14 | 12 | 12 |
| B | 11 | 12 | 0 |
| C | 10 | 0 | 0 |
| D | 16 | 12 | 0 |
Which is pulling only the results from the greater run of that test.
Can anyone help?
Try this:
select product, max(ad) ad, max(ss) ss, max(td) td
from (
select Product,
MAX(case tests when 'AD' then results ELSE 0 END) AS AD,
MAX(case tests when 'SS' then results ELSE 0 END) AS SS,
MAX(case tests when 'TD' then results ELSE 0 END) AS TD
FROM product
GROUP BY product, tests
) test_reports
group by product
ORDER BY product;
Demo # SQL Fiddle
I think, assuming fro your expected result, you are wanting to SUM on those columns (AD,SS,TD) based on your highest RUN number. You could use ROW_NUMBER to assign the order based on your requirement and choose the right values set
Try this...
WITH CTE AS
( SELECT *, ROW_NUMBER() OVER(partition BY product,test order by runs desc) rownum FROM product
)
select Product,
SUM (case test when 'AD' then results ELSE 0 END) AS AD,
SUM (case test when 'SS' then results ELSE 0 END) AS SS,
SUM (case test when 'TD' then results ELSE 0 END) AS TD
FROM CTE
WHERE rownum=1
GROUP BY product
ORDER BY product
One way to approach this is to think of a temporary table that has the following fields: product, tests, and max_runs. (i.e. identifying the max run # for each combination of product + tests). If you have such a table, you can JOIN it back to the original (inner join) to select only the row with the max run#.
Then, using your case statement on the result will work.
Putting it all together, you would get this:
select P.product,
sum(case P.tests when 'AD' then P.results ELSE 0 END) AS AD,
sum(case P.tests when 'SS' then P.results ELSE 0 END) AS SS,
sum(case P.tests when 'TD' then P.results ELSE 0 END) AS TD
from product P join
(
SELECT product, tests, max(runs) As max_runs
from product
group by product, tests
) As M
on P.product=M.product and P.tests=M.tests and P.runs=M.max_runs
group by P.product
order by P.product
Check out this SQL Fiddle if you want to play with it.