Oracle SQL/PLSQL: Return Boolean value when multiple criterion met across many rows of data - sql

I have a query that currently returns multiple rows of data. I need to analyse this data using PL/SQL and/or SQL to determine whether it meets the business requirements - returning either TRUE or FALSE.
Sample Data 1 Sample Data 2 Sample Data 3
TYPE STATUS TYPE STATUS TYPE STATUS
Red Open Red Open Red Open
Blue Open Blue Open Blue Open
Yellow Open Yellow Open Yellow Open
Red Closed Yellow Closed
Red Pending
Requirements - if met return TRUE, otherwise FALSE:
The STATUS for each TYPE must be 'Open'.
If there is more than 1 record for the same TYPE then the STATUS on at least 1 record must be 'Open', the STATUS on the remaining records must be 'Closed'.
Results based on requirements above:
Sample Data 1 = FALSE
Sample Data 2 = TRUE
Sample Data 3 = TRUE
Any and all help much appreciated, apologies if this question is a duplicate.

Oracle SQL doesn't have boolean types, so let's use 0 and 1:
select type,
(case when count(distinct case when status = 'open' then type end) = count(distinct type) and
count(case when status = 'open' then type end) = count(distinct type) and
sum(case when status not in ('open', 'closed') then 1 else 0 end) = 0
then 1 else 0
end) as flag
from t
group by type;
The logic:
The first condition says that each type has at least one "open".
The second condition (combined with the first) says that each type has exactly one "open".
The third condition says that the only status are "open" and "closed".

Related

Using IF statement to pull boolean column header for an entry

I'm not good at all with IF statements. I currently have a schedule that looks like this:
Lot(Int) PartNum(Varchar50) Amount(Int) IsPainted(Bool) IsInspected(Bool) Finished(Bool)
1 xxx-0191 500 1 1 0
2 xxx-0191 700 1 0 0
What I'm trying to accomplish, and I'm under the thought it'll have to be handled by an IF statement but I'm certainly open for using whatever works best here, is to have a query that will give me the following
Lot PartNum Amount Status
1 xxx-0191 500 Inspected
2 xxx-0191 700 Painted
What I need it to do is just pull the last available column of "True" or "1" in the boolean columns and just display that information in the "Status" column in the query.
use this code
select
Lot,
PartNum,
Aamount,
Case when IsInspected=1 then 'Inspected' else 'Painted' end Status
from
table
Use case. Something like this:
select lot, partnum, amount,
(case when Finished = 1 then 'Finished'
when IsInspected = 1 then 'Inspected'
when IsPainted = 1 then 'Painted'
) as status
This chooses the last boolean as the one chosen for the status.

Why does <> operator not work as expected on my varbinary(20) sql data?

I have a MySQL database, it contains a table that contains some data in columns of type varbinary(20)
Don't ask me why - it just is and i need to deal with it.
This data represents the number of modules a student has completed as part of a course. There is also another column called criterias that represents the number of modules that must be completed in order for the course to be marked complete. When I am doing a count of the number of completed courses, I want to count the rows where
completed = criteria AND completed != 0 ( ...oh and where the student is enrolled)
(because in some cases the criteria is 0 so I want to skip any courses where a student has completed 0 of 0 modules).
Additionally for some reason the value of 0 in the varbinary column is 30 (if anyone can offer an explanation for this then great) and so where there are 3 modules that need to be completed the value in the criteria column will be 33
So my SQL query looks like this -
count(CASE WHEN (completed <> 30 AND (completed = criterias) AND enrolled = 'Yes') THEN 1 END) AS Total_Complete
However this count seems to include courses where student has completed 0 of 0 courses so it would appear that my completed <> 30 is not working.
As I was writing this I answered my own question but I thought id leave it up here incase it helped anyone else.
The solution was to ignore the fact that for whatever reason 0 was represented by 30 and change my sql to -
count(CASE WHEN (completed <> 0 AND (completed = criterias) AND enrolled = 'Yes') THEN 1 END) AS Total_Complete
This worked

Completing the where clause in sql server

I have a table kyc3 where there are walletno, status and rank columns present. rank columns are currently filled with 0. While status column has following data: accepted, rejected, registered and scanned. I want to put value for each status in rank column where
accepted = 1, rejected = 2, registered = 3 and scanned = 4
I wrote following query but do not understand how to complete it:
INSERT INTO kyc3([rank]) SELECT status_ FROM kyc3
I understand I need to put a where clause that will indicate my logic for data population. But what should I write?
If the table is populated and you want to change the rank field, you want to use an UPDATE statement, as INSERT is for adding new rows to your table:
UPDATE kyc3
SET rank = CASE WHEN status = 'accepted' THEN 1
WHEN status = 'rejected' THEN 2
WHEN status = 'registered' THEN 3
WHEN status = 'scanned' THEN 4
END
You can use update to fill a cell of an existing row.
update kyc3
set rank = CASE WHEN status = 'accepted' THEN 1
WHEN status = 'rejected' THEN 2
WHEN status = 'registered' THEN 3
WHEN status = 'scanned' THEN 4
END
Use insert only for creating new rows.

Counting number of records filtering out a certain condition

I am trying to get a count of the number of unique incidents in a table that have only one session in them. We have a table called Session Tracking that stores the Incident number and also stores the previous status and current status for that session. I want to get a count of the number of incidents that have only one session, and I also want to get a count of the number of incidents that may have more than one session, but only if the following sessions start in closed and end in closed. Basically not counting the sessions where they don't change status in the aggregate list.
Example:
Incident ID Start Status End Status
1 Open Closed
1 Closed Closed
2 Open Closed
3 Open Closed
4 Open Open
4 Open Closed
I want to get the first three incidents because incidents 2 and 3 both had only 1 session each, and want to count the first incident because it had a session after it had already closed, and that second session doesnt count. The fourth incident won't be counted because it had more than one session where it was open.
This is the statement I am using, and think something might be off...
SELECT Incident, COUNT(Incident)
FROM Session_Tracking
WHERE NOT (Prev_Status = 'Closed' AND Current_Status = 'Closed')
GROUP BY Incident
HAVING COUNT(Incident) = 1
Assuming you are using a reasonable database that supports window functions, you can do this by just counting things:
select SUM(case when numInIncident = 1 then 1 else 0 end) as Singletons,
SUM(case when ClosedClosed = numInIncident - 1 and numInINcident > 1 then 1 else 0
end) as RestClosed
from (select st.*,
COUNT(*) over (partition by incident) as numInIncident,
sum(case when startStatus = 'Closed' and endStatus = 'Closed' then 1 else 0 end) over (partition by incident) as ClosedClosed
from session_tracking
) st
The inner subquery counts the number of rows for each incident, and the numbe rof rows when the start and end statuses are both "closed". The outer query applies this logic to get what the numbers you want.

Get specific "version" of a column

I have an app that uses SQLite to store data locally. There may be more than one file storing the data. All the files contain a list of items, but only one of them has the "correct" status for the current user (basically, there is a "user" db in $HOME and a "system-wide" one in /etc).
Usually, both files will contain the same list of items, and only the status column will differ. If, however, either contains items not in both, I want that data as well.
SQLite does not have FULL OUTER JOIN.
A solution I have come up with is this:
SELECT item, group_concat(status) AS status FROM (SELECT item,status FROM items UNION SELECT item,status FROM otherdb.items) GROUP BY item;
And then parsing the comma-separated "status" output to get the "right" status. I would like a pure SQL solution, however.
The values I want for status are:
If any = 1, status = 1
elif any = -1, status = -1
elif any = 2, status = 2
elif any = -2, status = -2
else status = 0 or NULL
status may only (in the db) be -2,-1,0,NULL,1,2 so this covers all data.
If there is a solution that only gives whichever one is non-zero and non-null, that could work too, although I would prefer the above.
I would sugest you one approach:
1. create a temp table, one adittional column for a flag "otherbd";
2. throw everything from the 2 tables in there;
3. delete the lines you don't want;
Create a status priority table with the following values
status priority
1 5
-1 4
2 3
-2 2
0 1
NULL 0
The concept is to join your two tables against this StatusPriorty table, Group the records and use MAX(Priority) to get your results