Retrieve last record from current month and previous month - sql

I need to get the last recorded value from the current month and the previous month. There are roughly 4,600 records per month.
The following is the code I have tried, however it returns '0' for the two months and not the value:
SELECT a.LogPoint as [Meter]
,max(CASE WHEN c.DateTimeStamp = dateadd(MM,-1,getdate()) THEN c.FloatVALUE ELSE 0 END) as [Total LAST Month]
,max(CASE WHEN c.DateTimeStamp = getdate() THEN c.FloatVALUE ELSE 0 END) as [Total This Month]
FROM
SWR.dbo.LoggedEntities a
,SWR.dbo.TrendLogRelation b
,SWR.dbo.LogTimeValues c
WHERE
a.GUID = b .GUID
AND a.Type LIKE 'trend.ETLog'
AND a.LogPoint = 'WsumOut_Trnd'
AND b.EntityID = c.ParentID
GROUP BY a.LogPoint
Any help would be greatly appreciated.
Cheers.

I assume the LogPoint is the primary key. correct? In that case check following:
SELECT mainA.LogPoint AS [Meter],
lastMonth.FloatValue AS [Total LAST Month],
thisMonth.FloatValue AS [Total This Month]
FROM SWR.dbo.LoggedEntities mainA
CROSS APPLY
(
SELECT TOP 1 c.FloatVALUE
FROM SWR.dbo.LoggedEntities a
JOIN SWR.dbo.TrendLogRelation b ON a.GUID = b.GUID
JOIN SWR.dbo.LogTimeValues c ON b.EntityID = c.ParentID
WHERE a.LogPoint = mainA.LogPoint
ORDER BY c.DateTimeStamp DESC
) thisMonth
CROSS APPLY
(
SELECT TOP 1 c.FloatVALUE
FROM SWR.dbo.LoggedEntities a
JOIN SWR.dbo.TrendLogRelation b ON a.GUID = b.GUID
JOIN SWR.dbo.LogTimeValues c ON b.EntityID = c.ParentID
WHERE a.LogPoint = mainA.LogPoint AND c.DateTimeStamp <= DATEADD(MM,-1,GETDATE())
ORDER BY c.DateTimeStamp DESC
) lastMonth
WHERE a.Type LIKE 'trend.ETLog'
AND a.LogPoint = 'WsumOut_Trnd';
Just realized that I missed the last month date check. added now. try that :)

getdate() includes both the time and the date, which is why you aren't getting any matches.
One option is to cast both values to dates and then do the comparison.

Two important points before I start:
Never use commas in the FROM clause. Always use explicit JOIN syntax.
Table aliases should be abbreviations for the table.
Then, you want to use row_number():
SELECT LogPoint as [Meter],
max(CASE WHEN seqnum = 1 AND
DATEDIFF(month, DateTimeStamp, getdate()) = 1
THEN cltv.FloatVALUE
END) as [Total LAST Month],
max(CASE WHEN seqnum = 1 AND
DATEDIFF(month, DateTimeStamp, getdate()) = 0
THEN ltv.FloatVALUE
END) as [Total This Month]
FROM (SELECT le.LogPoint, ltv.DateTimeStamp,
ROW_NUMBER() OVER (PARTITION BY YEAR(DateTimeStamp), MONTH(DateTimeStamp)
ORDER BY DateTimeStamp DESC
) as seqnum
FROM SWR.dbo.LoggedEntities le JOIN
SWR.dbo.TrendLogRelation tlr
ON le.GUID = tlr.GUID JOIN
SWR.dbo.LogTimeValues ltv
ON ltr.EntityID = ltv.ParentID
WHERE le.Type LIKE 'trend.ETLog' AND
le.LogPoint = 'WsumOut_Trnd' AND
DATEDIFF(month, ltv.DateTimeStamp, getdate()) IN (0, 1)
) x
WHERE seqnum = 1;

Related

How do I show the percentage of a group in SQL?

I am trying to show the percentage of tasks completed before a certain deadline, for separate groups.
I have calculated the percentage for the whole, but when I try to split the data into a calculation for each group I keep getting errors.
To calculate the percentage, I have been using:
DECLARE #TM DATETIME;
SET #TM = DATEADD(MONTH,DATEDIFF(MONTH,'19000101', GETDATE()), '19000101')
SELECT CAST(
(
SELECT COUNT (a.[completed])
FROM [table] a
JOIN [other table] b
ON a.TaskID = b.TaskID
WHERE a.[completed] >= DATEADD(MONTH,0,#TM) AND
b.[completedByDeadline] = 1) AS DECIMAL (10,2))
/
CAST(
(
SELECT COUNT([completed])
FROM [table]
WHERE [completed] >= DATEADD(MONTH,0,#TM))
*100 AS Decimal (10,2))
When I try to add the [groupName] column to the SELECT list and a GROUP BY clause, there are errors; it mentions the need for an EXISTS keyword, but I can't see where to put one.
Any help that people could provide would be fantastic! Thanks.
I would just use this:
DECLARE #TM DATETIME;
SET #TM = DATEADD(MONTH,DATEDIFF(MONTH,'19000101', GETDATE()), '19000101')
SELECT
COUNT (case
when b.[completedByDeadline] = 1
then 1
else NULL
end) / COUNT (a.[completed])
FROM [table] a
LEFT JOIN [other table] b
ON a.TaskID = b.TaskID
WHERE a.[completed] >= DATEADD(MONTH,0,#TM)
I like using AVG() for this sort of query:
SELECT AVG(case when b.[completedByDeadline] = 1 then 1.0 else 0
end)
FROM [table] a LEFT JOIN
[other table] b
ON a.TaskID = b.TaskID
WHERE a.[completed] >= DATEADD(MONTH, 0, #TM);
If completedByDeadline only takes on the values 0 and 1, this can be simplified further:
SELECT AVG(b.[completedByDeadline] * 1.0)
FROM [table] a LEFT JOIN
[other table] b
ON a.TaskID = b.TaskID
WHERE a.[completed] >= DATEADD(MONTH, 0, #TM);
Note that these will return NULL if there are no corresponding tasks in b.

SQL COUNT that includes 0 values

have a query that lists that amount of jobs for each day over a 7 day period.
works fine but it doesn't include 0 results.
what do i need to do get have it include 0 results.
select date_received, count(*)
from calls with (nolock)
where contract = 'BLAH'
and date_received between DATEADD(day,-8,GETDATE()) AND GETDATE()-1
group by date_Received
order by date_received
this query produces results for 6 days, the 7th day has 0 calls, but that day to be included.
If you have a calendar table, you can do:
SELECT A.[Date] date_received,
COUNT(*) N
FROM dbo.Calendar A
LEFT JOIN ( SELECT *
FROM dbo.calls
WHERE contract = 'BLAH') B
ON A.[Date] = B.date_received
WHERE A.[Date] >= DATEADD(DAY,-8,CONVERT(DATE,GETDATE())
AND A.[Date] <= DATEADD(DAY,-1,CONVERT(DATE,GETDATE()))
GROUP BY A.[Date]
If not, you can use a CTE for you calendar table:
;WITH Calendar AS
(
SELECT DATEADD(DAY,-1*number,CONVERT(DATE,GETDATE())) [Date]
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 8
)
SELECT A.[Date] date_received,
COUNT(*) N
FROM Calendar A
LEFT JOIN ( SELECT *
FROM dbo.calls
WHERE contract = 'BLAH') B
ON A.[Date] = B.date_received
GROUP BY A.[Date]

Selecting the Max Date From Multiple Tables

any help would be so incredibly appreciated. I am trying to select the last activity date from a group of tables. The tables include Entry Date, Note date, payment date, and Claim Date. I would like to return only the max value from all these dates. Furthermore I only want records where there has been no activity for over 45 days. I am currently using the following SQL to bring all the dates in then using calculated fields in EXCEL to figure the rest out. Is it possible to do this all with SQL?
Thanks in advance.
SELECT xrxTrnLgr.PatId, xrxTrnLgr.Balance,
Max(xrxPatNotes.NoteDate) AS 'Max of NoteDate',
Max(xrxTrnIcf.PostDate) AS 'Max of IcfPostDate',
Max(xrxPat.EntryDate) AS 'Entry Date',
Max(xrxPat.Coverage) AS 'Coverage',
Max(xrxTrnPay.PostDate) AS 'Last Payment'
FROM xrxTrnLgr
LEFT OUTER JOIN xrxPatNotes ON xrxTrnLgr.PatId = xrxPatNotes.PatId
LEFT OUTER JOIN xrxTrnIcf ON xrxTrnLgr.PatId = xrxTrnIcf.PatId
LEFT OUTER JOIN xrxPat ON xrxTrnLgr.PatId = xrxPat.PatId
LEFT OUTER JOIN xrxTrnPay ON xrxTrnLgr.PatId = xrxTrnPay.PatId
GROUP BY xrxTrnLgr.PatId, xrxTrnLgr.Balance
HAVING (xrxTrnLgr.Balance>$.01)
I think this might do it all in SQL:
select t.patid, t.balance,
max(case when which = 'note' then thedate end) as note,
max(case when which = 'post' then thedate end) as post,
max(case when which = 'entry' then thedate end) as entry,
max(case when which = 'coverage' then thedate end) as coverage,
max(case when which = 'lastPayment' then thedate end) as lastPayment
from xrxTrnLgr t left join
((select patid, notedate as thedate, 'note' as which
from xrxPatNotes
) union all
(select patid, postdate, 'post'
from xrxtrnIcf
) union all
(select patid, EntryDate, 'entry'
from xrxPat
) union all
(select paid, Coverage, 'coverage'
from xrxPat.Coverage
) union all
(select patid, PostDate, 'LastPayment'
from xrxTrnPay.PostDate
)
) d
on t.patid = d.patid
group by t.patid, t.balance
having min(now() - thedate) >= 45

SQL Query in CRM Report

A "Case" in CRM has a field called "Status" with four options.
I'm trying to
build a report in CRM that fills a table with every week of the year (each row is a different week), and then counts the number of cases that have each Status option (the columns would be each of the Status options).
The table would look like this
Status 1 Status 2 Status 3
Week 1 3 55 4
Week 2 5 23 5
Week 3 14 11 33
So far I have the following:
SELECT
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM [DB].[dbo].[Contact]
Which gives me the following:
Status 1 Status 2 Status 3
2 43 53
Now I need to somehow split this into 52 rows for the past year and filter these results by date (columns in the Contact table). I'm a bit new to SQL queries and CRM - any help here would be much appreciated.
Here is a SQLFiddle with my progress and sample data: http://sqlfiddle.com/#!2/85b19/1
Sounds like you want to group by a range. The trick is to create a new field that represents each range (for you one per year) and group by that.
Since it also seems like you want an infinite range of dates, marc_s has a good summary for how to do the group by trick with dates in a generic way: SQL group by frequency within a date range
So, let's break this down:
You want to make a report that shows, for each contact, a breakdown, week by week, of the number of cases registered to that contact, which is divided into three columns, one for each StateCode.
If this is the case, then you would need to have 52 date records (or so) for each contact. For calendar like requests, it's always good to have a separate calendar table that lets you query from it. Dan Guzman has a blog entry that creates a useful calendar table which I'll use in the query.
WITH WeekNumbers AS
(
SELECT
FirstDateOfWeek,
-- order by first date of week, grouping calendar year to produce week numbers
WeekNumber = row_number() OVER (PARTITION BY CalendarYear ORDER BY FirstDateOfWeek)
FROM
master.dbo.Calendar -- created from script
GROUP BY
FirstDateOfWeek,
CalendarYear
), Calendar AS
(
SELECT
WeekNumber =
(
SELECT
WeekNumber
FROM
WeekNumbers WN
WHERE
C.FirstDateOfWeek = WN.FirstDateOfWeek
),
*
FROM
master.dbo.Calendar C
WHERE
CalendarDate BETWEEN '1/1/2012' AND getutcdate()
)
SELECT
C.FullName,
----include the below if the data is necessary
--Cl.WeekNumber,
--Cl.CalendarYear,
--Cl.FirstDateOfWeek,
--Cl.LastDateOfWeek,
'Week: ' + CAST(Cl.WeekNumber AS VARCHAR(20))
+ ', Year: ' + CAST(Cl.CalendarYear AS VARCHAR(20)) WeekNumber
FROM
CRM.dbo.Contact C
-- use a cartesian join to produce a table list
CROSS JOIN
(
SELECT
DISTINCT WeekNumber,
CalendarYear,
FirstDateOfWeek,
LastDateOfWeek
FROM
Calendar
) Cl
ORDER BY
C.FullName,
Cl.WeekNumber
This is different from the solution Ben linked to because Marc's query only returns weeks where there is a matching value, whereas you may or may not want to see even the weeks where there is no activity.
Once you have your core tables of contacts split out week by week as in the above (or altered for your specific time period), you can simply add a subquery for each StateCode to see the breakdown in columns as in the final query below.
WITH WeekNumbers AS
(
SELECT
FirstDateOfWeek,
WeekNumber = row_number() OVER (PARTITION BY CalendarYear ORDER BY FirstDateOfWeek)
FROM
master.dbo.Calendar
GROUP BY
FirstDateOfWeek,
CalendarYear
), Calendar AS
(
SELECT
WeekNumber =
(
SELECT
WeekNumber
FROM
WeekNumbers WN
WHERE
C.FirstDateOfWeek = WN.FirstDateOfWeek
),
*
FROM
master.dbo.Calendar C
WHERE
CalendarDate BETWEEN '1/1/2012' AND getutcdate()
)
SELECT
C.FullName,
--Cl.WeekNumber,
--Cl.CalendarYear,
--Cl.FirstDateOfWeek,
--Cl.LastDateOfWeek,
'Week: ' + CAST(Cl.WeekNumber AS VARCHAR(20)) +', Year: ' + CAST(Cl.CalendarYear AS VARCHAR(20)) WeekNumber,
(
SELECT
count(*)
FROM
CRM.dbo.Incident I
INNER JOIN CRM.dbo.StringMap SM ON
I.StateCode = SM.AttributeValue
INNER JOIN
(
SELECT
DISTINCT ME.Name,
ME.ObjectTypeCode
FROM
CRM.MetadataSchema.Entity ME
) E ON
SM.ObjectTypeCode = E.ObjectTypeCode
WHERE
I.ModifiedOn >= Cl.FirstDateOfWeek
AND I.ModifiedOn < dateadd(day, 1, Cl.LastDateOfWeek)
AND E.Name = 'incident'
AND SM.AttributeName = 'statecode'
AND SM.LangId = 1033
AND I.CustomerId = C.ContactId
AND SM.Value = 'Active'
) ActiveCases,
(
SELECT
count(*)
FROM
CRM.dbo.Incident I
INNER JOIN CRM.dbo.StringMap SM ON
I.StateCode = SM.AttributeValue
INNER JOIN
(
SELECT
DISTINCT ME.Name,
ME.ObjectTypeCode
FROM
CRM.MetadataSchema.Entity ME
) E ON
SM.ObjectTypeCode = E.ObjectTypeCode
WHERE
I.ModifiedOn >= Cl.FirstDateOfWeek
AND I.ModifiedOn < dateadd(day, 1, Cl.LastDateOfWeek)
AND E.Name = 'incident'
AND SM.AttributeName = 'statecode'
AND SM.LangId = 1033
AND I.CustomerId = C.ContactId
AND SM.Value = 'Resolved'
) ResolvedCases,
(
SELECT
count(*)
FROM
CRM.dbo.Incident I
INNER JOIN CRM.dbo.StringMap SM ON
I.StateCode = SM.AttributeValue
INNER JOIN
(
SELECT
DISTINCT ME.Name,
ME.ObjectTypeCode
FROM
CRM.MetadataSchema.Entity ME
) E ON
SM.ObjectTypeCode = E.ObjectTypeCode
WHERE
I.ModifiedOn >= Cl.FirstDateOfWeek
AND I.ModifiedOn < dateadd(day, 1, Cl.LastDateOfWeek)
AND E.Name = 'incident'
AND SM.AttributeName = 'statecode'
AND SM.LangId = 1033
AND I.CustomerId = C.ContactId
AND SM.Value = 'Canceled'
) CancelledCases
FROM
CRM.dbo.Contact C
CROSS JOIN
(
SELECT
DISTINCT WeekNumber,
CalendarYear,
FirstDateOfWeek,
LastDateOfWeek
FROM
Calendar
) Cl
ORDER BY
C.FullName,
Cl.WeekNumber

How to output only one max value from this query in SQL?

Yesterday Thomas helped me a lot by providing exactly the query I wanted. And now I need a variant of it, and hopes someone can help me out.
I want it to output only one row, namely a max value - but it has to build on the algorithm in the following query:
WITH Calendar AS (SELECT CAST(#StartDate AS datetime) AS Date
UNION ALL
SELECT DATEADD(d, 1, Date) AS Expr1
FROM Calendar AS Calendar_1
WHERE (DATEADD(d, 1, Date) < #EndDate))
SELECT C.Date, C2.Country, COALESCE (SUM(R.[Amount of people per day needed]), 0) AS [Allocated testers]
FROM Calendar AS C CROSS JOIN
Country AS C2 LEFT OUTER JOIN
Requests AS R ON C.Date BETWEEN R.[Start date] AND R.[End date] AND R.CountryID = C2.CountryID
WHERE (C2.Country = #Country)
GROUP BY C.Date, C2.Country OPTION (MAXRECURSION 0)
The output from above will be like:
Date Country Allocated testers
06/01/2010 Chile 3
06/02/2010 Chile 4
06/03/2010 Chile 0
06/04/2010 Chile 0
06/05/2010 Chile 19
but what I need right now is
Allocated testers
19
that is - only one column - one row - the max value itself... (for the (via parameters (that already exists)) selected period of dates and country)
use order and limit
ORDER BY 'people needed DESC' LIMIT 1
EDITED
as LIMIT is not exist in sql
use ORDER BY and TOP
select TOP 1 .... ORDER BY 'people needed' DESC
WITH Calendar
AS (
SELECT
CAST(#StartDate AS datetime) AS Date
UNION ALL
SELECT
DATEADD(d, 1, Date) AS Expr1
FROM
Calendar AS Calendar_1
WHERE
( DATEADD(d, 1, Date) < #EndDate )
)
SELECT TOP 1 *
FROM
(
SELECT
C.Date
,C2.Country
,COALESCE(SUM(R.[Amount of people per day needed]), 0) AS [Allocated testers]
FROM
Calendar AS C
CROSS JOIN Country AS C2
LEFT OUTER JOIN Requests AS R
ON C.Date BETWEEN R.[Start date] AND R.[End date]
AND R.CountryID = C2.CountryID
WHERE
( C2.Country = #Country )
GROUP BY
C.Date
,C2.Country
OPTION
( MAXRECURSION 0 )
) lst
ORDER BY lst.[Allocated testers] DESC
Full example following the discussion in #Salil answer..
WITH Calendar AS (SELECT CAST(#StartDate AS datetime) AS Date
UNION ALL
SELECT DATEADD(d, 1, Date) AS Expr1
FROM Calendar AS Calendar_1
WHERE (DATEADD(d, 1, Date) < #EndDate))
SELECT TOP 1 C.Date, C2.Country, COALESCE (SUM(R.[Amount of people per day needed]), 0) AS [Allocated testers]
FROM Calendar AS C CROSS JOIN
Country AS C2 LEFT OUTER JOIN
Requests AS R ON C.Date BETWEEN R.[Start date] AND R.[End date] AND R.CountryID = C2.CountryID
WHERE (C2.Country = #Country)
GROUP BY C.Date, C2.Country
ORDER BY 3 DESC
OPTION (MAXRECURSION 0)
the ORDER BY 3 means order by the 3rd field in the SELECT statement.. so if you remove the first two fields, change this accordingly..