How to find Missing number in Sequence field using SQL? - sql

I have a table called Student and field name called StudentNumber
Student Table
StudentNumber
-------------
1
2
3
4
5
8
10
Expecting output
6
7
9
I tried like below
Declare #trans int;
set #trans = 1;
while(#trans <=50000)
BEGIN
if((select StudentNumber from [Student] where StudentNumber = #trans) != #trans)
BEGIN
print #trans;
END
END
set #trans = #trans + 1;

You could use (SQL Server 2016 and above):
SELECT Number
FROM (select cast([key] as int) +
(SELECT MIN(StudentNumber) FROM Students) as number
from OPENJSON( '[1'
+ replicate(',1',(SELECT MAX(StudentNumber) FROM Students)-
(SELECT MIN(StudentNumber) FROM Students))+']')) n
LEFT JOIN Students s
ON n.number = s.StudentNumber
WHERE s.StudentNumber IS NULL;
DBFiddle Demo
Note: You could exchange first subquery with any other tally number generator.
More info: SQL, Auxiliary table of numbers

it should be like below
Declare #trans int;
set #trans = 1;
while(#trans <=50000)
BEGIN
if NOT EXISTS (select StudentNumber from [Student] where StudentNumber = #trans)
BEGIN
print #trans;
END
END
set #trans = #trans + 1;

You can do the following
;with report as(
select 1 as missing
union all
select missing + 1
from report
where missing < #max
)
select *
from report m
where not exists ( select 1 from student s where s.id = m.missing)
option (maxrecursion 0);
Here a working demo
Result
missing
6
7
9
Hope that this will help you

I know you try to solve it iterative, just for sports
an idea how to achieve the same using recursive CTE
with missingstudents (StudentNumber)
as (
select StudentNumber-1 from Students s
where not exists (
select StudentNumber from Students s2
where s.StudentNumber-1 = s2.StudentNumber)
UNION ALL
select StudentNumber-1 from missingstudents s
where not exists (
select StudentNumber from Students s2
where s.StudentNumber-1 = s2.StudentNumber)
)
select * from missingstudents

You can try this:
select m.number from
(select min(StudentNumber) a,max(StudentNumber) b from Students) c ,master..spt_values M
where c.a <= m.number
and c.b > = m.number
and type ='P'
and m.number not in (select StudentNumber from Students)

Try like this;
declare #id int
declare #maxStudentNumber int
set #id = 1
select #maxStudentNumber = max(StudentNumber) from Student
create table #MissingIds
(
id int
)
while #id < #maxStudentNumber
begin
insert into #MissingIds values(#id)
set #id = #id + 1
end
select m.id
from #MissingIds m
left join Student s
on m.id = s.StudentNumber
where s.StudentNumber is null
drop table #MissingIds

Related

How to tune the following query?

This query gives me the desired result but i can't run this query every time.The 2 loops is costing me.So i need to implement something like view.But the logic has temp tables involved which isn't allowed in views as well.so, is there any other way to store this result or change the query so that it will cost me less.
DECLARE #Temp TABLE (
[SiteID] VARCHAR(100)
,[StructureID] INT
,[row] DECIMAL(4, 2)
,[col] DECIMAL(4, 2)
)
DECLARE #siteID VARCHAR(100)
,#structureID INT
,#struct_row INT
,#struct_col INT
,#rows_count INT
,#cols_count INT
,#row INT
,#col INT
DECLARE structure_cursor CURSOR
FOR
SELECT StructureID
,SiteID
,Cols / 8.5 AS Cols
,Rows / 11 AS Rows
FROM Structure
WHERE SellerID = 658 --AND StructureID = 55
OPEN structure_cursor
FETCH NEXT
FROM structure_cursor
INTO #structureID
,#siteID
,#struct_col
,#struct_row
SELECT #rows_count = 1
,#cols_count = 1
,#row = 1
,#col = 1
WHILE ##FETCH_STATUS = 0
BEGIN
WHILE #row <= #struct_row
BEGIN
WHILE #col <= #struct_col
BEGIN
--PRINT 'MEssage';
INSERT INTO #Temp (
SiteID
,StructureID
,row
,col
)
VALUES (
#siteID
,#structureID
,#rows_count
,#cols_count
)
SET #cols_count = #cols_count + 1;
SET #col = #col + 1;
END
SET #cols_count = 1;
SET #col = 1;
SET #rows_count = #rows_count + 1;
SET #row = #row + 1;
END
SET #row = 1;
SET #col = 1;
SET #rows_count = 1;
FETCH NEXT
FROM structure_cursor
INTO #structureID
,#siteID
,#struct_col
,#struct_row
END
CLOSE structure_cursor;
DEALLOCATE structure_cursor;
SELECT * FROM #Temp
Do this with a set-based operation. I think you just want insert . . . select:
INSERT INTO #Temp (SiteID, StructureID, row, col)
SELECT StructureID, SiteID, Cols / 8.5 AS Cols, Rows / 11 AS Rows
FROM Structure
WHERE SellerID = 658;
You should avoid cursors, unless you really need them for some reason (such as calling a stored procedure or using dynamic SQL on each row).
EDIT:
Reading the logic, it looks like you want to insert rows for based on the limits in each row. You still don't want to use a cursor. For that, you need a number generator and master..spt_values is a convenient one, if it has enough rows. So:
with n as (
select row_number() over (order by (select null)) as n
from master..spt_values
)
INSERT INTO #Temp (SiteID, StructureID, row, col)
SELECT StructureID, SiteID, ncol.n / 8.5 AS Cols, nrow.n / 11 AS Rows
FROM Structure s JOIN
n ncol
ON ncol.n <= s.struct_col CROSS JOIN
n nrow
ON nrow <= s.struct_row
WHERE SellerID = 658;
You can generate the number of rows and columns and then CROSS APPLY with those, like below. I've left out your SellerID condition.
;WITH Cols
AS
(
SELECT StructureID, SiteID, CAST(Cols / 8.5 AS INT) AS Col
FROM Structure
UNION ALL
SELECT s.StructureID, s.SiteID, Col - 1
FROM Structure s
INNER JOIN Cols c ON s.StructureID = c.StructureID AND s.SiteID = c.SiteID
WHERE Col > 1
)
, Rows
AS
(
SELECT StructureID, SiteID, CAST(Rows / 11 AS INT) AS Row
FROM Structure
UNION ALL
SELECT s.StructureID, s.SiteID, Row - 1
FROM Structure s
INNER JOIN Rows r ON s.StructureID = r.StructureID AND s.SiteID = r.SiteID
WHERE Row > 1
)
--INSERT INTO #Temp (SiteID, StructureID, row, col)
SELECT s.SiteID, s.StructureID, r.Row, c.Col
FROM Structure s
CROSS APPLY Cols c
CROSS APPLY Rows r
WHERE s.StructureID = c.StructureID AND s.SiteID = c.SiteID
AND s.StructureID = r.StructureID AND s.SiteID = r.SiteID
We can do this by using CROSS APPLY and CTE.
CREATE TABLE Structure(SiteID varchar(20), StructureID int,
Cols decimal(18,2), [Rows] decimal(18,2))
INSERT INTO Structure (SiteID, StructureID, Cols, [Rows])
VALUES
('MN353970', 51,17,22),
('MN272252', 52,17,11)
;WITH RowCTE([Rows]) AS
(
SELECT 1
UNION ALL
SELECT 2
),
ColCTE(Cols) AS
(
SELECT 1
UNION ALL
SELECT 2
)
SELECT SiteID, StructureID, R.Rows, C.Cols
FROM Structure s
CROSS APPLY
(
SELECT Cols FROM ColCTE
) C
CROSS APPLY
(
SELECT [Rows] FROM RowCTE
) R
Sql Fiddle Demo

Compare comma separated rows

I have a requirement where in I should compare top row with previous rows of database records which they are comma separated.
example :
My table data looks something like this:
ID Phase Updated By
1 Test1,Test2,Test3 sxmalla
2 Test1,Test2 rkgauta
3 Test1,Test3 sxmalla
I have to display somthing the most recent changes in Phase and who has updated.The comma seperated data is submitted with multiple chechboxes in front end. User can update them through multiple checkboxes in same page.
Here Test3 is most recent change,then below that Test2 is the most recent change and on third row the actual first entry.
I need to show the result as
Phase Updated By
Test3 sxmalla
Test2 rkgauta
Test1,Test3 sxmalla
Here is the code that I currently using to compare 2 comma seperated rows
ALTER Proc [dbo].[PMT_GetPhasesEditHistory]
#Project_ID int
As Begin
SET NOCOUNT ON
Declare #added varchar(1000), #removed varchar(1000),#strN varchar(1000),#strO varchar(1000)
DECLARE test_cursor CURSOR FOR
SET #strO=(SELECT TOP 1 P1.Phase from phase P1,Phase P2 where P1.ID = P2.ID-1 and p1.project_id=#Project_ID order by p1.ID Desc)
SET #strN =(SELECT TOP 1 P2.Phase from phase P1,Phase P2
where P1.ID = P2.ID-1 and p1.project_id=#Project_ID order by p1.ID Desc)
If object_id('dbo.#tN') is not null Begin ; drop table dbo.#tN ;End
CREATE TABLE dbo.#tN( var varchar(100)); insert into #tN select * from fnSplitStringAsTable(#strN,',')
If object_id('dbo.#tO') is not null Begin; drop table dbo.#tO ;End
CREATE TABLE dbo.#tO (var varchar(100)); insert into #tO select * from fnSplitStringAsTable(#strO,',')
Declare #i int
Set #i=1
Set #added = ''
While #i != (select COUNT(*)+1 from #tN)
Begin
if not exists(select VAR from #tO where var = (select Top 1 var from #tN where var in ( Select Top (#i) VAR from #tN where Var in (Select Top (#i) var From #tN order by VAR desc) order by var asc)))
Begin
Set #added = #added + (select Top 1 var from #tN where var in ( Select Top (#i) VAR from #tN where Var in (Select Top (#i) var From #tN order by VAR desc) order by var asc)) + ','
End
set #i=#i+1
End
If(len(#added) > 1) Begin; set #added = RTRIM(LEFT(#added,Len(#added) - 1)); End
Select #added as Added
drop table #tN;Drop table #tO
End
Here is a possible solution:
WITH CTE_Prep AS
(
SELECT *, DENSE_RANK() OVER (ORDER BY ID DESC) RN
FROM phase
CROSS APPLY dbo.DelimitedSplit8K(Phase,',')
)
,CTE_Result AS
(
SELECT ID, STUFF ((SELECT ', ' +Item
FROM CTE_Prep c WHERE Item NOT IN (SELECT Item FROM CTE_Prep c2 WHERE c2.RN + 1 = c.RN)
AND c.Id = c3.ID
FOR XML PATH('')),1,2,'') AS Phase
FROM CTE_Prep c3
GROUP BY ID
)
SELECT r.Phase, p.[Updated By] FROM CTE_Result r
LEFT JOIN phase p ON r.id = p.id
This is using DelimitedSplit8K function from SQLServerCentral for splitting, but I'm sure you can do with your existing.
SQLFiddle DEMO
I am going to try and answer the normalization question.
Table PhaseTest
PhaseID int
TestID int
PK PhaseID, TestID
(this PK will enforce no duplicate TestID in a PhaseID
Table PhaseUser
PhaseID int PK
UserID int
Table Test
TestID int PK
TestName varchar
Table User
UserID int PK
UserName varchar
this shows the results on separate lines (no comma)
select PT1.PhaseID, Test.TestName, User.UserName
from PhaseTest PT1
left outer join PhaseTest PT2
on PT2.PhaseID = PT1.PhaseID + 1
and PT2.TestID = PT1.TestID
join PhaseUser
on PhaseUser.UserID = PT1.UserID
join Test
on Test.TestID = PT1.UserID
where PT2.PhaseID is null
order by PT1.TestID
union
select PT1.PhaseID, Test.TestName, User.UserName
from PhaseTest PT1
join PhaseUser
on PhaseUser.UserID = PT1.UserID
join Test
on Test.TestID = PT1.UserID
where PT1.PhaseID = (select max(PhaseID) from PhaseTest)

Is it possible to group unlike items and count them together?

Given the following table:
Chain Name
123 Company 1
124 Other Company 1
123 Whatever Company
125 This One
126 That One
125 Another One
127 Last One
I get the following results when I do a Count on the Chain column:
123 2
124 1
125 2
126 1
127 1
Is it possible to group Chain 123 and 124 so they're counted together? Also group 125 and 126? The modified results would look like this:
123/124 3
125/126 3
127 1
My SQL looks like this:
SELECT Table1.Chain, Count(*) as [Count]
FROM Table1 LEFT JOIN Table2 on Table1.Chain = Table2.Chain
WHERE (((Table1.Chain) IN (Table2.Chain)))
GROUP BY Table1.Chain
ORDER BY Table1.Chain;
Thank you!
Depending upon your needs, this might be a bit of a hack, but I would probably add a table to store the Chain and ChainGroup that you are seeking. Something like this:
Chain ChainGroup
123 123/124
124 123/124
125 125/126
126 125/126
127 127/128
Then, in the query, I would join to this table and instead of grouping by Chain I would group by ChainGroup.
I would prefer this over something like a nested IIF statement as those get pretty difficult to debug, and odds are you'll have additional groupings in the future which would be trivial to add to the table and have the new grouping automatically appear in the query.
yes, you can:
SELECT min(Table1.Chain) & '/' & max(Table1.Chain) as chain, Count(*) as [Count]
FROM Table1 LEFT JOIN Table2 on Table1.Chain = Table2.Chain
WHERE (((Table1.Chain) IN (Table2.Chain)))
GROUP BY int((Table1.Chain-1)/2)
ORDER BY min(Table1.Chain);
You can use a nested Iif statement. Hopefully I've got all my parentheses right below! :-)
SELECT Iif(Table1.Chain="123", "123/124",
Iif(Table1.Chain="124", "123/124",
Iif(Table1.Chain="125", "125/126",
Iif(Table1.Chain="126", "125/126", Table1.Chain)))) as [Chain]
, Count(*) as [Count]
FROM Table1 LEFT JOIN Table2 on Table1.Chain = Table2.Chain
WHERE (((Table1.Chain) IN (Table2.Chain)))
GROUP BY Iif(Table1.Chain="123", "123/124",
Iif(Table1.Chain="124", "123/124",
Iif(Table1.Chain="125", "125/126",
Iif(Table1.Chain="126", "125/126", Table1.Chain))))
ORDER BY Table1.Chain;
You could also move the case statement into a subquery in your from clause or a common table expression if you don't want to write it twice in your query.
consider something like:
SELECT
chain_group, COUNT(*) FROM (
SELECT
Table1.Chain,
switch(Table1.Chain IN("123","124"), "123/124",
Table1.Chain IN("125","126"),"125/126",
Table1.Chain) AS chain_group
FROM
Table1 INNER JOIN
Table2 ON
Table1.Chain = Table2.Chain) t
GROUP BY chain_group
ORDER BY chain_group
You can see the below example
----- Make main Table
CREATE TABLE #test
( id int , Name varchar(100))
INSERT #test(id,Name)
values (123,'Company 1'),
(124,'Other Company 1'),
(123, 'Whatever Company'),
(125, 'This One'),
(126 , 'That One'),
(125, 'Another One'),
(127, 'Last One')
CREATE TABLE #temp
(rowID INT IDENTITY(1,1) , ID INT ,cnt INT )
CREATE TABLE #tempResult
(ID VARCHAR(20) ,cnt INT )
INSERT INTO #temp(ID,cnt)
SELECT ID ,COUNT(1) cnt FROM #test GROUP BY ID
DECLARE #rowCnt INT , #TotalCnt INT , #even INT , #odd INT ,
#idNum VARCHAR(20) , #valueCnt INT , #inStart INT = 1
SET #rowCnt = 1
SET #even = 1
SET #odd = 2
SELECT #TotalCnt = COUNT(1) FROM #temp
WHILE #rowCnt <= #TotalCnt
BEGIN
SET #inStart = 1
SET #odd = #rowCnt
SET #even = #rowCnt + 1
SET #idNum = ''
SET #valueCnt = 0
WHILE #inStart <= 2
BEGIN
IF #inStart = 1
Begin
SELECT #idNum = Convert(VARCHAR(5),ID) , #valueCnt = cnt
FROM #temp WHERE rowID = #odd
End
ELSE
BEGIN
SELECT #idNum = #idNum + '/' + Convert(VARCHAR(5),ID) , #valueCnt = #valueCnt + cnt
FROM #temp WHERE rowID = #even
END
SET #inStart = #inStart + 1
END
INSERT INTO #tempResult (ID, Cnt)
VALUES (#idNum,#valueCnt)
SET #rowCnt = #rowCnt + 2
END
SELECT *
FROM #tempResult

How to find missing id in the table

I have column looks like below
SID101
SID102
SID103
SID105
SID107
In the above criteria i need to find missed SID numbers. SID104 and SID 106 are missed while ordering.
How can i find the missed id numbers.Could any one help me finding it.
Thanks in advance.
If your table contains gaps with length more than 1 item, you can use this query:
declare #t table(s varchar(20))
insert #t values ('SID101'),('SID102'),('SID103'),('SID105'),('SID108');
with cte as
(
select substring(t.s, 4, len(t.s)) [i]
from #t t
)
select 'SID' + cast(m.number as varchar(20))
from master..spt_values m
left join cte c on c.i = m.number
where [Type] = 'P'
and m.number >= (select min(i) from cte)
and m.number <= (select max(i) from cte)
and c.i is null
Output:
-----------------------
SID104
SID106
SID107
Something like this should work:
DECLARE #i INT;
SET #i = 100;
CREATE TABLE #idsToCheck (checkId varchar(100));
WHILE (#i < 200)
BEGIN
INSERT INTO #idsToCheck VALUES ('SID' + CONVERT(varchar(100), #i));
SET #i = #i + 1;
END
SELECT * FROM #idsToCheck itc
LEFT OUTER JOIN MainTable mt ON itc.checkId = mt.realId
WHERE mt.realId = NULL
DROP TABLE #idsToCheck
... where MainTable is your table containing the SID101, SID102, etc. column values, and MainTable.realId is the column containing those IDs. Modify the #i initial value and number in the while loop condition based on which SIDs you want to check from/to.
It's difficult. With
SELECT COUNT(*),MAX(CAST(REPLACE(y.name,'SID','') AS INT)) AS col_max FROM
sys.objects x INNER JOIN sys.columns y ON x.object_id=y.object_id
WHERE x.name='<TABLE_NAME>'
you should know, how much columns are missing (i.e. COUNT(*) is 5 and col_max is 107)
When you have a table, which contains only one column with all possible IDs from 1 to max (i.e. 100,101,102,103,104,...,132) then you could do
SELECT * FROM (
SELECT CAST(REPLACE(y.name,'SID','') AS INT) AS col_id FROM
sys.objects x INNER JOIN sys.columns y ON x.object_id=y.object_id
WHERE x.name='<TABLE_NAME>'
) a
RIGHT JOIN <TABLE_IDS> b ON a.col_id=b.id
WHERE a.col_id IS NULL AND b.id<=(
SELECT MAX(CAST(REPLACE(y.name,'SID','') AS INT)) AS col_max FROM
sys.objects x INNER JOIN sys.columns y ON x.object_id=y.object_id
WHERE x.name='<TABLE_NAME>'
)
EDIT: sorry, I've seen just now, that these values aren't column names, but values. My solution will find missing column names
 Declare #St int
declare #end int
set #st = CAST( (select RIGHT( max(data),4) from orderno)as int)
set #end = CAST( (select RIGHT( min(data),4) from orderno)as int)
create table #temp(data int)
while(#St <= #end )
begin
insert into #temp values(#St)
set #St = #St +1
end
select * from orderno
select * from #temp
select data from #temp where data not in (select cast(RIGHT(data,4))
declare #t table(s varchar(20))
insert #t values ('SID101'),('SID102'),('SID103'),('SID105'),('SID107');
with cte as
(
select substring(t.s, 4, len(t.s)) [i]
from #t t
)
select 'SID' + cast(t1.i + 1 as varchar(20))
from cte t1
join cte t2 on t2.i > t1.i
and not exists(
select 1
from cte c3
where c3.i > t1.i and c3.i < t2.i
)
where t2.i <> t1.i + 1
Output:
-----------------------
SID104
SID106

SQL query to find Missing sequence numbers

I have a column named sequence. The data in this column looks like 1, 2, 3, 4, 5, 7, 9, 10, 15.
I need to find the missing sequence numbers from the table. What SQL query will find the missing sequence numbers from my table? I am expecting results like
Missing numbers
---------------
6
8
11
12
13
14
I am using only one table. I tried the query below, but am not getting the results I want.
select de.sequence + 1 as sequence from dataentry as de
left outer join dataentry as de1 on de.sequence + 1 = de1.sequence
where de1.sequence is null order by sequence asc;
How about something like:
select (select isnull(max(val)+1,1) from mydata where val < md.val) as [from],
md.val - 1 as [to]
from mydata md
where md.val != 1 and not exists (
select 1 from mydata md2 where md2.val = md.val - 1)
giving summarised results:
from to
----------- -----------
6 6
8 8
11 14
I know this is a very old post but I wanted to add this solution that I found HERE so that I can find it easier:
WITH Missing (missnum, maxid)
AS
(
SELECT 1 AS missnum, (select max(id) from #TT)
UNION ALL
SELECT missnum + 1, maxid FROM Missing
WHERE missnum < maxid
)
SELECT missnum
FROM Missing
LEFT OUTER JOIN #TT tt on tt.id = Missing.missnum
WHERE tt.id is NULL
OPTION (MAXRECURSION 0);
Try with this:
declare #min int
declare #max int
select #min = min(seq_field), #max = max(seq_field) from [Table]
create table #tmp (Field_No int)
while #min <= #max
begin
if not exists (select * from [Table] where seq_field = #min)
insert into #tmp (Field_No) values (#min)
set #min = #min + 1
end
select * from #tmp
drop table #tmp
The best solutions are those that use a temporary table with the sequence. Assuming you build such a table, LEFT JOIN with NULL check should do the job:
SELECT #sequence.value
FROM #sequence
LEFT JOIN MyTable ON #sequence.value = MyTable.value
WHERE MyTable.value IS NULL
But if you have to repeat this operation often (and more then for 1 sequence in the database), I would create a "static-data" table and have a script to populate it to the MAX(value) of all the tables you need.
SELECT CASE WHEN MAX(column_name) = COUNT(*)
THEN CAST(NULL AS INTEGER)
-- THEN MAX(column_name) + 1 as other option
WHEN MIN(column_name) > 1
THEN 1
WHEN MAX(column_name) <> COUNT(*)
THEN (SELECT MIN(column_name)+1
FROM table_name
WHERE (column_name+ 1)
NOT IN (SELECT column_name FROM table_name))
ELSE NULL END
FROM table_name;
Here is a script to create a stored procedure that returns missing sequential numbers for a given date range.
CREATE PROCEDURE dbo.ddc_RolledBackOrders
-- Add the parameters for the stored procedure here
#StartDate DATETIME ,
#EndDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Min BIGINT
DECLARE #Max BIGINT
DECLARE #i BIGINT
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable
END
CREATE TABLE #TempTable
(
TempOrderNumber BIGINT
)
SELECT #Min = ( SELECT MIN(ordernumber)
FROM dbo.Orders WITH ( NOLOCK )
WHERE OrderDate BETWEEN #StartDate AND #EndDate)
SELECT #Max = ( SELECT MAX(ordernumber)
FROM dbo.Orders WITH ( NOLOCK )
WHERE OrderDate BETWEEN #StartDate AND #EndDate)
SELECT #i = #Min
WHILE #i <= #Max
BEGIN
INSERT INTO #TempTable
SELECT #i
SELECT #i = #i + 1
END
SELECT TempOrderNumber
FROM #TempTable
LEFT JOIN dbo.orders o WITH ( NOLOCK ) ON tempordernumber = o.OrderNumber
WHERE o.OrderNumber IS NULL
END
GO
Aren't all given solutions way too complex?
wouldn't this be much simpler:
SELECT *
FROM (SELECT row_number() over(order by number) as N from master..spt_values) t
where N not in (select 1 as sequence union
select 2 union
select 3 union
select 4 union
select 5 union
select 7 union
select 10 union
select 15
)
This is my interpretation of this issue, placing the contents in a Table variable that I can easily access in the remainder of my script.
DECLARE #IDS TABLE (row int, ID int)
INSERT INTO #IDS
select ROW_NUMBER() OVER (ORDER BY x.[Referred_ID]), x.[Referred_ID] FROM
(SELECT b.[Referred_ID] + 1 [Referred_ID]
FROM [catalog].[dbo].[Referrals] b) as x
LEFT JOIN [catalog].[dbo].[Referrals] a ON x.[Referred_ID] = a.[Referred_ID]
WHERE a.[Referred_ID] IS NULL
select * from #IDS
Just for fun, I decided to post my solution.
I had an identity column in my table and I wanted to find missing invoice numbers.
I reviewed all the examples I could find but they were not elegant enough.
CREATE VIEW EENSkippedInvoicveNo
AS
SELECT CASE WHEN MSCNT = 1 THEN CAST(MSFIRST AS VARCHAR (8)) ELSE
CAST(MSFIRST AS VARCHAR (8)) + ' - ' + CAST(MSlAST AS VARCHAR (8)) END AS MISSING,
MSCNT, INV_DT FROM (
select invNo+1 as Msfirst, inv_no -1 as Mslast, inv_no - invno -1 as msCnt, dbo.fmtdt(Inv_dt) AS INV_dT
from (select inv_no as invNo, a4glidentity + 1 as a4glid
from oehdrhst_sql where inv_dt > 20140401) as s
inner Join oehdrhst_sql as h
on a4glid = a4glidentity
where inv_no - invno <> 1
) AS SS
DECLARE #MaxID INT = (SELECT MAX(timerecordid) FROM dbo.TimeRecord)
SELECT SeqID AS MissingSeqID
FROM (SELECT ROW_NUMBER() OVER (ORDER BY column_id) SeqID from sys.columns) LkUp
LEFT JOIN dbo.TimeRecord t ON t.timeRecordId = LkUp.SeqID
WHERE t.timeRecordId is null and SeqID < #MaxID
I found this answer here:
http://sql-developers.blogspot.com/2012/10/how-to-find-missing-identitysequence.html
I was looking for a solution and found many answers. This is the one I used and it worked very well. I hope this helps anyone looking for a similar answer.
-- This will return better Results
-- ----------------------------------
;With CTERange
As (
select (select isnull(max(ArchiveID)+1,1) from tblArchives where ArchiveID < md.ArchiveID) as [from],
md.ArchiveID - 1 as [to]
from tblArchives md
where md.ArchiveID != 1 and not exists (
select 1 from tblArchives md2 where md2.ArchiveID = md.ArchiveID - 1)
) SELECT [from], [to], ([to]-[from])+1 [total missing]
From CTERange
ORDER BY ([to]-[from])+1 DESC;
from to total missing
------- ------- --------------
6 6 1
8 8 1
11 14 4
DECLARE #TempSujith TABLE
(MissingId int)
Declare #Id Int
DECLARE #mycur CURSOR
SET #mycur = CURSOR FOR Select Id From tbl_Table
OPEN #mycur
FETCH NEXT FROM #mycur INTO #Id
Declare #index int
Set #index = 1
WHILE ##FETCH_STATUS = 0
BEGIN
if (#index < #Id)
begin
while #index < #Id
begin
insert into #TempSujith values (#index)
set #index = #index + 1
end
end
set #index = #index + 1
FETCH NEXT FROM #mycur INTO #Id
END
Select Id from tbl_Table
select MissingId from #TempSujith
Create a useful Tally table:
-- can go up to 4 million or 2^22
select top 100000 identity(int, 1, 1) Id
into Tally
from master..spt_values
cross join master..spt_values
Index it, or make that single column as PK.
Then use EXCEPT to get your missing number.
select Id from Tally where Id <= (select max(Id) from TestTable)
except
select Id from TestTable
You could also solve using something like a CTE to generate the full sequence:
create table #tmp(sequence int)
insert into #tmp(sequence) values (1)
insert into #tmp(sequence) values (2)
insert into #tmp(sequence) values (3)
insert into #tmp(sequence) values (5)
insert into #tmp(sequence) values (6)
insert into #tmp(sequence) values (8)
insert into #tmp(sequence) values (10)
insert into #tmp(sequence) values (11)
insert into #tmp(sequence) values (14)
DECLARE #max INT
SELECT #max = max(sequence) from #tmp;
with full_sequence
(
Sequence
)
as
(
SELECT 1 Sequence
UNION ALL
SELECT Sequence + 1
FROM full_sequence
WHERE Sequence < #max
)
SELECT
full_sequence.sequence
FROM
full_sequence
LEFT JOIN
#tmp
ON
full_sequence.sequence = #tmp.sequence
WHERE
#tmp.sequence IS NULL
Hmmmm - the formatting is not working on here for some reason? Can anyone see the problem?
i had made a proc so you can send the table name and the key and the result is a list of missing numbers from the given table
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create PROCEDURE [dbo].[action_FindMissing_Autoincremnt]
(
#tblname as nvarchar(50),
#tblKey as nvarchar(50)
)
AS
BEGIN
SET NOCOUNT ON;
declare #qry nvarchar(4000)
set #qry = 'declare #min int '
set #qry = #qry + 'declare #max int '
set #qry = #qry +'select #min = min(' + #tblKey + ')'
set #qry = #qry + ', #max = max('+ #tblKey +') '
set #qry = #qry + ' from '+ #tblname
set #qry = #qry + ' create table #tmp (Field_No int)
while #min <= #max
begin
if not exists (select * from '+ #tblname +' where '+ #tblKey +' = #min)
insert into #tmp (Field_No) values (#min)
set #min = #min + 1
end
select * from #tmp order by Field_No
drop table #tmp '
exec sp_executesql #qry
END
GO
SELECT TOP 1 (Id + 1)
FROM CustomerNumberGenerator
WHERE (Id + 1) NOT IN ( SELECT Id FROM CustomerNumberGenerator )
Working on a customer number generator for my company. Not the most efficient but definitely most readable
The table has one Id column.
The table allows for Ids to be inserted at manually by a user off sequence.
The solution solves the case where the user decided to pick a high number