To retrieve records having only two specific values - sql

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

Related

Select table adding columns with data depending on duplicates in other column

Imagine this data.
Id
Type
1
A
1
B
1
B
2
A
3
B
I want to select table and ad two columns turning it to this. How can i do it? (In teradata)
Id
Type
Id with both A+B
Id with only A
1
A
1
0
1
B
1
0
1
B
1
0
2
A
0
1
3
B
0
0
I'm not familiar with teradata but in standard SQL next query should be working:
SELECT
T.*,
CASE WHEN Cnt = 2 THEN 1 ELSE 0 END AS BOTH_TYPES_PRESENT,
CASE WHEN Cnt = 1 AND Type = 'A' THEN 1 ELSE 0 END AS ONLY_A_PRESENT
FROM T
LEFT JOIN (
SELECT Id, COUNT(DISTINCT Type) Cnt FROM T WHERE Type IN ('A', 'B') GROUP BY Id
) CNT ON T.Id = CNT.Id;
SQL online editor

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

Merge multiple columns into one column with multiple rows

In PostgreSQL, how can I merge multiple columns into one column with multiple rows?
The columns are all boolean, so I want to:
Filter for true values only
Replace the true value (1) with the name of the column (A, B or C)
I have this table:
ID | A | B | C
1 0 1 0
2 1 1 0
3 0 0 1
4 1 0 1
5 1 0 0
6 0 1 1
I want to get this table:
ID | Letter
1 B
2 A
2 B
3 C
4 A
4 C
5 A
6 B
6 C
I think you need something like this:
SELECT ID, 'A' as Letter FROM table WHERE A=1
UNION ALL
SELECT ID, 'B' as Letter FROM table WHERE B=1
UNION ALL
SELECT ID, 'C'as Letter FROM table WHERE C=1
ORDER BY ID, Letter
SELECT ID,
(CASE
WHEN TABLE.A = 1 then 'A'
WHEN TABLE.B = 1 then 'B'
WHEN TABLE.C = 1 then 'C'
ELSE NULL END) AS LETTER
from TABLE
You may try this.
insert into t2 select id, 'A' from t1 where A=1;
insert into t2 select id, 'B' from t2 where B=1;
insert into t2 select id, 'C' from t3 where C=1;
If you care about the order, then you can do this.
insert into t3 select id, letter from t2 order by id, letter;
W/o UNION
You can use a single query to get the desired output.Real time example
select id
,regexp_split_to_table((
concat_ws(',', case
when a = 0
then null
else 'a'
end, case
when b = 0
then null
else 'b'
end, case
when c = 0
then null
else 'c'
end)
), ',') l
from c1;
regexp_split_to_table() & concat_ws()

SQL Join different item from one table

I have a table
Tablename = table01
ID Item value
4 a 10
5 b 12
5 c 15
and my sql
select value as b from table01 where ID = 5 and Item = b
select value as c from table01 where ID = 5 and Item = c
How can i join this two sql?
this is my imagine result
b c
12 15
Here is one method:
select t1.id, t1.value as b, t2.value as c
from table1 t1 join
table1 t2
on t1.id = t2.id and t1.item = 'b' and t2.item = 'c';
SELECT MAX( CASE WHEN Item = 'b' THEN value END ) AS b,
MAX( CASE WHEN Item = 'c' THEN value END ) AS c
FROM table01;
Here is one way using Conditional Aggregate
select max(case when Item = 'b' then value end),
max(case when Item = 'c' then value end)
from yourtable
Where ID = 5
and Item in ( 'b' , 'c')
Note : This considers that ID & ITEM combination is not duplicated. If it is duplicated then you will max value out of duplicate

Exclude value of a record in a group if another is present

In the example table below, I'm trying to figure out a way to sum amount over id for all marks where mark 'C' doesn't exist within an id. When mark 'C' does exist in an id, I want the sum of amounts over that id, excluding the amount against mark 'A'. As illustration, my desired output is at the bottom. I've considered using partitions and the EXISTS command, but I'm having trouble conceptualizing the solution. If any of you could take a look and point me in the right direction, it would be greatly appreciated :)
sample table:
id mark amount
------------------
1 A 1
2 A 3
2 B 2
3 A 2
4 A 1
4 B 3
5 A 1
5 C 3
6 A 2
6 C 2
desired output:
id sum(amount)
-----------------
1 1
2 5
3 2
4 4
5 3
6 2
select
id,
case
when count(case mark when 'C' then 1 else null end) = 0
then
sum(amount)
else
sum(case when mark <> 'A' then amount else 0 end)
end
from sampletable
group by id
Here is my effort:
select id, sum(amount) from table t where not t.id = 'A' group by id
having id in (select id from table t where mark = 'C')
union
select id, sum(amount) from table t where t.id group by id
having id not in (select id from table t where mark = 'C')
SELECT
id,
sum(amount) AS sum_amount
FROM atable t
WHERE mark <> 'A'
OR NOT EXISTS (
SELECT *
FROM atable
WHERE id = t.id
AND mark = 'C'
)
GROUP BY
id
;