Oracle SQL Join query results - sql

I have the following two tables
Table 1: SOURCE_SYSTEM
ID CODE Source ID Source Name
123 111 Monster Dice.com
456 111 Dice ABC COMPANY
456 888 Ticv A2 systems
4566 999 MOnster hgtt solutions
789 222 Monster ABC COMPANY
985 222 Dice Dice.com
Table 2: TARGET_SYSTEM
RECORDID AI CL ID Source Name Op Code
123 111 Dice.com Secondary
456 111 ABC COMPANY Primary
789 222 ABC COMPANY Secondary
985 222 Dice.com Primary
We have a process which runs gets the data from source table and loads into target table. But in here the process has a rule saying the primary row in Target should has the Source Name from Source table where Source ID = ‘Monster’.
Here the following entry in Target is correct
RECORDID AI CL ID Source Name Op Code
123 111 Dice.com Secondary
456 111 ABC COMPANY Primary
But the following is wrong, has Primary Source name is Dice.com which should be ABC COMPANY.
RECORDID AI CL ID Source Name Op Code
789 222 ABC COMPANY Secondary
985 222 Dice.com Primary
So I need a query which can identify all the rows in Target which the same issue.

Why are the two rows for AI_CL_ID = 111 correct? They are wrong according to your specification, because recorded = 123 corresponds to 'Monster' but it has 'Secondary' in your target_system table.
To find all the rows in the target_system table with the wrong op_code you can use the following query. Assumptions: The pair (id, code) is unique target_system; there are no NULLs in any column; the source_name in target_system is always correct (it matches the source_name in source_system when matched by id and code); the marker 'Primary' is special, but there may be other markers besides 'Secondary'.
The solution does not include the rows from "with" to the closing " ) " after the definition of target_system; the WITH clause is used to generate test data within the query itself, but in real life you should simply start with select t.id, ... and hit your base tables or views.
with
source_system ( id, code, source_id, source_name) as (
select 123, 111, 'Monster', 'Dice.com' from dual union all
select 456, 111, 'Dice' , 'ABC COMPANY' from dual union all
select 456, 888, 'Ticv' , 'A2 systems' from dual union all
select 4566, 999, 'MOnster', 'hgtt solutions' from dual union all
select 789, 222, 'Monster', 'ABC COMPANY' from dual union all
select 985, 222, 'Dice' , 'Dice.com' from dual
),
target_system ( recordid, ai_cl_id, source_name, op_code ) AS (
select 123, 111, 'Dice.com' , 'Secondary' from dual union all
select 456, 111, 'ABC COMPANY', 'Primary' from dual union all
select 789, 222, 'ABC COMPANY', 'Secondary' from dual union all
select 985, 222, 'Dice.com' , 'Primary' from dual
)
select t.recordid, t.ai_cl_id, t.source_name, t.op_code
from target_system t inner join source_system s
on t.recordid = s.id and t.ai_cl_id = s.code
where ( s.source_id = 'Monster' and t.op_code != 'Primary' )
or
( s.source_id != 'Monster' and t.op_code = 'Primary' )
order by ai_cl_id, recordid
;
Output (with your inputs; the output is different from that in your post since what you have in your post is wrong, as I explained).
RECORDID AI_CL_ID SOURCE_NAME OP_CODE
---------- ---------- ----------- ---------
123 111 Dice.com Secondary
456 111 ABC COMPANY Primary
789 222 ABC COMPANY Secondary
985 222 Dice.com Primary

Related

SQL needed to find if a property exists in multiple counties

I need some SQL to determine if a property exists in multiple counties.
I have a list of distinct property ids and county ids, but I'm not sure how to find if the property exists in more than one county.
TABLE: PROPERTIES
PROPERTYID
COUNTYID
12345
1111
12345
1112
23456
1111
34567
2222
In this example, I need some sql that will only show me property 12345 since it exists in both county 1111 and 1112.
I'm sure there is some easy SQL, but I can't figure it out.
Sample data:
SQL> with properties (propertyid, countryid) as
2 (select 12345, 1111 from dual union all
3 select 12345, 1112 from dual union all
4 select 23456, 1111 from dual union all
5 select 34567, 2222 from dual
6 )
Query:
7 select propertyid
8 from properties
9 group by propertyid
10 having count(distinct countryid) > 1;
PROPERTYID
----------
12345
SQL>

Find the discrepancies in sql

I am using Oracle database.
Suppose that I have a table called "MYTABLE" and it contains the tuples of every dog in the world and the owners:
NAME
OWNER_ID
Aaron
81
Aaron
281
Aaron
404
Michael
81
Michael
281
Michael
404
Brendan
281
Brendan
81
Micon
404
Micon
81
Tyson
404
For DEFAULT every DOG must be associated with 3 different owners, in this case the owners are identified by an id: 81, 281 and 404.
How can I know the dogs that are not associated with 3 rows in the table?
I would like this output:
Brendan
Micon
Tyson
These 3 dogs do not have 3 rows in the given table. They are not associated exactly with owners 81, 281 and 404.
To find out which name is not associated with all three of the 81, 281 and 404 owner_id, you can use conditional aggregation in a HAVING clause:
SELECT name
FROM table_name
GROUP BY name
HAVING COUNT(DISTINCT CASE WHEN OWNER_ID IN (81, 281, 404) THEN OWNER_ID END) < 3
Which, for the sample data:
CREATE TABLE table_name (NAME, OWNER_ID) AS
SELECT 'Aaron', 81 FROM DUAL UNION ALL
SELECT 'Aaron', 281 FROM DUAL UNION ALL
SELECT 'Aaron', 404 FROM DUAL UNION ALL
SELECT 'Michael', 81 FROM DUAL UNION ALL
SELECT 'Michael', 281 FROM DUAL UNION ALL
SELECT 'Michael', 404 FROM DUAL UNION ALL
SELECT 'Brendan', 281 FROM DUAL UNION ALL
SELECT 'Brendan', 81 FROM DUAL UNION ALL
SELECT 'Brendan', 123 FROM DUAL UNION ALL -- Different owner_id
SELECT 'Micon', 404 FROM DUAL UNION ALL
SELECT 'Micon', 81 FROM DUAL UNION ALL
SELECT 'Micon', 81 FROM DUAL UNION ALL -- Duplicate
SELECT 'Tyson', 404 FROM DUAL
Outputs:
NAME
Brendan
Micon
Tyson
If you just want the name where they do not have three different owner_id (any owner_id) then:
SELECT name
FROM table_name
GROUP BY name
HAVING COUNT(DISTINCT OWNER_ID) < 3
Which, for the same sample data, would output:
NAME
Micon
Tyson
If you just want the name where there are not three owner_id (either unique or not) then:
SELECT name
FROM table_name
GROUP BY name
HAVING COUNT(OWNER_ID) < 3
Which, for the same sample data, outputs:
NAME
Tyson
db<>fiddle here
You can GROUP BY the NAME and the use COUNT(*) to exclude al that have less than 3 owners
SELECT "NAME" FROM tab1 GROUP BY "NAME" HAVING COUNT(*) < 3
| NAME |
| :------ |
| Brendan |
| Micon |
| Tyson |
db<>fiddle here

SQL to deal with Duplicate Record Management

I have an Oracle database application which creates lists of duplicate records for people to review, with users being able to deduplcate, leave or mark the record as being different to each other (legitimate duplicates). I need to report on the number of records in this queue.
The challenge is the legitimate duplicates as these are held on a second table of data and are held as two rows for each pair marked up (a≠b). However as duplicate groups can contain a number of duplicates, and records could be marked up a being a legitimate duplicate more than once I need to somehow remove the records that are marked up as legitimate duplicates from all the other records in a candidate group. Hopefully that is making sense.
So a simplified view of the two tables would be:
Duplicate Candidates
Group Key
Dup-1 123
Dup-1 234
Dup-2 123
Dup-2 345
Dup-2 567
Dup-3 234
Dup-3 567
Dup-4 123
Dup-4 567
Dup-4 235
Legitimate Duplicates:
Group Key
A 123
A 234
B 345
B 456
C 123
C 567
D 123
D 235
The results I would like to return from this example would be:
Duplicate Candidates
Group Key
Dup-2 123
Dup-2 345
Dup-2 567
Dup-3 234
Dup-3 567
Dup-4 567
Dup-4 235
Dup-1 would not be returned as Legitimate Group A has both Keys, Dup-2 would be returned as while both Key 123 and 345 are marked up as legitimate duplicates they are not currently marked as different to each other. Dup-3 again should be returned as the two records are not marked as legitimate duplicates. Finally the row Dup-4 123 should not be returned as it is marked up as legitimate duplicate to both of the other records in the group, but they should be returned as they are not marked a legitimate duplicates of each other.
I really need to carry this out in SQL as I will feed this data into a reporting solution (Business Objects or Tablaux) directly. Is anyone able to give me a nudge in the right direction on this. Unfortunately our software is completely black box so I cannot reverse engineer this from the code that deals with this for users.
Using Exists. Return the Candidate if at least one other member of the group is not in any group of Legitimates where the tested Candidate is a member too.
select *
from Candidates c
where exists (
select 1
from Candidates c2
where c2.Grp = c.Grp and c2.Key <> c.Key
and not exists (
select 1
from Legitimate l
where l.Key = c.Key
and exists (
select 1
from Legitimate l2
where l2.Grp = l.Grp and l2.Key = c2.Key
)
)
)
order by Grp, Key
Generate pairs of duplicate candidates using:
SELECT "GROUP",
PRIOR key AS key1,
key AS key2
FROM duplicate_candidates
WHERE LEVEL = 2
CONNECT BY PRIOR "GROUP" = "GROUP"
AND PRIOR key < key
and pairs of legitimate candidates using:
SELECT MIN(key), MAX(key)
FROM legitimate_duplicates
GROUP BY "GROUP"
Then you can find the duplicate pairs that are not in the legitimate candidate pairs and UNPIVOT the pairs and find the DISTINCT keys. In a single query:
SELECT DISTINCT
"GROUP",
key
FROM (
SELECT "GROUP",
PRIOR key AS key1,
key AS key2
FROM duplicate_candidates
WHERE LEVEL = 2
AND (PRIOR key, key) NOT IN (SELECT MIN(key), MAX(key)
FROM legitimate_duplicates
GROUP BY "GROUP")
CONNECT BY PRIOR "GROUP" = "GROUP"
AND PRIOR key < key
)
UNPIVOT (key FOR id IN (key1, key2))
Which, for the sample data:
CREATE TABLE duplicate_candidates ("GROUP", Key) AS
SELECT 'Dup-1', 123 FROM DUAL UNION ALL
SELECT 'Dup-1', 234 FROM DUAL UNION ALL
SELECT 'Dup-2', 123 FROM DUAL UNION ALL
SELECT 'Dup-2', 345 FROM DUAL UNION ALL
SELECT 'Dup-2', 567 FROM DUAL UNION ALL
SELECT 'Dup-3', 234 FROM DUAL UNION ALL
SELECT 'Dup-3', 567 FROM DUAL UNION ALL
SELECT 'Dup-4', 123 FROM DUAL UNION ALL
SELECT 'Dup-4', 567 FROM DUAL UNION ALL
SELECT 'Dup-4', 235 FROM DUAL;
CREATE TABLE Legitimate_Duplicates ("GROUP", Key) AS
SELECT 'A', 123 FROM DUAL UNION ALL
SELECT 'A', 234 FROM DUAL UNION ALL
SELECT 'B', 345 FROM DUAL UNION ALL
SELECT 'B', 456 FROM DUAL UNION ALL
SELECT 'C', 123 FROM DUAL UNION ALL
SELECT 'C', 567 FROM DUAL UNION ALL
SELECT 'D', 123 FROM DUAL UNION ALL
SELECT 'D', 235 FROM DUAL;
Note: GROUP is a reserved word and cannot be an unquoted identifier. It would be better to use a different name for the columns but you can use a quoted identifier (but its not best practice).
Outputs:
GROUP
KEY
Dup-2
123
Dup-2
345
Dup-2
567
Dup-3
234
Dup-3
567
Dup-4
235
Dup-4
567
db<>fiddle here

SQL output formatted in one line per entry

I have a problem getting data displayed right, directly from Oracle SQL.
I have 2 tables. Medarb with entries meda_id and init and contacts with meda_id, cont_type and number.
The cont_type can be either 'MT' or 'MA'
what I get is:
init type number
aaaa MT 11111111
aaaa MA 22222222
bbbb MT 33333333
bbbb MA 44444444 and so on.
what I wanted was: (each person on one line)
aaaa mt 11111111 ma 22222222
bbbb mt 33333333 ma 44444444 and so on.
Is that possible?
The SQL is like this:
select distinct medarb.init, contacts.cont_type, contacts.number
from contacts
inner join medarb on medarb.meda_id = contacts.meda_id
order by medarb.init
Kind regards
Per
Aggregation usually helps in such situations.
SQL> with test (init, type, cnumber) as
2 (select 'aaaa', 'MT', 111 from dual union all
3 select 'aaaa', 'MA', 222 from dual union all
4 select 'bbbb', 'MT', 333 from dual union all
5 select 'bbbb', 'MA', 444 from dual
6 )
7 select init,
8 'MT' mttype,
9 max(case when type = 'MT' then cnumber end) cnum_mt,
10 'MA' matype,
11 max(case when type = 'MA' then cnumber end) cnum_ma
12 from test
13 group by init
14 order by init;
INIT MT CNUM_MT MA CNUM_MA
---- -- ---------- -- ----------
aaaa MT 111 MA 222
bbbb MT 333 MA 444
SQL>
what is the unique column combination for this join, is it init and type columns?
You can try using Oracle Pivot functions.
https://blogs.oracle.com/sql/how-to-convert-rows-to-columns-and-back-again-with-sql-aka-pivot-and-unpivot
thanks

Oracle get latest value based on parent/child partition

I have a table named "customer" that looks like this:
ID ALPHA BRAVO CHARLIE DATE
-------------------------------------------------
1 111 222 333 02/02/2019
2 333 444 555 11/11/2019
3 666 555 777 12/12/2019
4 777 888 999 05/05/2020
5 100 101 110 12/25/2020
and I need to get the following output:
ID ALPHA BRAVO CHARLIE DATE NEW_COL ROW_NUM
-----------------------------------------------------------------------
1 111 222 333 02/02/2019 333 4
2 333 444 555 11/11/2019 333 3
3 666 555 777 12/12/2019 333 2
4 777 888 999 05/05/2020 333 1
5 100 101 110 12/25/2020 010 1
The ALPHA, BRAVO, and CHARLIE columns represent customer IDs. A given customer can have multiple IDs in the system. Records 1-4 represent IDs belonging to the same customer, let's say John. As per the table, John has 12 IDs, and his latest ID is 999. Record 5 represents another customer, let's say Jane. Jane has three IDs, and her last ID is 110.
The purpose of the ROW_NUM column is to get the last CUSTOMER.CHARLIE value. The idea is to use the first CHARLIE value as the partition. Basically, the goal is to get one parent:many children mapping. In this case, the ID 333 should be tied to 555, 777, and 999.
Here is the DDL/DML:
CREATE TABLE CUSTOMER
(ID NUMBER(20) NOT NULL,
ALPHA NUMBER(20) NOT NULL,
BRAVO NUMBER(20) NOT NULL,
CHARLIE NUMBER(20) NOT NULL,
CREATEDDATE DATE
);
INSERT INTO CUSTOMER
VALUES
(1, 111, 222, 333, to_date('02-FEB-19','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(2, 333, 444, 555, to_date('11-NOV-19','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(3, 666, 555, 777, to_date('12-DEC-19','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(4, 777, 888, 999, to_date('05-MAY-20','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(5, 100, 101, 110, to_date('25-DEC-20','DD-MON-RR'));
COMMIT;
I have tried the following query, but it fails to populate the partition column correctly:
WITH
charlies
AS
(SELECT DISTINCT charlie
FROM customer),
mult_customers
AS
(SELECT c.*, c.charlie AS NEW_COL
FROM customer c
UNION
SELECT c.*,
CASE WHEN c.alpha = e.charlie THEN c.alpha ELSE c.bravo END AS NEW_COL
FROM customer c
JOIN charlies e ON e.charlie = c.alpha OR e.charlie = c.bravo),
ranked
AS
(SELECT mc.*,
ROW_NUMBER ()
OVER (PARTITION BY NEW_COL ORDER BY createddate DESC) AS row_num
FROM mult_customers mc)
SELECT *
FROM ranked
ORDER BY ID;
Thanks for any help provided.
You task is known as connected components. I wrote about 7-8 years ago solution for this and even pl/sql package: http://orasql.org/2017/09/29/connected-components/
This PL/SQL solution is much more effective then pure SQL solutions: http://orasql.org/2014/02/28/straight-sql-vs-sql-and-plsql/
Let me know if you need help with adopting it for your task.