How to Convert varchar time to Time in SQL Server 2008 - sql-server-2008

I have decimal time and I am able to convert into time. However I need to insert converted time into a table which has a column of time datatype
DECLARE #hours decimal(15,4)
SELECT #hours = 20.5 //20 Hrs and 30 mins
SELECT
RIGHT('00' + CONVERT(varchar(2), FLOOR(#hours)), 2) + ':' +
RIGHT('00' + CONVERT(varchar(2), FLOOR(((#hours - FLOOR(#hours)) * 60))), 2) + ':' +
RIGHT('00' + CONVERT(varchar(2), FLOOR(((#hours - FLOOR(#hours)) * 60) - FLOOR(((#hours - FLOOR(#hours)) * 60))) * 60), 2) AS Time
This is my temp table that I need to insert the value into:
create table #timetest(timetest time)
insert into #timetest
SELECT
RIGHT('00' + CONVERT(varchar(2), FLOOR(#hours)), 2) + ':' +
RIGHT('00' + CONVERT(varchar(2), FLOOR(((#hours - FLOOR(#hours)) * 60))), 2) + ':' +
RIGHT('00' + CONVERT(varchar(2), FLOOR(((#hours - FLOOR(#hours)) * 60) - FLOOR(((#hours - FLOOR(#hours)) * 60))) * 60), 2)
I get this error:
Conversion failed when converting date and/or time from character
string.
Please help me

I believe you cannot have TIME values for more than 24 hours ....
Check the MSDN documentation on TIME:
Range 00:00:00.0000000 through 23:59:59.9999999
Update: if you've changed your time to less than 24 hours, you can do the insert like this:
create table #timetest(timetest time)
insert into #timetest(timetest)
SELECT
CAST(RIGHT('00' + CONVERT(varchar(2), FLOOR(#hours)), 2) + ':' +
RIGHT('00' + CONVERT(varchar(2), FLOOR(((#hours - FLOOR(#hours)) * 60))), 2) + ':' +
RIGHT('00' + CONVERT(varchar(2), FLOOR(((#hours - FLOOR(#hours)) * 60) - FLOOR(((#hours - FLOOR(#hours)) * 60))) * 60), 2) AS TIME)
You need to explicitly CAST your string AS TIME and then everything should work just fine.

declare #hours decimal(15,4)
set #hours = 20.5 --20 Hrs and 30 mins
create table #timetest(timetest time(0))
insert into #timetest(timetest) values(cast(#hours/24 as datetime))
select * from #timetest
drop table #timetest
Result:
20:30:00

Related

INSERT Trigger for a rating system: Division by zero error

I have followed this paper which suggests what is claimed to be a good approach to 5 star rating systems.
The schema is:
CREATE TABLE `ratings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL,
`positive` float NOT NULL DEFAULT 0,
`negative` float NOT NULL DEFAULT 0,
`stars` float DEFAULT 0,
`total` int(11) NOT NULL,
`lower_bound` float DEFAULT NULL,
PRIMARY KEY (`id`)
)
I setup the INSERT trigger which is:
CREATE
TRIGGER `insert_rating` BEFORE INSERT ON `ratings`
FOR EACH ROW
SET new.total = new.positive + new.negative,
new.stars = ROUND( (((new.positive / new.total) * 4) + 1) * 2, 0) / 2,
new.lower_bound = ((new.positive + 1.9208) / (new.positive + new.negative) - 1.96 * SQRT((new.positive * new.negative) / (new.positive + new.negative) + 0.9604) / (new.positive + new.negative)) / (1 + 3.8416 / (new.positive + new.negative))
but upon my first insert of (Also taken from the paper):
INSERT into ratings (product_id, positive, negative) VALUES (1, 0, 0)
I got a Division by zero error. Is there an SQL error in the design of this method or have I done something wrong? Would like to know how to fix.
There's also an update trigger but I don't think I will ever need to update it with zeros:
CREATE
TRIGGER `update_rating` BEFORE UPDATE ON `ratings`
FOR EACH ROW
SET new.total = new.positive + new.negative,
new.stars = ROUND( (((new.positive / new.total) * 4) + 1) * 2, 0) / 2,
new.lower_bound = ((new.positive + 1.9208) / (new.positive + new.negative) - 1.96 * SQRT((new.positive * new.negative) / (new.positive + new.negative) + 0.9604) / (new.positive + new.negative)) / (1 + 3.8416 / (new.positive + new.negative))
Gordon's answer will prevent the error.
The trigger expects either positive or negative to be non-zero, which makes sense. Your insert statement adds NO actual ratings (either positive or negative); so what's the point?
More importantly, why not save yourself some headaches and change the columns to do the work for you?
In your table definition, change the columns to
...
total INT GENERATED ALWAYS AS (positive+negative) STORED,
stars INT GENERATED ALWAYS AS (ROUND((((positive/NULLIF(positive+negative,0))*4)+1) *2, 0)/2) STORED,
lower_bound DOUBLE GENERATED ALWAYS AS ((positive + 1.9208) / NULLIF(positive + negative, 0) - 1.96 * SQRT((positive * negative) / (positive + negative) + 0.9604) / NULLIF(positive + negative, 0))) / (1 + 3.8416 / NULLIF(positive + negative, 0)) STORED,
...
(And remove all the triggers, of course)
The following line sets new.total to 0
SET new.total = new.positive + new.negative
The next line has new.positive / new.total. Since you just set new.total to 0 you get a divide by 0. I would try testing for this condition and setting new.stars = 0 where is happens.
It is like really hard to tell which division is causing the issue. But the solution is NULLIF():
SET new.total = new.positive + new.negative,
new.stars = ROUND( (((new.positive / NULLIF(new.total, 0)) * 4) + 1) * 2, 0) / 2,
n new.lower_bound = ((new.positive + 1.9208) / NULLIF(new.positive + new.negative, 0) - 1.96 * SQRT((new.positive * new.negative) / NULLIF(new.positive + new.negative, 0) + 0.9604) / NULLIF(new.positive + new.negative, 0))) / (1 + 3.8416 / NULLIF(new.positive + new.negative, 0)
This turns 0s into NULLs, so the result is NULL rather than an error.

Converting Degrees/Minutes/Seconds to Decimals using MySQL

I'm using MySQL version: 5.7.22
I've got two columns Latitude and Longitude both in Degrees/Minutes/Seconds format that I want to convert to Decimal format ex: 48° 52.250' N to 48.93611111
I have the following script but I'm stuck at how to split the degrees minutes and seconds. I cannot hard-code the values as I've done here left(Latitude,2) since the degrees might have 3 decimals as well
SELECT Latitude,
left(Latitude, 2) +
(TRUNCATE((Latitude - TRUNCATE(Latitude)) * 100) / 60) +
(((Latitude * 100) - TRUNCATE(Latitude * 100)) * 100) / (60 * 60) AS DECIMAL_DEGREES
FROM small_ocean_data
The formula for the conversion is this: D + M/60 + S/3600 * -1 if direction in ['W', 'S'] else 1
Any help would be grateful!
Well if I use this formula of yours: D + M/60 + S/3600
Where I believe D is Degrees and M are Minutes and S are Seconds.
With this select:
select SUBSTRING_INDEX('48° 52.250', '°',1) +
(SUBSTRING_INDEX('48° 52.250',' ',1)/60) +
(SUBSTRING_INDEX('48° 52.250','.',1)/3600);
Or for your database:
select SUBSTRING_INDEX(Latitude, '°', 1) +
(SUBSTRING_INDEX(Latitude ,' ',1)/60) +
(SUBSTRING_INDEX(Latitude ,'.',1)/3600) "DECIMAL_DEGREES"
FROM small_ocean_data;
I get 48.81333333333333
48 + 0.8 + 0.013333333333333334
Here is the DEMO

How do I calculate a percentage value from these two time values

I have two expressions which are calculating across a number of datasets
Expression 1 is as follows:
=Format((count(Fields!Second_Choice_Options.Value, "Authorisation") * 20 + count(Fields!Second_Choice_Options.Value, "ClaimPaid") * 20 + count(Fields!Second_Choice_Options.Value, "ClaimPended") * 20 + count(Fields!Second_Choice_Options.Value, "General") * 8 +count(Fields!Second_Choice_Options.Value, "Reassessment") * 20 +count(Fields!Second_Choice_Options.Value, "ReserveReview") *3 +count(Fields!Second_Choice_Options.Value, "Trigger") *5 + Sum(Fields!ACD_Calls.Value, "DataSet3") * 6 + Sum(Fields!Extn_Out_Calls.Value, "DataSet3") * 2) / 60, "00") & ":" & Format(DateAdd("s", (count(Fields!Second_Choice_Options.Value, "Authorisation") * 20 + count(Fields!Second_Choice_Options.Value, "ClaimPaid") * 20 + count(Fields!Second_Choice_Options.Value, "ClaimPended") * 20 + count(Fields!Second_Choice_Options.Value, "General") * 8 +count(Fields!Second_Choice_Options.Value, "Reassessment") * 20 +count(Fields!Second_Choice_Options.Value, "ReserveReview") *3 +count(Fields!Second_Choice_Options.Value, "Trigger") *5 + Sum(Fields!ACD_Calls.Value, "DataSet3") * 6 + Sum(Fields!Extn_Out_Calls.Value, "DataSet3") * 2) * 60, "00:00"), "mm:ss")
and the time value is 71:45:00
I then have a second expression which is
=System.Math.Floor(Sum(Fields!Staffed_Time.Value) / 3600) - System.Math.Floor(Sum(Fields!Time_in_Lunch.Value) / 3600)- System.Math.Floor(Sum(Fields!Time_in_AUX_1099.Value) / 3600) & ":" & Microsoft.VisualBasic.Strings.Format(Microsoft.VisualBasic.DateAndTime.DateAdd("s", Sum(Fields!Staffed_Time.Value), "00:00"), "mm:ss")
and the time value is 156:39:22
Therefore I need to make a new calculation in a textbox and take 71:45:00 as a percentage of 156:39:22 and then display that as a percentage - which would be 45.5%
How can I do this?
Thanks
Dan
Don't use the two expressions that return a formatted time (i.e.: 70:17:00) but the expressions that return the number of minutes (i.e.: 4217), so you can use this formula in a TextBox with Format property set to p2:
=[YourExpression1ToObtainMinutes]/[YourExpression2ToObtainMinutes]

Mysql POINT column for distance search

yes i know this question ever asked plenty of time but all seems outdated from 2012, base of thoses question/ansewers ,
i tried to perform the classic search distance with column POINT
but i have some trouble unresolvable..
is normal my POINT column looks like this ?
0x00000000010100000085B1852007052040C0B2D2A414684840
Here is all my steps, i am not able to see whats wrong,
i did based from last stack questions/answers.
I use mariadb 10 with Heideisql gui.
i have 2 colums lat and lon ,
i created a geopoints POINT column,
populate geopoint like this:
UPDATE geoFRA
SET geopoints = GeomFromText(CONCAT('POINT (', lon, ' ', lat, ')'))
After that my geopoints column looks like this :
0x00000000010100000085B1852007052040C0B2D2A414684840
Then i try to perform the query in 2 maners , first try :
SET#lat = 48.88;
SET#lon = 2.34;
SELECT *
FROM geoFRA
WHERE MBRContains(LineFromText(CONCAT(
'('
, #lon + 700 / ( 111.1 / cos(RADIANS(#lon)))
, ' '
, #lat + 700 / 111.1
, ','
, #lon - 700 / ( 111.1 / cos(RADIANS(#lat)))
, ' '
, #lat - 700 / 111.1
, ')' )
,geopoints)
and second try :
SET#lat = 48.88;
SET#lon = 2.34;
SET #kmRange = 172; -- = 50 Miles
SELECT *, (3956 * 2 * ASIN(SQRT(POWER(SIN((#lat - abs(`lat`)) * pi()/180 / 2),2) + COS(#lat * pi()/180 ) * COS(abs(`lat`) * pi()/180) * POWER(SIN((lon - `lon`) * pi()/180 / 2), 2)))) as distance
FROM `geoFRA`
WHERE MBRContains(LineString(Point(#lat + #kmRange / 111.1, #lon + #kmRange / (111.1 / COS(RADIANS(#lat)))), Point(#lat - #kmRange / 111.1, #lon - #kmRange / (111.1 / COS(RADIANS(#lat))))), `geopoints`)
Order By distance
I begin to think there is some mariadb incompatibility ?! or did i miss something?
thanks for any help..,
flau
CREATE TABLE geoFRA (id int NOT NULL, geopoints point NOT NULL);
INSERT INTO geoFRA (id, geopoints) VALUES
(1, geomFromText('POINT(48 2)')),
(2, geomFromText('POINT(48 3)')),
(3, geomFromText('POINT(48.88 2.34)')),
(4, geomFromText('POINT(49 2)')),
(5, geomFromText('POINT(49 3)'));
SET #p=geomFromText('POINT(48.88 2.34)');
SELECT X(geopoints), Y(geopoints), asText(geopoints), ST_Distance(geopoints, #p) as d
FROM geoFRA
ORDER BY d;
This returns the geopoints ordered by distance. Using geopoints without X(), Y() and asText() returns them in the Well-Known Binary (WKB) format: http://dev.mysql.com/doc/refman/5.7/en/gis-data-formats.html#gis-wkb-format

Cumulative DATEDIFF [duplicate]

I have a database column containing an integer value that represents a systems up time in seconds. I'd really like a query to be able to show me that up time in a easy to read format day(s) hour(s) minute(s) but I'm not quite sure how to do it. A lot of examples I've found appear to use parameters as an example but never much of how to use it in a select function.
I need the time to be the same as what's displayed on a website too. I tried one query earlier and its added days and removed minutes. Can anyone help me out?
Source data:
PDT0014 6141
PDT0008 4990
PDT0024 840227
PDT0033 2301
PDT0035 5439
PDT0005 3434
PDT0019 5482
Sample code:
SELECT tblAssets.AssetName,
(case when tblAssets.Uptime> (24*60*60)
then
cast(datepart(day,datediff(dd, 0, dateadd(second, tblAssets.Uptime, 0))) as varchar(4))
+ ' Day(s) ' + convert(varchar(2), dateadd(second, tblAssets.Uptime, 0), 108) +' Hour(s)'
else
convert(varchar(5), dateadd(second, tblAssets.Uptime, 0), 108) + ' Hour(s) Minute(s) '
end) AS Uptime
FROM tblAssets
Desired Query Output:
PDT0014 01:42 Hour(s) Minute(s)
PDT0008 01:23 Hour(s) Minute(s)
PDT0024 10 Day(s) 17 Hour(s)
PDT0033 00:38 Hour(s) Minute(s)
PDT0035 01:30 Hour(s) Minute(s)
PDT0005 00:57 Hour(s) Minute(s)
PDT0019 01:31 Hour(s) Minute(s)
Depending on the output you want:
DECLARE #s INT = 139905;
SELECT CONVERT(VARCHAR(12), #s /60/60/24) + ' Day(s), '
+ CONVERT(VARCHAR(12), #s /60/60 % 24)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), #s /60 % 60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), #s % 60), 2);
Result:
1 Day(s), 14:51:45
Or:
DECLARE #s INT = 139905;
SELECT
CONVERT(VARCHAR(12), #s /60/60/24) + ' Day(s), '
+ CONVERT(VARCHAR(12), #s /60/60 % 24) + ' Hour(s), '
+ CONVERT(VARCHAR(2), #s /60 % 60) + ' Minute(s), '
+ CONVERT(VARCHAR(2), #s % 60) + ' Second(s).';
Result:
1 Day(s), 14 Hour(s), 51 Minute(s), 45 Second(s).
You can replace 60/60/24 with 86400 etc. but I find it better self-documenting if you leave in the /seconds/minutes/hours calculations. And if you are going against a table, just use column_name in place of #s.
I tend to use:
CAST(FLOOR(seconds / 86400) AS VARCHAR(10))+'d ' +
CONVERT(VARCHAR(5), DATEADD(SECOND, Seconds, '19000101'), 8)
The top part just gets your days as an integer, the bottom uses SQL-Server's convert to convert a date into a varchar in the format HH:mm:ss after converting seconds into a date.
e.g.
SELECT Formatted = CAST(FLOOR(seconds / 86400) AS VARCHAR(10))+'d ' +
CONVERT(VARCHAR(5), DATEADD(SECOND, Seconds, '19000101'), 8),
Seconds
FROM ( SELECT TOP 10
Seconds = (ROW_NUMBER() OVER (ORDER BY Object_ID) * 40000)
FROM sys.all_Objects
ORDER BY Object_ID
) S
Example on SQL Fiddle
N.B. Change CONVERT(VARCHAR(5), DATEADD(.. to CONVERT(VARCHAR(8), DATEADD(.. to keep the seconds in the result
EDIT
If you don't want seconds and need to round to the nearest minute rather than truncate you can use:
SELECT Formatted = CAST(FLOOR(ROUND(Seconds / 60.0, 0) * 60 / 86400) AS VARCHAR(10))+'d ' +
CONVERT(VARCHAR(5), DATEADD(SECOND, ROUND(Seconds / 60.0, 0) * 60, '19000101'), 8),
Seconds
FROM ( SELECT Seconds = 3899
) S
I have just replaced each reference to the column seconds with:
ROUND(Seconds / 60.0, 0) * 60
So before doing the conversion rounding your seconds value to the nearest minute
You can convert seconds to days by dividing by 86400
You can convert seconds to hours by dividing by 3600, but you need to get the remainder
(by subtracting off the total days converted to hours)
You can convert seconds to minutes by dividing by 60, but you need to get the remainder (by subtracting off the total hours converted to minutes)
Seconds you can just report, but like minutes you want to only report the remainder of seconds (by sutracting off the total minutes converted to seconds)
SELECT FLOOR( UpTime / 86400 ) AS DAYS
, FLOOR( ( UpTime / 3600 ) - FLOOR( UpTime / 86400 ) * 24 ) AS HOURS
, FLOOR( ( UpTime / 60 ) - FLOOR( UpTime / 3600 ) * 60 ) AS MINUTES
, UpTime - FLOOR( UpTime / 60 ) * 60 AS SECONDS
FROM ( SELECT 269272 AS UpTime ) AS X
269272 represents 3 days (259200 seconds), 2 hours (7200 seconds), 47 minutes (2820 seconds) and 52 seconds.
This query produces:
| DAYS | HOURS | MINUTES | SECONDS |
------------------------------------
| 3 | 2 | 47 | 52 |
Substituting 125 (2 minutes, 5 seconds) for 259200 will produce:
| DAYS | HOURS | MINUTES | SECONDS |
------------------------------------
| 0 | 0 | 2 | 5 |
To convert this to a string representation, you can use SQL Server 2012's FORMAT function:
SELECT CASE
WHEN DAYS > 0 THEN
FORMAT( DAYS, '##' ) + ' Day(s) ' + FORMAT( HOURS, '##' ) + ' Hour(s)'
ELSE
FORMAT( HOURS, '##' ) + ':' + FORMAT( MINUTES, '##' ) + ' Hour(s) Minute(s)'
END AS UpTimeString
FROM (
SELECT FLOOR( UpTime / 86400 ) AS DAYS
, FLOOR( ( UpTime / 3600 ) - FLOOR( UpTime / 86400 ) * 24 ) AS HOURS
, FLOOR( ( UpTime / 60 ) - FLOOR( UpTime / 3600 ) * 60 ) AS MINUTES
, UpTime - FLOOR( UpTime / 60 ) * 60 AS SECONDS
FROM ( SELECT 125 AS UpTime ) AS X
) AS UptimeSubselect
This is another approach using DATEPART():
DECLARE #S INT = 86472,
#START DATETIME = CONVERT(DATETIME,0)
DECLARE #END DATETIME = DATEADD(SECOND,#S, #START)
SELECT CONVERT(VARCHAR(10),DATEPART(DAY,#END)-1) + ' Day(s) ' +
RIGHT(CONVERT(VARCHAR(10),100+DATEPART(HOUR, #END)),2) + ':' +
RIGHT(CONVERT(VARCHAR(10),100+DATEPART(MINUTE, #END)),2) + ':' +
RIGHT(CONVERT(VARCHAR(10),100+DATEPART(SECOND, #END)),2)
If you don't need to format time part:
SELECT CONVERT(VARCHAR(10),DATEPART(DAY,#END)-1) + ' Day(s) ' +
CONVERT(VARCHAR(10),DATEPART(HOUR, #END)) + ' Hour(s)' +
CONVERT(VARCHAR(10),DATEPART(MINUTE, #END)) + ' Minute(s)' +
CONVERT(VARCHAR(10),DATEPART(SECOND, #END)) + ' Second(s)'
DECLARE #Seconds INT = 86200;
SELECT CONVERT(VARCHAR(15),
CAST(CONVERT(VARCHAR(12), #Seconds / 60 / 60 % 24)
+':'+ CONVERT(VARCHAR(2), #Seconds / 60 % 60)
+':'+ CONVERT(VARCHAR(2), #Seconds % 60) AS TIME), 100) AS [HH:MM:SS (AM/PM)]