I have class table which references student table.
I write a trigger to +1 amount of exellent_eng when insert >=8 score of English subject but it has error:
Msg 4104, Level 16, State 1, Procedure tr_addExellentEnglishStudent, Line 3 [Batch Start Line 1]
The multi-part identifier "x.exellent_Eng" could not be bound.
I'm using SSMS.
CREATE TRIGGER tr_addExellentEnglishStudent ON dbo.dbo_student AFTER INSERT AS
BEGIN
UPDATE dbo.dbo_class
SET x.exellent_Eng += 1
FROM dbo.dbo_class x
JOIN dbo.dbo_student s ON s.class_id = x.class_id
JOIN dbo.dbo_score c ON c.student_id = s.student_id
WHERE (c.subject_id = 1 AND c.score_id >= 8)
END
Few points to correct here:
I don't think you want your trigger on the dbo_student table, because when you first insert a student they won't have any scores. I think you wanted the trigger on adding a new dbo_score record?
As noted in the comments if you alias the table you are updating you should use the notation update <alias> e.g. update x
You don't prefix the column(s) to update with the table name/alias, SQL Server knows which table you are updating.
You probably want to restrict the update to students affected by using the Inserted pseudo-table.
CREATE TRIGGER tr_addExellentEnglishStudent ON dbo.dbo_score
AFTER INSERT AS
BEGIN
UPDATE x SET
exellent_Eng += 1
FROM dbo.dbo_class x
JOIN dbo.dbo_student s ON s.class_id = x.class_id
JOIN dbo.dbo_score c ON c.student_id = s.student_id
WHERE (c.subject_id = 1 AND c.score_id >= 8)
and c.id in (select id from Inserted)
END
Note: this doesn't consider any of the edge cases which might arise e.g. if you update an existing score from 7 to 8 then technically you would want to increase your excellent_Eng result. Similarly if you delete a score or update it from 8 to 7 you would want to decrease it. For these reasons if can be simpler to re-calculate the absolute result rather than making incremental changes.
Related
I was using below query in sql server to update the table "TABLE" using the same table "TABLE". In sql server the below query is working fine.But in DB2 its getting failed.Not sure whether I need to make any change in this query to work in DB2.
The error I am getting in DB2 is
ExampleExceptionFormatter: exception message was: DB2 SQL Error:
SQLCODE=-204, SQLSTATE=42704
This is my input Data and there you can see ENO 679 is repeating in both round 3 and round 4.
My expected output is given below. Here I am taking the ID and round value from round 4 and updating rownumber 3 with the ID value from rownumber 4.
My requirement is to find the ENO which is exist in both round 3 and round 4 and update the values accordingly.
UPDATE TGT
SET TGT.ROUND = SRC.ROUND,
TGT.ID = SRC.ID
FROM TABLE TGT INNER JOIN TABLE SRC
ON TGT.ROUND='3' and SRC.ROUND='4' and TGT.ENO = SRC.ENO
Could someone help here please. I tried something like this.But its not working
UPDATE TABLE
SET ID = (SELECT t.ID
FROM TABLE t, TABLE t2
WHERE t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3'
) ,
ROUND= (SELECT t.ROUND
FROM TABLE t, TABLE t2
WHERE t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3')
where ROUND='3'
You may try this. I think the issue is you are not relating your inner subquery with outer main table
UPDATE TABLE TB
SET TB.ID = (SELECT t.ID
FROM TABLE t, TABLE t2
WHERE TB.ENO=t.ENO ---- added this
and t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3'
) ,
TB.ROUND= (SELECT t.ROUND
FROM TABLE t, TABLE t2
WHERE TB.ENO=t.ENO --- added this
and t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3')
where tb.ROUND='3'
Try this:
UPDATE MY_SAMPLE TGT
SET (ID, ROUND) = (SELECT ID, ROUND FROM MY_SAMPLE WHERE ENO = TGT.ENO AND ROUND = 4)
WHERE ROUND = 4 AND EXISTS (SELECT 1 FROM MY_SAMPLE WHERE ENO = TGT.ENO AND ROUND = 4);
The difference with yours is that the correlated subquery has to be a row-subselect, it has to guarantee zero or one row (and will assign nulls in case of returning zero rows). The EXISTS subquery excludes rows for which the correlated subquery will not return rows.
I have a data set in which I would like to update a column PREVACCEPTID.
The update is based on the contents of the same table, a sample data is shown below:
The column should be updated after a search to see if station has had previous acceptances and what was this?
If we SELECT all DISTINCT 'ACCEPTID' for station A we would get the below.
I want to use this DISTINCT ACCEPTID to populate 'PREVACCEPTID'.
So whereever I have an entry with for e.g. '142692', I would lookup the sub-table and check if there are exists any previous ACCEPTID s, if that is the case populate with the previous one, in this case '142691' (see after results table as they are populated)
I have tried a few things now, I am getting an error for the below:
UPDATE a
SET a.PREVACCEPTID = (CASE
WHEN COUNT(DISTINCT b.ACCEPTID) = 1
THEN b.ACCEPTID
WHEN COUNT(DISTINCT b.ACCEPTID) > 1
AND b.ACCEPTID <> MIN(a.ACCEPTID)
THEN b.ACCEPTID - 1
END)
FROM dbo.table a
RIGHT JOIN dbo.table b ON b.STATION = a.STATION
AND b.PERIOD = a.PERIOD
AND b.ACCEPTID = a.ACCEPTID
I get this error:
Msg 157, Level 15, State 1, Line 326
An aggregate may not appear in the set list of an UPDATE statement.
The end result is per below:
I think a cte would be better option, but i have never used one.
Thanks in advance.
If I interpret your question and subsequent comments correctly, I assume you want the previous AcceptID to be populated to be last AcceptID for a given set of rows sharing the same Station and Period. Last I assume would be defined by the time components (StackDate and QTime). And, in the case where there is only one row for a given Station and Period, you'd want the Previous AcceptID to be set to be the same as AcceptID for that row.
Under the above conditions, below is a query that will work. Note: Replace table 'Test' with your own table name.
UPDATE t SET PrevAcceptID =
ISNULL(
(SELECT TOP 1 AcceptID
FROM Test t2
WHERE t2.Station = t.Station AND t2.Period = t.Period AND t2.AcceptID < t.AcceptID ORDER BY StackDate DESC, QTime DESC),
AcceptID)
FROM Test AS t
I have a table for bookings (table_b) that has around 1.3M rows. A second table (table_s) is used to note when these rows are needed to be accessed by a separate application.
Currently there are triggers to make a record in table_s but this doesn't help with all existing data.
I believe I need to have a query that selects the rows that exists in table_b but not table_s and then insert a row for each line.
Here is my current syntax but don't think it has been formed correctly
DECLARE #b_id [INT] = 0;
WHILE(1 = 1)
BEGIN
SELECT TOP 10
#b_id = MIN([b].[b_id])
FROM
[table_b] AS [b]
LEFT JOIN
[table_s] AS [s] ON [b].[b_id] = [s].[b_id]
WHERE
[s].[b_id] IS NULL;
IF #b_id IS NULL
BREAK;
INSERT INTO [table_s] ([b_id], [processed])
VALUES (#b_id, 0);
END;
Syntactically everything is fine. But there are some misconceptions present in your query
select top 10 #b_id = MIN(b.b_id)
a variable can hold just one value, even though you select top 10 it will assign single value to variable. Your current approach will loop for each non existing record
I don't think for 1 million records insert we need to split the insert into batches. Try this way
INSERT INTO table_s
(b_id,
processed)
SELECT b_id,
0
FROM table_b AS b
WHERE NOT EXISTS (SELECT 1
FROM table_s AS s
WHERE b.b_id = s.b_id)
I want to update multiple tables and values after inserting values in one table so I created a trigger. It works fine for inserts of one row, but as soon I insert more rows, SQL Server gives me following error:
subquery returned more than 1 value. this is not permitted when the subquery follows = or when the subquery is used as an expression?
Here is my trigger:
CREATE TRIGGER [dbo].[tbl_Sales_ForInsert]
ON [dbo].[SALES]
FOR INSERT
AS
BEGIN
DECLARE #ITEMMODEL varchar(100)
SELECT #ITEMMODEL = ITEM_MODEL FROM inserted
UPDATE SALES
SET PROFIT = TOTAL_PRICE - (SELECT QUANTITY FROM SALES WHERE ITEM_MODEL = #ITEMMODEL) * (SELECT RATE FROM ITEM_DETAILS WHERE ITEM_MODEL = #ITEMMODEL)
WHERE ITEM_MODEL = #ITEMMODEL
UPDATE ITEM_DETAILS
SET QUANTITY = QUANTITY - (SELECT QUANTITY FROM SALES WHERE ITEM_MODEL = #ITEMMODEL)
WHERE ITEM_MODEL = #ITEMMODEL
--UPDATE ITEM_DETAILS SET AMOUNT = AMOUNT - (SELECT RATE FROM ITEM_DETAILS WHERE ITEM_MODEL=#ITEMMODEL) * (SELECT QUANTITY FROM SALES WHERE ITEM_MODEL=#ITEMMODEL) where ITEM_MODEL=#ITEMMODEL
END
As I insert data in SALES table for 1st time the update got successful but for 2nd time it gives me above error remember ITEM_MODEL is foreign key constraint in SALES table.
I have been suffering with this error can anyone help me please?
Your fundamental flaw is that you seem to expect the trigger to be fired once per row - this is NOT the case in SQL Server. Instead, the trigger fires once per statement, and the pseudo table Inserted might contain multiple rows.
Given that that table might contain multiple rows - which one do you expect will be selected here??
SELECT #ITEMMODEL = ITEM_MODEL FROM inserted
It's undefined - you might get the values from arbitrary rows in Inserted.
You need to rewrite your entire trigger with the knowledge the Inserted WILL contain multiple rows! You need to work with set-based operations - don't expect just a single row in Inserted!
So in your case, your trigger code should look something like this:
CREATE TRIGGER [dbo].[tbl_Sales_ForInsert]
ON [dbo].[SALES]
FOR INSERT
AS
BEGIN
-- update the dbo.Sales table, set "PROFIT" to the difference of
-- TOTAL_PRICE and (QUANTITY * RATE) from the "Inserted" pseudo table
UPDATE s
SET s.PROFIT = i.TOTAL_PRICE - (i.QUANTITY * i.RATE)
FROM dbo.Sales s
INNER JOIN Inserted i ON i.ITEM_MODEL = s.ITEM_MODEL
-- update the dbo.ITEM_DETAILS table
UPDATE id
SET id.QUANTITY = id.QUANTITY - i.Quantity
FROM dbo.ITEM_DETAILS id
INNER JOIN Inserted i ON id.ITEM_MODEL = i.ITEM_MODEL
END
Marc_s is right about expecting the inserted pseudo table containing more than one row. There are instances that a query might work if a subquery was just limited to one row with a TOP(1).
UPDATE SALES
SET PROFIT = TOTAL_PRICE - (SELECT TOP(1) QUANTITY FROM SALES WHERE ITEM_MODEL = #ITEMMODEL)
* (SELECT TOP(1) RATE FROM ITEM_DETAILS WHERE ITEM_MODEL = #ITEMMODEL)
WHERE ITEM_MODEL = #ITEMMODEL
I have been searching around stackoverflow but I have not found what I'm looking for.
I have a Sql Server Database. One table with a field "Priority" I would like to update on every insert or update.
The problem is that I want to perform a Priority pile using this rules:
1.-If the value I try to insert has a prority value that already exists then every consecutive row in the table must change its priority value adding 1.
2.-If the value I try to insert has a priority that not exists then the trigger does nothing.
This is the trigger I haver built:
ALTER trigger [Priority]
on [dbo].[TBL_PILA]
after insert, update
AS
declare #priority int;
declare #reg_id int;
SELECT #reg_id =i.id from inserted i;
SELECT #priority =PRIORITY from TBL_PILA where ID =#reg_id
-- perform update here in TBL_PILA table
UPDATE TBL_PILA SET PRIORITY=PRIORITY+1 WHERE ID <>#reg_id AND PRIORITY>=#priority
GO
Edit: As Suggestions, I change the trigger body like this:
ALTER trigger [Priority]
on [dbo].[TBL_PILA]
after insert, update
if exists (select *
from inserted i join TBL_PILA m
on i.ID = m.ID
)
update TBL_PILA set PRIORITY = PRIORITY + 1
where exists (select * from inserted i
join TBL_PILA m
on i.ID = m.ID
where m.PRIORITY>=i.PRIORITY)
Now I have a new problem: the priority value inserted is affected by the trigger and it is added 1 too.
Does anybody knows how to increase priority values only affecting some range as I explained below?
The problem is whenever exists a few consecutive values and one not consecutive value the trigger must stops.
Example
Priority 1 2 4 5 6 8
If I try to insert a row with priority=3 the result should be:
1 2 3 4 5 6 8
Then If I try to insert a row with priority=4 then the result should be:
1 2 3 4 (inserted value) 5 (4+1) 6 (5+1) 7 (6+1) 8
But using the trigger I built I get this: 1 2 3 4 5 6 7 9 (8+1)