Count based on group with filter - sql

I have a query that displays 2 columns: "Device_ID" and "Status". Device_ID is the name of all computers and status contains either "reboot" or "success" as values. I would like a third column that would count how many "success" there are for that specific Device_ID.
How could I go about doing this?

SELECT tgt.Device_ID, tgt.Status, src.cnt
FROM [TableName] tgt
INNER JOIN
(
Select Device_ID, count(CASE WHEN Status = 'SUCCESS' THEN 1 ELSE 0END) cnt
from [TableName]
GROUP BY Device_ID
) src
ON tgt.Device_ID= src.Device_ID;

SELECT A.Device_ID,A.Status,B.Count_of_Success_per_Device_ID
FROM Yourtable A
INNER JOIN
(
SELECT Device_ID,
SUM( CASE WHEN Status = 'Success' THEN 1 ELSE 0 END ) AS Count_of_Success_per_Device_ID
FROM Yourtable
GROUP BY Device_ID
) B
ON A.Device_ID = B.Device_ID ;

Related

How do I use SQL count with group by causing an error

Here is my code
SELECT
(SELECT count(*) WHERE status_id = #TO) as 'TO' ,
(SELECT count(*) WHERE status_id = #RO)as 'RO' ,
(SELECT count(*) WHERE status_id = #AO)as 'AO',
(SELECT count(*) WHERE status_id = #IO)as 'IP',
(SELECT count(*) WHERE status_id = #SO)as 'SO',
created_user
FROM
table1
GROUP BY
created_user
Now i'm getting the following error
Column 'status_id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I don't want to group by status_id, how to fix this issue?
I guess you can try to use conditional aggregation
SELECT created_user,
SUM
(
CASE
WHEN status_id = #TO THEN 1 ELSE 0 END
)AS 'TO',
SUM
(
CASE
WHEN status_id = #RO THEN 1 ELSE 0 END
)AS 'RO'
FROM table1
GROUP BY created_user

Using Groupby with additional filter

I have the data in Initial format:
STEP 1: To find out the users having more than 1 record and show those records. This was achieved using the below.
SELECT ID,
USER,
STATUS
FROM TABLE
WHERE USER in
(SELECT USER
FROM TABLE
GROUP BY USER
HAVING COUNT(*) > 1)
*STEP 2: From the above set of records find out records for which all the values are either 1 or 2. SO data should be something like:
Can I get some suggestions to how to achieve that. Note status is NVARCHAR hence aggregate functions can't be used.
The simplest thing is to check that the status is the same in your subquery. Assuming that status only takes on the values 1 and 2:
SELECT t.ID, t.USER, t.STATUS
FROM TABLE
WHERE t.USER IN (SELECT t2.USER
FROM TABLE t2
GROUP BY t2.USER
HAVING COUNT(*) > 1 AND
MIN(t2.status) = MAX(t2.status)
);
If there are other status values and you particularly care about 1 and 2, you would use:
SELECT t.ID, t.USER, t.STATUS
FROM TABLE
WHERE t.USER IN (SELECT t2.USER
FROM TABLE t2
GROUP BY t2.USER
HAVING COUNT(*) > 1 AND
MIN(t2.status) = MAX(t2.status) AND
MIN(t2.status) IN (1, 2)
);
Please check if this helps
SELECT ID,
[USER],
[STATUS]
FROM TABLE
WHERE [USER] in
(SELECT [USER]
FROM TABLE
GROUP BY [USER]
HAVING COUNT([USER]) > 1 AND ((MIN(STATUS) != MAX(STATUS) AND COUNT(STATUS) > 2) OR (MIN(STATUS) = MAX(STATUS))))

Select statement with a condition on multiple entries

Following is my table:
I want to create a view with the following conditions in a select statement:
If count(employee_id) > 1 then only the record having status = 'Current' is picked in the view.
I tried:
select employee_id
, case when COUNT(employee_id) > 1 and statusval = 'Current' then 'Y' else 'N' end as val
from table1
group by employee_id
I hope someone can help me with this statement. Thanks.
Try this
DECLARE #T TABLE (ID INT, STATUS VARCHAR(50))
INSERT INTO #T VALUES (1,'Current'),(2,'Historical'),(2,'Historical'),(2,'Current')
SELECT * FROM #T M
INNER JOIN (SELECT ID FROM #T
GROUP BY ID
HAVING COUNT(ID) > 1) S ON S.ID=M.ID
WHERE M.STATUS = 'Current'
Just to show you how your attempt could have looked. You were nearly there, you just needed to use the windowed version of count e.g.
with cte as (
select Employee_Id, [Status]
, case when count(*) over (partition by id) > 1 and [Status] = 'Current' then 1 else 0 end Val
from Table1
)
select Employee_Id, [Status]
from cte
where Val = 1;
And this approach appears on the face of it to perform better than a join.
All of your sample data have exactly one row with 'Current'. So, the simplest solution appears to be:
select t.*
from t
where t.status = 'Current';

Counting users which doesnt make a certain event

Hi from the following table
id event
1 unknown
1 unknown
1 unknown
2 unknown
2 X
2 Y
3 unknown
3 unknown
4 X
5 Y
i want count all the amount of users which in all of their rows has unknown values
In this case they should be 2 ids out of 5
My attempt was :
select
count(distinct case when event != 'unknown' then id else null end) as loggeds,
count(distinct case when event = 'unknown' then id else null end) as not_log_android,
count(distinct event) as session_long
from table
but is completly wrong
With NOT EXISTS:
select t.id
from tablename as t
where not exists (
select 1 from tablename where id = t.id and event <> 'unknown'
)
group by t.id
for the number of disinct ids:
select count(distinct t.id)
from tablename as t
where not exists (
select 1 from tablename where id = t.id and event <> 'unknown'
)
See the demo
You can check this question: How to check if value exists in each group (after group by)
SELECT COUNT(DISTINCT t1.id)
FROM theTable t1
WHERE NOT EXISTS (SELECT 1 from theTable t2 where t1.id = t2.id and t2.value != 'unknown')
OR
SELECT COUNT(t.id)
FROM theTable t
GROUP BY t.id
HAVING MAX(CASE value WHEN 'unknown' THEN 0 ELSE 1 END) = 0
SELECT id
FROM YourTable
GROUP BY id
HAVING COUNT(*) = COUNT ( CASE WHEN event = 'unknown' THEN 1 END )
I would do aggregation :
SELECT id
FROM table t
GROUP BY id
HAVING MIN(event) = MAX(event) AND MIN(event) = 'unknown';

Classic ASP / MSSQL - Remove returned results based on certain conditions

I have a little sql query, like so
SELECT * FROM table
This returns a bunch of results, i output the following fields:
ID
UserID
Amount
Date
What i want to do is get the most recent entry from each UserID ( based on ID ), then if the amount is 0 do not return ANY results from that UserID.
select t1.*
from your_table t1
join
(
select userid, max(date) as mdate
from your_table
group by userid
having sum(case when amount = 0 then 1 else 0 end) = 0
) t2 on t1.userid = t2.userid and t1.date = t2.mdate
In the subquery you group by the user and select only those having no amount of zero. In that select you use max(date) as mdate to get the latest date for each user.
That subquery can be joined to the original table to get the complete record and not just the userid.
try this
WITH cte AS
(
SELECT
MAX(ID) OVER (PARTITION BY UserID) MaxIDForUserID,
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY ID DESC) rn,
UserID,
Amount,
Date
FROM TableName
)
SELECT * FROM cte WHERE rn = 1 AND Amount != 0