I have a procedure with 2 selects, looks something like this...
PROCEDURE getRec
#pId INTEGER
AS
BEGIN
SELECT 'anything'
SELECT id, name
FROM my_table
WHERE id = #pId
END
When my perl script calls this stored procedure, if my_table has a matching record then it is displayed. However, if the ID passed in has no matches then the stored procedure returns 'anything'.
If there are no rows in the second select then I just want the procedure to return an empty result set. How can I achieve this?
Every SELECT will produce a result set (with the exception of SELECT #var = ...)
So will first be receiving the 'anything' result set
After that, you will receive the empty result set.
You need to get your perl code to fetch all rows in the first result set, then get the next result set and fetch all rows in that result set.
The functions to get the next result set will greatly depend on the perl library you are using.
Related
I have a select statement that's working fine but I need one more value that comes from a stored procedure and I can't call it as a value in the select statement
select
recp.percent,
(call libraryEXT.get_rate_for_detail(detail_number))
from
mainTable.orders ORD
inner join
mainTable.receipts recp on ORD.rcptID = recp.rcptID
It works fine to only get recp.percent, but putting the next value in for calling the stored procedure says it doesn't expect "call"
If I run the stored procedure by itself it returns one record with the columns: name, rcptID, time and I need the rcptID from that
How can I properly call the stored procedure and make the value returned be my other value in the select statment?
As #mao said, this is not possible to call an SP in a select statement.
If you are the SP owner, try creating a table-function instead. This one can be called in a select statement.
Given the way you've used CALL libraryEXT.get_rate_for_detail(detail_number) it's apparently only returning a single value.
That being the case, you'd be better served by having it as a scaler User Defined Function (UDF).
Then this is what your code would look like:
select
recp.percent,
libraryEXT.get_rate_for_detail_UDF(detail_number) as rate
from
mainTable.orders ORD
inner join
mainTable.receipts recp on ORD.rcptID = recp.rcptID
I renamed the function just to be clear it's NOT the stored proc. If you created the stored proc, you could delete it and use the same name for the UDF.
I had a query in SQL for postgres to get the count
SELECT COUNT(*) AS count_variable FROM user WHERE something=something;
When I executed, it was returning the count. Then as per requirement this query was required inside a Postgres Function.When I used this query inside Function, Postgres replied
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function myfuntion(integer,integer) line 11 at SQL statement
I searched for this error and found that, this happens if query returned null while using SELECT, But already I was getting value when executed directly on command line.
And also some posts told to discard it we should use PERFORM instead of SELECT. So my new query inside the same function was
PERFORM COUNT(*) AS count_variable FROM user WHERE something=something;
After this function started working, but count_variable is always zero. I am checking it using raise after PERFORM query.
raise notice 'count_variable: %', count_variable;
count_variable is declared as
DECLARE
count_variable int;
...
BEGIN
count_variable := 0;
Is there anything I am missing or doing wrong, or COUNT() function doesn't works inside function. If count() is not available, is their any alternative for counting rows. Somewhere I saw ##ROWCOUNT is also a variable to get row count, but it gives error.
Help will be highly appreciated.
You don't want to discard the result of the select, so perform is the wrong choice. You want to store the result of the query in a variable, so you need an INTO clause:
DECLARE
count_variable int;
...
BEGIN
SELECT COUNT(*) INTO count_variable
FROM "user"
WHERE something=something;
...
Just because you give the column an alias that is the same name as a variable, does not mean the result is stored in that variable. The column names have no relation with variables.
This is all explained in detail in the manual. Especially the chapter Executing a Query with a Single-row Result
set serveroutput on;
set verify off;
set autoprint on;
variable b_employee_id employees.employee_id%type;
declare
v_last_name employees.last_name%type;
v_emp_id employees.employee_id%type;
begin
select employee_id into :b_employee_id from employees
where last_name='&v_last_name';
end;
/
The error message is self explanatory. Your select statement returned more than one row. When you use the INTO clause the select cannot return more than one row.
From the documentation:
By default, a SELECT INTO statement must return only one row.
Otherwise, PL/SQL raises the predefined exception TOO_MANY_ROWS and
the values of the variables in the INTO clause are undefined. Make
sure your WHERE clause is specific enough to only match one row
If no rows are returned, PL/SQL raises NO_DATA_FOUND. You can guard
against this exception by selecting the result of an aggregate
function, such as COUNT(*) or AVG(), where practical. These functions
are guaranteed to return a single value, even if no rows match the
condition.
exact fetch returns more than requested number of rows
This means, there are more than one entry in the database for given last_name.
If you want, you can get max employee_id for given last_name as below.
select max(employee_id) into :b_employee_id from employees
where last_name='&v_last_name';
I am having a stored procedure mentioned below.
create or replace
PROCEDURE example(
in_start_date IN VARCHAR2,
in_svc_provider IN a_message.msg_service_provider%type,sell OUT number)
IS
BEGIN SELECT COUNT(*) as sell
FROM a_message b1 WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_trans_type = 'SELL'
AND b1.msg_service_provider = in_svc_provider;
end;
While executing the stored procedure I am getting following error.
Error(11,1): PLS-00428: an INTO clause is expected in this SELECT statement
Can you please provide me the resolution for this issue.while executing the same command in sql it is working fine but in stored procedure compilation error is occurring it means in stored procedure INTO replacing AS will give the same output please clarify.
The error message is fairly self-explanatory; the PL/SQL version of a SELECT requires an INTO clause so the result of your query has somewhere to go. You already have an OUT parameter to put the value into:
create or replace
PROCEDURE example(
in_start_date IN VARCHAR2,
in_svc_provider IN a_message.msg_service_provider%type,
sell OUT number)
IS
BEGIN
SELECT COUNT(*) INTO sell
FROM a_message b1
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_trans_type = 'SELL'
AND b1.msg_service_provider = in_svc_provider;
end;
The SELECT is now INTO your OUT parameter, and its value will be available to whoever calls your procedure.
This only works if your query will always return exactly one row. If it doesn't return anything then you'll get a no-data-found exception; if it returns more than one row you'll get a too-many-rows exception. And you need to have a variable for each column your query returns - only one in this case. You can also declare a local variable (between IS and BEGIN) to hold temporary values that you will manipulate within the procedure, but you don't need that here either.
When you compiled your procedure it would have said it compiled with warnings, because of that syntax error. If you created it in SQL*Plus or SQL Developer, and maybe some other tools, you could have seen the error straight away by issuing the command show errors, or at any time by querying the user_errors view. When you called the procedure it was invalid and was automatically recompiled, which just regenerated the same error as nothing had changed; that's when you saw the PLS-00428 message. It's better to look for errors at compile time than wait for recompilation at execution time.
Incidentally, it's generally better to convert a fixed value into the data type used by your table, rather than the other way round. When you do this:
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
... every column in your table has to have its msg_when_created DATE value converted to a string to be compared to the in_start_date string, which would prevent an index on that column being used. It's preferable to do:
WHERE b1.msg_when_created = TO_DATE(in_start_date, 'YYYY-MM-DD')
or if your column has a time component:
WHERE b1.msg_when_created >= TO_DATE(in_start_date, 'YYYY-MM-DD')
AND b1.msg_when_created < TO_DATE(in_start_date, 'YYYY-MM-DD') + INTERVAL '1' DAY
It would be even better to make your caller convert the value to a DATE so you don't have to worry about matching a passed format:
...
in_start_date IN a_message.msg_when_created%TYPE,
...
WHERE b1.msg_when_created >= TRUNC(in_start_date)
AND b1.msg_when_created < TRUNC(in_start_date) + INTERVAL '1' DAY
use into function
example: select count(*) into cnt_length from Table
I have a TSQL sproc that does three loops in order to find relevant data. If the first loop renders no results, then the second one normally does. I append another table that has multiple values that I can use later on.
So at most I should only have two tables returned in the dataset from the sproc.
The issue is that if the first loop is blank, I then end up with three data tables in my data set.
In my C# code, I can remove this empty table, but would rather not have it returned at all from the sproc.
Is there a way to remove the empty table from within the sproc, given the following:
EXEC (#sqlTop + #sqlBody + #sqlBottom)
SET #NumberOfResultsReturned = ##ROWCOUNT;
.
.
.
IF #NumberOfResultsReturned = 0
BEGIN
SET #searchLoopCount = #searchLoopCount + 1
END
ELSE
BEGIN
-- we have data, so no need to run again
BREAK
END
The process goes as follows: On the first loop there could be no results. Thus the rowcount will be zero because the EXEC executes a dynamically created SQL query. That's one table.
In the next iteration, results are returned, making that two data tables in the dataset output, plus my third one added on the end.
I didn't want to do a COUNT(*) then if > 0 then perform the query as I want to minimize the queries.
Thanks.
You can put the result for your SP in a table variable and then check if the table variable has any data in it.
Something like this with a SP named GetData that returns one integer column.
declare #T table(ID int)
declare #SQL varchar(25)
-- Create dynamic SQL
set #SQL = 'select 1'
-- Insert result from #SQL to #T
insert into #T
exec (#SQL)
-- Check for data
if not exists(select * from #T)
begin
-- No data continue loop
set #searchLoopCount = #searchLoopCount + 1
end
else
begin
-- Have data so wee need to query the data
select *
from #T
-- Terminate loop
break
end