SQL query to update table only if all values for column match - sql

I'm playing around with queries and tables and have a table that looks like this.
Name | Job | Status
===============================
Test1 | Completed | Pending
Test1 | 50% | Pending
Test2 | Completed | Pending
Test2 | Completed | Pending
Test2 | Completed | Pending
Is there a query I can use that will look at the name and job column, and if the job column is "completed" for all matching names, update the status column to say "completed"?
To clarify, in the above example, all the "Test2" jobs are marked as completed, so I would like the status to also say completed - but only if ALL the Test2 jobs say completed.

Here is one possible solution for SQL Server:
UPDATE yourTable t1
SET Status = 'Completed'
WHERE
Job = 'Completed' AND
NOT EXISTS (SELECT 1 FROM yourTable t2
WHERE t1.Name = t2.Name AND
(t2.Job <> 'Completed' OR t2.Job IS NULL));

Another option;
UPDATE Table1 SET Status = 'Completed' WHERE Name IN (
SELECT Name
FROM Table1
GROUP BY Name
HAVING COUNT(*) = SUM(CASE WHEN Job='Completed' THEN 1 ELSE 0 END)
)
The inner select finds the names with all Job values set to Completed, and the update just updates Status of the rows with the found names.
A DBfiddle for testing.

Try this
UPDATE Table_Name SET Status = 'Completed' WHERE Name = 'Completed' AND Job = 'Completed'

Please try it.
UPDATE yourTable
SET Status = 'Completed'
WHERE
Job = 'Completed' AND
Name not in (select Name from yourTable where Job<>'Completed')

You can try the following
create table #temp (Name varchar(20), Job varchar(20), sStatus varchar(20))
insert into #temp values
('Test1' , 'Completed' , 'Pending'),
('Test1' , '50%' , 'Pending'),
('Test2' , 'Completed' , 'Pending'),
('Test2' , 'Completed' , 'Pending'),
('Test2' , 'Completed' , 'Pending')
update #temp set sStatus = 'Completed'
where Name not in (
select a.Name from #temp a
where a.Job <> 'Completed'
)
select * from #temp

Related

Oracle Query to get single result depending on values in result set

WITH T1 AS SELECT DISTINCT(DETAILS) FROM ( SELECT STATUS, PREREQUISITE_NM,
(case when (STATUS='Completed' ) then 'Completed'
when (STATUS='Pending' ) then 'Pending'
when (STATUS='Failed' and PREREQUISITE_NM = 'Y') then 'Failed'
when (STATUS='Failed' and PREREQUISITE_NM = 'N') then 'Completed'
end )DETAILS FROM TABLE_LIST WHERE ID=1))
T2 AS ( SELECT DETAILS FROM T1)
Result 1 :
Pending
Failed
Completed.
Result 2:
Failed
Completed.
In above Query we see the different result set as per data available. I want to write a query in T2 Block which should give Output as :
for Pending/Failed/Completed : should give Pending as output.
For Failed/Completed : should give Failed as Output.
Is it possible to achieve this through query without using PL SQL block. like using WITH clause?
I can explain my aim such as
Lets say T1 Block is giving me result as three rows Pending,Failed, Completed then I want Pending as a Output value. If T1 Block is giving me result as Failed, Completed then I want to Failed as Output value. If T1 block is giving only Completed then Completed will be considered as a output value.
Thanks Roberto and Barbaros Ozhan, Both Answers were useful.Posting another way shared by one of my colleague.
WITH T1 AS (
SELECT
DISTINCT(DETAILS)
FROM (
SELECT STATUS, PREREQUISITE_NM,
(
CASE
WHEN (STATUS = 'Failed' ) THEN
CASE WHEN PREREQUISITE_NM = 'Y' THEN 'Failed'
WHEN PREREQUISITE_NM = 'N' THEN 'Completed'
END
ELSE
STATUS
END
)DETAILS FROM TABLE_lIST WHERE ID=1)
),
T2 AS
(
SELECT CASE
WHEN EXISTS
( SELECT DETAILS FROM T1 where DETAILS='Pending' )
THEN 'Pending'
WHEN EXISTS
( SELECT DETAILS FROM T1 WHERE DETAILS='InProgress' )
THEN 'InProgress'
WHEN EXISTS
(SELECT DETAILS FROM T1 where DETAILS='Failed' )
THEN 'Failed'
ELSE 'Completed' END as DETAILS from DUAL
)SELECT * FROM T2
You can use ROW_NUMBER() Analytic function to bring those status values in alphabetical order descendingly which would suite your need :
WITH T1 AS
(
SELECT DISTINCT (CASE
WHEN (STATUS = 'Failed' ) THEN
CASE WHEN PREREQUISITE_NM = 'Y' THEN 'Failed'
WHEN PREREQUISITE_NM = 'N' THEN 'Completed'
END
ELSE
STATUS
END) AS details
FROM TABLE_LIST
WHERE ID = 1
), T2 AS
(
SELECT T1.*, ROW_NUMBER() OVER (ORDER BY details DESC) AS rn
FROM T1
)
SELECT details
FROM T2
WHERE rn = 1
After reading your comments, I came up with this solution, that perhaps is not the best, but at the end gives the output you expect , based on that what you actually want is to transpose the rows produced in t1 to columns in t2
I used my own test, please be aware to replace the columns or modify whatever is necessary to adapt it to your own query
SQL> desc my_test
Name Null? Type
----------------------------------------- -------- ----------------------------
C1 NUMBER
C2 VARCHAR2(20)
C3 VARCHAR2(1)
SQL> select * from my_test ;
C1 C2 C3
---------- -------------------- -
1 Failed Y
2 Completed Y
1 Pending Y
1 Pending N
SQL>
So, If just got the first part of my query
SQL> WITH T1 AS (
SELECT DISTINCT c2 FROM ( SELECT c1,c2,
case when c2='Completed' then 'Completed'
when c2='Pending' then 'Pending'
when c2='Failed' and c3 = 'Y' then 'Failed'
when c2='Failed' and c3 = 'N' then 'Completed'
else c2
end FROM my_test WHERE c1=1
) )
select trim ( completed || ' ' || failed || ' ' || pending ) as result
from
(
select * from t1 pivot ( max(c2) for c2 in ( 'Completed' as Completed, 'Failed' as Failed, 'Pending' as Pending ) )
)
/ 9 10 11 12 13 14 15
RESULT
--------------------------------------------------------------
Failed Pending
Now I only need to build a case over that result ( modify it to your own requirements )
SQL> WITH T1 AS (
SELECT DISTINCT c2 FROM ( SELECT c1,c2,
case when c2='Completed' then 'Completed'
when c2='Pending' then 'Pending'
when c2='Failed' and c3 = 'Y' then 'Failed'
when c2='Failed' and c3 = 'N' then 'Completed'
else c2
end FROM my_test WHERE c1=1
) )
select
case when result = 'Completed Failed Pending' then 'Pending'
when result = 'Completed Failed' then 'Failed'
when result = 'Failed Pending' then 'Failed' -- I guess
when result = 'Completed Pending' then 'Pending' -- I guess
end as output
from (
select trim ( completed || ' ' || failed || ' ' || pending ) as result
from
(
select * from t1 pivot ( max(c2) for c2 in ( 'Completed' as Completed, 'Failed' as Failed, 'Pending' as Pending ) )
)
)
/
OUTPUT
-------
Failed
SQL>

How to add new column to table with the value corresponding to the same table?

There is a status column in my table with int values. How can I assign a value to the int or do I have to create a new column in the table?
I have tried to ALTER table but what is the best method?
select status from table1;
If I run the above query we get -
id status
1 1
2 2
3 1
4 5
I want to get output -
id status
1 Accepted
2 Completed
3 Accepted
4 Declined
USE case expression, postgres
select status,
case
when status=1 then 'Accepted'
when status=2 then 'Completed'
when status=3 then 'Accepted'
when sttaus=4 then 'Declined'
end mystatus
from table1;
You can use case, refer to this SO Question
PostgreSQL CASE ... END with multiple conditions. The query will look something like this:
SELECT
id,
CASE
WHEN (status = 1) THEN 'Accepted'
WHEN status=2 then 'Completed'
WHEN status=3 then 'Accepted'
WHEN sttaus=4 then 'Declined'
END AS status
FROM table1 ;
The correct case expression would be:
select id,
(case status
when 1 then 'Accepted'
when 2 then 'Completed'
when 5 then 'Declined'
end) as status
from table1;
You can also do this with a join to a derived table:
select t1.id, v.status
from table1 t1 left join
(value (1, 'Accepted'), (2, 'Completed'), (5, 'Declined')
) v(status_int, status)
on t1.status = v.status_int;
I mention this because you should probably have a reference table for the status values. In this case, the reference table is created on the fly in the query. But it should probably be a real table in the database.

SQL Query to get the workorders which skipped some lines processing

As I am not expert in writing the SQL queries so want for help.
I have the below given dataset
I need to write a query to get all the workorderid's which have skipped the process and moved to next seq_no , ex:
workorderid = AW1 which has a line "open" for seq_no=30 and went ahead to "complete" for seq_no = 40
The final result set should look like below
Workorderid
-----------
AW1
AW3
One method simply uses conditional aggregation:
select workorderid
from t
group by workorderid
having (max(case when status = 'Open' then seq_no end) <
max(case when status = 'Complete' then seq_no end)
)
That is, is there a 'Complete' after the last 'Open', based on seq_no.
Here is another one using EXISTS:
SELECT t1.workorderid
FROM t t1
WHERE t1.status = 'Open'
AND EXISTS
(SELECT 1
FROM t t2
WHERE t2.workorderid = t1.workorderid
AND t2.seq_no > t1.seq_no
AND t2.status = 'Complete')

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'.

SQL Query: comparison with condition

I have a table which looks as follows (simplified):
name | status
app-1 | start
app-1 | run
app-1 | run
app-1 | run
app-1 | finish
app-2 | start
app-2 | run
app-2 | run
now, I would like to filter all apps, that have "start" for a status AND no "finish". For the example above, the result is supposed to be "app-2".
I have no clue how to do the comparison while additionally use a condition...it really gives me some hard time. I hope someone can help me with it?!
select name from _table t1
where t1.status = 'start'
and not exists (
select name from _table t2
where t1.name = t2.name
and t2.status = 'finish'
)
Try something like this:
SELECT * FROM table_name
WHERE status = 'run' and name NOT IN
(SELECT name FROM table_name WHERE status = 'finish')
not sure which Relational Database you are using but the query will be similar:
Select AppStatus.Name
From (
Select Name, Started, Finished
Sum(Case When status = 'start' then 1 else 0 end) as Started,
Sum(Case When status = 'finish' then 1 else 0 end) as Finished,
From Table
Group By Name
) as AppStatus
Where AppStatus.Started > 0 and AppStatus.Finished > 0
Update:
If you assume that all rows will begin with a start, and have zero or more runs and then a finish, this will also work and is much more simple!
Select Distinct(Name)
From Table Where Name Not In (
SELECT Name
FROM Table
WHERE Status = 'finish')