SQL merge statement with Joins - sql

I am trying to use a merge statement for upsert operation. I want to do something like below where I join the both target and source table to the Student table for a unique key that only exists in the student table. Just to keep in mind, I cannot join StudentID. There could be a duplicate in my code. I need to join the schoolID for uniqueness.
Merge into GuardianTo gto inner join StudentTo sto on gto.fkStudentId = sto.StudentID
Using (Select * from GuardianFrom gfrom inner join StudentFrom sfrom on gfrom.fkStudentId = sfrom.StudentID) from
ON gto.guardianId = from.guardianId and sto.SchoolID = from.SchoolID
When....
I need to join the target guardianTo table with studentTo table to get the unique key of SchoolID. and match this ID with From tables. I know that this could be done in a separate insert and update statement (not merge), but is there a way to do something like the above using merge statement?

If you are using MSSQL you can do a merge like the code below. You need to supply a list of column names to use from your source query and then update/insert the columns you need in your target table (GuardianTo).
Merge into GuardianTo gto
Using (Select * from GuardianFrom gfrom inner join StudentFrom sfrom on gfrom.fkStudentId = sfrom.StudentID ) AS source (<column names in GuardianFrom, Studentfrom go here> )
ON (gto.guardianId = source.guardianId and gto.SchoolID = source.SchoolID)
WHEN MATCHED THEN
UPDATE SET <column in GuardianTo>= source.<column from source above> /* add any additional columns to update here*/
WHEN NOT MATCHED THEN
INSERT (guardianId, SchoolID, StudentID /* add any additional columns to insert here*/)
VALUES (source.guardianId, source.SchoolID, source.StudentID /* add any additional columns from the source to insert here*/);

Related

Update CarValue column in destination based on source carValue

I have a destination table that needs to be updated with the values that match from my source. I would like my destination to have the same CarValue as my source table would have. I have came up with the query above to pull the records that do not match my source and I want to use this to update my destination table values. Please provide examples of how to accomplish this.
select
s.*
,t.*
from SourceTable as s
full outer join DestinationTable as t
on s.CarNo = t.CarNo and s.CarName = t.CarName
where s.CarValue <> t.Carvalue
You do not need a full join. So:
update t
set carvalue = s.carvalue
from DestinationTable t join
SourceTable s
on s.CarNo = t.CarNo and s.CarName = t.CarName
where s.CarValue <> t.Carvalue;
This does not update non-matching rows. My guess is that you want to leave those alone. If you do want to update them, use a left join and remove the where clause.
You can update by using the current join statement
update t
set t.CarValue = s.Carvalue
from DestinationTable as t
full outer join SourceTable as s
on s.CarNo = t.CarNo and s.CarName = t.CarName
where s.Carvalue<>coalesce(t.Carvalue,'xYz');
coalesce() is added for the probability of existence of null values within the DestinationTable, assuming a car value never would be xYz.
Demo

Need to use join in the where clause of a update statement in sql?

I need to join multiple tables in the where clause of a update statement. Precisely there are two tables with master slave relationship. I need to update a row in the master table but need to check for the foreign key entry in its slave table.
Table A
TableId,Empid,EmpName,EmpAdd
Table B
TableId,Empid,DeptId,DeptName
When a row is inserted in Table A, Table B also has an insert. Say I need to update EmpAdd of TableA and this shall be based on the columns Empid,DeptId,DeptName from the two tables. Therefore I guess I need to join two tables.
what about checking for EXISTS instead of JOINs:
UPDATE tbl_master m
SET m.some_column = some_value
WHERE m.masteID = updatetable_id
AND EXISTS (SELECT * FROM tbl_slave s WHERE s.masterID = m.masterID)

How to create a table with multiple columns

Struggling with a create table statement which is based on this select into statement below:
#MaxAPDRefundAmount money = 13.00
...
select pkd.*, pd.ProviderReference, per.FirstName, per.Surname, #MaxAPDRefundAmount [MaxAPDRefundAmount],commission.Type [Commission] into #StagedData from CTE_PackageData pkd
inner join J2H.dbo.Package pk on pkd.Reference = pk.Reference
inner join J2H.dbo.Product pd on pk.PackageId = pd.PackageId
inner join J2H.dbo.FlightReservation fr on pd.ProductId = fr.ProductId
and fr.FlightBoundID = 1
inner join J2H.dbo.ProductPerson pp on pd.ProductId = pp.ProductID
and pp.StatusId < 7
inner join J2H.dbo.Flight f on fr.FlightId = f.FlightID
inner join J2H.dbo.Person per on pk.PackageId = per.PackageId
and per.PersonId = pp.PersonId
inner join J2H.dbo.PersonType pt on per.PersonTypeId = pt.PersonTypeID
We are changing a select into to just normal insert and select, so need a create table (we are going to create a temp (hash tag table) and not declaring a variable table. Also there is a pkd.* at the start as well so I am confused in knowing which fields to include in the create table. Do I include all the fields in the select statement into the create statement?
Update:
So virtually I know I need to include the data types below but I can just do:
create table #StagedData
(
pkd.*,
pd.ProviderReference,
per.FirstName,
per.Surname,
#MaxAPDRefundAmount [MaxAPDRefundAmount],
commission
)
"Do I include all the fields in the select statement into the create statement?" Well, that depends, if you need them, than yes, if not than no. It's impossible for us to say whether you need them... If you're running this exact query as insert, than yes.
As for the create statement, you can run the query you have, but replace into #StagedData with something like into TEMP_StagedData. In management studio you can let sql server build the create query for you: right-click the newly created TEMP_StagedData table in the object explorer (remember to refresh), script Table as, CREATE To and select New Query Editor Window.
The documentation of the CREATE TABLE statement is pretty straightforward.
No. Clearly, you cannot use pkd.* in a create table statement.
What you can do is run your old SELECT INTO statement as a straight SELECT (remove the INTO #stagedata) part, and look at the columns that get returned by the SELECT.
Then write a CREATE TABLE statement that includes those columns.
To create a table from a SELECT without inserting data, add a WHERE clause that never returns True.
Like this:
SELECT * INTO #TempTable FROM Table WHERE 1=0
Once the table with the columns for your SELECT, you can add additional columns with ALTER TABLE.
ALTER TABLE #TempTable ALL ExtraColumn INT
Then do your INSERT/SELECT.

Delete Query using Inner joins on more than two tables

I want to delete records from a table using inner joins on more than two tables. Say if I have tables A,B,C,D with A's pk shared in all other mentioned tables. Then how to write a delete query to delete records from table D using inner joins on table B and A since the conditions are fetched from these two tables. I need this query from DB2 perspective. I am not using IN clause or EXISTS because of their limitations.
From your description, I take the schema as:
A(pk_A, col1, col2, ...)
B(pk_B, fk_A, col1, col2, ..., foreign key fk_A references A(pk_A))
C(pk_c, fk_A, col1, col2, ..., foreign key fk_A references A(pk_A))
D(pk_d, fk_A, col1, col2, ..., foreign key fk_A references A(pk_A))
As you say DB2 will allow only 1000 rows to be deleted if IN clause is used. I don't know about DB2, but Oracle allows only 1000 manual values inside the IN clause. There is not such limit on subquery results in Oracle at least. EXISTS should not be a problem as any database, including Oracle and DB2 checks only for existence of rows, be it one or a million.
There are three scenarios on deleting data from table D:
You want to delete data from table D in which fk_A (naturally) refers to a record in table A using column A.pk_A:
DELETE FROM d
WHERE EXISTS (
SELECT 1
FROM a
WHERE a.pk_A = d.fk_A
);
You want to delete data from table D in which fk_A refers to a record in table A, and that record in table A is also referred to by column B.fk_A. We do not want to delete the data from D that is in A but not in B. We can write:
DELETE FROM d
WHERE EXISTS (
SELECT 1
FROM a
INNER JOIN b ON a.pk_A = b.fk_A
WHERE a.pk_A = d.fk_A
);
The third scenario is when we have to delete data in table D that refers to a record in table A, and that record in A is also referred by columns B.fk_A and table C.fk_A. We want to delete only that data from table D which is common in all the four tables - A, B, C and D. We can write:
DELETE FROM d
WHERE EXISTS (
SELECT 1
FROM a
INNER JOIN b ON a.pk_A = b.fk_A
INNER JOIN c ON a.pk_A = c.fk_A
WHERE a.pk_A = d.fk_A
);
Depending upon your requirement you can incorporate one of these queries.
Note that "=" operator would return an error if the subquery retrieves more than one line. Also, I don't know if DB2 supports ANY or ALL keywords, hence I used a simple but powerful EXISTS keyword which performs faster than IN, ANY and ALL.
Also, you can observe here that the subqueries inside the EXISTS clause use "SELECT 1", not "SELECT a.pk" or some other column. This is because EXISTS, in any database, looks for only existence of rows, not for any particular values inside the columns.
Based on 'Using SQL to delete rows from a table using INNER JOIN to another table'
The key is that you specify the name of the table to be deleted from
as the SELECT. So, the JOIN and WHERE do the selection and limiting,
while the DELETE does the deleting. You're not limited to just one
table, though. If you have a many-to-many relationship (for instance,
Magazines and Subscribers, joined by a Subscription) and you're
removing a Subscriber, you need to remove any potential records from
the join model as well.
DELETE subscribers
FROM subscribers INNER JOIN subscriptions
ON subscribers.id = subscriptions.subscriber_id
INNER JOIN magazines
ON subscriptions.magazine_id = magazines.id
WHERE subscribers.name='Wes';
delete from D
where fk = (select d.fk from D d,A a,B b where a.pk = b.fk and b.fk = d.fk )
this should work

copying column from table

I need to copy a column from one table to another. The problem is matching the values with the right rows.
INSERT INTO DestinationTable (money_owed)
SELECT "credit"
FROM SourceTable
How do I search through the destination table and compare another field to see if it's the same one in the source table?
You need to join the two tables on the matching condition.
Something like this
UPDATE
DestinationTable
SET
DestinationTable.money_owed = SourceTable.Credit
FROM
DestinationTable
INNER JOIN SourceTable
ON DestinationTable.Field2 = SourceTable.Field2
do an Update from:
UPDATE
destination
SET
destination.money_owed = source.Credit
FROM
destination
INNER JOIN
source
ON
source.id = destination.id