one to many relationship query in oracle - sql

I am trying to query a number of tables that have records with a one to many relationship. The records I need are the myid values with the following criteria:
They have to have the attribute
firstcode with values of 1, 3, 8, 200. It can be any combination of these codes or all of them.
secondstuff is also related to the firstcode; each firstcode will have a secondstuff value. The secondstuff values I am interested in are X, Y, Z (there are many others).
The problem I am running into is sometimes the myid record comes back, and it has 4 of the firstcode values, but not all of the firstcode values have the correct secondstuff value. Here is my query:
Select MYID
from myidtable a
where myid in (select myid1
from dadtable b
join momtable c
on b.dadid=c.momdadid
join kidtable d
on c.momid = d.kidid
where d.firstcode in (1, 3,8, 200)
and c.secondstuff in ('X', 'Y’, 'Z')
and thedate > to_date('12/31/2020', 'MM/DD/YYYY')
)
So in some cases I get a record back that has for example:
Myid firstcode secondstuff
34 1 X
34 3 M
34 8 X
As you can see, firstcode 3 has a secondstuff of M, as such, myid =34 shouldn’t be returned. What I am looking for is something like the following:
Myid firstcode secondstuff
35 1 X
35 3 Z
35 8 X
In this case, all my first codes that were associated with the myid table have the correct secondstuff values. Please note, its fine if some of the first code values are not associated with the myid table; Any two firstcodes will suffice.

From the information provided it seems that there are 2 columns with same name in two different tables. You are filtering in kidtable and while displaying you are accessing column from a different table. Make sure that you filter secondstuff column from all the tables in which it is present.

Related

SQL command to remove groups of entries where all are equal (not merely DISTINCT)

i am so green in SQL that I don't even know how to properly phrase my question or look for an existing answer in stack overflow or anywhere else. Sorry!
Assume i have 3 columns. One is an ID and two data columns A and B. A single ID can have multiple entries. I like to remove all entries, where A and B are same for a given ID. Probably i give an example
ID
A
B
01
x
y
01
x
y
01
x
y
02
x
y
02
x
z
02
x
y
In this table I would like to remove all 3 entries that belong to ID 01 as A as well as B are all x and y, respectively. For ID 02, however, column B differs for the first and second entry. Therefore I like to keep ID 02. I hope this illustrates the idea sufficiently :-).
I am look for a 'scalable' solution, as I am not only looking at two data columns A and B, but actually 4 different columns.
Does anyone know how to set a proper filter in SQL to remove those entries according to my needs?
Many thanks.
Benjamin
As for this, it basically doesn't matter how many coumns you actually have, as long as they are identical
this can be used for an as joining basis for a DELETE
WITH CTE AS
(SELECT DISTINCT "ID", "A", "B" FROM tab1),
CTE2 AS (SELECT "ID", COUNT(*) count_ FROM CTE GROUP BY "ID" HAVING COUNT(*) >1)
SELECT "ID" FROM CTE2
| ID |
| -: |
| 2 |
db<>fiddle here

How to update a target table with Merge statement

I'm trying to update a column in target table using merge statement by joining target table with source tables and getting the following error.
I need to compare a offer_id, order_Date and Doc_receipt_date from TRADE table with offer_trade_by_date, offer_start_date, offer_end_date. Here I'm trying to verify the trade is done with in the time period. If TRADE is done in time then it's pass the check (i.e 'Y'). If TRADE is not done in time then it didn't pass the check (i.e 'N'). If we don't have any information to check the condition (i.e when DOCK_RECEIPT_DATE is NULL) then ('X'). To achieve this check I wrote below code and getting the following error.
ORA: 30926 unable to get a stable set of rows in the source table.
Check the data in my tables below.
TRADE / Target table
KEYID DPBL_OFFER ORD_DATE DOC_RECPT_DT TRADE_DATE_MET
1 107 30-SEP-17 01-JAN-17 X
2 107 22-SEP-17 NULL X
3 107 07-OCT-17 NULL X
4 107 24-NOV-17 28-NOV-17 X
5 106 24-AUG-17 11-SEP-17 X
6 105 11-JUN-17 NULL X
7 108 05-SEP-17 13-SEP-17 X
8 109 28-JUL-17 10-AUG-17 X
9 110 01-SEP-17 14-SEP-17 X
PROD_OFFER /Source table)
Offer_id Trade_by_Date
106 14-OCT-17
107 14-NOV-17
105 02-AUG-17
108 18-NOV-17
109 14-OCT-17
110 18-NOV-17
OFFER_START_END_V /Source Table 2)
Offer_id Offer_Period Offer_Start_Date Offer_End_Date
106 1 27-JUL-17 27-JUL-17
106 2 28-JUL-17 14-OCT-17
107 1 15-SEP-17 23-JAN-18
105 1 01-JUN-17 02-AUG-17
108 1 23-AUG-17 14-SEP-17
108 2 16-SEP-17 19-SEP-17
110 1 23-AUG-17 14-SEP-17
110 2 16-SEP-17 19-SEP-17
109 1 02-JUL-17 12-NOV-17
Here keyid in my target table is PK and DPBL_OFFER id is offer_id from target table and isn't FK.
Check below code
MERGE INTO TRADE TB
USING (
SELECT T1.KEYID, T1.DPBL_OFFER
, CASE WHEN T1.ORD_DATE >= T3.OFFER_START_DATE AND
T1.ORD_DATE <= T2.TRADE_BY_DATE AND
T1.COD_RECPT_DATE <= T3.OFFER_END_DATE
THEN 'Y'
WHEN T1.ORD_DATE < T3.OFFER_START_DATE AND
T1.ORD_DATE > T2.TRADE_BY_DATE AND
T1.COD_RECPT_DATE > T3.OFFER_END_DATE
THEN 'N'
ELSE 'X'
END AS TRADE_DATE_MET
FROM TRADE T1
JOIN PROD_OFFER T2
ON T1.DPBL_OFFER_ID = T2.OFFER_ID
JOIN OFFER_START_END_V T3
ON T1.DPBL_OFFER_ID = T3.OFFER_ID) JT
ON TB.KEYID = JT.KEYID
AND TB.DPBL_OFFER_ID = JT.OFFER_ID
WHEN MATCH THEN
UPDATE SET TB. TRADE_DATE_MET = JT.TRADE_DATE_MET;
Can some one help me to overcome this error.?
FYI:- I'm using Oracle 11g.
That error generally means that there is at least one row in the target table (at least one, there may be many) for which there are at least TWO different rows in the source table (or result of three-table join, in your case) satisfying the ON condition(s) in the MERGE statement - and for which the values used in the UPDATE clause are actually different.
In your case: for KEYID = 5, DPBL_OFFER is 106. This joins to one row in PROD_OFFER and two different rows in OFFER_START_END_V. And the TRADE_END_MET is different for the two resulting rows in the three-table join. (Or, if it is the same - let's say 'N' for both - for this KEYID, then perhaps for KEYID= 7, with DPBL_OFFER = 108, which also joins to two different rows in the last table, the resulting TRADE_END_MET is not the same in both rows.)
This kind of error is usually fatal, since it is in fact an error in logic, regardless of code (or even of language). That is, even if you express the problem in common language and you try to solve it with paper and pencil, you can't, because it is self contradictory.
It is similar to, but more complicated than: Target table has columns ID (primary key) and FLAG (currently null). Source has columns ID and flag. Target has one row (1, null). Source has two rows, (1, 'Y') and (1, 'N'). You want to use the source to update the flag in the target. Do you see why that doesn't make sense? This is exactly the kind of problem you are having.
Run the three-way join by itself (the "source table" for the MERGE) and inspect the TRADE_END_MET values for KEYID = 5 and 7 - you will likely find the problem.

google bigquery selecting rows with multiple values in repeating field

Lets say I have a schema:
key STRING NULLABLE
values INTEGER REPEATED
Now, please note that second column is a repeated field of integers,
Lets say the data is something like:
key:'abc'
values: 1 2 3 (3 separate values, same for below values)
key:'def'
values: 1 2 5
key:'ghi'
values: 1 6 9
And here I wish to find out keys which has values 1 and 2 ? Expecting 'abc' and 'def' as result set.
Looking for a query for this. I want an 'and' ('in' does not work here). I need those both values to be present for any key to return as result.
SELECT
key,
SUM(values = 1 or values = 2) WITHIN RECORD AS check
FROM yourtable
HAVING check = 2

Oracle: Select multiple values from a column while satisfying condition for some values

I have a column COL in a table which has integer values like: 1, 2, 3, 10, 11 ... and son on. Uniqueness in the table is created by an ID. Each ID can be associated with multiple COL values. For example
ID | COL
——————————
1 | 2
————+—————
1 | 3
————+—————
1 | 10
————+—————
is valid.
What I want to do is select only the COL values from the table that are greater than 3, AND (the problematic part) also select the value that is the MAX of 1, 2, and 3, if they exist at all. So in the table above, I would want to select values [3, 10] because 10 is greater than 3 and 3 = MAX(3, 2).
I know I can do this with two SQL statements, but it's sort of messy. Is there a way of doing it with one statement only?
SELECT col FROM table
WHERE
col > 3
UNION
SELECT MAX(col) FROM table
WHERE
col <= 3
This query does not assume you want the results per id, because you don't explicitely mention it.
I don't think you need pl/sql for this, SQL is enough.

Delete duplicates when the duplicates are not in the same column

Here is a sample of my data (n>3000) that ties two numbers together:
id a b
1 7028344 7181310
2 7030342 7030344
3 7030354 7030353
4 7030343 7030345
5 7030344 7030342
6 7030364 7008059
7 7030659 7066051
8 7030345 7030343
9 7031815 7045692
10 7032644 7102337
Now, the problem is that id=2 is a duplicate of id=5 and id=4 is a duplicate of id=8. So, when I tried to write if-then statements to map column a to column b, basically the numbers just get swapped. There are many cases like this in my full data.
So, my question is to identify the duplicate(s) and somehow delete one of the duplicates (either id=2 or id=5). And I preferably want to do this in Excel but I could work with SQL Server or SAS, too.
Thank you in advance. Please comment if my question is not clear.
What I want:
id a b
1 7028344 7181310
2 7030342 7030344
3 7030354 7030353
4 7030343 7030345
6 7030364 7008059
7 7030659 7066051
9 7031815 7045692
10 7032644 7102337
All sorts of ways to do this.
In SAS or SQL, this is simple (for SQL Server, the SQL portion should be identical or nearly so):
data have;
input id a b;
datalines;
1 7028344 7181310
2 7030342 7030344
3 7030354 7030353
4 7030343 7030345
5 7030344 7030342
6 7030364 7008059
7 7030659 7066051
8 7030345 7030343
9 7031815 7045692
10 7032644 7102337
;;;;
run;
proc sql undopolicy=none;
delete from have H where exists (
select 1 from have V where V.id < H.id
and (V.a=H.a and V.b=H.b) or (V.a=H.b and V.b=H.a)
);
quit;
The excel solution would require creating an additional column I believe with the concatenation of the two strings, in order (any order will do) and then a lookup to see if that is the first row with that value or not. I don't think you can do it without creating an additional column (or using VBA, which if you can use that will have a fairly simple solution as well).
Edit:
Actually, the excel solution IS possible without creating a new column (well, you need to put this formula somewhere, but without ANOTHER additional column).
=IF(OR(AND(COUNTIF(B$1:B1,B2),COUNTIF(C$1:C1,C2)),AND(COUNTIF(B$1:B1,C2),COUNTIF(C$1:C1,B2))),"DUPLICATE","")
Assuming ID is in A, B and C contain the values (and there is no header row). That formula goes in the second row (ie, B2/C2 values) and then is extended to further rows (so row 36 will have the arrays be B1:B35 and C1:C35 etc.). That puts DUPLICATE in the rows which are duplicates of something above and blank in rows that are unique.
I haven't tested this out but here is some food for thought, you could join the table against itself and get the ID's that have duplicates
SELECT
id, a, b
FROM
[myTable]
INNER JOIN ( SELECT id, a, b FROM [myTable] ) tbl2
ON [myTable].a = [tbl2].b
OR [myTable].b = tbl2.a