call oracle function inside where clause [duplicate] - database

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there a function to split a string in plsql?
I have following oracle function
create or replace
function FUN_CUSTID(t in varchar2)
RETURN VARCHAR2
IS
TYPE str_array2 IS TABLE OF VARCHAR2(100);
v_names str_array2;
v_condition varchar2(1000);
BEGIN
v_condition := '(';
select REGEXP_SUBSTR(t, '[^ ,]+', 1, rownum)
bulk collect into v_names
from DUAL
connect by level <= length (regexp_replace(t, '[^ ,]+')) + 1;
FOR indx in v_names.FIRST..v_names.LAST LOOP
if (indx = v_names.LAST) then
v_condition := v_condition || '''' || v_names(indx) ||'''';
else
v_condition := v_condition || '''' || v_names(indx) ||''',';
end if;
v_condition := v_condition || ')';
END LOOP;
return v_condition;
end FUN_CUSTID;
/
Now i want to call this function from where clause like
SELECT customer_id,
name_remark,
wbs_id,
service_circuit_id,
sum(actual_minutes) TOTAL_USAGE,
min(first_connection_time) DATE_FROM,
max(first_connection_time) DATE_TO,
sum(amount) AMOUNT
FROM temp
FROM customer_id IN (SELECT FUN_CUSTID('CUST00001,CUST00002') FROM DUAL)
GROUP BYcustomer_id, name_remark, wbs_id, service_circuit_id
ORDER BY customer_id;
When i run this function directly and replace value in place of function call in upper query its work perfect with some records but upper query could not work.
How to call function in where clause ?

Your function generates its output in v_condition as ('A','B',.....) this is one whole string for Oracle in the select query and will not work with IN. Consider using dynamic SQL for this. Oracle treats the output of the function as one singe value as ('A','B',.....) so the IN clause would be parsed as-
IN ('('A','B',.....)',...)
Which is not what you want. You want something like below
IN ('A','B',.....)
And this can be achieved by dynamic SQL.

Related

How do I call a declared array variable in a where clause in postgres?

I am trying to build a declared array from all the dogs that share the same family_id and query the dog_characteristics table using the array.
CREATE OR REPLACE FUNCTION update_dog_characteristics_guarantor_id()
RETURNS trigger AS $$
DECLARE dog_ids INT[];
BEGIN
SELECT id into dog_ids FROM dogs WHERE dogs.family_id = OLD.id;
IF ((OLD.family_id IS NOT NULL) && ((SELECT COUNT(*) FROM dog_ids) > 0)) THEN
UPDATE
dog_characteristics
SET
guarantor_id = NEW.guarantor_id
WHERE
dog_characteristics.account_id = OLD.account_id
AND dog_characteristics.dog_id IN ANY(dog_ids);
RETURN NULL;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
What I have tried
AND dog_characteristics.dog_id = ANY(dog_ids);
AND dog_characteristics.dog_id = ANY(dog_ids::int[]);
AND dog_characteristics.dog_id IN (dog_ids::int[]);
AND dog_characteristics.dog_id IN (dog_ids);
AND dog_characteristics.dog_id IN (ARRAY(dog_ids));
AND dog_characteristics.dog_id IN ARRAY(dog_ids);
AND dog_characteristics.dog_id IN implode( ',', dog_ids);
Most common error
ERROR: malformed array literal: "672"
DETAIL: Array value must start with "{" or dimension information.
CONTEXT: PL/pgSQL function update_dog_characteristics_guarantor_id() line 5 at SQL statement
There are multiple errors in your trigger function.
As dog_ids is declared as an array, the result of the first select has to be an array as well. To do that, you need to aggregate all IDs that are returned from the query.
So the first select statement should be
select array_agg(id) --<< aggregate all IDs into an array
into dog_ids
FROM dogs
WHERE dogs.family_id = OLD.id;
To check if an array has elements, you can't use select count(*), you need to use use array_length() or cardinality().
The && is not the "AND" operator in SQL - that's AND - so the if should be:
IF OLD.family_id IS NOT NULL AND cardinality(dog_ids) > 0 THEN
...
END IF;
The where condition on the array should be:
AND dog_characteristics.dog_id = ANY(dog_ids);

ORA-6504 Type of result set variables does not match

I am trying to print records that are mismatching (by some criteria) in my two tables that I have queried below in my procedure
CREATE OR REPLACE PROCEDURE one_two_mismatch( p_rc OUT SYS_REFCURSOR,
p_rc2 OUT SYS_REFCURSOR )
AS
BEGIN
dbms_output.put_line('T1 Table');
OPEN p_rc
FOR select t1.ENTITY_KEY, t1.ENTITY_ID, t1.COMPONENT_ID, t1.PARENT_KEY,
t1.ENTITY_TYPE_KEY from entity t1,(select entity_id from (select
c.entity_id, count(e.component_id) as ONE_CNT, count(c.component_id) as
TWO_CNT from entity e, entity_cmm c where e.entity_id =
c.entity_id group
by c.entity_id) where ONE_CNT <> TWO_CNT) t2 where t1.ENTITY_ID =
t2.ENTITY_ID;
dbms_output.put_line('T2 Table');
OPEN p_rc2
FOR select t3.ENTITY_KEY, t3.ENTITY_ID, t3.COMPONENT_ID, t3.PARENT_KEY,
t3.ENTITY_TYPE_KEY from entity_cmm t3,(select entity_id from
(select c.entity_id, count(e.component_id) as ONE_CNT,
count(c.component_id) as TWO_CNT from est_entity e, entity_cmm c
where e.entity_id = c.entity_id group by c.entity_id) where ONE_CNT <>
TWO_CNT)
t4 where t3.ENTITY_ID = t4.ENTITY_ID;
END one_two_mismatch;
I have written the following statements below in my PL/SQL developer SQL window to execute the above procedure but am encountering an error in line 9 which says type of result set variable or query doesn't match
declare
p_rc sys_refcursor;
p_rc2 sys_refcursor;
l_rec est_entity%rowtype;
m_rec est_entity_cmm%rowtype;
begin
one_two_MISMATCH(p_rc, p_rc2);
LOOP
FETCH p_rc INTO l_rec;
EXIT WHEN p_rc%NOTFOUND;
DBMS_OUTPUT.put_line(l_rec.ENTITY_KEY || ',' || l_rec.ENTITY_ID ||
',' || l_rec.COMPONENT_ID ||',' || l_rec.PARENT_KEY ||','||
l_rec.ENTITY_TYPE_KEY );
END LOOP;
CLOSE p_rc;
LOOP
FETCH p_rc2 INTO m_rec;
EXIT WHEN p_rc2%NOTFOUND;
DBMS_OUTPUT.put_line( m_rec.ENTITY_KEY || ',' || m_rec.ENTITY_ID || ',' ||
m_rec.COMPONENT_ID ||',' || m_rec.PARENT_KEY ||','||
m_rec.ENTITY_TYPE_KEY);
END LOOP;
CLOSE p_rc2;
end;
Can someone please help?
Based on the information provided, it sounds like one or both queries in procedure cmm_st_mismatch do not have the correct column list. In the anonymous block, the two variables declared to receive the ref cursor records
l_rec est_entity%rowtype;
m_rec est_entity_cmm%rowtype;
are declared as row types. The ref cursor being fetched from must have the same number, type and order of columns as the table referenced in the rowtype variable declaration. Judging from the error you described, there is a mismatch.

Netezza while loop syntax

I want to make a statement in netezza so that it waits until a statement is correct before proceeding. Any help would be appreciated - something similar to the below
WHILE (
select count(*) EVENT_DESCRIPTION from TEST_DA_CONTROL.CTRL.C_DBA_MAINTENANCE_AUDIT
where EVENT_DESCRIPTION = 'STARTED' and DATETIME_LOGGED > (select add_months(current_date,0))) = 0
LOOP
wait 5
end loop;
but I don't know the correct syntax.
Best to assign that output to a variable. I seem to recall that getting data out of an execute immediate is a little arduous in nzplsql, but there are convenient variables already available for you to use. Here I'll use ROW_COUNT.
declare
event_descriptions int;
sql varchar;
begin
event_descriptions := 1;
while event_descriptions > 0 loop
--Actual work
sql := '
select * EVENT_DESCRIPTION from TEST_DA_CONTROL.CTRL.C_DBA_MAINTENANCE_AUDIT
where EVENT_DESCRIPTION = ''STARTED'' and DATETIME_LOGGED > (select add_months(current_date,0))) = 0;';
execute immediate sql;
event_descriptions := ROW_COUNT;
end loop;
end;

Postgresql: Array value must start with "{" or dimension information

CREATE OR REPLACE FUNCTION f_old_transactions (IN p_fromdate date, IN p_todate date, IN p_transtype varchar,IN OUT p_cancelled boolean,
OUT p_transaction_date date,
OUT p_type varchar,
OUT p_description varchar,
OUT p_amount numeric)
RETURNS SETOF record AS
$BODY$
declare lRunQuery text;
declare lTotalRec record;
declare lBranchList text[];
declare lTranstype text[];
BEGIN
select into lTranstype
dt.type
from
v_data_types dt;
lTranstype := regexp_split_to_array(p_transtype, ',');
lrunquery := 'select
it.transaction_date trandate,
dt.type,
it.description,
ita.amount,
it.cancelled
from
import_transaction it
inner join import_transaction_account ita on it.import_transaction_id=ita.import_transaction_id
where
it.transaction_date >= ' || quote_literal(p_fromdate) || '
and it.transaction_date <= ' || quote_literal(p_todate) || '
and dt.type = any(' || quote_literall(p_transtype) || ') and';
if (p_cancelled = TRUE) then
lrunquery := lrunquery || '
it.cancelled = ' || quote_literal(p_cancelled) || '';
else
lrunquery := lrunquery || '
it.cancelled = ' || quote_literal(p_cancelled) || '';
end if;
FOR lTotalrec in
execute lRunQuery
LOOP
p_transaction_date := ltotalrec.trandate;
p_type :=ltotalrec.type;
p_description :=ltotalrec.description;
p_amount :=ltotalrec.amount;
p_cancelled := ltotalrec.cancelled;
return next;
END LOOP;
return ;
end;
$BODY$
LANGUAGE plpgsql IMMUTABLE
COST 100
ROWS 1000;
ALTER FUNCTION f_old_transactions(date,date,varchar,boolean) OWNER TO "CompuLoanPostgres";
select * from f_old_transactions ('01-Jan-2010','31-Dec-2018','Receipt Cash','FALSE')
I'm getting an error that my array value must start with "{". My array I'm trying to create is from a view v_data_type the view consist of only one column with a varchar type.
Can anyone please direct me where the issue in my code is?
Thank you in advance
I don't think you've given us enough information to know for certain what's going wrong. Notably, I have no idea what the tables should look like, either in schema or content. Without that, I can't build a test case in my own DB to debug.
That said, I noticed a couple things, specifically around the lTranstype variable:
You're assigning lTranstype twice. First you SELECT INTO it, and then you immediately assign it to a value unpacked from the p_transtype argument. It's not clear to me what you want in that variable.
When constructing your query later, you include and dt.type = any(' || quote_literall(p_transtype) || '). The problem is that p_transtype is a varchar argument, and you're trying to access it like an array. I suspect you want that to read and dt.type = any(' || quote_literall(lTranstype) || '), but I could be mistaken.
I'm guessing that your type error is coming from that second problem, but it seems like you need to reassess what the different variables in this function are intended for. Good luck.

Passing an array to function and use it in WHERE IN clause

I want to use array(which is passed to function) under Where in clause
Here is what i tried
First created the array type
create or replace type p_emp_arr as table of number
Function is
create or replace
FUNCTION getEmployee_func ( empId_arr IN p_emp_arr)
RETURN number IS
total number(2) := 0;
BEGIN
IF(empId_arr is null)
THEN
empIdClause := '';
ELSE
empIdClause := 'AND Employee.empId in (select column_value from table('||empId_arr||'))';
END IF;
....
RETURN total;
END;
But gives error
Error(17,23): PLS-00306: wrong number or types of arguments in call to '||'
The error is because CONCAT (||) operator accepts only scalar variables (string/number), you cannot pass an array to it.
You need to execute this as a dynamic PL/SQL block.
In case you want to bind the array dynamically, try something like this.
Bind the variables using IN and OUT keywords appropriately.
In your Anonymous block string, prefix the to-be-bind variables with colon (:)
EXECUTE IMMEDIATE '
BEGIN
SELECT
COLUM1,COLUMN2..
INTO
:VAR1, :VAR2..
FROM .... WHERE...
AND Employee.empId in (select column_value from table(:empId_arr));
END;
'
USING OUT VAR1, OUT VAR2... IN empId_arr;
It can also be Simply,
OPEN EMP_CURSOR FOR
'SELECT * FROM Employee
where empId in SELECT COLUMN_VALUE FROM TABLE(:empId_arr)'
USING empId_arr ;
If you take the output as a cursor;
AS Wernfried mentioned.. Using MEMBER OF operator.
OPEN EMP_CURSOR FOR
'SELECT * FROM Employee
where empId member of :empId_arr'
USING empId_arr ;

Resources