Postgres C extended data type definition - c++

When dealing with the following problems, Postgres is a bit tricky to deal with more complex structures. I want to set up a two-dimensional array of structure, but I don't know how to make Postgres C support me to do so? Do anyone have any ideas?
Table
id contents(text) num(double)
1 I love you. {1,3,4,5,6,7,8,10}
2 why do it? {3,4,2,11,12,33,44,15}
3 stopping. {22,33,11,15,14,22,11,55}
4 try it again. {15,12,11,22,55,21,31,11}
Sort the rows of each position of the array to get the fo.lowing structure. The result of the first row below is the first position of the num field column array, and so on.the count 4 refers to returning the first n sorted.
select my_func(contents, num, 4) from table;
expected result:
result
{('stopping.', 22), ('try it again.', 15), ('why do it?', 3), ('I love you.', 1)}
{('stopping.', 33), ('try it again.', 12), ('why do it?', 4), ('I love you.', 3)}
{('stopping.', 11), ('try it again.', 11), ('I love you.', 4), ('why do it?', 2)}
......
......
Thanks in advance.

I'm not sure why you need C extended data type, but the following will give you what you want and can be implemented as plpgsql function.
WITH t1 AS (
SELECT id, contents, unnest (num) AS n FROM table
),
t2 AS (
SELECT id, contents, n,
row_number () OVER (PARTITION BY id ORDER BY id) AS o
FROM t1 ORDER BY o ASC, n DESC, id ASC
),
t3 AS (
SELECT array_agg (ROW (contents, n)) AS a, o
FROM t2 GROUP BY o ORDER BY o
)
SELECT array_agg (a ORDER BY o) FROM t3;
UPDATE: Problem of the above may be undefined order of 'unnest'.
The following gives consistent relation between index and num, but need to write the size of num array explicitly.
WITH RECURSIVE t1 (i, id, contents, num) AS (
SELECT 1, id, contents, num[1] FROM table
UNION ALL
SELECT t1.i + 1, table.id, table.contents, table.num[t1.i + 1]
FROM t1, table
WHERE t1.id = table.id AND t1.i < 8 -- put here size of array
),
t2 (i, d) AS (
SELECT i, array_agg (ROW (contents, num) ORDER BY num DESC)
FROM t1 GROUP BY i
)
SELECT array_agg (d ORDER BY i) FROM t2;

Related

Big query analytical function not giving expected results

I am trying to write a sql in bigquery and I have a requirement to filter records based on a group by column and another column in the table
what I mean is I want to check if the group by column(column name:mnt) has more than one row then I have to check if col2 (col name: zel) value, then I have to apply a filter saying col2 ='X' and only pass that record else pass i.e dont filter the records if the col1 has only distinct one value per group
So I have written a sql to do this I have used row_number as well as rank , dense rank function but I noticed the value of rank and dense rank and row number functions return same value for a group
Please see the below code
#standardsql
with t1 as (SELECT mnt,
case when rank() over (partition by ltrim(rtrim(mnt)) order by
ltrim(rtrim(mnt)) asc) >1 then 'Y' else 'N' end
as flag,
rank() over (partition by mnt order by mnt) as rn,
dense_rank() over (partition by mnt order by mnt) as drn, FROM
projectname.datasetname.tablename1),
t2 as ( SELECT
mnt,
rel,
lif,
lts,
lokez FROM projectname.datasetname.tablename2
WHERE lts <> "" AND _PARTITIONTIME = TIMESTAMP(CURRENT_DATE()) ) ,
t3 as (SELECT
lif,
lifn,
lts,
par FROM `projectname.datasetname.tablename3`)
,t4 as (SELECT rcv FROM `projectname.datasetname.tablename4` WHERE mes
= 'PRO')
select * from (
SELECT t1.mnt as mnt,
t1.flag,
t1.rn,
t1.drn
t2.rel as zel,
t2.lokez as ZLOEKZ,
t4.rcv as Zrcv
FROM t1 left join t2 on replace(t1.mnt, '00000000', '') =
REPLACE(t2.mnt, '00000000', '') AND t1.lif = t2.lif and t2.lts <> ""
and
case when t1.flag = 'Y' and t2.rel ='X' then 1
when (t1.flag ='N' and t2.rel=t2.rel) or (t1.flag ='N' and t2.rel
is null) then 1
when t1.flag = 'Y' and t2.rel <>'X' then 2
else 3
end = 1
left join t3 ON t1.lif = t3.lif AND t2.lts = t3.lts AND
t3.par = 'BA' left join t4 on t4.rcv = t3.lifn and t2.lokez is null )
where ZLOEKZ is null order by mnt
As you can see I am using a case statement and even it seems to be not working fine. I am pasting the case condition below again
case when t1.flag = 'Y' and t2.rel ='X' then 1
when (t1.flag ='N' and t2.rel=t2.rel) or (t1.flag ='N' and
t2.rel
is null) then 1
when t1.flag = 'Y' and t2.rel <>'X' then 2
else 3
end = 1
But the expected record count did not match so I added the above sql lines to see if my analytical functions were giving me result I wanted
rank() over (partition by mnt order by mnt) as rn,
dense_rank() over (partition by mnt order by mnt) as drn
strangely for same mnt number the rank , dense rank and row_number function are assigning the same value what am i doing wrong here.
mnt flag rn drn rel lokez rcv
100 N 1 1 X abc 123
100 N 1 1 null xyz 123
100 N 1 1 null def 234
This is my output
I mean as per my code for same mnt number I am seeing flag set to N instead of Y and for the rank and dense rank are giving me same number for all 3 mnt it is generating 1 instead of 123 (note for rank function I understand) but dense rank should not do that
I tried to convey the issue as efficiently as I could please let me know if there is any clarifications I can provide.
any help appreciated
thanks
SELECT * EXCEPT(ct) FROM (
SELECT *, COUNT() OVER(PARTITION BY mnt) AS ct
) WHERE ct=1 or zel='X'
This is the code snippet for the problem you mentioned. Use this in your code according to the logic.

Parametized SQL query on a loop not updating correctly

I have an sql query running on a loop. There are two values FINGER and index_str that both need to be updated in parallel.
FINGER: (numpy array)
[['1012_8']
['10214_5']
['10409_9']
index_str: (pandas dataframe)
0 14,38,51,65,84,85
1 3,34,58,65,66,75
2 3,15,68,70,80,82
Above are the first 3 examples. There are over 1000 of each in reality.
for i in range(len(FINGER)):
print i
print FINGER[i]
for x in index_str[i]:
yy = FINGER[i][0]
#print range(len(FINGER))
index_str = str(x)
query = "SELECT finger, ind, x,y, CAST( (direction*180/3.142)as INT),CAST(quality*100 as INT) from UNIL_fingerprints where finger = '" + yy + "' and ind IN (" + index_str + ") order by ind "
print query
c.execute(query)
rows = c.fetchall()
print rows
Above is the loop and query in question.
So far the loop runs through all values of index_str for only the first FINGER value. To elaborate, the query updates for the first 3 examples as follows.
SELECT finger, ind, x,y, CAST( (direction*180/3.142)as INT),CAST(quality*100 as INT) from UNIL_fingerprints where finger = '1012_8' and ind IN (14,38,51,65,84,85) order by ind
SELECT finger, ind, x,y, CAST( (direction*180/3.142)as INT),CAST(quality*100 as INT) from UNIL_fingerprints where finger = '1012_8' and ind IN (3,34,58,65,66,75) order by ind
SELECT finger, ind, x,y, CAST( (direction*180/3.142)as INT),CAST(quality*100 as INT) from UNIL_fingerprints where finger = '1012_8' and ind IN (3,15,68,70,80,82) order by ind
Whereas '1012_8' should be '10214_5' and '10409_9' respectively in the 2nd and 3rd query above.
Any ideas on how to get this to update properly would be helpful.
You want zip():
for finger, indexes in zip(FINGERS, index_str):
print("fingers : {}- indexes: {}".format(finger, indexes))
Also you REALLY want to learn and use the db-api properly (well, unless you dont mind being hacked, that is).

PL/SQL split one to many rows

I have a table like this.
|PARAMKEY | PARAMVALUE
----------+------------
KEY |[["PAR_A",2,"SCH_A"],["PAR_B",4,"SCH_B"],["PAR_C",3,"SCH_C"]]
I need to split the values into three columns and I use REGEXP_SUBSTR. Here is my code.
SELECT REGEXP_SUBSTR(paramvalue, '[^],["]+', 1,1 ) PARAMETER
,REGEXP_SUBSTR(paramvalue, '[^],[",]+', 1, 2) VERSION
,REGEXP_SUBSTR(paramvalue, '[^],["]+', 1, 3) SCHEMA
FROM tmp_param_table
where paramkey = 'KEY'
UNION ALL
SELECT REGEXP_SUBSTR(paramvalue, '[^],["]+', 1, 4 ) PARAMETER
,REGEXP_SUBSTR(paramvalue, '[^],[",]+', 1, 5) VERSION
,REGEXP_SUBSTR(paramvalue, '[^],["]+', 1, 6) SCHEMA
FROM tmp_param_table
where paramkey = 'KEY'
UNION ALL
SELECT REGEXP_SUBSTR(paramvalue, '[^],["]+', 1, 7 ) PARAMETER
,REGEXP_SUBSTR(paramvalue, '[^],[",]+', 1, 8) VERSION
,REGEXP_SUBSTR(paramvalue, '[^],["]+', 1, 9) SCHEMA
FROM tmp_param_table
where paramkey = 'KEY';
and this is the result that i need.
PARAMETER | VERSION | SCHEMA
---------+---------+-------
PAR_A |2 |SCH_A
PAR_B |4 |SCH_B
PAR_C |3 |SCH_C
But the value is too long and I hope there is another way to make it simplier by using loop or anything.
Thanks
Try something like this:
with tmp_param_table as
(
select 'KEY' as PARAMKEY , '[["PAR_A",2,"SCH_A"],["PAR_B",4,"SCH_B"],["PAR_C",3,"SCH_C"]],["PAR_D",4,"SCH_D"]]' as PARAMVALUE from dual
),
levels as (select level as lv from dual connect by level <= 156),
steps as (select lv-2 as step from levels where MOD(lv,3)=0)
select step, (SELECT REGEXP_SUBSTR(paramvalue, '[^],["]+',1, step ) PARAMETER FROM tmp_param_table where paramkey = 'KEY') parameter,
(SELECT REGEXP_SUBSTR(paramvalue, '[^],["]+',1, step+1 ) PARAMETER FROM tmp_param_table where paramkey = 'KEY') version,
(SELECT REGEXP_SUBSTR(paramvalue, '[^],["]+',1, step+2 ) PARAMETER FROM tmp_param_table where paramkey = 'KEY') schema
from steps
Here
levels - returns numbers form 1 till 156 (52*3) (or whatever you need)
steps - are the numbers 1, 4, 7 etc with step 3
Results:
1 PAR_A 2 SCH_A
4 PAR_B 4 SCH_B
7 PAR_C 3 SCH_C
10 PAR_D 4 SCH_D
13
etc..
I have tried using regular expression
and part paramvalue column value into common separated value
SELECT
REGEXP_SUBSTR(COL, '[^],["]+', 1, 1) PARAMETER,
REGEXP_SUBSTR(COL, '[^],[",]+', 1, 2) VERSION,
REGEXP_SUBSTR(COL, '[^],["]+', 1, 3) SCHEMA
FROM
(
SELECT paramkey,REGEXP_SUBSTR(to_char(paramvalue),'[^][^]+',1,level ) COL
from tmp_param_table
connect by regexp_substr(to_char(paramvalue),'[^][^]+',1, level) is not null
)
WHERE COL <>','
I hope this may help.

SELECT Statement within IF statement

I would like to get a different result to my select statement when a parameter is 0, 1 or 2. I am not very skilled in PLSQL so I am not sure if my code would give the expected result. If i run this code i get a "SQL statement ignored" on line 3.
BEGIN
IF (:PARTYPE = 1) THEN
SELECT * FROM x
WHERE to_date(date) >= (Select to_date(sysdate)from DNV.dual)
ELSE
SELECT * FROM x
WHERE to_date(date) <= (Select to_date(sysdate)from DNV.dual)
END IF;
END;
This is just a example of my SELECT statement. Later this statement will become longer and more complex but I think this shows which results I am trying to get.
Below is a copy of my entire code but because I am not allowed to show this it has become very unreadable:
BEGIN
IF (:PARTYPE = 1) THEN
Select table1.Column1
, table1.Column2
, table1.Column3
, table1.Column4
, table1.Column5
, table1.Column6
, table1.Column7
, table1.Column8
, table1.Column9
, table1.Column10
, table1.Column11
, table1.Column12
, (Select table2.ColumnX From x2 table2 Where somthing) as "something" From x1 table1
WHERE to_date(date) >= (Select to_date(sysdate)from DNV.dual)
Order by columnX
ELSE
Select table1.Column1
, table1.Column2
, table1.Column3
, table1.Column4
, table1.Column5
, table1.Column6
, table1.Column7
, table1.Column8
, table1.Column9
, table1.Column10
, table1.Column11
, table1.Column12
, (Select table2.ColumnX From x2 table2 Where somthing) as "something" From x1 table1
WHERE to_date(date) <= (Select to_date(sysdate)from DNV.dual)
Order by columnX
END IF;
END;
I have created some new code with which i am trying to learn how a case statement works. This might help me with the code above. Unfortunately this code also doesn't work but I think it explanes my situation better. In this excample i use a separate table with data i made up. In some cases user2 is null but user1 is always filled. I want to get all items where user2 equals the parameter but if user2 is null and user1 does equal the paramter i still need that item to apear.
Select t1.user1,
t1.user2
From table t1
Where (Case
When t1.user2 IS NULL Then t1.user1 in (:PARUSER)
ELSE t1.user2 in (:PARUSER)
End Case)
Since the relational operator of the where clause depends on the partype, you cannot do the traditional CASE statement charm here. I'll have to resort with this one:
SELECT * FROM x
WHERE (to_date(date) >= (Select to_date(sysdate)from DNV.dual) AND :PARTYPE = 1)
OR (to_date(date) <= (Select to_date(sysdate)from DNV.dual) AND :PARTYPE != 1)

Oracle - how to convert string to row pair with out using WITH clause

In one of the column I have role and organization position
Example postion is 1 and organization is 310492 ...
1|310492|1|12319|1|562548|1|5202558
I need to convert this string to multiple rows
1,310492
1,12319
1,562548
1,5202558
I can not use WITH clause as I need to have is as correlated subquery
SELECT EXTRACT (VALUE (d), '//row/text()').getstringval ()
FROM (SELECT XMLTYPE ( '<rows><row>' || REPLACE (USERPROF.FIELD1, '|', '</row><row>') || '</row></rows>' ) AS xmlval FROM USERPROF WHERE FIELD1 IS NOT NULL ) x, TABLE (XMLSEQUENCE (EXTRACT (x.xmlval, '/rows/row'))) d
however this is converting entire string to multiple rows.
I tried playing with regexp and connect which is not helping me but fetching content of entire table by ignore where condition.
select regexp_substr(FIELD1,'[^|]+', 1, LEVEL) from USERPROF WHERE USERS_ID = 23502
connect by regexp_substr(FIELD1, '[^|]+', 1, level ) is not null;
Thanks in advance.
The SQL below:
with data as
(select '1|310492|1|12319|1|562548|1|5202558' as x from dual)
select fin from(
select 1+level-1 as occurrence
, instr(x,'|',1,1+level-1) as pos
, nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x))
as xxxx
, case when
nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x)) = length(x)
then instr(x,'|',1,1+level-1)
else
nvl(lag(instr(x,'|',1,1+level-1),1) over (order by 1+level-1),1) end as yyyy
, substr(x
,case when
nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x)) = length(x)
then instr(x,'|',1,1+level-1)
else
nvl(lag(instr(x,'|',1,1+level-1),1) over (order by 1+level-1),1) end
,nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x))
- case when
nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x)) = length(x)
then instr(x,'|',1,1+level-1)
else
nvl(lag(instr(x,'|',1,1+level-1),1) over (order by 1+level-1),1) end
) as fin
, length(x) as lastrw
from data
connect by level <= length(x) - length(replace(x, '|')) - 1
order by 1) x
where mod(occurrence,2) = 1 or xxxx = lastrw
Results in:
FIN
1|310492
|1|12319
|1|562548
|1|520255
Note that I'm just using the with clause to use the data you gave as an example.