SQL : finding which clause is making my query returning no answer - sql

My query is basic and look like this :
SELECT ID FROM Table WHERE CRIT1='a' AND CRIT2='b' AND CRIT3='c'
However it sometimes return no value. This is normal because there is no match in the table.
To help my users to find which criteria is too restrictive, I would like to find another query which tell me if it is because of clause CRIT1, CRIT2 or CRIT3 that I have no answer.
Currently, I've done it this way (using pseudo code) :
If ( SELECT ID FROM Table WHERE CRIT1='a' returns EOF )
Then WrongCriteria="CRIT1"
Elseif ( SELECT ID FROM Table WHERE CRIT1='a' AND CRIT2='b' returns EOF )
Then WrongCriteria="CRIT2"
Elseif ( SELECT ID FROM Table WHERE CRIT1='a' AND CRIT2='b' AND CRIT3='c' returns EOF )
Then WrongCriteria="CRIT3"
It works ... but there are several queries and each of them is very slow due to the poor network response time.
My question is thus : It is possible to do the above pseudo-code in one single SQL query?

You can combine three queries into one by using SUM on a conditional:
SELECT
SUM(CASE WHEN CRIT1='a' THEN 1 ELSE 0 END) as CRIT1
, SUM(CASE WHEN CRIT1='a' AND CRIT2='b' THEN 1 ELSE 0 END) as CRIT2
, SUM(CASE WHEN CRIT1='a' AND CRIT2='b' AND CRIT3='c' THEN 1 ELSE 0 END) as CRIT3
FROM MyTable
Zero in a column corresponds to the criterion being to restrictive.
Note that this is only a different implementation of your three queries, which "prioritizes" the criteria in a specific way (crit1 then crit2 then crit3). In theory, with three criteria you want to test all individual ones, plus three combinations of pairs, i.e get six counts for these conditions:
CRIT1='a'
CRIT2='b'
CRIT3='c'
CRIT1='a' && CRIT2='b'
CRIT1='a' && CRIT3='c'
CRIT2='b' && CRIT3='c'
The above six counts would give you a full picture of which criteria are too restrictive.

Yes it's possible to do this check in a single query using 'OR' operator.
I'm assuming it's only one condition which can be wrong at a time:
SELECT CASE WHEN CRIT1 <> 'a' THEN 'CRIT1'
WHEN CRIT2 <> 'b' THEN 'CRIT2'
WHEN CRIT3 <> 'c' THEN 'CRIT3' END AS WrongCriteria
FROM Table WHERE CRIT1<>'a' OR CRIT2<>'b' OR CRIT3<>'c'

To show all combinations of restrictions:
SELECT
COALESCE( 'Conditions:'
+ NULLIF(
( CASE WHEN CRIT1 <> 'a' THEN ' CRIT1' ELSE '' END )
+ ( CASE WHEN CRIT2 <> 'b' THEN ' CRIT2' ELSE '' END )
+ ( CASE WHEN CRIT3 <> 'c' THEN ' CRIT3' ELSE '' END ),
'' ),
'None' ) AS Restrictions
FROM MyTable

Related

How to check unique values in SQL

I have a table named Bank that contains a Bank_Values column. I need a calculated Bank_Value_Unique column to shows whether each Bank_Value exists somewhere else in the table (i.e. whether its count is greater than 1).
I prepared this query, but it does not work. Could anyone help me with this and/or modify this query?
SELECT
CASE
WHEN NULLIF(LTRIM(RTRIM(Bank_Value)), '') =
(SELECT Bank_Value
FROM [Bank]
GROUP BY Bank_Value
HAVING COUNT(*) = 1)
THEN '0' ELSE '1'
END AS Bank_Key_Unique
FROM [Bank]
A windowed count should work:
SELECT
*,
CASE
COUNT(*) OVER (PARTITION BY Bank_Value)
WHEN 1 THEN 1 ELSE 0
END AS Bank_Value_Unique
FROM
Bank
;
It works also, but I found solution also:
select CASE WHEN NULLIF(LTRIM(RTRIM(Bank_Value)),'') =
(select Bank_Value
from Bank
group by Bank_Value
having (count(distinct Bank_Value) > 2 )) THEN '1' ELSE '0' END AS
Bank_Value_Uniquness
from Bank
It was missing "distinct" in having part.

How to use an SQL Comparator in the base 'Case' selector in the 'When' logic without having to re-write conditions

I have an SQL query joined on multiple tables (all INNER JOINS).
The below is an example of the query I am trying to run (the ? is to illustrate the position in which I presume the answer to my question will be rectified).
Case
(
SELECT Count(ID)
FROM CPD_Candidates cpdCan
WHERE
cpdCan.CandidateID = can.CandidateID
AND
(
cpdCan.DateEnded >= GETDATE()
OR
coalesce(cpdCan.DateEnded, '') = N'1-Jan-1900'
)
AND
cpdCan.Deleted <> 1
)
When ? > 0 then 'Bigger' else 'Equal or Smaller' End
)
The idea with the above is that instead of the ? the actual value I want to compare against would be Count(ID), if it's greater than 0 I want it to SELECT 'Bigger', otherwise it should SELECT 'Equal or Smaller'. So a more-accurate depiction of what I wish to run would be the below.
Case
(
SELECT Count(ID)
FROM CPD_Candidates cpdCan
WHERE
cpdCan.CandidateID = can.CandidateID
AND
(
cpdCan.DateEnded >= GETDATE()
OR
coalesce(cpdCan.DateEnded, '') = N'1-Jan-1900'
)
AND
cpdCan.Deleted <> 1
)
When
Count(cpdCan.ID) > 0 then 'Bigger' else 'Equal or Smaller' End
)
Of course there is a syntax error above but I am enquiring as to whether it is possible to compare like in the above SQL query structure but replacing Count(cpdCan.ID) > 0 with some other means to achieve that value & logic?
If this is un-achievable in SQL Server 2016 what other means would be a better solution to this XY?
I think that you mean:
case when
(
SELECT Count(ID)
FROM CPD_Candidates cpdCan
WHERE
cpdCan.CandidateID = can.CandidateID
AND (cpdCan.DateEnded >= GETDATE() OR coalesce(cpdCan.DateEnded, '') = N'1-Jan-1900')
AND cpdCan.Deleted <> 1
) > 0
then 'Bigger'
else 'Equal or Smaller'
End

how do you check for nulls in any column in an entire table in SQL

I would like to check if any of my columns in a table have any null values. I am sure there is a quicker way than how I am doing it at the moment. I just want to see if there is a NULL in ANY column however my table has a lot of columns, is there a simple and quick way?
This way I have written so far works but it takes a long time to do for every column (hence the etc etc)
select
sum(case when id is null then 1 else 0 end) as id,
sum(case when name is null then 1 else 0 end) as name,
sum(case when review_count is null then 1 else 0 end) as review_coun,
sum(case when positive_review is null then 1 else 0 end) as
positive_review,
sum(etc etc
from user
I don't know if this will work for your scenario, but it's an option. You can CAST all your columns as a string and then concatenate them together. If you concatenate a NULL value with a string, it will return NULL.
SELECT 'Y'
WHERE EXISTS( -- Check if there are any NULL rows
SELECT
CAST(c1 AS CHAR(1)) ||
CAST(c2 AS CHAR(1)) ||
...
AS MyColumns
WHERE MyColumns IS NULL
)
;

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;

In SQL (Tsql) what's a good way to check mutually exclusive options are correct

EDIT: damien the unbeliever, my apologies, trying to be terse I omitted saying that the design of the table is not under my control; this table is a "dump" of data we receive from another vendor, and I have to convert it from their format to ours. The reason I need a query is to find out if the data is consistent with assumptions in other parts of code. The solutions proposed looking for length or exact match of the concatenated strings are better than my pair of queries for the problem I described.
I have a working pair of queries for my problem, but I wondered if there's something a bit prettier. Exactly one of taxidflag1, taxidflag2, taxidflag3 should be filled in with * in each row. So I confirm they all have two blanks and one * like this. All fields are are non nullable.
select * from acct where 2 <>
(case when taxidFlag1 <> '' then 1 else 0 end) +
(case when taxidFlag2 <> '' then 1 else 0 end) +
(case when taxidFlag3 <> '' then 1 else 0 end)
select * from acct where 1 <>
(case when taxidFlag1 = '*' then 1 else 0 end) +
(case when taxidFlag2 = '*' then 1 else 0 end) +
(case when taxidFlag3 = '*' then 1 else 0 end)
You could do this:
select * from acct where taxidFlag1 + taxidFlag2 + taxidFlag3 = '*';
This condition is only true if two are empty ('') and one is a asterisk (*).
select *
from
acct a1
where
(select count(*) from acct unpivot (foo for taxidFlag in (taxidFlag1, taxidFlag2, taxidFlag3)) as unp where unp.row_id = a1.row_id and foo = '*') <> 1
;
where row_id is your primary key field.