SQL - Add Data to Existing Data From Another Table - sql

I have a temp table #table in my stored procedure that looks like this:
AgtID | Bonus
-------------
5063 | 0
1104 | 0
And a table bonus that looks like this:
AgtID | Contest | Points | Event
--------------------------------
5063 | 21 | 1000 | 1
5063 | 21 | 3000 | 3
1104 | 21 | 1000 | 1
1104 | 21 | 500 | 2
And an update query (currently) like thus:
UPDATE tt
SET Bonus = b.Points
FROM #table tt
INNER JOIN tblContestData_Bonus b
ON tt.AgtID = b.AgtID
where ContestID = 21;
Currently, when I run this query, it'll overwrite whatever data is in #table.Bonus with the data in bonus.Points. This is fine for a single record, but as we start getting more bonus point events, I need to have it add to my value.
I know some languages have a i += value... does SQL have something similar?

I figured it out right after posting. Funny how that works. What I did:
UPDATE tt
SET Bonus = coalesce(
(select SUM(Points) as Points
from bonus b
where b.AgtID = tt.AgtID
and ContestID = 21
group by AgtID),0)
FROM #table tt;
Using the coalesce() to account for null values to math in following steps works fine even if there are no records.

I might be missing what you're after here, but you can add the existing value to the new value in an UPDATE:
UPDATE tt
SET Bonus = b.Points + Bonus
FROM #table tt
INNER JOIN tblContestData_Bonus b
ON tt.AgtID = b.AgtID
where ContestID = 21;

To do this properly in SQL, you need to pre-aggregate b. You cannot update a single record multiple times, so an update will does not accumulate when there are multiple matches. It only updates on (arbitrary) record.
Something like this will take all the bonus points and add them in:
UPDATE tt
SET Bonus = coalesce(tt.Bonus, 0) + b.Points
FROM #table tt INNER JOIN
(select agtId, sum(points) as points
from tblContestData_Bonus b
group by abtId
) b
ON tt.AgtID = b.AgtID
where ContestID = 21;

Related

How to fill the missing data from a row based on a similar row in the same table postgresql

Hey guys a bit of a novice question.
I have a table with the following inputs
Location in row 1 and row 4 in the table are the same however row 1 is missing code which should also be A.
i.e. the desired results should be
I tried
UPDATE sales AS dst
SET dst.code = src.code
FROM sales AS src
WHERE dst.location = src.location
AND dst.location <> '' AND src.location = ''
;
but to no avail
here you have two possibilities how to resolve your problem
CREATE TABLe sales (location int, code varchar(10))
INSERT INTO sales VALUEs (1,NULL),(2,'B'),(3,'c'),(1,'A')
4 rows affected
UPDATE sales s1
SET code = (SELECT MIN(code) FROM sales s2 WHERE s1.location = s2.location AND s2.location IS NOT NULL)
4 rows affected
SELECT * FROM sales
location | code
-------: | :---
1 | A
2 | B
3 | c
1 | A
CREATE TABLe sales2 (location int, code varchar(10))
INSERT INTO sales2 VALUEs (1,NULL),(2,'B'),(3,'c'),(1,'A')
4 rows affected
Update sales2
SET code = src.code
FROM sales2 as src
WHERE src.location = sales2.location and sales2.code is NULL AND src.code IS NOT NULL
;
1 rows affected
SELECT * FROM sales2
location | code
-------: | :---
2 | B
3 | c
1 | A
1 | A
db<>fiddle here
I'm almost hesitant to offer this up because it assumes a lot, but just to answer your specific question, I think this is what you want:
UPDATE sales AS dst
SET code = src.code
FROM sales AS src
WHERE
dst.location = src.location AND
dst.code is null and
src.code is not null
I think in your code you mixed up code and location, so on the last two lines you used "location" when you meant "code."
In addition you are likely confusing nulls with empty spaces. I assume the data is null and not containing an empty space. It's possible that assumption is wrong.
Also, don't use the alias on the set. It's implicit.

SQL - Set column value to the SUM of all references

I want to have the column "CurrentCapacity" to be the SUM of all references specific column.
Lets say there are three rows in SecTable which all have FirstTableID = 1. Size values are 1, 1 and 3.
The row in FirstTable which have ID = 1 should now have a value of 5 in the CurrentCapacity column.
How can I make this and how to do automatically on insert, update and delete?
Thanks!
FirstTable
+----+-------------+-------------------------+
| ID | MaxCapacity | CurrentCapacity |
+----+-------------+-------------------------+
| 1 | 5 | 0 (desired result = 5) |
+----+-------------+-------------------------+
| 2 | 5 | 0 |
+----+-------------+-------------------------+
| 3 | 5 | 0 |
+----+-------------+-------------------------+
SecTable
+----+-------------------+------+
| ID | FirstTableID (FK) | Size |
+----+-------------------+------+
| 1 | 1 | 2 |
+----+-------------------+------+
| 2 | 1 | 3 |
+----+-------------------+------+
In general, a view is a better solution than trying to keep a calculated column up-to-date. For your example, you could use this:
CREATE VIEW capacity AS
SELECT f.ID, f.MaxCapacity, COALESCE(SUM(s.Size), 0) AS CurrentCapacity
FROM FirstTable f
LEFT JOIN SecTable s ON s.FirstTableID = f.ID
GROUP BY f.ID, f.MaxCapacity
Then you can simply
SELECT *
FROM capacity
to get the results you desire. For your sample data:
ID MaxCapacity CurrentCapacity
1 5 5
2 5 0
3 5 0
Demo on SQLFiddle
Got this question to work with this trigger:
CREATE TRIGGER UpdateCurrentCapacity
ON SecTable
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON
DECLARE #Iteration INT
SET #Iteration = 1
WHILE #Iteration <= 100
BEGIN
UPDATE FirstTable SET FirstTable.CurrentCapacity = (SELECT COALESCE(SUM(SecTable.Size),0) FROM SecTable WHERE FirstTableID = #Iteration) WHERE ID = #Iteration;
SET #Iteration = #Iteration + 1
END
END
GO
Personally, I would not use a trigger either or store CurrentCapacity as a value since it breaks Normalization rules for database design. You have a relation and can already get the results by creating a view or setting CurrentCapacity to a calculated column.
Your view can look like this:
SELECT Id, MaxCapacity, ISNULL(O.SumSize,0) AS CurrentCapacity
FROM dbo.FirstTable FT
OUTER APPLY
(
SELECT ST.FirstTableId, SUM(ST.Size) as SumSize FROM SecTable ST
WHERE ST.FirstTableId = FT.Id
GROUP BY ST.FirstTableId
) O
Sure, you could fire a proc every time a row is updated/inserted or deleted in the second table and recalculate the column, but you might as well calculate it on the fly. If it's not required to have the column accurate, you can have a job update the values every X hours. You could combine this with your view to have both a "live" and "cached" version of the capacity data.

Update column in one table for a user based on count of required records in another table for same user without cursor

I have 2 tables A and B. I need to update a column in table A for all userid's based on the count of records that userid has in another table based on defined rules. If count of records in another table is 3 and is required for that userID, then mark IsCorrect as 1 else 0, if count is 2 and required is 5 then IsCorrect as 0 For e.g. Below is what I am trying to achieve
Table A
UserID | Required | IsCorrect
----------------------------------
1 | SO;GO;PE | 1
2 | SO;GO;PE;PR | 0
3 | SO;GO;PE | 1
Table B
UserID | PPName
-----------------------
1 | SO
1 | GO
1 | PE
2 | SO
2 | GO
3 | SO
3 | GO
3 | PE
I tried using Update in table joining another table, but cannot up with one. Also, do not want to use cursors, because of its overhead. I know I will have to create a stored Procedure for it for the rules, but how to pass the userID's to it without cursor is what am i am looking for.
This is an update for my earlier question. Thanks for the help.
Here's a solution for PostgreSQL:
update TableA
set IsCorrect =
case when
string_to_array(Required, ';') <#
(select array_agg(PPName)
from TableB
where TableA.UserID = TableB.UserID)
then 1
else 0
end;
You can also see it live on SQL Fiddle.
use sub-query and aggregate function and then case when for conditional update
update TableA A
set A.IsCorrect= case when T.cnt>=3 then 1 else 0 end
inner join
(
select B.UserID ,count(*) as cnt from TableB as B
group by UserID
) as T
on A.userid=T.UserID

MS Access Update Table with data being aggregated in query

I have a table in Access 2010, that I am trying to update the TotalDiary column with data from a query.
DiaryDt | EEID | EEName | EESpvrsID | OutOfDiary | TotalDiary
1/2/14 | 123 | phis | text | 5 |
I'm sure this is simplier than I am making it out to be, but I cannot get it to work. My query below is the data that needs updated into the TotalDiary column...
SELECT
a.TotalDiary, b.EEID
FROM ((
SELECT
e.EEID, COUNT(c.CaseID) as TotalDiary
FROM ((dbo_Case c
LEFT JOIN dbo_Employee e ON e.EEID = c.CaseEEID)
LEFT JOIN Auto_DailyDiary_PrimaryTbl a ON a.EEID = e.EEID)
WHERE c.CaseStatus <> 6
AND a.DiaryDt = Date()
GROUP BY e.EEID
) a
LEFT JOIN Auto_DailyDiary_PrimaryTbl b ON b.EEID = a.EEID)
WHERE b.DiaryDt = Date()
I need for the Update Query to Set TotalDiary = a.TotalDiary Where b.EEID = TableToUpdate.EEID
Any help would be appreciated.
Thanks.

DB2 large update from another table

I have a table with 600 000+ rows called asset. The customer has added a new column and would like it populated with a value from another table:
ASSET TEMP
| id | ... | newcol | | id | condition |
--------------------- ------------------
|0001| ... | - | |0001| 3 |
If I try to update it all at once, it times out/claims there is a dead lock:
update asset set newcol = (
select condition from temp where asset.id = temp.id
) where newcol is null;
The way I got around it was by only doing a 100 rows at a time:
update (select id, newcol from asset where newcol is null
fetch first 100 rows only) a1
set a1.newcol = (select condition from temp a2 where a1.id = a2.id);
At the moment I am making good use of the copy/paste utility, but I'd like to know of a more elegant way to do it (as well as a faster way).
I have tried putting it in a PL/SQL loop but I can't seem to get it to work with DB2 as a standalone script.