How to Copy a Timestamp Datatype - sybase

I have a table with a TIMESTAMP column:
create table dbo.EX_EMPLOYEE (
NAME_X varchar(10) null,
RECORD_TIME_STAMP timestamp null
)
when I copy the rows from one table to another, using either:
SELECT * INTO EX_EMPLOYEE_T
FROM EX_EMPLOYEE
WHERE 1=0
or:
INSERT INTO EX_EMPLOYEE_T
SELECT *
FROM EX_EMPLOYEE
I get this warning:
Warning: A non-null value cannot be inserted into a TIMESTAMP column by the user. The database timestamp value has been inserted into the TIMESTAMP field instead.
The TIMESTAMP column in the target table is replaced with the current database timestamp.
My question
How to copy rows with a TIMESTAMP column, while preserving the TIMESTAMP value from the source table ?
(Is there a setting similar to SET IDENTITY ON/OFF)
My scenario
I have 2 tables, one for "live" data and the other for "backup", so I need to copy the rows with the TIMESTAMP intact. I need it intact in order to detect if there has been a change to the "live" row.

The Sybase (now SAP) replication server (SRS) can replicate timestamp values between Sybase/SAP ASE tables, ie, the SRS maintuser can insert explicit values into a column of type timestamp.
How is this possible? There are a few requirements:
the user performing the insert (to the timestamp column) must have the replication_role role (and it has to be active)
you need to issue the set timestamp_insert on command (NOTE: this will generate an error if your user doesn't have replication_role)
you need to explicitly list the target table's columns in the insert statement
Setup:
exec sp_displaylogin
go
...
Configured Authorization:
...
replication_role (default ON) <<<=== verify role assigned and active
...
create table EX_EMPLOYEE
(NAME_X varchar(10) NULL
,RECORD_TIME_STAMP timestamp NULL
)
go
insert into EX_EMPLOYEE (NAME_X) values ('Larry')
insert into EX_EMPLOYEE (NAME_X) values ('Mo')
insert into EX_EMPLOYEE (NAME_X) values ('Curly')
go
select * from EX_EMPLOYEE
go
NAME_X RECORD_TIME_STAMP
---------- ------------------
Larry 0x00000000ec4304fa
Mo 0x00000000ec4304fd
Curly 0x00000000ec430501
select * into EX_EMPLOYEE_T FROM EX_EMPLOYEE where 1=2
go
Now for some insert tests ...
-- haven't issued the 'set timestamp_insert on' commmand, yet
insert into EX_EMPLOYEE_T
select * from EX_EMPLOYEE
go
Warning: A non-null value cannot be inserted into a TIMESTAMP column by the user. The database timestamp value has been inserted into the TIMESTAMP field instead.
-- received the *WARNING*, ie, rows are inserted but they receive new timestamp values
select * from EX_EMPLOYEE_T
go
NAME_X RECORD_TIME_STAMP
---------- ------------------
Larry 0x00000000ec430548 <<<=== different from what's in EX_EMPLOYEE
Mo 0x00000000ec43054a <<<=== different from what's in EX_EMPLOYEE
Curly 0x00000000ec43054c <<<=== different from what's in EX_EMPLOYEE
-- enable direct insert of timestamp values
set timestamp_insert on
go
truncate table EX_EMPLOYEE_T
go
-- w/out explicitly listing target columns ...
insert into EX_EMPLOYEE_T
select * from EX_EMPLOYEE
go
-- no warning message is generated, insert succeeds, but new timestamp values are generated
select * from EX_EMPLOYEE_T
go
NAME_X RECORD_TIME_STAMP
---------- ------------------
Larry 0x00000000ec430555 <<<=== different from what's in EX_EMPLOYEE
Mo 0x00000000ec430557 <<<=== different from what's in EX_EMPLOYEE
Curly 0x00000000ec430559 <<<=== different from what's in EX_EMPLOYEE
truncate table EX_EMPLOYEE_T
go
-- this time we'll explicitly list the target table's columns ...
insert into EX_EMPLOYEE_T (NAME_X, RECORD_TIME_STAMP)
select * from EX_EMPLOYEE
go
-- and now we see the timestamp values copied from the source
select * from EX_EMPLOYEE_T
go
NAME_X RECORD_TIME_STAMP
---------- ------------------
Larry 0x00000000ec4304fa <<<=== same as what's in EX_EMPLOYEE
Mo 0x00000000ec4304fd <<<=== same as what's in EX_EMPLOYEE
Curly 0x00000000ec430501 <<<=== same as what's in EX_EMPLOYEE
Above was tested on a ASE 15.7 SP138 dataserver.

Related

SQL trigger with IDENTITY_INSERT

I have two tables: Table1 is all the companies, Table2 is companies whose name start with A.
Table1 company (companyId int, companyName varchar(50), companySize int)
Table2 companyStartWithA (companyId int, companyName varchar(50), companySize int)
What I want to do is to create a trigger so that when I insert/update/delete something in Table1, it will automatically do the same in Table2
My code:
CREATE TRIGGER A_TRG_InsertSyncEmp
ON company
AFTER INSERT
AS
BEGIN
INSERT INTO companyStartWithA
SELECT *
FROM INSERTED
WHERE inserted.companyName LIKE 'A%'
END
And I get an error:
An explicit value for the identity column in table 'companyStartWithA' can only be specified when a column list is used and IDENTITY_INSERT is ON.
What can I do?
Thanks
The problem is the fact that you're not explicitly specifying the column in the INSERT statement, and using a SELECT * to fill the data. Both are big no-no's - you should always explicitly specify the column that you want to insert into, and you should always explicitly specify the columns that you want to select. Doing so will fix this problem:
CREATE TRIGGER A_TRG_InsertSyncEmp
ON company
AFTER INSERT
AS
BEGIN
INSERT INTO companyStartWithA (companyName, companySize)
SELECT companyName, companySize
FROM INSERTED
WHERE inserted.companyName LIKE 'A%'
END
But as Sean Lange absolutely correctly commented - this should really be just a view rather than a separate table.....
CREATE VIEW dbo.CompanyStartsWithA
AS
SELECT companyId, companyName, companySize
FROM dbo.Company
WHERE Name LIKE 'A%'
and then you don't need any messy triggers or anything - just insert into dbo.Company and all companies with a name that starts with an A will be visible in this view....

Adhoc SQL Server Insert

I have a complex sql requirement where in I need to insert data to target table(set of select statements from a source table) based on values in control table.
The control table has got list of products with attribute1, attribute2 and action columns(INCLUDE/EXCLUDE)
This insert is based on value of action column which is done at product level(For each product).
For action INCLUDE we have two cases:
1.when attribute2 is not null, For every product insert that attribute1/attribute2 combination alone and exclude all other atrribute1 combination(for that product)
when attribute2 is null, For that product include all attribute1 combinations
For action EXCLUDE in control table we have two cases:
1.For every product exclude the mentioned attribute1/attribute2 combination and include all other atrribute1 combination (for that product)
when attribute2 is null, For that product exclude the mentioned attribute1 combinations and include all other attribute 1 combinations
Below is the source table /control table and the values in it.
create table #source(
Product varchar(100),
attribute12Value varchar(100),--(its a combination of attribute1,attribute2, some value)
colx varchar(100),
coly varchar(100),
)
create table #control(
attribute1 varchar(100),
attribute2 varchar(100),
value varchar(100),
Product varchar(100),
action varchar(100)
)
insert #source(Product ,attribute12Value ,colx,coly)
select 'HP', 'hw1-i3proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'HP', 'hw2-i3proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'HP', 'hw2-i5proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'HP', 'hw2-i7proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'HP', 'hw3-i3proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'Dell', 'hw1-i3proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'Dell', 'hw1-i5proc-ver1-sale','normal','Y'
insert #source(Product ,attribute12Value ,colx,coly)
select 'Dell', 'hw1-i7proc-ver1-sale','normal','Y'
Based on the action value in the control table the output from source table should be as below:
--case1 when attribute2 not null
--For every product insert that attribute1/attribute2 combination alone and exclude all other atrribute1 combination(for that product)
insert #control(attribute1 ,attribute2,value ,Product,action)
select 'hw2','i3proc','ver1','HP','INCLUDE'
--For every product exclude the mentioned attribute1/attribute2 combination and include all other atrribute1 combination (for that product)
insert #control(attribute1 ,attribute2,value ,Product,action)
select 'hw2','i5proc','ver1','HP','EXCLUDE'
--case2 when attribute2 is null
-- For that product include all attribute1 combinations
insert #control(attribute1 ,attribute2,value ,Product,action)
select 'hw2',NULL,'ver1','HP','INCLUDE'
-- For that product exclude the mentioned attribute1 combinations and include all other attribute 1 combinations
insert #control(attribute1 ,attribute2,value ,Product,action)
select 'hw3',NULL,'ver1','HP','EXCLUDE'
Similarly this logic applies to all other products such as DELL which is then inserted into the target table.
I am able to find a INCLUDE logic like this:
select T1.Product,T1.attribute12Value,T1.colx,T1.coly from #control T
inner join #source T1 on T.action='INCLUDE'
and T.Product=T1.Product and PATINDEX(T.attribute1+'-'+isnull(T.attribute2,'')+'%',T1.attribute12Value)!=0
But I am stuck at the EXCLUDE logic where I need to exclude the mentioned attribute1/2 combination and include all other attribute1 combinations.
Sample Source Table
Can a general TSQL logic be applied for such a requirement to EXCLUDE records based on a control table?
Thanks.
T-SQL (for SQL-Server version 2008+) has an EXCEPT set based operator.
Given query A, to exclude a set of rows defined by query B from the result set :
-- result set
SELECT * FROM A
EXCEPT
-- rows to exclude/remove from result set
SELECT * FROM B
so for your exclude case 1 (for each product include all rows having specified attribute1, then remove all rows having specified attribute1/attribute2 combination) :
select T1.Product,T1.attribute12Value,T1.colx,T1.coly from #control T
inner join #source T1 on T.action='EXCLUDE' and T.Product=T1.Product AND [... Your predicate for selecting all attribute1 combinations ... ] AND attribute2 is not null
EXCEPT
select T1.Product,T1.attribute12Value,T1.colx,T1.coly from #control T
inner join #source T1 on T.action='EXCLUDE' and T.Product=T1.Product AND [... Your predicate for selecting the combination attribute1/attribute2 ... ] AND attribute2 is not null

Trigger two tables from two different databases to insert data (SQL Server)

What the title says, I want to insert data from a database to another database. The first database "DB1" is the source and the second database "DB2" is the target.
The relevant tables are defined as follows:
DB1 => tbl_Target
==================================
Id | Date | Name | Age | Num_Aucts
==================================
DB2 => tbl_Source
======================
Name | Age | Num_Aucts
======================
Well, tbl_Source contains 40 rows of data. I need to transfer these rows into tbl_Target. But how you can see tbl_Target has two additional columns Idand Date. Id will set automatically. The important column is Date. In this column I want to set the currently date. In this case from today. How can I define this in a trigger frunction in SQL Server with T-SQL?
I have begun in this direction:
USE DB1
GO
CREATE TRIGGER trg_Insert_tblSource ON tbl_Source
FOR INSERT AS
BEGIN
INSERT INTO DB2.dbo.tbl_Target ([Date], [Name], [Age], [Num_Aucts])
SELECT ??? // How to get the current date?
Can anyone help me? Do I need a stored procedure?
I don't know if I fully understood your question. But if you just want to transfer the data from one table to another, you don't need a trigger. You could achieve this with a simple INSERT...SELECT:
INSERT INTO DB2.dbo.tbl_Target (
[Date],
[Name],
[Age],
[Num_Aucts]
)
SELECT GETDATE(), [Name], [Age], [Num_Aucts]
FROM yourDB.dbo.tbl_Source
If you want to use a trigger, write the following in the BEGIN block:
INSERT INTO DB2.dbo.tbl_Target (
[Date],
[Name],
[Age],
[Num_Aucts]
)
SELECT GETDATE(), [Name], [Age], [Num_Aucts]
FROM inserted
The trigger gets fired each time you insert data into tbl_Source. But the existing data doesn't get inserted into tbl_Target with your trigger.
you can use GetDate() to get current date of server
USE DB1
GO
CREATE TRIGGER trg_Insert_tblSource ON tbl_Source
FOR INSERT AS
BEGIN
INSERT INTO DB2.dbo.tbl_Target (
[Date],
[Name],
[Age],
[Num_Aucts]
)
SELECT GETDATE(), [Name], [Age], [Num_Aucts]
FROM inserted;
END
GO

One Stored Procedure to insert one table and retrieve ID and insert multiple tables

I have 3 tables and columns. ex: Green (userID, Name, Address), Red (userID, TemproraryAddress), Blue (userID, WorkPlace).
I want to insert data into Green while userID is auto incremented int and unique id. After inserting those details want to retrieve userID and insert into Red and Blue Tables in one stored procedure
Note: This example table is to show a sample scenario, not for real world usage...
SQL has a very nice OUTPUT feature.
In this scenario, specify your identity column with an auto incrementing int or default value (such as newid()), do the insert and then use the output as input for your other input queries.
The output table has all the values just inserted and can be queried just as any other table, with the difference being it has your new value immediately available after commit.
INSERT INTO
tblInsertedID(ID)
SELECT * FROM
(INSERT
INTO tblDir(Dir)
OUTPUT inserted.ID
VALUES ('C:\NewDir\')
) InnerTable
DECLARE #userID INT;
INSERT dbo.Green(Name, Address) SELECT #name, #address;
SELECT #userID = SCOPE_IDENTITY();
INSERT dbo.Red(UserID, TemporaryAddress) SELECT #userID, #something;
INSERT dbo.Blue(UserID, WorkPlace) SELECT #userID, #something_else;
Use SCOPE_IDENTITY() to insert value in a variable for user is and then use this variable value in Red/Blue tables.

get last primary key-not identity- inserted using a trigger

I have an insert trigger to insert the primary key(varchar) of a table.I want to get the last inserted primary key value.
these is my insert trigger
ALTER TRIGGER dbo.equipment_insert_pk
ON dbo.Equipment
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
declare #id int;
declare #cat varchar(2);
select #cat=CategoryID from INSERTED;
select #id=cast(max(right(EquipmentID,4)) as int) from Equipment where CategoryID=#cat;
set #id=isnull(#id,0)+1;
-- Insert statements for trigger here
insert into Equipment
select CategoryID+right('0000'+cast(#id as varchar(4)),4)
,CategoryID
,Location
,Detail
,'../BarcodeImage/'+CategoryID+right('0000'+cast(#id as varchar(4)),4)+'.jpeg' from INSERTED;
END
I tried to write a function to fetch the last inserted primary key value but it seems not to work..because there is no scope for "inserted" outside trigger.Help me..
I tried this code within trigger with output clause no result so far..
insert into Equipment
output INSERTED.EquipmentID into #Temp_Tbl
select CategoryID+right('0000'+cast(#id as varchar(4)),4)
,CategoryID
,Location
,Detail
,'../BarcodeImage/'+CategoryID+right('0000'+cast(#id as varchar(4)),4)+'.jpeg' from INSERTED;
Any help ??
ok. I bumped into this exact same problem a few weeks ago.
I've tried many different ways - to no avail. Long story short - I ended up adding a new column with the type of UNIQUEIDENTIFIER (guid)
So to use your example - let's say there's a column called guid in dbo.Equipment
Roughly, here's how you do it:
insert into Equipment
output INSERTED.EquipmentID, INSERTED.guid into #Temp_Tbl
select CategoryID+right('0000'+cast(#id as varchar(4)),4)
,CategoryID
,Location
,Detail
,'../BarcodeImage/'+CategoryID+right('0000'+cast(#id as varchar(4)),4)+'.jpeg'
,NEWID() -- new column
from INSERTED;
Then you can query dbo.Equipment using #Temp_Tbl.guid to get the inserted id.
For example:
SELECT EquipmentID FROM dbo.Equipment e WHERE EXISTS (SELECT * FROM #Temp_Tbl tt WHERE tt.guid = e.guid)

Resources