how to evalute expression values with parameter in postgres sql - 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.

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

PostgreSQL GREATEST with NULLs

Using PostgreSQL, I am looking for something like SELECT GREATEST(0,x) where x can be NULL. In case x IS NULL, the query should return NULL, similar to MySQL and Google BigQuery and not 0 which is the standard behavior in PostgreSQL. Is there an easy way to accomplish this without cases and conditions?
SELECT GREATEST(0,NULL) should return NULL, not 0
In the official documentation:
The GREATEST and LEAST functions select the largest or smallest value
from a list of any number of expressions. The expressions must all be
convertible to a common data type, which will be the type of the
result (see Section 10.5 for details). NULL values in the list are
ignored. The result will be NULL only if all the expressions evaluate
to NULL.
Note that GREATEST and LEAST are not in the SQL standard, but are a
common extension. Some other databases make them return NULL if any
argument is NULL, rather than only when all are NULL.
https://www.postgresql.org/docs/9.6/functions-conditional.html
I'm looking for a GREATEST function that does not ignore NULLs
You can write your own function:
create function strange_greatest(variadic p_input int[])
returns int
as
$$
select v
from unnest(p_input) as t(v)
order by t desc nulls first
limit 1;
$$
language sql
immutable;
postgres=> select strange_greatest(1,2,4);
strange_greatest
----------------
4
(1 row)
postgres=> select strange_greatest(1,2,null,4);
strange_greatest
----------------
(1 row)
You could add another expression. For numbers:
select greatest(a, b, c) + (a + b + c - (a + b + c))
This is a bit more challenging for other data types. But arrays can help:
select greatest(a, b, c) * nullif( array_position(array[a, b, c], null) is not null), true )::int
For the case of 2 numbers (columns), if your table is like this:
create table tablename(a int, b int);
insert into tablename(a, b) values
(10, 20), (null, 30), (40, null);
then use the function greatest() like this:
select
greatest((a + b) - b, (a + b) - a) "greatest"
from tablename;
If a or b is null then both expressions: (a + b) - b and (a + b) - a are null and the function greatest() will return null.
See the demo.
Results:
| greatest |
| -------- |
| 20 |
| null |
| null |

Return boolean if one element matches among 2 arrays in postgresql

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

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.

Why does my SQL query != "Some Value" not return any rows where NULL?

I'm querying an Oracle db for my MVC project and I found something in my SQL that I was curious about. Why does this Query not return rows where the VALIDATED_BY Column is NULL?
SELECT *
FROM DM_SSA_DEV.REQUESTS
WHERE BATCH_ID = 1399
AND VALIDATED_BY <> 'AUTOUSER'
When I commented out the last line I got my expected 481 results:
SELECT *
FROM DM_SSA_DEV.REQUESTS
WHERE BATCH_ID = 1399
--AND VALIDATED_BY <> 'AUTOUSER'
Finally I found I could circumvent this issue via explicitly handling the NULLs. Was this the right thing to do or was there a better way, and why?
SELECT *
FROM DM_SSA_DEV.REQUESTS
WHERE BATCH_ID = 1399
AND (VALIDATED_BY <> 'AUTOUSER' OR VALIDATED_BY IS NULL)
P.S. I'm also really using Linq in my project so this is the code I used. Most efficient?
db.REQUESTS.Where(r => r.BATCH_ID == batchId && (r.VALIDATED_BY != "AUTOUSER" || r.VALIDATED_BY == NULL)).ToList<REQUEST>();
NULL is never equal (=) to any other value, even another NULL (it is a bit like floating-point NaN). This also includes not equal expressions involving NULL.
The intent can be expressed as x = y OR (y IS NULL and x IS NULL), when NULL values are to be considered equal.
The special case of not-equal or NULL-and-not-equal is x <> y OR x IS NULL, assuming y is never NULL.
Another option is to coalesce, COALESCE(x, '*') = COALESCE(y, '*'), depending on how much the optimizer is trusted and the equality of the coalesced value to NULL. There may also be other vendor extensions.
LINQ/EF will translate x == null (C#, null must be a constant expression) to x IS NULL (SQL).