SQL INNER JOIN update NOT duplicating rows - sql

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.

Related

update average/count from another table

I've been provided the below schema for this problem and I'm trying to do two things:
Update the ACCOUNT table's average_eval row with the average of the evaluation row from the POST_EVAL table per account_id.
Update the ACCOUNT table with a count of the number of posts per account_id, with default value 0 if the account_id has no post_id associated to it.
Here's the kicker : I MUST use the UPDATE statement and I'm not allowed to use triggers for these specific problems.
I've tried WITH clauses and GROUP BY but haven't gotten anywhere. Using postresql's pgadmin for reference.
Any help setting up these queries?
The first question can be done using something like this:
update account a
set average_eval = t.avg_eval
from (
select account_id, avg(evaluation) as avg_eval
from post_eval
group by account_id
) t
where t.account_id = a.account_id
The second question needs a co-related sub-query as there is no way to express an outer join in an UPDATE statement like the above:
update account a
set num_posts = (select count(*)
from post p
where p.account_id = a.account_id);
The count() will return zero (0) if there are no posts for that account. If a join was used (as in the first statement), the rows would not be updated at all, as the "join" condition wouldn't match.
I have not tested either of those statements, so they can contain typos (or even logical errors).
Unrelated, but: I understand that this is some kind of assignment, so you have no choice. But as RiggsFolly has mentioned: in general you should avoid storing information in a relational database that can be derived from existing data. Both values can easily be calculated in a view and then will always be up-to-date.

What is the difference between these 2 queries (end Result)

I am interested in if and what the difference is between these 2 queries are:
This one has SELECT TOP 1
UPDATE tblTemp SET [SOH] = (Select top 1 (tblstock.[Stock On Hand (Base UOM)])
FROM tblstock
WHERE tblTEMP.[ID] = tblstock.[ID])
and this one does not
UPDATE tblTemp SET [SOH] = (Select tblstock.[Stock On Hand (Base UOM)])
FROM tblstock
WHERE tblTEMP.[ID] = tblstock.[ID]
The first one affects more rows.
So my question is: Are they doing the same thing?
First, the second is more appropriately written as:
UPDATE tblTemp
SET [SOH] = tblstock.[Stock On Hand (Base UOM)]
FROM tblstock
WHERE tblTEMP.[ID] = tblstock.[ID];
(There is no reason to have a subquery with no FROM clause; it is a wasted SELECT.)
Second, they do not do the same thing. The first will set SOH to NULL if there is no match. The second will not change the existing value.
This ignores what happens when there are multiple matches. SQL Server does not specify which row is used for the update. So, even the same query might produce different results on different runs on the same data.
In your first query, your sub-query includes your where clause. So it will be updating all in the tblTemp table.
The second query has the where clause supplied outside of the sub-query, so applies this where to the tblTemp table.

Why does this SQL query need DISTINCT?

I've written a query to filter a table based on criteria found in a master table, and then remove rows that match a third table. I'm executing the query in Access, so I can't use MINUS. It works, but I found that it returns duplicate rows for some, but not all, of the selected records. I fixed it with DISTINCT, but I don't know why it would return duplicates in the first place. It's a pretty simple query:
select distinct sq.*
from
(select List_to_Check.*, Master_List.SELECTION_VAR
from List_to_Check
left join Master_List
on List_to_Check.SUB_ID = Master_List.SUB_ID
where Master_List.SELECTION_VAR = 'criteria'
) as sq
left join List_to_Exclude
on sq.SUB_ID = List_to_Exclude.SUB_ID
where List_to_Exclude.SUB_ID is null
;
Edit: The relationships between all three tables are 1-to-1 on the SUB_ID var. Combined with using a LEFT JOIN, I would expect one line per ID.
I recommend breaking your query apart and checking for duplicates. My guess is that it's your data/ the sub_ID isn't very unique.
Start with you sub query since you're returning all of those columns. If you get duplicates there, your query is going to return duplicates regardless of what is in your exclusion table.
Once you have those duplicates cleared up, check the exclusion table for duplicate sub_Id.
To save time in trouble-shooting, if there are known culprits that are duplicates, you may want to limit the returned values, so you can focus on the peculiarities of those data.
I'm not sure this is a problem, but look into the logic on
on List_to_Check.SUB_ID =
Master_List.SUB_ID
where Master_List.SELECTION_VAR = 'criteria'
Where clauses on data in the right side of a left outer join may not be returning the data you expect. Try this and see what happens:
on List_to_Check.SUB_ID = Master_List.SUB_ID
and Master_List.SELECTION_VAR = 'criteria'
The inner query joins List_to_Check and master but the outer query joins List_to_Exclude with Subscriber(maybe you can change the names i call these 3 tables)
To avoid duplicates you need to use one of the table in both the queries inner and outer. This will avoid duplicates.

Access 2010 Query Confusion

Just need some quick clarification
I have 2 Queries in my Access Database that should return Inverse results:
SELECT Equipment.title
FROM Equipment
WHERE (((Equipment.[EquipmentID]) Not In (
select EquipmentID
from DownPeriod
where UpDate is null
)));
The 2nd just excludes the Not before the In.
My Confusion comes from the fact that the query posted above does not return any results if an EquipmentID field has at least 1 null value in the DownPeriod table.
It works fine if the fields are filled, and the inverse query list always works. This makes me think there's an issue with the null value.
Now this field should never be null but I wanted to know if I could still get this to work in the unlikely event a null did occur.
Thank you in advanced!
Try joins:
SELECT Equipment.title FROM Equipment INNER JOIN DownPeriod
ON Equipment.EquipmentID = DownPeriod.EquipmentID
WHERE DownPeriod.UpDate is null
and
SELECT Equipment.title FROM Equipment INNER JOIN DownPeriod
ON Equipment.EquipmentID = DownPeriod.EquipmentID
WHERE DownPeriod.UpDate is not null
See if a change in syntax fixes your issue.
Not only should this work, but I believe it is a faster practise than using the IN() NOT IN() methods (might be wrong on that, but it looks nicer to read). It also adds the ability to quickly change the "is not null" criteria just the same as IN->NOT IN
I agree with StuckAtWork's approach. However, if you still want to understand why your original approach didn't produce the results you want, I think I can help you.
There may be an issue with empty strings which could complicate the situation. But regardless of whether or not empty strings are involved you have something more fundamental to consider.
Here is my version of the Equipment table.
EquipmentID title
1 one
2 two
3 three
And here is my version of the DownPeriod table.
ID EquipmentID text_field
1 1 one
2 2 two
3 Null
4 3 three
I didn't include your UpDate field in my DownPeriod table. It's irrelevant to your problem.
I pasted your SQL into a new Access query, discarded the WHERE clause from the subquery, and got exactly the same result as this query --- no rows returned:
SELECT e.title
FROM Equipment AS e
WHERE
e.EquipmentID Not In (
SELECT EquipmentID
FROM DownPeriod
);
So consider this situation from the db engine's perspective. Using my version of the Downloads table, it has a set of values (1, 2, Null, and 3) from the subquery. You're asking it to show you the rows from Equipment where EquipmentID is NOT IN that list of values. The db engine will only give you the rows for which that condition is True.
Null is the problem. For each EquipmentID, when it considers whether that value is not present in the subquery set, it doesn't know. That Null is an unknown value ... and the unknown value might be the same as the current EquipmentID it's considering ... or might be something else. But since the db engine doesn't know the real value, it can't evaluate the condition as True, so will not include that row in the result set. The same thing happens for every row in Equipment table ... therefore your query's result set is empty (no rows).
You could get your desired results by excluding Null values from the subquery result set with a WHERE clause like the one below. But I think StuckAtWork's suggestion is a better way to go.
SELECT e.title
FROM Equipment AS e
WHERE
e.EquipmentID Not In (
SELECT EquipmentID
FROM DownPeriod
WHERE EquipmentID Is Not Null
);

Can you explain anyone,how inner query and outer query is working

I want to know how inner and outer query is working?
Please explain me below query
update jobgrade set HIGHSAL=6000
where GRADE in(select grade from JOBGRADE where grade='B');
On a logical level you have to devide the inner and the outer query in 2 steps.
The outcome of the inner query - in your case it is the select grade from JOBGRADE where grade='B' part - will be appointed to the where GRADE in part in the outer query. Be aware that there are more options to achieve an innner/outer architecture ... or (equivalent) mainquery/subquery architecture. Especially the use of the in statement in the outer query is important. You could make use of the = clause but then the inner query (~ subquery) must yield exactly 1 row; not more en not less. Otherwise the
ORA-00913: too many values will be thrown.
Making use of the in statement allows the inner query to yield 0 value, 1 value or more then 1 value. In the end the where GRADE in will be matched with the value or values that are being retrieved from the inner query.
That query says update the jobgrade table and set the HIGHSAL column to a value of 6000 for every row where the value of the GRADE column is in the result set of the IN query.
Since the IN query is finding all of the rows in jobgrade where grade='B' it is just going to return a lot of rows with the value B. It makes no sense to do this.
You should just do this:
UPDATE jobgrade
SET HIGHSAL=6000
WHERE grade='B'
because it is the exact same thing.
I think I get what you're actually asking.
The query for the IN operator won't be affected by the update statement. So if you were updating a field that you filtered on in that query the results would be based on how the table was before the update statement.
I can't find anything to support my theory but I don't believe the query for the IN operator is executed more than once and the WHERE clause would come before the UPDATE clause in the order of operations.