Case statement throwing invalid argument type error - snowflake-cloud-data-platform

Hi I'm working on a snowflake query.
Case when x = a then 1
When ifnull(a,' ') <> b then 1 end as
I'm hiding the original column names.
The above case statement throwing error
invalid argument types for function '<>':(Row(varchar(25),varchar(1)),varchar(11)) .
Please help me!

i tried this and it worked, please check your code.
create or replace table test(x varchar2, a varchar2, b varchar2) ;
select a, b, case when x = a then 1
when ifnull(a, '') <> b then 1 end from test;

Related

PostgreSQL C aggregate function: How to return multiple values in transition function [duplicate]

Is the only way to pass an extra parameter to the final function of a PostgreSQL aggregate to create a special TYPE for the state value?
e.g.:
CREATE TYPE geomvaltext AS (
geom public.geometry,
val double precision,
txt text
);
And then to use this type as the state variable so that the third parameter (text) finally reaches the final function?
Why aggregates can't pass extra parameters to the final function themselves? Any implementation reason?
So we could easily construct, for example, aggregates taking a method:
SELECT ST_MyAgg(accum_number, 'COMPUTE_METHOD') FROM blablabla
Thanks
You can define an aggregate with more than one parameter.
I don't know if that solves your problem, but you could use it like this:
CREATE OR REPLACE FUNCTION myaggsfunc(integer, integer, text) RETURNS integer
IMMUTABLE STRICT LANGUAGE sql AS
$f$
SELECT CASE $3
WHEN '+' THEN $1 + $2
WHEN '*' THEN $1 * $2
ELSE NULL
END
$f$;
CREATE AGGREGATE myagg(integer, text) (
SFUNC = myaggsfunc(integer, integer, text),
STYPE = integer
);
It could be used like this:
CREATE TABLE mytab
AS SELECT * FROM generate_series(1, 10) i;
SELECT myagg(i, '+') FROM mytab;
myagg
-------
55
(1 row)
SELECT myagg(i, '*') FROM mytab;
myagg
---------
3628800
(1 row)
I solved a similar issue by making a custom aggregate function that did all the operations at once and stored their states in an array.
CREATE AGGREGATE myagg(integer)
(
INITCOND = '{ 0, 1 }',
STYPE = integer[],
SFUNC = myaggsfunc
);
and:
CREATE OR REPLACE FUNCTION myaggsfunc(agg_state integer[], agg_next integer)
RETURNS integer[] IMMUTABLE STRICT LANGUAGE 'plpgsql' AS $$
BEGIN
agg_state[1] := agg_state[1] + agg_next;
agg_state[2] := agg_state[2] * agg_next;
RETURN agg_state;
END;
$$;
Then made another function that selected one of the results based on the second argument:
CREATE OR REPLACE FUNCTION myagg_pick(agg_state integer[], agg_fn character varying)
RETURNS integer IMMUTABLE STRICT LANGUAGE 'plpgsql' AS $$
BEGIN
CASE agg_fn
WHEN '+' THEN RETURN agg_state[1];
WHEN '*' THEN RETURN agg_state[2];
ELSE RETURN 0;
END CASE;
END;
$$;
Usage:
SELECT myagg_pick(myagg("accum_number"), 'COMPUTE_METHOD') FROM "mytable" GROUP BY ...
Obvious downside of this is the overhead of performing all the functions instead of just one. However when dealing with simple operations such as adding, multiplying etc. it should be acceptable in most cases.
You would have to rewrite the final function itself, and in that case you might as well write a set of new aggregate functions, one for each possible COMPUTE_METHOD. If the COMPUTE_METHOD is a data value or implied by a data value, then a CASE statement can be used to select the appropriate aggregate method. Alternatively, you may want to create a custom composite type with fields for accum_number and COMPUTE_METHOD, and write a single new aggregate function that uses this new data type.

Why this Code is Giving ERROR

I am unable to use simple SELECT statement to initialize a variable.
DECLARE
A VARCHAR2(10);
BEGIN
A := (SELECT FIRST_NAME FROM FIMS_OWNER.EMPLOYEE_T WHERE WWID = 'NA734');
END;
/
ERROR:
[Error] Execution (4: 11): ORA-06550: line 4, column 11:
PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:
( - + case mod new not null <an identifier>
<a double-quoted delimited-identifier> <a bind variable>
continue avg count current exists max min prior sql stddev
sum variance execute forall merge time timestamp interval
date <a string literal with character set specification>
<a number> <a single-quoted SQL string> pipe
<an alternatively-quoted string literal with character set specification>
<an alternat
ORA-06550: line 4, column 76:
PLS-00103: Encountered the symbol ")" when expecting one of the following:
* & - + ; / at for mod remainder rem <an exponent (**)> and
or group having intersect minus order start union where
connect || multiset
And if it's not possible, what's the alternative for the same.
PS: I am using such query to set the variable(and later use it) with my cursor which takes the WWID dynamically and then changes the value accordingly.
Image: http://i.stack.imgur.com/wzSDk.png
Because in Oracle you cannot assign a query to a variable. However, you can query into a variable, as in ...
DECLARE
A VARCHAR2(10);
BEGIN
SELECT FIRST_NAME
INTO A
FROM FIMS_OWNER.EMPLOYEE_T
WHERE WWID = 'NA734';
END;
/
your code should be
DECLARE
A VARCHAR2(10);
BEGIN
SELECT FIRST_NAME INTO A FROM FIMS_OWNER.EMPLOYEE_T WHERE WWID = 'NA734';
END;
You should use the INTO clause to select a value into a variable

How to replace a value in array

I have a data like below.
id col1[]
--- ------
1 {1,2,3}
2 {3,4,5}
My question is how to use replace function in arrays.
select array_replace(col1, 1, 100) where id = 1;
but it gives an error like:
function array_replace(integer[], integer, integer) does not exist
can anyone suggest how to use it?
Your statement (augmented with the missing FROM clause):
SELECT array_replace(col1, 1, 100) FROM tbl WHERE id = 1;
As commented by #mu, array_replace() was introduced with pg 9.3. I see 3 options for older versions:
1. intarray
As long as ...
we are dealing with integer arrays.
elements are unique.
and the order of elements is irrelevant.
A simple and fast option would be to install the additional module intarray, which (among other things) provides operators to subtract and add elements (or whole arrays) from/to integer arrays:
SELECT CASE col1 && '{1}'::int[] THEN (col1 - 1) + 100 ELSE col1 END AS col1
FROM tbl WHERE id = 1;
2. Emulate with SQL functions
A (slower) drop-in replacement for array_replace() using polymorphic types, so it works for any base type:
CREATE OR REPLACE FUNCTION f_array_replace(anyarray, anyelement, anyelement)
RETURNS anyarray LANGUAGE SQL IMMUTABLE AS
'SELECT ARRAY (SELECT CASE WHEN x = $2 THEN $3 ELSE x END FROM unnest($1) x)';
Does not replace NULL values. Related:
Replace NULL values in an array in PostgreSQL
If you need to guarantee order of elements:
PostgreSQL unnest() with element number
3. Apply patch to source and recompile
Get the patch "Add array_remove() and array_replace() functions" from the git repo, apply it to the source of your version and recompile. May or may not apply cleanly. The older your version the worse are your chances. I have not tried that, I would rather upgrade to the current version.
You can create your own
based on this source :
CREATE TABLE arr(id int, col1 int[]);
INSERT INTO arr VALUES (1, '{1,2,3}');
INSERT INTO arr VALUES (2, '{3,4,5}');
SELECT array(
SELECT CASE WHEN q = 1 THEN 100 ELSE q END
FROM UNNEST(col1::int[]) q)
FROM arr;
array
-----------
{100,2,3}
{3,4,5}
You can create your own function and put it in your public schema if you still want to call by function though it will be slightly different than the original.
UPDATE tbl SET col1 = array_replace(col1, 1, 100) WHERE id = 1;
Here is the sample query for a test-array:
SELECT test_id,
test_array,
(array (
-- Replace existing value 'int' of an array with given value 'Text'
SELECT CASE WHEN a = '0' THEN 'MyEntry'
WHEN a = '1' THEN 'Apple'
WHEN a = '2' THEN 'Banana'
WHEN a = '3' THEN 'ChErRiEs'
WHEN a = '4' THEN 'Dragon Fruit'
WHEN a = '5' THEN 'Eat a Fruit in a Day'
ELSE 'NONE' END
FROM UNNEST(test_array::TEXT[]) a) ::TEXT
-- UNNEST : Lists out values of my_test_array
) test_result
FROM (
--my_test_array
SELECT 1 test_id, '{0,1,2,3,4,5,6,7,8,9}'::TEXT[][] test_array
) test;

Error passing array of ints to a plpgsql function (postgres 8.3.7)

I have the following function, which receives an array of ints, iterates it calling other function:
CREATE FUNCTION calculateAbsencesForIDs(INT[]) RETURNS TEXT AS
'
DECLARE
index integer := 0;
resultArray decimal[];
id int;
result text;
BEGIN
FOR id IN SELECT $1 LOOP
resultArray[index] = calculateAbsenceForID(id);
index := index + 1;
END LOOP;
RETURN array_to_string(resultArray, result);
END;
'
LANGUAGE plpgsql;
I try to call it using:
SELECT calculateAbsencesForIDs(ARRAY[85,74,75,76,77,78,79,80]);
or
SELECT calculateAbsencesForIDs('{85,74,75,76,77,78,79,80}');
or
SELECT calculateAbsencesForIDs('{85,74,75,76,77,78,79,80}'::int[]);
...
But I have always the same error:
[Error Code: 0, SQL State: 22P02] ERROR: invalid input syntax for integer: "{85,74,75,76,77,78,79,80}"
I don't know how I can call this function. I have looked in postgres docs, I think this is correct but it doesn`t work.
This line:
FOR id IN SELECT $1 LOOP
means that you assign id to each value from SELECT $1 which returns a single record with a single field of type INT[].
As id is declared as INT, you get the conversion error you're observing.
In 8.4 and above you could use UNNEST, in 8.3 replace it with
FOR id IN
SELECT $1[i]
FROM generate_series(1, ARRAY_UPPER($1, 1)) i
LOOP
Alternatively, you could just do:
SELECT ARRAY_TO_STRING
(
ARRAY
(
SELECT calculateAbsenceForID($1[i])
FROM generate_series(1, ARRAY_UPPER($1, 1)) i
)
)
You need to loop over the elements of the array like this:
BEGIN
FOR i in 1 .. array_length($1, 1) LOOP
resultArray[i] = calculateAbsenceForID($1[i]);
END LOOP;
RETURN array_to_string(resultArray, result);
END;
Note that this will throw an error if $1 is NULL

I need to know how i can write IF statements and CASE break statements that use and execute queries, etc in MySQL?

I need to execute a query that is highly dependent on several conditions what need to be checked by analyzing that data in other tables, the base goal is to return the rows from the tables if all of the conditions in the other tables are true, I am fed up with INNER joins LEFT joins and WHERE statement, i need to look up one table, if the returned value is 1, 0 or 4 or a set of values, i need to execute an other statement, and based on the resuts of that i need to execute one last statement which is my final result.
as far as functions are procedures are concerned, i studies the MySQL documentation like hell and all it gives me is this ::
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `SimpleCompare`(n INT, m INT) RETURNS varchar(20) CHARSET latin1
BEGIN
DECLARE s VARCHAR(20);
IF n > m THEN SET s = '>';
ELSEIF n = m THEN SET s = '=';
ELSE SET s = '<';
END IF;
SET s = CONCAT(n, ' ', s, ' ', m);
RETURN s;
END
Now this is so plain, i dont even know where to start, I the "returns varchar(20)" what does it need to be if im expecting it to return a table of 10 rows and not a VARCHAR(20), what do I declare "DECLARE s VARCHAR(20);" as if i want it to be a table not a VARCHAR(20).
the (n > m) after the "IF" how to i replace it with my own query ,
and after I do that, the "THEN SET s = '>'" how do i set s = to the query results ?, this is driving me crazy the syntax is beyond me, and the documentation does not explain anything.
Thanks in advance
To my knowledge, MySQL doesn't support a table valued data type. The use of the function you posted would be:
SELECT simplecompare(yt.n, yt.m) AS eval
FROM YOUR_TABE yt
...which would return:
eval
--------
1 = 1
2 < 3
etc.
SQL is set based, which is different from typical programming (procedural or OO).

Resources