Division of dates to create percentage SQL - sql

I am trying to do write in a function to subtract a few dates, then divide them together, add 1 then * 100 to get an overall % complete.
((SYSDATETIME() - proj.proj_scheduledDate)/(proj.proj_dueDate - proj.proj_scheduledDate + 1)) * 100 as 'percent done
returns
Operand data type datetime is invalid for divide operator.
What do I need to do to get this query to work? THANKS!

Might I suggest using DATEDIFF() with dd for a day datepart -- you can easily get the percentage of days completed - or go to smaller datepart values if you need to.
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.

SELECT
FLOOR((DATEDIFF(NOW(), proj.proj_scheduledDate) / DATEDIFF(proj.proj_dueDate, proj.proj_scheduledDate)) * 100)
FROM
foo;

Related

round GETDATE (SQL Server)

I have a function which is working fine in MySQL
round((now()-ts/60) as tdiff
(round the result of subtracting the current datetime from ts (also a datetime) divided by 60)
Attempting (and failing) to convert this for SQL Server.
Tried -
round((GETDATE()-ts/60) as tdiff
but that results in round function requires 2 or 3 parameters (which to me it does), so modified to -
round((GETDATE()-ts/60,0) as tdiff
but that results in the datatypes (GETDATE and ts) are incompatible in the subtract operator.
So then I attempted to cast both GETDATE and ts as date and that made no difference.
ts is a conventional datetime i.e.
2918-04-20 11:05:09 and I assumed GETDATE returned the same format.
As an example if GETDATE is today and ts is 2018-04-20 11:05:09 then tdiff is
6850891 (round effectively removes the dashes and colons and concatenates the datetime producing 20180420110509 for 2018-04-20 11:05:09 and 20180831164000 for 2018-08-31 16:40:00 and then divides by 60 to get 6850891.
Is there a remedy for this?
Regards, Ralph
GETDATE(), as per the documentation, returns a datetime. A datetime is accurate to 1/300 of a second, and it's accuracy cannot be changed.
If you want the time accurate to a second, you need to convert to a datetime2(0):
SELECT CONVERT(datetime2(0),GETDATE());
Also, however, don't use syntax like GETDATE()-ts. use the functions DATEADD and DATEDIFF for date maths.
I've no idea what GETDATE()-ts/60 is trying to acheive. Perhaps the number of minutes between the 2? DATEDIFF counts the "ticks" between 2 dates/times, thus DATEDIFF(MINUTE,'00:00:59','00:01:00') would return 1, despite there only being 1 second between the 2 times. This is because the minute value has "ticked" once (from 0 to 1). Therefore you might want to use DATEDIFF(SECOND,'00:00:59','00:01:00') / 60. This would return 0, as 1 / 60 in integer math is 0 (as is 59 / 60).
I think you want to use the DATEDIFF function:
DATEDIFF ( datepart , startdate , enddate )
DATEDIFF ( second, ts, GETDATE())
DATEDIFF ( second, ts, GETDATE())
DATEDIFF ( minute, ts, GETDATE())
DATEDIFF ( hour, ts, GETDATE())
The first argument tells it which increment of time to return.
If you are trying to find the difference between two values, then use datediff(). For instance:
select datediff(day, getdate(), ts)
gets the difference in days.
date_diff() or a related function would also be the right approach in MySQL.
sorry, I don't know if I have understand the question, you need to do date-date/60 and round the result?
In this case you have to change the minus ("-") with the DATEDIFF("Type return example DAYS", GETDATE(), ts).
So you will have ROUND((DATEDIFF(DAY,GETDATE(),ts)/60,0)
Please try and let me know if it will works for you
Bye

SQL operand data type datetime / varchar is invalid for sum operator

I am trying to subtract one column from another column, and then sum the result. However, whatever I change I keep getting one of the two errors as mentioned in the title.
From all other questions posted, I derived that my statement should be something like:
SELECT SUM(EndTime-BeginTime) AS TotalTime FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
As per suggestion in another topic, I changed the statement to:
SELECT SUM(CONVERT(varchar(EndTime-BeginTime), 108)) AS TotalTime FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
However, I still receive the error.
The times are stored as follows:
1-1-1900 7:30:00
Thanks for any suggestion...
Edit 1: Oh, I am using a Microsoft Query through ODBC for SQL in Excel, kind of like:
Excel vlookup incorporating SQL table
Edit 2: I prefer to have the output again in the HH:MM format.
The thing is, when I copy the complete database to excel, everything works just fine. I can subtract the columns and sum up. I just dont want to that manually every day....
I just checked the SQL database, and the column is of Date/Time type.
First of all, trying to solve date or numeric issues by converting to text never solves anything, it adds additional problems like failed conversions or unexpected results.
SQL Server doesn't have a time interval type. If you subtract two datetime values you get back another datetime value that represents the difference as the offset since 1900-01-01. The following query :
select getdate() - dateadd(d,-1,getdate())
Will return :
1900-01-02 00:00:00.000
Which is 1 full day after 1900-01-01.
datetime values can't be summed though. SQL Server does have a time type but that just represents the time of day. Even if today - yesterday worked, converting that to time would return 00:00.
A quick solution is to use DATEDIFF to calculate the difference between two dates in whatever unit is required - hourss, minutes, seconds etc. Be aware though that DATEDIFF returns the number of interval boundaries crossed. DATEDIFF(DAY,...) between 11pm yesterday and 1am today will return 1, because 1 day boundary was crossed.
You can use
SELECT sum(datediff(minute,EndTime,BeginTime)) AS TotalMinutes
FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
To calculate the difference in minutes and format it as a time interval on the client.
Another option is to cast the datetime to a float before summing, then back to datetime:
SELECT cast( sum(cast(EndTime - BeginTime as datetime)) as datetime) AS TotalOffset
FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
A 2-day duration would appear as :
1900-01-03 00:00:00.000
This works because datetime can be cast to a float whose integral part represents the offset from 1900-01-01 and the fractional part the time.
A client written in a language like C# that does support intervals could subtract 1900-01-01 from this to get back the actual duration, eg :
TimeSpan duration = sumResult - new DateTime(1900,1,1);
Another option would be to avoid the final cast and just use the resulting float value as the number of days.
Displaying in Excel
The last option could be the easiest way to display the duration in Excel! Excel dates are actually stored as floats. What makes them appear as dates or times is the cell's formatting.
You can set a cells format to [h]:mm:ss to display any number as a duration. The [] is important - without it Excel will only display the time part of the "date".
If you enter 2 in a cell, h:mm:ss will show it as 0:00:00 while [h]:mm:ss will display 48:00:00, 48 hours.
Despite its strangeness,
SELECT sum(cast(EndTime - BeginTime as datetime)) AS TotalDuration
FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
May be the best option to display a duration sum in Excel
You seem to want datediff():
SELECT SUM(DATEDIFF(second, BeginTime, EndTime) AS TotalTime
FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
How about the following:
WITH totalTime AS (
SELECT SUM(DATEDIFF(second, EndTime, BeginTime)) as TimeInSecond
FROM TimeRegister
WHERE OrderNumber = 00000 AND Activity = 11111;
)
SELECT RIGHT('0' + CAST(TimeinSecond / 3600 AS VARCHAR),2) + ':' +
RIGHT('0' + CAST((TimeinSecond / 60) % 60 AS VARCHAR),2) + ':' +
RIGHT('0' + CAST(TimeinSecond % 60 AS VARCHAR),2) AS TimeElapsed
FROM totalTime;
In this solution, the time is converted into seconds, before being totalled, and then converted to HH:MM:SS.

Pervasive dval stores dates as integer in days from 01/01/0001. I need a function to convert it for sql server

I need help. Pervasive DB stored dates in days. For example 719311 would be the amount of days from 01/01/0001 to May 28 1970. So May 28 1970 is the date represented in pervasive when looking at 719311.
You can use SQL Servers dateadd feature for this. However the values in Pervasive are much too large to add to the base date of 0 (1900-01-01).
To work around that I used the known integer/date provided and calculated the delta between 0001-01-01 and 1900-01-01 - which is 693597. This value is static, and can be subtracted from each Pervasive value and used in the dateadd. The result can then be added to 1900-01-01.
-- GET BASE DATE OF 0
SELECT CONVERT(DATETIME,0)
-- CALCULATE DIFF FROM 0 TO A KNOWN DATE...
SELECT DATEDIFF(DD,0,'1970-05-28')
--SUBTRACT ABOVE DIFF FROM KNOWN INTEGER FOR SAID DATE... THIS IS OUR DELTA
SELECT 719311-25714
-- ADD THE INTEGER OF SAID DATE, MINUS THE ABOVE DELTA TO 0 TO CONFIRM WE GET THE KNOWN DATE.
SELECT DATEADD(DD,719311-693597,0)
-- USING VARIABLES, LEAVE #DELTA AS A STATIC VALUE, JUST UPDATE #PERVASIVE
DECLARE #PERVASIVE INT, #DELTA INT
SET #PERVASIVE=719312
SET #DELTA=693597
SELECT DATEADD(DD,#PERVASIVE-#DELTA,0)
select datediff(day,'0001-01-01','1753-01-01') + 2
select 719311 - 639907 -- sql
select dateadd(day,79404,'1753-01-01')
dateadd() function cannot work with a date older than '1753-01-01', so you need the 719311 days minus the 639907 days. The difference you can than plug into the dateadd() function.
You should get this 1970-05-28 00:00:00.000
Another alternative is add days to a date datatype.
When I add 719311 days to '0001-01-01' I get '1970-05-30'
To get '1970-05-28' I have to remove 2 of those days.
select dateadd(day,719311-2,convert(date,'00010101'))
returns '1970-05-28'

SQL Command not properly ended ( oracle 11g for windows)

I m using this query to get a result of the difference between the start time and end time of an activity. Where the end time is null i wanted to put the minimum value as 500. Please advice and HELP!!
select * from table
where (end_time - start_time) * 24 * 60 > 1,
IF end_time IS NULL THEN '500';
So this is your query:
select * from table where (end_time - start_time) * 24 * 60 > 1;
But you want to treat a null end_time as 500. So use NVL or COALESCE to replace the null with 500:
select * from table where (nvl(end_time,500) - start_time) * 24 * 60 > 1;
IF end_time IS NULL THEN '500';
Just to make it more clear, '500' is not a number rather a string since it is enclosed within single quotation marks.
Now, end_time is. DATE data type or a timestamp, ideally. So, 500 makes no sense. You must convert it to appropriate type, whether 500 is days, hours, minutes, seconds, fraction of a second.
As in other answer it is suggested to use NVL(end_time, 500), it makes no sense. What does 500 - a date mean? Applying NVL is the need, however, you must convert it to the required value, else those are two different data types and Oracle won't allow it.
UPDATE
In my opinion,
Difference between two dates gives the number of days to the precision of seconds converted back to days. But, difference between an arbitrary number and a date makes no sense.
I assumed that start_time and end_time columns have number as datatype, for this calculation you need to select these specific columns and not all (*). Comparison is in where clause, this works in oracle11.
select ((NVL(END_TIME, 500)-START_TIME) * 24 * 60) from TABLE_NAME where ((NVL(END_TIME, 500)-START_TIME) * 24 * 60) > 1;

convert Excel Date Serial Number to Regular Date

I got a column called DateOfBirth in my csv file with Excel Date Serial Number Date
Example:
36464
37104
35412
When i formatted cells in excel these are converted as
36464 => 1/11/1999
37104 => 1/08/2001
35412 => 13/12/1996
I need to do this transformation in SSIS or in SQL. How can this be achieved?
In SQL:
select dateadd(d,36464,'1899-12-30')
-- or thanks to rcdmk
select CAST(36464 - 2 as SmallDateTime)
In SSIS, see here
http://msdn.microsoft.com/en-us/library/ms141719.aspx
The marked answer is not working fine, please change the date to "1899-12-30" instead of "1899-12-31".
select dateadd(d,36464,'1899-12-30')
You can cast it to a SQL SMALLDATETIME:
CAST(36464 - 2 as SMALLDATETIME)
MS SQL Server counts its dates from 01/01/1900 and Excel from 12/30/1899 = 2 days less.
tldr:
select cast(#Input - 2e as datetime)
Explanation:
Excel stores datetimes as a floating point number that represents elapsed time since the beginning of the 20th century, and SQL Server can readily cast between floats and datetimes in the same manner. The difference between Excel and SQL server's conversion of this number to datetimes is 2 days (as of 1900-03-01, that is). Using a literal of 2e for this difference informs SQL Server to implicitly convert other datatypes to floats for very input-friendly and simple queries:
select
cast('43861.875433912' - 2e as datetime) as ExcelToSql, -- even varchar works!
cast(cast('2020-01-31 21:00:37.490' as datetime) + 2e as float) as SqlToExcel
-- Results:
-- ExcelToSql SqlToExcel
-- 2020-01-31 21:00:37.490 43861.875433912
this actually worked for me
dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-30')
(minus 1 more day in the date)
referring to the negative commented post
SSIS Solution
The DT_DATE data type is implemented using an 8-byte floating-point number. Days are represented by whole number increments, starting with 30 December 1899, and midnight as time zero. Hour values are expressed as the absolute value of the fractional part of the number. However, a floating point value cannot represent all real values; therefore, there are limits on the range of dates that can be presented in DT_DATE. Read more
From the description above you can see that you can convert these values implicitly when mapping them to a DT_DATE Column after converting it to a 8-byte floating-point number DT_R8.
Use a derived column transformation to convert this column to 8-byte floating-point number:
(DT_R8)[dateColumn]
Then map it to a DT_DATE column
Or cast it twice:
(DT_DATE)(DT_R8)[dateColumn]
You can check my full answer here:
Is there a better way to parse [Integer].[Integer] style dates in SSIS?
Found this topic helpful so much so created a quick SQL UDF for it.
CREATE FUNCTION dbo.ConvertExcelSerialDateToSQL
(
#serial INT
)
RETURNS DATETIME
AS
BEGIN
DECLARE #dt AS DATETIME
SELECT #dt =
CASE
WHEN #serial is not null THEN CAST(#serial - 2 AS DATETIME)
ELSE NULL
END
RETURN #dt
END
GO
I had to take this to the next level because my Excel dates also had times, so I had values like this:
42039.46406 --> 02/04/2015 11:08 AM
42002.37709 --> 12/29/2014 09:03 AM
42032.61869 --> 01/28/2015 02:50 PM
(also, to complicate it a little more, my numeric value with decimal was saved as an NVARCHAR)
The SQL I used to make this conversion is:
SELECT DATEADD(SECOND, (
CONVERT(FLOAT, t.ColumnName) -
FLOOR(CONVERT(FLOAT, t.ColumnName))
) * 86400,
DATEADD(DAY, CONVERT(FLOAT, t.ColumnName), '1899-12-30')
)
In postgresql, you can use the following syntax:
SELECT ((DATE('1899-12-30') + INTERVAL '1 day' * FLOOR(38242.7711805556)) + (INTERVAL '1 sec' * (38242.7711805556 - FLOOR(38242.7711805556)) * 3600 * 24)) as date
In this case, 38242.7711805556 represents 2004-09-12 18:30:30 in excel format
In addition of #Nick.McDermaid answer I would like to post this solution, which convert not only the day but also the hours, minutes and seconds:
SELECT DATEADD(s, (42948.123 - FLOOR(42948.123))*3600*24, dateadd(d, FLOOR(42948.123),'1899-12-30'))
For example
42948.123 to 2017-08-01 02:57:07.000
42818.7166666667 to 2017-03-24 17:12:00.000
You can do this if you just need to display the date in a view:
CAST will be faster than CONVERT if you have a large amount of data, also remember to subtract (2) from the excel date:
CAST(CAST(CAST([Column_With_Date]-2 AS INT)AS smalldatetime) AS DATE)
If you need to update the column to show a date you can either update through a join (self join if necessary) or simply try the following:
You may not need to cast the excel date as INT but since the table I was working with was a varchar I had to do that manipulation first. I also did not want the "time" element so I needed to remove that element with the final cast as "date."
UPDATE [Table_with_Date]
SET [Column_With_Excel_Date] = CAST(CAST(CAST([Column_With_Excel_Date]-2 AS INT)AS smalldatetime) AS DATE)
If you are unsure of what you would like to do with this test and re-test! Make a copy of your table if you need. You can always create a view!
Google BigQuery solution
Standard SQL
Select Date, DATETIME_ADD(DATETIME(xy, xm, xd, 0, 0, 0), INTERVAL xonlyseconds SECOND) xaxsa
from (
Select Date, EXTRACT(YEAR FROM xonlydate) xy, EXTRACT(MONTH FROM xonlydate) xm, EXTRACT(DAY FROM xonlydate) xd, xonlyseconds
From (
Select Date
, DATE_ADD(DATE '1899-12-30', INTERVAL cast(FLOOR(cast(Date as FLOAT64)) as INT64) DAY ) xonlydate
, cast(FLOOR( ( cast(Date as FLOAT64) - cast(FLOOR( cast(Date as FLOAT64)) as INT64) ) * 86400 ) as INT64) xonlyseconds
FROM (Select '43168.682974537034' Date) -- 09.03.2018 16:23:28
) xx1
)
For those looking how to do this in excel (outside of formatting to a date field) you can do this by using the Text function https://exceljet.net/excel-functions/excel-text-function
i.e.
A1 = 132134
=Text(A1,"MM-DD-YYYY") will result in a date
This worked for me because sometimes the field was a numeric to get the time portion.
Command:
dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-31')