Using dynamic values in AS portion of an SQL Server query - sql-server

I'm making a query (and a long, nasty bugger it is) to return dynamically updating values from an SAP system. I've got everything figured out but how to make the column headers what I want. They need to be the name of the previous 11 months and this month (or the 3 letter abbreviation).
Currently, I just have
SELECT ... AS [OCT]
for this month, but in two days it's going to be different, and I'd like to have the query auto-update the column headers each time it is run.
I figured out that I can use the variables I have declared to use in my functions to get the name three letter name of the month:
DECLARE #last_month DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 0, 0)
SELECT CONVERT(char(3), #last_month);
to return the selected month. How do I get this to be usable in the "AS" field?
Here is what I currently have:
DECLARE #last_two_months DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0)
DECLARE #last_month DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 0, 0)
SELECT (a whole mess of things that somehow work) AS [SEPT],
Table.CurrentTotal AS [OCT];
I'd like to replace [OCT] with something that will return OCT as the column header for the next two days and then return NOV for the next month, and similarly changing [SEPT] to something that will return SEP for the next two days, then return OCT for the next month.

Use Dynamic Query
DECLARE #last_month DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 0, 0),
#alias char(3),
#sql nvarchar(max)=''
SELECT #alias= CONVERT(char(3), #last_month);
set #sql = 'SELECT ... as ['+#alias+']..'
--Print #sql
exec sp_executesql #sql
Use the Print Statement to debug the dynamic query

Related

TSQL: How to change date if date falls between current year dates?

I need to change a passed variable date if the date falls under the current year Nov 1st to Dec 31st
How to do this in TSQL?
Example:
Example #1
#ip_batch_date = '2020-12-01T00:00:00'
check #ip_batch_date >=' '2020-11-01T00:00:00' AND #ip_batch_date<='2020-12-31T00:00:00'
Then #ip_batch_date = '2021-01-01T00:00:00'
Example #2
#ip_batch_date = '2021-11-15T00:00:00'
check #ip_batch_date >='2021-11-01T00:00:00' AND #ip_batch_date<='2021-12-31T00:00:00'
Then #ip_batch_date = '2022-01-01T00:00:00'
Assuming you already have a passed in date variable called #ip_batch_date, off the top of my head I would use something like
IF (YEAR(#ip_batch_date) = YEAR(GetDate()) AND MONTH(#ip_batch_date) BETWEEN 11 AND 12)
SET #ip_batch_date = DATEFROMPARTS(YEAR(GetDate())+1,1,1);
If instead of a passed in date, you were writing a query that was going to process lots of rows with a date column in them that you wanted to subject this logic to, it would be best not to have ip_date_column converted by a function, but rather to leave the date column bare and compare it to two constructed dates, like this:
CASE WHEN my_date_column BETWEEN DATEFROMPARTS(YEAR(GetDate()),11,1)
DATEFROMPARTS(YEAR(GetDate()),12,31)
THEN DATEFROMPARTS(YEAR(GetDate())+1,1,1);
ELSE my_date_column
END
Finally, if my_date_column was a datetime or datetime2 column instead of just a date, make sure you you datetimefromparts or datetime2fromparts instead, and add the time in as well to avoid last day boundary issues
If I understood your question correctly:
DECLARE #Date DATETIME
SET #Date = '2020-12-01T00:00:00'
SET #Date = CASE WHEN RIGHT(CONVERT(VARCHAR(8), #Date, 112), 4) >= 1101 THEN DATEADD(yy, DATEDIFF(yy, 0, #Date) + 1, 0) ELSE #Date END
SELECT #Date
-- Output : 2021-01-01 00:00:00.000
SET #Date = '2021-12-01T00:00:00'
SET #Date = CASE WHEN RIGHT(CONVERT(VARCHAR(8), #Date, 112), 4) >= 1101 THEN DATEADD(yy, DATEDIFF(yy, 0, #Date) + 1, 0) ELSE #Date END
SELECT #Date
-- Output : 2022-01-01 00:00:00.000
DECLARE #IP_BATCH_DATE DATETIME= '2020-12-01T00:00:00'
IF #ip_batch_date >= '2020-11-01T00:00:00' AND #ip_batch_date<='2020-12-31T00:00:00'
BEGIN
SELECT datefromparts(YEAR(GETDATE()), 1, 1)
END
ELSE
BEGIN
SELECT #ip_batch_date
END

Declaring a date as being the last month day of another date

I'm trying to write a financial report on our SAP B1 system using SQL Server Studio.
In my report I want the information to be calculated on a month to month basis. In my report I have #start date as #Startofcurrentfinancialyear, and my end as DD+30 (because there are 31 days in the month) However I am wanting to have mm+1 and dd-1 to bring me to the last day in the month.
I plan on changing the report for each month to give me the following.
MM+1 (for month 2) and MM+2 - DD 1 to give me the date range for month 2 etc.
Currently, I can make this go based on the following: MM+0, DD+30, then going ahead doing DD+60 etc and calculating for each month how many days they are, but this will give me problems with leap years.
DECLARE #Start DATETIME = DATEADD(MM,-0,#StartOfCurrentFinancialYear)
DECLARE #End DATETIME = DATEADD(DD,+30,#StartOfCurrentFinancialYear)
I expect to be able to define a month for each section and give the last day of the defined month based on the parameters given above.
If you want the end of month, then in all supported versions of SQL Server, you can do:
DECLARE #Start DATETIME = DATEADD(MONTH, -0, #StartOfCurrentFinancialYear);
DECLARE #End DATETIME = EOMONTH(#StartOfCurrentFinancialYear);
If you are using an unsupported version, you can do date arithmetic:
DECLARE #End DATETIME = DATEADD(day, -1,
DATEADD(month, 1,
DATEADD(day,
1 - DAY(#StartOfCurrentFinancialYear),
#StartOfCurrentFinancialYear
),
)
);
This does the following calculation:
Innermost subquery dateadd() moves to the first day of the month.
Middle subquery adds one month.
Outer query subtracts one day.
If you want start of the month and end of the month you can get it by using DateAdd function like :
DECLARE #Start DATETIME = DATEADD(DAY, (DAY(GETDATE()) * -1) + 1, GETDATE())
DECLARE #End DATETIME = DATEADD(MONTH,1,DATEADD(DAY, DAY(GETDATE()) * -1, GETDATE()))
SELECT #Start, #End
you can replace GETDATE() with your date variable so after your replacement the code should be something like this :
DECLARE #StartOfCurrentFinancialYear AS DATE = '31/aug/2019'
DECLARE #Start DATETIME = DATEADD(DAY, (DAY(#StartOfCurrentFinancialYear) * -1) + 1, #StartOfCurrentFinancialYear)
DECLARE #End DATETIME = DATEADD(MONTH,1,DATEADD(DAY, DAY(#StartOfCurrentFinancialYear) * -1, #StartOfCurrentFinancialYear))
SELECT #Start, #End

Adding fixed time onto datetime gives unexpected results

I have a query that takes two datetime variables (Start date and end date) and appends two differing fixed times to allow for a business trading time offset.
An example of a test query using this logic is:
DECLARE #startdate datetime;
DECLARE #enddate datetime;
SET #startdate = convert(datetime,'2017-01-01')
SET #enddate = convert(datetime,'2017-01-02')
SELECT *
FROM ig_Business..Check_Item_Detail CID (NOLOCK)
JOIN ig_business..Check_Sales_Detail CSD (NOLOCK) ON CSD.transaction_data_id = CID.transaction_data_id
WHERE csd.tendered_date_time BETWEEN DATEADD(m, DATEDIFF(m, 0, convert(date, #STARTDATE)), 0) + '06:00:00'
AND DATEADD(m, DATEDIFF(m, 0, convert(date, #ENDDATE)), 0) + '05:59:59'
However, the result set for this query is empty, and I am unsure why, because when I run
select DATEADD(m, DATEDIFF(m, 0, convert(date, #STARTDATE)), 0) + '06:00:00'
i get back a seemingly valid datetime : 2017-01-01 06:00:00.000
An example of what is returned when I remove the time restriction:
i get back a seemingly valid datetime : 2017-01-01 06:00:00.000
You're not.
You're getting back a date that has been automatically cast to a string, and have glued another string on the end, giving you a string that looks like a datetime.
If you want to add something to the date, use another dateadd(). This will give you a BETWEEN comparison with actual datetimes.
Right now you are doing a "between" with a datetime and a string.
I'm surprised it doesn't throw an error.
If 2012+, you can use format() to append a time to a date/datetime value
Example
Declare #startdate date = '2017-01-01'
Select format(#startdate,'yyyy-MM-dd 06:00:00')
Returns
2017-01-01 06:00:00
This format() can be included in your where
...
Where SomeDateTime between format(#startdate,'yyyy-MM-dd 06:00:00')
and format(#enddate,'yyyy-MM-dd 17:00:00')

What is the equivalent of Oracle's LAST_DAY() function in SQL Server 2008?

I have used the LAST_DAY() function in Oracle like this:
Last_Day( to_date( '$pay_first_day' , 'YYYY-mm-dd') )
What do i have to do in SQL server 2008 R2 database to achieve the same result?
Try this one -
DECLARE #Date DATETIME
SELECT #Date = GETDATE()
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date) + 1, 0) - 1
SQL Server 2012 introduces a new date function called EOMONTH which returns the last day of the month that contains the specified date, with an optional offset.
EOMONTH ( <start_date> [, <month_to_add> ] )
For instance
select EOMONTH('01/07/2018')
Would return
2018-01-31
-- Wrapping the answer in a function for seamless transition.
CREATE FUNCTION [dbo].[LAST_DAY]
(
#inDate DATETIME
)
RETURNS DATETIME
AS
BEGIN
RETURN DATEADD(MONTH, DATEDIFF(MONTH, 0, #inDate) + 1, 0) - 1
END
-- TO TEST: SELECT dbo.LAST_DAY(getDate()) as LastDayOfThisMonth
-- note: Please mark as answer if this helps you better then the one before.
Could you please try this, it should work as expected :
SELECT DATEADD (DAY, -1, DATEADD (MONTH, DATEDIFF (MONTH, 0, '$pay_first_day') + 1, 0))
It would return the last day equivalent of the given date in this format : '2013-02-28 00:00:00.000' if your $pay_first_day is in February, and it would return '2013-04-30 00:00:00.000' if your $pay_first_day is in April.
Here are two UDF for begin and end of month.
CREATE FUNCTION dbo.End_of_month (#Date datetime)
RETURNS datetime AS
BEGIN
DECLARE #ret datetime
SET #Ret=DATEADD(DAY,-DAY(#Date)+1,#Date);
SET #Ret=DATEADD(Month,1,#Ret);
SET #Ret=DATEADD(Day,-1,#Ret);
RETURN(#Ret)
END
CREATE FUNCTION dbo.Begin_of_month (#Date datetime)
RETURNS datetime AS
BEGIN
DECLARE #ret datetime
SET #Ret=DATEADD(DAY,-DAY(#Date)+1,#Date);
RETURN(#Ret)
END

Create "BETWEEN/AND"-capable DATETIMEs from given DATETIME

I want to create two DATETIME variables I can use to check with BETWEEN AND when given just one DATETIME in a stored procedure on SQL Server 2008.
So, when I get 2012/12/31 15:32:12 as input, I want to generate two new variables out of that, being #from = 2012/12/31 00:00:00 and #to = 2012/12/31 23:59:59.
These two variables are used to check if the records lie between them - that is, are on the same day as the input date.
I fooled around using CAST and CONVERT, but I don't really konw how to manipulate the dates in the way I want.
Should I do this another way? Or are there functions I'm not aware of?
Now it is version independedt
declare #from datetime, #to datetime
SET #from = convert(varchar, convert(datetime, '2012/12/31 15:32:12', 111), 112)
SET #to = DATEADD(day, 1, #from)
select * from yourtable where test date >= #from AND date < #to
You can;
declare #input datetime = '2012/12/31 15:32:12'
declare #from datetime = dateadd(day, 0, datediff(day, 0, #input))
declare #to datetime = dateadd(second, -1, dateadd(day, 1, #from))
>>>
2012-12-31 00:00:00.000 2012-12-31 23:59:59.000
Be careful of accuracy on your #to. 23:59:59.001 is a valid date but won't show up in your range if you subtract an entire second.
It is more common to set your #from and then use < #from + 1 instead of BETWEEN. (The plus adds whole days in SQL).
First convert your input date to a varchar using the appropriate date format(111 in this case), For the to date, append the midnight hour
Then cast your varchar back to datetime.
Example :
SELECT #from = CAST(CONVERT(VARCHAR(10), GETDATE(), 111) AS DATETIME)
,#to = CAST(CONVERT(VARCHAR(10), GETDATE(), 111)+' 23:59:59:997' AS DATETIME)
Here is a useful chart of datetime formats with brief explanations.
http://www.sql-server-helper.com/tips/date-formats.aspx

Resources