Sql want to get matching plus new records from tables - sql

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.

Related

SQL Join On Columns of Different Length

I'm trying to join two tables together in SQL where the columns contain a different number of unique entries.
When I use a full join the additional entries in the column joined on are missing.
The code I'm using is (in a SAS proc SQL):
proc sql;
create table table3 as
select table1.*, table2.*
from table1 full join table2
on table1.id = table2.id;
quit;
Visual example of problem (can't show actual tables as contain sensitive data)
Table 1
id | count1
1 | 2
2 | 3
3 | 2
Table 2
id | count2
1 | 4
2 | 5
3 | 6
4 | 2
Table 3
id | counta | countb
1 | 2 | 4
2 | 3 | 5
3 | 2 | 6
- | - | 2 <----- I want don't want the id column to be blank in this row
I hope I've explained my problem clearly enough, thanks in advance for your help.
The id from table 1 is blank because the row from table2 has no match in table 1. Try looking at the output from this query:
select coalesce(table1.id, table2.id) as id, table1.count1, table2.count2
from table1 full join table2
on table1.id = table2.id;
Coalesce works from left to right returning the first non null value (it can take more than 2 arguments). If the id in table 1 is null it uses the id from table 2 instead
I recommend also to alias all tables in queries, so I’d have written this:
SELECT
COALESCE(t1.id, t2.id) as id,
t1.count1,
t2.count2
FROM
table1 t1
FULL OUTER JOIN
table2 t2
ON
t1.id = t2.id;
Simply select coalesce(t1.id, t2.id), will return the first non-null id value.

Update a table based on a condition

I have a column Table1.Tradedate and another column Table2.SettlementDate.
Based on the comparison between these 2, I want to update a column in table 2
IF (Table1.TradeDate <= Table2.SettlementDate)
BEGIN
UPDATE Table2 SET Status='Y'
END
This is what I have tried but I know its wrong, since the table will obviously contain more than 1 records. So, I believe what I should do is
use a join on 2 tables based on some #id to pick a particular record
check the IF condition for that particular record
update the Status column in table2.
I hope my approach is correct but I am writing it incorrectly.
Table1:
SKacc | Name | TradeDate | Othercolumns....
1 | xxx | 01/07/2019 |
2 | xxx | 01/06/2019 |
Table2:
SKAcc | Name | SettlementDate | Status |Other Columns....
1 | xxx | 01/08/2019 | NULL |
2 | xxx | 01/08/2019 | NULL |
Try below
update t2 set Status = 'Y'
from table2 t2
join table1 t1 on t1.id = t2.id
where t1.tradeDate <= t2.settlementDate
Try joining the two tables with the related column and then update the table you want to update with the value. Using inner join in the example but can change depending on the usecase
UPDATE Table2
SET Status = 'Y'
FROM Table2
INNER JOIN Table1 ON Table1.id = Table2.table1_id
WHERE Table1.TradeDate <= Table2.SettlementDate
I would not recommend a JOIN for this purpose. Instead:
update table2
set Status = 'Y'
where exists (select 1
from table1 t1
where t1.id = t2.id and
t1.tradeDate <= t2.settlementDate
);
The reason I recommend this version is because you have not specified that id is unique in table1. In general, you only want to use JOIN in UPDATE when you can guarantee that there is only one matching row.

How to do an outer join with full result between two tables

I have two tables:
TABLE1
id_attr
-------
1
2
3
TABLE2
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
As a result I want a table that show:
RESULT
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
10 | 3 | NULL
So I want the row with id=10 and id_attr=3 also when id_Attr=3 is missing in TABLE2 (and I know that because I have a NULL value (or something else) in the val column of RESULT.
NB: I could have others ids in table2. For example, after insert this row on table2: {11,1,A}, as RESULT I want:
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
10 | 3 | NULL
11 | 1 | A
11 | 2 | NULL
11 | 3 | NULL
So, for every id, I want always the match with all id_attr.
Your specific example only has one id, so you can use the following:
select t2.id, t2.id_attr, t2.val
from table2 t2
union all
select 10, t1.id_attr, NULL
from table1 t1
where not exists (select 1 from table2 t2 where t2.id_attr = t1.id_attr);
EDIT:
You can get all combinations of attributes and ids in the following way. Use a cross join to create all the rows you want and then a left join to bring in the data you want:
select i.id, t1.id_attr, t2.val
from (select distinct id from table2) i cross join
table1 t1 left join
table2 t2
on t2.id = i.id and t2.id_attr = t1.id_attr;
It sounds like you want to do just an outer join on id_attr instead of id.
select * from table2 t2
left outer join table1 t1 on t2.id_attr = t1.id_attr;

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

MySQL: Typecasting NULL to 0

Let us suppose the following table (e.g. a result of several inner join statements):
id | column_1 | column_2
------------------------
1 | 1 |
2 | 2 | 2
3 | | 3
Which you could for example get from the following statement:
select a.id, t1.column_1, t2.column_2
from a
left join t1 on a.id = t1.id
left join t2 on a.id = t2.id
Now, if i'd like to sum up t1.column_1 and t2.column_2 as follows
select
a.id,
t1.column_1,
t2.column_2,
(t1.column_1 + t2.column_2) as cumulated
from a
left join t1 on a.id = t1.id
left join t2 on a.id = t2.id
The result will look as follows:
id | column_1 | column_2 | cumulated
------------------------------------
1 | 1 | NULL | NULL
2 | 2 | 2 | 4
3 | NULL | 3 | NULL
My question basically is: is there a way to typecast NULL into 0 in order to do some math?
I have tried CONVERT(t1.column_1, SIGNED) and CAST(t1.column_1 as SIGNED), but a NULL stays a NULL.
Use IFNULL(column, 0) to convert the column value to zero.
Alternatively, the COALESCE function will do the same thing: COALESCE(column, 0), except
COALESCE is ANSI-compliant, IFNULL is not
COALESCE takes an arbitrary number of columns/values and will return the first non-null value passed to it.