Oracle Pro*C : Handling end of fetch cursor - c

I can't figure out the problem on my code :
/* Declare a cursor for the FETCH statement. */
EXEC SQL DECLARE customer_cursor CURSOR FOR
SELECT CUSTOMER_ID, CUSTOMER_NAME
FROM CUSTOMER_TABLE
WHERE CUSTOMER_CARD_NUM = :argv[1];
if ( sqlca.sqlcode != 0 )
{
printf("Declare cursor failed\n");
return( sqlca.sqlcode );
}
EXEC SQL OPEN customer_cursor;
if ( sqlca.sqlcode != 0 )
{
printf("Open cursor failed\n");
return( sqlca.sqlcode );
}
EXEC SQL WHENEVER NOT FOUND GOTO no_match;
for ( ;; )
{
/* Fetching data */
EXEC SQL FETCH customer_cursor
INTO :var_customer_id, :var_customer_name;
if ( sqlca.sqlcode != 0 )
{
EXEC SQL CLOSE cust_data_cursor;
return ( sqlca.sqlcode );
}
/* Doing some stuff here */
processing_customer();
}
EXEC SQL CLOSE customer_cursor;
/* Handling the no data found here */
no_match:
printf("NO CUSTOMER MATCHING THIS CARD_NUM\n");
/* Some stuff */
......
return 1;
My query is supposed to return just one row or nothing, when nothing is returned all is ok, but when ther's a matching, the function processing_customer is executed and the strange is that the no_match is executed too.
Thanks for helping me to fix that.

As #Roger Cornejo suggests, you need a way to not execute the 'no match' section if there is a match. no_match: is just a label so there's nothing to tell your code not to execute that section. You either need to return before that label, or goto something after it. You also need to close the cursor in the no-match scenario.
But this seems unnecessarily messy and as #Arion hinted you don't need an explicit cursor for this - just do a select into and catch the exception.
EXEC SQL SELECT CUSTOMER_ID, CUSTOMER_NAME
INTO :var_customer_id, :var_customer_name
FROM CUSTOMER_TABLE
WHERE CUSTOMER_CARD_NUM = :argv[1];
if (sqlca.sqlcode == 1403)
{
printf("NO CUSTOMER MATCHING THIS CARD_NUM\n");
/* Some stuff */
......
return 1;
}
if (sqlca.sqlcode != 0)
{
return ( sqlca.sqlcode );
}
/* Doing some stuff here */
processing_customer();
You've said there will be zero or one rows; if there are more than one you'll get a too-many-rows error (ORA-02112).

add GOTO after "EXEC SQL CLOSE customer_cursor;"

Change your label "no_match" to "no_more_records" and you'll realize why it runs 2 times:
a) when there are no records, the FETCH raises the NOT FOUND condition inmediatly and therefore will go to the label "no_more_records"
b) when there is one (or more) record(s), the FETCH is executed returning the first record.
Then the
if ( sqlca.sqlcode != 0 )
evaluates to false (in fact, only useful to trap other problems) and then
processing_customer();
After it, the FETCH run again (by the infinity for) and behave as in (a): no_more_records condition arrives.

Related

How to apply line break in the comment for snowflake procedures?

Trying to input line break in the comment section, but it failed to display row by row.
Examples: When execute the query below, the output of the comment should be followed by the format below. However, the comment becomes "FunctionName:IfElse\nDescription: ..........."
CREATE OR REPLACE PROCEDURE APPROVALS_J_TEST("MYSTR" VARCHAR(16777216))
RETURNS VARCHAR(16777216)
LANGUAGE JAVASCRIPT
**comment** = FunctionName: IfElse
Description: ...........
EXECUTE AS OWNER
AS
'if (MYSTR == ''0001'')
{
return ''Success''
}
else if (MYSTR == ''0002'')
{
return ''Success''
}
else {
return ''Failure''
}
';
The CREATE PROCEDURE docs note comment is a single quote wrapped string.
COMMENT = '<string_literal>'
so lets try one of those:
CREATE OR REPLACE PROCEDURE APPROVALS_J_TEST("MYSTR" text)
RETURNS text
LANGUAGE JAVASCRIPT
comment = 'FunctionName: IfElse
Description: ...........
'
EXECUTE AS OWNER
AS
'
if (MYSTR == ''0001'')
{
return ''Success''
}
else if (MYSTR == ''0002'')
{
return ''Success''
}
else {
return ''Failure''
}
';
show procedures;
So it seems to work

Oracle function re-write in SQL-Server

I have an Oracle function that needs to be converted to SQL-Server function
This is the Oracle Function:
FUNCTION check_education(in_crs_code IN VARCHAR2)
RETURN BOOLEAN IS
v_bool BOOLEAN := FALSE;
v_dummy VARCHAR2(1);
CURSOR find_education IS
SELECT 'x'
FROM KU_LIBRARY_EDUCATION_EXTLOAN
WHERE UPPER(course_code) = UPPER(in_crs_code) AND in_use = 'Y';
BEGIN
OPEN find_education;
FETCH find_education INTO v_dummy;
IF find_education%FOUND THEN
v_bool := TRUE;
ELSE
v_bool := FALSE;
END IF;
CLOSE find_education;
RETURN (v_bool);
END check_education;
This is what I have written in SQL-Server to replicate Oracle function:
CREATE FUNCTION [dbo].[check_education](#in_crs_code VARCHAR(4000))
RETURNS BIT AS
BEGIN
DECLARE #v_bool BIT = 0;
DECLARE #v_dummy VARCHAR(1);
DECLARE find_education CURSOR LOCAL FOR
SELECT 'x'
FROM [dbo].[KU_LIBRARY_EDUCATION_EXTLOAN]
WHERE UPPER(course_code) = UPPER(#in_crs_code)
AND in_use = 'Y';
OPEN find_education;
FETCH find_education INTO #v_dummy;
IF ##CURSOR_ROWS >1 BEGIN
SET #v_bool = 1;
END
ELSE BEGIN
SET #v_bool = 0;
END
CLOSE find_education;
DEALLOCATE find_education;
RETURN (#v_bool);
END;
I would expect the SQL server function to return 1 if the cursor returns 'x' but i'm getting 0. Anu help will be appreciated.
I would suggest using an inline table valued function instead of a scalar function. To make sure this is an inline table valued function it MUST be a single select statement. This means there can't be loops and other stuff. Fortunately this query does not actually need any loops. A simple count will return the number of rows. And any value other than 0 when converted to a bit will always be 1.
CREATE FUNCTION [dbo].[check_education]
(
#in_crs_code VARCHAR(4000)
) RETURNS table as return
SELECT CourseExists = convert(bit, count(*))
FROM [dbo].[KU_LIBRARY_EDUCATION_EXTLOAN]
WHERE UPPER(course_code) = UPPER(#in_crs_code)
AND in_use = 'Y';
This is a mere EXISTS thing, so we could try
CREATE FUNCTION [dbo].[check_education](#in_crs_code VARCHAR(4000)) RETURNS BIT AS
BEGIN
RETURN EXISTS ( <query> )
END;
But as far as I know, SQL Server doesn't accept this (though I cannot say why not - maybe it's because of their lack of a real boolean; Oracle doesn't accept it, because EXISTS is no keyword in their PL/SQL programming language).
So we'd use IF/ THEN/ ELSE:
CREATE FUNCTION [dbo].[check_education](#in_crs_code VARCHAR(4000)) RETURNS BIT AS
BEGIN
IF EXISTS
(
SELECT 'x'
FROM ku_library_education_extloan
WHERE UPPER(course_code) = UPPER(in_crs_code) AND in_use = 'Y'
)
RETURN 1
ELSE
RETURN 0
END
END;
There may be errors, because I've never coded a stored procedure in T-SQL, but anyway, you get the idea.

Does T-SQL allow multiple ELSE IF? Or must I nest conditionals? SQL Server 2012

In C#, you can have multiple conditionals of which only one will execute:
if (Condition1)
{
// Condition1 is true.
}
else if (Condition2)
{
// Condition1 is false and Condition2 is true.
}
else if (Condition3)
{
// Condition1 is false and Condition2 is false and Condition3 is true.
}
else
{
// Condition1, Condition2, and Condition3 are false.
}
But does the same logic work in T-SQL or must you nest the statements? Will this execute exactly like the above code?
IF #variable1 = 1
BEGIN
--#variable1 = 1
END
ELSE IF #variable1 = 2
BEGIN
--#variable1 = 2
END
ELSE IF #variable3 = 3
BEGIN
--#variable1 = 3
END
ELSE
BEGIN
--#variable1 > 3
END
I might be wrong here, but isn't there a way the SQL code would not evaluate the same way as the C# code from a logic standpoint if SQL doesn't allow multiple conditionals like C#? For example, is execution of each new ELSE IF guaranteed to be exclusive of the previous statements?
Yes, they are the same. Only one condition will be executed and the order of conditions is crucial.
LiveDemo
DECLARE #variable1 INT = 2
,#variable3 INT = 3;
IF #variable1 = 1
BEGIN
SELECT 'First IF'
END
ELSE IF #variable1 = 2
BEGIN
SELECT 'Second IF'
END
ELSE IF #variable3 = 3
BEGIN
SELECT 'Third IF'
END
ELSE
BEGIN
SELECT 'Else Clause'
END
In both the C# case as well as the SQL Server case, the ELSE keyword indicates that ONLY one block beneath an IF statement with a valid condition is going to be executed. Without ELSE, that's when the behavior changes. Your example is fine.

Sql Server ISERROR function

I have a function that returns the format of formula.some part of it----
if(CHARINDEX(#fieldname,#formula)<>0)
Begin
declare #previouschar char = SUBSTRING(#formula, CHARINDEX(#fieldname, #formula)-1, 1),
#nextchar char = SUBSTRING(#formula, CHARINDEX(#fieldname ,#formula)+len(#fieldname), 1)
if(#previouschar in('[',']','(',')','{','}','+','-','/','*')
and #nextchar in ('[',']','(',')','{','}','+','-','/','*'))
Begin
set #calFormula= replace(#calFormula,#fieldname,' case when FLD'+Convert(varchar,#flid)+' is null OR FLD'+Convert(varchar,#flid)+'='''' then 0.0 else Convert(decimal(18,'+ Convert(varchar,#decimalPlc) +'),FLD'+Convert(varchar,#flid)+' ) end ')
End
end
set #cnt1=#cnt1+1
End
set #calFormula= replace(#calFormula,'[','')
set #calFormula= replace(#calFormula,']','')
return #calFormula
I want to implement ISERROR method of DAX in Sql Server Relational Database that would check if any divisor entered is zero then it assigns NULL in calculated formula.How to work for this?Can there be some alternate method like ISERROR in SQL?
Sure.
IsError(1/0) will return true (because there is an error)
IsError(1/1) will return false (no error).
Technet

Not sure how to approch this, doing some math with error checking and updating my new value in tsql

if (freightCostTotal == 0)
{
freightCount = 1;
dataGridView1.Rows[i].Cells[iFreightCount].Value = "1";
if (freightCostDefinedTotal != 0)
{
freightCostTotal = Convert.ToDecimal(pcsg.Freight_CountColumn.Table.Rows[0]["Fixed Freight"].ToString());
}
else
{
if (!String.IsNullOrEmpty(dataGridView1.Rows[i].Cells[iCost_Prior_ReCompute].Value.ToString()))
Cost_Prior_ReCompute = Convert.ToDecimal(dataGridView1.Rows[i].Cells[iCost_Prior_ReCompute].Value.ToString());
//freightCostPercentTotal = 0.05M;
//decimal costFreight = Convert.ToDecimal(pcsg.Freight_CountColumn.Table.Rows[0]["Cost"].ToString());
freightCostTotal = (Cost_Prior_ReCompute * freight_perc_);
}
dataGridView1.Rows[i].Cells[iFreight].Value = String.Format("{0:0.00}", freightCostTotal);
}
The following is not working. This is my first attempt at doing sql math
select freightCostTotal, Cost_Prior_ReCompute],freight_perc_, FixedFreight,
if (freightCostTotal == 0) then freightCount = 1;
if (freightCostDefinedTotal != 0) then freightCostDefinedTotal = FixedFreight else
set freightCostTotal = (Cost_Prior_ReCompute * freight_perc_);
from VF_CasINV_Cost
Thanks,
Jerry
Not sure what you're after exactly, but here's a start below. FYI -- your conditional on Cost_Prior_Recompute needs a default / else value -- I just put a '?' in there for now, since I can't tell what it should be.
Also -- I can't tell if freigntCostTotal is an actually field in your database that you're trying to update, or if you plan to just compute it based on other fields each time. So far, I'm assuming you're just going to compute it.
So this is how you would select -- keeping in mind (I assume from reading your code) you are looking for data where the frieghtCostTotal has NOT been updated in the database yet.
SELECT
1 as freightCount,
CASE WHEN freightCostDefinedTotal <> 0
THEN FixedFreight
ELSE ISNULL(Cost_Prior_ReCompute,?) * freight_perc_
END as freigntCostTotal,
Cost_Prior_ReCompute,
freight_perc_,
FixedFreight
FROM
VF_CasINV_Cost
WHERE
freightCostTotal = 0
Alternatively, you could just pull the data out like this, but it will get all data, not just the freightCostTotal = 0 data.
SELECT
1 as freightCount,
freigntCostTotal,
Cost_Prior_ReCompute,
freight_perc_,
FixedFreight
FROM
VF_CasINV_Cost
Here's how you would update. BTW -- If you're new to updating with SQL, I'd highly recommend you test this out on some non-production data first. Or at least, back-up your table first.
UPDATE VF_CasINV_Cost
SET freightCostTotal = CASE WHEN freightCostDefinedTotal <> 0
THEN FixedFreight
ELSE ISNULL(Cost_Prior_ReCompute,?) * freight_perc_
END
WHERE freightCostTotal = 0

Resources