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
Related
what I want to do is the following:
I have a table like this:
ID; STATUS; ORIGIN
1 READY a
2 READY b
3 OPEN a
4 OPEN a
This should be queried to:
IDS; OPEN; READY; ORIGIN
1,3,4 2 1 a
2 0 1 b
The query so far:
SELECT ORIGIN,
SUM(CASE WHEN UPPER(STATUS) = 'OPEN' THEN 1 ELSE 0 END) AS OPEN,
SUM(CASE WHEN UPPER(STATUS) = 'READY' THEN 1 ELSE 0 END) AS READY,
<LIST_FUNC>(ID, ',') AS IDS
FROM TABLE
GROUP BY ORIGIN;
I am looking for a function in derby (<LIST_FUNC>), that does the concatenation of the ID column during the group by aggregation. Of course, the signature may look different.
Thanks in advance!
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'.
I want to find a category wise count in sql server with multiple criteria
Below is the table
I want to find groupwise, checklistcode wise status count
for instance group CLT having total count for Open status and Closed status
so output should look like this
CLT | Clinker transport | CL07M1 | Mechanical Requirments | 4 | 1
I have tried query which is as follows,
select distinct pd.GroupCode,
pd.GroupName,
pd.CheckListCode,
pd.CheckListName,
OpenTotal =
CASE WHEN pd.Status = 'Open' THEN COUNT(pd.Status)
END,
ClosedTotal =
CASE WHEN pd.Status = 'Closed' THEN COUNT(pd.Status)
END
from PunchListDetails pd
group by pd.GroupCode,
pd.GroupName,
pd.CheckListCode,
pd.CheckListName,
pd.Status;
But results is not according to my needs. This above query is showing following result
This is showing in two different lines but i want it in aggregated form as explained above.
Your approach is correct, but you are (also) grouping by the status, so you'll get a different row for each status - hence you get one row that counts the open statuses and one that counts the closed ones.
Just remove pd.Status from the end of the group by clause and you should be fine:
select distinct pd.GroupCode,pd.GroupName,pd.CheckListCode,pd.CheckListName,
OpenTotal =
CASE WHEN pd.Status = 'Open' THEN COUNT(pd.Status)
END,
ClosedTotal =
CASE WHEN pd.Status = 'Closed' THEN COUNT(pd.Status)
END
from PunchListDetails pd
group by pd.GroupCode,pd.GroupName,pd.CheckListCode,pd.CheckListName
You can try this:
SELECT GroupCode
,GroupName
,CheckListCode
,CheckListName,
,SUM(CASE WHEN Status = 'Open' THEN 1 ELSE 0 END) as OpenTotal
,SUM(CASE WHEN Status = 'Closed' THEN 1 ELSE 0 END) as ClosedTotal
FROM PunchListDetails
GROUP BY GroupCode,GroupName,CheckListCode,CheckListName
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')
Given the table like
| userid | active | anonymous |
| 1 | t | f |
| 2 | f | f |
| 3 | f | t |
I need to get:
number of users
number of users with 'active' = true
number of users with 'active' = false
number of users with 'anonymous' = true
number of users with 'anonymous' = false
with single query.
As for now, I only came out with the solution using union:
SELECT count(*) FROM mytable
UNION ALL
SELECT count(*) FROM mytable where active
UNION ALL
SELECT count(*) FROM mytable where anonymous
So I can take first number and find non-active and non-anonymous users with simple deduction .
Is there any way to get rid of union and calculate number of records matching these simple conditions with some magic and efficient query in PostgreSQL 9?
You can use an aggregate function with a CASE to get the result in separate columns:
select
count(*) TotalUsers,
sum(case when active = 't' then 1 else 0 end) TotalActiveTrue,
sum(case when active = 'f' then 1 else 0 end) TotalActiveFalse,
sum(case when anonymous = 't' then 1 else 0 end) TotalAnonTrue,
sum(case when anonymous = 'f' then 1 else 0 end) TotalAnonFalse
from mytable;
See SQL Fiddle with Demo
Assuming your columns are boolean NOT NULL, this should be a bit faster:
SELECT total_ct
,active_ct
,(total_ct - active_ct) AS not_active_ct
,anon_ct
,(total_ct - anon_ct) AS not_anon_ct
FROM (
SELECT count(*) AS total_ct
,count(active OR NULL) AS active_ct
,count(anonymous OR NULL) AS anon_ct
FROM tbl
) sub;
Find a detailed explanation for the techniques used in this closely related answer:
Compute percents from SUM() in the same SELECT sql query
Indexes are hardly going to be of any use, since the whole table has to be read anyway. A covering index might be of help if your rows are bigger than in the example. Depends on the specifics of your actual table.
-> SQLfiddle comparing to #bluefeet's version with CASE statements for each value.
SQL server folks are not used to the proper boolean type of Postgres and tend to go the long way round.