mysql where clause spanning multiple years? - mysql

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.

Related

SSRS : Repeating table with multiple-value parameter

I'm struggling with something which is probably easy in reporting services, but could not find any online help on this.
I'm building a telephony report for my company that show statistics for our clients. The main parameters for this report are : client name, date from, date to
Each client can have several calls queues (not the same number for each) so I need to create a statistics table that shows numbers, and repeats itself for each call queue.
I created a multi-values parameter for the queues that populates itself from this query:
SELECT queue_id FROM customers WHERE customer_name = #Customer
The subreports parameters are:
date_from = [#date_from]
date_to = [#date_to]
queueid = =Split(join(Parameters!client_call_queues.Value,","),",")
And here comes the issue, when I show the report preview, I can see the table with values, but summed for all queues, not splitted.
If I add a custom grouping on the tablix, it returns me a wrong calculation.
To go deeper in details, here's below a first printscreen that shows the numbers for all the queues:
and the table I get from the subreport, without custom grouping:
I tried to add this custom grouping, in the subreport tablix:
And here's the result it gives with that grouping:
Here's below the query used to populate subreport tablix:
SELECT
#queueid,
ISNULL(q1.[Day],'TOTAL') AS [Day],
COUNT(*) AS [Calls In],
SUM(CASE WHEN q1.[Call Type] = 'Answered Within Threshold' THEN 1 ELSE 0
END) + SUM(CASE WHEN q1.[Call Type] = 'Answered After Threshold' THEN 1 ELSE
0 END) AS [Answered],
SUM(CASE WHEN q1.[Call Type] = 'Abandoned Within Threshold' THEN 1 ELSE 0
END) AS [Abd. Within Threshold],
SUM(CASE WHEN q1.[Call Type] IN ('Abandoned Within Threshold') THEN 1 ELSE 0
END)/CONVERT(DECIMAL(10,2),COUNT(*)) AS [Calls Abandoned Within Threshold
Rate],
SUM(CASE WHEN q1.[Call Type] = 'Abandoned After Threshold' THEN 1 ELSE 0
END) AS [Abd. After Threshold],
SUM(CASE WHEN q1.[Call Type] IN ('Abandoned After Threshold') THEN 1 ELSE 0
END)/CONVERT(DECIMAL(10,2),COUNT(*)) AS [Calls Abandoned After Threshold
Rate],
SUM(CASE WHEN q1.[Call Type] = 'Voicemail' THEN 1 ELSE 0 END) AS [Voice
Mail]
FROM
(
SELECT
CUS.[Customer],
SUBSTRING(CONVERT(VARCHAR,ACD.[startdatetime],121),1,10) AS [Day],
ACD.[sessionid],
ACD.[contactdisposition],
ISNULL(ACD.[Squeuetime],0) AS [Squeuetime],
CUS.[ans_speed_secs],
CUS.[abd_tresh],
ACD.[businesshours],
ACD.[contacttype],
ISNULL(ACD.[connecttime],0) AS [connecttime],
ACD.[voicemail],
CUS.[ans_speed_rate],
ACD.[callednumber],
CUS.[Active],
ISNULL(ACD.[Stalktime], 0) AS [Stalktime],
ISNULL(ACD.[Sholdtime], 0) AS [Sholdtime],
CASE
WHEN ACD.[contactdisposition] = 2 AND ISNULL(ACD.[Squeuetime],0) <= CUS.
[ans_speed_secs] THEN 'Answered Within Threshold'
WHEN ACD.[contactdisposition] = 2 AND ISNULL(ACD.[Squeuetime],0) > CUS.
[ans_speed_secs] THEN 'Answered After Threshold'
WHEN ACD.[contactdisposition] <> 2 AND ISNULL(ACD.[Squeuetime],0) <=
CUS.[abd_tresh] THEN 'Abandoned Within Threshold'
WHEN ACD.[contactdisposition] <> 2 AND ISNULL(ACD.[Squeuetime],0) > CUS.
[abd_tresh] THEN 'Abandoned After Threshold'
WHEN ACD.[voicemail] = 'VoiceMail' THEN 'Voicemail'
END AS [Call Type]
FROM [ACD].[dbo].[UccxCallsQuery2] ACD
LEFT OUTER JOIN [ACD].[dbo].[Customers] CUS ON ACD.[callednumber] = CUS.
[Called_id]
WHERE CUS.[ACDSelection] IN (#queueid)
AND ACD.[businesshours] <> 'NBO'
AND ACD.[contacttype] = 1
AND CUS.[Active] = 1
AND CONVERT(DATE,ACD.[startdatetime]) BETWEEN #date_from AND #date_to
) q1 GROUP BY q1.[Day] WITH ROLLUP
I guess this is only a simple thing, but can spot it.
Thanks in advance for any help on this !

MySQL Attendance System

I have made an attendance system for a project, However I'm stuck right now by trying to create a query.
SELECT
COUNT(Students.idStudents) total,
SUM(case when Attendance.status LIKE 'present' then 1 else 0 end) present,
SUM(case when Attendance.status LIKE 'late' then 1 else 0 end) late,
SUM(case when Attendance.status is null then 1 else 0 end) absents
FROM Students, Schools, Tags LEFT JOIN Attendance
ON Attendance.tagCode = Tags.tagCode
WHERE Schools.idSchools = Students.idSchools
AND Tags.idStudents = Students.idStudents
This code works and generates an attendance. However this will show all the dates.
When I add in another line to specify date
AND Attendance.date = DATE(NOW());
It will not show anything..
There's 'Present', 'Late' status for the attendance however if the student's record in that table doesn't exist, it is considered as absent.
How do I do that?
Assuming you're using a case insensitive collation, your purported solution can be rewritten as follows:
SELECT COUNT(p.idStudents) total
, SUM(CASE WHEN a.status = 'present' THEN 1 ELSE 0 END) present -- [or just SUM(a.status = 'present')]
, SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) late
, SUM(CASE WHEN a.status IS NULL THEN 1 ELSE 0 END) absents
FROM Students p
JOIN Schools s
ON s.idSchools = p.idSchools
JOIN Tags t
ON t.idStudents = p.idStudents
LEFT
JOIN Attendance a
ON a.tagCode = t.tagCode
AND a.date = CURDATE() ;
For next time: Your ERD shows 10 tables, but only 4 feature in this problem. If a table isn't likely to be part of the proposed solution, don't show it. Don't provide pictures. Instead, where possible, provide proper DDLs (and/or an sqlfiddle), TOGETHER WITH THE DESIRED RESULT SET based upon a minimal, but properly representative data set.
Welcome to SO.
Figured it out..
SELECT
COUNT(Students.idStudents) total,
SUM(case when Attendance.status LIKE 'present' then 1 else 0 end) present,
SUM(case when Attendance.status LIKE 'late' then 1 else 0 end) late,
SUM(case when Attendance.status is null then 1 else 0 end) absents
FROM Students, Schools, Tags LEFT JOIN (SELECT * FROM Attendance WHERE Attendance.date = NOW()) AS Attendance
ON Attendance.tagCode = Tags.tagCode
WHERE Schools.idSchools = Students.idSchools
AND Tags.idStudents = Students.idStudents
The problem with the original query was you were asking for students where their attendance was "NOW" where no student was ever now but they are current attending classes. They may have signed in at 8am and you run the query at 10am. You'd need to manipulate the datetime to choose your start time and end time based on the current day.
timestampadd(HOUR, 08, CURDATE()) - this will give you 8am, you'd then query for when attendance.date is greater than or equal to 8am and then potentially less than or equal to 4pm?

mysql query split column into m

I have the following database structure:
FieldID|Year|Value
a|2011|sugar
a|2012|salt
a|2013|pepper
b|2011|pepper
b|2012|pepper
b|2013|pepper
c|2011|sugar
c|2012|salt
c|2013|salt
now I would like to run a query that counts the number of fields for every item in the particular year looking something like this:
value|2011|2012|2013
sugar|2|0|0
salt |0|2|1
pepper|1|1|2
I used multiple tables for every year before. However the distinct values for 2011,2012 and 2013 might be different (e.g. sugar would only be present in 2011)
For individual years I used:
SELECT `Value`, COUNT( `FieldID` ) FROM `Table` WHERE `Year`=2011 GROUP BY `Value`
A1ex07's answer is fine. However, in MySQL, I prefer this formulation:
SELECT Value,
sum(`Year` = 2011) AS cnt2011,
sum(`Year` = 2012) AS cnt2012,
sum(`Year` = 2013) AS cnt2013
FROM t
GROUP BY value;
The use of count( . . . ) produces the correct answer, but only because the else clause is missing. The default value is NULL and that doesn't get counted. To me, this is a construct that is prone to error.
If you want the above in standard SQL, I go for:
SELECT Value,
sum(case when `Year` = 2011 then 1 else 0 end) AS cnt2011,
sum(case when `Year` = 2012 then 1 else 0 end) AS cnt2012,
sum(case when `Year` = 2013 then 1 else 0 end) AS cnt2013
FROM t
GROUP BY value;
You can do pivoting :
SELECT `Value`,
COUNT(CASE WHEN `Year` = 2011 THEN FieldID END) AS cnt2011,
COUNT(CASE WHEN `Year` = 2012 THEN FieldID END) AS cnt2012,
COUNT(CASE WHEN `Year` = 2013 THEN FieldID END) AS cnt2013
FROM `Table`
GROUP BY `Value`
It is called Pivot Table, achieve with a chain of CASE statements which apply a 1 or 0 for each condition, then SUM() up the ones and zeros to retrieve a count.
SELECT
Value,
SUM(CASE WHEN Year = 2011 THEN 1 ELSE 0 END) AS 2012,
SUM(CASE WHEN Year = 2012 THEN 1 ELSE 0 END) AS 2012,
SUM(CASE WHEN Year = 2013 THEN 1 ELSE 0 END) AS 2013
FROM Table
GROUP BY Value

Mysql where clause breaks calculated query

wonder if someone can point out the error in my code below. I have mysql query that displays sales leads by month, then calculates % of those converted to sales. If I add where clause to this it breaks the total column as it outputs the same as the Comms column?
Select
q.*,
ROUND(100 * Comms / 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,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 4) As Apr,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 5) As May,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 6) As Jun,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 7) As Jul,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 8) As Aug,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 9) As Sep,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 10) As Oct,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 11) As Nov,
SUM(YEAR(b.CaseDate) = 2013 AND Month(b.CaseDate) = 12) As Dece,
Count(b.CaseID) As Total,
Sum(Case When Year(b.StatusSubmittedDate) = 2013 Then 1 Else 0
End) As Comms
From
tblcontacts a Inner Join
Without WHERE clause it outputs;
Total - Comms - Conversion
479 - 148 - 30.9%
With WHERE clause it outputs;
Total - Comms - Conversion
148 - 148 - 100%
I cant work out why this has happened?
Kind Regards
UPDATE:
I rewrote your whole query:
Select
q.*,
totals.total,
ROUND(100 * Comms / totals.total, 2) As Conversion
If(q.Adviser Is Null, 1, 0) As remove
From
(Select
a.ContactFullName As Adviser,
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 Dece,
Count(b.StatusSubmittedDate) As Comms
From
tblcontacts a Inner Join
tblcases b On a.ContactID = b.ContactAssignedTo
WHERE Year(b.StatusSubmittedDate) = 2013
Group By
a.ContactFullName With Rollup) q
inner join (select a.ContactFullName As Adviser, count(*) as total from
tblcontacts a Inner Join
tblcases b On a.ContactID = b.ContactAssignedTo
WHERE Year(b.StatusSubmittedDate) = 2013
group by Adviser
)totals on q.Adviser = totals.Adviser
Original answer:
To have multiple COUNTS you can workaround like this:
Count(b.CaseID) As Total,
SUM(CASE WHEN YEAR(b.StatusSubmittedDate) = 2013 THEN 1 ELSE 0 END) As Comms,
but this:
ROUND(100 * Count(b.StatusSubmittedDate) / Count(b.CaseID),
won't work, since this calculation has to be done later.
Select
q.*,
ROUND(100 * Comms / Total, 2) As Conversion,
If(q.Adviser Is Null, 1, 0) As remove
From
(Select
a.ContactFullName As Adviser,
Sum(Month(b.CaseDate) = 1 and year(b.CaseDate) = 2012) As Jan,
... Dec,
Count(b.CaseID) As Total,
SUM(CASE WHEN YEAR(b.StatusSubmittedDate) = 2013 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

Msql Crosstab month rows as columns?

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