SQL Server 2008 R2: Trigger on `TEXT` column - sql

I have the table which consist of column with datatype text.
Table EmployeeMaster
CREATE TABLE [EmployeeMaster]
(
EmpID int identity(1,1),
EmpName varchar(20),
EmpPhone int,
EmpAddress TEXT
);
And I want to create audit log on this table.
Audit Table: EmployeeMaster_Audit
CREATE TABLE [EmployeeMaster_Audit]
(
EmpID int,
EmpName varchar(20),
EmpPhone int,
EmpAddress VARCHAR(MAX)
);
Writing trigger for INSERT.
Trigger:
CREATE TRIGGER [dbo].[EmployeeMaster_Insert]
ON [dbo].[EmployeeMaster]
FOR INSERT
AS
INSERT INTO [dbo].[EmployeeMaster_Audit]
([EmpID], [EmpName], [EmpPhone], [EmpAddress])
SELECT CONVERT(int,[EmpID]) as [EmpID],[EmpName],[EmpPhone],CONVERT(varchar(max),[EmpAddress]) AS [EmpAddress] FROM INSERTED
GO
Error Details: While creating trigger getting following error:
Cannot use text, ntext, or image columns in the 'inserted' and 'deleted' tables.
My Try: CONVERT(varchar(max),[EmpAddress])

Since the trigger is fired after the insert, you can simply query back to the EmployeeMaster to get the inserted data. Something like this:
CREATE TRIGGER [dbo].[EmployeeMaster_Insert]
ON [dbo].[EmployeeMaster]
FOR INSERT
AS
INSERT INTO [dbo].[EmployeeMaster_Audit] ([EmpID], [EmpName], [EmpPhone], [EmpAddress])
SELECT EM.[EmpID]
, EM.[EmpName]
, EM.[EmpPhone]
, CONVERT(varchar(max), EM.[EmpAddress]) AS [EmpAddress]
FROM INSERTED I
INNER JOIN dbo.[EmployeeMaster] EM
ON EM.[EmpID] = I.[EmpID]
GO
This is assuming you cannot change the text datatype, see Zohar's answer.

The correct solution to the problem would be to replace the text column with a varchar(max) column.
The Image, Text, and nText data types are deprecated since 2008 version introduced varbinary(max), varchar(max) and nvarchar(max).
For more information, read Microsoft official documentation page on ntext, text, and image (Transact-SQL):
IMPORTANT! ntext, text, and image data types will be removed in a future version of SQL Server. Avoid using these data types in new development work, and plan to modify applications that currently use them. Use nvarchar(max), varchar(max), and varbinary(max) instead.

Related

How to properly create an insert trigger with SQL Server

I am trying to create a trigger to send INSERT information from base table (Hub) to a log table.
The Log table contains the following columns:
ChangeID, Date, User, Table, Action, Description
The Hub table has 3 columns:
Date, Mat, Hub
I'm using this T-SQL code for my trigger:
CREATE TRIGGER tg_test
ON Hub
FOR INSERT
AS
BEGIN
DECLARE #sys_usr CHAR(30);
SET #sys_usr = SYSTEM_USER;
SET NOCOUNT ON;
INSERT INTO Logs_Table (Date, User, Table, Action, Description)
SELECT
(CURRENT_TIMESTAMP,
SYSTEM_USER,
'Hub',
'INSERT',
CONCAT('Mat: ', i.Mat, '; Hub: ', i.Hub))
FROM
INSERTED AS i;
The Logs_Table was created with following SQL:
CREATE TABLE Logs_Table
(
ChangeID INT IDENTITY PRIMARY KEY,
Date DATETIME,
User VARCHAR(200),
Table VARCHAR(200),
Action VARCHAR(100),
Description VARCHAR(MAX)
)
When I try to run the command to execute the query to create the trigger I get the following error:
ProgrammingError: (102, Incorrect syntax near ','.
DB-Lib error message 20018, severity 15:
General SQL Server error: Check messages from the SQL Server
Does anybody know where that syntax error is?
You shouldn't have ( and ) around the list of columns in your SELECT.
INSERT dbo.Logs_Table([Date], [User], [Table], Action, Description)
SELECT -- remove this (
CURRENT_TIMESTAMP,
SYSTEM_USER,
'Hub',
'INSERT',
CONCAT('Mat: ', i.Mat, '; Hub: ', i.Hub) -- remove this )
FROM INSERTED AS i;
Next, your trigger has a BEGIN but seems to be missing an END.
You should also try to avoid using generic and reserved words like Date, User, and Table for column names, and always use schema prefix. It also might make sense to apply defaults to the columns in the log table that take built-in functions, so you don't have to reference them in the trigger at all.
CREATE TABLE dbo.Logs_Table
(
ChangeID INT IDENTITY PRIMARY KEY,
[Date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
[User] VARCHAR(200) NOT NULL DEFAULT SYSTEM_USER,
[Table] VARCHAR(200),
Action VARCHAR(100),
Description VARCHAR(MAX)
);
This really simplifies the insert in your trigger. A couple of other comments, [User] and [Table] should really be nvarchar, and I was lazy but default constraints should be named.

How do I get the user that deleted a record?

I'm trying to create a history table that stores deleted records as well as user that deleted the record. I know how to store the records but not the user.
The table definition looks like this:
CREATE TABLE HistoryComics(
Id INT IDENTITY PRIMARY KEY,
ComicId INT,
Title NVARCHAR(50),
Author NVARCHAR(50),
[Description] TEXT,
Issue INT,
Publisher VARCHAR(20),
CoverPage VARBINARY(MAX),
DateDeleted DATETIME DEFAULT SYSDATETIME(),
DeletedBy VARCHAR(20)
);
I've seen examples of how to do this with MySQL but not with T-SQL
You should use CURRENT_USER/SUSER_SNAME ( SQL Server 2008+).
It is safe to add default value to your column DeletedBy.
However, be careful, both returns sysname, which means nvarchar(128).
In addition this means that you should enlarge your table definition.
Good starting point on topic 'How to Capture Deleted Records' is my article published on
SQL Server Central.
How to Capture Deleted Records
More info on USER_NAME (Transact-SQL) and SUSER_SNAME (Transact-SQL)

Trigger on View not firing on SQL Server 2012

I have seen some articles mention the possibility of a Trigger on a View, triggering on either insert, updates or deletes to one of the base tables from which the View is created.
However I am not able to get a simple example to work.
CREATE TABLE [Test].[Data] (
Id INT PRIMARY KEY IDENTITY (1,1),
Data VARCHAR(255) NOT NULL,
);
GO
CREATE VIEW [Test].[View] AS SELECT * FROM [Test].[Data];
GO
CREATE TABLE [Test].[Queue] (
Id INT PRIMARY KEY IDENTITY (1,1),
DataId INT NOT NULL,
Action VARCHAR(255) NOT NULL,
Timestamp DATETIME NOT NULL,
);
GO
CREATE TRIGGER InsertTrigger ON [Test].[View] INSTEAD OF INSERT AS
BEGIN
DECLARE #DataId INT;
DECLARE #Timestamp DATETIME;
SET #DataId = (SELECT Id FROM INSERTED);
SET #Timestamp = GETDATE();
INSERT INTO [Test].[Queue] (DataId, Action, Timestamp) VALUES (#DataId, 'Insert', #Timestamp)
END
GO
ENABLE TRIGGER InsertTrigger ON [Test].[View];
GO
INSERT INTO [Test].[Data] (Data) VALUES ('Testdata');
The trigger is not firing, is the above not possible or is there something wrong with my Sql?
Edit: Although answered I would like to clarify the question. The idea was to get the trigger on the View to fire, when there was an Insert to the base table and not the View itself.
A trigger on a view will only work on inserts into that view, not on any inserts into tables to which the view references.
In your script you're not inserting into that view, you're inserting into a table.
In addition to not testing this correctly, your view is wrong. You are not considering that inserted represents multiple rows, not one.
So:
CREATE TRIGGER InsertTrigger ON [Test].[View] INSTEAD OF INSERT AS
BEGIN
INSERT INTO [Test].[Queue] (DataId, Action, Timestamp)
SELECT i.Id, 'Insert', GETDATE()
FROM Inserted;
END;
GO
INSERT INTO [Test].[View] (Data)
VALUES ('Testdata');

Autogenerate ID in stored procedure -SQL

I have this stored procedure in SQL Server which I use in visual net to generate values for some table.
CREATE PROCEDURE grabardatos
#codigocliente int,
#nombre varchar(50),
#apellido varchar(50),
#sexo char(1),
#direcion varchar(50),
#telefono varchar(50),
#tipo varchar(50)
AS
BEGIN
INSERT INTO CLIENTES(Numero,Nombre,Apellido,Sexo,Direcion,Telefono,Tipo)
VALUES ( #codigocliente,#nombre,#apellido,#sexo,#direcion,#telefono,#tipo)
END
The parameter #codigocliente is the id of the table which, according to this code, has to be entered manually in visual net. How Can the id be autogenerated in the sql code of the stored procecure instead of being entered manually in visual net?
If the clientes table has an identity key, it will be automatically generated by SQL as part of the INSERT. You can then use ##identity to retrieve it's value.
The add the key to the table, you need to create a column
ALTER TABLE Add IdKey INT IDENTITY(1,1)
Note that during the INSERT, you cannot provide a value for this column...

trying to change a data type in table using a query

I have this query
CREATE TABLE COSTUMER(
COSTUMER_ID INT,
TAXI_ID INT,
COSTUMER_PHONE_NUMBER BIGINT,
COSTUMER_NAME VARCHAR(40),
DESTINATION VARCHAR(40)
);
i'd like to change the DESTINATION data type to DATETIME rather than VARCHAR. or if you can suggest a better data type that can store a full address the please do.
I tried this query
ALTER TABLE COSTUMER ALTER DESTINATION DATETIME
but when executed I get this message :
102 stating expecting column
If it is a mySql database then the syntax should be as follows:
ALTER TABLE table_name
MODIFY COLUMN column_name datatype
ALTER TABLE COSTUMER MODIFY COLUMN DESTINATION DATETIME;