Update TableA values based on Values from TableB (multiple options) - sql-server

I have Two tables:
TableA
+************************************+
|Col1 | code | Country | Value2 |
+************************************+
|Field1 | IN | INDIA | NA |
|Field2 | CA | CANADA | NA |
|Field3 | US | USA | NA |
+************************************+
TableB
+***************************+
|Field1 | Field2 | Field3 |
+***************************+
|1 | 4 | IN |
|2 | 5 | CA |
|3 | 6 | - |
+***************************+
I am trying to update column Field3 in TableB, Based on values from Column Country in TableA
That is: If Field3 in TableB has Value IN then it should get updated to India
or If Filed3 has Value CA it should get updated to Canada
and in the third case if no matching value is present then it should get update to "NA" or "NotSpecified"
So far I have tried updating TableB using a INNER JOIN:
UPDATE TableB SET TableB.Field3 = TableA.Country
FROM TableB INNER JOIN TableA ON TableB.Field3 = TableA.Code
I am really struggling update table based on multiple IF statements? Should I use CASE?
Any help or suggestions would be much appreciated.

Use a LEFT JOIN with an ISNULL.
UPDATE TableB SET
Field3 = ISNULL(TableA.Country, 'NA')
FROM
TableB
LEFT JOIN TableA ON TableB.Field3 = TableA.Code
Using a LEFT JOIN won't force all TableB records to join against a TableA record, and the ISNULL will set a default value in case the Code doesn't exist on TableA.

Related

maintain distinct results with table join

I have a relatively simple query.
SELECT DISTINCT
tA.id AS 'id'
//as pointed out, I could just select tB.value without the case here
,CASE WHEN tB.udf_id IN ('1')
THEN tB.value
END AS 'side'
FROM tableA tA
INNER JOIN tableB tB ON tA.id = tB.id
WHERE tB.udf_id IN ('1')
tableA
|id| date |
|--|----------|
|1 | 1/1/2023 |
|2 | 1/2/2023 |
|3 | 1/3/2023 |
tableB
|id|udf_id| value |
|--|------|---------|
|1 | 1 | right |
|1 | 2 | active |
|2 | 1 | left |
|2 | 2 | NULL |
|3 | 3 | right |
|3 | 3 | pending |
This will give me 1 row per "id" because of the WHERE clause.
Result Output
|id| value |
|--|---------|
|1 | right |
|2 | left |
|3 | right |
However, I now want to add another condition to what data gets returned.
I only want to return results;
tB.value is not NULL when tB.udf_id=2
(pseudocode, I know this doesn't work this way)
So the new result output would look the same but drop id=2 because tb.value=NULLwhen tb.udf_id=2.
New Result Output
|id| value |
|--|---------|
|1 | right |
|3 | right |
I'm struggling on how to do this. Just adding another udf_id value creates multiple rows of results instead of the one, which I don't want. And I don't believe I can express my codition in the WHERE clause like that.
My assumption is that I need to do some sort of subquery?
Below code will check for udf_id = '2' without "joining" an extra set of records
SELECT DISTINCT
tA.id AS 'id'
//as pointed out, I could just select tB.value without the case here
,CASE WHEN tB.udf_id IN ('1')
THEN tB.value
END AS 'side'
FROM tableA tA
INNER JOIN tableB tB ON tA.id = tB.id
WHERE tB.udf_id IN ('1')
-- This will check for non NULL udf_id = '2' value
AND EXISTS( SELECT * FROM tableB AS ID2 WHERE tA.id = ID2.id AND udf_id = '2' AND value IS NOT NULL )

SQL (SSMS) join all records from one table and second table but exclude 'duplicates' from second

I'm having an issue where I went all records in Table B and any non matching records in Table A but it's bringing back the matching records in Table A. There is another left join to an additional table which is brought in for reference only.
I'm using SSMS v18.
So ID will be on Table A and Table B. There will be multiple records of this ID on A and B but I don't want the duplicate records if date/time and ID is the same in Table A and in Table B.
e.g. - I've simplified the query I'm using below.
Select
a.id
a.datetime
a.emp_id
c.team_id
From
table_a as a
Left Join
table_b as b On a.id = b.id
And a.datetime <> b.datetime
Left Join
table_c On a.emp_id = c.emp_id
As there isn't NULLs I don't think I can use that. I don't believe a full outer join will return what I need.
Is there a method is solve this? A union query solution will not work as Table A and Table B do not have the same columns/column names.
Please let me know if more information is required.
EDIT - Additional
Apologies but now there's been a change of requirement where I now need to remove the matching records rather than remove just the duplicates. Is there a way around this?
Additional - Data Examples
Table A:
+----+------------------+--------+
| Id | Datetime | emp_id |
+----+------------------+--------+
| 1 | 20/04/2021 10:30 | a |
| 1 | 20/04/2021 11:15 | a |
| 2 | 21/04/2021 12:10 | b |
| 2 | 21/04/2021 13:20 | b |
| 2 | 22/04/2021 15:30 | c |
| 3 | 23/04/2021 09:45 | d |
| 4 | 23/04/2021 14:35 | e |
+----+------------------+--------+
Table B:
+----+------------------+-------------+
| Id | Datetime | other_field |
+----+------------------+-------------+
| 1 | 20/04/2021 10:30 | x |
| 2 | 21/04/2021 13:20 | y |
| 4 | 23/04/2021 14:35 | z |
+----+------------------+-------------+
Desired Output:
+----+------------------+--------+---------+
| Id | Datetime | emp_id | team_id |
+----+------------------+--------+---------+
| 1 | 20/04/2021 11:15 | a | team_01 |
| 2 | 21/04/2021 12:10 | b | team_02 |
| 2 | 22/04/2021 15:30 | c | team_01 |
| 3 | 23/04/2021 09:45 | d | team_02 |
+----+------------------+--------+---------+
So the duplicate ID & Datetime in Table B does not show in final output (regardless of any other fields)
You seem to need a right join instead of a left join. A left join will bring back all rows in table A, and all rows in table B which match the condition which you provided. You seem to want all in table B, which requires a right join.
I know some developers who have an aversion to right joins, if you feel that way, you can simply switch the order of the tables in your query to have table B listed first, left join to table A. I feel that the first solution is the easier one, though you need to be comfortable with it.
Here are my solutions, listed in the order in which I mentioned above.
Select
a.id
,a.datetime
,a.emp_id
,c.team_id
From
table_a as a
RIGHT Join -- here is my change
table_b as b On a.id = b.id
And a.datetime <> b.datetime
Left Join
table_c On a.emp_id = c.emp_id;
/*solution II*/
Select
a.id
,a.datetime
,a.emp_id
,c.team_id
From
table_b as b
Left Join
table_a as a On a.id = b.id
And a.datetime <> b.datetime
Left Join
table_c On a.emp_id = c.emp_id;
/*Updated solution, based on the comments (requirements seem to have changed)*/
Select
a.id
,a.datetime
,a.emp_id
,c.team_id
From
table_b as b
Left Join
table_a as a On a.id = b.id
Left Join
table_c On a.emp_id = c.emp_id
WHERE (a.datetime <> b.datetime OR b.datetime IS NULL);
Explanation of the updated solution: there was nothing to take into account the rows which would not match, hence the OR in the join
Please see Microsoft documentation on joins below.
https://learn.microsoft.com/en-us/sql/relational-databases/performance/joins?view=sql-server-ver15#:~:text=Joins%20indicate%20how%20SQL%20Server,be%20used%20for%20the%20join.

How could I update multiple columns in Oracle with same id?

I am new in Oracle SQL and I am trying to make an update of a table with the next context:
I have a table A:
+---------+---------+---------+----------+
| ColumnA | name | ColumnC | Column H |
+---------+---------+---------+----------+
| 1 | Harry | null | null |
| 2 | Harry | null | null |
| 3 | Harry | null | null |
+---------+---------+---------+----------+
And a table B:
+---------+---------+---------+
| name | ColumnE | ColumnF |
+---------+---------+---------+
| Harry | a | d |
| Ron | b | e |
| Hermione| c | f |
+---------+---------+---------+
And I want to update the table A so that the result will be the next:
+---------+---------+---------+----------+
| ColumnA | name | ColumnC | Column H |
+---------+---------+---------+----------+
| 1 | Harry | a | d |
| 2 | Harry | a | d |
| 3 | Harry | a | d |
+---------+---------+---------+----------+
How could I do it?
merge into tableA a
using tableB b
on (a.name=b.name)
when matched then update set
columnC = b.columnE,
columnH = b.columnF
create table tableA (columnC varchar2(20), columnH varchar2(20), name varchar2(20), columnA number);
create table tableB (columnE varchar2(20), columnF varchar2(20), name varchar2(20));
insert into tableA values (null, null,'Harry',1);
insert into tableA values (null, null,'Harry',3);
insert into tableA values (null, null,'Harry',3);
insert into tableB values ('a', 'd','Harry');
insert into tableB values ('b', 'e','Ron');
insert into tableB values ('c', 'f','Hermione');
select * from tableA;
merge into tableA a
using tableB b
on (a.name=b.name)
when matched then update set
columnC = b.columnE,
columnH = b.columnF;
select * from tableA;
I got no error
UPDATE tableA t1
SET (ColumnC, ColumnH) = (SELECT t2.ColumnE, t2.ColumnF
FROM table2 t2
WHERE t1.name = t2.name)
WHERE EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.name = t2.name)
This should work. You can refer to this answer for more info:
Oracle SQL: Update a table with data from another table
I think you can use below query and update your table A.
Update all rows with 'a' and 'd';
update table A
set (columnC , columnh ) = (SELECT COLUMNE,COLUMNF
FROM TABLE B
where b.name =a.name);
Alternatively you can also use:
UPDATE (SELECT T2.COLUMNE COLE,
T2.COLUMNF COLF,
T1.COLUMNC COLC,
T1.COLUMNH COLH
FROM tableB T2,
tableA T1
WHERE T1.NAME = T2.NAME)
SET COLC = COLE,
COLH = COLF ;
and Output is :
+---------+---------+---------+----------+
| ColumnA | name | ColumnC | Column H |
+---------+---------+---------+----------+
| 1 | Harry | a | d |
| 2 | Harry | a | d |
| 3 | Harry | a | d |
+---------+---------+---------+----------+

How to count the the data of specific two columns of different table in PostgreSQL?

I have two tables exactly having same column name but having different data or values. Now I want to count the total number of data of first column of table_1 union data of first column of table_2. How to do this?
____________________ ________________________
| Table_1 | | Table_2 |
---------+---------- -----------+------------|
|arsc_lvl| Dist Name| | arsc_lvl | Dist_Name |
---------+---------- -----------+------------|
|1 | Banke | | 5 | Bara |
|5 | Banke | | 7 | Bara |
|6 | Bara | | 9 | Bara |
---------+----------+ -----------+------------+
select count ("arsc_lvl")
from "Table_1", "Table_2"
where
"arsc_lvl"<=10
this also did not provide me what I want.
I even used joins like this:
SELECT *
FROM [MyTable] Table_1
INNER JOIN [MyOtherTable] Table_2
ON Table_1."arsc_lv" = Table_2."arsc_lv"
It too didn't work for me.
I got stuck here, please help.
You want to count the number of rows in the union, so translate it into SQL:
SELECT count(*)
FROM (SELECT * FROM table_1
UNION
SELECT * FROM table_2) u;
If you don't want to eliminate duplicates, use UNION ALL instead of UNION.
select count(*),arsc_lvl from table1,table2;
You can try this It worked for me.
select count(*) from tbl1 join tbl2 on tbl1.id = tbl2.id;

Split table in two tables plus a link table

I have a table with three columns with double values, but no double rows. Now I want to split this table in two table with unique values and a link table. I think the Problem gets clearer when I Show you example tables:
Original:
| ID | Column_1 | Column_2 | Column_3 |
|----|----------|----------|----------|
| 1 | A | 123 | A1 |
| 2 | A | 123 | A2 |
| 3 | B | 234 | A2 |
| 4 | C | 456 | A1 |
Table_1
| ID | Column_1 | Column_2 |
|----|----------|----------|
| 1 | A | 123 |
| 2 | B | 234 |
| 3 | C | 456 |
Table_2
| ID | Column_3 |
|----|----------|
| 1 | A1 |
| 2 | A2 |
Link-Table
| ID | fk1 | fk2 |
|----|-----|-----|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 3 | 1 |
Table_1 I created like this:
INSERT INTO Table_1(Column_1, Column_2)
SELECT DISTINCT Column_1, Column_2 FROM Original
WHERE Original.Column_1 NOT IN (SELECT Column_1 FROM Table_1)
Table_2 I created in the same way.
The question now is, how to create the Link-Table?
The original table does grow continuesly, so only new entries should be added.
Do I have to use a Cursor, or is there a better way?
SOLUTION:
MERGE Link_Table AS LT
USING (SELECT DISTINCT T1.ID AS T1ID, T2.ID AS T2ID FROM Original AS O
INNER JOIN Table_1 AS T1 ON T1.Column_1 = O.Column_1
INNER JOIN Table_2 AS T2 ON T2.Column_3 = O.Column_3) AS U
ON LT.fk1 = U.T1ID
WHEN NOT MATCHED THEN
INSERT (fk1, fk2)
VALUES (U.T1ID, U.T2ID);
You can JOIN all 3 tables to get proper data for link table:
--INSERT INTO [Link-Table]
SELECT t1.ID,
t2.ID
FROM Original o
INNER JOIN Table_1 t1
ON t1.Column_1 = o.Column_1
INNER JOIN Table_2 t2
ON t2.Column_3 = o.Column_3
If your original table will grow, then you need to use MERGE to update/insert new data.
You have to inner join your Original,Table_1 and Table_2 to get the desired result.
Try like this, Its similar to gofr1 post.
DECLARE #orginal TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
,Column_3 VARCHAR(10)
)
DECLARE #Table_1 TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
)
DECLARE #Table_2 TABLE (
ID INT
,Column_3 VARCHAR(10)
)
Insert into #orginal values
(1,'A',123,'A1')
,(2,'A',123,'A2')
,(3,'B',234,'A2')
,(4,'C',456,'A1')
Insert into #Table_1 values
(1,'A',123)
,(2,'B',234)
,(3,'C',456)
Insert into #Table_2 values
(1,'A1')
,(2,'A2')
SELECT O.ID
,T1.ID
,T2.ID
FROM #orginal O
INNER JOIN #Table_1 T1 ON T1.Column_1 = O.Column_1
INNER JOIN #Table_2 T2 ON T2.Column_3 = O.Column_3

Resources