Pivot Table MySQL? - mysql

I Have A Query :
SELECT item_id,
MAX(CASE WHEN `vendor_id` = 2
THEN price
END) AS "Bandung",
MAX(CASE WHEN `vendor_id` = 3
THEN price
END) AS "Vendor Bandung",
MAX(CASE WHEN `vendor_id` = 4
THEN price
END) AS "Jakarta",
MIN(price)
FROM transactions
GROUP BY item_id
Output:
I Want to get detail information about price from where,.. like below
|ItemID|Bandung|Vendor Bandung|Jakarta |Price Min|*Area*
|10001 |12000 |11000 |9000 |9000 |*Jakarta|*
|10002 |12000 |11000 |12400 |11000 |*Vendor Bandung|*
|10004 |12000 |11000 |12400 |11000 |*Vendor Bandung|*
|10005 |12000 |11000 |12400 |11000 |*Vendor Bandung|*

WITH cte AS (
SELECT item_id,
MAX(CASE WHEN vendor_id = 2
THEN price
END) AS Bandung,
MAX(CASE WHEN vendor_id = 3
THEN price
END) AS `Vendor Bandung`,
MAX(CASE WHEN vendor_id = 4
THEN price
END) AS Jakarta,
MIN(price) MinPrice
FROM transactions
GROUP BY item_id
)
SELECT *,
CASE MinPrice WHEN Bandung THEN 'Bandung'
WHEN `Vendor Bandung` THEN 'Vendor Bandung'
WHEN Jakarta THEN 'Jakarta'
ELSE 'unknown'
END Area
FROM cte
For ancient versions:
SELECT *,
CASE MinPrice WHEN Bandung THEN 'Bandung'
WHEN `Vendor Bandung` THEN 'Vendor Bandung'
WHEN Jakarta THEN 'Jakarta'
ELSE 'unknown'
END Area
FROM
(
SELECT item_id,
MAX(CASE WHEN vendor_id = 2
THEN price
END) AS Bandung,
MAX(CASE WHEN vendor_id = 3
THEN price
END) AS `Vendor Bandung`,
MAX(CASE WHEN vendor_id = 4
THEN price
END) AS Jakarta,
MIN(price) MinPrice
FROM transactions
GROUP BY item_id
) cte

SQL
SELECT DATASET.`bandung`,
DATASET.`vendor bandung`,
DATASET.`jakarta`,
DATASET.`price min`,
( CASE DATASET.`price min`
WHEN DATASET.`bandung` THEN "bandung"
WHEN DATASET.`vendor bandung` THEN "vendor bandung"
WHEN DATASET.`jakarta` THEN "jakarta"
ELSE "otrher"
end ) AS "Area"
FROM (SELECT item_id,
Max(CASE
WHEN `vendor_id` = 2 THEN price
end) AS "Bandung",
Max(CASE
WHEN `vendor_id` = 3 THEN price
end) AS "Vendor Bandung",
Max(CASE
WHEN `vendor_id` = 4 THEN price
end) AS "Jakarta",
Min(price) AS "Price Min"
FROM transactions
GROUP BY item_id) DATASET
Table
SELECT * FROM transactions;
Result

Related

How to make this sql query compatible for older verisons of mysql such v.5.5 and above?

I have this query it works on MySQL 8.0 but not on the below versions like MySQL 5.5. How to make this compatible as I am getting this error on web server: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(partition by pid order by age' at line 11
SELECT p.id, p.pid, p.name,
MAX(CASE WHEN t.dr = 1 THEN t.name END) as name1,
MAX(CASE WHEN t.dr = 1 THEN age END) as age1,
MAX(CASE WHEN t.dr = 2 THEN t.name END) as name2,
MAX(CASE WHEN t.dr = 2 THEN t.age END) as age2,
MAX(CASE WHEN t.dr = 3 THEN t.name END) as name3,
MAX(CASE WHEN t.dr = 3 THEN t.age END) as age3,
MAX(CASE WHEN t.dr = 4 THEN t.name END) as name4,
MAX(CASE WHEN t.dr = 4 THEN t.age END) as age4
FROM Table1 p
join (select id , pid, name, age, DENSE_RANK() OVER (partition by pid order by age) as dr
from Table2) t on p.pid= t.pid
group by p.id, p.pid, p.name
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=d324e7654218dae3d1168df2bf529099
select version();
version()
5.5.62
Schema:
CREATE TABLE Table1
(id int , name varchar(15) , pid int )
INSERT INTO Table1
values (1, 'Jack', 1521),
(2, 'Steve',1522)
CREATE TABLE Table2
(id int, pid int, name varchar(15), age int);
INSERT INTO Table2
VALUES
(1, 1521, 'John', 12),
(2, 1521, 'Maria', 7),
(3, 1521, 'Larry', 3),
(4, 1522, 'Harry', 5)
Query:
SELECT p.id, p.pid, p.name,
MAX(CASE WHEN t.dr = 1 THEN t.name END) as name1,
MAX(CASE WHEN t.dr = 1 THEN age END) as age1,
MAX(CASE WHEN t.dr = 2 THEN t.name END) as name2,
MAX(CASE WHEN t.dr = 2 THEN t.age END) as age2,
MAX(CASE WHEN t.dr = 3 THEN t.name END) as name3,
MAX(CASE WHEN t.dr = 3 THEN t.age END) as age3,
MAX(CASE WHEN t.dr = 4 THEN t.name END) as name4,
MAX(CASE WHEN t.dr = 4 THEN t.age END) as age4
FROM Table1 p
join (select id , pid, name, age, (select count(*) from Table2 t2
where t.pid=t2.pid and t2.age<=t.age) as dr
from Table2 t) t on p.pid= t.pid
group by p.id, p.pid, p.name
Output:
id
pid
name
name1
age1
name2
age2
name3
age3
name4
age4
1
1521
Jack
Larry
3
Maria
7
John
12
null
null
2
1522
Steve
Harry
5
null
null
null
null
null
null
db<>fiddle here
One method is a correlated subquery to replace DENSE_RANK():
FROM Table1 p JOIN
(SELECT t2.*,
(SELECT COUNT(DISTINCT tt2.age)
FROM table2 tt2
WHERE tt2.pid = t2.pid AND
tt2.age <= t2.age
) as dr
FROM Table2 t2
) t
ON p.pid = t.pid
Here is a db<>fiddle.

Total purchase, sales and stock remained for each product using mysql

I am trying to get total purchase, sales and sotck remained for reach product using mysql query which is as follows:
select fk_product_id,
(select sum(quantity) from entry_products where status =0 ) as total_purchase,
(select sum(quantity) from entry_products where status =1)as total_sales,
(select sum(quantity) from entry_products where status =0 ) -
(select sum(quantity) from entry_products where status =1) as stock
from entry_products group by fk_product_id
Output
fk_product_id total_purchase total_sales stock
1 1700 660 1040
2 1700 660 1040
3 1700 660 1040
My Expected Output is
fk_product_id total_purchase total_sales stock
1 350 200 150
2 1100 460 640
3 250 0 250
You need conditional aggregation:
select fk_product_id,
sum(case when status = 0 then quantity else 0 end) as total_purchase,
sum(case when status = 1 then quantity else 0 end) as total_sales,
sum(case when status = 0 then quantity else 0 end) - sum(case when status = 1 then quantity else 0 end) as stock
from entry_products
group by fk_product_id
Because MySql evaluates boolean expressions as 1 for true or 0 for false, the code could be written also like this:
select fk_product_id,
sum((status = 0) * quantity) as total_purchase,
sum((status = 1) * quantity) as total_sales,
sum((status = 0) * quantity) - sum((status = 1) * quantity) as stock
from entry_products
group by fk_product_id

Subquery returns more than 1 row MySQL?

SELECT *,
CASE MinPrice WHEN Bandung THEN 'Bandung'
WHEN `Vendor Bandung` THEN 'Vendor Bandung'
WHEN Jakarta THEN 'Jakarta'
WHEN KJ THEN 'KJ'
ELSE 'unknown'
END AREA,
(SELECT trx.sumber_id FROM `transactions` AS trx WHERE cte.item_id = trx.item_id AND cte.MinPrice = trx.price) AS `sumber_id`
FROM
(
SELECT item_id ,
MAX(CASE WHEN vendor_id = 2
THEN price
END) AS Bandung,
MAX(CASE WHEN vendor_id = 3
THEN price
END) AS `Vendor Bandung`,
MAX(CASE WHEN vendor_id = 4
THEN price
END) AS Jakarta,
MAX(CASE WHEN vendor_id = 5
THEN price
END) AS KJ,
MIN(NULLIF(price, 0)) MinPrice
FROM
transactions
WHERE `start_periode` = '2020-02-17'
GROUP BY `item_id`, `start_periode`
) cte;
i got error :
Query: SELECT *, CASE MinPrice WHEN Bandung THEN 'Bandung' WHEN Vendor Bandung THEN 'Vendor Bandung' WHEN Jakarta THEN 'Jakarta' WHEN...
Error Code: 1242
Subquery returns more than 1 row
I would just write this query as:
SELECT
t1.item_id,
t1.sumber_id,
COALESCE(t2.min_price, 0) AS min_price
FROM transactions t1
LEFT JOIN
FROM
(
SELECT item_id, MIN(price) AS min_price
FROM transactions
WHERE start_periode = '2020-02-17' AND vendor_id IN (2,3,4,5)
GROUP BY item_id
) t2
ON t1.item_id = t2.item_id;

need absent and present count with month name

I need a month name with absent and present count. This is my database query:
SELECT sid,COUNT(CASE WHEN STATUS ='A' THEN 1 END) AS absent_count,COUNT(CASE WHEN STATUS ='P' THEN 1 END) AS present_count,
MONTHNAME(attendance_date) AS `Month_Name`
FROM attendance
WHERE SID = '2'
AND campus_id = 2
GROUP BY sid;
There's no point in group by sid - it will always be '2', as per your where clause. Instead, since you want to count per month name, that should appear in the group by clause:
SELECT MONTHNAME(attendance_date) AS `Month_Name`,
COUNT(CASE WHEN STATUS ='A' THEN 1 END) AS absent_count,
COUNT(CASE WHEN STATUS ='P' THEN 1 END) AS present_count,
FROM attendance
WHERE sid = '2' AND campus_id = 2
GROUP BY MONTHNAME(attendance_date);

MySql: Displaying Sums of all rows for each column as an extra row at the end

How do I get the sum of each column for all rows of a result-set? I mean I want to display the sums-row as the last row of my result-set.
My query looks like this:
select f.filename,
count(distinct case when v.rUser like '%bike%' then 1 else null end) as bikeUser,
count(distinct case when v.rUser like '%Pedestrian%' then 1 else null end) as pedestrianUser,
count(distinct case when d.weather like '%clear%' then 1 else null end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else null end) as hatExtras
from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename;
When I use with roll up after the 'group by' clause, it gives me sum of the groups generated by the 'group by clause' (horizontal sum) whereas I need the vertical sum of each column at the end.
Any ideas?
Your ROLLUP is already correct, it's really the COUNT(CASE WHEN Field = 'Blah' THEN 1 ELSE 0 END) is the main culprit why your query is not working
You must do either:
COUNT(CASE WHEN Field = 'Blah' THEN 1 END)
or
SUM(CASE WHEN Field = 'Blah' THEN 1 ELSE 0 END)
But since MySQL has a duality between boolean and integer type like it is in C language, hence you can do this too:
SUM(Field = 'Blah')
This is your incorrect query (wrong results): http://www.sqlfiddle.com/#!2/70187/1
create table ProductInventory(
ProductCode varchar(10) not null,
Location varchar(50) not null
);
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','CN');
insert into ProductInventory(ProductCode,Location) values('KB','CN');
insert into ProductInventory(ProductCode,Location) values('KB','JP');
insert into ProductInventory(ProductCode,Location) values('KB','US');
insert into ProductInventory(ProductCode,Location) values('MOUSE','US');
insert into ProductInventory(ProductCode,Location) values('MOUSE','CN');
Incorrect Output:
PRODUCTCODE USQTY CHINAQTY
CPU 3 3
KB 3 3
MOUSE 2 2
8 8
This is the correct query: http://www.sqlfiddle.com/#!2/70187/2
select ProductCode,
COUNT(CASE WHEN Location = 'US' THEN 1 END) as UsQty,
COUNT(CASE WHEN Location = 'CN' THEN 1 END) as ChinaQty
from ProductInventory
group by ProductCode with rollup
Correct output:
PRODUCTCODE USQTY CHINAQTY
CPU 2 1
KB 1 1
MOUSE 1 1
4 3
Please, don't insist that this is correct, this is very incorrect:
COUNT(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) AS UsQty
You must either do this (correct) :
COUNT(CASE WHEN Location = 'US' THEN 1 END) AS UsQty
Or this (correct) : http://www.sqlfiddle.com/#!2/70187/5
SUM(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) AS UsQty
Or this (correct) : http://www.sqlfiddle.com/#!2/70187/6
SUM(CASE WHEN Location = 'US' THEN 1 END) AS UsQty
Or try take advantage of the fact that MySql has duality between boolean and integer (correct) : http://www.sqlfiddle.com/#!2/70187/4
SUM(Location = 'US') AS UsQty
Bottomline
Please don't use this (incorrect) : http://www.sqlfiddle.com/#!2/70187/3
COUNT(Location = 'US') as UsQty
And please don't use this too (incorrect, similar to your query): http://www.sqlfiddle.com/#!2/70187/1
COUNT(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) as UsQty
By the way, this also works, it's for you to find out why ;-)
COUNT(CASE WHEN Location = 'US' THEN 1976 END) AS UsQty
UPDATE
I have an inkling that this is what you need:
create table Product
(
ProductCode varchar(10) not null primary key,
ProductName varchar(100) not null
);
insert into Product(ProductCode,ProductName) values
('CPU','Central Processing Unit'),
('KB','Keyboard'),
('MSE','Mouse'),
('RAM', 'Random Access Memory');
create table ProductInventory(
ProductCode varchar(10) not null,
Location varchar(50) not null
);
insert into ProductInventory(ProductCode,Location) values
('CPU','US'),
('CPU','PH'),
('CPU','PH'),
('KB','PH'),
('KB','US'),
('KB','US'),
('MSE','US'),
('MSE','JP');
select p.ProductCode,
coalesce(SUM(i.Location = 'US'),0) as UsQty,
coalesce(SUM(i.Location = 'PH'),0) as PhilippinesQty
from Product p
left join ProductInventory i on i.ProductCode = p.ProductCode
group by p.ProductCode with rollup
Output:
ProductCode UsQty PhilippinesQty
CPU 1 2
KB 2 1
MSE 1 0
RAM 0 0
4 4
Live test: http://www.sqlfiddle.com/#!2/2bb09/1
Don't use COUNT for counting when you are using evaluation; despite the name, SUM would yield the correct result for counting based on conditions:
Given this: http://www.sqlfiddle.com/#!2/79375/1
create table ProductInventory(
ProductCode varchar(10) not null,
Location varchar(50) not null
);
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','ARM');
insert into ProductInventory(ProductCode,Location) values('KB','CN');
insert into ProductInventory(ProductCode,Location) values('KB','PH');
insert into ProductInventory(ProductCode,Location) values('KB','US');
insert into ProductInventory(ProductCode,Location) values('MOUSE','AA');
insert into ProductInventory(ProductCode,Location) values('MOUSE','BB');
select ProductCode, COUNT(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) as Qty
from ProductInventory
group by ProductCode
order by ProductCode
That will produce incorrect results:
PRODUCTCODE QTY
CPU 3
KB 3
MOUSE 2
Use SUM instead, correct results: http://www.sqlfiddle.com/#!2/79375/3
select ProductCode, SUM(Location = 'US') as Qty
from ProductInventory
group by ProductCode
order by ProductCode
That would result to:
PRODUCTCODE QTY
CPU 2
KB 1
MOUSE 0
COUNT works by counting the NON-nullness of value or expression
If you still want to use COUNT, pass any non-null value to COUNT; and don't use ELSE NULL END, your query will look tedious, just saying :-) http://www.sqlfiddle.com/#!2/79375/4
select ProductCode, COUNT(CASE WHEN Location = 'US' THEN Location END) as Qty
from ProductInventory
group by ProductCode
order by ProductCode
Output:
PRODUCTCODE QTY
CPU 2
KB 1
MOUSE 0
You can create a temptable (#mytemptable) and add the sum as last entry and then return the select of the created temptable. But this is only working in stored procedures I think.
select f.filename,
count(case when v.rUser like '%bike%' then 1 else 0 end) as bikeUser,
count(case when v.rUser like '%Pedestrian%' then 1 else 0 end) as pedestrianUser,
count(case when d.weather like '%clear%' then 1 else 0 end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else 0 end) as hatExtras
INTO #myTempTable from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename;
INSERT INTO #myTempTable select(create the sum here but care that you have the same columns)
SELECT * FROM #myTempTable
within just one select you can do it with the command "UNION"
*EDITED: 27.04. 11:55
select f.filename,
count(case when v.rUser like '%bike%' then 1 else 0 end) as bikeUser,
count(case when v.rUser like '%Pedestrian%' then 1 else 0 end) as pedestrianUser,
count(case when d.weather like '%clear%' then 1 else 0 end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else 0 end) as hatExtras
from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename;
UNION
SELECT SUM(bikeUser), SUM(pedestrianUser), SUM(clearWeather), SUM(hatExtras)
FROM (
select f.filename,
count(case when v.rUser like '%bike%' then 1 else 0 end) as bikeUser,
count(case when v.rUser like '%Pedestrian%' then 1 else 0 end) as pedestrianUser,
count(case when d.weather like '%clear%' then 1 else 0 end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else 0 end) as hatExtras
from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename) as summary
hope this helps :)