How to do countIf() in Oracle - sql

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;

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

returning the column values as a list or else 0

I had a query where i am trying to get the results of a query, the query can have multiple rows or it can be empty, i am trying if it is empty, it should return me 0 for a column i am looking which is called as sequence
My query is like this:
select CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END AS Sequence
from dbo.mytable
it returns me the either 1 or 0, for 1 i want that column should return me values or it should combine all the rows and return me the value of that column as list like 1,2,3,4,5,6,7
This should work.
SELECT
CASE WHEN MY_COUNT > 0 THEN 1 ELSE 0 END AS SEQUENCE
FROM
(SELECT COUNT(*) AS MY_COUNT
FROM
DBO.MYTABLE);
If you want only one row in the result set, simply do:
select (case when count(*) > 0 then 1 else 0 end) as sequence
from mytable;
If you care at all about performance, the more efficient method is:
select (case when exists (select 1 from dbo.mytable) then 1 else 0
end) as sequence

Check any 4 out 10 conditions are satisfied in SQL

I apologize for asking a very vague question but here it is.
I have to write a SQL query in SQL Server as follows.
I have a table say tblA having 10 columns from col1, col2,.....col10.
Each column is not null and definitely holds some value and all of type int.
The query should be to select all such records in which at least 4 columns are matching with given filter criteria, where the filter criteria has values for all 10 columns.
I googled dint get a clue. It needs to be done in SQL server and single query.
Please suggest.
Thanks in advance.
SELECT *
FROM
yourtable
WHERE
case col1 when #value1 then 1 else 0 end +
case col2 when #value2 then 1 else 0 end +
...
case col10 when #value10 then 1 else 0 end
>=4
You can use CASE expressions to determine if four or more columns match:
SELECT *
FROM YourTable
WHERE CASE WHEN Col1 = Filter1 THEN 1 ELSE 0 END +
CASE WHEN Col2 = Filter2 THEN 1 ELSE 0 END +
....
CASE WHEN Col10 = Filter10 THEN 1 ELSE 0 END >= 4
You can do something like this:
select *
from (select t.*,
(case when col1 <whatever> then 1 else 0 end) as col01_matches,
(case when col2 <whatever> then 1 else 0 end) as col02_matches,
. . .
from t
) t
where (col1_matches + col2_matches + col3_matches . . .) >= 4
This creates a separate indicator variable for each match. You could also do the sum in the subquery, in a single variable. I would prefer to have each match separately, just in case the logic gets more complicated or I want to see what matches.

query sql returning custom value

I have a table with 3 columns (containing Integer values that assume only values from 0 to 10). I want extract, with a single query, a table with 1 column. This column must assume a value based on the following logic:
If one of these three columns has value 0 ----> the value of column of table generated by query must be 0 too.
If none of the last three columns has value 0 ----> the value of column must assume the value 1.
You are looking for CASE construct or IF function:
SELECT CASE WHEN (t.field1 = 0 OR t.field2 = 0 OR t.field3 = 0) THEN 0
ELSE 1 END AS value
FROM t;
In this specific case you might also use the fact that any member being zero will zero the product:
SELECT CASE WHEN (t.field1*t.field2*t.field3 = 0) THEN 0 ELSE 1 END AS value
FROM t;
Or
SELECT IF((t.field1*t.field2*t.field3)=0, 0, 1) AS value FROM t;
This is a simple case statement. Assuming there are no NULL values, try this:
select (case when col1 = 0 or col2 = 0 or col3 = 0 then 0 else 1 end)
Try this
SELECT
CASE
WHEN column1 = 0 THEN 0
WHEN column2 = 0 THEN 0
WHEN column3 = 0 THEN 0
ELSE 1
END
FROM urtable

SQL Selecting MIN value from row data with null values

My table in Oracle is like this
Col Col1 Col2 Col3 ColR
-- ---- ---- ---- ----
30 73 40 null -10
60 32 null 20 40
90 80 null null 10
80 45 81 30 50
I can also set 0 instead of null in the above column.
I need to find the min value from Col1,Col2,Col3 ignoring null or 0 and populate the ColR by subtracting from Col.
EDIT:
i wrote a CASE statement which doesn't work due to the null values inside my table.
SELECT col,col1,col2,col3,
CASE
WHEN Col1 < Col2 AND Col1 < Col3
THEN Col - Col1
WHEN Col2 < Col1 AND Col2 < Col3
THEN Col - Col2
ELSE Col - Col3
END ColR
FROM
(SELECT col,col1,
CASE
WHEN col22 IS NULL
THEN NULL( i can also SET TO 0 but it will mess WITH my other calculation TO find MIN)
ELSE ROUND( 100* ( (col22) / (col44)))
END col2 ,
CASE
WHEN col33 IS NULL
THEN NULL
ELSE ROUND( 100* ( (col33) / (col44)))
END col3
FROM TABLE
)
I have just included the case statement inside my select query. all the the column values all populated from another query.
It sounds like you want something like
SELECT least( (case when col1 is null or col1 = 0 then 999999999 else col1 end),
(case when col2 is null or col2 = 0 then 999999999 else col2 end),
(case when col3 is null or col3 = 0 then 999999999 else col3 end) )
FROM <<table name>>
where 999999999 is some numeric value that is large enough that it will always be larger than any other valid value. If it is possible that all three columns will have NULL or 0 values, then you'd probably want to add an additional check that if the result of that least function is 999999999 that you return 0 or NULL or whatever else makes sense.
#X-Zero was kind enough to put together a working SQL Fiddle example of this construct. Note that his example is filtering out the rows where all three columns have either NULL or 0 values.
// IF YOU NEED MINIMAL FROM COL1 or COL (ANY COLUMN)
SELECT MIN (COL1) FROM (SELECT * FROM TABLE WHERE COL1 IS NOT NULL)
Can you please elaborate I am not able to help you with this small set of info actually.
Oracle NVL Usage:
nvl(check_expression, replacement_value)
So
nvl(col2,0) ought to take of nulls that mess with your math.
So try:
CASE
WHEN nvl(col1,0) < nvl(col2,0) AND nvl(col1,0) < nvl(col3,0)
THEN Col - nvl(col1,0)
WHEN nvl(col2,0) < nvl(col1,0) AND nvl(col2,0) < nvl(col3,0)
THEN Col - nvl(col2,0)
ELSE Col - nvl(col3,0)
END ColR
EDIT: Taking X-Zero's point which I missed. I think if you replace the NULLS with 9999999 instead of 0, the logic will work, although that may be too specific to this sample data and not a real world solution.
If you want to ignore nulls in a column, you could wrap them with the NVL function. This replaces null values in a column with the value specified, for which you could use some large number. For example:
NVL(col1,99999)
Oracle Database SQL Reference - NVL: http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions105.htm