Simple Math Stored Procedure Returning NULL? - sql-server

I would appreciate if someone could let me know why this stored procedure returns NULL (I am using SQL Server 2005)? Thanks for the help.
CREATE PROCEDURE calc_runningtotal_averageprice_realisedpl
#filled_size REAL,
#reported_execution REAL,
#old_running_total REAL,
#old_average_price REAL,
#new_running_total REAL OUTPUT,
#new_average_price REAL OUTPUT,
#realised_pl REAL OUTPUT
AS
BEGIN
SET #new_running_total = #old_running_total + #filled_size
SET #realised_pl = 0
IF SIGN(#filled_size) = SIGN(#old_running_total)
BEGIN
SET #new_average_price = (#filled_size * #reported_execution + #old_running_total * #old_average_price) / (#new_running_total)
END
ELSE
BEGIN
DECLARE #quantity REAL
IF ABS(#reported_execution) < ABS(#old_running_total)
SET #quantity = ABS(#reported_execution)
ELSE
SET #quantity = ABS(#old_running_total);
SET #realised_pl = (#reported_execution - #old_average_price) * #quantity * SIGN(#filled_size) * -1;
SET #new_average_price =
CASE
WHEN ABS(#filled_size) < ABS(#old_running_total) THEN #old_average_price
WHEN ABS(#filled_size) = ABS(#old_running_total) THEN 0
WHEN ABS(#filled_size) > ABS(#old_running_total) THEN #reported_execution
END
END
END
IF I run the following, I get 3 NULLS
DECLARE #new_running_total REAL
DECLARE #new_average_price REAL
DECLARE #realised_pl REAL
EXEC calc_runningtotal_averageprice_realisedpl 1, 1, 2, 2, #new_running_total, #new_average_price, #realised_pl
SELECT #new_running_total, #new_average_price, #realised_pl
I am expecting something like 3, 1.66666, 0

You are simply not decorating the output parameters in the call with OUTPUT:
EXEC calc_runningtotal_averageprice_realisedpl 1, 1, 2, 2,
#new_running_total OUTPUT,
#new_average_price OUTPUT,
#realised_pl OUTPUT

Related

EXECUTE sp_executesql not working in SQL Server

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

T-SQL Function to Throw error

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.

How to write these kind of functions in solr data config.xml

CREATE OR REPLACE FUNCTION page(IN i_app name character varying, IN i_photo_id big int, IN i_page integer, IN i_member_id big int, OUT o_similar_page_name character varying, OUT o_similar_page_id big int, OUT o_similar_photo_id big int[])
DECLARE
v_limit INTEGER := 4;
v_offset INTEGER;
BEGIN
SET SEARCH_PATH = '';
v_start_time = DAYTIME();
i_app name = UPPER(i_app name);
IF i_app name <> 'DD' THEN
RAISE EXCEPTION 'Enter Valid Application Name';
END IF;
IF i_page = 1 THEN
v_offset := 0;
ELSE
v_offset := i_page * v_limit - v_limit;
END IF;
Please help me.
Answer
No.
Reason
Its not actually the purpose of SOLR. Functions has to be written in the DB level and the data that is retrieved out of query will be stored in SOLR for fast retrieval.
ALTERNATIVE SOLUTION
You can create the function and call it in the select statement to index the data into SOLR.
Note : Final results fetched out of functions can be stored in the SOLR.
Example:
CREATE FUNCTION CustomerLevel(p_creditLimit double) RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
DECLARE lvl varchar(10);
IF p_creditLimit > 50000 THEN
SET lvl = 'PLATINUM';
ELSEIF (p_creditLimit <= 50000 AND p_creditLimit >= 10000) THEN
SET lvl = 'GOLD';
ELSEIF p_creditLimit < 10000 THEN
SET lvl = 'SILVER';
END IF;
RETURN (lvl);
END
Query to used in SOLR for Indexing
SELECT CustomerLevel(123123123) as CustomerLevel from CustomerRating;

SQL parse text in field

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),',','')

Simple Firebird Query

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

Resources