How to convert this Access inner join query into SQL Server? - sql

I want to write an update statement that compares the new code table to the old code by joining on the MASTER_ID. Then If the NEW_CODE.CODE = 1234 AND OLD_CODE.CODE_ID is not in the CODE_MAPPING table then SET NEW_CODE.CODE_ID = OLD_CODE.CODE_ID AND NEW_CODE.SEQ_NO = OLD_CODE.SEQ_NO. This is what I have so far but it does not seem to correctly update if I get a null value in the CODE_ID column. I think I need to do a self join but nothing I do seems to work any help would be greatly appreciated.
I have three tables with the following data:
**NEW_CODE**
MASTER_ID SEQ_NO CODE_ID CODE
100 0 XX 1234
200 0 5555
300 0 XX 1234
300 0 XX 1234
**OLD_CODE**
MASTER_ID SEQ_NO CODE_ID
100 1 D1
200 1 A1
300 1
300 2 Z1
**CODE_MAPPING**
CODE_ID
A1
B1
C1
D1
UPDATE STATEMENT:
UPDATE NEW
SET SEQ_NO = OLD.SEQ_NO,
CODE_ID = OLD.CODE_ID
FROM NEW_CODE NEW
INNER JOIN OLD_CODE OLD
ON NEW.MASTER_ID = OLD.MASTER_ID
LEFT JOIN CODE_MAPPING CM
ON OLD.CODE_ID = CM.CODE_ID
WHERE NEW.CODE = 1234
AND CM.CODE_ID IS NULL
The updated table should look like this:
**UPDATED NEW_CODE**
MASTER_ID SEQ_NO CODE_ID CODE
100 0 XX 1234
200 0 5555
300 1 1234
300 2 Z1 1234
So the only thing that should update is the two rows with a MASTER_ID of 300. But for some reason I am getting the following result instead:
**CURRENT RESULT NEW_CODE**
MASTER_ID SEQ_NO CODE_ID CODE
100 0 XX 1234
200 0 5555
300 2 Z1 1234
300 2 Z1 1234

As you have two rows with same identifier (MASTER_ID), tsql is needed instead of a simple statement.
Precondition for rows to update:
Every row in NEW could be matched to one row in OLD and reverse.
We need a criteria to identify updated rows in NEW. I use SEQ_NO=0 here.
a unique key for each row in OLD and NEW is needed. Your example data don't contain a unique key. So I add one to OLD and one to NEW. It can be dropped in the end.
alter table OLD add IDX int IDENTITY(1,1)
alter table NEW add IDX int IDENTITY(1,1)
declare a cursor on OLD (only rows to be updated)
DECLARE #IdxOld int
DECLARE #IdxNew int
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT idx
FROM OLD
WHERE NOT EXISTS (SELECT * FROM CODE_MAPPING CM
WHERE OLD.CODE_ID = CM.CODE_ID)
do foreach on OLD and update NEW
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #IdxId
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #IdxNew = Min(Idx) -- min to get only one row
FROM NEW
INNER JOIN OLD_CODE OLD ON NEW.MASTER_ID = OLD.MASTER_ID
WHERE NEW.CODE = 1234
AND OLD.IDX = #IdxOld -- current row from old
AND SEQ_NO=0 -- row not updated yet
UPDATE NEW
SET SEQ_NO = OLD.SEQ_NO,
CODE_ID = OLD.CODE_ID
FROM NEW_CODE NEW
INNER JOIN OLD_CODE OLD ON NEW.MASTER_ID = OLD.MASTER_ID
WHERE NEW.IDX = #IdxNew
AND OLD.IDX = #IdxOld
FETCH NEXT FROM MY_CURSOR INTO #IdxId
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
Drop IDX columns
alter table OLD drop COLUMN IDX
alter table NEW drop COLUMN IDX

The aliases do not match in the update . . . that is new is not new_code. Try this:
UPDATE NC
SET SEQ_NO = OC.SEQ_NO,
CODE_ID = OC.CODE_ID
FROM NEW_CODE NC INNER JOIN
OLD_CODE OC
ON NC.MASTER_ID = OC.MASTER_ID LEFT JOIN
CODE_MAPPING CM
ON OC.CODE_ID = CM.CODE_ID
WHERE NC.CODE = 1234 AND CM.CODE_ID IS NULL;

Related

Compare data between two tables and update one table data

I have two tables and i need to compare data and update one table records. Please let me know how this can be done, i am trying to not use merge. This is the scenario
Proj1 Table
This is the first table where data needs to be synchronized
ID Text
1 R1
2 R2
3 R3
Proj2 Table
This is the table where data updates are taking place
ID Text Active
3 R1 1
4 R3 1
5 R4 1
After a compare is done on Text field between both these tables result should be similar to below. We are syncing data in Proj2 to similar to Proj1.
ID Text Active
3 R1 1 (Ignore as it exists in both tables)
4 R3 1 (Ignore as it exists in both tables)
5 R4 0 (Update to inactive as it does not exist Proj1 table)
6 R2 1 (Insert as it does not exist in Proj2 table)
If you really can't use MERGE, you can simply split it into an update and an insert query :
INSERT INTO #Proj2(Text, Active)
SELECT Text,1 FROM #Proj1 p1
WHERE NOT EXISTS(
SELECT *
FROM #Proj2 p2
WHERE p2.Text = p1.Text
);
UPDATE
p2
SET
p2.Active = CASE WHEN p1.id is null THEN 0 ELSE 1 END
FROM
#Proj2 p2
LEFT JOIN
#Proj1 p1
ON
p2.Text = p1.Text;
This assumes that your ID is an auto-increment.
Thsi is pretty much like Zak's new answer, but with the 2 update queries merged.
merge [Proj2Table] target
using ( select [id], [text] from [Proj1Table] ) source ([id], [text] )
on target.[id] = source.[id]
when not matched by source
then update
set target.[Active] = 0
when not matched by target
then insert
([id], [text] )
values( source.[id], source.[text] )
-- update records in table 2 that cannot be found in table 1
update P2
set P2.[Active] = 0
from [Proj2Table] as P2
left join [Proj1TAble] as P1 on P1.[text] = P2.[text]
where P1.[id] is null;
-- update records in table 2 that can be found in table 1
update P2
set P2.[Active] = 1
from [Proj2Table] as P2
join [Proj1TAble] as P1 on P1.[text] = P2.[text];
-- insert missing records from table 1 into table 2 with active bit set
insert into [Proj2Table] ([id] , [text] , [active] )
select [id] , [text] , [active] = 1
from [Proj1Table] as P1
where not exists (select 1 from [Proj2Table] as P2 where P2.[text] = P1.[text])
;
Not sure if [id] column should match or is a pk/identity/sequence
Another approach would be to use a cursor, if you really don't want to use MERGE
-declare a cursor on the first table and scroll the row, then for each row selct the corresponding row in the second table and ac accordingly, if found/not found...
not the best performance-related suggestion though...

Update a range of rows in a table where the condition is in another table

example:
table 1
invoice line article price
1 1 pen 10
1 2 mouse 11
1 3 paper 15
2 1 ... 25
2 2 ... 80
2 3 ...
2 4 ....
table 2
invoice date
1 2014-01-03 00:00:00.0000
2 2014-05-12 00:00:00.0000
3 2014-06-17 00:00:00.0000
how can I update the price only on the rows where the invoice date is for example the month of november
I know that i must use a join but i'm already joining this table for doing other stuff in the same query:
UPDATE invoicelines
SET invoicelines.netprice = ART.price
FROM invoicelines IL INNER JOIN items ITM
ON IL.item = ITM.item
i want to update the invoicelines with a specified date, but this date is in another table, and the situation is similar to the first example
update table1
set price = price + 10
from table1 t1 join table2 t2 on t1.invoice = t2.invoice
where month(t2.date) = 11
As to "I know that i must use a join": No, you don't have to join. When a condition is in another table you would usually use EXISTS or IN.
update table1
set price = ...
where invoice in
(
select invoice
from table2
where month(`date`) = 11
);
Or:
update table1
set price = ...
where exists
(
select *
from table2
where month(table2.`date`) = 11
and table2.invoice = table1.invoice
);
You forgot to name your dbms. Date functions are mostly dbms specific, so a MONTH function may be available or not.
I Solved With This
UPDATE Invoicelines
SET Invoicelines.NetPrice = ART.Price
FROM Invoicelines BR INNER JOIN Items ART join InvoiceHead bt on month(bt.docdate)=11
ON BR.Item = ART.Item
where BR.sheetNumber=bt.sheetNumber

Update between 2 databases using dblink not working

Basically I have 2 databases each containing 2 tables. I need to update what's in database 2 using a table in database 1.
Below is database 1 table 2 (db1 ta2)
pid | pname | pcompany | clocation | did | name
1 Pirates Argos London 1 Mary
Database 2 table 1 (db1 tb1)
pid | pname | pcompany |
1 Ba Ba Black Argos
Now I need to update 'Ba Ba Black' to Pirates meaning I need to update db2 tb1 from db1 ta2.
UPDATE tb1
SET name = ta1.name
WHERE ta1.name = (SELECT ta1.name FROM dblink('port=5432, dbname=db1 user=postgres password=12345',
'SELECT name FROM ta1'))
AS t1 (a integer, b character(20), c integer)
WHERE pid = 1;
But I have this error:
ERROR: syntax error at or near "AS"
LINE 5: AS t1 (a integer, b character(20), c integer)
Any idea what I might be messing up?
Add table / column aliases and (most probably) a WHERE condition like this:
UPDATE tb1 b
SET name = a.pname -- maybe you want to update *pname* instead?
FROM (
SELECT *
FROM dblink('port=5432 dbname=db1 user=postgres password=12345'
, 'SELECT pname FROM ta1 WHERE pid = 1')
AS t(pname text)
) a
WHERE b.pid = 1;
Assuming type text. Adapt to your actual type.
And no comma in the connection string.
I am not linking a to b since a returns a single row here.
I worked the following way:
DO$$
DECLARE
sql_statement TEXT;
BEGIN
sql_statement:='UPDATE public.ta2 SET name='''||NEW.name||''' WHERE pid=1;';
PERFORM public.dblink('port=5432 dbname=db1 user=postgres password=*',sql_statement);
RETURN NEW;
END;
$$
languaje plpgsql;
You can consult this link: https://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html

SQL Update Skipping duplicates

Table 1 looks like the following.
ID SIZE TYPE SERIAL
1 4 W-meter1 123456
2 5 W-meter2 123456
3 4 W-meter 585858
4 4 W-Meter 398574
As you can see. Items 1 and 2 both have the same Serial Number. I have an innerjoin update statement that will update the UniqueID on these devices based on linking their serial number to the list.
What I would like to do. Is modify by hand the items with duplicate serial numbers and scripted update the ones that are unique. Im presuming I have to reference the distinct command here somewhere buy not sure.
This is my update statement as is. Pretty simple and straight forward.
update UM00400
Set um00400.umEquipmentID = tb2.MIUNo
from UM00400 tb1
inner join AA_Meters tb2 on
tb1.umSerialNumber = tb2.Old_Serial_Num
where tb1.umSerialNumber <> tb2.New_Serial_Num
;WITH CTE
AS
(
SELECT * , rn = ROW_NUMBER() OVER (PARTITION BY SERIAL ORDER BY SERIAL)
FROM UM00400
)
UPDATE CTE
SET CTE.umEquipmentID = tb2.MIUNo
inner join AA_Meters tb2
on CTE.umSerialNumber = tb2.Old_Serial_Num
where tb1.umSerialNumber <> tb2.New_Serial_Num
AND CTE.rn = 1
This will update the 1st record of multiple records with the same SERIAL.
If i understand your question correctly below query will help you out :
;WITH CTE AS
(
// getting those serial numbers which are not duplicated
SELECT umSerialNumber,COUNT(umSerialNumber) as CountOfSerialNumber
FROM UM00400
GROUP BY umSerialNumber
HAVING COUNT(umSerialNumber) = 1
)
UPDATE A SET A.umEquipmentID = C.MIUNo
FROM UM00400 A
INNER JOIN CTE B ON A.umSerialNumber = B.umSerialNumber
INNER JOIN AA_Meters C ON A.umSerialNumber = C.Old_Serial_Num

update each row in a procedure

I have the following data in a table TABLE1
DOCUMENT ------ FIELD1
12345
23456
34567
45678
98765
i have the following data in a view VIEW1
DOCUMENT ---- BUS
12345 ------------ 5
23456 ------------ 6
34567 ------------ 8
45678 ------------ 12
98765 ------------ 14
What i would like to do is update each row
if (table1.document = view1.document)
then
table1.field1 = view1.bus
Any insight will help.
Thank you.
That can be done using plain SQL, no procedures required:
UPDATE table1 SET field1 = (SELECT bus FROM view1 WHERE table1.document = view1.document)
Or, if your database allows it:
UPDATE (select table1.field1, view1.bus FROM table1 JOIN view1 ON table1.document = view1.document) SET table1.field1 = view1.bus
As Dan said, but in MS SQL Server I find this styling easier to read:
UPDATE U
SET U.field1 = V.bus
FROM table1 AS U
JOIN view1 AS V
ON V.document = U.document
Note that if VIEW1 could have multiple rows for a given TABLE1 row [DOCUMENT] value then the [BUS] value choosen to update TABLE1 will be random, within the matching set. (If this is the case the query could be modified to choose MAX / MIN / etc.)
I would refine this query to NOT update any rows that already matched the BUS value, which will make it faster if it is rerun and thus some values already exist in TABLE1
UPDATE U
SET U.field1 = V.bus
FROM table1 AS U
JOIN view1 AS V
ON V.document = U.document
WHERE U.field1 = V.bus
OR (U.field1 IS NOT NULL AND V.bus IS NULL)
OR (U.field1 IS NULL AND V.bus IS NOT NULL)
you can leave out the NULL / NOT NULL tests if the field is defined as not allowing NULLs.