SQL join 2 rows into 1 with conditions - sql

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.

Related

How to join two tables and show source?

How to join values from two tables ...
Table_1:
ID | Value
----------
10 | Dog
27 | Cat
Table_2:
ID | Value
----------
27 | Cat
My SQL... (Microsoft Access 2016)
SELECT ID, VALUE , "YES" AS Table_1, NULL AS Table_2
FROM Table_1
UNION
SELECT ID, VALUE, NULL AS Table_1, "YES" AS Table_2
FROM Table_2
...returns this result:
ID | Value | Table_1 | Table_2
------------------------------
10 | Dog | YES |
27 | Cat | YES |
27 | Cat | | YES
But I would like to get a result like this:
ID | Value | Table_1 | Table_2
------------------------------
10 | Dog | YES |
27 | Cat | YES | YES
You can use aggregation and union all:
select id, value, max(table_1) as table_1, max(table_2) as table_2
from (select ID, VALUE , "YES" AS Table_1, NULL AS Table_2
from Table_1
union
select ID, VALUE, NULL AS Table_1, "YES" AS Table_2
from Table_2
) t
group by id, value;
The alternative in SQL is a FULL JOIN, but MS Access does not support full joins.
You can make a list of table1 + table2 values and then check if the values exists in table2 or 2 using simple jeft join.
select
base.*,
iif(isnull(t.value), null, 'YES') table1,
iif(isnull(t2.value), null, 'YES') table2
from
(
Select value from Table_1 -- if you have duplicate values add groupby here
union
select value from Table_2
) base -- Make a collection of values from table1 and 2
left join Table_1 T on base.value = T.value
left join Table_2 T2 on base.value = T2.value;
Not sure if you can open above query in design view but the query should work in access. to be design view friendly, you need to make a query object for the base and then you can simply do left joins and iifs

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.

Retrieve data from the same table if subId is an id of other item

I have a table that contains some records, and I would like to get only these records that have subID to a record with the id of the subID value. If there is no row with the id then do not take this row to the table. Also do not duplicate values if already in the table and do not look at rows that have subId 0 because they are as parents we can say so they do not have childs
----------------------------
ID | SUBID | NAME | ENABLED |
30 | 0 | EXP1 | TRUE |
55 | 30 | EXP2 | TRUE |
70 | 30 | EXP3 | FALSE |
99 | 42 | EXP4 | FALSE |
232| 0 | EXP5 | TRUE |
65 | 232 | EXP6 | TRUE |
-----------------------------
Expected result:
----------------------------
ID | SUBID | NAME | ENABLED |
30 | 0 | EXP1 | TRUE |
55 | 30 | EXP2 | TRUE |
70 | 30 | EXP3 | FALSE |
232| 0 | EXP5 | TRUE |
65 | 232 | EXP6 | TRUE |
-----------------------------
If someone could help me how to write this SQL statement in a good way I will be grateful.
You can use 'Exists':
SELECT T1.* FROM TEST T1
WHERE EXISTS (SELECT T2.ID FROM TEST T2 WHERE T2.ID = T1.SUBID)
OR EXISTS (SELECT T3.SUBID FROM TEST T3 WHERE T3.SUBID = T1.ID)
Test Result:
DB<>Fiddle
How about a union
select a.*
from have a
inner join have b
on a.subid=b.id
union
select b.*
from have a
inner join have b
on a.subid=b.id;
This can be actually pretty complicated, as you've evidently found out. I'd suggest a CTE and a UNION with your JOINs and aliases. It also looks like it'll need all that in a subquery to do a DISTINCT, too.
Without testing this, I'd image it looks something like this:
WITH MAIN AS (
SELECT ID, SUBID, NAME
FROM TABLE t
WHERE ENABLED = TRUE
)
SELECT DISTINCT ID, NAME
FROM (
SELECT ID, NAME
FROM MAIN
UNION
SELECT t.ID, t.NAME
FROM MAIN
LEFT JOIN TABLE t on MAIN.SUBID = t.ID
WHERE MAIN.SUBID <> 0
)
The outer select might not be needed if you do a distinct on each of the inner queries, but without testing it, I can't say for sure. I'd guess it would only DISTINCT the two lists separately, which isn't your intended result.
I'm kind of hoping someone else can come up with a less complicated version. I'd also suggest you do some more research on CTEs, UNIONs, aliases, and see if you can make this simpler on your own. But this should get you in the right direction.
BTW, I used a CTE (WITH MAIN AS) so that the query wouldn't be duplicated.
Try this script-
SELECT YT.*
FROM your_table YT
INNER JOIN (
SELECT DISTINCT(B.ID)
FROM your_table A
LEFT JOIN your_table B
ON A.SUBID = B.ID
WHERE B.ID IS NOT NULL
) C ON YT.ID = C.ID OR YT.SUBID = C.ID
By my understanding of what you are trying to do, you simply want:
SELECT * FROM myTable t1
WHERE SubID = 0
OR EXISTS (SELECT NULL FROM myTable t2 WHERE t2.id = t1.SubID)

Access VBA: Select only multiple values

Say, I have a table that looks like this:
ID | PNo | MM | CP |
---|-----|------|----|
1 | 13 | True | 4 |
2 | 92 | True | 3 |
3 | 1 | True | 3 |
4 | 13 | False| 2 |
5 | 13 | True | 3 |
6 | 1 | True | 3 |
I want to go through all PNos and compare all rows with that PNo and only select those that have different values in field MM.
My plan was to create a table with the distinct values of PNo, iterate through that table by using the usual record set and write an SQL query for each PNo.
Now my problem is the construction of the SQL query.
I can select all rows with Table.PNo = rs("PNo") but I have no idea how to formulate the query to catch the rows with varying values.
You can use a subquery:
Select *
From YourTable
Where PNo IN
(Select T.PNo
From YourTable
Group By PNo, MM
Having Count(*) = 2)
I think this should work.
This will create a cartesian product on y our PNo field. i.e. Every record connected to every record (but just on that PNo).
SELECT *
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.PNo = T2.PNo
You'll end up with 9 instances of PNo 13, 4 of 1 and 1 of 92. Now we just want to return the ones where MM is different, so add that to the WHERE clause.
SELECT *
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.PNo = T2.PNo
WHERE T1.MM <> T2.MM
ORDER BY T1.ID
This will return four records. PNo 1 and 92 will have vanished as the MM result was the same for those. ID number 4 will be returned twice as the MM value is different from that in ID 1 and ID 5.
To remove the duplicate value you could then use DISTINCT:
SELECT DISTINCT T1.ID, T1.PNo, T1.MM, T1.CP
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.PNo = T2.PNo
WHERE T1.MM <> T2.MM
ORDER BY T1.ID
Note: One of the differences between the answer given by #Jonathan and mine is that his query is updateable and mine isn't.
The following should do what you want:
SELECT * FROM MyTable WHERE PNo in
(SELECT t.PNo FROM MyTable t
INNER join MyTable f
ON t.PNo = f.PNo
WHERE t.MM = true and f.MM = false)
The inner join ensures that only those PNos that have both MM false and MM true are included.

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

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