I am trying to return some values in SQL. Let's call Column A as UniqueIdentifier I then have a row that lists two different actions that can be done to this unique identifier, let's call the column action and the actions a and b
The actions can be duplicated more than one time per unique identifier, thus listing tons of duplicated UniqueIdentifier
How do I get the count of UniqueIdentifier where action a has been performed and the count where action a has not?
I did create a really long and cumbersome way(listed below) using temp tables but I feel like there must be a more roundabout way
<!-- language: lang-sql -->
select
UniqueIdentifier
,case when action = 'a' then 1 else 0 end [actionflag]
into #actionflags
from mydatabase
select
distinct UniqueIdentifier
,sum(actionflag)
into #actionflagscount
from #actionflags
group by UniqueIdentifier
select case when actionflag > 0 then 1 else 0 end [actionflag]
,count(uniqueidentifier)
from #actionflagscount
group by case when actionflag > 0 then 1 else 0 end
Do you want DISTINCT ?
select case when actionflag > 0 then 1 else 0 end [actionflag],
count(distinct uniqueidentifier)
from #actionflagscount
group by case when actionflag > 0 then 1 else 0 end
This is what I came up with
DROP TABLE IF EXISTS #temp
CREATE TABLE #temp ([UniqueIdentifier] INT, Action NVARCHAR(10))
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (1, 'a')
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (2, 'a')
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (3, 'a')
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (4, 'b')
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (5, 'b')
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (6, 'c')
INSERT INTO #temp ([UniqueIdentifier], Action) VALUES (7, 'c')
SELECT CASE WHEN Action = 'a' THEN 1 ELSE 0 END AS ActionFlag, COUNT(*)
FROM #temp
GROUP BY CASE WHEN Action = 'a' THEN 1 ELSE 0 END
-- Results:
-- ActionFlag (No column name)
-- 0 4
-- 1 3
Considering you may have:
The same action performed several times on the same UniqueIdentifier
Different actions performed on the same UniqueIdentifier
I would do:
SELECT DISTINCT UniqueIdentifier, CASE WHEN EXISTS (SELECT 1 FROM MyDatabase WHERE action = 'a' and UniqueIdentifier = MDB.UniqueIdentifier) THEN 1 ELSE 0 END AS ActionPerformed
FROM MyDatabase MDB
If this looks fine, then, a simple COUNT will do the trick surrounding the previous query.
SELECT Count(*), ActionPerformed
FROM (
SELECT DISTINCT UniqueIdentifier, CASE WHEN EXISTS (SELECT 1 FROM MyDatabase WHERE action = 'a' and UniqueIdentifier = MDB.UniqueIdentifier) THEN 1 ELSE 0 END AS ActionPerformed
FROM MyDatabase MDB
) T
GROUP BY ActionPerformed
ActionPerformed = 1 means action a was performed (possibly action b was performed too on the same UniqueIdentifier). ActionPerformed = 0 means action a was not performed (but it does not say anything about action b)
I would use two levels of aggregation:
select sum(case when num_as > 0 then 1 else 0 end) as num_with_as,
sum(case when num_as = 0 then 1 else 0 end) as num_without_as
from (select uniqueidentifier,
sum(case when action = 'a' then 1 else 0 end) as num_as
from mydatabase
group by uniqueidentifier
) d;
The inner query counts the number of "a"s per uniqueidentifier. The outer query uses this to get the two values you want.
I have a table called TESTTABLE
The table script and some sample date
CREATE TABLE Test_Table(
NODE VARCHAR(10) NOT NULL PRIMARY KEY
,EVENTID CHAR(255) NOT NULL
,TYPE INTEGER NOT NULL
,FIRSTOCCURRENCE VARCHAR(16) NOT NULL
,LASTOCCURRENCE VARCHAR(16) NOT NULL
,TALLY INTEGER NOT NULL
,TICKETNUMBER VARCHAR(20)
,TIME_DELTA VARCHAR(5)
);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Washington','ReachabilityProblem',2,'12/13/2017 23:24','12/13/2017 23:24',1,NULL,'1 sec');
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('San Diego','ReachabilityProblem',1,'12/13/2017 23:23','12/13/2017 23:23',1,NULL,NULL);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Richmond','ReachabilityProblem',1,'12/13/2017 14:23','12/13/2017 14:23',1,NULL,NULL);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Richmond','ReachabilityProblem',1,'12/13/2017 23:23','12/13/2017 23:23',1,NULL,NULL);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('New York','ReachabilityProblem',2,'12/13/2017 23:24','12/13/2017 23:24',1,NULL,'1 sec');
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('New York','ReachabilityProblem',2,'12/13/2017 11:32','12/13/2017 11:33',2,NULL,'1 sec');
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('New York','ReachabilityProblem',1,'12/13/2017 16:35','12/13/2017 16:35',1,NULL,NULL);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Landsdown','ReachabilityProblem',2,'12/13/2017 23:24','12/13/2017 23:24',1,NULL,'1 sec');
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Houston','ReachabilityProblem',2,'12/13/2017 14:24','12/13/2017 14:24',1,NULL,'1 sec');
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Houston','ReachabilityProblem',1,'12/13/2017 11:31','12/13/2017 11:32',2,NULL,NULL);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Dallas','ReachabilityProblem',1,'12/13/2017 23:23','12/13/2017 23:23',1,NULL,NULL);
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Dallas','ReachabilityProblem',2,'12/13/2017 23:24','12/13/2017 23:24',1,NULL,'1 sec');
INSERT INTO Test_Table(NODE,EVENTID,TYPE,FIRSTOCCURRENCE,LASTOCCURRENCE,TALLY,TICKETNUMBER,TIME_DELTA) VALUES ('Coco Beach','ReachabilityProblem',1,'12/13/2017 23:23','12/13/2017 23:23',1,NULL,NULL);
I'm trying to obtain this
I have tried this
Select DATEDIFF(Day, GETDATE(), DATEADD(HOUR, 15, GETDATE()))
Select
[NODE]
,[EVENTID]
,[TYPE]
,[FIRSTOCCURRENCE]
,LASTOCCURRENCE]
,DATEDIFF(Minute, FIrst OCCURENCE, LAST OCCURENCE) as [Outage in MIN]
,[TicketNumber]
,[Severity]
,Tally]
From
[XYZ].[XYZ].[XYZ_STATUS]
Where
[FIRST OCCURRENCE] >= DATEADD(hh, -24, GETDATE())
Group by node;
Please help a rookie
Group by returns a relation/table with a row for each group, if you are going to use the GROUP BY clause, so in your SELECT statement you can only select the column that you are grouping by and use aggregate functions on that column because the other columns will not appear in the resulting table.
Maybe this is what you want...
Select
DATEDIFF (DAY, GETDATE(), DATEADD(Hour, 15, GETDATE())),
,Node
,EventID
,Type
,Severity
,Tally
FROM xyz.xyz.xyz_status
GROUP BY Node,EventID,Type,Severity,Tally
When we group by two or more columns, it is saying "Group them so that all of those with the same col1 and col2 are in the same group, and then calculate all the aggregate functions (Count, Sum, Average, etc.) for each of those groups"
Maybe you want this...
SELECT DATEDIFF(minute,(SELECT TOP(1) FIRSTOCCURRENCE FROM
xyz.xyz.xyz_status),(SELECT TOP(1) LASTOCCURRENCE FROM
xyz.xyz.xyz_status))
FROM xyz.xyz.xyz_status
WHERE node = 'Houston';
Here you can take a look at more examples of DATEDIFF function.
This should put you on track although Writing reports in SQL is probably a bad idea. What I believe you're wanting to do it output. You can also look at the ROLLUP options some of which are deprecated.
with data as (
select
NODE, EVENTID, TYPE, FIRSTOCCURRENCE, LASTOCCURRENCE,
DATEDIFF(Minute, FIRSTOCCURRENCE, LASTOCCURRENCE) as OutageInMin,
TicketNumber, Tally,
ROW_NUMBER() OVER (PARTITION BY NODE ORDER BY FIRSTOCCURRENCE) as rn
from Test_Table
--WHERE FIRSTOCCURRENCE >= DATEADD(hh, -24, GETDATE())
)
select
case when grouping(rn) = 1 then 'SITE TOTAL' else NODE end as NODE,
case when grouping(rn) = 1 then null else min(EVENTID) end as EVENTID,
case when grouping(rn) = 1 then null else min(TYPE) end as TYPE,
case when grouping(rn) = 1 then null else min(FIRSTOCCURRENCE) end as FIRSTOCCURRENCE,
case when grouping(rn) = 1 then null else min(LASTOCCURRENCE) end as LASTOCCURRENCE,
case when grouping(rn) = 1 then null else min(Tally) end as Tally,
case when grouping(rn) = 1 then null else min(TicketNumber) end as TicketNumber,
case when grouping(node) = 1
then min(OutageInMin) else sum(OutageInMin) end as "Outage In MIN"
from
data
group by grouping sets ( (NODE, rn), (NODE) )
order by data.NODE, grouping(rn), rn;
http://rextester.com/DZIHJ81264
GROUP BY is only authorized in SQL when you are aggregating something. The easiest exemple is a count.
Example : you want to know how much EventID are linked to a given Node :
SELECT Count(EventId), node FROM xyz.xyz.xyz_status GROUP BY node;
Here is a site that present the Group By function. If you clarify what you are searching for, we'll give you a more concrete example.
I have created a temporary table with dynamic columns. These columns are the values in a master table.
Say,
Id |Name
1 |Prepaid
2 |Postpaid
so the temporary table columns will be
Id Prepaid Postpaid
In this case the columns are dynamic.
consider the below code for temp table:
declare #temp as table (Id int, Prepaid float, postpaid float)
insert into #temp values(1,100,200)
insert into #temp values(1,10,500)
insert into #temp values(1,-100,-100)
insert into #temp values(1,10,200)
insert into #temp values(1,100,-100)
insert into #temp values(1,150,560)
insert into #temp values(1,90,200)
I need to insert a row with average of each column.
Average should be calculated taking the rows which meet the condition, i.e, the column should not contain a value -100.
I need to insert a row with average values like for the above values.
Id PrepaidAvg PostPaidAvg
1 76.6666666666667 320
Hard to determine exactly what result you expect, but here is one try:
SELECT
Id,
PrepaidAvg = AVG(CASE WHEN Prepaid > 0 THEN Prepaid ELSE NULL END),
PostpaidAvg = AVG(CASE WHEN postpaid > 0 THEN postpaid ELSE NULL END)
FROM #temp
GROUP BY Id;
If this is off you can get more elaborate:
;WITH prepaid AS
(
SELECT Id, PrepaidAvg = AVG(Prepaid)
FROM #temp WHERE Prepaid > 0
), postpaid AS
(
SELECT Id, PostpaidAvg = AVG(postpaid)
FROM #temp WHERE postpaid > 0
)
SELECT Id = COALESCE(prep.Id, postp.Id),
prep.PrepaidAvg,
postp.PostpaidAvg
FROM prepaid AS prep
FULL OUTER JOIN postpaid AS postp
ON prep.Id = postp.Id;
Use this query
insert into #temp
select avg(Id), avg(Prepaid), avg(postpaid)
from #temp
where Prepaid <> -100 and postpaid <> -100
I have a table that functions as an event log and stores the users signed in state, 'In', 'Out', or 'Rejected' (sometimes users my be 'Rejected' based on external criteria).
Here is some sample data so you can get an idea of what the table looks like:
Table MyTable
PersonID - State - DateTime
// data sample
156 - 'Out' - 02-14-2010 13:04:15
156 - 'In' - 02-21-2010 09:01:13
16 - 'In' - 02-21-2010 09:05:01
58 - 'Rejected' - 02-21-2010 11:04:58
156 - 'Out' - 02-21-2010 11:10:02
Here is some pseduo check restraint code outlining what I'd like to do:
CHECK(
CASE
WHEN (
[State] = 'In' AND
(Select TOP 1 State FROM MyTable WHERE PersonID=#PersonID_ToUpdate)!='In' ORDER BY DateTime DESC)
)
THEN 'T'
WHEN (
[State] = 'Out' AND
(Select TOP 1 State FROM MyTable WHERE PersonID=#PersonID_ToUpdate)!='Out' ORDER BY DateTime DESC)
)
THEN 'T'
WHEN (
[State] = 'Rejected' AND
(Select TOP 1 State FROM MyTable WHERE PersonID=#PersonID_ToUpdate)!='In' ORDER BY DateTime DESC)
)
THEN 'T'
ELSE 'F'
END = 'T'
)
Basically:
A person can sign IN if their last state was not 'In'
A person can sign OUT if their last state was not 'Out'
A person can be REJECTED if their last state was not 'In'
I don't know if a Check Constraint is the best way to do this or if my database design will allow for this level of constraint; please let me know if I'm out of my mind (and kindly suggest a more suitable method for storing the data and/or ensuring data integrity)
note: I'm using SQL-Server 2008
Here's a sample trigger. It assumes that you're only going to insert 1 row at a time (which is probably the case here), and I haven't bothered with indexes, etc.
I added a clause for when the state is 'Out' so it ignores 'Rejected' states - this was to prevent multiple Out's. Its very basic but you get the idea.
if object_id('dbo.MyTable') is not null
drop table dbo.MyTable;
create table dbo.MyTable (
PersonID int not null,
[State] varchar(20) not null,
[DateTime] datetime not null default(getdate())
);
if object_id('dbo.ins_MyTable_status_validation') is not null drop trigger dbo.ins_MyTable_status_validation;
go
create trigger dbo.ins_MyTable_status_validation
on dbo.MyTable
instead of insert
as
begin
set nocount on;
-- assuming you're only inserting 1 row at a time (which makes sense for an event log)
if (select count(*) from inserted) > 1 begin
print 'Multiple rows inserted - raise some kind of error and die'
return
end
declare #personid_toupdate int,
#state varchar(20);
select #personid_toupdate = personid,
#state = [state]
from inserted;
if case
when (
#state = 'In' and
isnull((select top 1 [State] from dbo.MyTable where personid = #personid_toupdate order by [datetime] desc), 'Blah') != 'In'
)
then 'T'
when (
#state = 'Out' and
isnull((select top 1 [State] from dbo.MyTable where personid = #personid_toupdate and [State] != 'Rejected' order by [datetime] desc), 'Blah') != 'Out'
)
then 'T'
when (
#state = 'Rejected' and
isnull((select top 1 [State] from dbo.MyTable where personid = #personid_toupdate order by [datetime] desc), 'Blah') != 'In'
)
then 'T'
else 'F'
end = 'T'
begin
-- data is valid, perform the insert
insert dbo.MyTable (PersonID, [State])
select PersonID, [State]
from inserted;
end
else
begin
-- data is invalid, return an error (something a little more informative than this perhaps)
raiserror('bad data...', 16, 1)
end
end
go
-- test various combinations to verify constraints
insert dbo.MyTable (PersonID, [State]) values (1, 'In')
insert dbo.MyTable (PersonID, [State]) values (1, 'Out')
insert dbo.MyTable (PersonID, [State]) values (1, 'Rejected')
select * from dbo.MyTable
You have to use a trigger.
You can use a udf in a check constraint to hide the table access. But don't.