SQL Ignore non matching columns - sql

I'm trying to develop a stored procedure which does a select on a table. The stored procedure has 4 inputs: Input1, Input2, Input3, Input4.
Table has 4 columns: Col1,Col2,Col3, Col4.
The requirement is if there is no match on all selects, we need to ignore that and select pick next one:
Use case:
Select *
from table
where Col1=Input1
and Col2=Input2
and Col3=Input3
and Col4=Input4;
If there are no returns for the condition due to Col2 not equal to Input2, select needs to ignore it and try to match on others like:
Select *
from table
where Col1=Input1
and Col3=Input3
and Col4=Input4;
It should go like that till last possible option for the response:
Select *
from table
where Col1=Input1;
Please assist if there is a way and thanks in advance.

As it's mentioned in the comments, the question is a bit vague so I'm afraid any answer would be a bit vague too. You could do something like this:
select top 1 *,
case when Coll=input1 then 1 else 0 end as match1,
case when Col2=input2 then 1 else 0 end as match2,
case when Col3=input3 then 1 else 0 end as match3,
case when Col4=input4 then 1 else 0 end as match4
from table
order by match1+match2+match3+match4 desc
this is assuming SQL server as the DBMS (if it is Oracle, you may need to use LIMIT instead of TOP, for instance) and I also assumed that the columns have all the same weight in terms of matching.
Also, I'm assuming that you want only one of the best matches, if not you may need to do some changes to the TOP and/or use a where clause.
Finally, You may want to use isnull() if your columns and/or inputs are nullable.

Hmmm . . . One method is:
select t.*
from (select t.*,
sum(case when condition1 then 1 else 0 end) over () as c_1,
sum(case when condition1 and condition2 then 1 else 0 end) over () as c_12,
sum(case when condition1 and condition2 and condition3 then 1 else 0 end) over () as c_123,
sum(case when condition1 and condition2 and condition3 and condition4 then 1 else 0 end) over () as c_1234
from t
) t
where (c_1234 > 0 and condition1 and condition2 and condition3 and condition4) or
(c_1234 = 0 and c_123 > 0 and condition1 and condition2 and condition3) and
(c_123 = 0 and c_12 > 0 and condition1 and condition2 ) and
(c_12 = 0 and c_1 > 0 and condition1 ) ;
Depending on the conditions and other considerations -- such as whether you only expect one row -- there might be simpler methods.

Related

How to check if all rows validate a predicate

I've a table in my database for which I need to check if all rows have one field not null.
If there are no row or if there is at least 1 row with the field null => true
If there are rows and they are all with the field not null => False
Is there a way to do this in on simple query? Or I need to check if my table is empty first then if it's not check if I've a row with the field value empty ?
This will count how many NULL values you have in a field;
SELECT
SUM(CASE WHEN FieldName IS NULL THEN 1 ELSE 0 END) NullValues
FROM TableName
Will return 0 if there are no NULL values, and will return the number of NULLS if there are any present.
If you actually want to return a value as 'True' or 'False' then do this;
SELECT CASE
WHEN a.NullValues > 0
THEN 'True'
ELSE 'False'
END CheckField
FROM (
SELECT
SUM(CASE WHEN FieldName IS NULL
THEN 1
ELSE 0
END) NullValues
FROM TableName
) a
Use count(*) and count(field) and compare the two:
select
case when count(*) > 0 and count(*) = count(field) then 1 -- not empty and no nulls
else 0 end as isgood
from mytable;
Oracle SQL has no boolean data type , so I use 1 for true and 0 for false. You can replace this with whatever you like (e.g. 'true' instead of 1 and 'false' instead of 0).
As to turning this into a predicate (correlated to a main query), you'd use something along the lines of:
select ...
from main
where exists
(
select 1
from mytable
where mytable.colx = main.coly
having count(*) > 0 and count(*) = count(field)
);
You can do this with aggregation. However, it is difficult to understand what you are asking for. If you want to check that a field has no NULL values, you can do:
select (case when count(*) > 0 then 1 else 0 end) as HasNullValues
from t
where field is null;
Alternate way I found using max with putting null first:
select case when
max(field) keep (dense_rank first order by datfin desc nulls first) is null then 1
else 0 end as flag
from MYTABLE;

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.

SQL 2 counts with different filter

I have a table and I need calculate two aggregate functions with different conditions in one statement. How can I do this?
Pseudocode below:
SELECT count(CoumntA) *< 0*, count(CoumntA) * > 0*
FROM dbo.TableA
This is the same idea as tombom's answer, but with SQL Server syntax:
SELECT
SUM(CASE WHEN CoumntA < 0 THEN 1 ELSE 0 END) AS LessThanZero,
SUM(CASE WHEN CoumntA > 0 THEN 1 ELSE 0 END) AS GreaterThanZero
FROM TableA
As #tombom demonstrated, this can be done as a single query. But it doesn't mean that it should be.
SELECT
SUM(CASE WHEN CoumntA < 0 THEN 1 ELSE 0 END) AS less_than_zero,
SUM(CASE WHEN CoumntA > 0 THEN 1 ELSE 0 END) AS greater_than_zero
FROM
TableA
The time when this is not so good is...
- There is an index on CoumntA
- Most values (50% or more feels about right) are exactly zero
In that case, two queries will be faster. This is because each query can use the index to quickly home in on the section to be counted. In the end only counting the relevant records.
The example I gave, however, scans the whole table every time. Only once, but always the whole table. This is worth it when you're counting most of the records. In your case it looks liek you're counting most or all of them, and so this is probably a good way of doing it.
It is possible to do this in one select statement.
The way I've done it before is like this:
SELECT SUM(CASE WHEN ColumnA < 0 THEN 1 END) AS LessThanZero,
SUM(CASE WHEN ColumnA > 0 THEN 1 END) AS GreaterThanZero
FROM dbo.TableA
This is the correct MS SQL syntax and I believe this is a very efficient way of doing it.
Don't forget you are not covering the case when ColumnA = 0!
select '< 0' as filter, COUNT(0) as cnt from TableA where [condition 1]
union
select '> 0' as filter, COUNT(0) as cnt from TableA where [condition 2]
Be sure that condition 1 and condition 2 create a partition on the original set of records, otherwise same records could be counted in both groups.
For SQL Server, one way would be;
SELECT COUNT(CASE WHEN CoumntA<0 THEN 1 ELSE NULL END),
COUNT(CASE WHEN CoumntA>0 THEN 1 ELSE NULL END)
FROM dbo.TableA
Demo here.
SELECT
SUM(IF(CoumntA < 0, 1, 0)) AS lowerThanZero,
SUM(IF(CoumntA > 0, 1, 0)) AS greaterThanZero
FROM
TableA
Is it clear what's happening? Ask, if you have any more questions.
A shorter form would be
SELECT
SUM(CoumntA < 0) AS lowerThanZero,
SUM(CoumntA > 0) AS greaterThanZero
FROM
TableA
This is possible, since in MySQL a true condition is equal 1, a false condition is equal 0
EDIT: okay, okay, sorry, don't know why I thought it's about MySQL here.
See the other answers about correct syntax.

Quick SQL Syntax Question

I have a standard insert into / select statement that is formatted similar to this:
insert into Table
( ...,
...)
select
field1,
field2,
field3,
field4,
fieldetc
from .... etc
There are three specific fields in the select statement that will need different values selected depending on another field, let's call it checker and the three fields are field2, field3, and field 4. The values will either be a 0 or in the other situation will need a case when. My question is, how do I format an if/else statement so it will work within the select statement? How I have it now is like this:
select
field1data,
if checker = 'A' or checker is null
begin
0,
0,
0,
end
else
begin
case when ... then ... else ... end,
case when ... then ... else ... end,
case when ... then ... else ... end,
end
fieldetcdata
from... etc
This is returning errors. How can I format this so it will work correctly, either selecting zeroes for these three fields or running through my case when statements in the other situation. Thanks!
You'll need to specify case statement for each field separately.
Select field1data,
Case When IsNull(Checker,'A') = 'A' Then 0
When Cond1 Then Whatever1
...
Else ...
End,
Case When IsNull(Checker,'A') = 'A' Then 0
When Cond2 Then Whatever1
...
Else ...
End,
Case When IsNull(Checker,'A') = 'A' Then 0
When Cond2 Then Whatever1
...
ELSE ...
End,
fieldetcdata
From ETC
Take out the IF and the BEGIN/END stuff and it should work. All you need to use is the
CASE COALESCE(checker,'A') WHEN 'A' THEN 0 ELSE alternate_value END
for each conditional value you want to SELECT
EDIT: Using your example:
SELECT
field1data,
CASE WHEN ISNULL(checker) THEN alternate_value1
WHEN checker = 'B' THEN alternate_value11 END,
CASE WHEN ISNULL(checker) THEN alternate_value2
WHEN checker = 'B' THEN alternate_value22 END,
CASE WHEN ISNULL(checker) THEN alternate_value3
WHEN checker = 'B' THEN alternate_value3 END,
fieldetcdata
FROM
TABLE
EDIT2: For multiple conditions, you simply add WHEN clauses.
http://msdn.microsoft.com/en-us/library/ms181765.aspx
Edited based on comments below.
You need to use a CASE statement with multiple WHEN conditions.
SELECT
field1data,
CASE COALESCE(checker, 'A') WHEN 'A' THEN 0 WHEN condition2 THEN ... ELSE ... END,
CASE COALESCE(checker, 'A') WHEN 'A' THEN 0 WHEN condition2 THEN ... ELSE ... END,
CASE COALESCE(checker, 'A') WHEN 'A' THEN 0 WHEN condition2 THEN ... ELSE ... END,
CASE COALESCE(checker, 'A') WHEN 'A' THEN 0 WHEN condition2 THEN ... ELSE ... END,
CASE COALESCE(checker, 'A') WHEN 'A' THEN 0 WHEN condition2 THEN ... ELSE ... END
FROM ...

Grouping data in the select statement

I have huge data which needs to be classifed in to different groups while retrieving. Each group has a different condition. I don't want to retrieve them separately. I want to know the number of items in each group using a single sql statement.
For example, the pseudo code will be like this:
Select count(IssueID) as Issue1_Count if(condition1),
count(IssueID) as Issue2_Count if(condition2),
count(IssueID) as Issue3_Count if(condition3)
From table1, table2, tabl3
where common_condition1 and common_Condition2;
Can somebody help me in making an Oralce query for this...
Put it like this:
SELECT
SUM(CASE WHEN condition1 THEN 1 ELSE 0 END) as Issue1_Count,
SUM(CASE WHEN condition2 THEN 1 ELSE 0 END) as Issue2_Count,
SUM(CASE WHEN condition3 THEN 1 ELSE 0 END) as Issue3_Count,
FROM
table1, table2, tabl3
WHERE
common_condition1 and common_Condition2;
Oracle's CASE statement should help you here. Have a look at this: http://www.dba-oracle.com/t_case_sql_clause.htm
There are limits though, so I'm not 100% positive you can do exactly what you have here using them.