How to write a query to find a record which is not processed - sql

I am trying to write a query from a table A which has 2 columns :
ID , STATUS
The Status can be PROCESSING, NOTPROCESSED, FAILED, SUCCESS
When a record is successfully processed, a new record is created in the DB with STATUS as PROCESSED and the ID is the same as the previous NOTPROCESSED record.
The Sample Records in DB would like :
1 NOTPROCESSED
2 PROCESSED
1 PROCESSED
3 NOTPROCESSED
4 NOTPROCESSED
2 PROCESSED
3 NOTPROCESSED
4 NOTPROCESSED
The records can appear as duplicate for NOTPROCESSED.
I have to query the records which are NOTPROCESSED i.e
3 NOTPROCESSED
4 NOTPROCESSED
Its getting quite confusing to write the query.
Can anyone help with the logic.

you may use not exists to get this output.
select distinct a.id,a.status
from table a
where a.status='NOTPROCESSED'
and not exists (select null
from table b
where b.id=a.id
and b.status='PROCESSED')

Group by the ids and take only those groups having no record of status PROCESSED
select id
from your_table
group by id
having sum(case when status = 'PROCESSED' then 1 else 0 end) = 0
or get only the ones with only one kind of status
having count(distinct status) = 1
or use alphabetically the highest status
having max(status) = 'NOTPROCESSED'

Here are a couple of options:
select distinct id from A where id not in (
select id from A where status = 'PROCESSED'
);
select distinct id from A natural left join (
select id from A where status = 'PROCESSED'
) as B where B.id is null;

You can use analytical function as follows:
select * from
(select t.*, count(case when status = 'PROCESSED' then 1 end)
over (partition by ID) as cnt
from your_table t) t
where status = 'NOTPROCESSED' and cnt = 0

Related

How to write oracle sql query for selecting single record which is having highest status

Assume that have a scenario like in request table with same request Id I may have multiple records with different statuses
status like Draft, InProgress, Approved, Completed . we need to fetch single highest status record. Here preferred order is Completed -> Approved -> InProgress -> Draft.
if have three records like one is with InProgress, one with Approved and another one is with Completed, then among these three in need fetch only one record which have highest status Completed.
if have two records like one is with InProgress and another one is with Draft, then among these two in need fetch only one record which have highest status InProgress.
Could any one please suggest me on this ?
Use the ROW_NUMBER analytic function to order the rows based on a CASE expression that converts your string values to priorities:
SELECT *
FROM (
SELECT t.*,
ROW_NUMBER() OVER (
PARTITION BY request_id
ORDER BY CASE status
WHEN 'Completed' THEN 1
WHEN 'Approved' THEN 2
WHEN 'InProgress' THEN 3
WHEN 'Draft' THEN 4
ELSE 5
END
) as rn
FROM table_name t
)
WHERE rn = 1;
Its a bit of an heinous solution (tested on postgresql) - but you can convert your textual status into a number with a CASE statement and then use that plus a subquery to get the highest status:
SELECT rt.*
FROM
(SELECT
id,
MAX(CASE
WHEN status = 'Draft' THEN 0
WHEN status = 'InProgress' THEN 10
WHEN status = 'Approved' THEN 20
WHEN status = 'Completed' THEN 30
END) AS msid
FROM
request_table
GROUP BY
id) max_per_id
INNER JOIN
request_table rt ON max_per_id.id = rt.id
AND max_per_id.msid = CASE WHEN rt.status='Draft' THEN 0 WHEN rt.status='InProgress' then 10 WHEN rt.status='Approved' THEN 20 WHEN rt.status='Completed' then 30 END
The subquery
SELECT
id,
MAX(CASE
WHEN status = 'Draft' THEN 0
WHEN status = 'InProgress' THEN 10
WHEN status = 'Approved' THEN 20
WHEN status = 'Completed' THEN 30
END) AS msid
FROM
request_table
GROUP BY
id) max_per_id
provides the highest numeric status for each id. That then gets joined on the id and the numeric version of the status with the original table

SQL: status flips between 1 and 2; select all statuses, which are 2 since the last time it was 1

I have write only DB log of changes I keep track of (or statuses) and values fluctuate between 1 and 2. In the below table; ID is identity column, STATUS is either 1 or 2 and USER is a user id.
If the latest status (i.e. max ID) for a given user is 1 then my query should return nothing (1 = good). So running the query against the data above would be just that.
Here comes my question: I want to query for all statuses of 2 since the last time it was 1. Here is sample data:
In this case my query should return 2 and 3 (ID) because these have statuses of 2 since the last time it was 1.
This next query should return nothing because the latest status for this user was switched to 1:
And finally this next one should return 5 (because the latest status is 2 since the last time it was 1):
There is no date field in this table, you can only work with MAX(ID) ... GROUP BY ID, USER
How can I do this? I'm using MS SQL 2016.
You can use windowed aggregates to do this
WITH T
AS (SELECT ID,
STATUS,
[USER],
MAX(CASE WHEN Status = 1 THEN ID END) OVER ( PARTITION BY [USER]) AS MaxS1
FROM YourTable)
SELECT *
FROM T
WHERE Status = 2
AND (ID > MaxS1 OR MaxS1 IS NULL)
Remove the OR MaxS1 IS NULL if you don't want the rows returned for users that have 2 and have never had 1 as a status
You can filter with not exists:
select t.*
from mytable t
where
t.status = 2
and not exists (
select 1 from mtyable t1 where t1.user = t.user and t1.id > t.id and t1.status = 1
)
This phrases as: all records with status 2 that have no following record (ie a record with the same user and a greatest id) with status = 1. If there are no records with status = 1 for a given user, all its records will be returned.
This can also be expressed with a left join antipattern:
select t.*
from mytable t
left join mytable t1 on t1.user = t.user and t1.id > t.id and t1.status = 1
where t1.id is null and t.status = 2

Combine Multiple Sql Queries into one

I have a column called "status" in a sql table called "latest" which contains five different values new,deployed,resolved,assigned and closed as shown below
Status
--------------
NEW
NEW
DEPLOYED
NEW
RESOLVED
ASSIGNED
ASSIGNED
RESOLVED
ASSIGNED
NEW
NEW
RESOLVED
CLOSED
ASSIGNED
I want to write a query in which i can count the number of times each of these words occur in the column "status". Currently I'm using count function in 5 different queries like this.
1)select count(status) from latest where status="NEW";
2)select count(status) from latest where status="DEPLOYED";
3)select count(status) from latest where status="RESOLVED";
4)select count(status) from latest where status="ASSIGNED";
5)select count(status) from latest where status="CLOSED";
Is there a way i could combine all these queries into single query without using joins or union to get 5 different count values??
QUERY 1:
SELECT STATUS, COUNT(1) FROM LATEST
GROUP BY STATUS
ORDER BY STATUS;
Your Output would be:
STATUS COUNT
ASSIGNED 4
CLOSED 1
DEPLOYED 1
NEW 5
RESOLVED 3
To get the output in single row with 5 columns you can use:
QUERY 2:
SELECT COUNT(CASE WHEN STATUS='ASSIGNED' THEN 1 END) ASSIGNED_COUNT,
COUNT(CASE WHEN STATUS='CLOSED' THEN 1 END) CLOSED_COUNT,
COUNT(CASE WHEN STATUS='DEPLOYED' THEN 1 END) DEPLOYED_COUNT,
COUNT(CASE WHEN STATUS='NEW' THEN 1 END) NEW_COUNT,
COUNT(CASE WHEN STATUS='RESOLVED' THEN 1 END) RESOLVED_COUNT
FROM LATEST
Your Output would be:
ASSIGNED_COUNT | CLOSED_COUNT | DEPLOYED_COUNT | NEW_COUNT | RESOLVED_COUNT
4 | 1 | 1 | 5 | 3
EXPLANATION:
Query 1 can be used where there can be any number of dynamic status. For example, even if there is a status named DEFERRED, it would automatically be included without query change. But, if there is say, no record with status as "NEW", then no data would be returned.
Query 2 can be used to return all the data in a single row. If a new status is to be included, then the query must be modified. If there are no records for a status, then 0 would be returned. IDEAL FOR DASHBOARD kind of usage.
Try this cool one
Select *
from
(
Select Status,COUNT(*) 'Count'
from LATEST
group by Status with rollup
) t
where t.Count is not null
Try this:
SELECT l.status, COUNT(1)
FROM latest l
GROUP BY l.status;
OR
SELECT SUM(l.status = 'NEW') AS NEW_STATUS,
SUM(l.status = 'DEPLOYED') AS DEPLOYED_STATUS,
SUM(l.status = 'RESOLVED') AS RESOLVED_STATUS,
SUM(l.status = 'ASSIGNED') AS ASSIGNED_STATUS,
SUM(l.status = 'CLOSED') AS CLOSED_STATUS
FROM latest l;
UPDATE
Use SELECT...INTO statement to achieve this, check below query
SELECT SUM(l.status = 'NEW') AS NEW_STATUS,
SUM(l.status = 'DEPLOYED') AS DEPLOYED_STATUS,
SUM(l.status = 'RESOLVED') AS RESOLVED_STATUS,
SUM(l.status = 'ASSIGNED') AS ASSIGNED_STATUS,
SUM(l.status = 'CLOSED') AS CLOSED_STATUS
INTO NEW_STATUS, DEPLOYED_STATUS, RESOLVED_STATUS,
ASSIGNED_STATUS, CLOSED_STATUS
FROM latest l;
Try This...
1.>
Select Count() as Count,Status from latest where (status='NEW' Or status='DEPLOYED' or status='RESOLVED' or status='ASSIGNED' Or status='CLOSED') group by Status;*
OR
2.>
select count(status) from latest where (status='NEW' Or status='DEPLOYED' or status='RESOLVED' or status='ASSIGNED' Or status='CLOSED');

SQL query to filter unique status records

I need a SQL Server and Oracle compatible query to get the following result
Table:
PRIMARY IDN SECONDARY_IDN STATUS
1 47 Pending
2 47 Completed
3 47 Error
4 57 Pending
5 59 Completed
6 60 Pending
7 60 Completed
My input would be either Pending, Completed, or Error.
I need to list out all the secondary IDN with just 1 status and that is the input status.
For example my input is Pending: it should show up 57 ONLY. Others might have Pending but it also has completed and error records .
Can you please help me ?
SELECT SECONDARY_IDN
FROM tableName
GROUP BY SECONDARY_IDN
HAVING SUM(CASE WHEN Status = 'Pending' THEN 1 ELSE 0 END) = COUNT(*)
SQLFiddle Demo
You need groups that have only one status. For that, you want to use aggregation:
select secondary_idn
from t
group by secondary_idn
having max(status) = min(status) and -- all the statuses are the same
max(status) = 'Pending' -- and the status is Pending
SELECT *
FROM tableName tn
WHERE tn.Status = 'Pending'
AND NOT EXISTS ( SELECT *
FROM tableName nx
WHERE nx.SECONDARY_IDN = tn.SECONDARY_IDN
AND nx.Status <> 'Pending'
);
The outer query has no group by, so all columns are available to it (the dreaded select * is there to illustrate this fact)
The exists needs to detect only one unwanted record to yield true, solutions with aggregates (min, max, count) may have to scan (and aggregate) the whole group to establish the desirability of the record.
select status
, secondary_idn
, count(*) records
from theTable
where whatever
group by status, secondary_idn
having count(*) = 1

SQL Query help for single table query

I have a table that records status on course progress. A new record is added for each user/course comination when a course is started. That record is updated with a 'completed' status when the course is completed. I need to find the records for users who have never completed any courses.
Example Table:
User Course Status
A 1 S
A 2 C
B 1 S
C 2 S
D 2 C
C 3 S
I need a query that finds the following:
User Course Status
B 1 S
C 2 S
C 3 S
Any help is appreciated.
select user, course, status
from your_table
where user in
(
select user
from your_table
group by user
having sum(CASE WHEN status = 'C' THEN 1 ELSE 0 END) = 0
)
Select User, Course, Status from MyTable where User not in (Select Distinct User from MyTable where Status = 'C')
SELECT User,Course,Status FROM YourTable a
LEFT JOIN
(SELECT DISTINCT User FROM YourTable WHERE Status='C') CompletedAnything
ON a.User=CompletedAnything.User
WHERE COmpletedAnything.User IS NULL
Here's a SQL Fiddle that gives you what you want:
http://sqlfiddle.com/#!2/b6988/1
Query is this:
select User, Course, Status
from mytable
where User not in
(select distinct User from mytable where status = 'C' ans User is not null)