I have a SQL Server database with users. I want to keep one specific user from changing his picture. I don't believe there is a way to make a single cell immutable but is there a way to create a trigger that is called so that whenever this person changes his picture (newpicture.jpg), the UPDATE gets either rolls back or the data value is changed by to the desired value (justin.jpg)?
I'm not a SQL expert but this is what I have so far
CREATE TRIGGER justin ON Users
AFTER UPDATE
AS
IF EXISTS (SELECT ImagePath from Users WHERE Id = '[justin's id]')
BEGIN
ROLLBACK TRANSACTION;
RETURN
END;
GO
The problem with this is that it just checks if the specific user already has a picture, and then keeps the entire table (and not just that specific user) from updating.
In short, I just want to keep my friend, Justin, from being able to change his current picture, which is of him drinking out of a juice box. Thank you in advance for your suggestions.
If you just want to restrict this specific user from having any ImagePath value other than a predefined one, then you can simply use a CHECK CONSTRAINT:
ALTER TABLE Users
ADD CONSTRAINT CHK_Justin
CHECK ( ([UserId] <> 'Justin') OR
([UserId] = 'Justin') AND (ImagePath = '/images/fixedPic.jpg'))
Instead of Rolling back the whole transaction just update after his update:
CREATE TRIGGER justin
ON Users
AFTER UPDATE
AS
BEGIN
UPDATE Users
SET [ImagePath] = '/images/fixedPic.jpg'
WHERE [UserId] = '[justins id]'
END;
GO
Related
I am new to triggers, I am trying one that would let me insert the reasons for the update into a log table after another table was updated updated. The problem is that I am trying to make the user type an input as it would do in a stored procedure but that doesn't work with triggers apparently.
Let's say we have the table, Users:
User ID | User
--------+-------
1 John
The result I want is the following:
Log_ID | Reason_Change
-------+------------------------------------------
1 John wanted to change his name to John25
Is that possible?
I am trying:
#Reason_Change VARCHAR(500)
In SQL Server, you can do this with an instead of trigger on a view. The idea is the following:
Create a view that contains the columns from users along with the change reason.
Define an instead of trigger on the view. This will allow an insert to include the change reason.
Only use the view for inserts.
Then, you can include the reason in the insert. The trigger would put all the other columns in users and update the logs table appropriately.
Such triggers are explained in the documentation.
In my asp.net mvc application , I use Sql Data Adapter to update a record.
For example
UPDATE sample SET status = 1 WHERE id = #id
I need to test a scenerio where this sql code cannot be run and not any records are updated. How can i make this?
Should i make a lock for sample table and how can i do that ?
How can i make this UPDATE query somehow not works and not updates any record ?
Forgot to note that: I cannot change this code or application code and cannot give random #id parameter.
I need to do that in database level.
You can make the specific table in database read only by using one of the below techniques.
Insert, Update, Delete Trigger
Check Constraint and Delete Trigger
Make the Database Read Only
Put the Table in a Read Only File Group
DENY Object Level Permission
Create a View
You could set id to a value that does not exist for sure (e.g. -1).
Or you could remove the user rights of the user accessing the database (in the connection string) for updating this table. Hoping it's not sa :)
Add an [Authorize] attribute to the controller in question and attempt to perform the operation as a guest user.
Edit. To do it server side, enter the following to a query window on the database
Begin Transaction
That should lock up the database while you do your tests
I am tryign to create a trigger which will update a table so that when something is inserted into the table the given end date will change to set to the day before the start date of the new entry. i have created this trigger which complies but when checking it doesn't work. can anyone see the porblem with it?
CREATE TRIGGER
updatetrigger12345
BEFORE INSERT ON
shares_amount
FOR EACH ROW
BEGIN
UPDATE OF
shares_amount
SET
date_end = :NEW.date_start-1
WHERE
share_issue_id = :NEW.share_issue_id
AND
share_id= :NEW.share_id
;
END
;
/
Bad, bad, bad. You do not want to attempt to update the table on whose trigger is being executed. You just need to update the ":new" fields of interest. Maybe something like this:
CREATE TRIGGER
updatetrigger12345
BEFORE INSERT ON
shares_amount
FOR EACH ROW
BEGIN
:NEW.date_end := :NEW.date_start-1;
END
;
/
Here is a tutorial. In addition, I would try to really stay away from using trigger if not needed. There certainly are situations when they make sense; however, they can be abused and cause a lot of confusion and problems down the road. Please read this classic AskTom article The Trouble With Triggers.
This is probably laughably easy for an SQL expert, but SQL (although I can use it) is not really my thing.
I've got a table in a DB. (Let's call it COMPUTERS)
About 10.000 rows. 25 columns. 1 unique key: Column ASSETS.
Occasionally an external program will delete 1 or more of the rows, but isn't supposed to do that, because we still need to know some info from those rows before we can really delete the items.
We can't control the behavior of the external application so we came up with a different idea:
We want to create a second identical table (COMPUTERS_BACKUP) and initially fill this with a one-on-one copy of COMPUTERS.
After that, once a day copy new records from COMPUTERS to COMPUTERS_BACKUP and update those records in COMPUTERS_BACKUP where the original in COMPUTERS has changed (ASSETS column will never change).
That way we keep the last state of a record deleted from COMPUTERS.
Can someone supply the code for a stored procedure that can be scheduled to run once a day? I can probably figure this out myself, but it would take me several hours or so and I'm very pressed for time.
just create a trigger for insert computers table
CREATE TRIGGER newComputer
ON [Computers]
AFTER INSERT
Begin
INSERT INTO COMPUTERS_BACKUP
SELECT * FROM Inserted
End
It'll work when you insert new computer to computers table and it'll also insert the record to bakcup table
When you update computers you could change computers backup too with update trigger
CREATE TRIGGER newComputer
ON [Computers]
AFTER UPDATE
Begin
//can access before updating the record through SELECT * FROM Deleted
//can access after updating the record through SELECT * FROM Inserted
UPDATE Computers_BACKUP SET
(attributes) = inserted.(attribute)
WHERE id = inserted.id
End
At the end I guess you don't want to delete the backup when original record is deleted from computers table. You can chech more examples from msdn using triggers.
When a record removed from computers table
CREATE TRIGGER computerDeleted ON [Computers] AFTER DELETE
Begin
INSERT INTO Computers_BACKUP
SELECT * FROM Deleted
End
Besides creating triggers, you may look into enabling Change Data Capture, which is available in SQL Server Enterprise Edition. It may be an overshot, but it should be mentioned and you may find it useful for other tables and objects.
IMHO a possible solution, if you never delete records (only update) from that table in your application, can be to introduce an INSTEAD OF DELETE trigger
CREATE TRIGGER tg_computers_delete ON computers
INSTEAD OF DELETE AS
DELETE computers WHERE 1=2;
It will prevent the deletion of the records.
Here is SQLFiddle demo.
A trigger for Before Delete event can help you to guard this table:
CREATE TRIGGER backup_row_before_delete ON COMPUTERS_Table FOR Delete
as
INSERT INTO Computers_Backup
SELECT deleted.* from deleted
You can change deleted.* for deleted.col1, deleted.col2 if you want to keep certain columns only.
will delete 1 or more of the rows, but isn't supposed to do that
Then you have permission and integrity issues.
You can most certainly use a trigger to record deletions (and updates of course) but I would not recommend you use it purely to keep a copy of stuff you didn't want deleted in the first place!
Remove delete permissions if you have to or beef up your data integrity if you can. Without your schema it's hard to tell exactly how though.
Finally, use your (INSTEAD OF) trigger to check whatever conditions you need to prevent the delete when appropriate.
How do I find out what application or SP is modifing the values in a config table? I thought I had isolated the app that was responsible but these particular values keep chnging back to true when I keep modifying them to be false.
First, create a logging table:
CREATE TABLE modlog(
datestamp smalldatetime,
username varchar(255) NOT NULL DEFAULT SYSTEM_USER
);
Then create an UPDATE trigger on your table:
CREATE TRIGGER mytable_mods ON mytable FOR UPDATE AS
INSERT INTO modlog(smalldatetime) VALUES (GETDATE());
Just peek into the modlog table to figure out which user is updating the table, and when. You could get fancy and also log particular fields being updated.
Another approach would be to set up a trace in SQL Server Profiler, filter the heck out of it so it only returns updates on that table, and keep it open until something happens.
If your applications include the ApplicationName parameter in their connection strings, you can use App_Name() instead of SYSTEM_USER, which will log the application name, removing the extra detective work. Knowing the user might still be useful so you can figure out what they are doing to trigger the update.
Create a trigger to roll back the update. Wait for the app to error out. It can be a very simple trigger:
CREATE TRIGGER BugOffRogueProgram
ON MyConfigTable
FOR UPDATE
AS
BEGIN
ROLLBACK TRAN
END
The answers provided so far are absolutely on the spot - that's the way to do it in SQL Server 2005.
Just as a brief teaser: in SQL Server 2008, there's a new feature called Change Data Capture to support this exact scenario "out of the box" without the need to write triggers and update tables yourself. Quite handy!
Marc