Invalid floating point operation with CTE - sql

I'm getting An invalid floating point operation occurred error with this code.
It's telling me that the problem is on line where the CTE starts.
If I don't have the SQRT function, then everything work fine, but as soon as I add the SQRT I get the error.
What I'm trying to do is to get rid of the negative by squaring the number.
declare #start_date date, #end_date date
set #start_date = '2012/01/01'
set #end_date = '2012/12/31';
with tbl1
as
(
select
strata,
entranceID,
sum(count)/count(*) as AverageCount
from
train
where
surveydate between '2012/01/01' and '2012/12/31'
group by
strata,
entranceID
)
select
a.jobnumber,
a.strata,
a.EntranceID,
Count,
b.AverageCount,
count - AverageCount
, CASE WHEN AverageCount = 0 then 0
ELSE SQRT(count - AverageCount)
END as A

In the expression:
SQRT(count - AverageCount)
The value of count has to be >= AverageCount.
This may not be true for your test data.
Consider using :
SQRT (ABS(count - AverageCount))
Instead, If that makes sense in your case.

Related

Same query but different result when ran in different database servers

I have a local environment running MariaDB server version 10.2.14 and a production environment running MariaDB server version 10.1.40.
When running a calculation based on the haversine formula to calculate distance between 2 geolocations, my local environment returns 0 as the result, but the prod environment returns null.
A sample query is below:
select (acos(cos(radians((41.480473))) * cos(radians(41.480473)) *
cos(radians((-81.630990)) - radians(-81.630990)) +
sin(radians((41.480473))) * sin(radians(41.480473))) * 3958.755
) as distance
The result should be zero because it is essentially trying to get the distance between 2 locations with the same geolocation info.
Can anyone shed some light why my prod environment is giving me a null value when running the above sample instead of zero?
The difference comes from rounding errors for the outmost acos-function. The other system may give you exactly 1 while the other system may give you bit over 1 due to rounding errors. Valid parameters for acos are from 1 is 0 and acos value > 1 is NULL.
You can use ROUND before the outmost acos and make the calculation a function for easier use:
create function f_distance_in_miles(
in_lat1 decimal(9,7),
in_long1 decimal(9,7),
in_lat2 decimal(9,7),
in_long2 decimal(9,7)
)
returns float
deterministic
begin
declare v_i real;
set v_i = cos(radians(in_lat1)) * cos(radians(in_lat2)) * cos(radians(in_long1)
- radians(in_long2))
+ sin(radians(in_lat1)) * sin(radians(in_lat2));
if (v_i<-1) then
set v_i = -1;
elseif (v_i>1) then
set v_i = 1;
end if;
return acos(v_i)*3958.755;
end
And then use it like:
select f_distance_in_miles(41.480473, -81.630990, 41.480473, -81.630990)

Percentage of two values returning NULL

Same as yesterdays question which has been answered successfully but different problem. I have two values, 1 and 0 for which I need to calculate the percent change. Based on this website http://www.percent-change.com/index.php?y1=1&y2=0 the percent change between 1 and 0 is -100%. Based on the suggested formula which is (((y2- y1))/ y1) my code looks like this.
DefinedYearVSPriorYearIndividual = ((( CTEDefinedYear.IndividualCases - CTEPreviousYear.IndividualCasesLastYear ))
/ ( CTEPreviousYear.IndividualCasesLastYear ) ) * 100
which returns NULL.
The two numbers are
CTEDefinedYear.IndividualCases = 1
CTEPreviousYear.IndividualCasesLastYear = 0
The desired result should be -100%.
Can anybody see what I'm doing wrong?
Here is the answer.
Declare #y1 as int =1;
Declare #y2 as int =0;
select (((#y2- #y1))/ #y1)*100
Output is -100. You missed the *100 part.
In your case, You switched variables. attached formula is right one.
select ((0 - 1) / 1)*100;
But you used select ((1 - 0) / 0)*100;
so, you will get an error:
Msg 8134, Level 16, State 1, Line 1
Divide by zero error encountered.
You have to handle 0 in the division side, with CASE logic, to avoid divide by zero error.
DECLARE #CTEDefinedYear_IndividualCases INT = 1
DECLARE #CTEPreviousYear_IndividualCasesLastYear INT = 0
SELECT ((#CTEDefinedYear_IndividualCases - #CTEPreviousYear_IndividualCasesLastYear) / (CASE WHEN #CTEPreviousYear_IndividualCasesLastYear = 0 THEN 1 ELSE #CTEPreviousYear_IndividualCasesLastYear END)) * 100
Got it to work with this code.
DefinedYearVSPriorYearIndividual = ISNULL(100.0 *
(ISNULL(CTEDefinedYear.IndividualCases,0)
- ISNULL(CTEPreviousYear.IndividualCasesLastYear,0))
/ NULLIF(CTEPreviousYear.IndividualCasesLastYear,0),0)

Table used in cursor select is restructured from compile-time to run-time

I'm getting CALL Failed. [7691] SP_name:Table used in cursor select is restructured from compile-time to run-time.
I believe its because I have loop over dates in my stored procedure:
If min_mnth <= max_mnth THEN
LoopMnth:
FOR cc_mnth AS cc_cdates CURSOR FOR
SELECT To_Char(calendar.calendar_date, 'yyyy-mm') as mnth
from sys_calendar.calendar
where To_Char(calendar.calendar_date, 'yyyy-mm') between min_mnth and max_mnth
and mnth not in (select report_mnth from tb1)
and mnth >= '2017-08'
group by 1 order by 1
.....
Interesting fact, that that such procedure sometimes work, mostly then I had less loop iterations.
I have found only this relevant information https://community.teradata.com/t5/Database/Error-7691-P1-Table-used-in-cursor-select-is-restructured-from/td-p/36691
They suggests SET SESSION DATEFORM = INTEGERDATE - same error.
What is this error about and how to fix it?
Then you get such error, just
1) SET SESSION DATEFORM = INTEGERDATE
2) Recreate your procedure

SQL - Why does the ordering matter for this select?

I ran the below code and got the following error;
Conversion failed when converting the varchar value '1.5' to data type int
BEGIN -- first update to check Interface held SMR and Interface held SMA
update interface set INTERR = 'U7'
from interface i
where
i.conttype = 'SMR'
and isnumeric(i.contrate)=1
and cast(i.contrate as decimal(12,2)) < 5
and caseno = #caseno
and exists (
select 1
from interface i2
where i2.caseno = #caseno
and i2.conttype = 'SMA'
and i2.intmembno = i.intmembno
and i2.effdte = i.effdte
and i2.contrate > cast(0 as decimal(12,2))
and isnumeric(i2.contrate)=1
)
In this example SMR = 5 and SMA = 1.5 and both values have been declared as Numerics. However by switching around the ordering of the clauses the error stops occuring and the stored procedure continues on as it should (see below)
BEGIN -- first update to check Interface held SMR and Interface held SMA
update interface set INTERR = 'U7'
from interface i
where
i.conttype = 'SMR'
and isnumeric(i.contrate)=1
and cast(i.contrate as decimal(12,2)) < 5
and caseno = #caseno
and exists (
select 1
from interface i2
where i2.caseno = #caseno
and isnumeric(i2.contrate)=1 -- This was moved up
and i2.conttype = 'SMA'
and i2.intmembno = i.intmembno
and i2.effdte = i.effdte
and i2.contrate > cast(0 as decimal(12,2))
)
Can you help me understand why the ordering matters? Normally it doesn't and shouldn't, as far as I know.
Thanks!
Paul
WHERE conditions are not executed in any particular order. This is even true when using subqueries and CTEs -- the optimizer rearranges processing and for good reason.
And, using implicit conversion is dangerous -- as you are finding. So, use explicit conversions and do:
where i.conttype = 'SMR' and
try_cast(i.contrate as decimal(12,2)) < 5 and
caseno = #caseno and
exists (select 1
from interface i2
where i2.caseno = #caseno and
i2.conttype = 'SMA' and
i2.intmembno = i.intmembno and
i2.effdte = i.effdte and
try_cast(i2.contrate as decimal(12,2)) > 0
)
Notes:
You do not have to check isnumeric().
There is no need to cast a constant such as 0 for the comparison.
You can do similar things with a case in pre-2012 versions of SQL Server.

Set Date from another table in SQL Server

I have a code in VB.Net application which I would like to move to stored procedure.
VB code looks something like this :
if(id == 3)
{
var year = Year(invoiceDate)
updatedDate = DateSerial(dueYear, DueDateMonth, DueDateDay)
If updatedDate < invoiceDate Then
updatedDate += 1
updatedDate = DateSerial(updatedDate , getMonthFromDBTable, getDayFromDBTable)
End If
}
This is part of a condition which I am trying to resolve.
Currently in SQL I have the following
DECLARE #tmpCalendarDate DATETIME;
DECLARE #tmpYear int;
SET #tmpCalendarDate = convert(varchar(10), getdate(),120);
SET #tmpYear = DATEPART(yyyy, #tmpCalendarDate);
SELECT COALESCE (
CASE WHEN tt.ID = 1 THEN DATEADD(day, t.DaysUntilDue, r.InvoiceDate) END,
CASE WHEN tt.ID = 3 THEN -- This is where I need to add the condition.
I was thinking of setting the #tmpCalendarDate with the values to look something like
CASE WHEN tt.ID = 3 THEN #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay'
where t is a table.
This value cannot be changed, so I would rather calculate and fetch it once rather than calculating it every time binding changes (wpf application).
Any help is greatly appreciated.
UPDATE: I realized maybe I am vague with my question, so here it is
How do i set #tmpCalendarDate? I tried
SELECT #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay' FROM table t
and I get an error 'Conversion failed when converting date and/or time from character string.' Instead I am expecting something like #tmpCalendarDate to be set to '2016-03-12'
Also, can I add an If..Else condition inside CASE.Then
In my example:
CASE WHEN tt.ID = 3 THEN #tmpCalendarDate = '#tmpYear-t.DueDateMonth-t.DueDateDay'
IF (#tmpCalendarDate > InvoiceDate)
BEGIN
--Do some logic
END
ELSE
--Do some logic
BEGIN
END
You can use DATEFROMPARTS
#tmpCalendarDate = DATEFROMPARTS(#tmpyear, t.DueDateMonth, t.DueDateDay)
Your mistake in your original attempt is you are setting #tempCalendarDate to actual string #tmpYear-t.DueDateMonth-t.DueDateDay which results in a conversion error.