I am trying to use MAX() to select the most recent placement date within our database, and use Table_CTE so I can then select and filter between the dates desired.
BEGIN
DECLARE #Rangetill DATE, #Rangefrom DATE
SET #rangefrom = DATEADD(day, -50, GETDATE())
SET #Rangetill = DATEADD(day, -90, GETDATE());
WITH Table_CTE (Name, ID, Rangefrom, Rangetill, StatusID, Statusdate) AS
(
SELECT
PE.Personname + ' ' + PE.Surname [Name],
A.ApplicantId,
#rangefrom [Expiry warning from],
#rangetill [Expiry warning till],
A.Statusid,
selected = CASE
WHEN P.EndDate IS NOT NULL AND P.EndDate > A.StatusDate
THEN CONVERT(DATE, P.EndDate, 103)
ELSE CONVERT(DATE, A.StatusDate, 103)
END
FROM
Applicants AS A
LEFT JOIN
Person AS PE ON A.ApplicantId = PE.PersonID
LEFT JOIN
Placements AS P on A.applicantid = P.Applicantid
)
SELECT *
FROM Table_CTE
WHERE table_cte.Statusdate BETWEEN #Rangetill AND #Rangefrom
AND (Table_CTE.StatusID = 58 OR Table_CTE.statusid = 63)
ORDER BY Name DESC
END
The above selects the right information but also selects duplicate applicants with placement end dates (p.enddate) as they could have been placed more than once. The WHERE clause also limits the most recent enddate to within the range provided by the Variables and as there needs to be a log there will be multiple end dates. so my solution or idea would be to uses a max() within the Case or CTE Select. However I am not sure how to use or work with Max() in this case.
In this case I would like to check and return the Max(p.enddate) if it exists and store that in the statusdate of Table_CTE.
Is this possible and is it the best way to provide this information in a stored procedure?
In the CTE would be more efficient but this is easier
SELECT c.[Name], max(c.Statusdate)
FROM Table_CTE c
WHERE c.Statusdate Between #Rangetill and #Rangefrom
AND c.StatusID in (58, 63)
group by c.[Name]
Add the other columns on your own
Declare
#Rangetill date,
#Rangefrom date
SET #rangefrom = DATEADD(day, -50, GETDATE())
SET #Rangetill = DATEADD(day, -90, GETDATE());
With Table_CTE ( ID, Rangefrom, Rangetill, Statusdate)
AS (
Select
A.ApplicantId
, #rangefrom [Expiry warning from]
, #rangetill [Expiry warning till]
, selected = CASE
WHEN max(P.EndDate) IS NOT NULL AND max(P.EndDate) > max(A.StatusDate)
THEN max(CONVERT(DATE, P.EndDate, 103))
ELSE max(CONVERT(DATE, A.StatusDate, 103))
END
FROM Applicants AS A
LEFT JOIN Person AS PE ON A.ApplicantId = PE.PersonID
LEFT JOIN Placements AS P on A.applicantid = P.Applicantid
GROUP BY A.ApplicantId
)
SELECT
PE.PersonName + ' ' + PE.Surname [NAME]
, A.ApplicantId
, Table_CTE.ID
, Table_CTE.Statusdate
, #Rangefrom [Range from]
, #Rangetill [Range till]
FROM Table_CTE
LEFT JOIN Applicants AS A ON A.ApplicantId = Table_CTE.ID
LEFT JOIN Person as PE on PE.PersonID = A.ApplicantId
WHERE table_cte.Statusdate Between #Rangetill and #Rangefrom
AND (A.StatusID = 58 or A.statusid = 63 )
Order by PE.PersonName + ' '+ PE.Surname desc
END
Really messy way around things but I got my solution by removing all but the variables and ID from CTE so I could select Max(DATE) on both A.statusdate and P.EndDate.
By doing this I could group by A.ApplicantID and rejoin specific tables outside of the CTE in order to get Applicant Name and Status ID back into my results set.
Thank you for your help everyone.
Related
I have to get the list of months and year in between my dates. Currently it only returns month and year for dates that has data associated with it.
for example my dates is between: '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016'
It only prints out: May2016, June2016, July2016, Auguest2016, September2016
I want it to print out all of the months and year in between. Here is my sql queries:
select d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016')
First, create a numbers table
CREATE TABLE Numbers(N INT)
insert into Numbers(N)
select top 1000000 row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2
then use DATEADD to list dates between desired values, like this
declare #iniDate as date
set #iniDate='20150801'
select dateadd(MONTH,N,#iniDate) dates
from Numbers
where N<15 order by N
These returns dates from #iniDate up to 15 months later
EDIT: try this, I don't have sql right now
select datename(mm, dateadd(MONTH,N,#iniDate))+datename(yyyy ,dateadd(MONTH,N,#iniDate)) display
from ( select top 15row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2) numbers right join (
select d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016')
sql-server
) qq
on datename(mm, dateadd(MONTH,N,#iniDate))+datename(yyyy ,dateadd(MONTH,N,#iniDate)) = qq.display
where N<15 order by N
If I understand what you're trying to accomplish, a recursive CTE might help. Here's a quick example of what you can do. The CTE will expand out into a list of dates, which you can then use as the base for your query.
The contents of the TargetData CTE may need to be adjusted, as I don't have a complete picture of your data structure.
DECLARE #startDate DATE = '1/1/2015';
DECLARE #endDate DATE = '7/31/2016';
-- Recursive CTE to generate a list of months within the date range:
WITH Months AS (
SELECT CONVERT(DATE, DATEADD(D, -(DAY(#startDate)) + 1, #startDate)) [MonthDate]
UNION ALL
SELECT DATEADD(M, 1, MonthDate)
FROM Months
WHERE MonthDate <= DATEADD(M, -1, #endDate)
),
TargetData AS (
-- This is a slightly modified version of the original query:
select
d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display,
-- Return the "MonthDate" so that it can be left joined to the Months table:
DATEADD(D, -(DAY(d.c_issue_date)) + 1, d.c_issue_date) [MonthDate]
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN #startDate AND #endDate
)
SELECT
m.MonthDate,
DATENAME(mm, m.MonthDate) + DATENAME(yyyy, m.MonthDate),
td.*
FROM Months m
LEFT JOIN TargetData td ON td.MonthDate = m.MonthDate;
You need to join on primary keys between tables, I haven't seen a between statement with that syntax. So I suggest trying the following:
SELECT d.id_base as case_id, c.C_LAST_ACTION AS 'Docketed',c.C_CASE_TYPE AScaseType,ct.C_NAME As 'caseName', ct.C_DESCRIPTION AS 'caseNameDescription'
,CASE
WHEN d.c_mod_decision_id is not null THEN '' AS 'null_val'
ELSE CONCAT(YEAR(d.c_issue_dateDATENAME), MONTH(d.c_issue_date))
END AS 'display'
FROM t_case_decision d INNER JOIN T_CASE_INPUT c on c.id = d.id_base
INNER JOIN T_CASE_TYPE ct on c.id = ct.id
WHERE CONVERT(DATE,d.c_issue_date) BETWEEN '08/01/2015'
AND '08/01/2016';
I hope this helps or points you in the right direction :)
I have two queries. One query pulls the information based on the orders that have been scheduled to them in a day by employee. The other query pulls the number of orders that have been completed and paid in a day, along with the total amount of the revenue from the orders.
I have scraped the forums to get the code together to get these queries, but I need to have both queries joined together. I want to use this information in report builder once I get it done. It's probably simple for someone, but it's confusing me as I'm far from any sort of expert with SQL.
I only need one day at the moment, but found this code and modified for now and hope that I can use it in the future when needing week and month data.
Any help would be appreciated.
Query 1
declare #dt DATE = '20160823'
set DATEFIRST 7;
set #dt = dateadd(week, datediff(week, '19050101', #dt), '19050101');
;with dt as
(
select
Technician = (CASE emp_id
WHEN 'CW697' THEN 'Joe Biggs'
WHEN 'DZ663' THEN 'Mimi Cassidy'
END),
dw = datepart(weekday, DATE)
from
dbo.ordemps
where
date >= #dt and date <dateadd(day, 7, #dt)
),
x AS
(
select
Technician, dw = coalesce(dw,8),
c = convert(varchar(11), COUNT(*))
from
dt
group by
grouping sets((Technician), (Technician,dw))
)
select
Technician,
[Sun] = coalesce([1], '-'),
[Mon] = coalesce([2], '-'),
[Tue] = coalesce([3], '-'),
[Wed] = coalesce([4], '-'),
[Thu] = coalesce([5], '-'),
[Fri] = coalesce([6], '-'),
[Sat] = coalesce([7], '-'),
TOTAL =[8]
from
x
PIVOT
(MAX(c) FOR dw IN([1],[2],[3],[4],[5],[6],[7],[8])) as pvt;
Query 2
select
case
when grouping(d.m)=15 then 'Year ' + cast(max(d.y) as varchar(10))
when grouping(date)=15 then datename(m, max(DATE)) + ' ' + cast(max(d.y) as varchar(10))
else cast(cast([date] as date) as varchar(255))
end as DATE,
TotalOrders = /*sum(Amount)*/convert(varchar(11), COUNT(*)),
TotalSales = sum(Amount),
Technician = (CASE recv_by
WHEN 'CW697' THEN 'Joe Biggs'
WHEN 'DZ663' THEN 'Mimi Cassidy'
END)
from
ordpay
cross apply
(select
datepart(yy, [date]),
datepart(m, [date])
) d(y, m)
where
[DATE] >= dateadd(day, datediff(day, 1, getdate()), 0)
and [date] < dateadd(day, datediff(day, 0, getdate()), 0)
group by
recv_by, d.y, rollup (d.m, date)
order by
d.y desc, grouping(d.m), d.m, grouping(DATE), DATE
At the easiest level you can use can join sub-queries. Your example is a little trickier because you are using CTEs which can't go in the subquery. To get you going in the right direction it should generally look like this:
with cte1 as (),
cte2 as ()
select *
from (
select *
from tables
where criteria -- subquery 1 (cannot contain order by)
) a
join ( -- could be a left join
select *
from tables
where criteria -- subquery 2 (cannot contain order by)
) b
on b.x = a.x --join criteria
where --additional criteria
order by --final sort
where subquery 1 would be your query 1 from select Technician to the end
and subquery 2 would be everything from your query 2 except the order by.
For further information on joins see the MSDN documentation
Since you aren't going to research much it doesn't seem here's a clunky and quick way, and keeps it simple for you, without having to explain a lot if we were to join the queries together more elegantly.
The first set of code has 2 common table expressions (CTE). So, select those results into a temp. Notice the --addition here
....
select
Technician,
[Sun] = coalesce([1], '-'),
[Mon] = coalesce([2], '-'),
[Tue] = coalesce([3], '-'),
[Wed] = coalesce([4], '-'),
[Thu] = coalesce([5], '-'),
[Fri] = coalesce([6], '-'),
[Sat] = coalesce([7], '-'),
TOTAL =[8]
into #someTemp --Addition here
from
....
Do the same for your second query...
...
into #someOtherTemp --Addition here
from
ordpay
...
Then join them togehter...
select t1.someColumns, t2.someOtherColumns
from #someTemp t1
inner join #someOtherTemp t2 on t1.column = t2.column
The following query gives playing time of the users from the database on daily basis for the last 15 days. It adds 0 if no game is played. Now I want to get the data of playing time on weekly basis and 0 if no game is played in the whole week. So I want the query to give the last 15 weeks of data.
Here is the daily query.
CREATE PROCEDURE [dbo].[spGetPlayingTimeOfthepeoplesPerDay] #email NVARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MinDate DATE
,#MaxDate DATE
,#LastXDays INT
SELECT #LastXDays = - 15
SELECT #MaxDate = peoples.l_update
FROM peoples
WHERE peoples.email = #email
DECLARE #test TABLE (
quantity VARCHAR(100)
,DATE DATE
,TimePerDay DECIMAL(5, 2)
);
WITH CTE
AS (
SELECT peoples.email
,peoples.l_update
,act.quantity
,act.starttime
,act.endtime
,act.duration AS [Totaltime]
FROM peoples
INNER JOIN MPeoples ON peoples.Id = MPeoples.parent_id
INNER JOIN slines ON MPeoples.id = slines.movesuser_id
INNER JOIN seg ON slines.id = seg.sline_id
INNER JOIN act ON seg.id = act.seg_id
WHERE act.quantity = 'playing'
AND (peoples.email = #email)
GROUP BY peoples.email
,act.quantity
,act.duration
,act.starttime
,act.endtime
,peoples.l_update
)
INSERT INTO #test (
quantity
,DATE
,TimePerDay
)
SELECT quantity
,Cast(starttime AS DATE) AS DATE
,SUM(datediff(second, starttime, endtime)) / 60.0 AS TimePerDay
FROM cte WITH (NOLOCK)
WHERE starttime >= dateadd(day, #LastXDays, l_update)
GROUP BY quantity
,cast(starttime AS DATE)
SELECT #MaxDate = #MaxDate
,#MinDate = dateadd(day, (#LastXDays + 1), #MaxDate);
WITH AllDates
AS (
SELECT #MinDate AS xDate
UNION ALL
SELECT Dateadd(Day, 1, xDate)
FROM AllDates AS ad
WHERE ad.xDate < #MaxDate
)
SELECT 'playing' AS quantity
,ad.xDate
,Isnull(t.TimePerDay, 0) AS TimePerDay
FROM AllDates AS ad WITH (NOLOCK)
LEFT JOIN #test AS t ON ad.xDate = t.DATE
END
Change the DATEADD from day to week. Hence, two changes:
dateadd(week, #LastXDays, l_update)
and
dateadd(week, (#LastXDays + 1), #MaxDate)
In this case, I would also rename the #LastXDays variable to #LastXWeeks.
CREATE PROCEDURE [dbo].[spGetPlayingTimeOfthepeoplesPerDay] #email NVARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MinDate DATE
,#MaxDate DATE
,#LastXDays INT
SELECT #LastXWeeks = - 15
SELECT #MaxDate = peoples.l_update
FROM peoples
WHERE peoples.email = #email
DECLARE #test TABLE (
quantity VARCHAR(100)
,DATE DATE
,TimePerDay DECIMAL(5, 2)
);
WITH CTE
AS (
SELECT peoples.email
,peoples.l_update
,act.quantity
,act.starttime
,act.endtime
,act.duration AS [Totaltime]
FROM peoples
INNER JOIN MPeoples ON peoples.Id = MPeoples.parent_id
INNER JOIN slines ON MPeoples.id = slines.movesuser_id
INNER JOIN seg ON slines.id = seg.sline_id
INNER JOIN act ON seg.id = act.seg_id
WHERE act.quantity = 'playing'
AND (peoples.email = #email)
GROUP BY peoples.email
,act.quantity
,act.duration
,act.starttime
,act.endtime
,peoples.l_update
)
INSERT INTO #test (
quantity
,DATE
,TimePerDay
)
SELECT quantity
,Cast(starttime AS DATE) AS DATE
,SUM(datediff(second, starttime, endtime)) / 60.0 AS TimePerDay
FROM cte WITH (NOLOCK)
WHERE starttime >= dateadd(week, #LastXWeeks, l_update)
GROUP BY quantity
,cast(starttime AS DATE)
SELECT #MaxDate = #MaxDate
,#MinDate = dateadd(week, (#LastXWeeks + 1), #MaxDate);
WITH AllDates
AS (
SELECT #MinDate AS xDate
UNION ALL
SELECT Dateadd(Day, 7, xDate)
FROM AllDates AS ad
WHERE ad.xDate < #MaxDate
)
SELECT 'playing' AS quantity
,ad.xDate
,Isnull(t.TimePerDay, 0) AS TimePerDay
FROM AllDates AS ad WITH (NOLOCK)
LEFT JOIN #test AS t ON ad.xDate = t.DATE
END
Also, a piece of advice: don't use query hints (NOLOCK) if you do not understand their use. In this case, using NOLOCK can have disastrous effects on your results.
Here are a few articles which you should read before deciding if you are going to keep using NOLOCK or not.
Understanding the SQL Server NOLOCK hint
Bad habits : Putting NOLOCK everywhere
This question already has answers here:
Left Join With Where Clause
(7 answers)
Closed 4 years ago.
Here is what I´m doing:
WITH cte AS (
SELECT * FROM TimeDim
)
SELECT t.TimeDimPK, c.ID
FROM CTE AS t
LEFT OUTER JOIN TABLE c ON c.TimeDimFK = t.TimeDimPK
ORDER BY t.TimeDimPK
WHERE c.ID = 1
Result, which is missing dates as shown below:
TimeDimPK ID
20120930 1
20121231 1
20130131 1
What I´m trying to get
TimeDimPK ID
20120930 1
20121031 NULL
20121130 NULL
20121231 1
20130131 1
It looks like your WHERE clause is getting rid of the other dates. Try this instead:
WITH cte
AS ( SELECT TimedimPK
FROM TimeDim
)
SELECT t.TimeDimPK ,
c.ID
FROM cte t
LEFT OUTER JOIN TABLEname c ON c.TimeDimFK = t.TimeDimPK
WHERE c.ID = 1
OR c.ID IS NULL
ORDER BY t.TimeDimPK
You can try to use a "number/date generator", this queries will fill in all missing days, then select the last day of the month. I am not sure about all your data details, so I am currently giving you two suggestions:
1 - Compact suggestion:
DECLARE #minDate DATETIME, #maxDate DATETIME;
SELECT #minDate = MIN(TimeDimPK), #maxDate = MAX(TimeDimPK) FROM TimeDim;
WITH DateGenerator AS
(
--Create a list with a lot of dates from #minDate
SELECT TimeDimPK = CONVERT(DATE, DATEADD(dd, ROW_NUMBER() OVER (ORDER BY OBJECT_ID), #minDate)) FROM sys.objects
)
--List all days, including missing days
SELECT TimeDimPK
, c.ID
FROM DateGenerator n
LEFT JOIN AnotherTable c ON c.TimeDimFK = n.TimeDimPK
WHERE
--Stop the number generator at the last day of the last month from the cte table
n.TimeDimPK <= CONVERT(DATE, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0, #maxDate )+1,0)))
--This will get the last day of every month
AND TimeDimPK = CONVERT(DATE, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,TimeDimPK)+1,0)))
2 - Suggestion with your cte clause, if you want to use it for some tweaking:
WITH NumberGenerator AS
(
--Create a number list 1,2,3,4,5,6,7,8,++
SELECT Number = ROW_NUMBER() OVER (ORDER BY OBJECT_ID) FROM sys.objects
), cte AS (
--Your cte query with a date number based on the days between the firts and current days
SELECT
TimeDimPK = CONVERT(DATETIME, TimeDimPK)
--Get the number of days to add from the first day in your table
, DateNumber = DATEDIFF(dd, MIN(TimeDimPK) OVER (), TimeDimPK)
FROM #TimeDim
), TableWithMissingDates AS
(
--Fill missing days
SELECT TimeDimPK = CONVERT(DATE, DATEADD(dd, n.Number - 1, MIN(t.TimeDimPK) OVER ()))
, c.ID
FROM NumberGenerator n
LEFT JOIN cte t ON t.DateNumber = n.Number
LEFT JOIN #Test2 c ON c.TimeDimFK = t.TimeDimPK
--Stop the number generator at the last day of the last month from the cte table
WHERE CONVERT(DATE, DATEADD(dd, n.Number - 1, (SELECT MIN(TimeDimPK) FROM cte))) < CONVERT(DATE, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0, (SELECT MAX(TimeDimPK) FROM cte) )+1,0)))
)
SELECT * FROM TableWithMissingDates
WHERE
--This will get the last day of every month
TimeDimPK = CONVERT(DATE, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,TimeDimPK)+1,0)))
Both queries will return the same table:
Table structure:
This is the data for which i want to use pivot table
i want to display the result as
Teacher Activity [2013-11-22] and so on The date field will display the count of the attendance.
Below is the code which i am using, result is coming as 0 under every date, which is not correct:
DECLARE #temp AS TABLE(dates datetime)
;with cte (datelist, maxdate) as
(
select DATEADD(dd,-3,GETDATE()), GETDATE()
union all
select dateadd(dd, 1, datelist), maxdate
from cte
where datelist < maxdate
)
INSERT INTO #temp
SELECT c.datelist
FROM cte c
DECLARE #listdate nvarchar(MAX)
SELECT #listdate = (select(STUFF( (SELECT ', ' + QUOTENAME(convert(CHAR(10), dates, 120))
from #temp ORDER BY dates asc
FOR XML PATH('')),1, 1, '')))
print #listdate
exec('(SELECT * INTO ##temptable from
(select distinct teachername as Teacher,activityname AS Activity,memberid as attendance,
QUOTENAME(convert(CHAR(10), attendancedate, 120)) AS DATES from
tbteachertimelog inner join tbteacher on
teacherid = tbteacher.id
inner join tbactivity on tbactivity.id = tbteachertimelog.activityid
left join tbattendance on tbattendance.activityid = tbteachertimelog.activityid and
convert(CHAR(10), tbattendance.attendancedate, 120) = convert(CHAR(10), tbteachertimelog.date, 120)
group by teachername,activityname,memberid,
attendancedate
) p
PIVOT
(
count(attendance)
FOR DATES IN ('+#listdate+')) AS pvt
)
')
alter table ##temptable add TotalStudents int,meetings int,total64 int
update ##temptable set TotalStudents =
(SELECT SUM(memcount) FROM (select count(distinct memberid) as memcount from tbteachertimelog
inner join tbattendance on tbattendance.activityid = tbteachertimelog.activityid and
convert(CHAR(10), tbattendance.attendancedate, 120) = convert(CHAR(10), tbteachertimelog.date, 120)
where --teacherid = ##temptable.teacherid and tbteachertimelog.activityid = ##temptable.activityid
--and
tbattendance.attendancedate >= dateadd(dd,-7,getdate()) and tbattendance.attendancedate <= getdate()
group by convert(CHAR(10), tbattendance.attendancedate, 120)) x)
update ##temptable set meetings =
(select count(distinct convert(CHAR(10), tbattendance.attendancedate, 120)) as dayscount from tbteachertimelog
inner join tbattendance on tbattendance.activityid = tbteachertimelog.activityid and
convert(CHAR(10), tbattendance.attendancedate, 120) = convert(CHAR(10), tbteachertimelog.date, 120)
where teacherid = ##temptable.teacherid and tbteachertimelog.activityid = ##temptable.activityid)
select * from ##temptable
drop table ##temptable
The problem is with the following line in your subquery:
QUOTENAME(convert(CHAR(10), attendancedate, 120)) AS DATES
The QUOTENAME is required when you are creating the list of dates as the column headers but since you added this to your subquery your dates in the table appear:
DATES
[2013-11-22]
[2013-11-23]
[2013-11-24]
But you want the dates being returned inside your subquery should be without the brackets:
DATES
2013-11-22
2013-11-23
2013-11-24
The PIVOT function is looking for dates that match your data but since you have the dates surrounded with square brackets you don't get any matches, as a result you are returning zeros for everything.
Your columns don't match your data because of the bracket -- for example:
Header -- YourDate
2013-11-22 -- does not match [2013-11-22]
2013-11-23 -- does not match [2013-11-23]
2013-11-24 -- does not match [2013-11-24]
The query should be:
exec('
with data as
(
SELECT *
from
(
select distinct teachername as Teacher,
activityname AS Activity,
memberid as attendance,
convert(CHAR(10), attendancedate, 120) AS DATES
from tbteachertimelog
inner join tbteacher
on teacherid = tbteacher.id
inner join tbactivity
on tbactivity.id = tbteachertimelog.activityid
inner join tbattendance
on tbattendance.activityid = tbactivity.id
) p
PIVOT
(
count(attendance)
FOR DATES IN ('+#listdate+')
) AS pvt
)
select *
from data
')