Grouping and counting issue - sql

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.

Related

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

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

How can i select row from table according to column values of row in sql server

i want to select row on condition based on column values in sql server please check below example with required result.
WITH allData
AS (
select mlid=1,value=0,checkid=1
union all
select mlid=2,value=6,checkid=2
union all
select mlid=3,value=6,checkid=1
union all
select mlid=4,value=0,checkid=2
)
select * from allData
Result
Mlid Value checked
1 0 1
2 6 2
3 6 1
4 0 2
required result -->
condition:- if checked column values is 1 and values column is 0 than display checked values values 2 rows only
either display checked column values 1
like below result
Mlid value checked
2 6 2
3 6 1
This will work for your sample data, but would fail for pretty much anything else?
WITH allData AS (
SELECT MLID = 1, [VALUE] = 0, CHECKID = 1
UNION ALL
SELECT MLID = 2, [VALUE] = 6, CHECKID = 2
UNION ALL
SELECT MLID = 3, [VALUE] = 6, CHECKID = 1
UNION ALL
SELECT MLID = 4, [VALUE] = 0, CHECKID = 2)
SELECT
CASE WHEN a1.CHECKID = 1 AND a1.VALUE = 0 THEN a2.MLID ELSE a1.MLID END AS MLID,
CASE WHEN a1.CHECKID = 1 AND a1.VALUE = 0 THEN a2.[VALUE] ELSE a1.[VALUE] END AS [VALUE],
CASE WHEN a1.CHECKID = 1 AND a1.VALUE = 0 THEN a2.CHECKID ELSE a1.CHECKID END AS CHECKID
FROM
allData a1
INNER JOIN allData a2 ON a2.MLID = a1.MLID + 1 AND a2.CHECKID = 2
WHERE
a1.CHECKID = 1;
I guess this might get you started on a better query, or even raise some questions about what you actually need, and how these rows are related?

Getting distinct rows on SQL query with multiple IIF columns

In SQL Server I am creating a view that shows if a record in table CONTACTS has certain tags in a different table TAGS.
This is my query:
SELECT DISTINCT
contacts.ID, contacts.NAME,
IIF(tags.tag = 'A', 1, 0) as A,
IIF(tags.tag = 'B', 1, 0) as B,
IIF(tags.tag = 'C', 1, 0) as C,
IIF(tags.tag = 'D', 1, 0) as D
FROM
contacts
LEFT JOIN
TAGS ON contacts.ID = TAGS.CONTACT_ID
I would like the results like this:
ID NAME A B C D
------------------------------------
1 BOB 1 0 0 1
1 Charlie 1 0 1 0
but I get
ID NAME A B C D
------------------------------------
1 BOB 1 0 0 0
1 BOB 0 0 0 1
1 Charlie 1 0 0 0
1 Charlie 0 0 1 0
Must be something I overlook, but I can't find it.
You need simply use GROUP BY clause + MAX aggreate instead of DISTINCT
SELECT contacts.ID, contacts.NAME
, MAX(IIF(tags.tag = 'A', 1, 0)) as A
, MAX(IIF(tags.tag = 'B', 1, 0)) as B
, MAX(IIF(tags.tag = 'C', 1, 0)) as C
, MAX(IIF(tags.tag = 'D', 1, 0)) as D
FROM contacts LEFT JOIN
TAGS ON contacts.ID = TAGS.CONTACT_ID
group by
contacts.ID, contacts.NAME
As Gordon Linoff says, use of standard SQL case when is more compatible with all the database (postgres, oracle, sql server ...)
IIF(tags.tag = 'A', 1, 0)
is equivalent to
CASE WHEN tags.tag = 'A' THEN 1 ELSE 0 END
Use group by:
SELECT c.ID, c.NAME,
MAX(CASE WHEN t.tag = 'A' THEN 1 ELSE 0 END) as A,
MAX(CASE WHEN t.tag = 'B' THEN 1 ELSE 0 END) as B,
MAX(CASE WHEN t.tag = 'C' THEN 1 ELSE 0 END) as C,
MAX(CASE WHEN t.tag = 'D' THEN 1 ELSE 0 END) as D
FROM contacts c LEFT JOIN
TAGS t
ON c.ID = t.CONTACT_ID
GROUP BY c.ID, c.NAME;
Note changes the query:
Introduced table aliases. These make the query easier to write and to read.
Removed the SELECT DISTINCT, because you really want a GROUP BY.
Changed IIF() to CASE. I see no reason to use a function designed for backward compatibility to MS Access over the SQL standard function.
SELECT contacts.ID, contacts.NAME
, MAX(IIF(tags.tag = 'A', 1, 0)) as A
, MAX(IIF(tags.tag = 'B', 1, 0)) as B
, MAX(IIF(tags.tag = 'C', 1, 0)) as C
, MAX(IIF(tags.tag = 'D', 1, 0) as D
FROM contacts LEFT JOIN
TAGS ON contacts.ID = TAGS.CONTACT_ID
GROUP BY contacts.ID, contacts.NAME

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

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')