Divide by zero error in stored procedure - sql

Hi i executed the following stored procedure in .net web application. Then run the application. I got this error
" Divide By zero error "
Stored procedure:
CREATE procedure Details(#Stringtext varchar(8000),#SearchStringtext varchar(100))
as begin
SELECT ({fn LENGTH(#Stringtext)}-
{fn LENGTH({fn REPLACE(#Stringtext, #SearchStringtext, '')})})/
{ fn LENGTH(#SearchStringtext)}AS String_Count
end

Evidently:
{ fn LENGTH(#SearchStringtext)}
... is evaluating to zero.

The length of the SearchStringText is Zero and hence there is divide by zero error.
Make sure that when the function is called, the string is of non-zero length.
Alternatively check for length before doing the select

{ fn LENGTH(#SearchStringtext)}
is evaluating to 0.
However, why is this a stored procedure? You are not using any db feature? Unless this is a simplified problem , all this (length, replace etc) could be done in your .net application

If SearchStringtext is empty, the length of it becomes 0. Thus the stored procedure tries to divide by zero (which is an undefined thing to do).
In other words the following part becomes zero:
{ fn LENGTH(#SearchStringtext)}
You might want to add some logic (if statement perhaps) to prevent the division to happen if the SearchStringtext is empty.

The only division operation in this procedure, has fn LENGTH(#SearchStringtext) as the divisor.
Hence it seems that length of **SearchStringtext** is evaluating to zero. It might be possible that you are trying to search an Empty string.
Please check and then elaborate the question details, along with the DB platform.

It seems that the length of SearchStringtext is 0 -- so the procedure tries to divide by zero.

Related

how to convert this String to Decimal

i have this String '5666,232343' and i want to convert it to Decimal, i use cast('5666,232343' as decimal(7,5)) but it returns NULL value.
Do you know why it doesn't work with CAST
Zorkolot is right. The current precision and scale that you've used is not sufficient for the value you've provided.
If you're using SQL Server 2012 or higher and you want to keep the comma in the value, then you can use the TRY_PARSE function and set a culture. It will return NULL if it encounters an error instead of not completing the statement and returning red text. This also allows you to add basic error handling to the statement, if you wanted, by getting failed conversions to return the value of zero. For example:
This is your original query (which is currently erroring) with my error handling fix:
select coalesce(try_parse('5666,232343' as decimal(7,5) using 'en-GB'),'0') as [DecimalValue]
This is the same thing as above but I've amended the decimal precision and scale so that the value is successfully converted:
select coalesce(try_parse('5666,232343' as decimal(16,6) using 'en-GB'),'0') as [DecimalValue]
This should prevent you having to perform a REPLACE either manually or by using the SQL function.
You need to cast to a decimal that can hold the value of 5666.232343.
DECIMAL(7,5) allows numbers in this format: ##.#####. The biggest number you can have then is 99.99999. You also need to take the comma out and replace it with a period:
SELECT CAST('5666.232343' as decimal(16,6)) AS [DecimalValue]
The problem is probably the comma. In some databases, some of the functions are not as internationally-sensitive as (I think) they should be. So try:
cast(replace('5666,232343', ',', '.') as decimal(7, 5))

SQL CLR Aggregate function Error Handling

I have a user defined CLR aggregate function that can potentially throw an error. I would like to know how to handle an error if one occurs in my query.
The function is performing an IRR calculation similar to that which Excel does, ie. an iterative root-finding calculation. If no root is found, an error is thrown. This is the error I need to handle.
The query is part of a larger stored procedure and it looks something like:
select
MyID,
Excel_XIRR(col1)
from #t
group by MyID
and the error i get is something like this:
A .NET Framework error occurred during execution of user-defined routine or aggregate "Excel_Xirr":
System.ArgumentException: Not found an interval comprising the root after 60 tries, last tried was (-172638549748481000000000.000000, 280537643341281000000000.000000)
System.ArgumentException:
at System.Numeric.Common.rfindBounds#59(FastFunc`2 f, Double minBound, Double maxBound, Double precision, Double low, Double up, Int32 tries)
at System.Numeric.Common.findBounds(FastFunc`2 f, Double guess, Double minBound, Double maxBound, Double precision)
at System.Numeric.Common.findRoot(FastFunc`2 f, Double guess)
at Excel_Xirr.Terminate()
My problem is that not all the rows cause this error. There are some legitimate results from the query that I want to capture and use later in my stored procedure. Will this error stop me from getting the results of the query? If so, is there a way to figure out which rows throw the error (dynamically) and then rerun the query for the rest of the rows?
Not sure how well you have coded the XIRR function itself, looking at your function prototypes in Error messages it would seem you are using a Bi-section method of finding roots which is not most suitable to algorithms to use when it comes to finding rates. You will be locking yourself within a lower and upper bound no matter how large this bound is it is not going to help for all cases
As for solving your immediate problem with handling the error, you can change your .net code and replace the Throw...Exception statement with a return value of Math.Pow(-1, 0.5)
This will return a NAN to the calling program which you can then check with an IF statement to confirm whether your XIRR value is a number (when IRR is found) or a NAN value (when IRR is not found)

qt select not working with where statement

I'm using qt 4.8 and psql driver to connect to a postgres 9.1 database.
I'm doing a generic library to connect and insert into the database; almost all methods are ready but in the last one, I need to do a select from a table to insert values into another. When I try the select statement it behaves different. According to the code in turn but no one of the tests I made have resulted in a correct solution.
Here's my code:
struct enfriadores enf;
enf.horaE=time(&enf.horaE);
enf.horaS=time(&enf.horaS)+1900;
//base1.insertaEvento(db,enf);
QString consulta = "Select id_evento from eventos where extract(epoch from horae)=:hora_bus";
QDateTime hora_bus(QDateTime::fromTime_t(enf.horaE));
//qDebug()<< enf.horaE;
QSqlQuery query(db);
query.prepare(consulta);
query.bindValue(":hora_bus",hora_bus);
query.exec();
query.first();
while(query.next())
{
int valor = query.value(0).toInt();
qDebug() << valor << endl;
}
The base1.insertaEvento is a call from a class I did to insert data on the table where afterwards I'll need to extract the id. The
qDebug() << enf.horaE;
I put it to know if the time was in the right form before I attached it to the query, which by the way, was correct.
horaE is taken from a struct I have declaed in the previously mentioned class.
When I run the query as it is with the while(query.next()) it runs good but returns no results and if I delete the while loop but still maintain the query.next() compiler returns
QSqlQuery::value: not positioned on a valid record
0
I tried using the query.first() method and the query.setForwardOnly(true) but with same results.
Also if I try the value of hora_bus with qDebug() and replace it directly in the psql console I get a positive match so the problem is not in the way data is inserted or formatted, it's in the way the query is retrieved I believe but do not know how to resolve this
Any ideas?
Thanks
The SQL expression extract(epoch from horae) produces a number of seconds since 1/1/1970 so so that's what should be passed to the parameter :hora_bus.
The QDateTime::fromTime_t(enf.horaE) indicates that enf.horaE has this value, however instead of passing ot to the query, it's passing a QDateTime object whose text representation is probably going to be a string with year,month,etc... that can't be compared to a number of seconds.
So try this instead:
query.bindValue(":hora_bus",enf.horaE);
Also the code shouldn't ignore the boolean return values of prepare() and exec(). You don't want to try looping within results when the execution of the query has failed.
EDIT1:
indeed when passing a QDateTime set to today to a prepared query similar to yours, QSqlQuery::exec() returns false with an SQL error invalid input syntax for type double precision.
EDIT2: it appears QVariant doesn't support being initialized with a long so an explicit cast to a different supported type is necessary. I've chosen qlonglong for a safe larger value:
query.bindValue(":hora_bus",(qlonglong)enf.horaE);
Tested, it worked for me.
http://qt-project.org/doc/qt-4.8/qsqlquery.html#details
At the very end of the documentation it mentions the following:
Warning: You must load the SQL driver and open the connection before a QSqlQuery is created. Also, the connection must remain open while the query exists; otherwise, the behavior of QSqlQuery is undefined.
If the connection to the database is timing out, or one of the variables you are using goes out of scope, you might disconnect early and get undefined results.
You can also check the return values on most of your function calls to see if they were successful or not.
Hope that helps.

ISNUMERIC('07213E71') = True?

SQL is detecting that the following string ISNUMERIC:
'07213E71'
I believe this is because the 'E' is being classed as a mathmatical symbol.
However, I need to ensure that only values which are whole integers are returned as True.
How can I do this?
07213E71 is a floating number 7213 with 71 zeros
You can use this ISNUMERIC(myValue + '.0e0') to test for whole integers. Slightly cryptic but works.
Another test is the double negative myValue NOT LIKE '%[^0-9]%' which allows only digits 0 to 9.
ISNUMERIC has other issues in that these all return 1: +, -,
To nitpick: This is a whole integer. It is equivalent to 7213 * 10 ^ 71.
In the documentation it says
ISNUMERIC returns 1 when the input expression evaluates to a valid integer, floating point number, money or decimal type; otherwise it returns 0. A return value of 1 guarantees that expression can be converted to one of these numeric types.
Your number is also float (with exponential notation), therefore the only way to have ISINTEGER is to define it yourself on SQL. Read the following link.
http://classicasp.aspfaq.com/general/what-is-wrong-with-isnumeric.html
Extras:
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=59049
http://www.tek-tips.com/faqs.cfm?fid=6423
I have encountered the same problem. IsNumeric accepts "$, €, +, -, etc" as valid inputs and Convert function throws errors because of this.
Using "LIKE" SQL statement fixed my problem. I hope it'll help the others
SELECT UnitCode, UnitGUID, Convert(int, UnitCode) AS IntUnitCode
FROM [NG_Data].[NG].[T_GLB_Unit]
WHERE ISNULL(UnitType,'') <>'Department'
AND UnitCode NOT LIKE '%[^0-9]%'
ORDER BY IntUnitCode
PS: don't blame me for using "UnitCode" as nvarchar :) It is an old project :)
You have to ensure it out of the call to the database, whatever the language you work with, and then pass the value to the query. Probably the SQL is understanding that value as a string.

Informix: The meaning of dot (.)?

I am wondering if anyone could tell me any special meaning of the dot (.) in Informix regarding expressions and etc.
For example in stored procedures I see it used with integers, decimals and chars and one thing that is bugging me quite a lot is this:
if value = '.' then
//do something
end if
The above expression validates to true when value is of type numeric (5,1) and it is equal to 0.0
I have tried looking around and I can't find information on how a dot is treated but it seems " 0.0 = '.' " validates to true.
Can you show the data types and a working stored procedure that illustrates the problem?
There isn't supposed to be any special meaning to dot in that context. It is a string, and no numeric value should be equal to it; if the number is converted to a string, there will be either nothing (for NULL) or at least one digit, neither of which is the same as the string '.', and if the string '.' is converted to a number, that conversion should fail (arguably when the procedure is created, certainly at runtime).
One thing that puzzles me is that the syntax you are showing is not SPL syntax. SPL does not use 'end if', though I4GL does. Indeed, SPL (stored procedure language) only uses END in conjunction with a matching BEGIN.
It appears that my memory is failing and that I should not try reading manuals just before midnight.
It also appears that this code does what I would not expect...
+ set debug file to "/tmp/x1";
SET DEBUG FILE TO: Rows processed = 0
+ drop procedure so2139024();
DROP PROCEDURE: Rows processed = 0
+ create procedure so2139024() returning int as rv;
define value numeric(5,1);
define rv integer;
trace on;
let rv = 0;
let value = 0.0;
if value = '.' then
let rv = 1;
end if;
return rv;
end procedure;
CREATE PROCEDURE: Rows processed = 0
+ execute procedure so2139024();
1
EXECUTE PROCEDURE: Rows processed = 1
So, for some reason, the comparison is working; the value zero compares equal to dot. This was tested on MacOS X 10.6.2 with IBM Informix Dynamic Server 11.50.FC6 (and SQLCMD 86.04, built with CSDK 3.50.FC4, but running with 3.50.FC6).
The debug file contains:
trace on
expression:(= value, ".")
evaluates to t
let rv = 1
expression:rv
evaluates to 1
procedure so2139024 returns 1
iteration of cursory procedure so2139024
A priori, this should be reported via IBM/Informix Tech Support. I think it is most likely a bug of some sort, but I don't know how it is coming up with the answer. I will check through back-door channels too.
Back-door channels show that the likely problem is that the function deccvasc() in the ESQL/C library (also used internally by the server) is mishandling the string '.'.
The ESQL/C test code here shows that:
#include <stdio.h>
#include "dumpesql.h"
int main(void)
{
dec_t d;
int rc = deccvasc(".", 1, &d);
printf("rc = %d\n", rc);
dump_decimal(stdout, "Decimal", &d);
return(0);
}
The dump_decimal() function is non-standard, but prints information from the decimal structure. The output is:
rc = 0
DECIMAL: Decimal -- address 0x7FFF5FBFF090
E: -64, S = 1 (+), N = 0, M = value is ZERO
Consequently, the server is (mistakenly) accepting '.' as a valid representation of zero, rather than getting an error reported. For the time being, you will have to edit the stored procedure to make more sense - it is not clear what the test was supposed to achieve, but it clearly isn't written correctly. (That is not denying that there is also a bug in the server.) Please report this to IBM/Informix Technical Support.