I'm trying to get the salary of an employee and I'm not sure why ISNULL is not working here. Although the same query works when used outside subquery.
Maybe I'm implementing the Isnull function wrong.
Net salary is showing null even there is basic pay given.
DECLARE #dateFrom datetime
SET #dateFrom = '2018-03-01'
DECLARE #dateTo datetime
SET #dateTo = '2018-03-31'
Select
[Emp].ID
,[Emp].EmpCode
,[Emp].FirstName + ' ' + [Emp].LastName AS Name
,[Emp].BasicPay
,((select SUM(InstallmentAmount) from HRM.tbl_EmployeeLoanInstallment [Loan]
LEFT JOIN HRM.tbl_EmployeeLoan [EmpLoan] ON [EmpLoan].ID = [Loan].EmployeeLoanCode
where [EmpLoan].EmpCode = Emp.ID AND IsReceived != 1
AND CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo))) AS LoanDeduction
,( SELECT
(ISNULL([Info].[BasicPay], 0))
-
(SELECT SUM(ISNULL([Loan].InstallmentAmount, 0))
FROM [HRM].[tbl_EmployeeLoan] [EmpLoan]
FULL JOIN [HRM].[tbl_EmployeeInfo] [Info] ON [Info].[ID] = [EmpLoan].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeLoanInstallment] [Loan] ON [EmpLoan].[ID] = [Loan].[EmployeeLoanCode]
WHERE
CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND
CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo)
AND
[Info].[ID] = [Emp].[ID]
GROUP BY Info.ID)
FROM
[HRM].[tbl_EmployeeInfo] [Info]
WHERE Info.ID = Emp.ID
GROUP BY [Info].[ID], [Info].[BasicPay]
) AS NetSalary
from HRM.tbl_EmployeeInfo [Emp]
Output:
412 C3-345 Ayesha Fatima 20000.00 NULL NULL
413 C3-651 Zainab Ali 20000.00 NULL NULL
414 C1343 Ahmed Abdullah 20000.00 11111.11 8888.89
415 231 Ahmed Aslam 20000.00 NULL NULL
416 FS-16 Fawaz Aslam 25000.00 NULL NULL
Are you sure that your subquery return a value? Seems to not be the case.
If you really want a value, you should catch your null value at the end of your subquery.
,ISNULL(
( SELECT
(ISNULL([Info].[BasicPay], 0))
-
(SELECT SUM(ISNULL([Loan].InstallmentAmount, 0))
FROM [HRM].[tbl_EmployeeLoan] [EmpLoan]
FULL JOIN [HRM].[tbl_EmployeeInfo] [Info] ON [Info].[ID] = [EmpLoan].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeLoanInstallment] [Loan] ON [EmpLoan].[ID] = [Loan].[EmployeeLoanCode]
WHERE
CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND
CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo)
AND
[Info].[ID] = [Emp].[ID]
GROUP BY Info.ID)
, 0)
FROM
[HRM].[tbl_EmployeeInfo] [Info]
Related
I am working on a SQL query where I have to find out Average, Max value, Max Value-DateTime, Min Value, Min Value-DateTime of each Group of any Date. For this I used following query
SELECT
Dl.TagDescID,
convert( decimal(18,2), AVG( Dl.Value ) ) AS 'TotalAvgValue',
convert(decimal(18,2), MAX( Dl.Value ) ) AS 'MaxValue',
MAX( Dl.Date ) MaxDate,
convert( decimal(18,2), MIN( Dl.Value ) ) AS 'MinValue',
Min( Dl.Date ) MinDate
FROM
tblDataLog AS Dl WITH (nolock)
INNER JOIN tblTagDescription AS TD WITH (nolock) ON Dl.TagDescID = TD.ID
WHERE
( CONVERT(date, Dl.Date, 103) = CONVERT(date, #StartDate, 103) )
AND
( TD.GroupName = #Group )
GROUP BY
Dl.TagDescID
`
TagDescID TotalAvgValue MaxValue MaxDate MinValue MinDate
1 36.59 36.59 2020-01-07 10:13:42.293 36.59 2020-01-07 10:13:32.750
2 20.49 20.49 2020-01-07 10:13:42.293 20.49 2020-01-07 10:13:32.750
In the above Data Set The MaxValue of TagDescID 1 is 36.59 and its Date as 'MaxDate' should be the exact datetime when this maxvalue Arrives in the table tblDataLog. here Max-Date of MaxValue of TagDescID 1 is '2020-01-07 10:13:42.293' but the value should have been '2020-01-07 08:13:42.293'. Same for MinValue and MinDate For each TagDescID.
How to solve it?
The issue is that you are really asking for multiple aggregate and grouping sets at the same time. What you are observing is that each column aggregate expression is returning the result of that aggregate independently of the other columns, this is by design.
In the above query MaxDate and MinDate should be the Datetime when the MaxValue or MinValue inserted to the table tblDataLog.
In SQL Server we have a number of ways to query this.
One way is to query the set for the Max and Min values, then re-query the set for the Max and Min Dates around those times.
In this example I'm using a CTE instead of a simple nested query because I find the syntax more readable.
The two CROSS APPLY queries will evaluate once for each result in the Daily CTE.
This solution can be more efficient to using an inline lookup for the DateTime of the corresponding log records because it doesn't have to lookup once for every row in tblDataLog, this solution will result in 2 additional lookups for every row that is returned by the group by.
;WITH Daily as
(
SELECT
Dl.TagDescID,
convert(decimal(18,2),AVG(Dl.Value)) AS [TotalAvgValue],
convert(decimal(18,2),MAX(Dl.Value)) AS [MaxValue],
convert(decimal(18,2),MIN(Dl.Value)) AS [MinValue]
FROM #tblDataLog AS Dl
INNER JOIN #tblTagDescription AS TD ON Dl.TagDescID = TD.ID
WHERE (CONVERT(date, Dl.Date, 103) = CONVERT(date, #StartDate, 103)) AND (TD.GroupName=#Group)
GROUP BY Dl.TagDescID
)
SELECT Daily.TagDescID, TotalAvgValue, MaxValue, [Max].Date MaxDate, MinValue, [Min].Date MinDate
FROM Daily
CROSS APPLY (SELECT MAX(DlMax.Date) Date FROM #tblDataLog DlMax WHERE DlMax.TagDescID = Daily.TagDescId AND (CONVERT(date, DlMax.Date, 103) = CONVERT(date, #StartDate, 103)) AND DlMax.Value = Daily.MaxValue) as [Max]
CROSS APPLY (SELECT MIN(DlMin.Date) Date FROM #tblDataLog DlMin WHERE DlMin.TagDescID = Daily.TagDescId AND (CONVERT(date, DlMin.Date, 103) = CONVERT(date, #StartDate, 103)) AND DlMin.Value = Daily.MinValue) as [Min]
Another way to do this is to group by the date, instead of filtering for an explicit date value, so this will summarize by date and tag, giving you a report across multiple dates and multiple tags if you want it:
;WITH Daily as
(
SELECT
Dl.TagDescID,
TD.GroupName,
CONVERT(date, Dl.Date, 103) as Date,
MAX(Dl.Date) as Max_Date,
MIN(Dl.Date) as Min_Date,
convert(decimal(18,2),AVG(Dl.Value)) AS [TotalAvgValue],
convert(decimal(18,2),MAX(Dl.Value)) AS [MaxValue],
convert(decimal(18,2),MIN(Dl.Value)) AS [MinValue]
FROM #tblDataLog AS Dl
INNER JOIN #tblTagDescription AS TD ON Dl.TagDescID = TD.ID
GROUP BY Dl.TagDescID, TD.GroupName, CONVERT(date, Dl.Date, 103)
)
SELECT Daily.Date, Daily.GroupName, Daily.TagDescID, TotalAvgValue, MaxValue, [Max].Date MaxDate, MinValue, [Min].Date MinDate
FROM Daily
CROSS APPLY (SELECT MAX(DlMax.Date) Date FROM #tblDataLog DlMax WHERE DlMax.TagDescID = Daily.TagDescId AND DlMax.Date >= Daily.Min_Date AND DlMax.Date <= Daily.Max_Date) [Max]
CROSS APPLY (SELECT MIN(DlMin.Date) Date FROM #tblDataLog DlMin WHERE DlMin.TagDescID = Daily.TagDescId AND DlMin.Date >= Daily.Min_Date AND DlMin.Date <= Daily.Max_Date) [Min]
-- Optional Date Filter
-- WHERE TD.GroupName=#Group AND Daily.Date = #StartDate
In my test set, this returns:
Date GroupName TagDescID TotalAvgValue MaxValue MaxDate MinValue MinDate
2020-03-11 Test 1 5.00 8.00 2020-03-11 22:00:00.000 2.00 2020-03-11 10:00:00.000
2020-03-15 Test 1 5.00 8.00 2020-03-15 13:00:00.000 2.00 2020-03-15 06:00:00.000
Un-comment the where clause to enable your date filter, or you could change it to a date range and you would still see results by day.
I think this is what you are after. The corresponding Date when Value is minimum and maximum. You can use a sub-query to do this
SELECT
Dl.TagDescID,
convert( decimal(18,2), AVG( Dl.Value ) ) AS 'TotalAvgValue',
convert(decimal(18,2), MAX( Dl.Value ) ) AS 'MaxValue',
--MAX( Dl.Date ) MaxDate,
(SELECT TOP 1 x.[Date] FROM tblDataLog x WHERE x.TagDescID = Dl.TagDescID ORDER BY Value DESC) As MaxDate,
convert( decimal(18,2), MIN( Dl.Value ) ) AS 'MinValue',
--Min( Dl.Date ) MinDate
(SELECT TOP 1 x.[Date] FROM tblDataLog x WHERE x.TagDescID = Dl.TagDescID ORDER BY Value) As MinDate
FROM
tblDataLog AS Dl WITH (nolock)
INNER JOIN tblTagDescription AS TD WITH (nolock) ON Dl.TagDescID = TD.ID
WHERE
( CONVERT(date, Dl.Date, 103) = CONVERT(date, #StartDate, 103) )
AND
( TD.GroupName = #Group )
GROUP BY
Dl.TagDescID
EDIT : as others commented, avoid CONVERT(date, Dl.Date, 103) = CONVERT(date, #StartDate, 103)
You can replace that with
WHERE Dl.Date >= #StartDate
AND Dl.Date < DATEADD (DAY, 1, #StartDate)
I am looking for the count of records as below.
PLANNED_SHIP_From_Date PLANNED_SHIP_To Date Total_Lines_Count ....
1) 09-04-2016 07:00:01 09-04-2016 18:59:59 165 .....
2) 09-04-2016 19:00:00 10-04-2016 07:00:00 121 .....
3) 10-04-2016 07:00:01 10-04-2016 18:59:59 165 .....
4) 10-04-2016 19:00:00 11-04-2016 07:00:00 123 .....
5) 11-04-2016 07:00:01 11-04-2016 18:59:59 234 .....
.
Currently my query is counting the records as per date.
SELECT
cast(shdr.PLANNED_SHIP_DATE as date),
SUM(sdtl_1_1.TOTAL_LINES_COUNT) AS TOTAL_LINES_COUNT
FROM
dbo.SHIPMENT_HEADER AS shdr WITH (NOLOCK)
INNER JOIN
(
SELECT
SHIPMENT_ID,
COUNT(*) AS TOTAL_LINES_COUNT
FROM
dbo.SHIPMENT_DETAIL AS SHIPMENT_DETAIL_1 WITH (NOLOCK)
WHERE
(
STATUS1 >= 401
)
AND (
DATEDIFF(day, PLANNED_SHIP_DATE, CONVERT(date, SYSDATETIME())) < 4
)
GROUP BY
SHIPMENT_ID
) AS sdtl_1_1
ON sdtl_1_1.SHIPMENT_ID = shdr.SHIPMENT_ID
WHERE
(
shdr.TRAILING_STS >= 401
)
AND (
DATEDIFF(day, shdr.PLANNED_SHIP_DATE, CONVERT(date, SYSDATETIME())) < 4
)
GROUP BY
cast(shdr.PLANNED_SHIP_DATE as date)
Try this -
DECLARE #ReportDays int = 30,
#StartHr int = 7,
#Today DATETIME2 = CAST(SYSDATETIME() AS DATE);
--http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/you-require-a-numbers-table.aspx
WITH
a AS (SELECT 1 AS i UNION ALL SELECT 1),
b AS (SELECT 1 AS i FROM a AS x, a AS y),
c AS (SELECT 1 AS i FROM b AS x, b AS y),
d AS (SELECT 1 AS i FROM c AS x, c AS y),
e AS (SELECT 1 AS i FROM d AS x, d AS y),
numbers as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS number FROM e),
StartDates AS (
SELECT
DATEADD(
HH,
#StartHr + (n2.number * 12),
DATEADD(D, 0-n1.number, #Today)
) AS StartDT
FROM
(SELECT * FROM numbers WHERE Number BETWEEN 0 AND #ReportDays) n1
CROSS JOIN (SELECT * FROM numbers WHERE Number IN (0,1)) n2
),
DateRanges AS
(SELECT StartDT, DATEADD(hh, 12, StartDT) AS EndDT FROM StartDates),
Shipments AS
(SELECT
StartDT AS PLANNED_SHIP_From_Date,
EndDT AS PLANNED_SHIP_To_Date,
1 AS Shipment
FROM
DateRanges dr
LEFT JOIN dbo.SHIPMENT_DETAIL sd
ON sd.Status1 >=401
AND sd.PLANNED_SHIP_DATE BETWEEN dr.StartDT AND dr.EndDT)
SELECT
PLANNED_SHIP_From_Date,
PLANNED_SHIP_To_Date,
SUM(Shipment) AS TOTAL_LINES_COUNT
FROM
Shipments
ORDER BY
PLANNED_SHIP_From_Date;
What we're doing is -
Building a numbers table
Using that to pull a list of days, with two records per day
Working out the start & finish times for each time window
Joining the time windows to the records and summing
Hope that helps :-)
Add another column to your select....
CASE
WHENE DATEPART(HOUR, Planned_SHIP_DATE) < 12 THEN 'AM' ELSE 'PM'
END AS ShipPeriod
You could then add that column into a GROUPING to seperate the 'AM's from 'PM's
Of course I have assuumed you wanted AM/PM. But you can modify the CASE statement to break the hours up as you see fit.
Hope this helps
Thank you all for helping me out.
I have created a SQL query which worked for me. This query gives the count of records from morning 7 AM to 7 PM as MORNING_SHIFT count and 7PM to next day 7AM morning as EVENING_SHIFT for dates greater than 14 days in the past.
SELECT
CASE
WHEN convert(VARCHAR(50), sh.PLANNED_SHIP_DATE, 120) BETWEEN
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 07:00:00') AND
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 18:59:59')
THEN (CONCAT(cast(sh.PLANNED_SHIP_DATE as date),' ','morning_shift'))
WHEN convert(VARCHAR(50), sh.PLANNED_SHIP_DATE, 120) BETWEEN
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 00:00:00') AND
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 06:59:59')
then (CONCAT(cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date),' ','EVENING_shift'))
when
convert(VARCHAR(50), DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) , 120) BETWEEN (convert(VARCHAR(10), cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date), 120) + ' 19:00:00') AND
(convert(VARCHAR(10), cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date), 120) + ' 23:59:59')
THEN (CONCAT(cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date),' ','EVENING_shift'))
END AS 'actual_date_time', sh.PLANNED_SHIP_DATE
FROM dbo.SHIPMENT_HEADER AS sh WITH (nolock)
WHERE (shdr.TRAILING_STS >= 401) AND (DATEDIFF(day, shdr.ACTUAL_SHIP_DATE_TIME, CONVERT(date, SYSDATETIME())) < 14)
group by sh.ACTUAL_SHIP_DATE_TIME;
I created a new topic as i am trying to divide my initial question into multiple pieces.
The initial topic can be found in the following link.
I have created a SQL Fiddle link with table and sample data.
This is the Query that i have right now.
SELECT
Order1,
COUNT(UNit.UNIT) AS Units,
SUM(CASE
WHEN (DATEDIFF(dd, INSV_DATE, '2015-01-21')) >= 31 THEN 31
WHEN (DATEDIFF(dd, INSV_DATE, '2015-01-21')) < 0 THEN 0
ELSE (DATEDIFF(dd, INSV_DATE, '2015-01-21'))
END) AS Days31
FROM UNIT
WHERE Unit.INSV_DATE < '2015-01-21'
AND UNIT.MODEL IN ('Toyota')
AND (UNIT.Customer IN ('Jona'))
GROUP BY [Order1],
customer
how do i loop and pass date dynamically in the Datediff for a period of one month?
I want the 31 days output calculated for day wise.
The output should be like
Date | Order1 | Unit | Day31
----------------------------------
May20 | 90909 | 5 | 128
May19 | 90909 | 4 | 124
May17 | 90909 | 2 | 62
I actually want to do something like the following.
SELECT
Order1,
COUNT(UNit.UNIT) AS Units,
SUM(CASE
WHEN (DATEDIFF(dd, INSV_DATE, '2015-05-20')) >= 31 THEN 31
WHEN (DATEDIFF(dd, INSV_DATE, '2015-05-20')) < 0 THEN 0
ELSE (DATEDIFF(dd, INSV_DATE, '2015-05-20'))
END) AS Days31
FROM UNIT
WHERE Unit.INSV_DATE < '2015-05-20'
AND UNIT.MODEL IN ('Toyota')
AND (UNIT.Customer IN ('Jona'))
GROUP BY [Order1],
customer
SELECT
Order1,
COUNT(UNit.UNIT) AS Units,
SUM(CASE
WHEN (DATEDIFF(dd, INSV_DATE, '2015-05-19')) >= 31 THEN 31
WHEN (DATEDIFF(dd, INSV_DATE, '2015-05-19')) < 0 THEN 0
ELSE (DATEDIFF(dd, INSV_DATE, '2015-05-19'))
END) AS Days31
FROM UNIT
WHERE Unit.INSV_DATE < '2015-05-19'
AND UNIT.MODEL IN ('Toyota')
AND (UNIT.Customer IN ('Jona'))
GROUP BY [Order1],
customer
SELECT
Order1,
COUNT(UNit.UNIT) AS Units,
SUM(CASE
WHEN (DATEDIFF(dd, INSV_DATE, '2015-05-18')) >= 31 THEN 31
WHEN (DATEDIFF(dd, INSV_DATE, '2015-05-18')) < 0 THEN 0
ELSE (DATEDIFF(dd, INSV_DATE, '2015-05-18'))
END) AS Days31
FROM UNIT
WHERE Unit.INSV_DATE < '2015-05-18'
AND UNIT.MODEL IN ('Toyota')
AND (UNIT.Customer IN ('Jona'))
GROUP BY [Order1],
customer
Running the same query for everyday with the different date.
If you can guide me in making a day wise query that will be great.
You can build the list of dates using a recursive CTE, then CROSS JOIN it against your table to get the list of days you want:
DECLARE #StartDate date = 'Jan 1, 2015'
DECLARE #EndDate date = DATEADD(DAY, 30, #StartDate)
;WITH cte AS (
SELECT #StartDate AS ReportDate
UNION ALL
SELECT DATEADD(DAY, 1, ReportDate)
FROM cte
WHERE ReportDate < #EndDate
)
SELECT Order1,COUNT(UNit.UNIT) As Units,sum(CASE
WHEN (datediff(dd,INSV_DATE,cte.ReportDate)) >= 31 THEN 31
WHEN (datediff(dd,INSV_DATE,cte.ReportDate)) < 0 THEN 0
ELSE (datediff(dd,INSV_DATE,cte.ReportDate))END) as Days31
FROM UNIT
CROSS JOIN cte
WHERE Unit.INSV_DATE < cte.ReportDate AND
UNIT.MODEL in('Toyota') AND(UNIT.Customer in('Jona' ))
group by [Order1],customer
Based on my understanding of what you want, here is my "guess":
DECLARE #startDate DATE = CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(GETDATE()) AS VARCHAR) -- cast as mm/dd/yyyy
DECLARE #endDate DATE = GETDATE() -- mm/dd/yyyy
--creates a list of dates for the running month
;WITH month_dates
AS (
SELECT [Date] = DATEADD(Day, Number, #startDate)
FROM master.dbo.spt_values
WHERE Type = 'P'
AND DATEADD(day, Number, #startDate) <= #endDate
)
SELECT month_dates.[Date]
,Order1
,COUNT(UNit.UNIT) AS Units
,sum(CASE
WHEN (datediff(dd, INSV_DATE, month_dates.[Date])) >= 31
THEN 31
WHEN (datediff(dd, INSV_DATE, month_dates.[Date])) < 0
THEN 0
ELSE (datediff(dd, INSV_DATE, month_dates.[Date]))
END) AS Days31
FROM UNIT
CROSS JOIN month_dates --cross join list of dates
WHERE Unit.INSV_DATE < month_dates.[Date]
AND UNIT.MODEL IN ('Toyota')
AND (UNIT.Customer IN ('Jona'))
AND UNIT.Order1 = 'A1056729' --added this filter to test the output
GROUP BY month_dates.[Date]
,[Order1]
,customer
ORDER BY month_dates.[Date] desc
I have just started learning SQL. I've written the following:
DECLARE #DateFrom Date = '01-Jan-2014', #DateTo Date = '31-Dec-2014'
SELECT TotalCalls, UniqueCalls, TotalEmails, UniqueEmails, AgentsContacted, Instructed FROM
( SELECT *,
(SELECT YEAR(EventDate)) AS year,
(SELECT COUNT(*) FROM Events JOIN dbo.ContactType
ON EventContactType=ContactTypeID
WHERE ContactTypeName = 'Call' AND EventDate >= #DateFrom AND EventDate <= #DateTo) AS TotalCalls,
(SELECT COUNT(Distinct EventAgentID) FROM Events JOIN dbo.ContactType
ON EventContactType=ContactTypeID
WHERE ContactTypeName = 'Call' AND EventDate >= #DateFrom AND EventDate <= #DateTo) AS UniqueCalls,
(SELECT COUNT(*) FROM Events JOIN dbo.ContactType
ON EventContactType=ContactTypeID
WHERE ContactTypeName = 'Email' AND EventDate >= #DateFrom AND EventDate <= #DateTo) AS TotalEmails,
(SELECT COUNT(Distinct EventAgentID) FROM Events JOIN dbo.ContactType
ON EventContactType=ContactTypeID
WHERE ContactTypeName = 'Email' AND EventDate >= #DateFrom AND EventDate <= #DateTo) AS UniqueEmails,
(SELECT COUNT(DISTINCT EventAgentID)
FROM Events
JOIN dbo.ContactType
ON EventContactType=ContactTypeID
LEFT JOIN (SELECT AgentID, (SELECT CASE WHEN AgentDateOfRecentInstruction Is Null OR
AgentDateOfRecentInstruction < DATEADD(month, -12, #DateFrom) --for sp change get date to #FromDate
THEN 'NO' ELSE 'YES' END) AS InstructedWithinPastYear FROM Agents) ti
ON Events.EventAgentID=ti.AgentID
WHERE EventToFrom='1'
AND (ContactTypeName = 'Email' OR ContactTypeName = 'Call')
AND InstructedWithinPastYear = 'NO'
AND (EventDate >= #DateFrom AND EventDate <= #DateTo)) AS AgentsContacted,
(SELECT COUNT(DISTINCT EventAgentID)
FROM Events
Join dbo.AGents
ON EventAgentID=AgentID
JOIN dbo.ContactType
ON EventContactType=ContactTypeID
LEFT JOIN (SELECT AgentID, (SELECT CASE WHEN AgentDateOfRecentInstruction Is Null OR
AgentDateOfFirstIntsruction < #DateFrom --for sp change get date to #FromDate
THEN 'NO' ELSE 'YES' END) AS InstructedWithinPastYear FROM Agents) ti
ON Events.EventAgentID=ti.AgentID
WHERE EventToFrom='1'
AND (ContactTypeName = 'Email' OR ContactTypeName = 'Call')
AND (AgentDateOfRecentInstruction <= #DateTo AND AgentDateOfRecentInstruction >= #DateFrom)
AND (EventDate >= #DateFrom AND EventDate <= #DateTo)) AS Instructed
FROM Events
JOIN dbo.ContactType
ON EventContactType=ContactTypeID
Join dbo.AGents
ON EventAgentID=AgentID
)
as s
PIVOT (count(EventAgentID) FOR year
IN ([2013],[2014]) ) pvt
Which returns thousands of row of this:
TotalCalls | UniqueCalls | TotalEmails | UniqueEmails | AgentsContacted | Instructed
169 | 106 | 202 | 125 | 24 | 15
169 | 106 | 202 | 125 | 24 | 15
169 | 106 | 202 | 125 | 24 | 15
I want to it to return:
Year | TotalCalls | UniqueCalls | TotalEmails | UniqueEmails | AgentsContacted
2014 | 169 | 106 | 202 | 125 | 24
2013 | 69 | 68 | 112 | 86 | 13
I'm fairly certain I'm doing a few things wrong here but I wasn't able to write my question succinctly enough to work out how to do it from searches.
(note: The local variables are there temporarily whilst I write the procedure)
You could probably simplify this query greatly by putting everything into one query statement, rather than a series of individual queries in the SELECT statement. Right now, you have "SELECT (SELECT Blah1FROM X), (SELECT Blah2 FROM X)" where you could just as easily write "SELECT Blah1, Blah2 FROM X" with a little creativity.
You have a couple of basic flaws in your code that are causing your problem - you're aggregating every row in each of your SELECT queries, so the data you're returning is actually the count across all records, not for the year you want. In addition, you never group your results (look up the GROUP BY statement) so you're returning thousands of rows, one for each detail record, rather than the single row per year I think you want.
Consider writing something more like the following, which uses aggregations against a single query with the GROUP BY.
DECLARE #DateFrom Date = '01-Jan-2014', #DateTo Date = '31-Dec-2014'
SELECT
YEAR(EventDate) AS [Year],
COUNT(CASE WHEN ContactTypeName = 'Call' THEN EventAgentID END) AS TotalCalls, -- You might need the "EventDate >= #DateFrom AND EventDate <= #DateTo" as part of this CASE statement
COUNT(DISTINCT CASE WHEN ContactTypeName = 'Call' THEN EventAgentID END) AS UniqueCalls,
COUNT(CASE WHEN ContactTypeName = 'Email' THEN EventAgentID END) AS TotalEmails,
COUNT(DISTINCT CASE WHEN ContactTypeName = 'Email' THEN EventAgentID END) AS UniqueEmails,
COUNT(DISTINCT
CASE
WHEN
EventToFrom='1' AND
ContactTypeName IN ('Call', 'Email') AND
(AgentDateOfRecentInstruction IS NULL OR AgentDateOfRecentInstruction < DATEADD(month, -12, #DateFrom)) AND
(EventDate >= #DateFrom AND EventDate <= #DateTo)
THEN EventAgentID
END) AS AgentsContacted,
COUNT(DISTINCT
CASE
WHEN
EventToFrom='1' AND
ContactTypeName IN ('Call', 'Email') AND
AgentDateOfRecentInstruction <= #DateTo AND AgentDateOfRecentInstruction >= #DateFromAND
(EventDate >= #DateFrom AND EventDate <= #DateTo)
THEN EventAgentID
END) AS AgentsContacted
FROM
dbo.Events
INNER JOIN
dbo.ContactType ON
EventContactType=ContactTypeID
INNER JOIN
dbo.Agents ON
EventAgentID=AgentID
GROUP BY YEAR(EventDate)
Lacking any sample data or even really a schema, I can't guarantee that this conversion will work without any tweaks - you'll likely have to take this code, check for spelling or syntax errors, then go through each statement to make sure it's actually doing what you want it to. It should, however, get you started.
I have little table which gives me a very hard time:
Person datetime1 datetime2
Eric 2012-10-01 09:00:05.000 2012-10-01 22:00:00.000
Anna 2012-10-02 06:00:05.000 2012-10-03 12:00:05.000
Richard 2012-10-03 09:00:05.000 2012-10-04 02:00:05.000
Chuck 2012-10-01 12:00:05.000 2012-10-01 23:00:05.000
I am trying to write a query, which gives me statistics table. This table contains information about when a user logged in and out (daily granularity):
Date logged_in logged_off
2012-10-01 2 2
2012-10-02 1 0
2012-10-03 1 1
2012-10-04 0 1
According to my research, a pivot command could solve the problem?
select Person,
SUM(case when datetime1 = '2012-10-01' then 1 else 0 end) as [loggeed_in],
SUM(case when datetime2 = '2012-10-01' then 1 else 0 end) as [logged_of]
from table
group by Person
This is not working... Do you have any ideas?
This will fix the current query, but don't know if it will solve the whole problem...
select Person,
SUM(case when convert(varchar(10), datetime1, 111) = '2012/10/01' then 1 else 0 end) as [loggeed_in],
SUM(case when convert(varchar(10), datetime2, 111) = '2012/10/01' then 1 else 0 end) as [logged_of]
from table
group by Person
EDIT: I believe this will better suit requirements...
SELECT
[Date] = dt,
logged_in = (
SELECT COUNT(*)
FROM table1
WHERE convert(varchar(10), datetime1, 111) = convert(varchar(10), dt, 111)),
logged_off = (
SELECT COUNT(*)
FROM table1
WHERE convert(varchar(10), datetime2, 111) = convert(varchar(10), dt, 111))
FROM (
SELECT TOP 1000
row_number() OVER(ORDER BY (SELECT 0)) AS N
FROM master.dbo.syscolumns sc1, master.dbo.syscolumns sc2) tally
CROSS APPLY(
SELECT dt = DATEADD(dd, tally.N - 1, '2012-10-1')) tallydt
WHERE dt BETWEEN (SELECT MIN(dateadd(dd, -1, datetime1)) FROM table1) AND (SELECT MAX(datetime2) FROM table1)
GROUP BY dt
ORDER BY dt
Here is the working solution:
WITH O AS (
SELECT
CAST([login Date & Time] AS DATE) loginDate
,COUNT(*) logined
FROM table
GROUP BY CAST([login Date & Time] AS DATE)
), C AS (
SELECT
CAST([Close Date & Time] AS DATE) CloseDate
,COUNT(*) Closed
FROM table
WHERE [Close Date & Time] IS NOT NULL
GROUP BY CAST([Close Date & Time] AS DATE)
)
SELECT
COALESCE(C.CloseDate, O.loginDate) TheDate
--,O.loginDate
--,C.CloseDate
,O.logined
,C.Closed
FROM O
FULL JOIN C
ON O.loginDate = C.CloseDate
ORDER BY TheDate