I can run a statement like
select 'a' like any('a',b'), but is it still possible to run this statement if ('a','b') were in an array?
select 'a' like any(array_construct('a','b')) doesn't work.
You can use a JavaScript UDF to approximate this behavior. Rather than trying to get JavaScript to simulate the like syntax, it's probably better to use richer, more expressive Regular Expressions. This UDF will return true if any array member matches that regexp pattern, false if none do, and null if the regex pattern is invalid or it encounters an unexpected error:
create or replace function LIKE_ANY_ARRAY("arr" array, "pattern" string)
returns boolean
language javascript
strict immutable
as
$$
"option strict"
try {
var regex = RegExp(pattern,"g")
for(let i=0; i<arr.length; i++) {
if(regex.test(arr[i])) return true;
}
return false;
} catch {
return null;
}
$$;
select like_any_array(array_construct('a','b'), 'a'); -- True
select like_any_array(array_construct('abcde','b'), '[a-z]{5}'); -- True
select like_any_array(array_construct('abcde','b'), '[a-z]{8}'); -- False, none have enough letters
select like_any_array(array_construct(2,'b'), '[a-z]{8}'); -- Auto-casting
select like_any_array(array_construct('a', 'b'), '['); -- Invalid regex pattern returns NULL
This is returning a Boolean to approximate the behavior of the LIKE ANY function, but could very easily be converted to returning an array of all the matching members or an integer representing the first match, etc.
You could turn you array into a string that resembles a regex and match against that
where 'a' rlike array_to_string( ['a','b'],'|')
Related
I am looking for a partial match / using some kind of a wild card to do string matching in SNOWFLAKE arrays.
SELECT ARRAY_CONTAINS('HELLO'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI'))
<TRUE>
Tried like this , but no luck
SELECT ARRAY_CONTAINS('HELL%'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI'))
<FALSE>
Is there any other way to do this ?
Maybe you can convert the array (temporarily) to string and use CONTAINS operator?
SELECT CONTAINS( ARRAY_TO_STRING( ARRAY_CONSTRUCT('WHY','HELLO', 'HI'),',') , 'HELL' );
SELECT ARRAY_CONSTRUCT('HELLO', 'HI') AS aa
,':' || ARRAY_TO_STRING(aa,';') || ':' AS bb
,bb like '%:HELL%'
so this is a dirty solution, but it would "work"
You can do this with a JavaScript UDF. This example uses RegExp instead of the like function wildcards. It's overloaded so you can use standard RegExp or one with parameters (i for case insensitivity in particular). This returns a boolean to approximate the behavior of ARRAY_CONTAINS. If you want, you can do a simple modification to return the value of "i", which will be the ordinal position of the first match in the array, or -1 if it leaves the loop (not found).
create or replace function ARRAY_CONTAINS_REGEXP(REGEXP_EXPRESSION string, A array)
returns boolean
language javascript
as
$$
var rx = new RegExp(REGEXP_EXPRESSION);
for (var i = 0; i < A.length; i++){
if (A[i].search(rx) != -1) return true;
}
return false;
$$;
create or replace function ARRAY_CONTAINS_REGEXP(REGEXP_EXPRESSION string, A array, REGEX_PARAMS string)
returns boolean
language javascript
as
$$
var rx = new RegExp(REGEXP_EXPRESSION, REGEX_PARAMS);
for (var i = 0; i < A.length; i++){
if (A[i].search(rx) != -1) return true;
}
return false;
$$;
SELECT ARRAY_CONTAINS_REGEXP('HELL.'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI')); -- True. Wildcard match.
SELECT ARRAY_CONTAINS_REGEXP('HELL'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI')); -- True. Partial match.
SELECT ARRAY_CONTAINS_REGEXP('\\bHEL\\b'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI')); -- False. Full word matching.
SELECT ARRAY_CONTAINS_REGEXP('hel'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI')); -- False. Case sensitive.
SELECT ARRAY_CONTAINS_REGEXP('HeL'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI'), 'i'); -- True. Case insensitive partial match.
SELECT ARRAY_CONTAINS_REGEXP('\\bHeL\\b'::VARIANT, ARRAY_CONSTRUCT('HELLO', 'HI'), 'i'); -- False. Full word insensitive match.
I have a simple online interface for writing Groovy scripts that get incorporated into a larger piece of software. I was bouncing between on project in VB6 and the other in Groovy and so accidentally used one equals sign (which VB6 does for if statements) where I meant to use a double-equals in Groovy.
Could assigning a value to a database field in an if statement in this fashion actually update all of the records for which the rest of the if conditions were true?
Java's assignment operator will return the variable just assigned. If this is inside a statement expecting a boolean it will be evaluated according to Groovy's truthiness. We can see this in the Groovy console with some asserts:
groovy:000> assert (foo = 1)
===> null
groovy:000> assert (foo = 0)
ERROR org.codehaus.groovy.runtime.powerassert.PowerAssertionError:
assert (foo = 0)
|
0
or with an if statement:
groovy:000> if ((foo = 'bar')) {
groovy:001> println "Assignment was true!"
groovy:002> }
Assignment was true!
Note that you need the double parentheses for this to "work" because without them you will get a compile error trying to parse it:
groovy:000> if (foo = 'bar') {
groovy:001> println "Assignment was true!"
groovysh_parse: 2: expecting ')', found '=' # line 2, column 9.
if (foo = 'bar') {
^
It can be pretty insidious. It has some use cases though, like a while loop that iterates on a method's return value until it returns false:
while (data = getData()) {
doWork(data)
}
println "Done with all the data"
Is there 'concat' function in GreenPlum? I can use concat function in postgresql and it works well, but when i use it in Greenplum, I got an error.
select concat('a', 'b');
ERROR: function concat(unknown, unknown) does not exist at character 8
HINT: No function matches the given name and argument types. You may need to add explicit type casts.
LINE 1: select concat('a', 'b');
^
Is there some other functions can instead of 'concat' function in GreenPlum? And I have tried to create a function to instead of it, but got some syntax errors also.
CREATE OR REPLACE FUNCTION my_concat(VARIADIC arr VARCHAR[] ) RETURNS VARCHAR AS $$ SELECT array_to_string(arr, ''); $$ LANGUAGE SQL;
ERROR: syntax error at or near "VARCHAR" at character 51
LINE 1: CREATE OR REPLACE FUNCTION my_concat(VARIADIC arr VARCHAR[] ...
^
Anyone can help? Thanks very much!
Like most databases, Greenplum uses "||" to concatenate two strings together.
SELECT 'Green' || 'plum';
Result:
Greenplum
its a versional issue , you have use || in place where ever u using contact function.
Greenplum doesn't have the concat function yet. May be you can modify your code to use "||" instead of concat.
Well,
First I agree that you should replace your code to use the correct SQL syntax '||' for concatenation.
If you really want to create a function to emulate the concat, you could do something like:
create or replace function myschema.concat(arg1 text, arg2 text)
returns text as
$body$
declare
v_arg1 text;
v_arg2 text;
begin
v_arg1 := arg1;
v_arg2 := arg2;
return v_arg1 || v_arg2;
end
$body$
language plpgsql volatile;
Then, the query will work:
select myschema.concat('test1', 'test2');
>>test1test2
Hope you are looking for the below query.
gpadmin=# CREATE OR REPLACE FUNCTION my_concat( character varying[] ) RETURNS VARCHAR AS $$ SELECT array_to_string($1, ''); $$ LANGUAGE SQL;
gpadmin=# select my_concat(ARRAY['Green','plum']);
my_concat
Greenplum
I'm trying to build a JSON object that contains an array, using SQL Server 2016.
The source data for the array is itself JSON, so I'm using the JSON_QUERY inside a select statement, with the FOR JSON clause applied to the select statement.
Everything works beautifully until I wrap the JSON_QUERY clause in a CASE statement (in certain cases the array must not be included, i.e. must be null).
The following code illustrates the problem:
declare #projects nvarchar(max) = '{"projects": [23439658267415,166584258534050]}'
declare #id bigint = 123
SELECT
[data.array1] = JSON_QUERY(#projects, '$.projects') -- returns an array - perfect.
, [data.array2] = CASE WHEN 1 is NOT NULL
THEN JSON_QUERY(#projects, '$.projects')
ELSE NULL END -- returns an array - still good!
, [data.array3] = CASE WHEN #id is NOT NULL
THEN JSON_QUERY(#projects, '$.projects')
ELSE NULL END -- why do I end up with a string in the JSON when I do this?
FOR JSON PATH, without_array_wrapper
This code returns the following JSON:
{
"data":{
"array1": [23439658267415,166584258534050],
"array2": [23439658267415,166584258534050],
"array3":"[23439658267415,166584258534050]"
}
}
The problem is that the third 'array' is returned as a string object.
I would expect it to return the following JSON:
{
"data":{
"array1": [23439658267415,166584258534050],
"array2": [23439658267415,166584258534050],
"array3": [23439658267415,166584258534050]
}
}
If I remove the FOR JSON PATH... clause, all columns returned by the query are identical (i.e. all three nvarchar values returned by the JSON_QUERY function are identical).
Why is this happening, how do I make it output an array in the final JSON?
Wrap the result from the case statement in a call to JSON_QUERY.
, [data.array3] = JSON_QUERY(
CASE WHEN #id is NOT NULL
THEN JSON_QUERY(#projects, '$.projects')
ELSE NULL END
)
According to the documentation JSON_QUERY "Extracts an object or an array from a JSON string". Further down it says "Returns a JSON fragment of type nvarchar(max).". A bit confusing.
Doing a for xml json on a string value will give you a string value in the returned JSON string and when you do it on a JSON object you get the JSON object inlined in the resulting string value.
You can look at CASE as a function call with a return value automatically determined for you by looking at what values you are returning from the CASE. And since JSON_QUERY returns a string the case will return a string and the returned value will be a string value in JSON.
The case statement in the query plan looks like this.
<ScalarOperator ScalarString="CASE WHEN [#id] IS NOT NULL THEN json_query([#projects],N'$.projects') ELSE NULL END">
When you wrap the case in a call to JSON_QUERY it looks like this instead.
<ScalarOperator ScalarString="json_query(CASE WHEN [#id] IS NOT NULL THEN json_query([#projects],N'$.projects') ELSE NULL END)">
<Intrinsic FunctionName="json_query">
By some kind of internal magic SQL Server recognize this as a JSON object instead of a string and inserts it into the resulting JSON string as a JSON value instead.
CASE WHEN 1 is NOT NULL works because SQL Server is smart enough to see that the case statement will always be true and is optimized away.
I have a function in Postgres which return a setof composite type. When returning I am only able do it with return next; but not with return query command, why is that?
CREATE TYPE return_type AS
(paramname character varying,
value character varying);
CREATE OR REPLACE FUNCTION test(i_param1 character varying, i_param2 character varying)
RETURNS SETOF return_type AS
--this works just fine returning two rows
r.paramname:='row1';
r.value:='myvalue1';
return next r;
r.paramname:='row1';
r.value:='myvalue1';
return next r;
return;
-- with this command I do not get a single row attached in the resultset
return query
select 'row1' as paraName,'myvalue1' as value
UNION ALL
select 'row2' as paraName,'myvalue2' as value;
return;
This works for me, even in Postgres 8.4:
CREATE OR REPLACE FUNCTION test(i_param1 varchar, i_param2 varchar)
RETURNS SETOF return_type AS
$func$
BEGIN
RETURN QUERY
SELECT 'row1'::varchar, 'myvalue1'::varchar
UNION ALL
SELECT 'row2','myvalue2';
END
$func$ LANGUAGE plpgsql;
Your original should only return an exception, because of type mismatch. You need to cast the string literals to matching types. On the other hand, column aliases are irrelevant here: not visible outside the function body.
SQL Fiddle