Total in a mysql pivot query - mysql

I've this pivot query:
SELECT `fonte`,
MAX(IF(month= '1', sell, NULL)) AS Gen,
MAX(IF(month= '2', sell, NULL)) AS Feb,
MAX(IF(month= '3', sell, NULL)) AS Mar,
MAX(IF(month= '4', sell, NULL)) AS Apr,
MAX(IF(month= '5', sell, NULL)) AS Mag,
MAX(IF(month= '6', sell, NULL)) AS Giu,
MAX(IF(month= '7', sell, NULL)) AS Lug,
MAX(IF(month= '8', sell, NULL)) AS Ago,
MAX(IF(month= '9', sell, NULL)) AS Sett,
MAX(IF(month= '10', sell, NULL)) AS Ott,
MAX(IF(month= '11', sell, NULL)) AS Nov,
MAX(IF(month= '12', sell, NULL)) AS Dic,
FROM `pdl_dati` group by fonte
How can I insert the "total" for month='1' and month='2' and month='3' and month='4' and month='5' and month='6' and month='7' and month='8' and month='9' and month='10' and month='11' and month='12'?
Thanks

If you want a final row that has a total for each month you can use GROUP BY WITH ROLLUP:
SELECT `fonte`,
MAX(IF(month= '1', sell, NULL)) AS Gen, -- do you want this to be sum?
MAX(IF(month= '2', sell, NULL)) AS Feb,
MAX(IF(month= '3', sell, NULL)) AS Mar,
MAX(IF(month= '4', sell, NULL)) AS Apr,
MAX(IF(month= '5', sell, NULL)) AS Mag,
MAX(IF(month= '6', sell, NULL)) AS Giu,
MAX(IF(month= '7', sell, NULL)) AS Lug,
MAX(IF(month= '8', sell, NULL)) AS Ago,
MAX(IF(month= '9', sell, NULL)) AS Sett,
MAX(IF(month= '10', sell, NULL)) AS Ott,
MAX(IF(month= '11', sell, NULL)) AS Nov,
MAX(IF(month= '12', sell, NULL)) AS Dic
FROM `pdl_dati`
group by fonte with ROLLUP;
As a side note, if you are attempting to get the total for each fonte by month, I would think you would want to use sum instead of max. See Demo

Related

Changing multiple rows to columns (Pivotable) in a table from mysql [duplicate]

Hi i have the following mysql data
INSERT INTO `monthly` (`id`, `year`, `stat_id`, `cat_id`, `January`, `February`, `March`, `April`, `May`, `June`, `July`, `August`, `September`, `October`, `November`, `December`) VALUES
(1, '2017', '12', '25', '1', '3', '1', '1', '3', '4', '4', '2', '4', '', '', ''),
and i would like it to be convert to be like this
INSERT INTO `monthlydata` (`id`, `year`, `monthName`, `stat_id`, `cat_id`, `data`) VALUES
(1, '2017', 'January', '12', '25', '1'),
(2, '2017', 'February', '12', '25', '3'),
(3, '2017', 'March', '12', '25', '1'),
(4, '2017', 'April', '12', '25', '1'),
(5, '2017', 'May', '12', '25', '3'),
(6, '2017', 'June', '12', '25', '4'),
(7, '2017', 'July', '12', '25', '4'),
(8, '2017', 'August', '12', '25', '2'),
(9, '2017', 'September', '12', '25', '4'),
(10, '2017', 'October', '12', '25', ''),
(11, '2017', 'November', '12', '25', ''),
(12, '2017', 'December', '12', '25', ''),
is there an easier way to do this using mysql/php
You need to UNPIVOT your data. MySQL doesn't have a built in function to do that so you'll need to use multiple queries.
INSERT INTO `monthlydata` (`id`, `year`, `monthName`, `stat_id`, `cat_id`, `data`) VALUES
SELECT id, year, 'January', stat_id, cat_id, January
FROM monthly WHERE monthName = 'January'
UNION ALL
SELECT id, year, 'February', stat_id, cat_id, February
FROM monthly WHERE monthName = 'February'
UNION ALL
SELECT id, year, 'March', stat_id, cat_id, March
FROM monthly WHERE monthName = 'March'
.....
ID column here might cause issues. Depending on how you have defined it. If it is auto generated then you can remove it from the INSERT and let it be auto generated. Since you'll have rows for all months with same ID, you need to handle that scenario.

MySQL count(*) returning 0 even though I used IFNULL and COALESCE

Here is my query:
USE adventureWorks4mysql;
SELECT DISTINCT a.city, count(a.city) as "City Count", emp.Gender as Gender, emp.VacationHours as VacationHours,
(select if(count(*) is null,0, count(*))
FROM address aa
inner join employeeaddress empad on aa.AddressID = empad.AddressID
inner join employee emp on empad.EmployeeID = emp.EmployeeID
where MaritalStatus = 'M' and aa.city = a.city
group by aa.City) as married,
(select ifnull(count(*),0)
FROM address aa
inner join employeeaddress empad on aa.AddressID = empad.AddressID
inner join employee emp on empad.EmployeeID = emp.EmployeeID
where MaritalStatus = 'S' and aa.city = a.city
group by aa.City) as single
FROM address a
inner join employeeaddress empad on a.AddressID = empad.AddressID
inner join employee emp on empad.EmployeeID = emp.EmployeeID
group by a.City;
returns the following:
'Bellevue', '36', 'F', '5', '22', '14'
'Berlin', '1', 'F', '35', NULL, '1'
'Bordeaux', '1', 'M', '34', NULL, '1'
'Bothell', '13', 'M', '9', '7', '6'
'Calgary', '1', 'M', '33', '1', NULL
'Cambridge', '2', 'F', '37', '2', NULL
'Carnation', '5', 'M', '77', '4', '1'
'Detroit', '1', 'M', '38', NULL, '1'
'Duluth', '1', 'F', '24', NULL, '1'
'Duvall', '10', 'F', '80', '3', '7'
'Edmonds', '25', 'M', '84', '16', '9'
'Everett', '18', 'M', '42', '11', '7'
'Gold Bar', '5', 'M', '92', '3', '2'
'Index', '5', 'F', '61', '3', '2'
'Issaquah', '15', 'M', '70', '4', '11'
'Kenmore', '12', 'F', '86', '5', '7'
'Kent', '1', 'F', '5', '1', NULL
'Melbourne', '1', 'F', '36', NULL, '1'
'Memphis', '1', 'M', '29', '1', NULL
'Minneapolis', '1', 'M', '48', NULL, '1'
'Monroe', '14', 'M', '21', '4', '10'
'Nevada', '1', 'F', '27', '1', NULL
'Newport Hills', '7', 'M', '44', '2', '5'
'Ottawa', '1', 'M', '31', '1', NULL
'Portland', '1', 'F', '22', NULL, '1'
'Redmond', '21', 'M', '2', '11', '10'
'Renton', '17', 'M', '6', '12', '5'
'Sammamish', '17', 'F', '31', '6', '11'
'San Francisco', '2', 'M', '16', '2', NULL
'Seattle', '44', 'F', '82', '21', '23'
'Snohomish', '10', 'M', '88', '3', '7'
Not at all clear about you desired result, but is you are attempting to count cities, then I suggest you use "conditional aggregates" instead of your current approach, like this:
SELECT
a.city
, COUNT( a.city ) AS "City Count"
, count(CASE WHEN maritalstatus = 'M' THEN a.city END) AS married
, count(CASE WHEN maritalstatus = 'S' THEN a.city END) AS single
FROM address a
INNER JOIN employeeaddress empad ON a.addressid = empad.addressid
INNER JOIN employee emp ON empad.employeeid = emp.employeeid
GROUP BY
a.city;
Note how the case expression is INSIDE the aggregate function COUNT - hence the term "conditional aggregates" e.g. for singles, if there is a singe status then count that address other wise just ignore that row. nb COUNT does not increment if a value is null.
Please also note that you are only grouping by the single column city. If you really want more result rows because of gender and vacationhours then also use those columns in the GROUP BY clause
SELECT
a.city
, emp.gender AS Gender
, emp.vacationhours AS VacationHours
, COUNT( a.city ) AS "City Count"
, count(CASE WHEN maritalstatus = 'M' THEN a.city END) AS married
, count(CASE WHEN maritalstatus = 'S' THEN a.city END) AS single
FROM address a
INNER JOIN employeeaddress empad ON a.addressid = empad.addressid
INNER JOIN employee emp ON empad.employeeid = emp.employeeid
GROUP BY
a.city
, emp.gender
, emp.vacationhours
;

Rank by calculated variable in MySQL

The following table is for practice only. I will use the code on a much larger table.
SELECT *
FROM price_practice;
gives
id company dt price
'16', 'Amex', '2015-07-01', '5.00'
'17', 'Amex', '2015-07-02', '5.10'
'18', 'Amex', '2015-07-03', '5.00'
'19', 'Amex', '2015-07-06', '5.88'
'20', 'Amex', '2015-07-07', '4.21'
'21', 'Citi', '2015-07-01', '1.00'
'22', 'Citi', '2015-07-02', '1.10'
'23', 'Citi', '2015-07-03', '1.00'
'24', 'Citi', '2015-07-06', '0.88'
'25', 'Citi', '2015-07-07', '1.01'
'26', 'Amex', '2015-07-08', '5.23'
'27', 'Amex', '2015-07-09', '5.35'
'28', 'Amex', '2015-07-10', '5.55'
'29', 'Amex', '2015-07-13', '5.88'
'30', 'Amex', '2015-07-14', '6.01'
'31', 'Citi', '2015-07-08', '0.95'
'32', 'Citi', '2015-07-09', '0.83'
'33', 'Citi', '2015-07-10', '0.79'
'34', 'Citi', '2015-07-13', '0.72'
'35', 'Citi', '2015-07-14', '0.59'
The following snippet calculates the percentage change in price from one date to the next.
SELECT x.id, x.company, x.dt, x.price, (x.price - y.price)/y.price AS 'Change'
FROM
(
SELECT a.id AS aid, MAX(b.id) AS aPrevid
FROM price_practice a
INNER JOIN price_practice b
WHERE a.id > b.id
AND a.company = b.company
GROUP BY a.id
) Sub1
INNER JOIN price_practice x ON Sub1.aid = x.id
INNER JOIN price_practice y ON Sub1.aPrevid = y.id
ORDER BY x.id DESC
As intended, it returns
id company dt price Change
'35', 'Citi', '2015-07-14', '0.59', '-0.180556'
'34', 'Citi', '2015-07-13', '0.72', '-0.088608'
'33', 'Citi', '2015-07-10', '0.79', '-0.048193'
'32', 'Citi', '2015-07-09', '0.83', '-0.126316'
'31', 'Citi', '2015-07-08', '0.95', '-0.059406'
'30', 'Amex', '2015-07-14', '6.01', '0.022109'
'29', 'Amex', '2015-07-13', '5.88', '0.059459'
'28', 'Amex', '2015-07-10', '5.55', '0.037383'
'27', 'Amex', '2015-07-09', '5.35', '0.022945'
'26', 'Amex', '2015-07-08', '5.23', '0.242280'
'25', 'Citi', '2015-07-07', '1.01', '0.147727'
'24', 'Citi', '2015-07-06', '0.88', '-0.120000'
'23', 'Citi', '2015-07-03', '1.00', '-0.090909'
'22', 'Citi', '2015-07-02', '1.10', '0.100000'
'20', 'Amex', '2015-07-07', '4.21', '-0.284014'
'19', 'Amex', '2015-07-06', '5.88', '0.176000'
'18', 'Amex', '2015-07-03', '5.00', '-0.019608'
'17', 'Amex', '2015-07-02', '5.10', '0.020000'
The following snippet does something entirely different: it ranks observations by price for every company seperately.
SELECT (
CASE company
WHEN #curType
THEN #curRow := #curRow + 1
ELSE #curRow := 1 AND #curType := company END
) + 1 AS rank,
id,
company,
dt,
price
FROM price_practice,
(SELECT #curRow := 0, #curType := '') r
ORDER BY company DESC, price DESC;
As intended, it returns
rank id company dt price
'1', '22', 'Citi', '2015-07-02', '1.10'
'2', '25', 'Citi', '2015-07-07', '1.01'
'3', '23', 'Citi', '2015-07-03', '1.00'
'4', '21', 'Citi', '2015-07-01', '1.00'
'5', '31', 'Citi', '2015-07-08', '0.95'
'6', '24', 'Citi', '2015-07-06', '0.88'
'7', '32', 'Citi', '2015-07-09', '0.83'
'8', '33', 'Citi', '2015-07-10', '0.79'
'9', '34', 'Citi', '2015-07-13', '0.72'
'10', '35', 'Citi', '2015-07-14', '0.59'
'1', '30', 'Amex', '2015-07-14', '6.01'
'2', '19', 'Amex', '2015-07-06', '5.88'
'3', '29', 'Amex', '2015-07-13', '5.88'
'4', '28', 'Amex', '2015-07-10', '5.55'
'5', '27', 'Amex', '2015-07-09', '5.35'
'6', '26', 'Amex', '2015-07-08', '5.23'
'7', '17', 'Amex', '2015-07-02', '5.10'
'8', '18', 'Amex', '2015-07-03', '5.00'
'9', '16', 'Amex', '2015-07-01', '5.00'
'10', '20', 'Amex', '2015-07-07', '4.21'
The question is:
How do I rank observations by percentage change?
I imagine you can save the percentage change data in a new column and then rank it, but I suspect this is not the best method. I will do many similar calculations (eg weekly % change, variance etc), and I have around 3,000,000 observations, so the table would grow big quickly. If this is the only way to do it, I will, but I think combining the two snippets above to calculate percentage change and rank in one go would be better. Or what do you think?
As I'm sure you can tell from my question, I'm a beginner at MySQL. Any advise on how to proceed is appreciated!

Convert crosstab query into a view

I have the following query which I want to convert to a view:
SELECT
PartNum,
SUM(IF(DAYOFWEEK(DeliveryDate) = '2', value, NULL)) AS 'Mon',
SUM(IF(DAYOFWEEK(DeliveryDate) = '3', value, NULL)) AS 'Tue',
SUM(IF(DAYOFWEEK(DeliveryDate) = '4', value, NULL)) AS 'Wed',
SUM(IF(DAYOFWEEK(DeliveryDate) = '5', value, NULL)) AS 'Thu',
SUM(IF(DAYOFWEEK(DeliveryDate) = '6', value, NULL)) AS 'Fri',
SUM(IF(DAYOFWEEK(DeliveryDate) = '7', value, NULL)) AS 'Sat',
SUM(IF(DAYOFWEEK(DeliveryDate) = '1', value, NULL)) AS 'Sun',
SUM(IF(DeliveryDate > DATE_ADD(CURDATE(),INTERVAL 7 DAY), value, NULL)) AS 'Future'
FROM (
SELECT PartNum, DeliveryDate , SUM(Ordered) value FROM v_archived_items_due
GROUP BY PartNum, DeliveryDate
) t
GROUP BY PartNum;
When I try to save it as a view, I get the following error:
1349 - Views SELECT contains a subquery in the FROM clause.
The query works fine by itself. How do I turn it into a view?
MySQL does not allow subqueries in view so, without seeing any sample data to see how to rework this without the subqyery. Since this is working as expected, I would create a view of your subquery:
create view view1 as
SELECT PartNum, DeliveryDate , SUM(Ordered) value
FROM v_archived_items_due
GROUP BY PartNum, DeliveryDate;
Then just call this view in your query:
SELECT
PartNum,
SUM(IF(DAYOFWEEK(DeliveryDate) = '2', value, NULL)) AS 'Mon',
SUM(IF(DAYOFWEEK(DeliveryDate) = '3', value, NULL)) AS 'Tue',
SUM(IF(DAYOFWEEK(DeliveryDate) = '4', value, NULL)) AS 'Wed',
SUM(IF(DAYOFWEEK(DeliveryDate) = '5', value, NULL)) AS 'Thu',
SUM(IF(DAYOFWEEK(DeliveryDate) = '6', value, NULL)) AS 'Fri',
SUM(IF(DAYOFWEEK(DeliveryDate) = '7', value, NULL)) AS 'Sat',
SUM(IF(DAYOFWEEK(DeliveryDate) = '1', value, NULL)) AS 'Sun',
SUM(IF(DeliveryDate > DATE_ADD(CURDATE(),INTERVAL 7 DAY), value, NULL)) AS 'Future'
FROM view1
GROUP BY PartNum;
Behavoiur as designed
http://dev.mysql.com/doc/refman/5.1/en/create-view.html
You have to build a view from your subquery and use this.

MySQL count(*) everyday in a month returns [BLOB-2B] instead of number

I'm going to count every rows each day in a month with a specific user id(vwr_tid). Everything works fine - the result shows up in a table but one thing. A count each days doesn't comes up. It becomes [BLOB-xx] instead of number of rows that day. Here is my code :
SELECT MONTH_v, YEAR_V,
GROUP_CONCAT(IF(day_v=1, views, null)) AS '1',
GROUP_CONCAT(IF(day_v=2, views, null)) AS '2',
GROUP_CONCAT(IF(day_v=3, views, null)) AS '3',
GROUP_CONCAT(IF(day_v=4, views, null)) AS '4',
GROUP_CONCAT(IF(day_v=5, views, null)) AS '5',
GROUP_CONCAT(IF(day_v=6, views, null)) AS '6',
GROUP_CONCAT(IF(day_v=7, views, null)) AS '7',
GROUP_CONCAT(IF(day_v=8, views, null)) AS '8',
GROUP_CONCAT(IF(day_v=9, views, null)) AS '9',
GROUP_CONCAT(IF(day_v=10, views, null)) AS '10',
GROUP_CONCAT(IF(day_v=11, views, null)) AS '11',
GROUP_CONCAT(IF(day_v=12, views, null)) AS '12',
GROUP_CONCAT(IF(day_v=13, views, null)) AS '13',
GROUP_CONCAT(IF(day_v=14, views, null)) AS '14',
GROUP_CONCAT(IF(day_v=15, views, null)) AS '15',
GROUP_CONCAT(IF(day_v=16, views, null)) AS '16',
GROUP_CONCAT(IF(day_v=17, views, null)) AS '17',
GROUP_CONCAT(IF(day_v=18, views, null)) AS '18',
GROUP_CONCAT(IF(day_v=19, views, null)) AS '19',
GROUP_CONCAT(IF(day_v=20, views, null)) AS '20',
GROUP_CONCAT(IF(day_v=21, views, null)) AS '21',
GROUP_CONCAT(IF(day_v=22, views, null)) AS '22',
GROUP_CONCAT(IF(day_v=23, views, null)) AS '23',
GROUP_CONCAT(IF(day_v=24, views, null)) AS '24',
GROUP_CONCAT(IF(day_v=25, views, null)) AS '25',
GROUP_CONCAT(IF(day_v=26, views, null)) AS '26',
GROUP_CONCAT(IF(day_v=27, views, null)) AS '27',
GROUP_CONCAT(IF(day_v=28, views, null)) AS '28',
GROUP_CONCAT(IF(day_v=29, views, null)) AS '29',
GROUP_CONCAT(IF(day_v=30, views, null)) AS '30',
GROUP_CONCAT(IF(day_v=31, views, null)) AS '31'
FROM
(
SELECT DAY(vwr_date) AS day_v,
MONTH(vwr_date) AS MONTH_v,
Year(vwr_date) AS YEAR_V,
date(vwr_date) AS date_v,
count(vwr_id) AS views
FROM car_viewer
WHERE Year(vwr_date)='2012' AND vwr_tid='18'
GROUP BY date_v
) as viewz
GROUP BY MONTH_v, YEAR_V
ORDER BY MONTH_v, YEAR_V DESC
The script is updated from #rs : Count record each day of a month from mysql into html table
The result.
I don't see the need for GROUP_CONCAT(), when SUM() will serve your needs:
SELECT MONTH_v, YEAR_V,
SUM(IF(day_v=1, views, 0)) AS '1',
SUM(IF(day_v=2, views, 0)) AS '2',
SUM(IF(day_v=3, views, 0)) AS '3',
SUM(IF(day_v=4, views, 0)) AS '4',
SUM(IF(day_v=5, views, 0)) AS '5',
SUM(IF(day_v=6, views, 0)) AS '6',
SUM(IF(day_v=7, views, 0)) AS '7',
SUM(IF(day_v=8, views, 0)) AS '8',
SUM(IF(day_v=9, views, 0)) AS '9',
SUM(IF(day_v=10, views, 0)) AS '10',
SUM(IF(day_v=11, views, 0)) AS '11',
SUM(IF(day_v=12, views, 0)) AS '12',
SUM(IF(day_v=13, views, 0)) AS '13',
SUM(IF(day_v=14, views, 0)) AS '14',
SUM(IF(day_v=15, views, 0)) AS '15',
SUM(IF(day_v=16, views, 0)) AS '16',
SUM(IF(day_v=17, views, 0)) AS '17',
SUM(IF(day_v=18, views, 0)) AS '18',
SUM(IF(day_v=19, views, 0)) AS '19',
SUM(IF(day_v=20, views, 0)) AS '20',
SUM(IF(day_v=21, views, 0)) AS '21',
SUM(IF(day_v=22, views, 0)) AS '22',
SUM(IF(day_v=23, views, 0)) AS '23',
SUM(IF(day_v=24, views, 0)) AS '24',
SUM(IF(day_v=25, views, 0)) AS '25',
SUM(IF(day_v=26, views, 0)) AS '26',
SUM(IF(day_v=27, views, 0)) AS '27',
SUM(IF(day_v=28, views, 0)) AS '28',
SUM(IF(day_v=29, views, 0)) AS '29',
SUM(IF(day_v=30, views, 0)) AS '30',
SUM(IF(day_v=31, views, 0)) AS '31'
FROM
(
SELECT DAY(vwr_date) AS day_v,
MONTH(vwr_date) AS MONTH_v,
Year(vwr_date) AS YEAR_V,
date(vwr_date) AS date_v,
count(vwr_id) AS views
FROM car_viewer
WHERE Year(vwr_date)='2012' AND vwr_tid='18'
GROUP BY date_v
) as viewz
GROUP BY MONTH_v, YEAR_V
ORDER BY MONTH_v, YEAR_V DESC;
See http://sqlfiddle.com/#!2/75aa8/1 for a working example.