Reputation: 59328
I have a table of operations similar to one below. Operations
either succeed or fail. Sometimes, the operation
is not 'tried', then such a row does not exist:
id| Oper. | Success
-------------------
1 | A | TRUE
1 | B | TRUE
1 | C | TRUE
2 | A | TRUE
2 | B | FALSE
2 | C | TRUE
3 | A | TRUE
3 | B | TRUE
3 | C | FALSE
4 | A | TRUE
4 | B | TRUE
5 | A | TRUE
5 | C | TRUE
6 | A | FALSE
7 | A | TRUE
7 | B | FALSE
7 | C | FALSE
How can I find the id's of the rows from table which have either the operation B
& C
failed or not tried?
For the example above, the desired result is 2(B failed), 3(C failed), 4(C not tried), 5(B not tried), 6(B & C not tried), 7(both B & C failed)
Upvotes: 0
Views: 308
Reputation: 59328
Thanks for all the answers. With inspiration from the answers and some coffee my brain started to work and came up with the solution that I cannot believe it was this easy.
The solution, in words, is to select if not (b & c succeeded)
The sub-query does the "b & c succeeded" part:
SELECT * FROM table WHERE id NOT IN (
SELECT id FROM table
WHERE operation IN('B', 'C') AND success = true
GROUP BY id HAVING COUNT(id) = 2
)
Upvotes: 0
Reputation: 44323
A cross join is not required nor supported by all SQL engines, such as MySQL. The first select statement just selects distinct id's where the operation is either 'B' OR 'C' and success is 'FALSE'. But we need to add those id's that either 'B' or 'C' was never attempted. Those would be id's in the table for which there are no values of either 'B' or 'C' in the operation column.
/* select all id's that have been tried but failed: */
SELECT DISTINCT id FROM operation
WHERE operation IN ('B', 'C') AND success = 'FALSE'
UNION
/* select all id's that have never tried 'B': */
SELECT DISTINCT id FROM operation
WHERE id NOT IN (
SELECT DISTINCT id FROM operation
WHERE operation = 'B'
)
UNION
/* select all id's that have never tried 'C': */
SELECT DISTINCT id FROM operation
WHERE id NOT IN (
SELECT DISTINCT id FROM operation
WHERE operation = 'C'
)
;
Upvotes: 0
Reputation: 32021
use aggregation
select id from tbale
group by id
having sum(case when Success='FALSE' then 1 else 0 end)>=1
or count(*)=2
when any of the operations will be failed then sum(case when Success='FALSE' then 1 else 0 end)>=1
this condition will be true and return that id, on the other hand when 3rd operation will not be tried then count(*)=2
will be true but in case of 2 operations not tried then condtion of will be count(*)<=2
Upvotes: 0
Reputation: 74730
I'm assuming that operation A is always present:
SELECT
id,
CASE
WHEN b.Success = 'FALSE' THEN '(B failed)'
WHEN b.Success IS NULL THEN '(B not tried)'
WHEN c.Success = 'FALSE' THEN '(C failed)'
WHEN c.Success IS NULL THEN '(C not tried)'
END as reason
FROM
(SELECT id, success FROM table WHERE oper = 'A') A
LEFT JOIN (SELECT id, success FROM table WHERE oper = 'B') B
ON A.id = B.id
LEFT JOIN (SELECT id, success FROM table WHERE oper = 'C') C
ON A.id = C.id
WHERE
'FALSE' in (c.success, b.success) OR b.success is null or c.success is null
In essence we break your data in 3 virtual tables and left join them, looking for either the false or the null created by the left join when the data doesn't exist. This also allows us to determine why things went wrong. I wasn't sure whether the words in brackets were actual output you wanted or just you explaining why that number should appear in the results.
I considered funky sum/count solutions like Gordon/Zaynul posted but for me this form is more self documenting/readable. Do check the performance though, as indexing the Oper column may help considerably.
Upvotes: 0
Reputation: 3833
You may try this...
Please find this link for more info about exists
link
select tab.id, operate.operation from
(select distinct id from table) as tab cross join
(select distinct operation from table ) as operate
where not exists ( select * from table as table
where tab.id=table.id and tab.operate=table.operate and table.success='true' )
Upvotes: 0
Reputation: 1271151
This is tricky, because you want rows that are not in the table.
Generate combinations of all ids and operations. You can do this using a cross join
. Then filter out the ones that succeeded:
select i.id, op.operation
from (select distinct id from operations) i cross join
(select distinct operation from operations) op
where not exists (select 1
from operations o2
where o2.id = i.id and
o2.operation = i.operation and
o2.success = 'TRUE'
);
Upvotes: 1