I want to condense the following three queries into one query and out put the totals into 3 columns. Oh and how do I make it so I don't have to declare the date. I want it to "know" the current date, month, and year.
DECLARE #myDate as datetime
SET #myDate = '2015-01-1'
select SUM(Amount) as 'Day Total'
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(day,1,#myDate)
select SUM(Amount) as 'Month Total'
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(MONTH,1,#myDate)
select SUM(Amount) as 'Day Total'
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(year,1,#myDate)
What is the best way to do this?
Thanks!
Thanks for all the super fast responses! This is now solved.
If I'm understanding the problem correctly, then something like this ought to work:
declare #today date = convert(date, getdate());
select
[Day Total] = sum(case when [AccountingDate] >= #today and [AccountingDate] < dateadd(day, 1, #today) then [Amount] else 0 end),
[Month Total] = sum(case when [AccountingDate] >= #today and [AccountingDate] < dateadd(month, 1, #today) then [Amount] else 0 end),
[Year Total] = sum(case when [AccountingDate] >= #today and [AccountingDate] < dateadd(year, 1, #today) then [Amount] else 0 end)
from
[Accounting].[dbo].[HandPay];
Note that [Month Total] and [Year Total] don't give the sums of the entries that occur within the current month/year, but rather the sum of the entries that occur within a month/a year of today's date. I'm not sure if that's what you want, but it seems consistent with the original queries.
UPDATE: As suggested by D Stanley below, you can simplify this a bit since you know that the date ranges that compose the [Day Total] and [Month Total] sums are enclosed entirely within the date range that composes the [Year Total] sum. Here's what this might look like:
declare #today date = convert(date, getdate());
select
[Day Total] = sum(case when [AccountingDate] < dateadd(day, 1, #today) then [Amount] else 0 end),
[Month Total] = sum(case when [AccountingDate] < dateadd(month, 1, #today) then [Amount] else 0 end),
[Year Total] = sum([Amount])
from
[Accounting].[dbo].[HandPay]
where
[AccountingDate] >= #today and [AccountingDate] < dateadd(year, 1, #today);
Make them all part of a 'super' select:
DECLARE #myDate as datetime
SET #myDate = '2015-01-1'
SELECT
(select SUM(Amount)
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(day,1,#myDate) ) as 'Day Total',
(select SUM(Amount)
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(MONTH,1,#myDate) ) as 'Month Total',
(select SUM(Amount)
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(year,1,#myDate) ) as 'Day Total'
One way is to write each as a sub-query with a surrounding select. I have often found this useful as it allows me to piece together the query one bit at a time. This will give you null in the column values when there is no records - which may not be what you want. Refer to #JoeFarrell's question as he has provided an example of using case to turn null into 0.
(Please excuse the strange layout, felt it was worth accentuating the ,)
DECLARE #myDate as datetime
SET #myDate = '2015-01-1'
select
(select SUM(sale_total)
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(day,1,#myDate)) as 'Day Total'
,
(select SUM(sale_total)
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(MONTH,1,#myDate)) as 'Month Total'
,
(select SUM(sale_total)
from [Accounting].[dbo].[HandPay]
where AccountingDate>=#myDate and AccountingDate<dateadd(year,1,#myDate)) as 'Day Total'
Related
I am stuck with a SQL query.
I am trying to calculate two different things in a same query:
Number of business days in a month (this will exclude weekends).
How many days working days have been passed in a month.
Let's say for November (as on 11/9/2018)
no.of business days no. of business days passed
22 7
I tried like this :
WITH cteAllDates AS
(
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '10/01/2018'
SET #EndDate = '10/31/2018'
SELECT
(DATEDIFF(dd, #StartDate, #EndDate) + 1)
- (DATEDIFF(wk, #StartDate, #EndDate) * 2)
- (CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(dw, #EndDate) = 'Saturday' THEN 1 ELSE 0 END) AS x
) AS y
SELECT x
FROM cteAllDates
I would like to create a virtual table so that I can use these fields in my complete query. And if its possible I can do this with GETDATE() and not to declare dates every time.
Since you want to do it in a CTE, and based on the earlier answer you found on SO, here is a version that does it all for the current month without needing to define start and end dates:
EDIT: To create a holiday table
First, create a holiday table. Don't do this every time, make it a persistent table, and keep it filled up with all holidays you need - easter, xmas etc.
create table holidays(holiday date)
insert holidays values ('2018-09-23'),('2018-09-24')
Now the query, including the check for number of holidays between the dates
;with dates as(
select dateadd(d,-day(getdate())+1,convert(date,getdate())) as startofmonth,
dateadd(d,-1,dateadd(m,1,dateadd(d,-day(getdate())+1,convert(date,getdate())))) as endofmonth,
convert(date,getdate()) as today
)
,holidaycount as (
select count(*) as holidaysinmonth,
sum(case when holiday<=today then 1 else 0 end) as holidaystodate
from dates
join holidays on holiday between startofmonth and endofmonth
)
,daycounts as(
select dates.*,
(DATEDIFF(dd, startofmonth, endofmonth) + 1)
-(DATEDIFF(wk, startofmonth, endofmonth) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, endofmonth) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaysinmonth,0) as wkdaysinmonth,
(DATEDIFF(dd, startofmonth, today) + 1)
-(DATEDIFF(wk, startofmonth, today) * 2)
-(CASE WHEN DATENAME(dw, startofmonth) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, today) = 'Saturday' THEN 1 ELSE 0 END)
-isnull(holidaystodate,0) as wkdaystodate
from dates
cross join holidaycount
)
select * from daycounts
EDIT: If you cant create a temp table, add this as an additional CTE before the holidaycount one like so:
,holidays as (
select holiday from (values ('2018-11-23'),('2018-11-24')) t(holiday)
)
,holidaycount as (
You can try to use cte recursive make a calendar table, then use condition aggregate function to get your result.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1));
SET #EndDate = DATEADD(DAY, 1, EOMONTH(GETDATE()));
;WITH CTE AS (
select #StartDate startdt,#EndDate enddt
UNION ALL
SELECT DATEADD (day ,1 , startdt) , #EndDate
FROM CTE
WHERE DATEADD (day,1,startdt) <= #EndDate
)
select SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') THEN 1 END) 'no.of business days',
SUM(CASE WHEN DATENAME(dw, startdt) NOT IN ('Sunday','Saturday') AND GETDATE() >= startdt THEN 1 END) 'no. of business days passed'
FROM CTE
sqlfiddle
Result
no.of business days no. of business days passed
22 7
In Dubai, the standard weekend runs from Friday - Saturday rather than the traditional Saturday / Sunday.
I am trying to calculate the amount of working days between two given dates, and this is the code I have;
DATEDIFF(dd, DATEADD(hour, DATEDIFF(hh, getdate(), getutcdate()), #StartDate),
DATEADD(hour, DATEDIFF(hh, getdate(), getutcdate()), #EndDate)+1)
-
(
(DATEDIFF(wk, #StartDate, #EndDate) * 2
+(CASE WHEN DATENAME(dw, #StartDate) = 'Saturday' then 1 else 0 end)
+(CASE WHEN DATENAME(dw, #EndDate) = 'Friday' then 1 else 0 end)
))
)
However it is calculating the wrong amount of days. For example;
When the start date is 02-03-2016 and the end date is 02-06-2016 the returns as 4, but it should be 2.
When the start date is 02-03-2016 and the end date is 02-07-2016 the result is 3 which is correct.
The code below calculates the working days from your examples correctly. You can wrap it in a scalar function if you want.
declare #from date, #to date;
set #from = '2016-02-03';
set #to = '2016-02-06';
with dates(date)
as
(
select #from
union all
select dateadd(dd, 1, [date])
from dates
where [date] < #to
)
select count(*) [working days]
from (
select date, case when datename(dw, [date]) in ('Friday', 'Saturday') then 0 else 1 end as working
from dates) as dt
where dt.working = 1
I have a query where i need to get values in 4 columns but only if the date is greater than today from a 5th column. I have tried the following but it doesn't seem to be working.
Select
(case when clientplans.END_DATE < convert(date,getdate(,101) then '') else insplans.Desc_upper as PLAN NAME,
(case when clientplans.END_DATE < convert(date,getdate(,112) then '') else insplans.ID_NO,
(case when clientplans.END_DATE < convert(date,getdate(,112) then '') else insplans.cert_NO,
I have converted the date on the end date as follows:
convert (varchar,clientplans.END_DATE,112) as POLICY_EXP_DATE,
does it matter that I do the conversion of the end date later in the query? the clientplans.end_date has to be inserted into the results in a certain order which happens to be after the description, id and cert number. Thanks for any help.
Perhaps something like this does what you want:
Select (case when cp.END_DATE > cast(getdate() as date) then insplans.Desc_upper end) as PLAN_NAME,
(case when cp.END_DATE > cast(getdate() as date) then insplans.ID_NO end) as ID_NO,
(case when cp.END_DATE > cast(getdate() as date) then insplans.cert_NO END) as cert_NO
from clientplans cp . . .
Note the following:
This table uses table aliases (cp for clientplans), so the query is easier to write and to read.
It uses cast() to a date to just get the date.
Non-matching rows are given a NULL value instead of ''. That usually makes more sense.
EDIT:
Of course, you can use '', if you like:
Select (case when cp.END_DATE > cast(getdate() as date) then insplans.Desc_upper else '' end) as PLAN_NAME,
(case when cp.END_DATE > cast(getdate() as date) then insplans.ID_NO else '' end) as ID_NO,
(case when cp.END_DATE > cast(getdate() as date) then insplans.cert_NO else '' end) as cert_NO,
(case when cp.END_DATE > cast(getdate() as date)
then convert(varchar(255), cp.StartDate, 121) else ''
end) as StartDate
from clientplans cp . . .
Use this to get the start of today: DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
For example:
SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
And for yours...
Select
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.Desc_upper as PLAN NAME,
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.ID_NO,
(case when clientplans.END_DATE > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) then '') else insplans.cert_NO,
i think proper casting is required So I Used Here CAST(Field as DATE) and
in Your Query getdate(,101) is wrong syntax
Select
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.Desc_upper as PLAN NAME,
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.ID_NO,
(case when CAST(clientplans.END_DATE as date) < CAST(getdate() as date) then '')
else insplans.cert_NO
You can use cursor on the 5th column
and check #cursor_date> is greater than today.
Only then will get the rest of the 4 columns.
I have the following query
-- DELETE Current month and Month - 1 records from MonthlyTbl
DELETE FROM dbo.tbl_SDW_MONTHLY_AS
WHERE [Month Number] > MONTH(GETDATE()) - 2
AND [Year] = YEAR(GETDATE())
The query does not appear to be deleting the records from December 2013, can you help me fix this?
You can do it this way.
declare #dt datetime
set #dt = getdate()
DELETE FROM dbo.tbl_SDW_MONTHLY_AS
WHERE
100 * [Year] + [Month Number] >=
(
100 * datepart(YEAR, dateadd(DAY, - datepart(DAY, #dt) - 1, #dt)) +
datepart(MONTH, dateadd(DAY, - datepart(DAY, #dt) - 1, #dt))
)
Don't use MONTH number and YEAR number.
Use the dates instead.
DELETE FROM dbo.tbl_SDW_MONTHLY_AS
WHERE [Date] > DATEADD(MONTH,-2,GETDATE())
I'm trying to do a select for a whole series of different criteria. I'm essentially going to take today's date, and use it against our invoice table to figure out how we're shaping up this year, compared to the last several years.
In the end, I essentially want to have columns for Year, Year To Date Sales, Quarter To Date Sales, and Month to Date Sales. I've started to create a loop for this, but the problem I'm running into is that it's executing several select's, and not returning me one dataset, but rather 3.
Is the best way to tackle this to build a virtual table, fill it with my results, and then select them out of that?
Here's what I have so far:
DECLARE #startDate date, #endDate date;
DECLARE #counter int = 0;
WHILE #counter < 3 BEGIN
--set start and end dates
SELECT #startDate = CONVERT(date, (CONVERT(nvarchar, YEAR(DATEADD(YEAR,-1 * #counter, CONVERT(date, GETDATE())))) + '-02-01'));
SELECT #endDate = DATEADD(YEAR,-1 * #counter, CONVERT (date, GETDATE()));
--select results
SELECT YEAR(ib.DateDelivered) [Year], SUM(ib.TotalAmountLessFreight) [YTD Sale]
FROM InvoiceBase ib
WHERE ib.DateDelivered < #endDate
AND ib.DateDelivered > #startDate
GROUP BY YEAR(ib.DateDelivered);
--increment
SET #counter = #counter + 1;
END
The best way to do it would be in a single query. Try:
;with cte as
(select i.*,
dateadd(year, datediff(year,DateDelivered,getdate()), getdate()) [YearEnd]
FROM InvoiceBase i)
select YEAR(DateDelivered) [Year],
SUM(case when DateDelivered <= YearEnd
then TotalAmountLessFreight end) [YTD Sales],
SUM(case when DateDelivered <= YearEnd and
month(DateDelivered) >= floor((month(YearEnd)+2)/3)*3-2
then TotalAmountLessFreight end) [QTD Sales],
SUM(case when DateDelivered <= YearEnd and
datediff(month, DateDelivered, YearEnd) = 0
then TotalAmountLessFreight end) [MTD Sales]
FROM cte
GROUP BY YEAR(DateDelivered)