Postgresql function for passing arguments dynamically - sql

I created a function abcd_insert() which inserts data into table abcd, which has 8 columns. The code inside the function looks similar to below :
BEGIN
INSERT INTO abcd
VALUES
(
x ,
y ,
select sum(count) from (select count(*) from a where a1 = x and a2 = y and a3 = 1 union all select count(*) from b where b1 = x and b2 = y and b3 = 1 ) as n1,
select sum(count) from (select count(*) from a where a1 = x and a2 = y and a2 = 2 union all select count(*) from b where b1 = x and b2 = y and b3 = 2 ) as n2 ,
select sum(count) from (select count(*) from a where a1 = x and a2 = y and a2 = 3 union all select count(*) from b where b1 = x and b2 = y and b3 = 3 ) as n3 ,
select sum(count) from (select count(*) from a where a1 = x and a2 = y and a2 = 4 union all select count(*) from b where b1 = x and b2 = y and b3 = 4 ) as n4 ,
select sum(count) from (select count(*) from a where a1 = x and a2 = y and a2 = 5 union all select count(*) from b where b1 = x and b2 = y and b3 = 5 ) as n5 ,
SELECT sum(q1) from
(SELECT CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END as q1 FROM p1 where p11 = x and p12 = y union all
SELECT CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END as q1 FROM p2 where p21 = x and p22 = y ) as q1
);
END;
'x' and 'y' are my input parameters whose values will be passed to the function abcd_insert(). a,b,p1 and p2 are tables within the same schema.
When I pass 'x' and 'y' to the function at run time, it throws error.
Can someone please tell me what I am doing wrong here.

I think you'd better to specify the column names in your insert statement.
Insert into abcd ("column1",...,"column8") values ...
And please post the error, so that others can help.

with your sample code, you need brackets around queries, so you would use their result, eg:
t=# create table t (i int, e int);
CREATE TABLE
t=# create or replace function f(x int) returns void as $$
begin
insert into t values (x, (select 1 where x > 0));
end;
$$ language plpgsql;
CREATE FUNCTION
t=# select f(1);
f
---
(1 row)
t=# select * from t;
i | e
---+---
1 | 1
(1 row)

Related

Informix SQL 11.5 Attach the result of one select to another select by columns

i have one select:
select c1,c2,c3 from table1 where cond1
--result:
a b c
d e f
g h i
and another select is
select m2 from table2 where cond2
--result:
x
y
z
What combination of the two can I achieve with this output?
select m2 from table2 where cond2 **COMBIN** select c1,c2,c3 from table1 where cond1
--result
x a b c
y d e f
z d e f
of course, union and join didn't as COMBIN work.
You could do it with an SPL/Function.
Something like:
--drop procedure p1 ();
create procedure p1 () returning char AS t2_c1,char AS t1_c1,char AS t1_c2,char AS t1_c3;
define t1_c1 char;
define t1_c2 char;
define t1_c3 char;
define t2_c1 char;
prepare t1_id from "select c1,c2,c3 from t1";
prepare t2_id from "select c1 from t2";
declare t1_cur cursor for t1_id;
declare t2_cur cursor for t2_id;
open t1_cur;
open t2_cur;
while (1=1)
fetch t1_cur into t1_c1,t1_c2,t1_c3;
if (sqlcode == 100) then
exit;
end if
fetch t2_cur into t2_c1;
if (sqlcode == 100) then
exit;
end if
return t2_c1,t1_c1,t1_c2,t1_c3 with resume;
end while
close t1_cur;
close t2_cur;
free t1_cur ;
free t2_cur ;
free t1_id ;
free t2_id ;
end procedure;
execute procedure p1();
Which should give you:
D:\Infx\ids1410>dbaccess stores7 p
Database selected.
Routine dropped.
Routine created.
t2_c1 t1_c1 t1_c2 t1_c3
x a b c
y d e f
z g h i
3 row(s) retrieved.
Database closed.
D:\Infx\ids1410>
but it would be a lot simpler if you have a common column ;)
Well - let's handcraft a common column, using the ROW_NUMBER() OLAP function, and join by that ...
WITH
-- your input
table1(c1,c2,c3) AS (
SELECT 'a','b','c'
UNION ALL SELECT 'd','e','f'
UNION ALL SELECT 'g','h','i'
)
,
-- your input
table2(m2) AS (
SELECT 'x'
UNION ALL SELECT 'y'
UNION ALL SELECT 'z'
)
-- real query starts here, replace "," with "WITH"
,
tb1_w_id AS (
SELECT
ROW_NUMBER() OVER(ORDER BY c1) AS id
, *
FROM table1
WHERE true
)
,
tb2_w_id AS (
SELECT
ROW_NUMBER() OVER(ORDER BY m2) AS id
, *
FROM table2
WHERE true
)
SELECT
m2
, c1
, c2
, c3
FROM tb1_w_id
JOIN tb2_w_id ON tb1_w_id.id = tb2_w_id.id
;
-- out m2 | c1 | c2 | c3
-- out ----+----+----+----
-- out x | a | b | c
-- out y | d | e | f
-- out z | g | h | i

How to remove the null values and get the table like shown below?

Here i have the oracle db table like shown below:
name a1 b1 c1
---- --- --- ---
a z null null
a null y null
a nul null z
b y z null
b null null m
So my expected output table is:
name a1 b1 c1
---- --- --- ---
a z y z
b y z m
As aggregate functions [except count(*)] ignores NULL, you can simply use MAX or MIN and group by to get your desired result as below.
SELECT name,
max(a1) AS a1,
max(b1) AS b1,
max(c1) AS c1
FROM table1
GROUP BY name
OR
SELECT name,
min(a1) AS a1,
min(b1) AS b1,
min(c1) AS c1
FROM table1
GROUP BY name
Result:
NAME A1 B1 C1
------------------
a z y z
b y z m
DEMO
you can try something like that:
select name, max(nvl(a1, '')), max(nvl(a2, '')), max(nvl(a3, ''))
from table
group by name
SELECT name, MAX( a1 ) , MAX( b1 ) , MAX( c1 )
FROM Table
GROUP BY name
For SQL this will work

Get a limited number of rows for each match in Postgres

I have a table like:
1 a a1 a2
1 b b1 b2
1 c c1 c2
1 d d1 d2
2 a a1 a2
2 b b1 b2
2 c c1 c2
3........
3........
........
........
n x x1 x2
n y y1 y2
n z z1 z2
From this, I want to get for each number(1,2,3,4....n) some specified number(say 2) of rows.
Result:
1 a a1 a2
1 b b1 b2
2 a a1 a2
2 b b1 b2
.........
.........
n x x1 x2
n y y1 y2
I am trying to do group by and string_agg(). But I can't limit it to a specified number.
How can I go about it?
This can be done using a window function:
select nr, col1, col2, col3
from (
select nr, col1, col2, col3,
row_number() over (partition by nr order by col1) as rn
from the_table
) t
where rn <= 2;
If you want to influence which rows are returned, you can adjust the order by that defines the ordering of the rows in the window function.

SQL Update with Case/IFs

I have 8 bit columns, A1,A2,a3,a4,b1,b2,b3,b4. All 8 are completely independent and its based on these that another field should be populated.
I want to update this other field with the text A, B or AB depending on which of any of the 8 columns are set to 1.
Here are a couple of examples;
- all 8 fields are set to 1 then populate with AB,
- if A3 and B1 are set to 1 then populate with AB,
- if A1 and A3 are set to 1 then populate with A,
- if B4 and B2 are set to 1 then populate with B.
So for any combination of A1 through B4 the field should be set
Below is the what I have tried but it is incomplete but will give an idea;
UPDATE
Correct answer from adrianm
UPDATE m
SET ref = ASet + BSet
FROM contactMaster m
inner join contact c on
m.contactid = c.contactid
CROSS APPLY (
SELECT CASE WHEN (c.A1 | c.A2 | c.A3 | c.A4) = 1 THEN 'C' ELSE '' END AS ASet
,CASE WHEN (c.B1 | c.B2 | c.B3 | c.B4) = 1 THEN 'D' ELSE '' END AS BSet
) AS CA1
where ref is null
UPDATE ContactMaster
SET ref = ASet + BSet
FROM ContactMaster
INNER JOIN Contact
ON ContactMaster.ContactId = Contact.ContactId
CROSS APPLY (
SELECT CASE WHEN (Contact.A1 | Contact.A2 | Contact.A3 | Contact.A4) = 1 THEN 'A' ELSE '' END AS ASet
,CASE WHEN (Contact.B1 | Contact.B2 | Contact.B3 | Contact.B4) = 1 THEN 'B' ELSE '' END AS BSet
) AS CA1
WHERE ContactMaster.ref IS NULL
IF (Select Count(*) from table where A1=1 AND A2 =1 AND a3 =1 AND a4 =1 AND b1 =1 AND b2 =1 AND b3 =1 AND b4=1 )>0
BEGIN
UPDATE MyTable
SET ColumnValue ='AB'
where A1=1 AND A2 =1 AND a3 =1 AND a4 =1 AND b1 =1 AND b2 =1 AND b3 =1 AND b4=1
END
ELSE IF (Select Count(*) from table where A1 =1 and A3 =1 )>0
BEGIN
Update MyTable set columnValue ='A'
where A1 =1 and A3 =1
END

Find missing number from not sequence number

I have a database with 5 columns (A1,A2,A3,A4,A5) which store 5 numbers.
The 5 numbers are "1,2,3,4,5".
A1 A2 A3 A4 A5
-------------------------------
2 4 5 Null Null
I want get the missing number which is "1" and "3".
How do I find the missing number from 5 numbers?
Select Replace(Replace(Replace(Replace(
Replace('12345',(Cast(Coalesce(A5,0) as varchar(1))),''),
(Cast(Coalesce(A4,0) as varchar(1))),''),
(Cast(Coalesce(A3,0) as varchar(1))),''),
(Cast(Coalesce(A2,0) as varchar(1))),''),
(Cast(Coalesce(A1,0) as varchar(1))),'') from Table1
Sql Fiddle Demo
You can do this
WITH sequence AS
(
SELECT 1 n UNION ALL
SELECT n + 1 FROM sequence WHERE n < 5
)
SELECT n
FROM sequence s LEFT JOIN table1 t
ON s.n IN (t.a1, t.a2, t.a3, t.a4, t.a5)
WHERE t.a1 IS NULL
Output:
| N |
|---|
| 1 |
| 3 |
Here is SQLFiddle demo
Depending on the desired output, this might work. This returns the relevant missing number(s) for each row.
SELECT CASE WHEN COALESCE(A1,0)<>1 AND COALESCE(A2,0)<>1 AND COALESCE(A3,0)<>1
AND COALESCE(A4,0)<>1 AND COALESCE(A5,0)<>1 THEN 1 ELSE '' END A
, CASE WHEN COALESCE(A1,0)<>2 AND COALESCE(A2,0)<>2 AND COALESCE(A3,0)<>2
AND COALESCE(A4,0)<>2 AND COALESCE(A5,0)<>2 THEN 2 ELSE '' END B
, CASE WHEN COALESCE(A1,0)<>3 AND COALESCE(A2,0)<>3 AND COALESCE(A3,0)<>3
AND COALESCE(A4,0)<>3 AND COALESCE(A5,0)<>3 THEN 3 ELSE '' END C
, CASE WHEN COALESCE(A1,0)<>4 AND COALESCE(A2,0)<>4 AND COALESCE(A3,0)<>4
AND COALESCE(A4,0)<>4 AND COALESCE(A5,0)<>4 THEN 4 ELSE '' END D
, CASE WHEN COALESCE(A1,0)<>5 AND COALESCE(A2,0)<>5 AND COALESCE(A3,0)<>5
AND COALESCE(A4,0)<>5 AND COALESCE(A5,0)<>5 THEN 5 ELSE '' END E
FROM NumTest
WHERE COALESCE(A1,0)+COALESCE(A2,0)+COALESCE(A3,0)+COALESCE(A4,0)+COALESCE(A5,0)<>15
The results look like:
you'll need a table of integers from 1 to (in this case) 5:
DECLARE #ints table (n int);
INSERT #ints VALUES (1), (2), (3), (4), (5);
second, we get the numbers in the table row into a single comparable set:
SELECT x INTO #all FROM (
SELECT A1 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A2 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A3 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A4 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A5 as x FROM myTable WHERE ID = myRow
) y
then you can derive the answer:
SELECT #ints.n
FROM #ints left join #all on #ints.n = #all.x
WHERE #all.x is null
ORDER BY 1