Order by and custom sorting in Microsoft SQL Server - sql

I have a table with numeric and string values. I need to apply the custom sorting as mentioned below:-
CREATE TABLE [dbo].[TEST]
(
[Tag] [nvarchar](max) NULL,
[Category] [nvarchar](max) NULL,
[LE] [nvarchar](max) NULL,
[Description] [nvarchar](max) NULL,
[Row_Id] [int] NOT NULL,
CONSTRAINT [PK_testsirius_TEST_0_Row_Id]
PRIMARY KEY CLUSTERED ([Row_Id] ASC)
)
Insert into TEST values (1,'Area','EMR','A',199)
Insert into TEST values (2,'Area','EMR','B',200)
Insert into TEST values (3,'Area','EMR','C',201)
Insert into TEST values (201,'Area','EMR','1',399)
Insert into TEST values (202,'Area','EMR','2',400)
Insert into TEST values (203,'Area','EMR','3',401)
Excepted output:
select *
from TEST
order by asc
Output:
1
2
3
A
B
C
Current output:
C
B
A
3
2
1
Requirement :
If the sort direction is [↑] then first sort all the numeric values from smallest to the largest, then sort all the time values from oldest to newest and then sort all the text values from A to Z
If the sort direction is [↓] then first sort all the text values from Z to A, then sort all the time values from newest to oldest and then sort all the numeric values from largest to the smallest
While sorting, always place the blank cells at the bottom.

SELECT *
FROM TEST
ORDER BY CASE WHEN Description NOT LIKE '%[^0-9]%' THEN 0 ELSE 1 END,
LEN(Description),
Description

You can use isNumeric().
select *
from TEST
order by CASE WHEN isNumeric(Description) = 1 THEN Cast([Description] as int) ELSE 2147483647 END
, Description
-- for a descending order you can use the maths idea that -1 * a number maintains magnitude but reverses the order ...
select *
from TEST
order by CASE WHEN isNumeric(Description) = 1 THEN Cast([Description] as int) * -1 ELSE -2147483648 END
, Description desc
-- with the extra test case for 12345
CREATE TABLE [dbo].[TEST]
(
[Tag] [nvarchar](max) NULL,
[Category] [nvarchar](max) NULL,
[LE] [nvarchar](max) NULL,
[Description] [nvarchar](max) NULL,
[Row_Id] [int] NOT NULL,
CONSTRAINT [PK_testsirius_TEST_0_Row_Id]
PRIMARY KEY CLUSTERED ([Row_Id] ASC)
)
Insert into TEST values (1,'Area','EMR','A',199)
Insert into TEST values (2,'Area','EMR','B',200)
Insert into TEST values (3,'Area','EMR','C',201)
Insert into TEST values (201,'Area','EMR','1',399)
Insert into TEST values (202,'Area','EMR','2',400)
Insert into TEST values (203,'Area','EMR','3',401)
Insert into TEST values (204,'Area','EMR','12345',402)
select *
from TEST
order by CASE WHEN isNumeric(Description) = 1 THEN Cast([Description] as int) ELSE 2147483647 END
, Description
-- example output
Tag Category LE Description Row_Id
201 Area EMR 1 399
202 Area EMR 2 400
203 Area EMR 3 401
204 Area EMR 12345 402
1 Area EMR A 199
2 Area EMR B 200
3 Area EMR C 201
-- descending order
select *
from TEST
order by CASE WHEN isNumeric(Description) = 1 THEN Cast([Description] as int) * -1 ELSE -2147483648 END
, Description desc
-- example output
Tag Category LE Description Row_Id
3 Area EMR C 201
2 Area EMR B 200
1 Area EMR A 199
204 Area EMR 12345 402
203 Area EMR 3 401
202 Area EMR 2 400
201 Area EMR 1 399

Have you tried this:
select *
from TEST
order by case when Description not like '%[0-9]%' then 1 else 0 end, Description

Related

How to figure out which string or binary data would be truncated?

I have a stored procedure which works most of the time, but every now and again, I get an error message:
Msg 8152, Level 16, State 2, Line 98
String or binary data would be truncated.
The statement has been terminated.
How do I figure out which data string is causing this issue?
For this answer, which handles more complex select queries quite well, let's assume we have three tables defined as follows...
CREATE TABLE [dbo].[Authors](
[AuthorID] [int] NOT NULL,
[AuthorName] [varchar](20) NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[Books](
[BookID] [int] NOT NULL,
[AuthorID] [int] NOT NULL,
[BookName] [varchar](20) NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[Publications](
[BookID] [int] NOT NULL,
[PublicationName] [varchar](10) NOT NULL,
[AuthorID] [int] NOT NULL,
[WrittenBy] [varchar](10) NOT NULL
) ON [PRIMARY]
...and we create the following data...
INSERT INTO Authors ( AuthorID, AuthorName ) VALUES ( 1, 'BOB' )
INSERT INTO Authors ( AuthorID, AuthorName ) VALUES ( 2, 'JANE' )
INSERT INTO Authors ( AuthorID, AuthorName ) VALUES ( 3, 'SOREN LONGNAMESSON' )
INSERT INTO Books ( BookID, AuthorID, BookName ) VALUES ( 1, 1, 'My Life' )
INSERT INTO Books ( BookID, AuthorID, BookName ) VALUES ( 2, 2, 'Writing Long Titles For Dummies' )
INSERT INTO Books ( BookID, AuthorID, BookName ) VALUES ( 3, 3, 'Read Me' )
...and our complex query that is throwing the error is...
INSERT INTO Publications SELECT Books.BookID, Books.BookName, Authors.AuthorID, Authors.AuthorName FROM Books JOIN Authors ON Books.AuthorID = Authors.AuthorID
...then we can find the columns that are likely to be offending like this...
Step 1
Convert your INSERT statement into a SELECT INTO statement and write the results to a temporary table like this...
SELECT Books.BookID, Books.BookName, Authors.AuthorID, Authors.AuthorName INTO ##MyResults FROM Books JOIN Authors ON Books.AuthorID = Authors.AuthorID
Step 2
Now execute the following T-SQL to compare the column definitions of your destination table with the source columns of your complex query...
SELECT
SourceColumns.[name] AS SourceColumnName,
SourceColumns.[type] AS SourceColumnType,
SourceColumns.[length] AS SourceColumnLength,
DestinationColumns.[name] AS SourceColumnName,
DestinationColumns.[type] AS SourceColumnType,
DestinationColumns.[length] AS SourceColumnLength
FROM
tempdb.sys.syscolumns SourceColumns
JOIN tempdb.sys.sysobjects SourceTable ON SourceColumns.[id] = SourceTable.[id]
LEFT JOIN sys.syscolumns DestinationColumns ON SourceColumns.colorder = DestinationColumns.colorder
LEFT JOIN sys.sysobjects DestinationTable ON DestinationColumns.[id] = DestinationTable.[id]
WHERE
SourceTable.Name = '##MyResults'
AND DestinationTable.Name = 'Publications'
You can adapt this query to filter down to certain column types (you know the problem is with string or binary data) and also where the length of the source column is greater than the destination columns. Armed with this information you should be left with only a few columns that could possible cause truncation and can start your search from there.
TIP! Check your destination columns for ON INSERT TRIGGERS!!
The issue is clear that one of your column in the table is having a length more than the destination table.
To find the length of the column which might be creating the issue you can run this query
Select Max(Len(Column1)) --Take only varchar columns in this.
, Max(Len(Column2))
, Max(Len(Column3))
From YourTable
Now you can check the length of string with the column length of your destination table. Most probably you will find any one column is having a length more than the specified length your destination table column.
Lets say you get that the column2 has the issue after executing the above query ie the length of your varchar is more than the column length. Then to find the specific value you can run this query:
select * from yourtable
where len(column2)>20 --change 20 to the actual value of your column2
This will print your error message and store incorrect values in a global temp table. It's not ideal and will be applicable in all situations, but it works.
Our Tables
IF OBJECT_ID('dbo.yourTable') IS NOT NULL
DROP TABLE dbo.yourTable;
IF OBJECT_ID('tempdb..#valuesToBeInserted') IS NOT NULL
DROP TABLE #valuesToBeInserted;
CREATE TABLE yourTable
(
ID INT IDENTITY(1,1),
Col1 CHAR(2),
Col2 VARCHAR(5),
Col3 VARCHAR(10)
);
GO
SELECT * INTO #valuesToBeInserted
FROM
(
SELECT '12' col1,'12345' col2,'1234567890' col3 --good value
UNION ALL
SELECT '123','12345','1234567890' --bad value
UNION ALL
SELECT '12','123456','1234567890' --bad value
) A
Actual solution
BEGIN TRY
INSERT INTO yourTable(Col1,col2,col3)
SELECT *
FROM #valuesToBeInserted
END TRY
BEGIN CATCH
IF OBJECT_ID('tempdb..##TruncatedResults') IS NOT NULL
DROP TABLE ##TruncatedResults;
PRINT ERROR_MESSAGE() + CHAR(13) + 'Truncated values are in ##truncatedResults'
SELECT
CASE
WHEN DATALENGTH(Col1) > 2 THEN 1 ELSE 0
END AS isCol1Truncated,
CASE
WHEN DATALENGTH(Col2) > 5 THEN 1 ELSE 0
END AS isCol2Truncated,
CASE
WHEN DATALENGTH(Col3) > 10 THEN 1 ELSE 0
END AS isCol3Truncated,
* --lazy man's select
--col1,
--col2,
--col3
INTO ##truncatedResults --global temp table
FROM #valuesToBeInserted
WHERE DATALENGTH(Col1) > 2
OR DATALENGTH(Col2) > 5
OR DATALENGTH(Col3) > 10
END CATCH
If you wanted to create a dynamic SQL solution or just don't want to type it out, try this to create your CASE statements and where clause
DECLARE #caseStatement VARCHAR(MAX),
#whereClause VARCHAR(MAX);
SELECT #caseStatement = COALESCE(#caseStatement + ',','') + 'CASE WHEN ' + CONCAT('DATALENGTH(',COLUMN_NAME,') > ',CHARACTER_MAXIMUM_LENGTH) + ' THEN 1 ELSE 0 END AS Is' + COLUMN_NAME + 'Truncated',
#whereClause = COALESCE(#whereClause,'') + CONCAT('DATALENGTH(',COLUMN_NAME,') > ',CHARACTER_MAXIMUM_LENGTH,' OR ')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE CHARACTER_MAXIMUM_LENGTH > 0
AND TABLE_NAME = 'yourTable'
SELECT #whereClause = 'WHERE ' + SUBSTRING(#whereClause,1,LEN(#whereClause) - 3)
SELECT #caseStatement
SELECT #whereClause
Results:
CASE WHEN DATALENGTH(Col1) > 2 THEN 1 ELSE 0 END AS IsCol1Truncated,CASE WHEN DATALENGTH(Col2) > 5 THEN 1 ELSE 0 END AS IsCol2Truncated,CASE WHEN DATALENGTH(Col3) > 10 THEN 1 ELSE 0 END AS
WHERE DATALENGTH(Col1) > 2 OR DATALENGTH(Col2) > 5 OR DATALENGTH(Col3) > 10
A 2016/2017 update will show you the bad value and column.
A new trace flag will swap the old error for a new 2628 error and will print out the column and offending value. Traceflag 460 is available in the latest cumulative update for 2016 and 2017:
More info:
https://stackoverflow.com/a/63474873/852208
This error is occurring due to less size for some column, but you are trying to insert more length of Text in to that column.
For Ex:
EMP_Name varchar(10)
and you are trying to insert/update
JOHN VOUGER
during the above case this expections occur. So, first check with the varchar columns and if possible increase the size of the column.

SQL query to show repeating data from child records in columns

I have the following tables in a SQL Server 2000 database:
Master
MasterID | Details | [other fields]
=====================================
PK (int) | Free text | ...
LogTable
LogID | MasterID | UserID | LogDate | LogText
==========================================================
PK (int) | FK (int) | VarChar(2)| Date stamp | Free text
There may be many Log entries for each master record.
I have a query which extracts the most recent three associated Log entries for each Master row as shown below. Note that appropriate conversion and formatting is performed to achieve the LogData concatenation (omitted for clarity):
SELECT
M.MasterID, M.Details, L.LogDate + L.UserID + L.LogText AS LogData
FROM
MasterTable M
INNER JOIN
LogTable L ON M.MasterID = L.MasterID
AND L.LogID IN (SELECT TOP 3 LogID FROM LogTable
WHERE MasterID = M. MasterID ORDER BY LogDate DESC)
This produces output like this:
MasterID | Details | LogData
========================================================
1 | First | 05/11/2012 AB Called Client
2 | Second | 08/11/2012 CD Client Visit
2 | Second | 07/11/2012 CD Called Client
2 | Second | 05/11/2012 AB Called Client
What I need to achieve is showing the data from the second table as columns in the output, all reported against each single master record, thus avoiding repeated data. Like so:
MasterID | Details | LogData1 | LogData2 | LogData3
===========================================================================================================
1 | First | 05/11/2012 AB Called Client | (null) | (null)
2 | Second | 08/11/2012 CD Client Visit | 07/11/2012 CD Called Client | 05/11/2012 AB Called Client
Note that in the real world requirement, this solution will be part of flattening 5 tables with the output consisting of approx 20,000 rows and 90 columns of data.
Thanks in advance.
I'm going to post this, just to show it can be done, but HIGHLY SUGGEST, not do it through SQL. Should be done through the UI that's displaying to be more dynamic on your columns. Even then, I would design this differently.
-- create master table
DECLARE #MasterTable TABLE (
[MasterID] [int] IDENTITY (1, 1) NOT NULL ,
[Details] [varchar] (50) ,
[AdditionalField_1] [varchar] (50) ,
[AdditionalField_n] [varchar] (50)
)
-- create log table
DECLARE #LogTable TABLE (
[LogID] [int] IDENTITY (1, 1) NOT NULL ,
[MasterID] [int] NULL ,
[UserID] [varchar] (2) ,
[LogDate] [datetime] NULL ,
[LogText] [varchar] (50)
)
-- insert into master table
INSERT INTO #MasterTable (Details)
VALUES ('First')
INSERT INTO #MasterTable (Details)
VALUES ('Second')
-- insert into log table
INSERT INTO #LogTable (MasterID, UserID, LogDate, LogText)
VALUES (1, 'AB', '05/11/2012', 'Called Client')
INSERT INTO #LogTable (MasterID, UserID, LogDate, LogText)
VALUES (2, 'AB', '05/11/2012', 'Called Client')
INSERT INTO #LogTable (MasterID, UserID, LogDate, LogText)
VALUES (2, 'CD', '07/11/2012', 'Called Client')
INSERT INTO #LogTable (MasterID, UserID, LogDate, LogText)
VALUES (2, 'CD', '08/11/2012', 'Client Visit')
-- create table to display data
DECLARE #MyTemp TABLE (MasterID INT, Details VARCHAR(50), LogData1 VARCHAR(50), LogData2 VARCHAR(50), LogData3 VARCHAR(50))
INSERT INTO #MyTemp SELECT MasterID, Details, NULL, NULL, NULL FROM #MasterTable
-- create vars
DECLARE #ID INT, #NewID INT, #MasterID INT, #NewValue VARCHAR(100)
SET #ID = 0
-- loop through data
WHILE #ID >-1
BEGIN
-- clear vars
SELECT #NewID = NULL, #MasterID = NULL, #NewValue = NULL
-- get first record
SELECT TOP 1
#NewValue = CONVERT(VARCHAR(10), LogDate, 103)+ ' ' + UserID + ': ' + LogText
, #MasterID=MasterID
, #NewID=LogID
FROM #LogTable WHERE LogID>#ID
-- if no data, exit loop
IF #NewID IS NULL
BREAK
-- update record based on valuds in fields
UPDATE m
SET #ID = #NewID
, LogData1 = (CASE WHEN m.LogData1 IS NULL THEN #NewValue ELSE m.LogData1 END)
, LogData2 = (CASE WHEN m.LogData1 IS NOT NULL THEN
(CASE WHEN m.LogData2 IS NULL THEN #NewValue ELSE m.LogData2 END)
ELSE m.LogData2 END)
, LogData3 = (CASE WHEN m.LogData1 IS NOT NULL THEN
(CASE WHEN m.LogData2 IS NOT NULL THEN
(CASE WHEN m.LogData3 IS NULL THEN #NewValue ELSE m.LogData3 END)
ELSE m.LogData3 END)
ELSE m.LogData3 END)
FROM #MyTemp m
WHERE m.MasterID=#MasterID
END
--display all data
SELECT * FROM #MyTemp

Selecting rows based on row level uniqueness (combination of columns)

I hope somebody can help me solve the following problem.
I need to select unique rows based on a combination of 2 or 3 columns. Its basically a 3 level hierachy table that I build up referening the PK as the parentId in the hierachy.
To set everything up please run the following script:
-- ===================
-- Source table & data
-- ===================
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ExternalSource]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[ExternalSource](
[locname1] [varchar](max) NULL,
[locname2] [varchar](max) NULL,
[locname3] [varchar](max) NULL
) ON [PRIMARY]
END
INSERT [dbo].[ExternalSource] ([locname1], [locname2], [locname3]) VALUES (N'Location1', N'Floor1', N'Room123')
INSERT [dbo].[ExternalSource] ([locname1], [locname2], [locname3]) VALUES (N'Location2', N'Floor2', N'Room234')
INSERT [dbo].[ExternalSource] ([locname1], [locname2], [locname3]) VALUES (N'Location3', N'Floor2', N'Room111')
-- ===================
-- Destination table
-- ===================
CREATE TABLE [dbo].[Location](
[LocationID] [int] IDENTITY(1,1) NOT NULL,
[CompanyID] [tinyint] NOT NULL,
[ParentID] [int] NULL,
[LocationCode] [nvarchar](20),
[LocationName] [nvarchar](60) NOT NULL,
[CanAssign] [bit] NOT NULL)
-- Level 1 records in the hierachy
insert into Location
(
CompanyID,
ParentID,
LocationName,
CanAssign
)
select distinct 1, NULL, ES.locname1, 1
from dbo.ExternalSource ES
where ES.locname1 not in (select LocationName from Location) and ES.locname1 is not null
-- Level 2 records in the hierachy
insert into Location
(
CompanyID,
ParentID,
LocationName,
CanAssign
)
select 1, max(Loc.LocationID), ES.locname2, 1
from ExternalSource ES
left join Location Loc on ES.locname1 = Loc.LocationName
where ES.locname2 not in (select LocationName from Location) and ES.locname2 is not null and ES.locname1 is not null
group by ES.locname2
order by ES.locname2
select * from ExternalSource
select * from Location
The first insert into Location is not a problem at all, all I want at the first insert is unique Location names.
Now at my second insert I need to be able to tell whether ExternalSource.locname2 & Location.LocationName are unique in a "combined" fashion, if that makes sense...
If they are unique, then I need to have the location name at level 2 selected.
Here is an example:
Below is what you get when you do a select * from ExternalSource
locname1 locname2 locname3
Location1 Floor1 Room123
Location2 Floor2 Room234
Location3 Floor2 Room111
Given the above, there is only one Floor1 on locname2 so no issues there but as you can see there are two Floor2 on the locname2 column. I need a way to check if the value on locname2 + locname1 are unique when "combined". If they are I should select them both.
This is the expected output of the select during the second insert:
1 1 Floor1 1
1 2 Floor2 1
1 3 Floor2 1
But lets say the output of ExternalSource where to look like this:
locname1 locname2 locname3
Location1 Floor1 Room123
Location2 Floor2 Room234
Location2 Floor2 Room111
Note the bold Location2 above, because there are two rows with the same value on locname2 + locname1 it doesn't make it unique anymore and then the desired output whould have looked like this:
1 1 Floor1 1
1 3 Floor2 1
So you want to group by two columns in ExternalSource...?
select MAX(LocationID), Locname1, Locname2, 1 from ExternalSource
group by Locname1, Locname2

Duplicate a row multiple times

Basically I want to duplicate a row a variable number of times.
I have a table with the following structure:
CREATE TABLE [dbo].[Start](
[ID] [int] NOT NULL,
[Apt] [int] NOT NULL,
[Cost] [int] NOT NULL)
I want to duplicate each row in this table (Apt-1) times so in the end there will be #Apt rows. Moreover for each new row the value of Cost is decremented until it reaches 0. ID will be the same as there are no primary keys. If I have a record like this:
1 5 3
I need 4 new rows inserted in the same table and they should look like this
1 5 2
1 5 1
1 5 0
1 5 0
I have tried so far a lot of ways but I cannot make it work. Many thanks!
try this
DECLARE #Start TABLE (
[ID] [int] NOT NULL,
[Apt] [int] NOT NULL,
[Cost] [int] NOT NULL)
INSERT #Start (ID, Apt, Cost)
VALUES (1, 5, 3)
; WITH CTE_DIGS AS (
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS rn
FROM master.sys.all_columns AS a
)
INSERT #Start (ID, Apt, Cost)
SELECT ID, Apt, CASE WHEN Cost - rn < 0 THEN 0 ELSE Cost - rn END
FROM #Start
INNER JOIN CTE_DIGS
ON Apt > rn
Try:
;with cte as
(select [ID], [Apt], [Cost], 1 counter from [Start]
union all
select [ID],
[Apt],
case sign([Cost]) when 1 then [Cost]-1 else 0 end [Cost],
counter+1 counter
from cte where counter < [Apt])
select [ID], [Apt], [Cost]
from cte

Remove duplicate row and update next row to current row and continue

I need a select query ..
Environment : SQL DBA -SQL SERVER 2005 or newer
Example :
In this sample table, if I select top 20 no duplicate records should come and next record should be in 20 records .
Example :
123456 should not repeat in 20 records and if 18th is duplicate, in place of 18th, 19th record should come and in 19thβ€”20th should come, in 20th ---21st should come .
No concern of Asc or Desc for rows .
Lookup Table before
Id Name
123456 hello
123456 hello
123654 hi
123655 yes
LookUp Table after
Id Name
123456 hello
123654 hi
123655 yes
My table:
CREATE TABLE [dbo].[test](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ContestId] [int] NOT NULL,
[PrizeId] [int] NOT NULL,
[ContestParticipantId] [int] NOT NULL,
[SubsidiaryAnswer] [varchar](256) NOT NULL,
[SubsidiaryDifference] [bigint] NOT NULL,
[AttemptTime] [datetime] NOT NULL,
[ParticipantName] [varchar](250) NOT NULL,
[IsSubscribed] [bit] NOT NULL,
[IsNewlyRegistered] [bit] NOT NULL,
[IsWinner] [bit] NOT NULL,
[IsWinnerConfirmed] [bit] NOT NULL,
[IsWinnerExcluded] [bit] NOT NULL) ON [PRIMARY]
My question is: from this select, we actually need the first 20, but unique ones.
SELECT TOP 20 * FROM test order by SubsidiaryDifference
When we do the above query, we have currently some double in there. In case there is a double, we need take them only 1 time and take the next one
Any one know this issue ?
Thanks in advance :)
Reading your question, it appears you don't really want to delete the rows from the table - you just want to display the TOP 20 distinct rows - you try something like this:
;WITH LastPerContestParticipantId AS
(
SELECT
ContestParticipantId,
-- add whatever other columns you want to select here
ROW_NUMBER() OVER(PARTITION BY ContestParticipantId
ORDER BY SubsidiaryDifference) AS 'RowNum'
FROM dbo.Test
)
SELECT TOP (20)
ContestParticipantId,
-- add whatever other columns you want to select here
SubsidiaryDifference
FROM
LastPerContestParticipantId
WHERE
RowNum = 1
This will show you the most recent row for each distinct ContestParticipantId, order by SubsidiaryDifference - try it!
Update #2: I've created a quick sample - it uses the data from your original post - plus an additional SubID column so that I can order rows of the same ID by something...
When I run this with my CTE query, I do get only one entry for each ID - so what exactly is "not working" for you?
DECLARE #test TABLE (ID INT, EntryName VARCHAR(50), SubID INT)
INSERT INTO #test
VALUES(123456, 'hello', 1), (123456, 'hello', 2), (123654, 'hi', 1), (123655, 'yes', 3)
;WITH LastPerId AS
(
SELECT
ID, EntryName,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY SubID DESC) AS 'RowNum'
FROM #test
)
SELECT TOP (3)
ID, EntryName
FROM
LastPerId
WHERE
RowNum = 1
Gives an output of:
ID EntryName
123456 hello
123654 hi
123655 yes
No duplicates.