Result is not 0, but ORA-01476 divisor is equal to zero - SQL - zero

When I say:
NVL(OSS_REALIZADAS_MEN.NUMERO_DE_OS * 1,0) +
NVL(OSS_REALIZADAS_BIM.NUMERO_DE_OS * 2,0) +
NVL(OSS_REALIZADAS_TRI.NUMERO_DE_OS * 2,0) + NVL(OSS_REALIZADAS_SEM.NUMERO_DE_OS * 3,0) +
NVL(OSS_REALIZADAS_ANU.NUMERO_DE_OS * 5,0) as Realizadas_Tot,
NVL(OSS_PROGRAMADAS_MEN.NUMERO_DE_OS * 1,0) +
NVL(OSS_PROGRAMADAS_BIM.NUMERO_DE_OS * 2,0) +
NVL(OSS_PROGRAMADAS_TRI.NUMERO_DE_OS * 2,0) +
NVL(OSS_PROGRAMADAS_SEM.NUMERO_DE_OS * 3,0) +
NVL(OSS_PROGRAMADAS_ANU.NUMERO_DE_OS * 5,0) as Programadas_Tot
Then Programadas_Tot and Realizadas_Tot bring me some integer numbers.
But need to divide them:
(
NVL(OSS_REALIZADAS_MEN.NUMERO_DE_OS * 1,0) +
NVL(OSS_REALIZADAS_BIM.NUMERO_DE_OS * 2,0) +
NVL(OSS_REALIZADAS_TRI.NUMERO_DE_OS * 2,0) +
NVL(OSS_REALIZADAS_SEM.NUMERO_DE_OS * 3,0) +
NVL(OSS_REALIZADAS_ANU.NUMERO_DE_OS * 5,0)
)
/
(
NVL(OSS_PROGRAMADAS_MEN.NUMERO_DE_OS * 1,0) +
NVL(OSS_PROGRAMADAS_BIM.NUMERO_DE_OS * 2,0) +
NVL(OSS_PROGRAMADAS_TRI.NUMERO_DE_OS * 2,0) +
NVL(OSS_PROGRAMADAS_SEM.NUMERO_DE_OS * 3,0) +
NVL(OSS_PROGRAMADAS_ANU.NUMERO_DE_OS * 5,0)
)
as APPtot
But it shows me the error "ORA-01476 divisor is equal to zero".
I read a lot about decode and case, but i think it is not for what i want to do.
I tried a lot of ways with NVLs and NVL2s, but it keeps me saying that.
Thanks already!

For those who can have the same problem as I had above, here is my solution:
NVL(
NULLIF(
NVL(OSS_REALIZADAS_MEN.NUMERO_DE_OS * 1,0) +
NVL(OSS_REALIZADAS_BIM.NUMERO_DE_OS * 2,0) +
NVL(OSS_REALIZADAS_TRI.NUMERO_DE_OS * 2,0) +
NVL(OSS_REALIZADAS_SEM.NUMERO_DE_OS * 3,0) +
NVL(OSS_REALIZADAS_ANU.NUMERO_DE_OS * 5,0)
,0)
/
NULLIF(
NVL(OSS_PROGRAMADAS_MEN.NUMERO_DE_OS * 1,0) +
NVL(OSS_PROGRAMADAS_BIM.NUMERO_DE_OS * 2,0) +
NVL(OSS_PROGRAMADAS_TRI.NUMERO_DE_OS * 2,0) +
NVL(OSS_PROGRAMADAS_SEM.NUMERO_DE_OS * 3,0) +
NVL(OSS_PROGRAMADAS_ANU.NUMERO_DE_OS * 5,0),0)
,0)
* 100 AS APP

Related

Execute in Where clause if variable is not null

I am trying to write stored procedure that will execute code if variable is not null
#PageNumber INT = 1
,#PageSize INT = 100
,#Latitude DECIMAL(9, 6) NULL
,#Longitude DECIMAL(9, 6) NULL
,#Radius INT NULL
SELECT lst.[Id]
,lst.[Number]
FROM dbo.[Listing] lst
INNER JOIN dbo.[Branch] bra ON bra.[Id] = lst.BranchStartId
WHERE
*Pseudo Code*
IF (#Latitude > 0 AND #Longitude > 0 AND #Radius > 0)
BEGIN
(acos(sin(bra.Latitude * 0.0175) * sin(#Latitude * 0.0175) + cos(bra.Latitude * 0.0175) * cos(#Latitude * 0.0175) * cos((#Longitude * 0.0175) - (bra.Longitude * 0.0175))) * 6371 <= #Radius)
END
ELSE
*select all*
END
ORDER BY Id DESC
OFFSET #PageSize * (#PageNumber - 1) ROWS
FETCH NEXT #PageSize ROWS ONLY OPTION (RECOMPILE);
Can it be done without writing dynamic query?
I have figured out that it can be done by:
IF (#Latitude > 0 AND #Longitude > 0 AND #Radius > 0)
BEGIN
SELECT lst.[Id]
,lst.[Number]
FROM dbo.[Listing] lst
INNER JOIN dbo.[Branch] bra ON bra.[Id] = lst.BranchStartId
WHERE (acos(sin(bra.Latitude * 0.0175) * sin(#Latitude * 0.0175) + cos(bra.Latitude * 0.0175) * cos(#Latitude * 0.0175) * cos((#Longitude * 0.0175) - (bra.Longitude * 0.0175))) * 6371 <= #Radius)
END
ELSE
BEGIN
SELECT lst.[Id]
,lst.[Number]
FROM dbo.[Listing] lst
INNER JOIN dbo.[Branch] bra ON bra.[Id] = lst.BranchStartId
END
But in this scenario I am not able to get auto generated return type with linq to sql. Thank you for your time.
I think you want simple logical comparisons with OR:
WHERE #Latitude IS NULL OR #Longitude IS NULL OR #Radius IS NULL OR
(acos(sin(bra.Latitude * 0.0175) * sin(#Latitude * 0.0175) + cos(bra.Latitude * 0.0175) * cos(#Latitude * 0.0175) * cos((#Longitude * 0.0175) - (bra.Longitude * 0.0175))) * 6371 <= #Radius)

Calculating Distance - performance enhancement

declare #Latitude DECIMAL(17, 14)='-29.72216606140100',#Longitude DECIMAL(17, 14)='31.06697845459000'
SELECT DISTINCT
*,
pm_Latitude,
pm_Longitude,
CASE
WHEN p.latpoint = pm_Latitude
AND p.longpoint = pm_Longitude
THEN CAST(0 AS DECIMAL(8, 2))
ELSE CAST(p.distance_unit * DEGREES(ACOS(COS(RADIANS(p.latpoint)) * COS(RADIANS(pm_Latitude)) * COS(RADIANS(p.longpoint) - RADIANS(pm_Longitude)) + SIN(RADIANS(p.latpoint)) * SIN(RADIANS(pm_Latitude)))) AS DECIMAL(8, 2))
END AS 'pm_Distance'
FROM Pm_PropertyMapping WITH(NOLOCK) CROSS APPLY
(
SELECT #Latitude AS latpoint,
#Longitude AS longpoint,
100 AS radius,
111.045 AS distance_unit
) AS p
WHERE pm_PropertyName LIKE '%' + 'propertyname' + '%'
AND pm_Latitude BETWEEN p.latpoint - (p.radius / p.distance_unit) AND p.latpoint + (p.radius / p.distance_unit)
AND pm_Longitude BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint)))) AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
ORDER BY pm_Distance;
What this code does is it searches in a table for the closest property given a specific lat and long.
My question is. Is this the most efficient way of calculating distance in SQL?

Convert HHH:MM:SS to seconds

From the source database, I am getting HH:MM:SS as 832:24:12
Currently I am using below statement which is working fine for most of the cases hh:mm:ss but it fails when hours are more than 99
ISNULL(LEFT(COLUMN,2) * 3600 + RIGHT(LEFT(COLUMN,5),2) * 60 + RIGHT(COLUMN, 2) ,0)
Just another option with a small tweak to your original
Example
Declare #V varchar(50) = '832:24:12'
Select (left(#V,charindex(':',#V)-1)*3600) + (left(right(#V,5),2)*60) + right(#v,2)
Returns
2996652
You can use a tricky solution using PARSENAME() function.
DECALRE #Hours INT = 0, #Minutes INT = 0 , #Seconds INT = 0
SELECT #Hours = PARSENAME(REPLACE('832:24:12'+':00', ':', '.'),4),
#Minutes = PARSENAME(REPLACE('832:24:12'+':00', ':', '.'),3),
#Seconds = PARSENAME(REPLACE('832:24:12'+':00', ':', '.'),2)
SELECT #Hours * 3600 + #Minutes * 60 + #Seconds as TotalSeconds
I am replacing ':' with '.' character after appending dummy sequence of characters ':00' for PARSENAME() function to work by splitting into delimitted data.
For table query
SELECT PARSENAME(REPLACE(ISNULL(ColumnName + ':00',0), ':', '.'),4) * 3600 +
PARSENAME(REPLACE(ISNULL(ColumnName + ':00',0), ':', '.'),3) * 60 +
PARSENAME(REPLACE(ISNULL(ColumnName + ':00',0), ':', '.'),2) As TotalSecs
FROM TableName
This of a guess, however...
CREATE TABLE #Test (TimeString varchar(10))
INSERT INTO #Test
VALUES ('832:24:12')
SELECT TimeString,
(LEFT(TimeString, H.CI - 1) * 3600) + (SUBSTRING(TimeString,H.CI +1, M.CI - H.CI -1) * 60) + (RIGHT(TimeString, LEN(TimeString) - M.CI))
FROM #Test T
CROSS APPLY (VALUES(CHARINDEX(':',TimeString))) H(CI)
CROSS APPLY (VALUES(CHARINDEX(':',TimeString, H.CI+1))) M(CI);
DROP TABLE #Test;
Hours can be the leftwards chars minus 6 positions to take into account the positions for minutes and seconds in the string (:##:##).
The minutes can accessed by taking the left 2, of the rightmost 5 chars.
The seconds are the right 2 chars.
Ex:
DECLARE #tempval varchar(100) = '832:24:12'
SELECT LEFT(#tempval, LEN(#tempval) - 6) * 3600
+LEFT(RIGHT(#tempval, 5), 2) * 60
+RIGHT(#tempval, 2)
Returns
2996652

Convert decimal minutes to hh:mm:ss

I need to convert a value for example 2.54 that comes in minutes to a format like hh:mm:ss.
the value could be also zero.
DECLARE #f DECIMAL(6,2) = 2.54
SELECT CAST(DATEADD(SECOND, 60 * ROUND(#f, 0, 1) + 100 * (#f % 1), 0) AS time(0));
#f=2.54 -> 00:02:54
#f=330.42 -> 05:30:42
How it works:
ROUND(#f, 0, 1) - minutes; take only the integer part, discarding everything after the decimal point
MS Docs ROUND
100 * (#f % 1) - seconds; take the remainder of the integer division by 1
MS Docs %(Modulus)
DATEADD(SECOND, X, 0) equivalent to DATEADD(SECOND, X, '1900-01-01 00:00:00')
MS Docs DATEADD
CAST(X to time(0)) - trim date from DATETIME
MS Docs CAST
You can try like this
DECLARE #f DECIMAL = 2.54;
SELECT CONVERT(TIME(0), DATEADD(MINUTE, 60*#f, 0));
Gives result as
02:32:00
This is one of the solutions:
select
2.54 as NumericTime
,floor(2.54) as Minutes
,(2.54-floor(2.54))*100 as Seconds
,cast('00:'+cast(floor(2.54) as varchar)+':'
+cast((2.54-floor(2.54))*100 /* or 60 if this is common format */ as varchar) as time) as FullTime
But I really don't like all this additional CASTs. Maybe someone can provide better way.
I think I found it, what do you think? not very elegant but it's work.
DECLARE #number DECIMAL(12,4) = 2.54
SELECT CASE
WHEN #number >= 60 THEN CONVERT(VARCHAR(50), FLOOR(FLOOR(#number) / 60)) + ':' + CONVERT(VARCHAR(10), (FLOOR(#number) % 60)) + ':' + CONVERT(VARCHAR(10), FLOOR((#number-floor(#number)) * 60))
ELSE '00:' + CONVERT(VARCHAR(50), FLOOR(#number)) + ':' + CONVERT(VARCHAR(50), FLOOR((#number - floor(#number)) * 60))
END
Try this
SELECT Convert(time(0),CONVERT(datetime, DATEADD(MINUTE, 60*#f, 0)));
Try this:
DECLARE #Time DECIMAL(4,2) = 3.07
SELECT CAST(floor(#Time) AS VARCHAR) + ':'
+ REPLACE(REPLICATE('0',5 - LEN(CAST(#Time%1*100 AS VARCHAR)))
+ CAST(#Time%1*100 AS VARCHAR),'.',':');
This will also handle the corner cases where the Time is 2.05 sec, 4.09 sec etc.

Convert signed int to string ip address in SQL Server

I'm retrieving a signed int from a SQL Server database and need to convert it to a "normal" looking dotted string for display to users.
Googling, I found this code:
SELECT
dbo.IPADDRESS.IPADDRESS,
CAST(ROUND( (cast(dbo.IPADDRESS.IPADDRESS as bigint) / 16777216 ), 0, 1) AS varchar(4)) + '.' +
CAST((ROUND( (cast(dbo.IPADDRESS.IPADDRESS as bigint) / 65536 ), 0, 1) % 256) AS varchar(4)) + '.' +
CAST((ROUND( (cast(dbo.IPADDRESS.IPADDRESS as bigint) / 256 ), 0, 1) % 256) AS varchar(4)) + '.' +
CAST((cast(dbo.IPADDRESS.IPADDRESS as bigint) % 256 ) AS varchar(4)) as IPDottedNotation
FROM
dbo.IPADDRESS
which works some of the time, but produces wacky output other times. For example, converting this -1951276725 yields the result -116.-78.-30.-181.
Any suggestions? Thanks.
DECLARE #IPADDRESS TABLE (
IPADDRESS INT);
INSERT INTO #IPADDRESS
VALUES (-1139627840),
( 1);
SELECT
LTRIM(CAST(SUBSTRING(IP,4,1) AS TINYINT)) + '.' +
LTRIM(CAST(SUBSTRING(IP,3,1) AS TINYINT)) + '.' +
LTRIM(CAST(SUBSTRING(IP,2,1) AS TINYINT)) + '.' +
LTRIM(CAST(SUBSTRING(IP,1,1) AS TINYINT))
FROM #IPADDRESS
CROSS APPLY (SELECT CAST(IPADDRESS AS BINARY(4))) C(IP)
The code you have would work if IPADDRESS was a bigint (effectively storing the unsigned int representation in the database - i.e. all values > 0). Do you have the option of changing the datatype in the table?
To get what you have to work, you need to convert your signed int to the equivalent unsigned int before the conversion to bigint. I'm not sure what the most efficient way to do this in TSQL is, but it might be to cast it to binary:
SELECT dbo.IPADDRESS.IPADDRESS,
CAST(ROUND( (cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint) / 16777216 ), 0, 1) AS varchar(4)) + '.' +
CAST((ROUND( (cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint) / 65536 ), 0, 1) % 256) AS varchar(4)) + '.' +
CAST((ROUND( (cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint) / 256 ), 0, 1) % 256) AS varchar(4)) + '.' +
CAST((cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint) % 256 ) AS varchar(4)) as IPDottedNotation
Like #Ed Harper stated that the selected solution doesn't work for a signed int. Below is my solution which requires a little less casting and isn't inverted. Check out the following test scenario shown below where the converted string/varchar IP should be 192.168.18.188:
CREATE TABLE #data
(
ip NVARCHAR(45),
before NVARCHAR(45)
)
INSERT INTO #data
VALUES ('converted-ip','-1139627840')
update #data
set ip = cast((cast(before as int) & 255) as nvarchar) + '.' +
cast((cast(floor(convert(decimal, before)/256) as int) & 255) as nvarchar) + '.' +
cast((cast(floor(convert(decimal, before)/65536) as int) & 255) as nvarchar) + '.' +
cast((cast(floor(convert(decimal, before)/16777216) as int) & 255) as nvarchar)
select * from #data

Resources