I'm trying to implement a mechanism that would perform calculations based on dynamically defined algorithms. The way I do it is:
Build a string containing the definition of all the variables along with their values,
Fetch (from a table) the calculation formula,
Invoke sp_executesql.
Here is the contents of the string passed as the calculation (contents of variable #_l_Execute_Formula):
DECLARE #_1 FLOAT = 678;
DECLARE #_2 FLOAT = NULL;
DECLARE #_3 FLOAT = NULL;
SET #_l_Result = #_1 + #_2 + #_3
and the invocation is:
EXECUTE sp_executesql #_l_Execute_Formula ,
N'#_l_Result FLOAT OUTPUT' ,
#_l_Result = #_l_Result OUTPUT ;
I receive no error message but #_l_Result is NULL.
What am I doing wrong?
The sum of float values with NULL return NULL. You might want to escape NULL values.
DECLARE #_l_Execute_Formula NVARCHAR(MAX) = '
DECLARE #_1 FLOAT = 678;
DECLARE #_2 FLOAT = NULL;
DECLARE #_3 FLOAT = NULL;
SET #_l_Result = ISNULL(#_1, 0) + ISNULL(#_2, 0) + ISNULL(#_3, 0)'
DECLARE #_l_Result FLOAT
EXECUTE sp_executesql #_l_Execute_Formula ,
N'#_l_Result FLOAT OUTPUT' ,
#_l_Result = #_l_Result OUTPUT;
SELECT #_l_Result -- Result 678
Hello there I have a Function and is introduction a variable which will bring a letter or a number, if the variable is a letter it need to cause an error and return a 0, or if is a number then return 1.
SO in T-SQL I have a Procedure that eventually will call this function to check is is a number:
IF dbo.VALIDNUMBER(#sTxpX) != 0 AND #sTxpX IS NOT NULL
The variable #sTxpX is holding a value which is 'T' so I know it needs to return 0 from the function because is invalid to be a numeric, but Im not getting the proper function to build it, I will appreciate some help here.
CREATE FUNCTION DBO.VALIDNUMBER (#sTextStr VARCHAR(4000)) RETURNS BIT AS
BEGIN
DECLARE #bValidNumberStr BIT = 1; DECLARE #nTest BIGINT;
SET #nTest = CAST(#sTextStr AS numeric(38, 10)) + 1;
RETURN #bValidNumberStr;
EXCEPTION
WHEN OTHERS THEN
SET #bValidNumberStr = 0;
RETURN #bValidNumberStr;
END;
Try this function:
CREATE function [dbo].[VALIDNUMBER]
(#strText VARCHAR(4000))
RETURNS BIT
AS
BEGIN
DECLARE #Return as bit
IF TRY_CAST(#strText AS NUMERIC(38,10)) IS NOT NULL BEGIN
SET #Return = 1
END ELSE BEGIN
SET #Return = 0
END
RETURN #Return
END
Why can't you use the built-in SQL function? It's faster, and no need for you to drive yourself crazy to come up with a solution.
In your procedure do the following:
DECLARE #isNumber bit;
IF (ISNUMERIC(#sTextStr) = 1)
BEGIN
SET #isNumber = 1
END
ELSE
BEGIN
SET #isNumber = 0
RAISERROR(15600, 16, 20, 'That was not a number')
END
You can pass the #isNumber variable back to the user at a later point in time.
I am trying to parse a string using SQL but am too and still learning. I have text in a control or field 685 that is variable, but always the same format.
field 685 input
arr[hg19] 2q33.3q34(200,900,700-209,000,000)x2 xxx
Desired output
2:200900700-209000000
Basically, the # after the [hg19] but before the q (could also be a p) and the #'s in the () without the commas.
My attempt (though I'm not confident in it at all)
Thank you very much :).
SELECT PARSENAME(REPLACE('[685]', ' ', '.'), 2, 3, 4)
This works for me. The code should explain itself: solve using your knowledge of the input along with repeated use of CHARINDEX and SUBSTRING. You could combine this into one very long line of unreadable code, or use as is:
declare #s as varchar(100)
set #s = 'arr[hg19] 23q33.3q34(200,900,700-209,000,000)x2 xxx'
declare #ixBrace as integer; set #ixBrace = CHARINDEX(']',#s,0)
declare #ixP as integer; set #ixP = CHARINDEX('p',#s,#ixBRace)
declare #ixQ as integer; set #ixQ = CHARINDEX('q',#s,#ixBRace)
declare #ixPQ as integer; set #ixPQ = case when #ixP = 0 then #ixQ when #ixQ = 0 then #ixP when #ixP < #ixQ then #ixP else #ixQ end
declare #ixLParen as integer; set #ixLParen = CHARINDEX('(',#s,#ixPQ)
declare #ixMinus as integer; set #ixMinus = CHARINDEX('-',#s,#ixLParen)
declare #ixRParen as integer; set #ixRParen = CHARINDEX(')',#s,#ixMinus)
select SUBSTRING(#s,#ixBrace+1,#ixPQ-#ixBrace-1) + ':' +
REPLACE(SUBSTRING(#s,#ixLParen+1,#ixMinus-#ixLParen-1),',','') + '-' +
REPLACE(SUBSTRING(#s,#ixMinus+1,#ixRParen-#ixMinus-1),',','')
I'm not sure where the '2:' comes from so I guessed it came from the 'x2'
DECLARE #input VARCHAR(100) = 'arr[hg19] 2q33.3q34(200,900,700-209,000,000)x2 xxx'
SELECT SUBSTRING(#input,PATINDEX('%x[0-9]%',#input) + 1,CHARINDEX(' xxx',#input) - PATINDEX('%x[0-9]%',#input) - 1) + ':' +
REPLACE(SUBSTRING(#input,CHARINDEX('(',#input) + 1,CHARINDEX(')',#input) - CHARINDEX('(',#input) - 1),',','')
I am trying to do a while loop in Firebird to execute all the values from an SP using FlameRobin tool. However this is not working. Any suggestion?
declare i int = 0;
while ( i <= 2 ) do BEGIN
SELECT p.SOD_AUTO_KEY, p.CURRENCY_CODE, p.SO_CATEGORY_CODE, p.SO_NUMBER, p.INVC_NUMBER, p.ENTRY_DATE, p.SHIP_DATE, p.NEXT_SHIP_DATE, p.CONDITION_CODE, p.QTY_ORDERED, p.QTY_PENDING_INVOICE, p.QTY_INVOICED, p.UNIT_PRICE, p.EXCHANGE_RATE, p.UNIT_COST, p.ITEM_NUMBER, p.CONSIGNMENT_CODE, p.NOTES, p.STOCK_LINE, p.STM_AUTO_KEY, p.SERIAL_NUMBER, p.REMARKS, p.PN, p.PNM_AUTO_KEY, p.GR_CODE, p.CUSTOMER_PRICE, p.OPEN_FLAG, p.ROUTE_CODE, p.ROUTE_DESC, p.COMPANY_CODE, p.SITE_CODE, p.COMPANY_NAME, p.COMPANY_REF_NUMBER, p.CUST_REF, p.HOT_PART
FROM SPB_SALESHISTORY(i) p
i = i + 1;
end
Error Message I get:
Preparing query: declare i int = 0
Error: *** IBPP::SQLException ***
Context: Statement::Prepare( declare i int = 0 )
Message: isc_dsql_prepare failed
SQL Message : -104
can't format message 13:896 -- message file C:\Windows\firebird.msg not found
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 1, column 9
i
Total execution time: 0.004s
This is what I tried but it only says "Script Execution Finished" and does not return any results:
set term !!
EXECUTE BLOCK returns(p) AS
declare i integer = 0
BEGIN
while ( i <= 1000 ) do BEGIN
SELECT p.SOD_AUTO_KEY, p.CURRENCY_CODE, p.SO_CATEGORY_CODE, p.SO_NUMBER, p.INVC_NUMBER, p.ENTRY_DATE, p.SHIP_DATE, p.NEXT_SHIP_DATE, p.CONDITION_CODE, p.QTY_ORDERED,p.QTY_PENDING_INVOICE, p.QTY_INVOICED, p.UNIT_PRICE, p.EXCHANGE_RATE, p.UNIT_COST, p.ITEM_NUMBER, p.CONSIGNMENT_CODE, p.NOTES, p.STOCK_LINE, p.STM_AUTO_KEY, p.SERIAL_NUMBER, p.REMARKS, p.PN, p.PNM_AUTO_KEY, p.GR_CODE, p.CUSTOMER_PRICE, p.OPEN_FLAG, p.ROUTE_CODE, p.ROUTE_DESC, p.COMPANY_CODE, p.SITE_CODE, p.COMPANY_NAME, p.COMPANY_REF_NUMBER, p.CUST_REF, p.HOT_PART
FROM SPB_SALESHISTORY(i) p
i = i + 1
end
END !!
Mark,
I tried your suggestion however I got the following error:
set term!!;
EXECUTE BLOCK RETURNS (
SOD_AUTO_KEY Integer,
CURRENCY_CODE Char(3),
SO_CATEGORY_CODE Char(10),
SO_NUMBER Char(12),
INVC_NUMBER Char(12),
ENTRY_DATE Timestamp,
SHIP_DATE Timestamp,
NEXT_SHIP_DATE Timestamp,
CONDITION_CODE Varchar(10),
QTY_ORDERED Double precision,
QTY_PENDING_INVOICE Double precision,
QTY_INVOICED Double precision,
UNIT_PRICE Double precision,
EXCHANGE_RATE Double precision,
UNIT_COST Double precision,
ITEM_NUMBER Integer,
CONSIGNMENT_CODE Char(10),
NOTES Blob sub_type 1,
STOCK_LINE Integer,
STM_AUTO_KEY Integer,
SERIAL_NUMBER Varchar(40),
REMARKS Varchar(50),
PN Varchar(40),
PNM_AUTO_KEY Integer,
GR_CODE Varchar(10),
CUSTOMER_PRICE Double precision,
OPEN_FLAG Char(1),
ROUTE_CODE Char(1),
ROUTE_DESC Varchar(20),
COMPANY_CODE Varchar(10),
SITE_CODE Varchar(10),
COMPANY_NAME Varchar(50),
COMPANY_REF_NUMBER Varchar(30),
CUST_REF Varchar(15),
HOT_PART Char(1)
)
AS
declare i integer;
BEGIN
i=0;
while ( i <= 2 ) do
BEGIN
for SELECT SOD_AUTO_KEY,CURRENCY_CODE,SO_CATEGORY_CODE, SO_NUMBER,INVC_NUMBER,ENTRY_DATE, SHIP_DATE, NEXT_SHIP_DATE, CONDITION_CODE, QTY_ORDERED,QTY_PENDING_INVOICE, QTY_INVOICED, UNIT_PRICE, EXCHANGE_RATE, UNIT_COST,ITEM_NUMBER, CONSIGNMENT_CODE, NOTES, STOCK_LINE, STM_AUTO_KEY, SERIAL_NUMBER,REMARKS, PN, PNM_AUTO_KEY, GR_CODE, CUSTOMER_PRICE, OPEN_FLAG, ROUTE_CODE,ROUTE_DESC, COMPANY_CODE, SITE_CODE, COMPANY_NAME, COMPANY_REF_NUMBER, CUST_REF, HOT_PART
FROM SPB_SALESHISTORY (i)
into :SOD_AUTO_KEY, :CURRENCY_CODE, :SO_CATEGORY_CODE, :SO_NUMBER, :INVC_NUMBER,
:ENTRY_DATE, :SHIP_DATE, :NEXT_SHIP_DATE, :CONDITION_CODE, :QTY_ORDERED,:QTY_PENDING_INVOICE,
:QTY_INVOICED, :UNIT_PRICE, :EXCHANGE_RATE, :UNIT_COST, :ITEM_NUMBER, :CONSIGNMENT_CODE, :NOTES, :STOCK_LINE,
:STM_AUTO_KEY, :SERIAL_NUMBER, :REMARKS, :PN, :PNM_AUTO_KEY, :GR_CODE, :CUSTOMER_PRICE, :OPEN_FLAG, :ROUTE_CODE,:ROUTE_DESC,
:COMPANY_CODE, :SITE_CODE, :COMPANY_NAME, :COMPANY_REF_NUMBER, :CUST_REF,:HOT_PART
DO
suspend;
i = i + 1;
end
END!!
SET TERM;!!
Error:
Message: isc_dsql_prepare failed
SQL Message : -206
can't format message 13:794 -- message file C:\Windows\firebird.msg not found
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -206
Column unknown
I
At line 46, column 27
Total execution time: 0.005s
Based on your comments on the answer of Ain, it looks like you also want to return the selected values from the EXECUTE BLOCK. Your RETURNS (p) is invalid and will not work. You need to explicitly declare all columns you want to return, and you need to SUSPEND each row.
In addition you are also forgetting several statement terminators (;), and you can't declare the variable and its value together. The resulting execute block would be something like:
set term !!;
EXECUTE BLOCK returns (
SOD_AUTO_KEY INTEGER,
/* ... */
HOT_PART VARCHAR(255)
) AS
declare i integer;
BEGIN
i = 0;
while ( i <= 1000 ) do
BEGIN
FOR SELECT SOD_AUTO_KEY, /* ... */ HOT_PART
FROM SPB_SALESHISTORY(i)
INTO :SOD_AUTO, /* ... */ :HOT_PART
DO
SUSPEND;
i = i + 1;
end
END!!
SET TERM ;!!
I have left out some of the columns for brevity and guessed at their types.
No, you can't execute such scripts directly in Flamerobin's query window. I think simplest way would be to wrap your script into an stored procedure which you would drop after you're done with the result. To create the temp SP right-click on the Procedures node in the Flamerobin's database tree and select Create new - this creates the SP sceleton for you where you can insert your code.
You will need to wrap your stored procedure like code in a EXECUTE BLOCK statement.
Your sql script may be corrupted