How to check if non-unique key contains specific value pairs? - sql

I have the following table:
CREATE TABLE TABLE1 (
ID,
status,
timestamp
)
I would like to check for ID's that have status A, but also for ID's that have status B AND status C. I would like them to be placed into a count somewhat as follows:
SELECT
ID
,SUM(CASE WHEN status = 'A' then 1
WHEN
-- something like the following:
status = 'B' and (status = 'C' AND [timestamp of C] > [timestamp of B]) then 1
else 0 END) as SUCCESS
FROM TABLE1
GROUP BY ID
Do I need a self join here? How do I get the IDs that have this status = B & C with a timestampB < timestampC conditional?
Example table:
INSERT INTO TABLE1(ID, status, timestamp)
VALUES(1, A, 5)
VALUES(2,B, 3)
VALUES(2, D, 5)
VALUES(3, A, 5)
VALUES(4, B, 9)
VALUES(4,C,10)
Results should be:
1, 1
2, 0
3, 1
4, 1

If you want ids that have A and whose timestamp for B is less than C, then use:
select id
from t
group by id
having sum(case when status = 'A' then 1 else 0 end) > 0 and
min(case when status = 'B' then timestamp end) < max(case when status = 'C' then timestamp end)
EDIT:
select id,
(case when sum(case when status = 'A' then 1 else 0 end) > 0 and
min(case when status = 'B' then timestamp end) < max(case when status = 'C' then timestamp end)
then 1 else 0
end) as success_flag
from t
group by id

Related

SQL sum up count group by

Currently have a query that hits AWS Redshift. I have this group by a recipient in order to count the total of the output.
select count(CASE WHEN event_name = 'c' THEN 1 END)
from oe
where owner_id = $1
and rid = $2
and cid = $2
and rbid is not null
group by recipient
having count(CASE WHEN event_name = 'c' THEN 1 END) > 0
and count(CASE WHEN event_name = 'd' THEN 1 END) > 0
The output from that is this
5
4
1
1
I'd like to be able, to sum up those numbers to produce a final number, as well as count the number of rows. How can I go about achieving this?
This should give you the desired result.
select sum(sum_c), count(*) from (
select count(CASE WHEN event_name = 'c' THEN 1 END) sum_c
from oe
where owner_id = $1
and rid = $2
and cid = $2
and rbid is not null
group by recipient
having count(CASE WHEN event_name = 'c' THEN 1 END) > 0
and count(CASE WHEN event_name = 'd' THEN 1 END) > 0) x;

Group by several columns with count on another column SQL Server

I'm using SQL SERVER 2012 and I'm struggling with this SQL statement. Basically I have this table
table
I want to group by Date, and Username, with a count on the status column, like below :
query result
How can I achieve this?
You can use an aggredated query with a few conditional SUMs.
SELECT
LastUpdate,
UpdatedBy as User,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END) as A
SUM(CASE WHEN Status = 'C' THEN 1 ELSE 0 END) as C
SUM(CASE WHEN Status = 'D' THEN 1 ELSE 0 END) as D
SUM(CASE WHEN Status = 'Z' THEN 1 ELSE 0 END) as Z
SUM(CASE WHEN Status = 'X' THEN 1 ELSE 0 END) as X
FROM table
GROUP BY LastUpdate, UpdatedBy
ORDER BY LastUpdate, UpdatedBy
You can try using conditional aggregation
select LastUpdate,UpdatedBy,
count(case when Status='A' then UpdatedBy end) as 'A',
count(case when Status='C' then UpdatedBy end) as 'C',
count(case when Status='D' then UpdatedBy end) as 'D',
count(case when Status='Z' then UpdatedBy end) as 'Z',
count(case when Status='X' then UpdatedBy end) as 'X'
from tablename
group by LastUpdate,UpdatedBy
Ok I figured it out with help from the guys answers
SELECT
CAST(LastUpdate as DATE),
UserName,
SUM(CASE WHEN Status = 1 THEN 1 ELSE 0 END) as [Status_1],
SUM(CASE WHEN Status = 2 THEN 1 ELSE 0 END) as [Status_2],
SUM(CASE WHEN Status = 3 THEN 1 ELSE 0 END) as [Status_3]
FROM Table
WHERE LastUpdate BETWEEN '2018-11-30 10:013:44.080' AND '2018-12-30 10:013:44.080'
GROUP BY CAST(LastUpdate as DATE), UserName
ORDER BY CAST(LastUpdate as DATE)
This is a sample query where I'm looking for records between two dates. The problem I was having was in part due to filtering on datetime rather than date. The lastupdate column is a datetime so by casting to date it solved the issue

how to select rows with multiple where conditions

Not sure if the title made sense.
But this what I need, I am bad at sql:
I have table with the following data
ID| Value
------ | ------
1| A
1| B
1| C
1| D
2| A
2| B
2| C
I need O/P as
2 A
2 B
2 C
Using Select id where value in (A,B,C) and Not in (D)
is giving me o/p as
1 A
1 B
1 C
2 A
2 B
2 C
Need to select Id's having A,B,C but not D.
If you want to get rows which has one or more value in A, B, C, but not D:
select *
from your_table
where value in ('A', 'B', 'C')
and id not in (
select id
from your_table
where value = 'D'
);
If you want that all the three values A, B, C must be present for that id and but not D.
select id,
value
from (
select t.*,
count(distinct value) over (partition by id) n
from your_table t
where value in ('A', 'B', 'C')
and id not in (
select id
from your_table
where value = 'D'
)
)
where n = 3;
If you want to get rows having only A, B, C (and all of them present) then use :
select id,
value
from (
select t.*,
count(case
when value not in ('A', 'B', 'C')
then 1
end) over (partition by id) n,
count(distinct case
when value in ('A', 'B', 'C')
then value
end) over (partition by id) n2
from your_table t
)
where n = 0
and n2 = 3;
You can use conditional aggregation in a HAVING clause to filter across rows for each id:
SELECT id
FROM table1
GROUP BY id
HAVING MAX(CASE WHEN value = 'A' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN value = 'B' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN value = 'C' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN value = 'D' THEN 1 ELSE 0 END) = 0
This will show you which id values meet your criteria, and if you need you can put this in a subquery and join it to your table to get all the rows for that id:
SELECT a.*
FROM table1 a
JOIN ( SELECT id
FROM table1
GROUP BY id
HAVING MAX(CASE WHEN value = 'A' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN value = 'B' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN value = 'C' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN value = 'D' THEN 1 ELSE 0 END) = 0
) b
ON a.id = b.id
From your question, I understood that to find the count of Value column where the values are A, B, C but Value not equal to D. Then simply put those 3 value in IN operator. I will retrieve the result set without D.
Query
SELECT COUNT(Value) count, Value
FROM your_table_name
WHERE Value in ('A', 'B', 'C')
GROUP BY Value;
select id, value
from my_table
where value in ('A','B','C')
and id = 2

Grouping and counting issue

I have a table like this:
Id,Code, (some more columns)
1, c
1, a
1, b
1, b
1, b
2, a -- the desired row
3, b
3, c
3, a
3, a
I want to get one Id (or all) which have only been associated with 'a' and not 'b' and 'c'. How do I do this ?
What i tried just now:
select *
from
(
select Id, count(case when Code='a' then 0 else 1 end) c
from tbl
group by Id
)
where c = 0
Why does this not work ?
This will get you the list of Id values which are associated only with codes of 'a'.
select Id
from tbl
group by Id
having max(case when Code='a' then 0 else 1 end) = 0
See this fiddle for a live demo.

To retrieve records having only two specific values

Have the following Data in the table
Example Table
ID Value
1 a
1 b
1 c
2 a
2 b
2 c
3 a
3 b
I need to retrieve records having ID with only two values a and b.
So i am expecting only the Record with ID 3 .
Can anyone help me with the query
I guess you could do something like
select
ID,
sum(case when value = 'a' then 1
when value = 'b' then 1
else 3 end)
from
table1
group by id
having
sum (case when value = 'a' then 1
when value = 'b' then 1
else 3 end) =2
SQL Fiddle
That will work:
select x.id from
(
select id from mytable where value = 'a'
union all
select id from mytable where value = 'b'
) x
group by x.id
having COUNT(*) = 2
and not exists (select * from mytable t where t.id = x.id and value <> 'a' and value <> 'b')