checking element present in an array using sql - sql

I have a table with 3 columns: col1,col2,col3. Column3 is an array.
col3
[abc,def,xyz]
[abc,qwe,pou]
[]
[qwe,xyz]
[qwe,pou]
I have to write a sql query where i get col1, col2 and instead of col3, i have check whether it has value in('abc','xyz'). If it has these values then new_col = 1 else 0.
So the new_col looks like this:
new_col
1
1
0
1
0
i am looking for something like
select col1,col2, case when col3 in('xyz','abc')then 1 else 0 end as new_col from table
But this gives me an error saying "IN value and list items must have same type:array(varchar)"

This solution worked for me.
select col1, col2,case when cardinality(filter(col3, x->x in( 'abc', 'xyz')))>0 then 1 else 0 end as new_col from <table>

In Amazona Athena engine version 3 you should be able to use any_match from array functions:
with dataset(arr) as(
values (array ['abc','def','xyz']),
(array ['abc','qwe','pou']),
(array []),
(array ['qwe','xyz']),
(array ['qwe','pou'])
)
select if(any_match(arr, e -> e in ( 'abc', 'xyz')), 1, 0)
from dataset;
Output:
_col0
1
1
0
1
0
For earlier version you can use array_intersect:
select if(cardinality(array_intersect(arr, array['abc', 'xyz'])) > 0, 1, 0)
from dataset;

Related

Returning the maximum of non-null columns ​from a table

I have a table with 4 columns, one of which is a non-null column, all others can be given a null value.
I just want a SELECT that returns results that have as many non-null columns as possible.
For example:
If I have 5 records in my Table, 1 of those records will have 3 columns with data, 2 of them will have 2 columns with data and 2 of them will have only 1 column with data. In my select, I want as a result only the first option: to bring me 3 columns with data. But it can be just 2 columns with data, it will be dynamic according to the table to be updated.
I'm using Oracle SQL.
One option is a conditional sort based on the count of non-null values in each row, and then a row-limiting clause (available since Oracle 12c). Assuming that the 3 nullable columns are col1, col2 and col3, that would be:
select *
from mytable
order by
case when col1 is null then 0 else 1 end
+ case when col2 is null then 0 else 1 end
+ case when col3 is null then 0 else 1 end desc
fetch first row with ties
If you are running an older version of Oracle, you can get the same result with window function rank():
select *
from (
select
t.*,
rank() over(order by
case when col1 is null then 0 else 1 end
+ case when col2 is null then 0 else 1 end
+ case when col3 is null then 0 else 1 end desc
) rn
from mytable t
) t
where rn = 1

How to check If table contains diferent values?

I have table:
Id Value
1 79868
2 79868
3 79868
4 97889
5 97889
Now, I want to make next select with bool variable that check if table contains difrent values at table column Value. Something like this:
select
v= (select case when exists(...)
then 1
else 0
end)
Table contais Values: 79868, 97889 so v should return 1 in other case 0.
How to write select iniside select case??
You can compare the min and max values:
select (case when (select min(value) from t) = (select max(value) from t)
then 1 else 0
end) as all_same
With an index on (value), this should be quite fast.
The above solution assumes that there are no null values or that NULL values should be ignored.
You might try this:
SELECT CASE COUNT(*)
WHEN 1 THEN 1
ELSE 0
END AS all_equal
FROM (SELECT DISTINCT Value FROM my_table);
If I get your question correct, you want to check if value column contains more than 1 distinct values. You can achieve this using,
select (case when count(value) > 1 then 1 else 0 end) as out
from (select value from table group by value) temp
May this is better:
SELECT CASE COUNT(DISTINCT value) WHEN 1 THEN 1
ELSE 0
END AS all_equal
FROM my_table;
So, you just need one case expression with two Boolean variable
declare #bit1 bit = 1, #bit0 bit = 0
select
(case when min(value) = max(value) then #bit1 else #bit0 end) as v
from table t
where value is not null
This is a the same as another answers
But is has some test data
declare #T table(pk int identity primary key, val int not null);
insert into #T (val) values (79868), (79868), (79868);
select case when count(distinct(val)) = 1 then 0 else 1 end as dd
from #t t;
select case when min(val) = max(val) then 0 else 1 end as dd
from #t t;
insert into #T (val) values (97889), (97889);
select case when count(distinct(val)) = 1 then 0 else 1 end as dd
from #t t;
select case when min(val) = max(val) then 0 else 1 end as dd
from #t t;
I like the min max answer from Gordon best

How to find count of multiple columns in sql group by id?

I have a table with schema like below:
root
|id
|name
|col1
|col2
|...
|col30
Conditions are that multiple rows can have the same name (they're not primary key - the key is the ID). Values in col1-col30 will be some string, or it can have the string "null".
I'm interested in the number of columns filled in for each name.
For example,
if name "test1" has col1-5 filled in a row, and another row has "test1" and have col1, 3, 10, 6 filled in (and the rest of unfilled columns are just string value "null"), "test1" should have value 9.
I'm pretty new to SQL and have been looking this up.. Please help.
Give this a try:
SELECT
name,
CASE WHEN col1_max IS NOT NULL THEN 1 ELSE 0 END + -- Only include non-NULL values
CASE WHEN col2_max IS NOT NULL THEN 1 ELSE 0 END
FROM (
SELECT
name,
MAX(col1) AS col1_max, -- Non-NULL values come before NULL
MAX(col2) AS col2_max
FROM MyTable
GROUP BY name
) src
You can add more the rest of the columns to fit your case.
Updated
I just realized your NULL case is with a "null" string. Modified:
SELECT
name,
CASE WHEN col1_max IS NOT NULL THEN 1 ELSE 0 END + -- Only include non-NULL values
CASE WHEN col2_max IS NOT NULL THEN 1 ELSE 0 END
FROM (
SELECT
name,
MAX(CASE WHEN col1 = 'null' THEN NULL ELSE col1 END) AS col1_max, -- Non-NULL values come before NULL
MAX(CASE WHEN col2 = 'null' THEN NULL ELSE col2 END) AS col2_max
FROM MyTable
GROUP BY name
) src
First you unpivot your table and count those rows that have not null values. In postgres, you can achieve this with unnest. I have only used col1..7 -- change to upto col30 in your case
WITH t AS(
SELECT id,name,
unnest(array['col1', 'col2', 'col3', 'col4', 'col5', 'col6', 'col7']) AS colname,
unnest(array[col1, col2, col3, col4, col5, col6, col7]) AS colvalue
FROM your_table)
SELECT id, name,
SUM(CASE WHEN colvalue IS NULL THEN 0 ELSE 1 END) AS count_filled
FROM t
GROUP BY 1,2;

How to do countIf() in Oracle

How do I select a variable which gives an output the same as the excel function:
COUNTIFS(A1:D1,"<25", A1:D1, ">16")?
I.e. to count the number of times the values in my four fields are between 16 and 25.
You can do this with count() and case expressions. Note: case has an optional else clause; if it is not used, then the default else "value" is null. Count only counts non-null values, so you can combine these observations to write compact code. WHAT is counted doesn't matter; so the case expression may return a number (1 is usual, but 0 is just as valid and will give the same result, since the values are COUNTED, not SUMMED) - but you could also have a string like 'x' or a date in the case expression. Just to illustrate that, I will use a string.
select count( case when col > 16 and col < 25 then 'x' end ) as ct from your_table;
Here your_table is the name of your table, col is the name of the column containing the values, and ct is the name of the resulting column (the label for the count of values that satisfy your condition).
Of course, in a database you can get the same result more easily:
select count(*) as ct from your_table where col > 16 and col < 25;
Note, though, that the values are in one column.
If instead you have a table with four COLUMNS and many rows, and all the values in all columns are numbers, and you want to add a column showing how many values are strictly between 16 and 25 IN EACH ROW, the solution is different (but it uses the same ideas):
select col1, col2, col3, col4,
case when col1 > 16 and col1 < 25 then 1 else 0 end +
case when col2 > 16 and col2 < 25 then 1 else 0 end +
case when col3 > 16 and col3 < 25 then 1 else 0 end +
case when col4 > 16 and col4 < 25 then 1 else 0 end as ct
from my_table;
You would do this in a SQL query using case:
select sum(case when col between 16 and 25 then 1 else 0 end)
from t;
Note that between is inclusive in SQL, not exclusive, so based on your code logic:
select sum(case when col > 16 and col < 25 then 1 else 0 end)
from t;
Think, you have a 'user_table', where some of the user's 'status' are active (code-11) and others are inactive (code-22). You can count active and inactive with this sql below.
select count(case when status = 11 then 1 end) u_active, count(case when status = 22 then 1 end) u_inactive, from user_table;

Checking to see if multiple conditions are true within a group in SQL

Lets say I have the following table depicting a one-many relationship
col1 | col2
-------------
1 | foo
1 | bar
2 | foo
3 | buzz
I need to group by col1 and I need a boolean indicating whether or not there is both a mapping to 'foo' and a mapping to 'bar'.
So, the final result set would be
col1 | foobar
-------------
1 | 1
2 | 0
3 | 0
What is the best way to achieve this in T-SQL?
I've been trying something roughly equivalent to the following query with no luck.
SELECT
col1
, (
MAX (
CASE WHEN
COL2 = 'foo'
THEN 1 ELSE 0
END) = 1
AND
MAX (
CASE WHEN
COL2 = 'bar'
THEN 1 ELSE 0
END) = 1
)
FROM
table
GROUP BY
col1
EDIT:
To clarify, this table is a simplification.
I am looking for a solution to the general problem of having a one-many mapping and needing to produce a new 1-1 mapping with a Boolean indicating if a variable number of predicates are true of the different elements in the groups in the co-domain. (grouped by the fact that the same element maps to them)
Also, I should clarify that these various predicates could be anything.
For example, maybe I want to see if at least one of the columns in one of the rows = 'foo' and also that a different column in a (possibly different) row within the same group is between a certain set of numeric values.
What about this?
EDIT: Better use COUNT(DISTINCT col2)
DECLARE #tbl TABLE(col1 INT,col2 VARCHAR(100));
INSERT INTO #tbl VALUES
(1,'foo')
,(1,'bar')
,(2,'foo')
,(3,'buzz');
SELECT col1
,COUNT(DISTINCT col2)-1
FROM #tbl
GROUP BY col1
UPDATE:
If you try it like this, you would even see, which values are there. If you are only interested in "one or many" you might check for a comma in the returned string:
DECLARE #tbl TABLE(col1 INT,col2 VARCHAR(100));
INSERT INTO #tbl VALUES
(1,'foo')
,(1,'bar')
,(2,'foo')
,(3,'buzz');
SELECT outerTbl.col1
,STUFF
(
(
SELECT DISTINCT ', ' + col2
FROM #tbl AS innerTbl
WHERE innerTbl.col1=outerTbl.col1
FOR XML PATH('')
),1,2,''
)
FROM #tbl AS outerTbl
GROUP BY outerTbl.col1
This is the result:
1 bar, foo
2 foo
3 buzz
Here is a simple option
select col1
,MAX(case when col2='foo' then 1 else 0 end)*MAX(case when col2='bar' then 1 else 0 end) foobar
from #tbl
group by col1
Try this:
select
col1,
case when foo > 0 and bar > 0 then true else false end foobar
from (
select
col1,
sum(case when col2 = 'foo' then 1 end) foo,
sum(case when col2 = 'bar' then 1 end) bar
from table
group by col1) x