Get a particular record based on a condition in SQL - sql

My requirement is to get id for missing status from SQL table. I will get a list of status for each id, say A,B,C,D. In a scenario, I have to check status B exists or not. Table gets updated everyday and each time new Id will be created
Conditions,
If status A exists and other statuses such as C and D does not
exists, then don't need to get id.
If status A and B exists and other statuses such as C or D does not exists, then don't need to get id .
If status A exists and B not exists, other
statuses such as C or D exists, then I should get the id of that
record
If status A and B exists, other
statuses such as C or D exists (all status exists), then I don't need to get the id of that
record
Table1:
Id StatusCode
1 A
1 C
2 A
2 B
2 C
3 A
3 C
3 D
How do I get Id 1 and 3 using SQL query?, Seems simple but as I am new to SQL I could not able to get it in SQL.
select statement in this screenshot works fine when there is only one id, it fails on multiple id. I tried many other way, but no use

Try this
SELECT DISTINCT ID
FROM T1
WHERE Statuscode = 'A' AND ID NOT IN (SELECT ID FROM T1 WHERE Statuscode = 'B' )
AND (ID IN (SELECT ID FROM T1 WHERE Statuscode = 'C' ) OR ID IN (SELECT ID FROM T1 WHERE Statuscode = 'D' ))
FIDDLE DEMO
Also, To correct Gordon Linoff's answer, we need to add one more where criteria there
SELECT Id
FROM T1
GROUP BY Id
HAVING SUM(CASE WHEN Statuscode = 'A' THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN Statuscode = 'B' THEN 1 ELSE 0 END) = 0 AND
SUM(CASE WHEN Statuscode IN ('C', 'D') THEN 1 ELSE 0 END) > 0;
FIDDLE DEMO

This answers the original version of the question.
I think you can use aggregation:
select id
from t
group by id
having sum(case when status = 'A' then 1 else 0 end) > 0 and
sum(case when status in ('C', 'D') then 1 else 0 end) > 0;

SELECT id
FROM t
GROUP BY
Id
HAVING MAX(status) = CHAR(64 + COUNT(*))
--char(64+1) = A, char(64+2) = B etc
The logic behind this is that it will take all count the same types of id. So if you have 3 rows you will need abc. If you have an id with 4 rows you will have ABCD. Generally the max status should always be the same as the number of rows.
This is true of course if you have no duplicate between id and status code.

select distinct id from t where t.statuscode = 'C' or t.statuscode = 'D' group by t.id

Related

Sql Query - Find Item owned by a group of people

Suppose I have the following tables
Owner Table
item_id owner_id
A 1
A 2
B 1
B 2
B 3
I want to find items owned by owner 1 & 2 only i.e. item A, not Item C
What could be a query for this ?
Edit:
If its not obvious, the owner list will be given by user, hence the query should be able to find items of given owner list maintaining the above criteria (i.e. not hardcoded).
At present I am doing it with a query like this
SELECT * FROM items WHERE id = (
SELECT item_id FROM item_owners WHERE owner_id in (:ownerIds)
GROUP BY item_id HAVING COUNT(distinct owner_id) = :ownerCount LIMIT 1
)
Where :ownerIds and :ownerCount are user inputs from ORM, and items is my original table of item to hold other details of item
The question is: is it a correct query ? Will it fail in any scenario ? And is it efficient ?
THIS ANSWERS THE ORIGINAL VERSION OF THE QUESTION.
You can do this with group by and having:
select item_id
from owner_item
group by item_id
having sum(case when owner_id = 1 then 1 else 0 end) > 0 and
sum(case when owner_id = 2 then 1 else 0 end) > 0 and
sum(case when owner_id not in (1, 2) then 1 else 0 end) = 0;

How do I check if a certain value exists?

I have a historization table called CUR_VALID. This table looks something like this:
ID CUR_VALID
1 N
1 N
1 Y
2 N
2 Y
3 Y
For every ID there needs to be one Y. If there is no Y or multiple Y there is something wrong. The statment for checking if there are multiple Y I already got. Now I only need to check for every ID if there is one Y existing. Im just not sure how to do that. This is what I have so far. So how do I check if the Value 'Y' exists?
SELECT Count(1) [Number of N]
,MAX(CUR_VALID = 'N')
,[BILL_ID]
,[BILL_MONTH]
,[BILL_SRC_ID]
FROM db.dbo.table
GROUP BY [BILL_ID]
,[BILL_MONTH]
,[BILL_SRC_ID]
Having MAX(CUR_VALID = 'N') > 1
Why are you fiddling with 'N' when you are interested in 'Y'?
Use conditional aggregation to get the count of the value your are interested in.
SELECT
COUNT(*) AS number_of_all,
COUNT(CASE WHEN cur_valid = 'Y' THEN 1 END) AS number_of_y,
COUNT(CASE WHEN cur_valid = 'N' THEN 1 END) AS number_of_n,
bill_id,
bill_month,
bill_src_id,
FROM db.dbo.table
GROUP BY bill_id, bill_month, bill_src_id;
Add a HAVING clause in order to get only valid
HAVING COUNT(CASE WHEN cur_valid = 'Y' THEN 1 END) = 1
or invalid
HAVING COUNT(CASE WHEN cur_valid = 'Y' THEN 1 END) <> 1
bills.
The following query will give you the list of id for which your integrity condition is not met: For every ID there needs to be one Y. If there is no Y or multiple Y there is something wrong.
select T1.id from table T1 where (select count(*) from table T2 where T2.id=T1.id and T2.CUR_VALID='Y')!=1
This query returns both not having at least one 'Y' value and more than one 'Y' value ID's.
First, sum up the Y values and relate to each id, then select not 1 ones from that table.
select * from (
select ID, SUM(case when CUR_VALID = 'Y' then 1 else 0 end) as CNT
from table
group by ID
) b where b.CNT <> 1
DBFiddle
As I understand, you want to get all the id for which your integrity check passes. And integrity check for you means, there is only one row with CUR_VALID value equal to Y in the CUR_VALID table.
This can be achieved by a group by clause:
select id from CUR_VALID
where CUR_VALID.CUR_VALID = 'Y'
group by id
having count(CUR_VALID.CUR_VALID) = 1;

SQL Server - Get column who have specific value

I have a SQL query which returns :
id | value
1 a
1 a
1 b
2 a
2 a
I want to get only id who have only the value a. So the id 2
How to do this ?
You can use aggregation and having clause to check if all the rows have value 'a' for a given id:
Using Count:
select id
from t
group by id
having count(*) = count(case when value = 'a' then 1 end);
Or using Sum
select id
from t
group by id
having SUM(case when value = 'a' then 0 else 1 end) = 0;
Use the next code:-
Select id
from #test
group by id
having sum (case when value = 'a' then 0 else 1 end) = 0
The clue is passing 0 for 'a' and pass 1 for other, then having sum equals 0
This is slightly slower than #Gurwinder Singh's answer but can be more readable if performance is not your top priority.
CREATE TABLE tmp (id int, [value] char(1))
INSERT INTO tmp values (1,'a'),(1,'a'),(1,'b'),(2,'a'),(2,'a')
SELECT DISTINCT id
FROM tmp a
WHERE [value] = 'a'
AND id NOT IN (
SELECT id FROM tmp
WHERE [value] <> 'a')

identify rows with not null values in sql

How to retrieve all rows having value in a status column (not null) group by ID column.
Id Name Status
1394 Test 1 Y
1394 Test 2 null
1394 Test 3 null
1395 Test 4 Y
1395 Test 5 Y
I wrote like select * from table where status = 'Y'. It brings me 3 records, how to add condition to bring in only last 2? the 1394 ID have other 2 records, which status is null.
If you want to select groups where the status is only y, you can do:
select t.*
from t
where not exists (select 1
from t t2
where t2.id = t.id and
(t2.Status <> 'Y' or t2.status is null)
);
If you only want the ids, I would use group by and having:
select id
from t
group by id
having min(status) = 'Y' and max(status) = 'Y' and count(*) = count(status);
The last condition checks for no NULL values.
You could also write:
having min(status = 'Y' then 1 else 0 end) = 1
A simple way is:
select * from mytable
where status = 'Y'
and id not in (select id from mytable where status is null)
The existing query "where status = 'Y'" will bring you not null by definition.
If you are trying to get grouped results, a "GROUP BY id" clause will achieve this, which will also require putting id in the select explicitly instead of "*".
Example: SELECT id, COUNT(id) from table where status = 'Y'
If I am reading this correctly you want to bring in the ID for a grouping that never has a NULL status value:
I would use a subquery with a not-exist:
SELECT DISTINCT ID FROM mytable WHERE status IS NULL;
Then filter IDs that do not exist in that list:
SELECT * FROM mytable WHERE id NOT IN (SELECT DISTINCT ID FROM mytable WHERE status IS NULL);
Here are some possible solutions, because I am unclear on exactly what you want as output:
Select Id, Name, Status from table where status is not null;
results in 3 rows:
Id Name Status
1394 Test 1 Y
1395 Test 4 Y
1395 Test 5 Y
Select Id, count(*) as anAmt from table where status is not null group by Id;
/* only retrieves counts per Id */
results in 1 row for each Id:
Id anAmt
1394 1
1395 2

SQL Server : do not Select all if true

I have these columns
Id Status
----------
1 pass
1 fail
2 pass
3 pass
How do I select all that only have a status of pass but if the Id has at least one fail it will not be selected as well.
If same id can have multiple passes
SELECT id
from table
WHERE status = 'pass'
and id NOT IN (SELECT id FROM table WHERE status = 'fail')
You need to use GROUP BY & HAVING clause
SELECT Id
FROM yourtable
GROUP BY Id
HAVING Sum(case when status ='pass' then 1 else 0 end) = count(status)
HAVING clause can be changed to
HAVING Count(case when status ='pass' then 1 end) = count(status)
I just hate chatty case statement, so
SELECT Id
FROM table1
GROUP BY Id
HAVING COUNT(DISTINCT [Status]) = 1 AND MIN([Status]) = 'pass'
or
SELECT Id
FROM table1
GROUP BY Id
HAVING COUNT(NULLIF([Status], 'fail')) = 1 AND COUNT(NULLIF([Status], 'pass')) = 0
The second query only works when status has two values 'pass' and 'fail'.