Is there a more efficient query I can use - sql

I want to know if theres a better way to script out this update statement:
update table A
set item = (select itemA + ' - ' + itemB from table B where id = 1),
temp = (select itemA from table B where id = 1)
where sid = (select sItemId from table B where id = 1)

Use JOINS to make it more efficient and Alias to make it more readable.
UPDATE A
SET A.item = B.itemA + ' - ' + B.itemB
,A.temp = B.itemA
FROM tableA A
INNER JOIN tableB B ON A.[sid] = B.sItemId
where B.id = 1

SQL Server specific syntax:
update a
set item = b.itemA + ' - ' + b.itemB,
temp = b.itemA
from tableA a
inner join tableB b on a.sid = b.sItemId
where b.id=1
Alternatively you can use MERGE:
merge into tableA as a
using tableB as b
on a.sid = b.sItemId and b.Id = 1
when matched then update set item = b.itemA + ' - ' + b.itemB, temp = b.itemA
;
The advantage of merge is that it is standard SQL syntax, and it will fail if an attempt is made to update the same record twice (the update with join will silently do only one of the updates). IIRC in later versions (with the respective compatibility level) update will fail as well. Also merge is more flexible.

It is of course better to use only one join instead of retrieving the same table (tableB) 3 times
UPDATE tableA
SET tableA.item =tableB. itemA + ' - ' + tableB.itemB,
tableA.temp = tableB.itemA ,
...
FROM tableA, tableB
WHERE tableA.sid= tableB.sItemId And tableB.id =1

Related

sql Update specific rows from select query

Hello I need some awful stored procedure and I cannot think of such
I've got these tables
Criterias
CriteriaId
Title
.......
Table StepCriterias
StepID
CriteriaId
OrderNum
Table Steps
StepID
ProcedureID
Title
...
So I select all the StepCriterias of a step with particular name and particular number
SELECT *
FROM StepCriterias sc
INNER JOIN Steps s ON sc.StepId = s.StepId
WHERE
s.Title = 'MYteststep'
ANd s.ProcedureId = 2
So suppose this query returns me five rows; now I should UPDATE all the resulting rows and their OrderNum should be incremented by 1 (I should increase the OrderNum of each row). That's my first problem and I cannot think of a stored procedure that an make that.
You could replace the join logic with an exsits condition in an update statement:
UPDATE StepCriterias sc
SET OrderNum = OrderNum + 1
WHERE EXISTS (SELECT *
FROM steps s
WHERE sc.StepId = s.StepId AND
s.Title = 'MYteststep' AND
s.ProcedureId = 2)
Probably this way .
UPDATE sc
SET OrderNum = OrderNum + 1
FROM StepCriterias sc
INNER JOIN steps s ON sc.StepId = s.StepId
WHERE s.Title = 'MYteststep'
AND s.ProcedureId = 2
In the event that you want an increment for each match, and a stepcriteria could match more than once, then:
UPDATE StepCriterias sc
SET OrderNum = (OrderNum +
(SELECT COUNT(*)
FROM steps s
WHERE sc.StepId = s.StepId AND
s.Title = 'MYteststep' AND
s.ProcedureId = 2
)
WHERE EXISTS (SELECT 1
FROM steps s
WHERE sc.StepId = s.StepId AND
s.Title = 'MYteststep' AND
s.ProcedureId = 2
);
There are simpler ways to express this in most databases, but the above is general syntax that should work in any database.
You can use UPDATE with a subquery, something like:
UPDATE StepCriterias
SET OrderNum = sc.OrderNum + 1
WHERE StepId IN (SELECT StepId
FROM StepCriterias sc
INNER JOIN steps s ON sc.StepId = s.StepId
WHERE s.Title = 'MYteststep' AND s.ProcedureId = 2);

Running slow with intersect

Trying to optimize a query it is updaing the records in table A based on the INTERSECT on two data sets.
UPDATE #TableA
SET IsFlag = CASE WHEN ISNULL(RJobFlag, 0) > 0 THEN 0 ELSE 1 END
FROM #TableA AS ABC
OUTER APPLY (
SELECT 1 RJobFlag
WHERE EXISTS (
SELECT ABC.COLUMN1,ABC.COLUMN2,ABC.COLUMN3,ABC.COLUMN4,ABC.COLUMN5,ABC.COLUMN6,ABC.COLUMN7,ABC.COLUMN8,ABC.COLUMN8,ABC.COLUMN9,ABC.COLUMN10,StudentID,SubjectID
INTERSECT
SELECT XYZ.COLUMN1,XYZ.COLUMN2,XYZ.COLUMN3,XYZ.COLUMN4,XYZ.COLUMN5,XYZ.COLUMN6,XYZ.COLUMN7,XYZ.COLUMN8,XYZ.COLUMN8,XYZ.COLUMN9,XYZ.COLUMN10,StudentID,SubjectID
FROM #TableB AS XYZ
WHERE XYZ.COLUMN1 = (SELECT DISTINCT ID FROM #TableC MNOP WHERE MNOP.StudentID = ABC.StudentID)
AND StudentID = ABC.StudentID
AND SubjectID = ABC.SubjectID )
) Subquery
WHERE ABC.COLUMN1= '2'
Appretiated if you have some ideas to better optimize it.
Thanks
This might be worse never know.
UPDATE tA
SET IsFlag = COALESCE(RJobFlag, 0)
FROM #TableA tA
LEFT JOIN ( SELECT 1 RJobFlag, *
FROM #TableB tB
WHERE EXISTS ( SELECT *
FROM #TableC tC
WHERE tC.ID = tB.COLUMN1 AND tC.StudentID = tB.StudentID)
) tB
ON tA.StudentID = tB.StudentID
AND tA.SubjectID = tB.SubjectID
AND tA.COLUMN1 = tB.COLUMN1
AND tA.COLUMN2 = tB.COLUMN2
AND tA.COLUMN3 = tB.COLUMN3
AND tA.COLUMN4 = tB.COLUMN4
AND tA.COLUMN5 = tB.COLUMN5
AND tA.COLUMN6 = tB.COLUMN6
AND tA.COLUMN7 = tB.COLUMN7
AND tA.COLUMN8 = tB.COLUMN8
AND tA.COLUMN9 = tB.COLUMN9
AND tA.COLUMN10 = tB.COLUMN10
If #TableA has a bunch of records and you're using outer apply or outer join every time you update it will be slow since it has to update every single record. maybe there's a way to only update the records that have changed?

update rows from joined tables in oracle

I'm trying to migrate some tables into an existing table, I need to perform the updates only where DET_ATTACHMENT_ID equals DET_ATTACHMENT.ID, here's the query I have so far.
UPDATE DET_ATTACHMENT
SET attachment_type = 'LAB', -- being added by the query, to replace the table difference
payer_criteria_id = (
SELECT PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT
WHERE DET_LAB_ATTACHMENT.DET_ATTACHMENT_ID = DET_ATTACHMENT.ID)
WHERE exists(
SELECT DET_ATTACHMENT_ID
FROM DET_ATTACHMENT
JOIN DET_LAB_ATTACHMENT ON (ID = DET_ATTACHMENT_ID)
WHERE DET_ATTACHMENT_ID = DET_ATTACHMENT.ID
the problem with the existing query is that it's setting every row to have an attachment_type of "LAB", and nulling out the payer_criteria_id where it didn't match. What am I doing wrong?
The problem might be that your exists(...) predicate always evaluates to true, thus making the update run for all rows of det_attachment. Try it this way:
UPDATE DET_ATTACHMENT X
SET X.attachment_type = 'LAB',
X.payer_criteria_id = (
SELECT C.PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT C
WHERE C.DET_ATTACHMENT_ID = X.ID
)
WHERE
exists(
SELECT 1
FROM DET_ATTACHMENT A
JOIN DET_LAB_ATTACHMENT B
ON B.DET_ATTACHMENT_ID = A.ID
where B.det_attachment_id = X.id
)
;

SQL MERGE statement with conditional MATCH clause

As you can see in the code below the MERGE statement is exactly the same except based on the IF statement I'm changing the column that will be merged into the target table. Is there a better way of writing this? As the number of #Event's grow I don't want to be copying and pasting more and more of these as its not maintainable.
IF #Event = 1
BEGIN
MERGE INTO SomeTable
USING (
-- Some Query
) AS A ON SomeTable.Id = A.Id
WHEN MATCHED THEN
UPDATE SET SomeTable.Column1 = SomeTable.Column1 + 1;
END
ELSE IF #Event = 2
BEGIN
MERGE INTO SomeTable
USING (
-- Some Query
) AS A ON SomeTable.Id = A.Id
WHEN MATCHED THEN
UPDATE SET SomeTable.Column2 = SomeTable.Column2 + 1;
END
It might be a matter of debate whether one statement is better than two. But, you can combine these:
MERGE INTO SomeTable
USING (
-- Some Query
) AS A ON SomeTable.Id = A.Id
WHEN MATCHED THEN
UPDATE SET SomeTable.Column1 = (CASE WHEN #Event = 1
THEN SomeTable.Column1 + 1
ELSE SomeTable.Column1
END),
SomeTable.Column2 = (CASE WHEN #Event = 2
THEN SomeTable.Column2 + 1
ELSE SomeTable.Column2
END);
You dont really need a Merge statement for this and yes you can write your UPDATE statement a bit more dynamically. something like this.....
UPDATE ST
SET ST.Column1 = CASE WHEN #Event = 1
THEN ST.Column1 + 1
ELSE ST.Column1 END
,ST.Column2 = CASE WHEN #Event = 2
THEN ST.Column2 + 1
ELSE ST.Column2 END
FROM SomeTable ST
INNER JOIN
(
-- Some Query
) AS A
ON ST.Id = A.Id
Also you might want to read Use Caution with SQL Server's MERGE Statement as well though.

SQLite inner join - update using values from another table

This is quite easy and has been asked multiple times but I can't get it to work.
The SQL query I think should work is:
UPDATE table2
SET dst.a = dst.a + src.a,
dst.b = dst.b + src.b,
dst.c = dst.c + src.c,
dst.d = dst.d + src.d,
dst.e = dst.e + src.e
FROM table2 AS dst
INNER JOIN table1 AS src
ON dst.f = src.f
Using the update statement it is not possible because in sqlite joins in an update statement are not supported. See docs:
update statement
If you only wanted to update a single column to a static value, you could use a subquery in the update statement correctly. See this example: How do I make an UPDATE while joining tables on SQLite?
Now in your example, making an assumption that there is a unique key on "column f" - a workaround/solution I have come up with is using the replace statement:
replace into table2
(a, b, c, d, e, f, g)
select src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f
I also added an extra column to table2 "column g" to show how you'd "update" only some of the columns with this method.
One other thing to be cautious about is if you use "PRAGMA foreign_keys = ON;" it's possible to have issues with this as the row is effectively deleted and inserted.
I came up with an alternative technique using a TRIGGER and "reversing" the direction of the update, albeit at the cost of a dummy field in the source table.
In general terms, you have a Master table and an Updates table. You want to update some/all fields of records in Master from the corresponding fields in Updates linked by a key field Key.
Instead of UPDATE Master SET ... FROM Master INNER JOIN Updates ON Mater.Key = Updates.Key you do the following:
Add a dummy field TriggerField to the Updates table to act as the focus of the trigger.
Create a trigger on this field:
CREATE TRIGGER UpdateTrigger AFTER UPDATE OF TriggerField ON Updates
BEGIN
UPDATE Master SET
Field1 = OLD.Field1,
Field2 = OLD.Field2,
...
WHERE Master.Key = OLD.Key
END;
Launch the update process with the following:
UPDATE Updates SET TriggerField = NULL ;
Notes
The dummy field is merely an anchor for the trigger so that any other UPDATE Updates SET ... won't trigger the update into Master. If you only ever INSERT into Updates then you don't need it (and can remove the OF TriggerField clause when creating the trigger).
From some rough-and-ready timings, this seems to work about the same speed as REPLACE INTO but avoids the feels-slightly-wrong technique of removing and adding rows. It is also simpler if you are only updating a few fields in Master as you only list the ones you want to change.
It is orders of magnitude faster than the other alternative I've seen to UPDATE ... FROM which is:
UPDATE Master SET
Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
...
;
Updating six fields over 1700 records was roughly 0.05s for Tony and my methods but 2.50s for the UPDATE ... ( SELECT... ) method.
AFTER UPDATE triggers on Master seem to fire as expected.
As Tony says, the solution is the replace into way but you can use the sqlite hidden field rowid to simulate full update with join like:
replace into table2
(rowid,a, b, c, d, e, f, g)
select dest.rowid,src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f
With this you recreate full rows if you don't have primary key for the replace or as standard method to do the updates with joins.
SQLITE does not support UPDATE with INNER JOIN nor do several other DB's. Inner Joins are nice and simple however it can be accomplished using just a UPDATE and a subquery select. By using a where clause and the 'IN' with a subquery and a additional subquery for the 'SET' the same result can always be accomplished. Below is how it's done.
UPDATE table2
SET a = a + (select a from table1 where table1.f = table2.f),
b = b + (select b from table1 where table1.f = table2.f),
c = c + (select c from table1 where table1.f = table2.f),
d = d + (select d from table1 where table1.f = table2.f),
e = e + (select e from table1 where table1.f = table2.f)
WHERE RowId IN (Select table2.RowId from table1 where table1.f = table2.f)
Use below query:
UPDATE table2
SET a = Z.a,
b = Z.b,
c = Z.c,
d = Z.d,
e = Z.e
FROM (SELECT dst.id,
dst.a + src.a AS a,
dst.b + src.b AS b,
dst.c + src.c AS c,
dst.d + src.d AS d,
dst.e + src.e AS e
FROM table2 AS dst
INNER JOIN table1 AS src ON dst.f = src.f
)Z
WHERE table2.id = z.id