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')
Related
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
I have a table:
ref | name
===========
123abc | received
123abc | pending
134b | pending
156c | received
I want to be able to identify instances where a ref only has a pending and not a received. Note there could be multiple receives and pendings for the same ref.
How can I output the ref's that only have a pending and not a received?
So in my example, it would return:
134b | pending
I think it's something like:
SELECT ref, name FROM my_table
WHERE ref IS NOT NULL
GROUP BY ref, name
HAVING ref = 'pending' AND ref = 'received'
;
I would use aggregation:
select name
from my_table
where ref in ('pending', 'received')
group by name
having min(ref) = 'pending' and min(ref) = max(ref);
The second condition comparing min and max is, strictly speaking, not necessary. But it eliminates the dependence on the alphabetical ordering of the values.
You can use not exists for what you need (btw, from your data, column "name" contains values like pending and received):
select distinct ref, name
from my_table t1
where t1.name = 'pending' and not exists (select * from my_table t2 where t1.ref=t2.ref and t2.name='received')
PS. You can validate here with your sample data and my query:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=6fd633fe52129ff3246d8dba55e5fc17
Another way of doing it is with a WITH statement. This way, there is no need for nested sub-queries.
WITH ref_recieved_pending AS (
SELECT
ref,
sum(CASE WHEN name = 'received'
THEN 1
ELSE 0 END) as recieved_count,
sum(CASE WHEN name = 'pending'
THEN 1
ELSE 0 END) as pending_count
FROM test_table_2
GROUP BY ref
)
SELECT DISTINCT
ref,
'pending' as pending
FROM ref_recieved_pending
WHERE pending_count > 0 AND recieved_count = 0;
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')
I have a table that lists items and a status about these items. The problem is that some items have multiple different status entries. For example.
HOST Status
1.1.1.1 PASS
1.1.1.1 FAIL
1.2.2.2 FAIL
1.2.3.3 PASS
1.4.2.1 FAIL
1.4.2.1 FAIL
1.1.4.4 NULL
I need to return one status per asset.
HOST Status
1.1.1.1 PASS
1.2.2.2 FAIL
1.2.3.3 PASS
1.4.2.1 FAIL
1.1.4.4 No Results
I have been trying to do this with T-SQL Case statements but can't quite get it right.
The conditions are any Pass + anything is a Pass, Fail+ No Results is a fail and Null is No Results.
Try using a case statement to convert to ordered results and group on that, finally, you'll need to convert back to the nice, human-readable answer:
with cte1 as (
SELECT HOST,
[statNum] = case
when Status like 'PASS' then 2
when Status like 'FAIL' then 1
else 0
end
FROM table
)
SELECT HOST, case max(statNum) when 2 then 'PASS' when 1 then 'FAIL' else 'No Results' end
FROM cte1
GROUP BY HOST
NOTE: I used a CTE statement to hopefully make things a little clearer, but everything could be done in a single SELECT, like so:
SELECT HOST,
[Status] = case max(case when Status like 'PASS' then 2 when Status like 'FAIL' then 1 else 0 end)
when 2 then 'PASS'
when 1 then 'FAIL'
else 'No Result'
end
FROM table
You can use Max(Status) with Group by Host to get Distinct values:
Select host, coalesce(Max(status),'No results') status
From Table1
Group by host
Order by host
Fiddle Demo Results:
| HOST | STATUS |
|---------|------------|
| 1.1.1.1 | PASS |
| 1.1.4.4 | No results |
| 1.2.2.2 | FAIL |
| 1.2.3.3 | PASS |
| 1.4.2.1 | FAIL |
By default SQL Server is case insensitive, If case sensitivity is a concern for your server, then use the lower() function as below:
Select host, coalesce(Max(Lower(status)),'No results') status
From Table1
Group by host
Order by host
Fiddle demo
WITH CTE( HOST, STATUSValue)
AS(
SELECT HOST,
CASE STATUS WHEN 'PASS' 1 ELSE 0 END AS StatusValue
FROM Data
)
SELECT DISTINCT HOST,
CASE ISNULL(GOOD.STATUSVALUE,-1) WHEN 1 THEN 'Pass'
ELSE CASE ISNULL( BAD.STATUSVALUE,-1) WHEN 0 Then 'Fail' Else 'No Results' END
END AS Results
FROM DATA AS D
LEFT JOIN CTE AS GOOD
ON GOOD.HOST = D.HOST
AND GOOD.STATUSVALUE = 1
LEFT JOIN CTE AS BAD
ON BAD.HOST = BAD.HOST
AND BAD.STATUSVALUE = 0
I've got a sub-select in a query that looks something like this:
left outer join
(select distinct ID from OTHER_TABLE) as MYJOIN
on BASE_OBJECT.ID = MYJOIN.ID
It's pretty straightforward. Checks to see if a certain relation exists between the main object being queried for and the object represented by OTHER_TABLE by whether or not MYJOIN.ID is null on the row in question.
But now the requirements have changed a little. There's another row in OTHER_TABLE that can have a value of 1 or 0, and the query needs to know whether a relation exists between the primary for a 1-value, and also if it exists for a 0 value. The obvious solutions is to put:
left outer join
(select distinct ID, TYPE_VALUE from OTHER_TABLE) as MYJOIN
on BASE_OBJECT.ID = MYJOIN.ID
But that would be wrong because if 0-type and 1-type objects both exist for the same ID, it will increase the number of rows returned by the query, which isn't acceptable. So what I need is some sort of subselect that will return 1 row for each distinct ID, with a "1-type exists" column and a "0-type exists" column. And I have no idea how to code that in SQL.
For example, for the following table,
ID | TYPE_VALUE
_________________
1 | 1
3 | 0
3 | 1
4 | 0
I'd like to see a result set like this:
ID | HAS_TYPE_0 | HAS_TYPE_1
______________________________
1 | 0 | 1
3 | 1 | 1
4 | 1 | 0
Anyone know how I could set up a query to do this? Hopefully with a minimum of ugly hacks?
In the general case, you would use EXISTS:
SELECT DISTINCT ID,
CASE WHEN EXISTS (
SELECT * FROM Table1 y
WHERE y.TYPE_VALUE = 0 AND ID = x.ID)
THEN 1
ELSE 0 END AS HAS_TYPE_0,
CASE WHEN EXISTS (
SELECT * FROM Table1 y
WHERE y.TYPE_VALUE = 1 AND ID = x.ID)
THEN 1
ELSE 0 END AS HAS_TYPE_1
FROM Table1 x;
If you have a very large number of elements in the table, this won't perform so great - those nested subselects are often a kiss of death when it comes to performance.
For your specific case, you could also use GROUP BY and MAX() and MIN() to speed things up:
SELECT
ID,
CASE WHEN MIN(TYPE_VALUE) = 0 THEN '1' ELSE 0 END AS HAS_TYPE_0,
CASE WHEN MAX(TYPE_VALUE) = 1 THEN '1' ELSE 0 END AS HAS_TYPE_1
FROM Table1
GROUP BY ID;
Instead of select distinct ID, TYPE_VALUE from OTHER_TABLE
use
select ID,
MAX(CASE WHEN TYPE_VALUE =0 THEN 1 END) as has_type_0,
MAX(CASE WHEN TYPE_VALUE =1 THEN 1 END) as has_type_1
from OTHER_TABLE
GROUP BY ID;
You can do the same using PIVOT opearator...