Related
I have created a monthly chart using Google charts but the bars are showing up even when the value is zero.
Here is the screenshot of it
and here is the code and I know code is vulnerable to SQL Injection. You can ignore it. This is only for testing purpose
Previously order_total_amount column was set to "VARCHAR" datatype, then someone suggested that it should set to the "INT". So I changed it from Varchar to Int. But that didn't solved the problem. Bar is still showing up despite having 0 value
<script type="text/javascript">
google.charts.load('current', {'packages':['bar']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Monthly', 'Sales'],
<?php
$sale_chart = "SELECT
SUM(IF(month = 'Jan', total, 0)) AS 'Jan',
SUM(IF(month = 'Feb', total, 0)) AS 'Feb',
SUM(IF(month = 'Mar', total, 0)) AS 'Mar',
SUM(IF(month = 'Apr', total, 0)) AS 'Apr',
SUM(IF(month = 'May', total, 0)) AS 'May',
SUM(IF(month = 'Jun', total, 0)) AS 'Jun',
SUM(IF(month = 'Jul', total, 0)) AS 'Jul',
SUM(IF(month = 'Aug', total, 0)) AS 'Aug',
SUM(IF(month = 'Sep', total, 0)) AS 'Sep',
SUM(IF(month = 'Oct', total, 0)) AS 'Oct',
SUM(IF(month = 'Nov', total, 0)) AS 'Nov',
SUM(IF(month = 'Dec', total, 0)) AS 'Dec'
FROM
(SELECT
MIN(DATE_FORMAT(order_date, '%b')) AS month,
SUM(order_total_amount) AS total
FROM
invoice_order
WHERE
user_id = '$user_id'
GROUP BY YEAR(order_date) , MONTH(order_date)
ORDER BY YEAR(order_date) , MONTH(order_date)) AS sale";
$sale_chart_query = mysqli_query($connection,$sale_chart) or die(mysqli_error($connection));
$sale_chart_array = mysqli_fetch_assoc($sale_chart_query);
foreach($sale_chart_array as $x => $val) { ?>
['<?php echo $x; ?>','<?php echo $val; ?>'],
<?php } ?>
]);
var options = {
};
var chart = new google.charts.Bar(document.getElementById('chart_div'));
chart.draw(data, google.charts.Bar.convertOptions(options));
}
</script>
After replacing zero with null, that is how it showing up the result
using a value of null in the chart's data table will prevent a bar from appearing.
see following working snippet...
in this case, you're including strings instead of numbers in the data table.
remove the single quotes from the second array value, here...
['<?php echo $x; ?>',<?php echo $val; ?>],
google.charts.load('current', {
packages: ['bar']
}).then(function drawChart() {
var data = google.visualization.arrayToDataTable([
['Monthly', 'Sales'],
['Jan', 1000],
['Feb', null],
['Mar', null],
['Apr', null],
['May', 40000],
['Jun', null],
['Jul', null],
['Aug', null],
['Sep', null],
['Oct', null],
['Nov', null],
['Dec', null]
]);
var options = {};
var chart = new google.charts.Bar(document.getElementById('chart_div'));
chart.draw(data, google.charts.Bar.convertOptions(options));
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I am attempting to speed up a SQL query in MySql 5.7 by replacing YEAR() and MONTH() functions with their numeric equivalents during insert time. Specifically, I added the columns reportMonth, reportYear, both bigint(20) for that.
Interestingly, that approach is much slower. Why is that so? Shouldn't it be faster to run a query with fewer functions in it?
This takes about 12 seconds to complete. (with YEAR() and MONTH() functions)
SELECT
ProductTitle AS 'ProductTitle',
YEAR(ReportPeriodEndDay) AS 'Year',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 1 THEN OrderedRevenue END) AS 'Jan',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 2 THEN OrderedRevenue END) AS 'Feb',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 3 THEN OrderedRevenue END) AS 'Mar',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 4 THEN OrderedRevenue END) AS 'Apr',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 5 THEN OrderedRevenue END) AS 'May',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 6 THEN OrderedRevenue END) AS 'Jun',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 7 THEN OrderedRevenue END) AS 'Jul',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 8 THEN OrderedRevenue END) AS 'Aug',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 9 THEN OrderedRevenue END) AS 'Sep',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 10 THEN OrderedRevenue END) AS 'Oct',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 11 THEN OrderedRevenue END) AS 'Nov',
SUM(CASE WHEN MONTH(ReportPeriodEndDay) = 12 THEN OrderedRevenue END) AS 'Dec',
SUM(OrderedRevenue) AS 'TOTAL'
FROM
`sales_diagnostic_summary_orderedrevenuelevel`
GROUP BY ProductTitle, Year
WITH ROLLUP;
Result from EXPLAIN
# id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, SIMPLE, sales_diagnostic_summary_orderedrevenuelevel, , ALL, , , , , 745140, 100.00, Using temporary; Using filesort
This takes more than 120 seconds (with numeric equivalents)
SELECT
ProductTitle AS 'ProductTitle',
reportYear AS 'Year',
SUM(CASE WHEN reportMonth = 1 THEN OrderedRevenue END) AS 'Jan',
SUM(CASE WHEN reportMonth = 2 THEN OrderedRevenue END) AS 'Feb',
SUM(CASE WHEN reportMonth = 3 THEN OrderedRevenue END) AS 'Mar',
SUM(CASE WHEN reportMonth = 4 THEN OrderedRevenue END) AS 'Apr',
SUM(CASE WHEN reportMonth = 5 THEN OrderedRevenue END) AS 'May',
SUM(CASE WHEN reportMonth = 6 THEN OrderedRevenue END) AS 'Jun',
SUM(CASE WHEN reportMonth = 7 THEN OrderedRevenue END) AS 'Jul',
SUM(CASE WHEN reportMonth = 8 THEN OrderedRevenue END) AS 'Aug',
SUM(CASE WHEN reportMonth = 9 THEN OrderedRevenue END) AS 'Sep',
SUM(CASE WHEN reportMonth = 10 THEN OrderedRevenue END) AS 'Oct',
SUM(CASE WHEN reportMonth = 11 THEN OrderedRevenue END) AS 'Nov',
SUM(CASE WHEN reportMonth = 12 THEN OrderedRevenue END) AS 'Dec',
SUM(OrderedRevenue) AS 'TOTAL'
FROM
`sales_diagnostic_summary_orderedrevenuelevel`
GROUP BY ProductTitle, Year
WITH ROLLUP;
Result from EXPLAIN
# id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, SIMPLE, sales_diagnostic_summary_orderedrevenuelevel, , ALL, , , , , 745140, 100.00, Using filesort
Table mapping via DESCRIBE
# Field, Type, Null, Key, Default, Extra
ASIN, text, YES, MUL, ,
ProductTitle, text, YES, , ,
OrderedRevenue, double, YES, , ,
OrderedRevenuePercentOfTotal, double, YES, , ,
OrderedRevenuePriorPeriod, double, YES, , ,
OrderedRevenueLastYear, double, YES, , ,
OrderedUnits, double, YES, , ,
OrderedUnitsPercentOfTotal, double, YES, , ,
OrderedUnitsPriorPeriod, double, YES, , ,
OrderedUnitsLastYear, double, YES, , ,
SubcategorySalesRank, bigint(20), YES, , ,
SubcategoryBetterWorse, double, YES, , ,
AverageSalesPrice, double, YES, , ,
AverageSalesPricePriorPeriod, double, YES, , ,
ChangeInGVPriorPeriod, double, YES, , ,
ChangeInGVLastYear, double, YES, , ,
RepOOS, double, YES, , ,
RepOOSPercentOfTotal, double, YES, , ,
RepOOSPriorPeriod, double, YES, , ,
LBBPrice, double, YES, , ,
ReportPeriodStartDay, datetime, YES, , ,
ReportPeriodEndDay, datetime, YES, , ,
ReportDownloadDate, datetime, YES, , ,
ReportPeriod, text, YES, , ,
ReportFilename, text, YES, , ,
marketplace, text, YES, , ,
vendorId, text, YES, , ,
reportYear, bigint(20), YES, MUL, ,
reportMonth, bigint(20), YES, MUL, ,
reportWeek, bigint(20), YES, , ,
reportQuarter, bigint(20), YES, , ,
reportDayOfWeek, bigint(20), YES, , ,
reportDayOfYear, bigint(20), YES, , ,
There seems to be some optimization linked to the YEAR function, of which DESCRIBE knows nothing about (which is logical enough).
The way I would have implemented it is, when the YEAR function is called, if it sees that MONTH is called too, it does additional binning for the month value. Then, that part of the work is already done, and better, than through a CASE on an unrelated field (because the fact that it is called reportMonth does not make it related).
Since each year has no more than 12 months, that seems a worthwhile optimization - it won't use too much memory and the potential rewards are appreciable.
If you have a lot of sales per product, you might try a straight grouping by reportYear and reportMonth, and then run the CASE pivoting as a wrapping SELECT. Something like:
SELECT
ProductTitle,
reportYear as `Year`,
SUM(IF (reportMonth = 1, OrderedRevenue, 0) AS 'Jan',
...
SUM(IF (reportMonth = 12, OrderedRevenue, 0) AS 'Dec',
SUM(OrderedRevenue) AS 'TOTAL'
FROM (
SELECT productTitle,
reportYear,
reportMonth,
SUM(OrderedRevenue) AS OrderedRevenue
FROM
`sales_diagnostic_summary_orderedrevenuelevel`
GROUP BY ProductTitle, reportYear, reportMonth
) AS firstGrouping;
Very likely, having an index
CREATE INDEX myIndex ON
sales_diagnostic_summary_orderedrevenuelevel(ProductTitle,
reportYear, reportMonth, OrderedRevenue);
while costing something during UPDATE/DELETE/INSERTs, should improve things during this kind of SELECT. You might want to try the DATE version of both double-select and indexing on for size.
Additionally, I don't think there's any reason to store year, month and week as BIGINT. It won't make all that difference either in performance or in storage, but it still smells a bit to me.
i have a table collaborator that contains:
the columns : hiring_date and release_date ( date type)
i would like to calculate the total number of collaborators per month of a year
using hiring_date and release_date
I guess you are asking for something like this but please, try to give more information when asking
SELECT COUNT(*) FROM collaborator WHERE hiring_date >= date AND release_date<= date
You can use "GROUP BY" for this.
e.g., To calculate the total number of collaborators per month using hiring_date :
SELECT MONTH(hiring_date),COUNT(*) FROM `collaborator`
GROUP BY MONTH(hiring_date);
To calculate the total number of collaborators per month of a year using release_date, use :
SELECT MONTH(release_date),COUNT(*) FROM `collaborator `
GROUP BY MONTH(release_date)
WHERE YEAR(release_date) = <year>;
this code is to get number of hiring collaborators on 2016 per month
SELECT
SUM(IF(month = '1', total, 0)) AS 'Jan',
SUM(IF(month = '2', total, 0)) AS 'Feb',
SUM(IF(month = '3', total, 0)) AS 'Mar',
SUM(IF(month = '4', total, 0)) AS 'Apr',
SUM(IF(month = '5', total, 0)) AS 'May',
SUM(IF(month = '6', total, 0)) AS 'Jun',
SUM(IF(month = '7', total, 0)) AS 'Jul',
SUM(IF(month = '8', total, 0)) AS 'Aug',
SUM(IF(month = '9', total, 0)) AS 'Sep',
SUM(IF(month = '10', total, 0)) AS 'Oct',
SUM(IF(month = '11', total, 0)) AS 'Nov',
SUM(IF(month = '12', total, 0)) AS 'Dec'
FROM (
SELECT month(DATE_ENTREE) AS month , count(DATE_ENTREE) as total
FROM collaborateur where YEAR(DATE_ENTREE) =2016
GROUP BY month(DATE_ENTREE)) as e
and this code is the number of release per month on 2016
SELECT
SUM(IF(month = '1', total, 0)) AS 'Jan',
SUM(IF(month = '2', total, 0)) AS 'Feb',
SUM(IF(month = '3', total, 0)) AS 'Mar',
SUM(IF(month = '4', total, 0)) AS 'Apr',
SUM(IF(month = '5', total, 0)) AS 'May',
SUM(IF(month = '6', total, 0)) AS 'Jun',
SUM(IF(month = '7', total, 0)) AS 'Jul',
SUM(IF(month = '8', total, 0)) AS 'Aug',
SUM(IF(month = '9', total, 0)) AS 'Sep',
SUM(IF(month = '10', total, 0)) AS 'Oct',
SUM(IF(month = '11', total, 0)) AS 'Nov',
SUM(IF(month = '12', total, 0)) AS 'Dec'
FROM (
SELECT month(DATEE_SORTIE_COLLABORATEUR) AS month , count(DATEE_SORTIE_COLLABORATEUR) as total
FROM collaborateur where YEAR(DATEE_SORTIE_COLLABORATEUR) =2016
GROUP BY month(DATEE_SORTIE_COLLABORATEUR)) as s
my objective is to calculate total number of collaborator per month
hope this can help you to understand what i mean
I have mysql query that outputs years leads v sales and calculates the conversions rates which worked great in 2012 as it only held a years data. Now its 2013 I need to change how it works but have become stuck. If a lead came in December 2012, then became a sale in 2013 its is ommitted from my query output as it only asks for CaseDate of 2013.
Select
q.*,
ROUND(100 * q.Comms / q.Total, 2) As Conversion,
If(q.Adviser Is Null, 1, 0) As remove
From
(Select
a.ContactFullName As Adviser,
Sum(Year(b.CaseDate) = 2013 And Month(b.CaseDate) = 1) As Jan,
Sum(Year(b.CaseDate) = 2013 And Month(b.CaseDate) = 2) As Feb,
Sum(Year(b.CaseDate) = 2013 And Month(b.CaseDate) = 3) As Mar,
..... Dec
Sum(Case
When Year(b.CaseDate) = 2013 And Month(b.CaseDate) Between '1'
And '12' Then 1 Else 0 End) As Total,
Sum(Case When (Year(b.CaseDate) = 2012 Or Year(b.CaseDate) = 2013) And Year(b.StatusSubmittedDate) = ".(int)$_POST['year']." And Month(b.StatusSubmittedDate) Between ".(int)$_POST['start']." And ".(int)$_POST['end']." Then 1 Else 0 End) As Comms
From
tblcontacts a Inner Join
tblcases b On a.ContactID = b.ContactAssignedTo
Group By
a.ContactFullName With Rollup) q
This works;
Sum(Case When (Year(b.CaseDate) = 2012 Or Year(b.CaseDate) = 2013) And Year(b.StatusSubmittedDate) = 2013 And Month(b.CaseDate) Between '1' And '12' Then 1 Else 0 End) As Comms
This donly shows leads entered & submitted in 2013;
Sum(Case When (Year(b.CaseDate) = 2012 Or Year(b.CaseDate) = 2013) And Year(b.StatusSubmittedDate) = ".(int)$_POST['year']." And Month(b.CaseDate) Between ".(int)$_POST['start']." And ".(int)$_POST['end']." Then 1 Else 0 End) As Comms
Many Thanks
It depends on your business logic. If the logic says you only show leads that came in the same year, then your code is perfectly correct as-is (as-was?). If you want to include 2012 or 2013 (which it looks like you do), you need to spell it out completely, the server doesn't understand "2012 or 2013"
Sum(Case When (Year(b.CaseDate) = 2012 Or Year(b.CaseDate) = 2013) And Year(....
Notice the parenthesis around the Or statement, this is to make sure that CaseYear=2012 or CaseYear=2013 and SubmitYear=2013 is treated as (CaseYear=2012 or CaseYear=2013) and SubmitYear=2013 instead of CaseYear=2012 or (CaseYear=2013 and SubmitYear=2013)
Of course if the business logic does not care about the CaseYear, then take that out of the Sum.
Good morning, I am unsuccessfully trying to create a report using mysql/php, I would like to have rows as columns similar to Access Crosstab or Excel Pivot. I have sales staff & monthly sales which I would like to display across the page with month as column headers.
My query below outputs the data but every salesperson has a row for every month which doesnt read very well,
Jan | Feb | Mar | April
Sales1
Sales2
Sales3
Sales4
Select
tblcontacts.ContactFullName,
Count(tblcases.CaseID) As cases,
MonthName(tblcases.CaseDate) As Monthly
From
tblcases Inner Join
tblcontacts On tblcases.ContactAssignedTo =
tblcontacts.ContactID
Group By
tblcontacts.ContactFullName,
MonthName(tblcases.CaseDate)
with rollup
Ant advice or pointers appreciated, I have researched but most of it went right over my head!
Kind regards
What you can do is simply group by each contact and use conditional aggregation to count rows based on each month:
SELECT
a.ContactFullName,
SUM(MONTH(b.CaseDate) = 1) AS Jan,
SUM(MONTH(b.CaseDate) = 2) AS Feb,
SUM(MONTH(b.CaseDate) = 3) AS Mar,
SUM(MONTH(b.CaseDate) = 4) AS Apr,
SUM(MONTH(b.CaseDate) = 5) AS May,
SUM(MONTH(b.CaseDate) = 6) AS Jun,
SUM(MONTH(b.CaseDate) = 7) AS Jul,
SUM(MONTH(b.CaseDate) = 8) AS Aug,
SUM(MONTH(b.CaseDate) = 9) AS Sep,
SUM(MONTH(b.CaseDate) = 10) AS Oct,
SUM(MONTH(b.CaseDate) = 11) AS Nov,
SUM(MONTH(b.CaseDate) = 12) AS Dec
FROM
tblcontacts a
INNER JOIN
tblcases b ON a.ContactID = b.ContactAssignedTo
GROUP BY
a.ContactFullName
Edit: As per your comments to this answer: to get a price sum of each month, you can do something like:
SELECT
a.ContactFullName,
SUM(IF(MONTH(b.CaseDate) = 1, b.price, 0)) AS Jan,
SUM(IF(MONTH(b.CaseDate) = 2, b.price, 0)) AS Feb,
SUM(IF(MONTH(b.CaseDate) = 3, b.price, 0)) AS Mar,
SUM(IF(MONTH(b.CaseDate) = 4, b.price, 0)) AS Apr,
SUM(IF(MONTH(b.CaseDate) = 5, b.price, 0)) AS May,
SUM(IF(MONTH(b.CaseDate) = 6, b.price, 0)) AS Jun,
SUM(IF(MONTH(b.CaseDate) = 7, b.price, 0)) AS Jul,
SUM(IF(MONTH(b.CaseDate) = 8, b.price, 0)) AS Aug,
SUM(IF(MONTH(b.CaseDate) = 9, b.price, 0)) AS Sep,
SUM(IF(MONTH(b.CaseDate) = 10, b.price, 0)) AS Oct,
SUM(IF(MONTH(b.CaseDate) = 11, b.price, 0)) AS Nov,
SUM(IF(MONTH(b.CaseDate) = 12, b.price, 0)) AS Dec
FROM
tblcontacts a
INNER JOIN
tblcases b ON a.ContactID = b.ContactAssignedTo
GROUP BY
a.ContactFullName
Basically, for each row, if the casedate is in a particular month, pass the value of the price column to the SUM aggregation, otherwise, just pass it 0.
Select
tblcontacts.ContactFullName,
sum(case when MonthName(tblcases.CaseDate)='January' then 1 else 0 end) as January,
sum(case when MonthName(tblcases.CaseDate)='February' then 1 else 0 end) as February,
.
.
sum(case when MonthName(tblcases.CaseDate)='December' then 1 else 0 end) as December,
From
tblcases Inner Join
tblcontacts On tblcases.ContactAssignedTo =
tblcontacts.ContactID
Group By
tblcontacts.ContactFullName