How to select rows that have certain values present in another column - sql

I have a table :
id
value
1
A
1
B
1
C
2
A
2
B
3
A
my goal is to have the table where I have only IDs that have A,B,C present per id,
in this case it is:
id
1
how to construct the SQL query for that ?

One canonical approach uses aggregation:
SELECT id
FROM yourTable
WHERE value IN ('A', 'B', 'C')
GROUP BY id
HAVING COUNT(DISTINCT value) = 3;

To use exists statement like this:
select id from ${table} a where value = 'A'
and exists (select 1 from ${table} b where a.id = b.id and b.value = 'B')
and exists (select 1 from ${table} c where a.id = c.id and b.value = 'C')
To create index on column id will be more nice.

Related

How to select groups which has only the values we want and not select it if it also has other values in SQL

id
code
value
A
cod
2
A
buy
34
A
cod
4
B
cod
44
B
F
23
C
thk
45
C
cod
33
C
F
31
D
cod
22
In this table for example, I want those groups of id which has 'code' column value as ONLY cod or F. so query should return values of id = B and nothing else. ( Not even values with id = C because id=C also has 'thk' in code , not even id= D, and output should have ids with ONLY the mentioned two values)
expected output
id
code
value
B
cod
44
B
F
23
You want all rows for the ID of which not exists a forbidden row:
select id, code, value
from mytable
where not exists
(
select null
from mytable forbidden_row
where forbidden_row.id = mytable.id
and forbidden_row.code not in ('cod', 'F')
);
One of approaches with nested query
SELECT ID,Code, value FROM (
select ID, Code,
(SELECT count(*) FROM TableA a where Code = 'cod' and a.ID = TableA.ID) Cod,
(SELECT count(*) FROM TableA a where Code = 'F' and a.ID = TableA.ID) F,
(SELECT count(*) FROM TableA a where Code not in ('F','cod') and a.ID = TableA.ID) Other,
Value
from TableA
) SOURCE
WHERE Cod <> 0 AND F <> 0 and Other = 0
We can achieve this using CTE. Check this,
-- Split the two record category first, then check cod Or F condition.
WITH Count2 AS (
SELECT id
FROM YourTable
GROUP BY id
HAVING COUNT(id) = 2
),
codORF AS (
SELECT id, code, COUNT(id) FROM YourTable T1
LEFT JOIN Count2 T2 On T1.id = T2.id
WHERE code = 'cod' OR code = 'F'
GROUP BY id, code
Having COUNT(id) = 1
)
-- Finally to take all values
SELECT T1.*
FROM YourTable T1
INNER JOIN codORF T2 ON T1.id = T2.id
with main as (
select *, count(id) over(partition by id order by id) as total_rows
from sample
), next_and_before as (
select *,
COALESCE(lag(code) over(partition by id order by id),lead(code) over(partition by id order by id)) as before_next
from main where total_rows <= 2
)
select * from next_and_before
where lower(trim(concat(code,before_next)))in('codf','fcod','cod','f')
Its a bit of hacky solution:
first you are filtering out all the rows that have less than or equal to 2 rows, since there could be cases where you only have one row per id with a code value = 'f' or 'cod', if you don't want that then simply change the last part to: in ('codf','fcod')
then out of two rows, you are looking at the next and before value and checking if it contains other than 'f' or 'cod'
where clause will filter those out if they exist
Test Results from the link below:
Results of sample data

Grouping of column

Group Error
1 a
1 b
1 c
2 a
2 b
3 a
I want write an SQL query to get that record only which has either only a or b as an error or both a and b
Output should be Group 2, 3 as
Group 2 contains both a and b , Group 3 contains only a.
Any Group that contains Error apart from a,b should not be returned.
I'd group and use a condition on a count of errors that aren't a or b:
SELECT [group] -- Assuming MS SQL Syntax, like Ross Presser did in his answer
FROM mytable
GROUP BY [group]
HAVING COUNT(CASE WHEN [error] NOT IN ('a', 'b') THEN 1 END) = 0
Unsure of the DBMS and so the following may not be applicable, but to offer another option using a correlated subquery:
SELECT DISTINCT a.Group
FROM Table1 a
WHERE NOT EXISTS (SELECT 1 FROM Table1 b WHERE a.Group = b.Group AND b.Error NOT IN ('a','b'))
Or using a LEFT JOIN on a query of Groups containing at least one Error code not equal to a or b:
SELECT DISTINCT a.Group
FROM
Table1 a LEFT JOIN
(
SELECT DISTINCT t.Group
FROM Table1 t
WHERE t.Error <> 'a' AND t.Error <> 'b'
) b
ON a.Group = b.Group
WHERE b.Group IS NULL
And one more very specific to your example, but just for fun -
SELECT t.Group
FROM Table1 t
GROUP BY t.Group
HAVING MIN(t.Error) >= 'a' AND MAX(t.Error) <= 'b'
Replace Table1 with the name of your table in all of the above.

Get distinct records from table

I have data table giving following results:
number code
1 A
1 B
1 A
2 B
2 A
3 A
4 B
How do i find distinct number from table having code as A. The number should only have code A in table and not have B in table.
For the above table: My answer would be 3. As it has only code A.
If you only want A, one method is aggregation:
select t.number
from t
group by t.number
having min(code) = 'A' and max(code) = 'A';
SELECT DISTINCT a.number
FROM TableName a
WHERE a.Code = 'A'
AND NOT EXISTS (Select 1
FROM TableName b
WHERE a.number = b.number
AND b.Code = 'B')

How to find doubles in master-child table?

I need help with a query to find doubles. Let met explain the situation by example:
tableA (the master table) has a key field keyA with these values :
keyA
1
2
3
etc
tableB (the client table) has a foreign key field keyA and a value field, fieldB
keyA fieldB
1 a
1 b
2 a
2 b
3 a
3 c
4 a
4 b
4 c
etc
So, the values for fieldB in child table tableB are:
for tableA.keyA = 1 are: a and b
for tableA.keyA = 2 are: a and b
for tableA.keyA = 3 are: a and c
for tableA.keyA = 4 are: a, b and c
Now, given a value for keyA I need to find all records in tableA that have matching records in tableB for the field fieldB.
For example, if I search with keyA = 1 then
tableA.keyA = 2 is OK because both have same tableB.fieldB (a and b versus a and b)
tableA.keyA = 3 is not OK because both have not same tableB.fieldB (a and b versus a and c)
tableA.keyA = 4 is not OK because both have not same tableB.fieldB (a and b versus a, b and c)
I need a query that can give me this result. I hope someone can help me with this or can point me into the right direction.
Try this simple query , hope this will solve your problem
DECLARE #vkey int = 1
;WITH cte_test AS (
SELECT keyA,(SELECT ','+fieldb FROM tableB t1 WHERE t1.keyA = t.keyA FOR XML path('')) AS rslt
from tableB t
GROUP BY t.keyA)
SELECT t2.*
FROM cte_test t1
INNER JOIN cte_test t2 ON t1.[rslt] = t2.[rslt] AND t2.[keyA] <> t1.[keyA]
WHERE t1.[keyA] = #vkey
If there is no other item have the same combination , then there is no records in the result, otherwise it will return the matched items.
Assuming there are no duplicates, you can do this with a self-join and aggregation:
select c.keyA, c2.keyA
from (select c.*, count(*) over (partition by keyA) as numBs
from clientTable c
) c join
(select c.*, count(*) over (partition by keyA) as numBs
from clientTable c
) c2
on c2.fieldB = c.fieldB and
c2.keyA <> c.keyA and
c.keyA = 1 -- or whatever key you want to check
where c.numBs = c2.numBs
group by c.keyA, c2.keyA, c.numBs, c2.numBs
having count(*) = c.numBs;
The idea is to count the number of fieldB values for each keyA. These need to be equal (where c.numBs = c2.numBs) and to check that all match (having count(*) = c.numBs).

Select on records based on two column criterias

I would like to do an SQL query to select from the following table:
id type num
1 a 3
1 b 4
2 a 5
2 c 6
In the case where they have the same 'id' and be type 'a or b', so the result would look something like this:
id type num
1 a 3
1 b 4
Any one has any idea how that can be accomplished?
SELECT table1.*
FROM table1,
(
SELECT COUNT(*) as cnt, id
FROM (
SELECT *
FROM table1
WHERE type = 'a' OR type = 'b'
) sub1
GROUP BY id
HAVING cnt > 1
)sub2
WHERE table1.id = sub2.id
Tested here: http://sqlfiddle.com/#!2/4a031/1 seems to work fine.
Method 1:
select a.*
from some_table t
join some_table a on a.id = t.id and a.type = 'a'
join some_table b on b.id = t.id and b.type = 'b'
Method 2:
select *
from some_table t
where exists ( select *
from some_table x
where x.id = t.id
and x.type = 'a'
)
and exists ( select *
from some_table x
where x.id = t.id
and x.type = 'b'
)
The first technique offers the possibilities of duplicate rows in the results set, depending on the cardinality of id and type. The latter is guaranteed to provide a proper subset of the table.
Either query, assuming you have reasonable indices defined on the table should provide pretty equivalent performance.