Creating a computed column in MSSQL - sql-server

I'm having trouble creating a computed column in MSSQL. I'm using 2012, but ideally this would work with anything 2005 and on.
I need to set a column to be equal to 1% of another column for each month since the start date.
Here's what I have so far. I've tried entering this into the formula property of the computed column, but MSSQL says "There is an error with your forumla".
CASE
WHEN DATEDIFF(d, LienStartDate, GETDATE()) - (DATEDIFF(yyyy, LienStartDate, GETDATE()) * 365) >= 0
THEN Amount * (DATEDIFF(m, LienSTartDate, GETDATE()) * 0.01)
WHEN DATEDIFF(d, LienStartDate, GETDATE()) - (DATEDIFF(yyyy, LienStartDate, GETDATE()) * 365) < 0
THEN Amount * ((DATEDIFF(m, LienStartDate, GETDATE()) - 1) * 0.01) END
When I run it against the following data as a select I get back the correct results. (12, 11, 12)
LienStartDate | Amount
2014/01/20 100
2014/01/25 100
2014/01/23 100

Related

Get result of last six months using DATEDIFF

I'm trying to create a query in SQL that retrieves rows based on their date.
I want to get the result of the last 6 months using DATEDIFF() function (and not another function ) but my query still returns rows that are greater than GETUTCDATE().
The query that I use is:
SELECT * FROM CARS
WHERE DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) < 180
Why am i still getting results that are greater than GETUTCDATE() ?
First, you may think you want to use datediff, but the fact that you are using it (or any other function, for that matter) on a column makes it impossible for SQL Server to use any indexes defined with this column - and that might be a real performance penalty for that.
Second, the reason you get records for future dates is that if the first date is later than the second date, the DateDiff function will return a negative number. All negative numbers I know of are smaller than 180.
A better query would be this:
SELECT *
FROM CARS
WHERE c.ExpiredWarranty <= GETUTCDATE()
-- If you want 6 months, don't bother with days...
AND c.ExpiredWarranty > DATEADD(MONTH, -6, GETUTCDATE())
DATEDIFF returns a positive number whenever the third argument is greater than the second. In your case, you want records whose warranties have expired within 6 months. On one extreme, this is 180 days, and the other extreme, this is 0 days. For warranties expiring in the future, your current call to DATEDIFF would return a negative number.
To fix this, just restrict the DATEDIFF output to between 0 and 180 days, and don't allow negative diffs:
SELECT *
FROM CARS
WHERE DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) BETWEEN 0 AND 180;
Because if ExpiredWarranty > GETUTCDATE() then DATEDIFF between them returns a negative number which is definitely less then 180.
Try:
SELECT *
FROM CARS
WHERE DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) < 180
AND DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) >= 0;
Or:
SELECT *
FROM CARS
WHERE DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) BETWEEN 0 AND 180;
Try this:
WHERE DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) >= 0 AND DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) < 180
Or:
WHERE DATEDIFF(d, c.ExpiredWarranty, GETUTCDATE()) BETWEEN 0 AND 180;

Convert number of hours to days and hours in SQL Server (NOT T-SQL)

I have a number of hours which I need to display in the format of days and hours.
This number is derived from a DATEDIFF instruction.
For numbers less than 24, I wish to display only hours - ie, 21 hours.
For larger numbers, I wish to display days and hours - ie, 3 days, 14 hours
I do not need to display any smaller unit than hours, and values should be rounded down to the preceding hour, so 1 hour and 59 minutes will be 1 hour.
I cannot use a stored procedure - this must run as a single select statement.
I am aware that I can calculate the value by using modulo, so assuming 71 hours:
select concat((71 - (71 % 24)) / 24, ' days, ', 71 % 24, ' hours')
This however is somewhat messy, and as the statement must be a single select, I will have to calculate the DATEDIFF 3 times as below.
SELECT CONCAT (
(DATEDIFF(HOUR, StartDate, EndDate) -
(DATEDIFF(HOUR, StartDate, EndDate) % 24)) / 24,
' days, ',
DATEDIFF(HOUR, StartDate, EndDate) % 24,
' hours')
FROM RecordsTable
Is it possible to either format a number of hours as days and hours directly using an inbuilt SQL command, or failing that, select (datediff(hour, StartDate, EndDate) into a variable which I can reuse in the single select?
EDIT - As suggested, the solution was to use a CTE as follows:
WITH totalhours (htotal) AS
(
SELECT
DATEDIFF(HOUR, StartDate, EndDate) AS htotal
FROM
RecordsTable
)
SELECT
CONCAT ((htotal - (htotal % 24)) / 24,
' days, ',
htotal % 24,
' hours')
FROM
RecordsTable;
Use a CTE to generate your total once, and reference that total in your select against the CTE. Or use a subquery to generate the total once and then select from the subquery to get the desired results.
The fundamental issue is you need to materialize the total once to be able to reference it; forcing the engine to materialize a value is generally done via a CTE or subquery.
You can do a lot with datetime objects and format strings or datepart. For example,
declare #n int = 105;
select format(dateadd(day, -1, dateadd(hour, #n, '1753-1-1')), 'd h');
-- 4 9
Taking the minimum datetime value (1753-01-01), adding the requisite number of hours, subtracting one day (because on the first day you want days = 0), and then formatting.
You could improve the formatting like this:
select format(dateadd(day, -1, dateadd(hour, #n, '1753-1-1')), 'd \da\y(\s), h \hour(\s)');
-- 4 day(s), 9 hour(s)
Of course this will only work up to 31 days, because then you'll be out of the month of January in 1753 and into February. If that's the case, revert to datepart. This is uglier, but will work for larger values
select
datepart(day, (dateadd(day, -1, dateadd(hour, #n, '1753-1-1')))),
datepart(hour, (dateadd(day, -1, dateadd(hour, #n, '1753-1-1'))));

sql not in between two weekdays and times

I have a query that monitors connection process. Now I'm stuck and need to set a proper monitoring for weekday and time range.
The process starts on Sunday 22:00, and goes down for 5 min. at 21:55 - every day to Friday. (not goes up from Friday 21:55 till 22:00 on Sunday)
Below is the SQL Query I tried:
IF CASE
WHEN (100 * DATEPART(hh, GETDATE()))
+ DATEPART(MINUTE, GETDATE())
BETWEEN 2155 AND 2200 -- Monitoring for whole day, wen connection is up
AND DATEPART(dw,GETDATE()), (100 * DATEPART(hh, GETDATE()))
+ DATEPART(MINUTE, GETDATE())
NOT BETWEEN (5, 2155) AND (0, 2200) --except trough Friday night to Sunday (weekdays and time).
THEN 1 ELSE 0 END = 0
You needed to add some SELECT statements into the parts of the case where you were getting the values to range between. Try this:
SELECT
CASE
WHEN(100 * DATEPART(hh, GETDATE())) + DATEPART(MINUTE, GETDATE()) -- = 731
BETWEEN 2155 AND 2200 -- Monitoring for whole day, wen connection is up
AND (
(
SELECT
DATEPART(dw, GETDATE())
) NOT BETWEEN(5) AND(0)
AND
(
SELECT
(100 * DATEPART(hh, GETDATE())) + DATEPART(MINUTE, GETDATE())
) NOT BETWEEN(2155) AND(2200)
)
THEN 1
ELSE 0
END;
The first calculation equals 731 so looking at the query I would except it to return '0' which it does

how to use sql to get number of seconds from a string formatted like "HH:MM:SS"

I have a C# program that recorded a TimeSpan value into a SQL Server table's varchar field. For example, the varchar field might have the value "00:12:05.7989790".
How could I use SQL code to get that total value in SECONDS? Since that varchar represents 12 minutes and 5 seconds, I would like a SQL statement that extracts it as "725".
I've tried some code like this:
select
Case when IsDate(the_value)=1 then datepart(HOUR, CONVERT(datetime, the_value))*360 else 0 end
+ Case when IsDate(the_value)=1 then datepart(MINUTE, CONVERT(datetime, the_value))*60 else 0 end
+ Case when IsDate(the_value)=1 then datepart(SECOND, CONVERT(datetime, the_value))*1 else 0 end
from mytable
but it complains "Conversion failed when converting date and/or time from character string."
Any suggestions would be greatly appreciated.
DATEDIFF function
https://msdn.microsoft.com/en-AU/library/ms189794.aspx
DATEDIFF(ss, '00:00:00.000', [your time column])
I would use datediff() and use explicit conversion to time:
select datediff(second, '00:00:00', convert(time, the_value))
If the units can exceed 23 hours, then you have a challenge, because the conversion will fail. In this case, string manipulation is an option:
select (left(the_value, 2) * 60 * 60 +
substring(the_value, 3, 2) * 60 +
substring(the_value, 5, 2)
) as seconds
This assumes that all strings are in the proper format. You can validate this with a case:
select (case when the_value like '[0-9]0-9]:[0-9[0-9]:[0-9][0-9]%'
then (left(the_value, 2) * 60 * 60 +
substring(the_value, 3, 2) * 60 +
substring(the_value, 5, 2)
)
end) as seconds

SQL Server: Return records within X days of a date

I need a WHERE condition in SQL Server where I can return the past 7 days of activity from a given date.
Pretend I have 2 columns of dates [dateA] and [dateB]
I am looking for something like
SELECT *
FROM TABLE
WHERE [dateB] >= ([dateA] - 7 days)
WHERE dateB >= DATEADD(DAY, -7, dateA)
Potentially useful reading...
select * from table
where dateB >= dateadd(dd,-7, dateA)
SELECT *
FROM TABLE
WHERE [dateB]) >= convert(datetime,[dateA] - 7)
You were so close
IF you need past 7 days activity then you need take difference of date in that column from today i.e GETDATE() it will be something like this......
WHERE (DATEDIFF(DAY, GETDATE(), dateA) <= 0 AND DATEDIFF(DAY, GETDATE(), dateA) > -7 )
AND (DATEDIFF(DAY, GETDATE(), dateB) <= 0 AND DATEDIFF(DAY, GETDATE(), dateB) > -7 )

Resources