Sum Value as per case in MySql - mysql

As per below MySql Query fetch product count correctly see the red box in image. I need if icat_id 444 than 448 count (158) SUM in category_count (435) of icat_id 444.
After this icat_id 444 total sum of 435 + 158 = 593.
But Case not working properly. Please help
SELECT c.vcategory, c.icat_id,
COUNT( DISTINCT product_cat_rel_1.iprod_id) AS category_count,
UPPER(REGEXP_REPLACE(CONCAT(' ', c.vcategory), ' (.)[^ ]+', '\\1' )) AS category_name,
SUM(CASE WHEN (c.icat_id = '444') THEN 1 WHEN (c.icat_id = '448') THEN 1 ELSE 0 END) AS tt
FROM product
INNER JOIN product_cat_rel_1 ON product_cat_rel_1.iprod_id = product.iprod_id
INNER JOIN product_price ON product_price.iprod_id = product.iprod_id
INNER JOIN category as c ON c.icat_id = product_cat_rel_1.icat_id
WHERE product.estatus='1'
AND product_cat_rel_1.icat_id in (444,448,450,454,471,549,592,741,765,782)
GROUP BY product_cat_rel_1.icat_id

As per requirement group by both 444 and 448 as 444 and sum up corresponding value. Apply changes in given query.
-- MySQL
SELECT c.vcategory,
CASE WHEN product_cat_rel_1.icat_id IN (444, 448)
THEN 444
ELSE product_cat_rel_1.icat_id
END icat_id,
COUNT( DISTINCT product_cat_rel_1.iprod_id) AS category_count,
UPPER(REGEXP_REPLACE(CONCAT(' ', c.vcategory), ' (.)[^ ]+', '\\1' )) AS category_name,
SUM(category_count) AS tt
FROM product
INNER JOIN product_cat_rel_1 ON product_cat_rel_1.iprod_id = product.iprod_id
INNER JOIN product_price ON product_price.iprod_id = product.iprod_id
INNER JOIN category as c ON c.icat_id = product_cat_rel_1.icat_id
WHERE product.estatus='1'
AND product_cat_rel_1.icat_id in (444,448,450,454,471,549,592,741,765,782)
GROUP BY CASE WHEN product_cat_rel_1.icat_id IN (444, 448)
THEN 444
ELSE product_cat_rel_1.icat_id
END

Related

Mysql Select Two Rows in One

I need to select in one row grouped by a same key other two values in the same field:
TABLE
attribute_id
entity_id
value
DATA
attribute_id|entity_id| value
85| 220| 4740
257| 220|image1.png
And need this result:
attibute_id 85 as SKU, attribute_id 257 as IMAGE in this result:
SKU | IMAGE
4740 | image1.png
How can I do this? TIA!
I think this does what you want:
select ts.entity_id, ts.value as sku, ti.value as image
from t ts join
t ti
on ts.entity_id = ti.entity_id and
ts.attribute_id = 85 and
ti.attribute_id = 257;
You can also solve this using conditional aggregation:
select t.entity_id,
max(case when t.attribute_id = 85 then t.value end) as sku,
max(case when t.attribute_id = 257 then t.value end) as image
from t
group by t.entity_id;
If you have attribute_id|entity_id combinations unique across the table you don't need to group data, just join like this:
http://sqlfiddle.com/#!9/1b2f60/2
SELECT a.entity_id,
a.value AS some_attribute1,
b.value AS image
FROM attribs a
LEFT JOIN attribs b
ON a.entity_id = b.entity_id
AND b.attribute_id = 257
WHERE a.attribute_id = 85

Mysql subquery issues

Here is my mysql schema and query.
http://sqlfiddle.com/#!2/73b0d/2
I want sum(each day's memo.discount), date, sum(each day's sale sum(item.sell_price)) in each row. But can't seem to find out the way. How can I do this?
Expected outcome.
total_discount | added_on | total_sale
300 | 2014-06-25 00:00:00 | 1580
230 | 2014-06-26 00:00:00 | 980
Thanks in advance.
SELECT
SUM(m.discount) AS total_discount,
m.added_on,
sub0.total_sold AS total_sale
FROM memo m
LEFT OUTER JOIN
(
SELECT DATE(memo.added_on) AS group_added_on, SUM(item.sell_price) AS total_sold
FROM memo
JOIN memo_item ON memo_item.memo_id = memo.id
JOIN item ON item.id = memo_item.item_id
WHERE memo.showroom_id = 2
GROUP BY group_added_on
) sub0
ON group_added_on = DATE(m.added_on)
WHERE m.showroom_id = 2 and m.added_on BETWEEN '2014-06-25' AND '2014-06-26'
GROUP BY m.added_on
This has a sub query that gets the sum of the selling prices for each day for the showroom_id you are interested in, then joins that back against the memo table.
How about this?
select
sum(m.discount) as total_discount,
m.added_on,
sum(item.sell_price) as total_sale
from memo m
join memo_item on memo_item.memo_id = m.id
join item on item.id = memo_item.item_id
where m.showroom_id = 2 and m.added_on between '2014-06-25' and '2014-06-26'
group by m.added_on
Edit: to use discount only from "memo" table... :
select
sum(discount) as total_discount,
added_on,
sum(subtotal_sale) as total_sale
from
(
select
m.discount,
m.added_on,
sum(item.sell_price) as subtotal_sale
from memo m
join memo_item on memo_item.memo_id = m.id
join item on item.id = memo_item.item_id
where m.showroom_id = 2 and m.added_on between '2014-06-25' and '2014-06-26'
group by m.id
) h
group by added_on

SQL query problems transpose MySQL

There are 2 simple tables
People:
person_id
Name
Reading assestment
date
person_id
quality
speed
Trying to create sql query
SELECT
AVG(r.quality),
AVG(r.speed),
FROM reading_assestment r,people p
where r.person_id =p.person_id
and person_id="3"
Current output:
Quality Speed
77 65
Outcome I am looking for:
Assestment Value
Quality 77
Speed 65
It is something to do with transpose , pivots.
The most general way is to start with your query and then unpivot using separate logic:
select (case when n = 1 then 'Quality' else 'Speed' end) as Assessment,
(case when n = 1 then avg_quality else avg_speed end) as Value
from (select AVG(r.quality) as avg_quality, AVG(r.speed) as avg_speed
from reading_assestment r join
people p
on r.person_id =p.person_id
where person_id = 3
) t cross join
(select 1 as n union all select 2) n
SELECT
AggResults.person_id AS person_id,
Assesment.Name AS AssessmentName,
CASE WHEN Assessment.Name = 'Quality' THEN AggResults.AvgQuality
WHEN Assessment.Name = 'Speed' THEN AggResults.AvgSpeed
ELSE NULL
END AS AssessmentValue
FROM
(
SELECT
people.person_id AS person_id,
AVG(quality) AS AvgQuality,
AVG(speed) AS AvgSpeed
FROM
reading_assessment
INNER JOIN
people
ON reading_assessment.person_id = people.person_id
GROUP BY
people.person_id
)
AS AggResults
CROSS JOIN
(
SELECT 'Quality' AS Name
UNION ALL
SELECT 'Speed' AS Name
)
AS Assessment
WHERE
AggResults.person_id = 3
I moved the = 3 to the outer query, just for ease of use. Most optimisers will treat both options similarly.

How to select grouped records only if every record in a group meets a certain criteria in MySQL?

I'm using MySQL 5.0.88/Coldfusion8 and I have a table that contains products based on barcodes/EANs.
So a product 123 in size S,M,L,XL will have four records in the table
product size ean qty disregard_inventory
123 S 1111111111111 5 0
123 M 1111111111112 7 0
123 L 1111111111113 1 0
123 XL 1111111111114 2 0
Right now I'm searching this table like so:
SELECT count(a.id) AS total_records, a.disregard_inventory, a.qty
FROM artikelstammdaten a
...
GROUP BY a.style
HAVING sum(a.qty) != 0 OR (a.disregard_inventory = 1)
This works ok and selects all products which are not sold out (sum > 0 across all eans)/always available
I now want to add a function, so users can search for products that have at least 1pc in each size. In this case, style 123
123 S 1
123 M 0
123 L 12
123 XL 9
would not be included in the resultset as size M is sold out.
However I can't get it to work. This is what I have (produces rubbish):
GROUP BY a.style
<cfif form.select_type EQ "running_sizes">
HAVING a.qty!= 0 OR ( a.disregard_inventory = 1 )
<cfelse>
HAVING sum(a.bestand) != 0 OR (a.disregard_inventory = 1)
</cfif>
Question:
Is it at all possible to group by style and only include style when each underlying ean has a quantity > 0? If so, thanks for pointers!
EDIT:
here is my full query, which I'm testing with:
SELECT count(a.id) AS gesamt_datensaetze, a.nos, a.nos_anzeige, a.bestand, SUM(a.bestand>0) AS what
FROM artikelstammdaten a
WHERE a.aktiv = "ja"
AND a.firma LIKE "some_company"
// groups by seller_id, style
GROUP BY a.iln, a.artikelnummer
HAVING sum(a.bestand) != 0 OR (a.nos = "ja" AND a.nos_anzeige = "ja")
AND ( SUM(a.bestand > 0) = COUNT(*))
Solution:
Partenthesis mising:
HAVING (( sum(a.bestand) != 0 ) OR (a.nos = "ja" AND a.nos_anzeige = "ja" ))
AND ( SUM(a.bestand > 0) = gesamt_datensaetze )
This works.
I suggest the following query:
SELECT COUNT(a.id) AS total_records, a.disregard_inventory, a.qty
FROM artikelstammdaten a
...
GROUP BY a.style
HAVING (SUM(a.qty) != 0 OR (a.disregard_inventory = 1))
AND (SUM(qty>0) = total_records)
The last condition I added to the query enables to return a style only if the number of sizes for this product (total_records) is equal to the number of available sizes for this product (SUM(qty>0)).
qty>0 will either return 0 (when the product is not available in the given size, or 1 (when it is available). So SUM(qty>0) will return an integer number between 0 and the total number of sizes.
You can accomplish this using a join on a subquery. Basically, join on the set of product IDs where the quantity available is zero, and then only return results where there was no match.
SELECT count(a.id) AS total_records, a.disregard_inventory, a.qty
FROM artikelstammdaten a
LEFT JOIN (
SELECT DISTINCT id
FROM artikelstammdaten
WHERE qty = 0
) b
ON b.id = a.id
WHERE b.id IS NULL
...
GROUP BY a.style
HAVING sum(a.qty) != 0 OR (a.disregard_inventory = 1)
I think you should check MIN(a.qty):
select product from t group by product having min(qty)>0

MySQL SELECT to Rank A Number out of a set of numbers

I have rows of data from a SELECT query with a few prices (say three for this example). One is our price, one is competitor1 price, one is competitor2 price. I want to add a column that spits out the rank of our price as compared to the other two prices; if our price is the lowest it would spit out the number 1 if the highest it would spit out the number it is out of.
Something like this:
Make | Model | OurPrice | Comp1Price | Comp2Price | Rank | OutOf
MFG1 MODEL1 350 100 500 2 3
MFG1 MODEL2 50 100 100 1 3
MFG2 MODEL1 100 NULL 50 2 2
MFG2 MODEL2 9999 500 NULL 2 2
-Sometimes the competitor price will be NULL as seen above, and I believe this is where my issue lies. I have tried a CASE and it works when only on one competitor but when I add a AND statement it spits out the ranks as all NULL. Is there a better way of doing this through a MySQL query?
SELECT
MT.MAKE as Make,
MT.MODEL as Model,
MT.PRICE as OurPrice,
CT1.PRICE as Comp1Price,
CT2.PRICE as Comp2Price,
CASE
WHEN MT.PRICE < CT1.PRICE AND MT.PRICE < CT2.PRICE
THEN 1 END AS Rank
(CT1.PRICE IS NOT NULL) + (CT2.PRICE IS NOT NULL) + 1 as OutOf
FROM mytable MT
LEFT JOIN competitor1table as CT1 ON CT1.MODEL = MT.MODEL
LEFT JOIN competitor2table as CT2 ON CT2.MODEL = MT.MODEL
ORDER BY CLASS
Not tested, but you can try:
SELECT
a.MAKE AS Make,
a.MODEL AS Model,
a.PRICE AS OurPrice
MAX(CASE WHEN a.compnum = 1 THEN pricelist END) AS Comp1Price,
MAX(CASE WHEN a.compnum = 2 THEN pricelist END) AS Comp2Price,
FIND_IN_SET(a.PRICE, GROUP_CONCAT(a.pricelist ORDER BY a.pricelist)) AS Rank,
COUNT(a.pricelist) AS OutOf
FROM
(
SELECT MAKE, MODEL, PRICE, PRICE AS pricelist, 0 AS compnum
FROM mytable
UNION ALL
SELECT a.MAKE, a.MODEL, a.PRICE, CT1.PRICE, 1
FROM mytable a
LEFT JOIN competitor1table CT1 ON a.MODEL = CT1.MODEL
UNION ALL
SELECT a.MAKE, a.MODEL, a.PRICE, CT2.PRICE, 2
FROM mytable a
LEFT JOIN competitor2table CT2 ON a.MODEL = CT2.MODEL
) a
GROUP BY
a.MAKE, a.MODEL
(CT1.PRICE IS NOT NULL AND CT1.PRICE < MT.PRICE) + (CT2.PRICE IS NOT NULL AND CT2.PRICE < MT.PRICE) + 1 as Rank