Get distinct records from table - sql

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

Related

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

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.

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.

SQL: group function is not allowed here

I have this query
SELECT * FROM TABLEA A
INNER JOIN TABLEB B ON A.ID = B.ID AND COUNT(B.*) < 4
WHERE A.STATUS = 0
In tablea, ID will have 2 row of data(2 entries), but in tableb the same ID will have upto 4 rows of data. I am trying to get the ID that has less than 4 rows of data in tableb and display that result.
so if ID 12345 is having only 2 rows of data in tableb, display that result. IF ID 98765 has 4 rows of data in tableb, ignore this entry.
But when i try the above query it says "group function is not allowed here". Please can someone help.
You can not use count() without goup by or having clause. In your case you need having
SELECT * FROM TABLEA A
INNER JOIN TABLEB B ON A.ID = B.ID
WHERE A.STATUS = 0
having COUNT(B.*) < 4
see the sqlfiddle
write it the way you would say it...
"I am trying to get the ID that has less than 4 rows of data in tableb and display that result"
SELECT * FROM TABLEA a
JOIN TABLEB b ON b.ID = a.ID
WHERE A.STATUS = 0
and (Select count(*) from TABLEB
where id = a.Id) < 4
it's not clear, but if you also only want Ids which have 2 or more rows in TableA:
SELECT * FROM TABLEA a
JOIN TABLEB b ON b.ID = a.ID
WHERE A.STATUS = 0
and (Select count(*) from TABLEB
where id = a.Id) < 4
and (Select count(*) from TABLEA
where id = a.Id) > 1

select sql query to merge results

I have a table old_data and a table new_data. I want to write a select statement that gives me
Rows in old_data stay there
New rows in new_data get added to old_data
unique key is id so rows with id in new_data should update existing ones in old_data
I need to write a select statement that would give me old_data updated with new data and new data added to it.
Example:
Table a:
id count
1 2
2 19
3 4
Table b:
id count
2 22
5 7
I need a SELECT statement that gives me
id count
1 2
2 22
3 4
5 7
Based on your desired results:
SELECT
*
FROM
[TableB] AS B
UNION ALL
SELECT
*
FROM
[TableA] AS A
WHERE
A.id NOT IN (SELECT id FROM [TableB])
I think this would work pretty neatly with COALESCE:
SELECT a.id, COALESCE(b.count, a.count)
FROM a
FULL OUTER JOIN b
ON a.id = b.id
Note - if your RDBMS does not contain COALESCE, you can write out the function using CASE as follows:
SELECT a.id,
CASE WHEN b.count IS NULL THEN a.count
ELSE b.count END AS count
FROM ...
You can write a FULL OUTER JOIN as follows:
SELECT *
FROM a
LEFT JOIN b
ON a.id = b.id
UNION ALL
SELECT *
FROM b
LEFT a
ON b.id = a.id
You have to use UPSERT to update old data and add new data in Old_data table and select all rows from Old_data. Check following and let me know what you think about this query
UPDATE [old_data]
SET [count] = B.[count]
FROM [old_data] AS A
INNER JOIN [new_Data] AS B
ON A.[id] = B.[id]
INSERT INTO [old_data]
([id]
,[count])
SELECT A.[id]
,A.[count]
FROM [new_Data] AS A
LEFT JOIN [old_data] AS B
ON A.[id] = B.[id]
WHERE B.[id] IS NULL
SELECT *
FROM [old_data]