I have this function:
CREATE OR REPLACE FUNCTION array_drop_null(anyarray)
RETURNS anyarray
AS $$
BEGIN
RETURN array(SELECT x FROM UNNEST($1) x WHERE x IS NOT NULL);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
I can get a correct behavior with non-empty array:
asset=# select 1 FROM array_drop_null(ARRAY[1,2,NULL]::int[] ) x WHERE ARRAY_LENGTH(x, 1) = 2;
?column?
----------
1
(1 row)
However, when I pass an empty array or NULL, I got this:
asset=# select array_drop_null('{}'::int[] )
asset-# ;
ERROR: plpgsql functions cannot take type anyarray
CONTEXT: compile of PL/pgSQL function "array_drop_null" near line 0
asset=# SELECT '{}'::INT[];
int4
------
{}
(1 row)
When I pass a column with TEXT[] to the function, it returns {} if the column entry is NULL.
Another case:
asset=# select 1 FROM array_drop_null(ARRAY[NULL]::int[] ) x WHERE x IS NULL;
?column?
----------
1
(1 row)
It doesn't return {}, instead it returns NULL.
I am confused about the behavior. Can someone explain what is going on? What is a proper way to pass an empty array or NULL?
Related
I have question. Already i have avg_new function, which include nulls (as 0) in the result. I have start from linkedin link.
Code:
select avg(a),avg_new(nvl(a,-9999)) from
(select 'test' h, 2 a from dual
union all
select 'test' h, null a from dual
union all
select 'test' h, 2 a from dual
union all
select 'test' h ,2 a from dual)
the results are
2; 1,5
I would like to extend avg_new function by adding denominator parameter ex.:
avg_new(nvl(a,-9999),10)
Te result should be then 0.6
Default value of the parameter would be null, then function works as previous example. If the parameter would be >0 then I would divide sum of 'a' by value of this parameter. How i could do this? I would like to pass this parameter to used type object and to perform further calculations there. Is it possible?
create or replace FUNCTION avg_new (input NUMBER , denominator NUMBER DEFAULT NULL) RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING T_avg_new;
Right now the type could proper read only the first parameter. After adding i have errors:
ORA-29925: cannot execute T_avg_new.ODCIAGGREGATEINITIALIZE
ORA-06553: PLS-306: wrong number or types of arguments in call to "ODCIAGGREGATEINITIALIZE"
00000 - "cannot execute %s"
*Cause: The specified function does not exist or does not have an
appropriate signature.
*Action: Implement the function with the appropriate signature.
I have a table of club´s members with a column of status that a want to use as a filter in my function below. But the result is always the same no matter what number I pass as a function parameter. The count always comes with the total registers of the entire table.
CREATE OR REPLACE FUNCTION fn_count_members
(id_status in club.members.id_status%TYPE)
RETURN NUMBER IS
total club.members.id%TYPE:=0;
BEGIN
SELECT COUNT(id) INTO total
FROM club.members m
WHERE m.id_status = id_status;
RETURN total;
END;
And the query:
select id_status, fn_count_members(1) as total from club.members;
What am I missing here?
Thank you.
You have two issues:
CREATE OR REPLACE FUNCTION fn_count_members(
p_id_status in club.members.id_status%TYPE -- change the parameter name to
-- something different from the
-- column name.
)
RETURN NUMBER IS
total club.members.id%TYPE:=0;
BEGIN
SELECT COUNT(id) INTO total
FROM club.members m
WHERE m.id_status = p_id_status; -- and here
RETURN total;
END;
/
Then you need to pass the parameter in rather than using 1:
select id_status,
fn_count_members(id_status) as total
from club.members;
db<>fiddle here
This is wrong:
(id_status in club.members.id_status%TYPE)
---------
this
Because, when used in where clause
WHERE m.id_status = id_status
it turns out to be something like where 1 = 1 and returns everything, no filtering at all.
Rename parameter to e.g.
(par_id_status in club.members.id_status%TYPE)
and use it as
WHERE m.id_status = par_id_status
I want to generate a sequence by matching the condition given. I've two sequences in the case condition and depending on the test condition the query should generate the respective sequence. However even though the output is correct both the sequences are being generated and resulting in missed sequence issue. Is there any way that only the success test condition is executed. Below is the query used in oracle DB.
select CASE
WHEN :x=7
THEN seq1.NEXTVAL
ELSE seq2.NEXTVAL
END output from dual;
Suppose I pass x input as 7, I will get nextvalue of seq1 as output which is correct, however the nextvalue for seq2 is also generated in back end and missed the next time sequence is generated.
I need this condition for auditing.
You already know what's going on with your code. See if this helps.
First, create both sequences:
SQL> create sequence seq1;
Sequence created.
SQL> create sequence seq2;
Sequence created.
Now, create two functions, one for each sequence:
SQL> create or replace function f1 return number as begin return seq1.nextval; end;
2 /
Function created.
SQL> create or replace function f2 return number as begin return seq2.nextval; end;
2 /
Function created.
Run the select statement several times; once with input value 7 and several times with other values. But, don't select directly from the sequence - use functions instead:
SQL> select case when &x = 7 then f1
2 else f2
3 end result
4 from dual;
Enter value for x: 7
old 1: select case when &x = 7 then f1
new 1: select case when 7 = 7 then f1
RESULT
----------
1
SQL> /
Enter value for x: 2
old 1: select case when &x = 7 then f1
new 1: select case when 2 = 7 then f1
RESULT
----------
1
SQL> /
Enter value for x: 3
old 1: select case when &x = 7 then f1
new 1: select case when 3 = 7 then f1
RESULT
----------
2
SQL> /
Enter value for x: 4
old 1: select case when &x = 7 then f1
new 1: select case when 4 = 7 then f1
RESULT
----------
3
SQL> /
Enter value for x: 5
old 1: select case when &x = 7 then f1
new 1: select case when 5 = 7 then f1
RESULT
----------
4
OK; let's now check sequence's values:
SQL> select seq1.currval, seq2.currval from dual;
CURRVAL CURRVAL
---------- ----------
1 4
Aha! They aren't the same as they were using your code (i.e. having sequences in the select statement). Therefore, this might be a workaround for your problem.
However, sequences aren't to be used if you want gapless list of numbers. They will provide uniqueness, that's for sure, but - you most probably can't avoid gaps.
I have the below query which works, which gives the nth string corresponding to the key I give in the where clause as names (separator being ##)
select names from (
select
regexp_substr('a##b##c##d##e##f','[^##]+', 1, level) as names,
rownum as nth
from dual
connect by regexp_substr('a##b##c##d##e##f', '[^##]+', 1, level) is not null
)
where nth in (
select nth from (
select
regexp_substr('150##200##13##8##51##61','[^##]+', 1, level) as names,
rownum as nth
from dual
connect by regexp_substr('150##200##13##8##51##61', '[^##]+', 1, level) is not null
)
where names = '200'
)
Now, I have a table temp with say 3 columns x,y and z where x has strings like a##b##c##d##e##f, y has 1##2##3##4##5##6 and z will have number like 1.
If I have a rows like
a##b##c##d##e##f 150##200##13##8##51##61 200
a##b##c##d##e##f 1##2##3##4##5##6 2
g##h##i##j##k##l 1##2##3##4##5##99 99
I want outputs like
a##b##c##d##e##f 150##200##13##8##51##61 200 b
a##b##c##d##e##f 1##2##3##4##5##6 2 b
g##h##i##j##k##l 1##2##3##4##5##99 99 l
simply plugging "temp" in place of dual in the above query takes long time as the db has over 50k rows. Any better solution or how do I fix this?
You may find a plain SQL solution, but I'd prefer to capsule the critical substring functionality in a function. After that the query is trivial
update
with tcols as (
select rownum colnum from dual connect by level <= 6 /* (max) number of columns */),
t2 as (
select x,y,z, colnum,
nth_substring(y,'#',colnum) subs
from regexp_tst, tcols
)
select
x,y,z, colnum,
nth_substring(x,'#',colnum) a
from t2
where subs = z
;
.
X Y Z A
---------------- ---------------- ---------- ----
a##b##c##d##e##f 1##2##3##4##5##6 1 a
a##b##c##d##e##f 1##2##3##4##5##6 2 b
g##h##i##j##k##l 1##2##3##4##5##6 3 i
The required function is as follows (You may want to adjust the trimming and the repeated delimieter logic)
create or replace function nth_substring( i_str VARCHAR2, i_del VARCHAR2, i_pos NUMBER)
/*
find n-th substring in delimited string
i_str input string e.g. a##b##c##d##e##f
i_del delimiter character
i_pos position of the strin starting from 1
*/
return VARCHAR2 is
BEGIN
return rtrim(ltrim(regexp_substr(i_str,'[^'||i_del||']+', 1, i_pos)));
END;
/
In the database I have a procedure that returns different numerical values with the word RETURN.
This procedure I use with LINQ in my application, but it always returns -1 instead of the proper number.
Example T-SQL:
Create PROCEDURE EmailStatus
AS
BEGIN
IF NOT EXISTS (SELECT * FROM msdb.sys.service_queues WHERE name = N'ExternalMailQueue'
AND is_receive_enabled = 1)
return (100)
ELSE
RETURN 101
END
Example LINQ:
TestXMLEntities nw = new TestXMLEntities();
var r = nw.EmailStatus();
Use SELECT 101 instead of RETURN 101. Description