How can I return the top N most recently inserted records from a table? [duplicate] - sql

I have created table like below:
create table EmployeeDetails
(
id int,
name varchar(50),
designation varchar(50),
ReportingTo int
)
And inserted rows like this:
insert into EmployeeDetails values(1, 'A', 'Developer', 3)
insert into EmployeeDetails values(5, 'E', 'CEO', 5)
insert into EmployeeDetails values(2, 'B', 'Developer', 3)
insert into EmployeeDetails values(3, 'C', 'Manager', 4)
insert into EmployeeDetails values(4, 'D', 'S.Manager', 5)
My question is: how can I identify the last inserted row in the table?
Used queries:
select IDENT_CURRENT('EmployeeDetails')
Select SCOPE_IDENTITY()
But I still didn't find the answer.
Replies are always welcome

You have a fundamental misunderstanding of tables in relational databases. They represent unordered sets. So, there is no "last row" in a table. The information on the ordering of rows has to be included when you create the table and/or load data into it.
In SQL Server, the simplest method is an identity column. That is why many tables are defined as:
create table EmployeeDetails (
id int identity primary key,
name varchar(50),
designation varchar(50),
ReportingTo int
);
You can also add default insertion time columns:
create table EmployeeDetails (
id int identity primary key,
name varchar(50),
designation varchar(50),
ReportingTo int,
CreatedAt datetime default gettime()
);
However, you can have multiple rows with the same datetime value.

You also can use rowversion like below,if you add a column
CREATE TABLE MyTest (myKey int
,myValue int, RV rowversion);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);
select * from mytest order by rv desc
Note:
This always give the last row inserted/Updated
References:
rowversion

Add fields of type datetime with name CreateDate and UpdateDate in your table, when you insert record in your table set their value for getdate()
After that you can run queries:
Select top 10 * from YourTable Order By CreateDate DESC
Or for last updated
Select top 10 * from YourTable Order By UpdateDate DESC

Please find my answer as below. Hope this may help you.
Add one more column to store record creation date/time as below.
create table EmployeeDetails
(
id int,
name varchar(50),
designation varchar(50),
ReportingTo int,
CreatedOn datetime
)
After table creation and inserting records write/execute query (here inner query is used) as below
select
*
from EmployeeDetails
where CreatedOn = (select max(CreatedOn) from EmployeeDetails )

Related

How to get old value and new value of multiple field in trigger in SQL server?

I have a table Person:
CREATE TABLE Person
(
ID INT PRIMARY KEY,
FirstName varchar(50),
LastName varchar(50),
Phone varchar(50),
Address varchar(50),
City varchar(50),
PinCode varchar(50),
DateOfBirth DATETIME,
UpdatedOn DATETIME,
UpdatedBy varchar(50)
)
Whenever I insert or update the multiple fields from above table then I want previous value and current value of all updated fields and store that in another table using Trigger. How we can get values of all updated fields.
For example
INSERT INTO Person
VALUES (1, 'first', 'last', '11111', 'add', 'city', 'pin', GETDATE(), GETDATE(), 'ABC')
UPDATE Person
SET FirstName = 'First11',
LastName = 'Last22',
Phone = '1010101010'
WHERE id = 1
When I will hit above commands in both cases I want old and current value and store it in another table. How we can achieve this using triggers?
For SQL Server when you updated ( he delete the old values and then insert the new values )
ALTER TRIGGER [dbo].[YOUR_TRIGGER_NAME_INSERT]
ON [dbo].[YOUR_TABLE]
AFTER INSERT --Here when you insered rows
AS
BEGIN
select * from inserted --get all inserted rows
--Your code
END
And Update
ALTER TRIGGER [dbo].[YOUR_TRIGGER_NAME_UPDATE]
ON [dbo].[YOUR_TABLE]
AFTER UPDATE--Here when you updated rows
AS
BEGIN
select * from inserted --get all inserted (new values) rows
select * from deleted--get all deleted (old values) rows
--Your code
END

SQL Inserted table trigger

If I run the following select statement inside an insert trigger, is it possible that it will return more than one result?:
DECLARE #variable char(1) = (SELECT ID FROM inserted)
If so, then what's the best to handle it?
Here is the problem that I am trying to solve: Every time when the new record is inserted into a table, I want to take the newly inserted ID and insert it into another table(if it doesn't exists).
Thank you!
Instead of
DECLARE #variable char(1) = (SELECT ID FROM inserted)
You can do something like following:
Declare #VarTempTbl as table (id int)
Insert into #VarTempTbl (id)
Select id from inserted
So that you can get those values for further processing
Now, I had created Two tables One for Master table and another for When any Insertion happens in that Master table, that entry has to inserted into the another table.
CREATE TABLE tblEmployee
(
Id int Primary Key,
Name nvarchar(30),
Gender nvarchar(10),
DepartmentId int
)
CREATE TABLE tblEmployee_New
(
Id int Primary Key,
Name nvarchar(30),
Gender nvarchar(10),
DepartmentId int
)
Trigger:
CREATE TRIGGER TR_EMPLOYEEDETAILS_AFTEROFINSERT
ON TBLEMPLOYEE
AFTER INSERT
AS
BEGIN
TRUNCATE TABLE tblEmployee_New
INSERT INTO TBLEMPLOYEE_NEW(ID, NAME, GENDER, DEPARTMENTID)
SELECT ID, NAME, GENDER, DEPARTMENTID
FROM INSERTED
END
Now Lets try to insert into record into a master table
Insert into tblEmployee values (1,'John', 'Male', 3)
Insert into tblEmployee values (2,'Mike', 'Male', 2)
It has automatically insert the newly inserted records into the another table.
If your want to remove the Previous records then add a drop Statement in that above Trigger.
Note: You can also use #Temp Table instead of creating a another table('tblEmployee_New')
Kinldy Share your comments

how to move record from one database to another database

I have two database,where two table are same with all schema.
I want to move specific records of employees and employeesrates with all columns of both tables.
below is the query.
CREATE TABLE #emp
(
empID INT IDENTITY(1, 1) primary key ,
Firstname varchar(20)
);
CREATE TABLE #empRates
(
ID INT IDENTITY(1, 1) primary key ,
empid int, -- foreign key from #emp
rate decimal(10,3),
startdate datetime,
enddate datetime,
);
insert into #emp (firstname) values('First')
insert into #emp (firstname) values('Second')
insert into #emp (firstname) values('Third')
insert into #empRates(empid,rate,startdate,enddate) values(1,10,'2020/01/10','2020/01/20')
insert into #empRates(empid,rate,startdate,enddate) values(1,15,'2020/01/20','2020/01/30')
insert into #empRates(empid,rate,startdate,enddate) values(2,10,'2020/01/10','2020/01/20')
insert into #empRates(empid,rate,startdate,enddate) values(3,15,'2020/01/20','2020/01/30')
select * from #emp
select * from #empRates
drop table #emp
drop table #empRates
Here both database on same server. Database1 and Database2.
below my query which tried.
insert into database2..empRates(empid,rate,startdate,enddate) select empid,rate,startdate,enddate
from database1..empRates
Here my problem is both database have different records,so identity are different,so after insert other employee rates get displayed for another like mashed up.
I am using sql server 2012.
can you please provide the way.
You should take a look at this post --> How to turn IDENTITY_INSERT on and off using SQL Server 2008?
This way you can specify value for id column during insert, so rows on destination databases will keep IDs from origin.
Hope it helps!

Update temp table with identity after insert

I have a temp table that looks like this:
FirstName
LastName
DOB
Sex
Age
ExternalID
In my stored procedure I'm inserting these values into a regular table that has the following structure:
ID identity(1,1)
FirstName
LastName
So, I do this:
Insert into myTable
select FirstName, LastName from TempTable
During the insert I need to insert primary key from main table back into temp table "ExternalID" column. How can this be achieved?
I tried using OUTPUT statement but it only allows to insert to a separate table and then I have no way to map back to temp table
I need to insert generated IDs to column ExternalID in temp table right after the insert. FirstName and LastName are not unique.
One possible solution would be to use loop and insert one row at a time. This way, I can update temp table row with scope_identity(). But I want to avoid using loops.
Try using MERGE instead of INSERT.
MERGE allows you to output a column you didn't insert, such as an identifier on your temp table. Using this method, you can build another temporary table that maps your temp table to the inserted rows (named #TempIdTable in the sample below).
First, give #TempTable its own primary key. I'll call it TempId. I'll also assume you have a column on #TempTable to store the returned primary key from MyTable, ID.
--Make a place to store the associated ID's
DECLARE #TempIdTable TABLE
([TempId] INT NOT NULL
,[ID] INT NOT NULL)
--Will only insert, as 1 never equals 0.
MERGE INTO myTable
USING #TempTable AS tt
ON 1 = 0
WHEN NOT MATCHED
THEN
INSERT ([FirstName]
,[LastName])
VALUE (t.[FirstName]
,t.[LastName])
OUTPUT tt.[TempId], inserted.[ID] --Here's the magic
INTO #TempIdTable
--Associate the new primary keys with the temp table
UPDATE #TempTable
SET [ID] = t.[ID]
FROM #TempIdTable t
WHERE #TempTable.[TempId] = t.[TempId]
I was working on a similar issue and found this trick over here: Is it possible to for SQL Output clause to return a column not being inserted?
Here's the full code I used in my own testing.
CREATE TABLE [MQ]
([MESSAGEID] INT IDENTITY PRIMARY KEY
,[SUBJECT] NVARCHAR(255) NULL);
CREATE TABLE [MR]
([MESSAGESEQUENCE] INT IDENTITY PRIMARY KEY
,[TO] NVARCHAR(255) NOT NULL
,[CC] NVARCHAR(255) NOT NULL
,[BCC] NVARCHAR(255) NOT NULL);
CREATE TABLE #Messages (
[subject] nvarchar(255) NOT NULL
,[to] nvarchar(255) NOT NULL
,[cc] nvarchar(255) NULL
,[bcc] nvarchar(255) NULL
,[MESSAGEID] INT NULL
,[sortKey] INT IDENTITY PRIMARY KEY
);
INSERT INTO #Messages
VALUES ('Subject1','to1','cc1','bcc1', NULL)
,('Subject2','to2', NULL, NULL, NULL);
SELECT * FROM #Messages;
DECLARE #outputSort TABLE (
[sortKey] INT NOT NULL
,[MESSAGEID] INT NOT NULL
,[subject] NVARCHAR(255)
);
MERGE INTO [MQ]
USING #Messages M
ON 1 = 0
WHEN NOT MATCHED
THEN
INSERT ([SUBJECT])
VALUES (M.[subject])
OUTPUT M.[SORTKEY]
,inserted.[MESSAGEID]
,inserted.[SUBJECT]
INTO #outputSort;
SELECT * FROM #outputSort;
SELECT * FROM [MQ];
UPDATE #Messages
SET MESSAGEID = O.[MESSAGEID]
FROM #outputSort O
WHERE #Messages.[sortKey] = O.[sortKey];
SELECT * FROM #Messages;
DROP TABLE #Messages;
As you said, FirstName and LastName are not unique. This means you cannot use a trigger because there can be the same FirstName + LastName so you cannot join on them.
But you can do the inverse thing: first update your temp table ExternalID (I suggest you to use sequence object and just do update #t set ExternalID = next value for dbo.seq1;) and then just insert your rows including ExternalID into myTable. To be able to insert into identity field you can use set identity_insert myTable on or you can re-design your destination table to contain no identity at all as now you use sequence for the same purpose.
We need a unique column for able to make the comparison at the update operation after the insert. That's why we are using ExternalID column temporarily. ExternalID updated by row_nubmber.
;WITH CTE AS
(
SELECT *, RN = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM #TempTable
)
UPDATE CTE SET ExternalID = RN
We are keeping the output of the insert operation in a temp table. The trick is order by with ExternalID, it will help us for making the unique row number for same first and last name
DECLARE #output TABLE (
ID INT,
FirstName VARCHAR(10),
LastName VARCHAR(10))
Insert into #myTable
OUTPUT inserted.ID, inserted.FirstName, inserted.LastName INTO #output(ID, FirstName, LastName)
select FirstName, LastName from #TempTable T
order by ExternalID
For replacing the ExternalID column with inserted id value, we are making comparing with first name, last name and row number.
;WITH TMP_T AS(
SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY FirstName, LastName ORDER BY ExternalID) FROM #TempTable )
,OUT_T AS(
SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY FirstName, LastName ORDER BY ID) FROM #output )
UPDATE TMP_T SET ExternalID = OUT_T.ID
FROM
TMP_T INNER JOIN OUT_T ON
TMP_T.FirstName = OUT_T.FirstName
AND TMP_T.LastName = OUT_T.LastName
AND TMP_T.RN = OUT_T.RN
Sample Data:
DECLARE #TempTable TABLE (
FirstName VARCHAR(10),
LastName VARCHAR(10),
DOB VARCHAR(10),
Sex VARCHAR (10),
Age VARCHAR(10),
ExternalID INT)
INSERT INTO #TempTable VALUES
('Serkan1', 'Arslan1', 'A','M','1',NULL),
('Serkan2', 'Arslan2', 'B','M','1',NULL),
('Serkan3', 'Arslan', 'C','M','1',NULL),
('Serkan3', 'Arslan', 'D','M','1',NULL)
DECLARE #myTable TABLE (
ID INT identity(100,1), -- started from 100 for see the difference
FirstName VARCHAR(10),
LastName VARCHAR(10))
Result:
MyTable
ID FirstName LastName
----------- ---------- ----------
100 Serkan1 Arslan1
101 Serkan2 Arslan2
102 Serkan3 Arslan
103 Serkan3 Arslan
TempTable
FirstName LastName DOB Sex Age ExternalID
---------- ---------- ---------- ---------- ---------- -----------
Serkan1 Arslan1 A M 1 100
Serkan2 Arslan2 B M 1 101
Serkan3 Arslan C M 1 102
Serkan3 Arslan D M 1 103
One way to do this is by duplicating the data into a second temp table like so:
SELECT *
INTO #TEMPTABLE
FROM (VALUES (1, 'Adam'), (2, 'Kate'), (3, 'Jess')) AS X (Id, Name)
SELECT TOP 0 CAST(NULL AS INT) AS IdentityValue, *
INTO #NEWTEMPTABLE
FROM #TEMPTABLE
CREATE TABLE #TABLEFORINSERT (
IdentityColumn INT IDENTITY(1,1),
Id INT,
Name VARCHAR(255)
)
INSERT INTO #TABLEFORINSERT (Id, Name)
OUTPUT INSERTED.IdentityColumn, INSERTED.Id, Inserted.Name INTO #NEWTEMPTABLE
SELECT Id, Name FROM #TEMPTABLE
--New temp table with identity values
SELECT * FROM #NEWTEMPTABLE

Update records based on inserted IDs and another non source column in SQL

Probably there is already answer for it, but i couldn't find it... So i have 2 tables and data in third one. Lets name them (Source, Target and UpdateTarget).
I need to insert records from Source to Target, then grab autoincremented IDs from Target and update UpdateTarget table with these IDs based on filters from Source table. I've tried to use OUTPUT, but it gives me an error:
The multi-part identifier "s.EmployeeID" could not be bound.
Here is my current SQL query:
CREATE TABLE dbo.target
(
id INT IDENTITY(1,1) PRIMARY KEY,
employee VARCHAR(32)
);
CREATE TABLE dbo.source
(
id INT IDENTITY(1,1) PRIMARY KEY,
employee VARCHAR(32),
EmployeeID int
);
CREATE TABLE dbo.updateTarget
(
id INT IDENTITY(1,1) PRIMARY KEY,
ExternalID int
);
DECLARE #MyTableVar TABLE
(
id INT,
EmployeeID int
);
INSERT dbo.target (employee)
OUTPUT
inserted.id, -- autoincremented ID
s.EmployeeID -- here i got an error
INTO #MyTableVar
SELECT s.employee
FROM dbo.source AS s
UPDATE dbo.updateTarget
SET ExternalID = data.ID
FROM #MyTableVar data
WHERE updateTarget.ID = data.EmployeeID
DROP TABLE source
DROP TABLE target
DROP TABLE updateTarget
I don't have EmployeeID column in target table.
Is there a way to achieve it without making two queries for each record? Or can you point me to existing answer if there are any?
Thanks!
1) INSERT INTO table variable generated id, and EmployeeId for usage in update
2) MERGE instead of INSERT (it allows to get column EmployeeId from SRC)
3) OUTPUT result, action inserted, getting id from TGT and EmployeeId
INSERT INTO #MyTableVar(id, EmployeeId)
SELECT id, EmployeeId
FROM (
MERGE dbo.target TGT
USING dbo.source SRC
ON TGT.employee = SRC.employee
WHEN NOT MATCHED THEN
INSERT (employee)
VALUES (src.employee)
OUTPUT inserted.id, SRC.EmployeeId)
AS out(id, EmployeeId);;
MERGE gives better OUTPUT options