SQL Update Query with two levels of join? - sql

I'm trying to put together an update query where the source field is two tables away. Here's a query I got to work in the SQLCMD window which pulls both fields when they don't match:
SELECT
Act_det.Shift AS Shift_a, Inc_main.Shift AS Shift_b,
FROM
dbo.Act_det
INNER JOIN
dbo.Act_main ON Act_det.Activ_id = Act_main.Activ_id
INNER JOIN
dbo.Inc_main ON Act_main.Inci_no = Inc_main.Inci_no
WHERE
Act_det.Shift <> Inc_main.Shift;
I want to set Act_det.Shift = Inc.main_Shift when they don't match.
The relationships are that the Act_det table has a field Activ_id which matches to a single record in the Act_main table. The Act_main then has an inci_no which matches to a single record in the Inc_main table which has the "shift" value that we want to query and update "shift" in the act-det table with if they don't already match.
I've tried putting together an update query based on other responses found here and other places but I can't figure out how to make an Update/Set and the joins coexist.
UPDATE dbo.Act_det
SET db.act_det.shift = dbo.inc_main.shift,
INNER JOIN dbo.Act_main ON Act_det.Activ_id = Act_main.Activ_id
INNER JOIN dbo.Inc_main ON Act_main.Inci_no = Inc_main.Inci_no
WHERE Act_det.Shift <> Inc_main.Shift;
This bombs out with
Incorrect syntax near the keyword 'INNER'.
I can't just update every record even if they already match, since at the application level every Incident that gets updated will get flagged for re-submission to the state, and we'll end up with like 15,000 records going up for audit.

I did post the improper "latest" version of my attempts. (When cutting and pasting from OneNote it wants to do it as a picture, so I ended up using the up arrow in the SQLCMD and landed on a prior attempt.) I had it formatted with a FROM and without the extraneous comma. BUT I never caught me having dbo instead of db.
From the comments:
I presume you're using SQL Server - in which case you're missing a 'FROM' (and have an extra comma). Also you have a 'db' where it should be either 'dbo' or blank in the 'set' area. It should start as Update dbo.Act_det set shift = dbo.inc_main.shift FROM dbo.Act_det INNER JOIN dbo.Act_main etc –
seanb

Related

SQL SRVR 2016: Trouble joining to a nested select statement

I'm working in a query window in SSMS.
Using 3 tables:
WORK_ORDER wo
An order to fabricate a part
OPERATION op
An operation in the fabrication of the part (laser, grinding, plating, etc.)
PART pt
A unique record defining the part
My objective is to report on the status of an operation (say #3) (#total parts ordered, #completed parts), but additionally to include the number of parts that have completed the previous operation (#2) in the sequence and are ready for the process. My solution was to use the LAG function, which works perfectly when the nested select statement below is run independently, but I get an avg of 4X duplication in my results, and my Completed_QTY_PREV_OP column is not displayed. I am aware that's because it's not in the parent select statement, but I wanted to correct the join first. I'm guessing the two problems are related.
Footnote: The WHERE contains a filter that you can ignore. The parent select statement works perfectly without the joined subquery.
Here's my sql:
SELECT op.RESOURCE_ID, pt.USER_5 AS PRODUCT, wo.PART_ID, wo.TYPE, wo.BASE_ID,
wo.LOT_ID, wo.SPLIT_ID, wo.SUB_ID, op.SEQUENCE_NO, pt.DESCRIPTION,
wo.DESIRED_QTY, op.FULFILLED_QTY AS QTY_COMP, op.SERVICE_ID, op.DISPATCHED_QTY, wo.STATUS
FROM dbo.WORK_ORDER wo INNER JOIN
dbo.OPERATION op ON wo.TYPE = op.WORKORDER_TYPE
AND wo.BASE_ID = op.WORKORDER_BASE_ID
AND wo.LOT_ID = op.WORKORDER_LOT_ID
AND wo.SPLIT_ID = op.WORKORDER_SPLIT_ID
AND wo.SUB_ID = op.WORKORDER_SUB_ID INNER JOIN
dbo.PART pt ON wo.PART_ID = pt.ID
LEFT OUTER JOIN
--The nested select statement works by itself in a query window,
--but the JOIN throws an error.
(SELECT
pr.WORKORDER_TYPE, pr.WORKORDER_BASE_ID, pr.WORKORDER_LOT_ID,
pr.WORKORDER_SPLIT_ID, pr.WORKORDER_SUB_ID, pr.SEQUENCE_NO,
LAG (COMPLETED_QTY, 1) OVER (ORDER BY pr.WORKORDER_TYPE, pr.WORKORDER_BASE_ID,
pr.WORKORDER_LOT_ID, pr.WORKORDER_SPLIT_ID, pr.WORKORDER_SUB_ID, pr.SEQUENCE_NO) AS COMP_QTY_PREV_OP
FROM dbo.OPERATION AS pr) AS prev
--End of nested select
ON
op.WORKORDER_TYPE = prev.WORKORDER_TYPE AND
op.WORKORDER_BASE_ID = prev.WORKORDER_BASE_ID AND
op.WORKORDER_LOT_ID = prev.WORKORDER_LOT_ID AND
op.WORKORDER_SPLIT_ID = prev.WORKORDER_SPLIT_ID AND
op.WORKORDER_SUB_ID = prev.WORKORDER_SUB_ID
WHERE (NOT (op.SERVICE_ID IS NULL)) AND (wo.STATUS = N'R')
You haven't given enough information for a definitive answer, so instead I will give you an approach to debugging this.
You are getting unexpected rows as a result of a JOIN. This means that your JOIN condition is not matching the two sides of the JOIN on a one-to-one basis. There are multiple rows in the table being JOINed that meet the JOIN conditions.
To find these rows, temporarily change your SELECT list to SELECT *. Do this both in the outer SELECT, and in the derived table. Look through the columns being returned by the JOINed table, and find the values that you didn't expect to be returned.
Since the JOIN that causes the issue is the last one, they will be all the way to right of the result of a SELECT *.
Then add more conditions to the JOIN to eliminate the unwanted rows from the results.
I simplified the whole query by first creating a temp table filled by the previously nested SELECT, and then joining to it from the parent SELECT.
Works perfectly now. Thanks for looking.
PS: I apologize for the confusion about an error message. I noticed after I posted that I had an old comment in the code regarding an error. The error had been resolved before posting, but I neglected to remove the comment.

Using a record to choose a field to update a query shows a popup

UPDATE tblInstance
(INNER JOIN Master_Table ON tblInstance.[WorkOrder] = Master_Table.[Work_Order_number])
INNER JOIN tblCustomer_New ON Master_Table.[Customer_Name] = tblCustomer_New.[Customer_Name]
SET tblInstance.to_test_date = [Master_Table].[tblCustomer_New.Inital_Invoice];
I use a record from one table to choose a field in another table to update a record in a third table. I have all the table relationships set within Access.
Edit:
A value box pops up when trying to run it. It isn't pulling any data from the master table.
When MS Access does not find a certain identifier in your query it shows a value box asking for the value. See: Why does Access want me to enter a parameter value?
To solve this you can take the following steps:
Look at the parameter name it is asking for; it could be that the column name or a table name is incorrectly written. If you see an incorrect name which is not in the database, fix it.
Otherwise try the same query but as a select statement:
SELECT *
FROM tblInstance
(INNER JOIN Master_Table ON tblInstance.[WorkOrder] = Master_Table.[Work_Order_number])
INNER JOIN tblCustomer_New ON Master_Table.[Customer_Name] = tblCustomer_New.[Customer_Name];
And then try just the subqueries, starting with, for example:
SELECT *
FROM tblInstance
(INNER JOIN Master_Table ON tblInstance.[WorkOrder] = Master_Table.[Work_Order_number])

SQL INNER JOIN update NOT duplicating rows

I have an update query that has an inner join. I expect this query to return two columns because of the join, but it seems that the QUERY is taking only the first row and using that to update the data while ignoring the rest.
Here is my update command
UPDATE [mamd]
SET [Brand_EL] = IIF(CHARINDEX('ELECT', UPPER([mml].[Brand_Desc])) > 0, 'YES', [Brand_EL])
FROM [mamd] [m]
INNER JOIN [ior] [ir] ON [ir].[CLIENT_CUSTOMER_ID] = [m].[CustomerId] COLLATE Latin1_General_CI_AS
INNER JOIN [maslist] [mml] ON [mml].[Model] = [ir].[MODEL] COLLATE Latin1_General_CI_AS
If I do a select like this
SELECT [ir].[CLIENT_CUSTOMER_ID], IIF(CHARINDEX('ELECT', UPPER([mml].[Brand_Desc])) > 0, 'YES', [Brand_EL])
FROM [mamd] [m]
INNER JOIN [ior] [ir] ON [ir].[CLIENT_CUSTOMER_ID] = [m].[CustomerId] COLLATE Latin1_General_CI_AS
INNER JOIN [maslist] [mml] ON [mml].[Model] = [ir].[MODEL] COLLATE Latin1_General_CI_AS
I get the following data returned
CLIENT_CUSTOMER_ID | Brand_EL
-------------------+----------
980872 | NO
980872 | YES
The reason I think it's only taking one record is because
The value NEVER changes to "YES"
When I run the update command it says only 1 row updated even though it should have gone through two
One thing that might be contributing to the problem is that [mamd] does NOT contain multiple records for that same user; It's a unique field. Since it's a unique field and therefore only has one row, does that mean that it will run that join only once? If that's the case, is there a better way I can do this without nested selects to generate the results?
UPDATE
Hey Everyone,
Just as an update, I took Gordons Advice and use aggregation. In this example that I have, I only cared if the value was "YES' because I only need to know if the customer bought a specific product. So what I ended up doing was grouping by the Customer ID and using the MAX function. If the customer bought a product, "YES" would bubble up to the top. If he didn't it would stay as NO or NULL. In that event, it wouldn't matter.
The behavior is correct and documented, although not in a very clear way:
Use caution when specifying the FROM clause to provide the criteria
for the update operation. The results of an UPDATE statement are
undefined if the statement includes a FROM clause that is not
specified in such a way that only one value is available for each
column occurrence that is updated, that is if the UPDATE statement is
not deterministic. For example, in the UPDATE statement in the
following script, both rows in Table1 meet the qualifications of the
FROM clause in the UPDATE statement; but it is undefined which row
from Table1 is used to update the row in Table2.
What this is trying to say is that a row is only updated once by the update. Which value gets used is indeterminate. So, if you need to decide how you want to handle the multiple matches.

How to fix: Only one expression can be specified in the select list when the subquery is not introduced with EXISTS

I've been through a bunch of existing posts but couldn't get this to
work. I'm trying to build a query get all the records in a table and
an extra column. The extra column is populated by this logic - the
first value represented in the row which has same session ID as the
original record and has ToolName=ReportingTool. When I try to
implement the query like this, I get this error.
I tried doing a left join but the problem there is I don't know how to
limit the left join output (from the right table's select) to 1. This
causes multiple joins on the left and the no. of records returned
changes. My query is as follows:
SELECT
*
FROM [TraceDB].[dbo].[TelemetryLogs] AS TelemetryOuter
LEFT JOIN [TraceDB].[dbo].[TelemetryLogs] AS TelemetryInner
ON
TelemetryInner.SessionID = TelemetryOuter.SessionID AND
TelemetryInner.ToolName='ReportingTool' AND
TelemetryInner.Name='Identity' AND
TelemetryInner.SessionID = (
SELECT TOP 1 *
FROM [TraceDB].[dbo].[TelemetryLogs] AS TelemtryIntInt
WHERE TelemtryIntInt.SessionID=TelemetryInner.SessionID
)
WHERE
TelemetryOuter.ToolName ='ReportingTool'
EDIT: Fixed a comma which got introduced as a copy paste type
Try
SELECT TOP 1 TelemtryIntInt.SessionID
In your inner SELECT. You're currently returning the whole row and you can't compare a scalar sessionID against a whole row.

Query with multiple INNER JOINS, difficulties in avoiding duplicates

I have an ACCESS BD with a main table ('Principale') having a many-to-many connection with another ('TabRegisti'), with a join table between them ('TabRegisti_Unione').
I've a form for 'Principale' where there's a Search Button that, after the user click, creates a query for a listbox in another form.
The query that I'm using is the following:
SELECT Principale.ID, Principale.CodiceDVD, Principale.Cofanetto,
Principale.TitoloDVD, TabRegisti.NomeRegista, TabRegisti.CognomeRegista,
TabCategoria.Categoria, Principale.Durata, Principale.AttoriPrincipali,
Principale.Produzione, Principale.AnnoDVD, Principale.AnnoFilm,
Principale.DataACQ, Principale.Ubicazione
FROM TabRegisti
INNER JOIN (TabCategoria
INNER JOIN ((Principale INNER JOIN TabUbicazione
ON Principale.Ubicazione = TabUbicazione.Ubicazione)
INNER JOIN TabRegisti_unione
ON Principale.ID = TabRegisti_unione.IDrifPrincipale)
ON TabCategoria.CategorieID = Principale.CategorieID)
ON TabRegisti.IDRegista = TabRegisti_unione.IDregistaUnione
WHERE (((TabRegisti.NomeRegista) Like "*anc*")
AND ((TabRegisti.CognomeRegista) Like "*"))
ORDER BY Principale.CodiceDVD;
I'm using the query, with the correct syntax, in VBA (the Where clause showed is just an example, of course).
It works fine but leaves duplicates of the main table's records.
I've tried to insert the clause DISTINCT and, after, the clause DISTINCTROW, but nothing chanced (duplicates are still there).
Otherwise, the use of the clause GROUP BY (i.e. 'GROUP BY Principale.CodiceDVD' before the clause ORDER BY) gives an error. Suggstions?
Hope the explanation of the problem is clear enough (I'm not english motherlanguage, so be indulgents).
DISTINCT will show only rows with distinct values in your selection fields. Your selected fields row must not be actually identical. You need to remove from the SELECT fields the once that you probably don't need and that generate a row that you don't want to see.