updating Table from Another Table with Criteria - sql

i am trying to write a query that will update the schemeid of a row with the id of the matching row from another table.
tblschemes b holds the schemes detail and tblclaims_liberty a holds the claims data and the fields to join on are b.nett_scheme = a.schemename and a.agentcode = b.agentcode
why then id the query below allocating a schemeid to rows of data that do not match the agentcode??
update tblclaims_liberty
set tblclaims_liberty.schemeid = tblschemes.id
from tblschemes inner join tblclaims_liberty on tblclaims_liberty.schemename = tblschemes.nett_scheme and tblclaims_liberty.agentcode = tblschemes.agentcode
where
ce_report = 'yes'
and (tblclaims_liberty.schemeid != tblschemes.id or schemeid is null) --only updates rows that require updateing instead of 6mil+ lines of data.
can someone point me in the right direction?? why is it not recognising the agentcode match?
regards,
Adam

Try with this:
update tblclaims_liberty TLtoUpdate
set TLtoUpdate.schemeid =
(
select TS.id
from tblschemes TS inner join tblclaims_liberty TL on TL.schemename = TS.nett_scheme and TL.agentcode = TS.agentcode
where TL.schemeid = TLtoUpdate.schemeid
)
where TLtoUpdate.ce_report = 'yes' and TLtoUpdate.schemeid is null
Looks there was missing the TL.id condition in the subquery.

Related

SQL Server - How to do Inner Join when condition could be empty?

I am trying to get the Country from my factories AddressID directly in one Query with an Inner join. My problem is that the AddressID could be an empty string.
How do i check that and do some kind of exception or something similar? I if address ID is empty i need an empty string as result for f.Country.
This is my query for now, but if AddressID = '' then the row is not showing up in my result.
SELECT o.FactoryID,o.Name,o.Rating,o.ProductCategory,o.Emissions,o.LatestChanges,o.AddressID,o.ProductTags,f.Country
FROM FactoryHistory o
INNER JOIN AddressHistory f on f.AddressID = o.AddressID
WHERE NOT o.LatestChanges = 'Deleted' AND o.IsCurrent = 1 AND f.IsCurrent = 1
I something in my question is missing or unclear, just let me know!
Just left join:
SELECT o.FactoryID, o.Name, o.Rating, o.ProductCategory, o.Emissions, o.LatestChanges, o.AddressID, o.ProductTags, f.Country
FROM FactoryHistory o
LEFT JOIN AddressHistory f on f.AddressID = o.AddressID AND f.IsCurrent = 1
WHERE NOT o.LatestChanges = 'Deleted' AND o.IsCurrent = 1
If you still want to filter out factories whose AddressID is not null (assuming that by empty you mean null) and that do not exist in the address table, than you can add a condition in the WHERE clause:
WHERE
NOT o.LatestChanges = 'Deleted'
AND o.IsCurrent = 1
AND (o.AddressID IS NULL OR f.AddressID IS NOT NULL)
It might be clearer with a negation:
WHERE
NOT o.LatestChanges = 'Deleted'
AND o.IsCurrent = 1
AND NOT (o.AddressID IS NOT NULL AND f.AddressID IS NULL)

Update multiple rows with different values based on Ids

I have a table called Todo. This contains a list of id's and a completedDate field which is NULL. There are some other columns but they are not used here.
I then have a query which returns the following data:
data
The query is from the same table and is as follows...
SELECT Todo.id, MIN(CloudCall.CloudCallHistory.CallStarted)
FROM Todo
JOIN CloudCall.CloudCallHistory ON CloudCall.CloudCallHistory.ObjectId = Todo.foreignId
JOIN CloudCall.CloudCallNotebookTypeCategoryLink ON CloudCall.CloudCallNotebookTypeCategoryLink.CategoryCode = CloudCall.CloudCallHistory.CategoryId
JOIN NotebookTypes ON NotebookTypes.NotebookTypeId = CloudCall.CloudCallNotebookTypeCategoryLink.NotebookTypeId
WHERE CloudCall.CloudCallHistory.CallStarted > Todo.foreignDate
AND Todo.completedDate IS NULL
AND Todo.cancelledDate IS NULL
AND NotebookTypes.NotebookFolderId = 175
AND CloudCall.CloudCallHistory.CategoryId != 17427
GROUP BY Todo.id
So what I want to do is update the Todo table with the new date where the id's match. Is there anyway to do this in 1 query?
It would look something like this maybe?:
UPDATE Todo
SET completedDate... (SELECT...)
WHERE id = ?
where the select would be the query that returned the data shown in the image. Thanks
Something like this
UPDATE Todo
SET completedDate = o.otherDate
FROM Todo t
INNER JOIN (SELECT otherDate, id FROM otherTable) AS o ON t.id = o.id
Update
To join against the query that collects the dates:
UPDATE Todo
SET completedDate = o.min_date
FROM Todo t
JOIN (SELECT Todo.id, MIN(CloudCall.CloudCallHistory.CallStarted) AS min_date
FROM Todo
JOIN CloudCall.CloudCallHistory ON CloudCall.CloudCallHistory.ObjectId = Todo.foreignId
JOIN CloudCall.CloudCallNotebookTypeCategoryLink ON CloudCall.CloudCallNotebookTypeCategoryLink.CategoryCode = CloudCall.CloudCallHistory.CategoryId
JOIN NotebookTypes ON NotebookTypes.NotebookTypeId = CloudCall.CloudCallNotebookTypeCategoryLink.NotebookTypeId
WHERE CloudCall.CloudCallHistory.CallStarted > Todo.foreignDate
AND Todo.completedDate IS NULL
AND Todo.cancelledDate IS NULL
AND NotebookTypes.NotebookFolderId = 175
AND CloudCall.CloudCallHistory.CategoryId != 17427
GROUP BY Todo.id) AS o ON o.id = t.id
Just use JOIN for this purposes:
UPDATE t1
SET t1.completedDate = t2.[Column]
FROM dbo.ToDo AS t1
INNER JOIN dbo.Table2 AS t2
ON t1.CommonField = t2.[Common Field]
WHERE t1.id in (...);
Try this:
UPDATE Todo SET completedDate=CloudCall.CloudCallHistory.CallStarted
FROM Todo
JOIN CloudCall.CloudCallHistory ON CloudCall.CloudCallHistory.ObjectId = Todo.foreignId
JOIN CloudCall.CloudCallNotebookTypeCategoryLink ON
CloudCall.CloudCallNotebookTypeCategoryLink.CategoryCode =
CloudCall.CloudCallHistory.CategoryId
JOIN NotebookTypes ON
NotebookTypes.NotebookTypeId = CloudCall.CloudCallNotebookTypeCategoryLink.NotebookTypeId
WHERE
CloudCall.CloudCallHistory.CallStarted > Todo.foreignDate AND
Todo.completedDate IS NULL AND Todo.cancelledDate IS NULL AND
NotebookTypes.NotebookFolderId = 175 AND
CloudCall.CloudCallHistory.CategoryId != 17427
GROUP BY Todo.id
Please use aliases, makes the query readable without eight pages of horizontal scrolling.
Because you're dealing with aggregate data, you'll need to use a variation on SQL Server's proprietary UPDATE FROM syntax:
;WITH aggData AS
(
SELECT Todo.id, MinStart = MIN(ch.CallStarted)
FROM Todo
INNER JOIN CloudCall.CloudCallHistory AS ch
ON ch.ObjectId = Todo.foreignId
INNER JOIN CloudCall.CloudCallNotebookTypeCategoryLink AS cl
ON cl.CategoryCode = ch.CategoryId
INNER JOIN NotebookTypes AS nt
ON nt.NotebookTypeId = cl.NotebookTypeId
WHERE ch.CallStarted > Todo.foreignDate
AND Todo.completedDate IS NULL
AND Todo.cancelledDate IS NULL
AND nt.NotebookFolderId = 175
AND ch.CategoryId <> 17427
GROUP BY Todo.id
)
UPDATE t SET completedDate = aggData.MinStart
FROM Todo AS t
INNER JOIN aggData
ON t.id = aggData.id;
You can probably simplify this so that Todo is only read once, but let's start with something that doesn't drastically rewrite the entire query.

SQL Joining tables but getting skipped values

Hi i have joined to tables the code is below. Notice I have used A.Manad = B.Manad which joins data where the month of table A and B is equal. But sometimes table B dont have any data for that month. My code just skip the data, i would rather it just leave it empty or with a value of 0.
The Code takes a list of Orgnr which is swedish for company numbers and joins two tables where the orgnr is the same and the month is the same, but for some reason it doesnt join the data when the value is empty for one company. I still want the orgnr to show up in the joint table.
select Tillnr = A.tillnr, Orgnr = A.orgnr, Månad = A.Manad, Intrastat =
A.varde,Moms = B.vardeutf
into #Tabell1
From
IntrastatFsum A
left outer join
Momsuppg B
on A.Orgnr = B.Orgnr
where A.Orgnr in(
165563137933,165020456017,.......)
AND A.Ar = 2017
AND B.Ar = A.AR
AND A.Manad = 9
AND A.Manad = B.Manad
AND A.InfUtf = 'U'
You should move your WHERE clause AND A.Manad = B.Manad and AND B.Ar = A.AR to the LEFT JOIN clause.
In this way you will preserve all data from table IntrastatFsum:
select Tillnr = A.tillnr, Orgnr = A.orgnr, Månad = A.Manad, Intrastat =
A.varde,Moms = B.vardeutf
into #Tabell1
From
IntrastatFsum A
left outer join
Momsuppg B
on A.Orgnr = B.Orgnr
AND A.Manad = B.Manad
AND A.AR = B.Ar
where A.Orgnr in(
165563137933,165020456017,.......)
AND A.Ar = 2017
AND A.Manad = 9
AND A.InfUtf = 'U'

DB2 Update with subquery that contains join - correlating

I am trying to perform an update with a subquery where the update table is joined in the subquery. I cannot figure out how to associate the update record with the record found in the subquery. Something like the following, though as written this will obviously update the entire table. Thanks in advance.
Update OPTION OPT
SET (PSTREET, PCITY, PPROVINCE, PCOUNTRY, PPOSTALCODE)=
(select ADDRESS, CITY, PROVSTATE, COUNTRY, POSTALCODE
from ADDRESSES addr INNER JOIN COMPANY C ON C.SECURITYCOMPANY = addr.CODE1 || addr.CODE2
INNER JOIN DCODE D ON C.COMPANY_ID = D.COMPANY_ID
INNER JOIN OPTION OPT ON OPT.DCODE_ID = D.DCODE_ID
WHERE C.YEAROF IS NULL
AND C.DELETED IS NULL
AND D.DCODEEFF < CURRENT TIMESTAMP
AND (D.DCODEEXP IS NULL OR D.DCODEEXP > CURRENT TIMESTAMP)
AND D.DCODEELEMENT = addr.DCODEELEMENT
AND D.IND = addr.IND
AND ((addr.IND = 'B' AND addr.VAL1 = OPT.VAL1 AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'Y' AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'X' AND addr.VAL1 = OPT.VAL1))
You need to have some criteria to identify the records in OPT that you want to update. If its a single record, you'll need a surrogate or natural key. If its a many records like, say, based on a timestamp, you will need that time. Those criteria can then be put into a where clause after your set.
Use a condition in the WHERE clause in the sub-query that ties the result(s) in the sub-query to the outer table that you're updating. Here I added AND addr.addr_id = OPT.addr_id to your WHERE clause, but whatever the id column is called it needs to be shared between the table that you are updating and the sub-query.
UPDATE OPTION OPT
SET (PSTREET, PCITY, PPROVINCE, PCOUNTRY, PPOSTALCODE) =
(SELECT ADDRESS, CITY, PROVSTATE, COUNTRY, POSTALCODE
FROM ADDRESSES addr INNER JOIN COMPANY C ON C.SECURITYCOMPANY = addr.CODE1 || addr.CODE2
INNER JOIN DCODE D ON C.COMPANY_ID = D.COMPANY_ID
INNER JOIN OPTION OPT ON OPT.DCODE_ID = D.DCODE_ID
WHERE C.YEAROF IS NULL
AND C.DELETED IS NULL
AND D.DCODEEFF < CURRENT TIMESTAMP
AND (D.DCODEEXP IS NULL OR D.DCODEEXP > CURRENT TIMESTAMP)
AND D.DCODEELEMENT = addr.DCODEELEMENT
AND D.IND = addr.IND
AND ((addr.IND = 'B' AND addr.VAL1 = OPT.VAL1 AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'Y' AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'X' AND addr.VAL1 = OPT.VAL1)
AND addr.addr_id = OPT.addr_id)
In reality the criteria might be more complicated (involving a compound key or some inequality condition, for instance) - but regardless, adding the condition to the inner query is what's required.

update with subquery

The code :
UPDATE tt_t_documents
SET t_Doc_header_ID = (SELECT
MIN(dh.Doc_header_ID)
FROM tt_t_documents td WITH (NOLOCK)
JOIN Doc_header dh WITH (NOLOCK)
ON dh.DH_doc_number = td.t_dh_doc_number
AND dh.DH_sub = 1
JOIN Pred_entry pe WITH (NOLOCK)
ON pe.Pred_entry_ID = dh.DH_pred_entry
JOIN Doc_type dt WITH (NOLOCK)
ON dty.Doc_type_ID = pe.PD_doc_type
AND dt.DT_mode = 5
HAVING COUNT(dh.Doc_header_ID) = 1);
I want to update my columns, but before that I also want to check if there is only one ID found.
The problem in this select is that I get more than one ID.
How can I write a query that updates each row and checks in the same query that there is only one id found?
I am guessing that you intend something like this:
update td
set t_Doc_header_ID = min_Doc_header_ID
from tt_t_documents td join
(select DH_doc_number, min(dh.Doc_header_ID) as min_Doc_header_ID
from Doc_header dh join
Pred_entry pe
on pe.Pred_entry_ID = dh.DH_pred_entry join
Doc_type dt
on dty.Doc_type_ID = pe.PD_doc_type and dt.DT_mode = 5
where dh.DH_doc_number = td.t_dh_doc_number and dh.DH_sub = 1
group by DH_doc_number
having count(dh.Doc_header_ID) = 1
) dh
on dh.DH_doc_number = td.t_dh_doc_number;
Using a join also means that you do not update the values where the condition does not match. If you use a left join, then the values will be updated to NULL (if that is your intention).
I'm not sure I believe you are getting more than one id back with that select given that you are doing a 'min' on it and have no group by. It should be only returning the lowest value for Doc_header_id.
To do what you are asking, first, you should have some way of joining to the tt_t_documents table in the update statement (eg. where td.id == tt_t_documents.id).
Second, you could re-write it to use the sub-query in the from. Something like:
update
tt_t_documents
set
t_Doc_header_ID = x.Doc_Header_id
from tt_t_documents join (
select td.id,
min(dh.Doc_header_ID)
from
tt_t_documents td
join Doc_header dh
on dh.DH_doc_number = td.t_dh_doc_number
and dh.DH_sub = 1
join Pred_entry pe
on pe.Pred_entry_ID = dh.DH_pred_entry
join Doc_type dt
on dty.Doc_type_ID = pe.PD_doc_type
and dt.DT_mode = 5
group by td.id
having
count(dh.Doc_header_ID) = 1
) x on tt_t_documents.id= x.id;
The syntax may not be perfect and I'm not sure how you want to find the doc_header_id but it would be something like this. The sub query would only return values with 1 doc_header_id). Not knowing the schema of your tables, this is as close as I can get.