ORACLE - remove from result set if two or more "same" records found - sql

ID | NAME | REFERENCE | STATUS
-------------------------------
1 | name1 | 123 | 0
2 | name1 | 123 | 1
3 | name2 | 111 | 0
4 | name3 | 222 | 0
5 | name5 | 555 | 1
Let's say I have this table TABLE1. I need a select statement that will only find records with STATUS=0, but if "same" record exists with STATUS=1 (like those records with ID 1 and 2)
So, query must find only third and fourth record.

Based on your suggested results, I am reading your question as "find only records with status = 0 where the same name/reference combination doesn't have a record with status = 1".
One way you can do this is with a not exists clause:
select t.*
from table t
where status = 0 and
not exists (select 1
from table t2
where t2.name = t.name and
t2.reference = t.reference and
t2.status = 1
);

Try this query out:
SELECT A.*
FROM TABLE1 A
LEFT JOIN TABLE1 B ON
A.ID = B.ID AND
A.NAME = B.NAME AND
A.REFERENCE = B.REFERENCE AND
B.STATUS = 1
WHERE A.STATUS = 0
AND B.REFERENCE IS NULL
The NULL check on B.REFERENCE in the WHERE clause basically ensures that there was no matching record found in the LEFT JOIN (you could just use B.ID or B.NAME also).

MINUS can be used to get the value with Status both 0 but not 1.
SELECT ID, Name, Reference, Status
FROM Table1
WHERE (Name, Reference) IN (SELECT Name, Reference
FROM Table1
WHERE Status = 0
MINUS
SELECT Name, Reference
FROM Table1
WHERE Status = 1)

SELECT * FROM TABLE WHERE NAME NOT IN
(
SELECT NAME FROM
TABLE
GROUP BY NAME
HAVING COUNT(DISTINCT STATUS)>1
) AND STATUS='0';

Related

SQL join 2 rows into 1 with conditions

I have a table with updated and inserted values. So, most IDs have 2 rows, one for insert, other for update (there is an "operator" column which has value UPDATED or value INSERTED). Sample data:
operator | ID | row2 | row3
===========================
updated | 01 | | 231
===========================
inserted | 01 | abc | 123
===========================
updated | 02 | khj | 567
===========================
inserted | 02 | klo | 567
===========================
inserted | 03 | nmb | 900
My task is to join these 2 rows in 1 grouping them by their ID. But, all values have to be from the "update" row AND if there are some NULL values in the "update", they must be taken from the "insert" row.
Desired results:
ID | row2 | row3
==================
01 | abc | 231
==================
02 | khj | 567
==================
03 | nmb | 900
==================
The goal is to have all distinct IDs with the newest data.
Does anyone have any idea how to do this?
I have tried implementing the following logic, but it doesn't return me the newest data:
SELECT
ID,
MAX(Field1) AS Field1,
MAX(Field2) AS Field2
FROM
table_name
GROUP BY
ID;
You may try this -
Select
u.ID,
NVL(u.row2, i.row2),
NVL(u.row3, i.row3) -- and so on for more columns
from
(Select * from tableName where operator = 'updated') u,
(Select * from tableName where operator = 'inserted') i
where u.ID = i.ID;
If your table has data such that there isn't any record with 'updated', you would need LEFT OUTER JOIN, so you may use below query then -
Select
i.ID,
NVL(u.row2, i.row2),
NVL(u.row3, i.row3) -- and so on for more columns
from
(Select * from tableName where operator = 'updated') u,
(Select * from tableName where operator = 'inserted') i
where u.ID(+) = i.ID;
If I understand correctly, you want to select rows, with update first and then the insert if there is no update. So one method is:
select t.*
from table_name t
where t.operator = 'UPDATED' or
not exists (select 1
from table_name t2
where t2.id = t.id and t2.operator = 'UPDATED'
);
you can do it this way:
SELECT
a.*
FROM
table_name a
WHERE a.operator = 'UPDATED'
UNION ALL
SELECT
b.*
FROM
table_name b
WHERE b.operator = 'INSERTED'
AND b.ID NOT IN
(SELECT
c.ID
FROM
table_name c
WHERE c.operator = 'UPDATED'
AND c.ID = b.ID)
Note: If you want or need to remove duplicates, you can replace: UNION ALL with UNION,
graciously.

Sql want to get matching plus new records from tables

I am new to SQL queries, I have tables:
Table1:
Id | Flag
----+------
200 | 1
201 | 1
202 | 1
203 | 1
204 | 1
Table2:
Id | Flag
----+------
200 | 0
203 | 1
I want result like this:
Id | Flag
----+------
200 | 0
201 | 1
202 | 1
204 | 1
I have tried with left join but still I am not getting expected result.
It seems that you want a join where the Flag value from TableB is given priority over the value from TableA and where the Flag values do not match in both tables.
If that is the case, you could accomplish this with the use of a COALESCE() as well as a WHERE condition to remove items where the join fails and the matching Flag values):
SELECT a.ID,
COALESCE(b.Flag, a.Flag) Flag
FROM TableA a
LEFT JOIN TableB b
ON a.ID = b.ID
AND (b.Flag IS NULL OR a.Flag <> b.Flag)
Example
You can see an interactive working example here, which given your data outputs the expected values:
You seem to want all rows except for the ones with "1" in both flag columns. Then, if available you want the flag in table2.
If this is a correct interpretation:
select t1.id, coalesce(t2.flag, t1.flag)
from table1 t1 left join
table2 t2
on t1.id = t2.id
where t1.flag <> 1 or
(t2.flag is null or t2.flag <> 1)
Here is a db<>fiddle.

Join tables with same keys, second table has multiple values for key and rows of second table must have same column value

I have two tables with shared key and I'm trying to join them to filter data based on few conditions
tbl1
id | OutPutValue |
1 | 2019 |
2 | 2018 |
tbl2
object_id | status | type |
1 | 22 | a |
1 | 22 | c |
1 | 33 | b |
2 | 33 | c |
2 | 33 | c |
2 | 33 | c |
What I'm trying to get is : it must select all 'OutPutValue' from tbl1 where, in tbl2 column 'type' should be c, and column 'status' must have same value for all rows i.e. 33. Note that Primary key (id) of tbl1 is foreign key (object_id) in tbl2.
Select column from tbl1 if, All rows in tbl2 (id of tbl1 have multiple rows (based on object_id) in tbl2) have same status value i.e. 33 and Type should be 'c'.
OutPutValue | Type | status |
2018 | c | 33 |
I have tried with following solution, but it's not returning desired output :
SELECT a.OutPutValue FROM tbl1 a JOIN tbl2 b ON a.id = b.object_id WHERE b.Type =c
GROUP BY a.OutPutValue, b.status HAVING b.STATUS IN(33)
You can try using correlated subquery
DEMO
select distinct OutPutValue,type, status
from t2 a inner join t1 b on a.object_id=b.id
where type='c' and not exists
(select 1 from t2 a1 where a.object_id=a1.object_id and status<>33 and type='c')
OUTPUT:
OutPutValue type status
2018 c 33
Another solution could be the following :
SELECT T1.id, T1.outputvalue FROM tbl1 T1
JOIN (
SELECT tbl2.*, MAX(type), MAX(status)
FROM tbl2
GROUP BY object_id
HAVING
MIN(status) = MAX(status) AND
MIN(type) = MAX(type)
) T2 ON T1.id = T2.object_id
WHERE T2.type = 'c'
EDIT: I have updated my query to match a particular case which make it quite similar to another answer.
FIND A DEMO HERE
Try a join combined with an aggregation:
SELECT
t1.OutPutValue,
MAX(t2.type) AS type,
MAX(t2.status) AS status
FROM tbl1 t1
INNER JOIN tbl2 t2
ON t1.id = t2.object_id
GROUP BY
t1.id,
t1.OutPutValue
HAVING
MIN(t2.status) = MAX(t2.status) AND
MAX(t2.status) = 33 AND
MIN(t2.type) = MAX(t2.type) AND
MAX(t2.type) = 'c';

Select ALL records with fieldvalue1 if any records (with fieldvalue1) have fieldvalue3 have a specific value

I need to show all records for a specific value if ANY one of those records have another specific value. Essentially, if field3 = 'b', what is field1? Show all records with value of field1 regardless of their field3 value.
Record Number External Id Letter
1 123456 a
2 123456 b
3 123456 c
4 456852 t
5 456852 b
record 2 has a letter value of 'b' - so I want to look at externalid, which is 123456, now I want to pull all records for external id regardless if the other records have a letter value of 'b'
Use EXISTS and a correlated subquery:
SELECT *
FROM mytable t
WHERE
t.letter = 'b'
OR EXISTS (
SELECT 1
FROM mytable t1
WHERE
t1.record_number != t.record_number
AND t1.external_id = t.external_id
AND t1.letter = 'b'
)
Another option is to use a window function:
SELECT record_number, external_id, letter
FROM (
SELECT
t.*,
MAX(CASE WHEN letter = 'b' THEN 1 END) OVER(PARTITION BY external_id) mx
FROM mytable t
) x WHERE mx = 1
Demo on DB Fiddle:
record_number | external_id | letter
------------: | ----------: | :-----
1 | 123456 | a
2 | 123456 | b
3 | 123456 | c
4 | 456852 | t
5 | 456852 | b
Use exists, but don't worry about filtering in the outer query:
select t.*
from t
where exists (select 1
from t t2
where t2.external_id = t.external_id and t2.letter = 'b'
);
With an index on (external_id, letter), I would expect this to have very good performance.

TSQL - retrieve results from table A that contains exact data contained in table B

I have TableA (id bigint, name varchar) and TableB (name varchar) that contains the following data:
Table A: Table B: Results:
------------- --------- ---------------
| 1 | "A" | | "A" | | 1 | "A" |
| 1 | "B" | | "B" | | 1 | "B" |
| 2 | "A" | --------- | 4 | "A" |
| 3 | "B" | | 4 | "B" |
| 4 | "A" | ---------------
| 4 | "B" |
-------------
I want to return results from TableA that contains an EXACT match of what's in table B.
Using the 'IN' clause only retrieves back an occurrence.
Also, another example, if TableB has only "A", I want it to return back: 2-"A"
I understand your question but it is a tricky one as not exactly in line with the relational logic. You are looking for id's for which SELECT name FROM TableA WHERE id IN ... ORDER BY name; is identical to SELECT name FROM B order by name;.
Can you assume that A(id,name) is unique and B(name) is unique? Better said, are there constraints like that or can you set them up?
If yes, here is a solution:
1. Get rid of ids in A with rows not matching the rows in B
SELECT id, A.name FROM A WHERE id NOT IN
(SELECT id FROM A LEFT JOIN B ON A.name = B.name WHERE B.name IS NULL);
2. Count rows per each id (this is why the unique constraints are necessary)
SELECT id, COUNT(*) FROM
(
SELECT id, A.name FROM A WHERE id NOT IN
(SELECT id FROM A LEFT JOIN B ON A.name = B.name WHERE B.name IS NULL)
) t
GROUP BY id;
3. Only retain those that match the number of rows of B.
SELECT id, COUNT(*) FROM
(
SELECT id, A.name FROM A WHERE id NOT IN
(SELECT id FROM A LEFT JOIN B ON A.name = B.name WHERE B.name IS NULL)
) t
GROUP BY id
HAVING COUNT(*) = SELECT COUNT(*) FROM B;
This works in SQL Server
select * from TableA a
where
(select count(*) from TableB) = (select count(*) from TableA where id = a.id) and
(select count(*) from TableB) =
(
select count(*) from
(
select name from TableA where id = a.id
intersect
select name from TableB
) as b
)