the following query is displaying the result i want except i want it to show 0 for each month with non production.
SELECT
DATENAME(MONTH, DATEADD(M, MONTH(PolicyDetails.IssuedDate), - 1)) AS Month,
SUM(PolicyDetails.Premium) AS TotalProduction,
DATENAME(YEAR, PolicyDetails.IssuedDate) AS Year
FROM PolicyDetails INNER JOIN Clients
ON PolicyDetails.ClientId = Clients.ClientId
WHERE (Clients.Username = #Username)
GROUP BY MONTH(PolicyDetails.IssuedDate), DATENAME(YEAR, PolicyDetails.IssuedDate)
Month Total Production -$$
2019 - August 30.00
2019 - October 45.00
in this table i want to show "2019 - September" with Total Production = 0 instead of displaying nothing. How ??
If you want to show all months in the data, probably the simplest method is to use conditional aggregation. Your calculation of the month seems awkward. You seem to want the previous month, so:
SELECT DATENAME(YEAR, pd.IssuedDate) AS Year,
DATENAME(MONTH, DATEADD(MONTH, -1, pd.IssuedDate)) AS Month,
SUM(CASE WHEN c.Username = #Username THEN pd.Premium ELSE 0 END) AS TotalProduction
FROM PolicyDetails pd INNER JOIN
Clients c
ON pd.ClientId = c.ClientId
GROUP BY DATENAME(YEAR, pd.IssuedDate), DATENAME(MONTH, DATEADD(MONTH, -1, pd.IssuedDate))
ORDER BY MIN(pd.IssuedDate)
This assumes that you have at least one row per month in the data.
Otherwise, the canonical approach is to generate the months you want (using a derived table or recursive CTE or calendar table). Your month arithmetic is a bit awkward for that solution. It would look like:
SELECT YEAR(DATEADD(MONTH, -1, months.mstart)),
MONTH(DATEADD(MONTH, -1, months.mstart)),
COALESCE(SUM(pd.Premium), 0) AS TotalProduction
FROM (VALUES (CONVERT(DATE, '2019-08-01')),
(CONVERT(DATE, '2019-09-01')),
(CONVERT(DATE, '2019-10-01'))
) months(mstart) LEFT JOIN
PolicyDetails pd
ON pd.IssuedDate >= DATEADD(month, -1, months.mstart) AND
pd.IssuedDate < months.mstart LEFT JOIN
Clients c
ON pd.ClientId = c.ClientId AND
c.Username = #Username
GROUP BY YEAR(DATEADD(MONTH, -1, months.mstart)),
MONTH(DATEADD(MONTH, -1, months.mstart))
ORDER BY MIN(pd.IssuedDate)
I suppose that might be a usecase for SQL-IF.
Syntax as follows:
SELECT IF([condition], "YES", "NO");
In your case, try to combine that with your query.
Maybe like this:
SELECT IF([subquery > 0] AS X, X, 0);
If-Condition Like:
SELECT IF((SELECT COUNT(*) FROM PolicyDetails ) > 0, 1, 0);
But you will have to combine that output with your existing query posted above, to gain the output if the table is filled.
Related
I have two tables in SQL Server.
I want to select DeptCode, DeptName, YearToDate, PeriodToDate (2 months for example) and group it by DeptCode.
There is a result which I want to get:
In YTD column I want to get sum of totalCost since 01/01/actualYear.
In PTD column I want to get the sum from last two months.
I created a piece of code which shows me correct YTD cost but I don't know how I can add next one for getting total cost for other date range. Is it possible to do this?
SELECT
d.DeptCode,
d.DeptName,
SUM(s.TotalCost) as YTD
FROM [Departments] AS d
INNER JOIN Shipments AS s
ON d.DeptCode= s.DeptCode
WHERE s.ShipmentDate BETWEEN DateAdd(yyyy, DateDiff(yyyy, 0, GetDate()), 0)
AND GETDATE()
GROUP BY d.DeptCode, d.DeptName
Your expected output doesn't match 2 months, but here's the code to accomplish what you want. You just have to add a SUM(CASE...) on the 2nd condition.
SELECT
d.DeptCode,
d.DeptName,
SUM(s.TotalCost) as YTD,
SUM(CASE WHEN s.ShipmentDate >= DATEADD(month, -2, GETDATE()) then s.TotalCost else 0 END) as PTD
FROM [Departments] AS d
INNER JOIN Shipments AS s
ON d.DeptCode= s.DeptCode
WHERE Year(s.ShipmentDate) = Year(GETDATE())
GROUP BY d.DeptCode, d.DeptName
Just add one more column that returns 0 when not in the two-month range, e.g. SUM(CASE WHEN (date check) THEN (amount) ELSE 0 END). Check out the fifth line:
SELECT
d.DeptCode,
d.DeptName,
SUM(s.TotalCost) as YTD,
SUM(CASE WHEN DateDiff(MONTH, s.ShipmentDate, GetDate()) < 2 THEN s.TotalCost ELSE 0 END) PTD,
FROM [Departments] AS d
INNER JOIN Shipments AS s
ON d.DeptCode= s.DeptCode
WHERE s.ShipmentDate BETWEEN DateAdd(yyyy, DateDiff(yyyy, 0, GetDate()), 0)
AND GETDATE()
GROUP BY d.DeptCode, d.DeptName
Try this one :
nbr_last2month_ AS
(
SELECT DISTINCT
Sum(s.[TotalCost]) AS 'PTD',
s.DeptCode,
s.DeptName
FROM [Shipements] s
LEFT JOIN [Departements] d ON d.[DeptCode] = s.[DeptCode]
WHERE Year(date_) LIKE Year(GETDATE())
AND MONTH(ShipementDate) LIKE Month(Getdate()) - 2
Group by DeptCode
),
nbr_YTD_ AS
(
SELECT DISTINCT
Sum(s.[TotalCost]) AS 'YTD',
s.DeptCode,
s.DeptName
FROM [Shipements] s
LEFT JOIN [Departements] d ON d.[DeptCode] = s.[DeptCode]
WHERE Year(ShipementDate) LIKE Year(GETDATE())
Group by DeptCode
),
SELECT
A.DeptCode,
A.DeptName,
YTD,
PTD
FROM nbr_YTD_ A
LEFT JOIN nbr_last2month_ B on B.DeptCode = A.DeptCode
ORDER BY DeptCode
I have created a stored procedure that is run at the end of every day which will return the attendance percentage of each student in a class, the result set will show the students previous attendance percentage compared against their new percentage. But for some reason the results are being stored in multiple rows instead of one row. The diagrams below will give you a better understanding of the problem.
The Two Tables:
Student Table
Percentage Table
The code I have written to get the results into a combined table:
select
StudentTb.StudentId,
StudentTb.Forename,
StudentTb.Surname,
CONVERT(VARCHAR(10),DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE())-1, 0),103) as [Previous Reading Date]
case studentTb.Date
when DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE())-1, 0) then PercentageTb.Percentage
End
'Previous Percentage'
CONVERT(VARCHAR,DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0),103) as [Present Reading Date]
case studentTb.Date
when DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE())-1, 0) then PercentageTb.Percentage
End
'Current Percentage'
from studentTb inner join
PercentageTb on studentTb.StudentID = PercentageTb.StudentID
and this is the result set from this query!
However this is not the way I intended the results to look, below shows the desired result set!
I thought the CASE statement would have done that for me but obviously I was wrong, could someone please give me some indication on where I need to go from here?
Why not just do a select with sub select? Assuming a student can only have one result on each day
DECLARE #CurrentDate DATE
DECLARE #PreviousDate DATE
SET #CurrentDate =
SET #PreviousDate =
SELECT
StudentTb.StudentId AS [ID],
StudentTb.Forename AS [Forename],
StudentTb.Surname AS [Surname],
(SELECT Percentage from PercentageTb where StudentID = S.studentID and Date = #PreviousDate) AS [PreviousPercentage]
(SELECT Percentage from PercentageTb where StudentID = S.studentID and Date = #CurrentDate) AS [CurrentPercentage]
from studentTb AS S
One way to accomplish what you want that should work is to use the max() aggregate function to flatten the results like this:
select
s.StudentID,
s.Forename,
s.Surname,
max(case when p.date = CONVERT(VARCHAR,DATEADD(DAY, DATEDIFF(DAY, 1, GETDATE()), 0),103) then p.date end) prev_date,
max(case when p.date = CONVERT(VARCHAR,DATEADD(DAY, DATEDIFF(DAY, 1, GETDATE()), 0),103) then p.percentage end) prev_perc,
max(case when p.date = CONVERT(VARCHAR,DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0),103) then p.date end) curr_date,
max(case when p.date = CONVERT(VARCHAR,DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0),103) then p.percentage end) curr_perc
from studentTb s
inner join percentageTb p on s.StudentID = p.StudentID
group by s.StudentID, s.Forename, s.Surname
Sample SQL Fiddle
Another option would be to join the percentageTb table twice (once for the current date and once for the previous day), see this example.
I have a line chart/graph that I need to include for all service outages we went through in the year. Currently, my SQL can pull data that includes any tickets creating in a ticketing system for these services.
However, if no ticket was created for a service, the service will not show in the rows or the service will show but not have a 100% Uptime for the months where no tickets were created for it.
Example of what I am looking for:
MONTH Service1 Service2 Service3
1 100% 99.7% 100%
2 99.8% 100% 96.5%
3 100% 99.8% 100%
But what it looks like is this:
MONTH Service1 Service2 Service3
1 99.7%
2 99.8% 96.5%
3 99.8%
The services get pulled by using a WHERE [Resource]='Affected Service' so they are dynamically brought into the table, but no data is pulled for the service if no ticket was created in that month.
Current SQL Coding:
WITH rslt (ResourceID, YearNumber, MonthNumber, AvailableMinutes, DowntimeMinutes) AS (
SELECT
ore.ResourceID,
DATEPART(yyyy, ipr.OpenDate_MST) YearNumber,
DATEPART(mm, ipr.OpenDate_MST) MonthNumber,
MAX(CASE
WHEN DATEADD(MONTH, DATEDIFF(MONTH, -1, ipr.OpenDate_MST), -1) = DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()), -1)
THEN (DATEPART(DD, GETDATE()) * 1440.0)
ELSE (DATEPART(DD, DATEADD(MONTH, DATEDIFF(MONTH, -1, ipr.OpenDate_MST), -1)) * 1440.0)
END) AvailableMinutes,
ISNULL(SUM(DATEDIFF(mi, ipr.OutageStartTime, ipr.OutageEndTime)), 0) DowntimeMinutes
FROM
vIncidentProblemRequest ipr
INNER JOIN vOwnedResource ore ON ore.ResourceID = ipr.AffectedServiceID
WHERE
CONVERT(DATETIME, CONVERT(CHAR(10), ipr.OpenDate_MST, 101)) >= '1/1/2013 12:00:00'
AND CONVERT(DATETIME, CONVERT(CHAR(10), ipr.OpenDate_MST, 101)) <= '12/31/2013 11:59:59'
GROUP BY
ore.ResourceID,
DATEPART(yyyy, ipr.OpenDate_MST),
DATEPART(mm, ipr.OpenDate_MST),
),
rslt2 (ResourceID, Application, ResourceClass, YearNumber, MonthNumber, AvailableMinutes, DowntimeMinutes, UptimePercent) AS (
SELECT
ore.ResourceID,
ore.ResourceName Application,
ore.ResourceClass,
rslt.YearNumber,
rslt.MonthNumber,
rslt.AvailableMinutes,
ISNULL(rslt.DowntimeMinutes, 0) DowntimeMinutes,
CASE
WHEN rslt.DowntimeMinutes IS NULL
THEN 1.0
ELSE ((rslt.AvailableMinutes - rslt.DowntimeMinutes)/rslt.AvailableMinutes)
END UptimePercent
FROM
vOwnedResource ore
LEFT OUTER JOIN rslt ON rslt.ResourceID = ore.ResourceID
WHERE
ore.ResourceClass = 'Enterprise Service')
select
MIN(DATEPART(yyyy, d.Date)) Year,
MIN(DATEPART(mm, d.Date)) MonthNum,
SUBSTRING(MIN(DATENAME(mm, d.Date)), 1, 3) Month,
r.Application,
r.ResourceClass,
CASE
WHEN r.UptimePercent IS NULL
THEN 1.0
ELSE r.UptimePercent
END UptimePercent
FROM
DimDate d
INNER JOIN rslt2 r ON r.YearNumber = datepart(yyyy, d.Date) AND r.MonthNumber = datepart(mm, d.Date)
WHERE
d.Date >= '1/1/2013 12:00:00'
AND d.Date <= '12/31/2013 11:59:59'
GROUP BY
datepart(yyyy, d.Date),
datepart(mm, d.Date),
DATENAME(mm, d.Date),
r.Application,
r.ResourceClass,
r.UptimePercent
ORDER BY
4,1,2
How about this-
Create a temp table having all service values as 100% for each month.
After that, update the temp table with the real values based on your filter condition.
It would really help if you showed the query. However, somewhere along the way, you can solve your problem using coalesce(). Assuming the values are really numbers between 0 and 100:
select month, coalesce(service1, 100) as service1,
coalesce(service2, 100) as service2, coalesce(service3, 100) as service3
The following answer describes the 'EXISTS' command. I think it will help you greatly.
Using CASE to Return a String If No Results From SELECT Statement
Tickets last 24 hours and can be either 'Child', 'Adult' or 'Teen'. Essentially, a ticket can be 'ConnectedTo' a number of movies. Child tickets for example will be connected to movies with a age rating of PG or below, while Adult tickets will be connected to every single movie.
The below returns info on all the tickets purchased for movies from the previous month:
SELECT *
FROM
[Test_DB].[dbo].[Tickets]
INNER JOIN
[Test_DB].[dbo].[Movies]
ON
[Test_DB].[dbo].[Tickets].[ConnectedTo] = [Test_DB].[dbo].[Movies].[MovieID]
WHERE
[Test_DB].[dbo].[Tickets].[DateEntered] >= DATEADD(month, DATEDIFF(month, 0, GETDATE())-1, 0) AND [Test_DB].[dbo].[Tickets].[DateEntered] <= DATEADD(month, DATEDIFF(month, 0, GETDATE()), -1)
Each ticket can have any number of notes attached to it. For example, if a special discount was given to a ticket holder, a note will be created about that. Similiarly, if a ticket is exchanged for another or refunded, a note will be created.
The below will return all the notes for a given Ticket based on the TicketID:
SELECT *
FROM
[Test_DB].[dbo].[Tickets]
JOIN [Test_DB].[dbo].[Notes]
ON [Test_DB].[dbo].[Tickets].[TicketID] = [Test_DB].[dbo].[Notes].[ConnectedTo]
WHERE TicketId = 64903
My question is, is there a way to combine the two? For example, the first bit of SQL could return 5 tickets, each with a different TicketID. Based on that, I want to make use of my second SQL to return all of the notes for those 5 tickets.
I was thinking of using UNION to combine the two selects... Though my brain keeps telling me that I need to JOIN the two pieces of SQL on the TicketId's, however every time I try to it comes out wrong. Any help would greatly be appreciated! Thanks.
This should work
SELECT [Test_DB].[dbo].[Tickets].*, [Test_DB].[dbo].[Notes].*
FROM [Test_DB].[dbo].[Tickets]
INNER JOIN [Test_DB].[dbo].[Movies]
ON
[Test_DB].[dbo].[Tickets].[ConnectedTo] = [Test_DB].[dbo].[Movies].[MovieID]
INNER JOIN [Test_DB].[dbo].[Notes]
ON [Test_DB].[dbo].[Tickets].[TicketID] = [Test_DB].[dbo].[Notes].[ConnectedTo]
WHERE [Test_DB].[dbo].[Tickets].[DateEntered] >= DATEADD(month, DATEDIFF(month, 0, GETDATE())-1, 0)
AND [Test_DB].[dbo].[Tickets].[DateEntered] <= DATEADD(month, DATEDIFF(month, 0, GETDATE()), -1)
I imagine that "notes" could be optional. If so, then you will want a left join rather than an inner join. Also, the use of aliases and eliminating the unnecessary square brackets would make your query easier to read:
SELECT *
FROM Test_DB.dbo.Tickets t INNER JOIN
Test_DB.dbo.Movies m
ON t.ConnectedTo = m.MovieID LEFT JOIN
Test_DB.dbo.Notes n
ON t.TicketID = n.ConnectedTo
WHERE t.DateEntered >= DATEADD(month, DATEDIFF(month, 0, GETDATE()) -1, 0) AND
t.DateEntered <= DATEADD(month, DATEDIFF(month, 0, GETDATE()), -1);
Note (no pun intended): if a ticket has multiple notes, then you will get multiple rows in the output.
I am trying to get the sum of "Qty" in a Table A called "Quote_Items" based on a "Required_by_Date" from Table B called Quotes. Both tables have a common "Quote_No" The required date is one month ago.
I have used the following but it produces a NULL, but I cannot see why
select sum(Qty)
from quotes.Quote_Items_Quantities
left outer join quotes.Quotes on (Quote_Required_by_Date = Qty)
WHERE (DatePart(yy, Quote_Required_by_Date) = DatePart(yy, DateAdd(m,1,getdate()))) and
datepart(m,Quote_Required_by_Date) = datepart(m,dateadd(m,1,getdate()))
Any suggestions what I am doing wrong here.
Try this:
SELECT SUM(i.Qty)
FROM Quote_Items i
JOIN Quotes q on i.Quote_No = q.Quote_No
AND CONVERT(varchar, q.Required_by_Date, 112) = CONVERT(varchar, DATEADD(month, -1, getdate()), 112)
or this (equivalent without using JOIN)
SELECT SUM(i.Qty)
FROM Quote_Items i
WHERE EXISTS(SELECT 1 FROM Quotes WHERE Quote_No = i.Quote_No AND CONVERT(varchar, Required_by_Date, 112) = CONVERT(varchar, DATEADD(month, -1, getdate()), 112))
Your query is producing NULL because of the join condition. You have
on Quote_Required_by_Date = Qty
However, the date is not going to match the quantity. Instead, you need to match on the Quote_No, according to your question:
select sum(Qty)
from quotes.Quote_Items_Quantities qiq left outer join
quotes.Quotes q
on q.Quote_Required_by_Date = qiq.Qty
WHERE (DatePart(yy, Quote_Required_by_Date) = DatePart(yy, DateAdd(m,1,getdate()))) and
datepart(m,Quote_Required_by_Date) = datepart(m,dateadd(m,1,getdate()));
You can also simplify your query by using the month() and year() functions:
select sum(Qty)
from quotes.Quote_Items_Quantities qiq left outer join
quotes.Quotes q
on q.Quote_Required_by_Date = qiq.Qty
WHERE year(Quote_Required_by_Date) = year(DateAdd(m, 1, getdate()) and
month(Quote_Required_by_Date) = month(dateadd(m,1,getdate());
Finally, you mind find it useful to use group by and get the results for many months:
select year(Quote_Required_by_Date), month(Quote_Required_by_Date), sum(Qty)
from quotes.Quote_Items_Quantities qiq left outer join
quotes.Quotes q
on q.Quote_Required_by_Date = qiq.Qty
group by year(Quote_Required_by_Date), month(Quote_Required_by_Date)
order by 1 desc, 2 desc;