Prevent column change without the other - sql

No-one should be allowed to update the customer address column unless the postcode column is also updated. If an attempt is made to update one without the other, then a trigger will fire and the user will be shown an error message.
Any help on how I can do this in Microsoft SQL Server 2012 will be appreciated!

You can use below logic
CREATE TRIGGER [dbo].AU_MyTrigger ON [dbo].MyTable
FOR UPDATE
AS
BEGIN
declare #bu_addr varchar(100)
declare #bu_zip varchar(100)
declare #au_addr varchar(100)
declare #au_zip varchar(100)
select #bu_addr = addr, #bu_zip = zip from DELETED
select #au_addr = addr, #ay_zip = zip from INSERTED
if (#bu_addr <> #au_addr) and (#bu_zip = #au_zip)
BEGIN
-- update table with old values
-- raise error
END
END
Note that if this update can happen in batch, you need to loop through each record and update their value to old and only return error at the end of trigger (outside of loop). In that case, for iterating on updated rows, you need to use CURSOR
You case might not be as easy as I explained, but this is the approach that works.

Related

SQL Server Trigger Variable scope

Could you please tell me what's wrong this this trigger (below is just a portion of the trigger).
When put variable on where parameter I don't get any result, instead, when I set is a default value I get correct result
Like this it doesn't work (I verified and #Cont_local is not null and data really exists inside the database):
Note:
info (information) is in a different table but on the same database.
the trigger is set to work on Cont (Contact) Table
select #Cont_local = ContID from inserted
SET #Addr = (select Addr from Info I where I.ContID = #Cont_local)
But like this, it works
select #Cont_local = '454877'
SET #Addr = (select Addr from Info I where I.ContID = #Cont_local)
While #Cont_local is returning some values, the select statement cannot detect it.
Is this related to the scope of #Cont_local variable or something else?
Instead, when I try to put data manually, query return values and store it on #Addr
Here is Complete code
ALTER TRIGGER [dbo].[Insert__]
ON [dbo].[Cont]
AFTER INSERT
AS
BEGIN
DECLARE #Cont_local nvarchar(50);
DECLARE #Name nvarchar(50);
DECLARE #firstnameme nvarchar(50);
DECLARE #Addr nvarchar(50);
select #Name = contName from inserted
select #firstname = contfirstname from inserted
select #Cont_local = ContID from inserted
SET #Addr = (select Addr from Info I where I.ContID = #Cont_local)
INSERT INTO Final_Contact (Name, firstname, address) values
(#Name, #firstname ,#Addr)
END
select #Cont_local = ContID from inserted
This line of code works only when in the inserted-table is only one record
This addresses the original version of the question.
I don't see why your code would return an error. However, it is malformed and an error waiting to happen. Let me explain.
This code:
select #Cont_local = ContID from inserted
Assumes that inserted has one row. Of course, the code runs when inserted has more than one row. It just returns one value.
The inserted and deleted views in SQL Server triggers can refer to multiple rows. In other words, triggers are set-based processing rather than row-by-row processing. In a properly structured trigger, the references should always be in FROM clauses.
The following example is totally made up, but it illustrates how to update a column in another table using information from inserted:
update a
set addr = c.addr
where inserted i join
info i
on i.contid = a.contid join
addresses a
on a.addrid = i.addrid

SQL Server : create trigger to replace old value to new value on another table

I am using SQL Server 2008. I want to create a trigger for update which will fire on update of user table.
Trigger functionality: replace user_tbl updated mobile number to user_work_tbl.
CREATE TRIGGER [dbo].[tr_User_Modified]
ON [dbo].[user_tbl]
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
DECLARE #MobileNo varchar(11)
IF UPDATE (mobile_no)
BEGIN
DECLARE #MobileNo VARCHAR(50)
SELECT #MobileNo = mobile_no
FROM [dbo].user_tbl
UPDATE [dbo].[user_work_tbl]
SET mobile_no = #MobileNo
WHERE [dbo].[user_work_tbl].mobile_no = #oldMobileNo // here I have a problem
END
END;
In the comment "here I have a problem" I need a mobile number which exists in user_tbl before update so that the only row of user_work_tbl gets updated.
Any suggestions to do this are also accepted.
Thanks for your all response
You need to join three tables together in your trigger - user_work_tbl, inserted and deleted. However, its not clear at the moment exactly what conditions are required:
CREATE TRIGGER [dbo].[tr_User_Modified]
ON [dbo].[user_tbl]
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
IF UPDATE (mobile_no)
BEGIN
UPDATE u
SET mobile_no=i.mobile_no
FROM user_work_tbl u
inner join
deleted d
on u.mobile_no = d.mobile_no
inner join
inserted i
on
i.PKCol = d.PKCol --What's the PK of user_tbl?
END
END;
inserted and deleted are pseudo-tables that contain the new and old rows that were affected by a particular statement, and have the same schema as the original table. They're only accessible from within the trigger.
Note, also, that the above trigger is correct, even when multiple rows are updated in user_tbl - provided you can correctly relate inserted and deleted in the final ON clause.
You can get the old phone number from the table deleted and the new one from inserted, but you should use user primary key the update the rows.

How to create a trigger to decrease a counter, what's wrong with my trigger?

I need to decrease a counter in a table schedules, when there was an insert in enrollments table:
CREATE TRIGGER [UpdateEnrollmentsTrigger]
ON [TBLENROLLMENT_ENR]
FOR INSERT
AS
BEGIN
DECLARE #ScheduleCode NVARCHAR
DECLARE #TotalSlots INT
IF EXISTS(SELECT SCH_CODE FROM inserted)
BEGIN
SELECT #ScheduleCode = SCH_CODE FROM inserted
SELECT #TotalSlots = SCH_TOTALSLOTS FROM TBLSCHEDULES_SCH
WHERE SCH_CODE = #ScheduleCode
UPDATE TBLSCHEDULES_SCH
SET SCH_FREESLOTS = #TotalSlots - 1
WHERE SCH_CODE = #ScheduleCode
END
END
When I trying to create this trigger, the query window of VS12 says:
SQL46010 :: Incorrect syntax near ].
Thanks in advance.
The specific error is because you are using FOR INSERT instead of AFTER INSERT, but there are other things that you should improve on your trigger.
First of all, always, always write the length of a NVARCHAR, leaving it blank will behave differently depending where it's used. So replace DECLARE #ScheduleCode NVARCHAR with DECLARE #ScheduleCode NVARCHAR(n), where n is the required length.
I'm also not sure why you are doing the IF EXISTS since it's reading the INSERTED pseudo table, that it's bound to have records because the trigger was fired.
Another thing to improve is that you are assuming that only one row was inserted, as you are storing it on a variable, that's wrong and it will behave incorrectly if you insert more than just one row.
Oh, I almost forgot, you should also always specify the schema, for instance: CREATE TRIGGER [UpdateEnrollmentsTrigger] ON [TBLENROLLMENT_ENR] should be CREATE TRIGGER dbo.[UpdateEnrollmentsTrigger] ON dbo.[TBLENROLLMENT_ENR] (using the correct schema, of course)

Trigger on update of an attribute of a table in SQL Server?

I created computer audit application. When I ran my application, it shows computer accessories on browser like computerName, osVersion, lastAudit, model, totalMemory, processor, userName.
I have created a database in SQL Server 2008 with one table Computers. When a value is inserted into that table, I need to update the table value in the column. In an attempt to try this, I'm using a trigger. However, I do not fully understand how triggers work.
Can someone please show me how to accomplish this.
My table has these columns:
id, computerName, osVersion, lastAudit, model, totalMemory, processor, userName
I know that in this code something wrong or missing but I am not able to complete this. Please help me in this regard.
CREATE TRIGGER update_trigger
ON computers
AFTER UPDATE
AS
BEGIN
declare #id as int
declare #computerName as varchar(100)
declare #osVersion as varchar(100)
declare #lastAudit as datetime
declare #model as varchar(100)
declare #totalMemory float
declare #processor as varchar(100)
declare #userName as varchar(100)
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
if update(id)
BEGIN
insert into computers values(#id,#computerName,#osVersion,#lastAudit,#model,
#totalMemory,#processor,#userName,'Update')
SET NOCOUNT ON;
END
GO
If you want to simply update one or more columns of your existing table when new rows are being inserted (or when they are updated? Not quite clear...), try a trigger like this:
CREATE TRIGGER trigUpdateTable
ON dbo.Computers
AFTER INSERT -- or AFTER UPATE or AFTER INSERT, UPDATE
AS
BEGIN
-- do whatever you want to do on INSERT and/or UPDATE
UPDATE
dbo.Computers
SET
LastAudit = GETDATE()
FROM
dbo.Computers c
INNER JOIN
Inserted i ON c.id = i.id
One very important point to remember: SQL Server triggers are not called per row that is affected - but per statement, and if your INSERT or UPDATE statement affects multiple rows, you'll have multiple entries in the Inserted pseudo table and you need to be able to deal with that fact in your trigger

SQL Trigger to update row

I need a SQL trigger that would zero pad a cell whenever its inserted or updated. Was curious if its best practice to append two strings together like I'm doing in the update command. Is this be best way to do it?
CREATE TRIGGER PadColumnTenCharsInserted ON Table
AFTER INSERT
AS
DECLARE
#pad_characters VARCHAR(10),
#target_column NVARCHAR(255)
SET #pad_characters = '0000000000'
SET #target_column = 'IndexField1'
IF UPDATE(IndexField1)
BEGIN
UPDATE Table
SET IndexField1 = RIGHT(#pad_characters + IndexField1, 10)
END
GO
Your padding code looks fine.
Instead of updating every row in the table like this:
UPDATE Table
update just the row that triggered the trigger:
UPDATE updated
Also, you've still got some extraneous code -- everything involving #target_column. And it looks like you're not sure if this is an INSERT trigger or an UPDATE trigger. I see AFTER INSERT and IF UPDATE.
Two questions:
What are you doing with #target_column? You declare it and set it with a column name, but then you never use it. If you intend to use the variable in your subsequent SQL statements, you may need to wrap the statements in an EXECUTE() or use sp_executesql().
The syntax "UPDATE Table..." is OK for your update statement assuming that "Table" is the name of the table you are updating. What seems to be missing is a filter of some kind. Or did you really intend for that column to be updated for every row in the whole table?
One way to handle this would be to declare another variable and set it with the PK of the row that is updated, then use a where clause to limit the update to just that row. Something like this:
DECLARE #id int
SELECT #id = Record_ID FROM INSERTED
-- body of your trigger here
WHERE Record_ID = #id
I like your padding code. It looks good to me.