Return boolean if one element matches among 2 arrays in postgresql - sql

I have 2 arrays in postgresql and I need to return true if there are at least 1 match of element between these 2 arrays no mather if it is same position.
Follows example below:
select array(select generate_series(0,10)) =
any(select array(select generate_series(10,11)))
it should return true because I have 10 in both arrays

https://www.postgresql.org/docs/current/static/functions-array.html
= equal
&& overlap (have elements in common)
formatting mine. You need other operator
select array(select generate_series(0,10)) &&
any(select array(select generate_series(10,11)));
?column?
----------
t
(1 row)

Go for && operator
like
SELECT ARRAY['apple','cherry','avocado'] && ARRAY['applea','cherrya','avocado']
SELECT ARRAY[1,4,3] && ARRAY[2,1]
https://www.postgresql.org/docs/9.6/static/functions-array.html

Related

postgres && - Array Overlap operator with wildcard

In postgres
select array['some', 'word'] && array ['some','xxx'] -- return true
select array['some', 'word'] && array ['','word'] -- return true
I'd like to know how I can use % wildcar in combination with && operator.
select array['some%', 'word'] && array ['','some'] -- I was thinking this will return true but it doesn't.
I want to check if a text array contains at least one element of another text array. The first text array can contains wildcard. What's the best way to do that ?
You could try unnest to parse every element of both arrays and compare them using LIKE or ILIKE:
SELECT EXISTS(
SELECT
FROM unnest(array['some%', 'word']) i (txt),
unnest(array ['','some']) j (txt)
WHERE j.txt LIKE i.txt) AS overlaps;
overlaps
----------
t
(1 row)
If you want to apply the % to all array elements, just place it directly in the WHERE clause in the LIKE or ILIKE operator:
SELECT EXISTS(
SELECT
FROM unnest(array['some', 'word']) i (txt),
unnest(array ['','XXsomeXX']) j (txt)
WHERE j.txt LIKE '%'||i.txt||'%') AS overlaps;
overlaps
----------
t
(1 row)
Demo: db<>fiddle

Oracle regular expression to replace numbers with alphabets

I have a string which contains only numbers.
I need to replace all digits in the string with a corresponding alphabet as below,
0 -> A
1 -> B
2 -> C
..
9 -> J
I tried with below using translate and replace functions and it works fine for me,
Forward :
WITH T (ID) AS (SELECT '10005614827' FROM DUAL)
SELECT ID, TRANSLATE(ID,'0123456789','ABCDEFGHIJ') "TRANSLATE",
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ID,'0','A'),'1','B'),'2','C'),'3','D'),'4','E'),'5','F'),'6','G'),'7','H'),'8','I'),'9','J') "REPLACE"
FROM T;
Output:
ID TRANSLATE REPLACE
10005614827 BAAAFGBEICH BAAAFGBEICH
Reverse:
WITH T (ID) AS (SELECT 'BAAAFGBEICH' FROM DUAL)
SELECT ID, TRANSLATE(ID,'ABCDEFGHIJ','0123456789') "TRANSLATE",
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ID,'A','0'),'B','1'),'C','2'),'D','3'),'E','4'),'F','5'),'G','6'),'H','7'),'I','8'),'J','9') "REPLACE"
FROM T;
Output:
ID TRANSLATE REPLACE
BAAAFGBEICH 10005614827 10005614827
Is there any way to use regular expression to implement this?
WITH T (ID) AS (SELECT '10005614827' FROM DUAL)
SELECT ID, REGEXP_REPLACE(ID,'[0-9]','[A-J]')
FROM T;
It's not possible in Oracle because of the limitations of current implementation.
More specifically, you cannot apply a function to matched value, you only can use backreferences in a form \n where n is a digit from 1 to 9.
For example, you can match each digit and repeat it as many times as it equals to.
column example format a40
with t(id) as (select '10005614827' from dual)
select id,
regexp_replace(id,'(1)|(2)|(3)|(4)|(5)|(6)|(7)|(8)|(9)|(0)','\1\2\2\3\3\3\4\4\4\4\5\5\5\5\5\6\6\6\6\6\6\7\7\7\7\7\7\7\8\8\8\8\8\8\8\8\9\9\9\9\9\9\9\9\9') example
from t
/
ID EXAMPLE
----------- ----------------------------------------
10005614827 1555556666661444488888888227777777
1 row selected.
But you can't apply any function to \n in replacing string.
On the other hand, in languages like Perl, Java, Scala... or even in PowerShell and others it's doable.
Example from Scala REPL.
scala> val str = "10005614827"
str: String = 10005614827
scala> // matching and converting each digit separately
scala> "\\d".r.replaceAllIn(str, x => (x.group(0)(0)+17).toChar + "")
res0: String = BAAAFGBEICH
scala> // marching and converting sequences of digits
scala> "\\d+".r.replaceAllIn(str, x => x.group(0).map(x=>(x+17).toChar))
res1: String = BAAAFGBEICH
To complete the picture, model solution just for fun.
SQL> with t(id) as (select '10005614827' from dual)
2 select *
3 from t
4 model partition by (id) dimension by (0 i) measures (id result)
5 rules iterate(10)
6 (result[0] = replace(result[0],iteration_number,chr(ascii(iteration_number)+17)))
7 /
ID I RESULT
----------- ---------- -----------
10005614827 0 BAAAFGBEICH
translate is the very best approach in this case though. This is exactly what this function was made for.
PS. Scala equivalent for example above with a function applied to matched value instead of using backreferences.
"\\d".r.replaceAllIn(str, x => (x.group(0)*(x.group(0)(0)-48)))
Using translate function I do not see problems.
Having for example the string number '3389432543' you can convert it using
SELECT TRANSLATE('3389432543','0123456789','ABCDEFGHIJ')
FROM DUAL;

Check if any of array elements starts with specific characters postgres

I am trying to check if an array has any of elements which starts with or ends with the string specified.
For Comparing strings we could do something like below,
select * from table where 'gggggg' ilike '%g';
Can someone help to find out if an array contains values as like pattern.
Eg array : ['str1', 'str2', 'str3']
Also I want to find if any of elements ends with 1 or starts with 'str'.
For now, the only thing you can do is unnest the array and test each element:
create table test (a text[]);
insert into test values (array['abc', 'def', 'ghi']);
select distinct a from test
JOIN lateral (select * from unnest(a) as u) as sub on TRUE
WHERE u like '%g';
a
---
(0 rows)
select distinct a from test
JOIN lateral (select * from unnest(a) as u) as sub on TRUE
WHERE u like 'g%';
a
---------------
{abc,def,ghi}
(1 row)
In postgres 12, you will be able to use jsonb_path_exists. Of course, this would work better if you stored your data in jsonb, but it will still work, just not as efficiently:
-- Starts with g
select a from test
where jsonb_path_exists(to_jsonb(a), '$[*] ? (# like_regex "^g")');
a
---------------
{abc,def,ghi}
(1 row)
-- Ends with g
select a from test
where jsonb_path_exists(to_jsonb(a), '$[*] ? (# like_regex "g$")');
a
---
(0 rows)

How to aggragate integers in postgresql?

I have a query that gives list of IDs:
ID
2
3
4
5
6
25
ID is integer.
I want to get that result like that in ARRAY of integers type:
ID
2,3,4,5,6,25
I wrote this query:
select string_agg(ID::text,',')
from A
where .....
I have to convert it to text otherwise it won't work. string_agg expect to get (text,text)
this works fine the thing is that this result should later be used in many places that expect ARRAY of integers.
I tried :
select ('{' || string_agg(ID::text,',') || '}')::integer[]
from A
WHERE ...
which gives: {2,3,4,5,6,25} in type int4 integer[]
but this isn't the correct type... I need the same type as ARRAY.
for example SELECT ARRAY[4,5] gives array integer[]
in simple words I want the result of my query to work with (for example):
select *
from b
where b.ID = ANY (FIRST QUERY RESULT) // aka: = ANY (ARRAY[2,3,4,5,6,25])
this is failing as ANY expect array and it doesn't work with regular integer[], i get an error:
ERROR: operator does not exist: integer = integer[]
note: the result of the query is part of a function and will be saved in a variable for later work. Please don't take it to places where you bypass the problem and offer a solution which won't give the ARRAY of Integers.
EDIT: why does
select *
from b
where b.ID = ANY (array [4,5])
is working. but
select *
from b
where b.ID = ANY(select array_agg(ID) from A where ..... )
doesn't work
select *
from b
where b.ID = ANY(select array_agg(4))
doesn't work either
the error is still:
ERROR: operator does not exist: integer = integer[]
Expression select array_agg(4) returns set of rows (actually set of rows with 1 row). Hence the query
select *
from b
where b.id = any (select array_agg(4)) -- ERROR
tries to compare an integer (b.id) to a value of a row (which has 1 column of type integer[]). It raises an error.
To fix it you should use a subquery which returns integers (not arrays of integers):
select *
from b
where b.id = any (select unnest(array_agg(4)))
Alternatively, you can place the column name of the result of select array_agg(4) as an argument of any, e.g.:
select *
from b
cross join (select array_agg(4)) agg(arr)
where b.id = any (arr)
or
with agg as (
select array_agg(4) as arr)
select *
from b
cross join agg
where b.id = any (arr)
More formally, the first two queries use ANY of the form:
expression operator ANY (subquery)
and the other two use
expression operator ANY (array expression)
like it is described in the documentation: 9.22.4. ANY/SOME
and 9.23.3. ANY/SOME (array).
How about this query? Does this give you the expected result?
SELECT *
FROM b b_out
WHERE EXISTS (SELECT 1
FROM b b_in
WHERE b_out.id = b_in.id
AND b_in.id IN (SELECT <<first query that returns 2,3,4,...>>))
What I've tried to do is to break down the logic of ANY into two separate logical checks in order to achieve the same result.
Hence, ANY would be equivalent with a combination of EXISTS at least one of the values IN your list of values returned by the first SELECT.

how to evalute expression values with parameter in postgres sql

I was trying to evaluate a regular expression in PostgreSQL in where clause.
I have a column with value like the example (1,2) below. When I write a query in where clause I am passing parameter values as either "a" or "a,b" or "b" then it should return only the rows that contain "a" or "a,b" or "b".
When I pass "a" then it should check the row value and evaluate the "AND" , "OR" conditions as well.
Example:1
((((a.b.city == "x" AND a.b.state == "y" AND a.b.country == "z")) OR
(dis(x.y.d1, x.y.d2, "47.6015", "-122.3304") <= 5))
AND ((p.q.test == "**a**") OR (p.q.test == "b")))
Example:2
((((a.b.city == "x" AND a.b.state == "y" AND a.b.country == "z")) OR
(dis(x.y.d1, x.y.d2, "123", "-456") <= 5)) AND ((p.q.test == "a,b")
Here is a sample query.
select * from testtable where column ='parameter'
Please suggest.
It's really hard to figure out quite what you're asking, but I think you want IN(...).
E.g.
p.q.test IN ('a', 'b')
is equivalent to
p.q.test = 'a' OR p.q.test = 'b'
You can pass an array as a query parameter if the list to match is dynamic:
p.q.test IN (?)
or a comma-separated list to match against:
p.q.test = ANY (regexp_split_to_array(?,','))
If your p.q.test is a comma-separated value list, then split it, and compare it to an array of possible matches using the && (array overlaps) operator:
WITH test(x) AS (VALUES ('a,b'), ('a'), ('b'), ('a,b,c'), ('b,c'), ('d,e'), ('e'))
SELECT x, regexp_split_to_array(x, ',') && ARRAY['a','b'] FROM test;
x | ?column?
-------+----------
a,b | t
a | t
b | t
a,b,c | t
b,c | t
d,e | f
e | f
(7 rows)
If && doesn't quite match what you want, look at the arrays manual; maybe the #> or <# (contains / contained by) operators are what you need.