Update on linked server with nested subquery - sql-server

I want to update on a linked server the result of a query as well from a linked server.
The first sql snippet gives me the value to be updated:
SELECT mmdb_vessel.IMONo, mmdb_vessel.DeathDate
From OPENQUERY(MMDB, 'SELECT FunctionalLocation, IMONo, VesselStatus, CONVERT(VARCHAR(10), DeathDate, 102) AS DeathDate
FROM VESSEL
WHERE VESSEL.VesselStatusID <> 42 AND VESSEL.DeathDate is not null') as mmdb_vessel
, eb_all_v
WHERE
eb_all_v.IMO_No = mmdb_vessel.IMONo
AND eb_all_v.status = 'in service'
the second is actually what I'm not able to implement, it should show what I want to achieve:
UPDATE EPI2..EPI.PLANT
SET KIND_OF_LIQUIDATION_NO = 1
, LIQUIDATION_DATE = [result from snippet above].DeathDate
Where EPI2..EPI.PLANT.IMONo = [result from snippet above].IMONo
I'm not so sure if my explanation is sufficient, please feel free to ask for additional information!
Thanks, already in advance,
Werner

I would recommend to select the data from the remote server first and store the required data e.g. in a temptable, because LinkedServer and updates can have some sideeffects (e.g. performing a tablescan on the remote table, altough you would not expect it if an updaet is involved, etc) - but this depends on your exact usage/scenario.
Select data you need to update
SELECT * INTO #tmpTable FROM LINKEDSERVER.EPI.dbo.PLANT WHERE ....
Perform the update on local server
UPDATE EPI2..EPI.PLANT SET KIND_OF_LIQUIDATION_NO = 1, LIQUIDATION_DATE = t.DeathDate FROM #tmpTable t INNER JOIN EPI2..EPI.PLANT p on t.IMONo = p.IMONo

Related

How to find rows in ms-sql with another rows' value followingly?

I have created an Sql table to trace objects' operation history. I have two columns; first one is the self tracing code and second tracing code is the tracing code for the code coming from source object to target. I created this to be able to look up the route of operations through the objects. You can see the tracing sample table below:
I need to create an sql code to query to show all the route in one table. When I first select the self code, it will be the incoming code for previous rows. There may be more than one incoming code to self and I want to be able to trace all. And I want to reach end until my search is null.
I tried select query like below but I am so new sql and need your help.
SELECT [TracingCode.Self],
[TracingCode.Incoming],
[EquipmentNo]
FROM [MKP_PROCESS_PRODUCT_REPORTS].[dbo].[ProductionTracing.Main]
WHERE [TracingCode.Self] = (SELECT [TracingCode.Incoming]
FROM [MKP_PROCESS_PRODUCT_REPORTS].[dbo].[ProductionTracing.Main]
WHERE [TracingCode.Self] = (SELECT [TracingCode.Incoming]
FROM [MKP_PROCESS_PRODUCT_REPORTS].[dbo].[ProductionTracing.Main]
WHERE [TracingCode.Self] = (SELECT [TracingCode.Incoming]
FROM [MKP_PROCESS_PRODUCT_REPORTS].[dbo].[ProductionTracing.Main]
WHERE [TracingCode.Self] = '028.001.19.2.3')));
To do this kind of parent/child thing to any level without explicitly coding all levels you need to use a recursive CTE.
More details here
https://www.red-gate.com/simple-talk/sql/t-sql-programming/sql-server-cte-basics/
Here is some test data and a solution I came up with. Note that three records actually match 028.001.19.2.3
If this doesn't do what you need please explain further with sample data.
DECLARE #Sample TABLE (
TC_Self CHAR(14) NOT NULL,
TC_In CHAR(14) NOT NULL,
EquipmentNo INT NOT NULL
);
INSERT INTO #Sample (TC_Self, TC_In, EquipmentNo)
VALUES
('028.001.19.2.3','026.003.19.2.2',96),
('028.001.19.2.3','026.001.19.2.2',96),
('028.001.19.2.3','026.002.19.2.2',96),
('028.001.19.2.2','026.002.19.2.1',96),
('028.001.19.2.2','026.002.19.2.1',96),
('028.001.19.2.1','026.002.19.1.1',96),
('026.003.19.2.2','024.501.19.2.5',117),
('024.501.19.2.5','024.501.19.2.6',999),
('024.501.19.2.6','024.501.19.2.7',998);
WITH CTE (RecordType, TC_Self, TC_In, EquipmentNo)
AS
(
-- This is the 'root'
SELECT 'Root' RecordType, TC_Self, TC_In, EquipmentNo FROM #Sample
WHERE TC_Self = '028.001.19.2.3'
UNION ALL
SELECT 'Leaf' RecordType, S.TC_Self, S.TC_In, S.EquipmentNo FROM #Sample S
INNER JOIN CTE
ON S.TC_Self = CTE.TC_In
)
SELECT * FROM CTE;
Also please note that most of the time to generate this answer was taken in generating the sample data to use.
In future when asking questions, people are far more likely to help if you post this sample data generation yourself

Joins and linked servers query causing delay

Hey guys the code below is taking a really long time. I've been looking at it for quite a while. Is there anything that stands out as the obvious cause of delay?
[SQLSRV-3-JB] is a linked server BTW
Select count(cast (Unique_ID as bigint)) as [Count],
T.[Region_Code],
T.[Region_Name],
U.[Region_Code],
Y.[Examination_Year],
case when [Subject] = 'MUSIC THEORY' THEN 'Theory'
else 'Practical'
end
from [SQLSRV-3-JB].[X].[dbo].[Exam_and_Candidate_Details] Y
left join [SQLSRV-3-JB].[X].[dbo].[UK_Exam_Centre_Info] T
on Y.Centre_Code = T.Centre_Code
left join [SQLSRV-3-JB].[X].[dbo].[UK_Exam_Centres] U
on Y.Centre_Code = U.Centre_Code
where Y.[Examination_Year] between 2010 and 2016
group by Y.[Examination_Year],
T.[Region_Code],
T.[Region_Name],
U.[Region_Code],
case when [Subject] = 'MUSIC THEORY' THEN 'Theory'
else 'Practical'
end
Yes, there is one very obvious problem - the remote server. When you use a linked server like this, SQL Server has a disturbing habit of pulling all of the data in the remote tables to the local server before performing JOINs or filtration.
The correct way to handle this is to make this query a view on the remote server, and query the view with your WHERE clause on your end. So, your remote code would look like this:
-- Remote Server
USE X
GO
CREATE VIEW dbo.ExamCenterInfo
AS
Select count(cast (Unique_ID as bigint)) as [Count],
T.[Region_Code],
T.[Region_Name],
U.[Region_Code],
Y.[Examination_Year],
case when [Subject] = 'MUSIC THEORY' THEN 'Theory'
else 'Practical'
end
from dbo.[Exam_and_Candidate_Details] Y
left join dbo.[UK_Exam_Centre_Info] T
on Y.Centre_Code = T.Centre_Code
left join dbo.[UK_Exam_Centres] U
on Y.Centre_Code = U.Centre_Code
group by Y.[Examination_Year],
T.[Region_Code],
T.[Region_Name],
U.[Region_Code],
case when [Subject] = 'MUSIC THEORY' THEN 'Theory'
else 'Practical'
end
Then your local code:
-- Local Server
SELECT *
FROM [SQLSRV-3-JB].[X].[dbo].ExamCenterInfo ECI
where ECI.[Examination_Year] between 2010 and 2016
NOTE: There is some possibility that this will pull all of the view output before filtering by year. If this is still a problem, you will have to create a more complex mechanism to execute the view with filtration on the remote server.

Update field based on Compound select statement

I have a select statement That I need to turn into an Update.
I need to update a particular unix time field to January 1, 2016.
I have to select the records using a compound select statement.
Update archive_queue set archive_time = 1451606400
FROM
select recordings.(star), archive_queue.(star)
from
recordings, archive_queue
where
recordings.device_alias = '70285' and recordings.keepdays = 120
and recordings.ident = archive_queue.rec_ident
The above gives me a syntax error. The select gives me the records that I need to update. I looked at some examples here, but can't figure out the proper syntax based on my needs. Thanks everyone !
You should remove the select and only have one FROM statement:
Update archive_queue set archive_time = 1451606400
from recordings, archive_queue
where recordings.device_alias = '70285' and recordings.keepdays = 120
and recordings.ident = archive_queue.rec_ident

Passing a SQL result to a 2nd SQL query

I'm coming to the end of setting up my first Python script which involves querying my SQL Server (which I've removed credentials for privacy reasons).
This is a excerpt of the code for which I can successfully login and query my SQL Server db.
I know my 2 SELECT queries work independently as I've tested already. But I've come unstuck setting the first SELECT query as a variable which I wish to pass into the 2nd Select queries where clause.
In SQL terms, I wish to set the adjusted date as the variable StartDate (from my first SELECT) and pass this to the Where statement in my 2nd SELECT statement. I think I'm failing on setting the variable properly. To reconfirm, I've verified the SELECT statements work from Python.
Is there something I need to add? Any suggestions appreciated.
import csv
import os
import urllib.request
import pymssql
conn = pymssql.connect(server='', user='', password='', database='')
StartDate = conn.cursor()
StartDate.execute('SELECT Dateadd(dd, -19, MAX(LastDateValue)) FROM tbl_Date')
ASXCodes = conn.cursor()
ASXCodes.execute('SELECT ASXCode FROM tbl_Company WHERE (ASX200 = 1 OR
MarketIndex =1 OR SegmentIndex = 1) AND Delisted = 0 AND LastTraded
>= StartDate ORDER BY ASXCode')
Just guessing - couldn't you do everything in one single query?
SELECT ASXCode FROM tbl_Company WHERE (ASX200 = 1 OR MarketIndex =1 OR SegmentIndex = 1) AND Delisted = 0 AND LastTraded >= (SELECT Dateadd(dd, -19, MAX(LastDateValue)) FROM tbl_Date) ORDER BY ASXCode
Also, I would imagine that tbl_Date.LastDateValue is indexed? If you get many records, that could be rather expensive...

How to do Sql Server CE table update from another table

I have this sql:
UPDATE JOBMAKE SET WIP_STATUS='10sched1'
WHERE JBT_TYPE IN (SELECT JBT_TYPE FROM JOBVISIT WHERE JVST_ID = 21)
AND JOB_NUMBER IN (SELECT JOB_NUMBER FROM JOBVISIT WHERE JVST_ID = 21)
It works until I turn it into a parameterised query:
UPDATE JOBMAKE SET WIP_STATUS='10sched1'
WHERE JBT_TYPE IN (SELECT JBT_TYPE FROM JOBVISIT WHERE JVST_ID = #jvst_id)
AND JOB_NUMBER IN (SELECT JOB_NUMBER FROM JOBVISIT WHERE JVST_ID = #jvst_id)
Duplicated parameter names are not allowed. [ Parameter name = #jvst_id ]
I tried this (which i think would work in SQL SERVER 2005 - although I haven't tried it):
UPDATE JOBMAKE
SET WIP_STATUS='10sched1'
FROM JOBMAKE JM,JOBVISIT JV
WHERE JM.JOB_NUMBER = JV.JOB_NUMBER
AND JM.JBT_TYPE = JV.JBT_TYPE
AND JV.JVST_ID = 21
There was an error parsing the query. [ Token line number = 3,Token line offset = 1,Token in error = FROM ]
So, I can write dynamic sql instead of using parameters, or I can pass in 2 parameters with the same value, but does someone know how to do this a better way?
Colin
Your second attempt doesn't work because, based on the Books On-Line entry for UPDATE, SQL CE does't allow a FROM clause in an update statement.
I don't have SQL Compact Edition to test it on, but this might work:
UPDATE JOBMAKE
SET WIP_STATUS = '10sched1'
WHERE EXISTS (SELECT 1
FROM JOBVISIT AS JV
WHERE JV.JBT_TYPE = JOBMAKE.JBT_TYPE
AND JV.JOB_NUMBER = JOBMAKE.JOB_NUMBER
AND JV.JVST_ID = #jvst_id
)
It may be that you can alias JOBMAKE as JM to make the query slightly shorter.
EDIT
I'm not 100% sure of the limitations of SQL CE as they relate to the question raised in the comments (how to update a value in JOBMAKE using a value from JOBVISIT). Attempting to refer to the contents of the EXISTS clause in the outer query is unsupported in any SQL dialect I've come across, but there is another method you can try. This is untested but may work, since it looks like SQL CE supports correlated subqueries:
UPDATE JOBMAKE
SET WIP_STATUS = (SELECT JV.RES_CODE
FROM JOBVISIT AS JV
WHERE JV.JBT_TYPE = JOBMAKE.JBT_TYPE
AND JV.JOB_NUMBER = JOBMAKE.JOB_NUMBER
AND JV.JVST_ID = 20
)
There is a limitation, however. This query will fail if more than one row in JOBVISIT is retuned for each row in JOBMAKE.
If this doesn't work (or you cannot straightforwardly limit the inner query to a single row per outer row), it would be possible to carry out a row-by-row update using a cursor.

Resources