{"id":108492,"date":"2026-03-17T14:00:00","date_gmt":"2026-03-17T14:00:00","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=108492"},"modified":"2026-02-20T15:38:25","modified_gmt":"2026-02-20T15:38:25","slug":"how-to-determine-the-last-value-used-by-a-sequence-in-sql-server","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/how-to-determine-the-last-value-used-by-a-sequence-in-sql-server\/","title":{"rendered":"How to determine the last value used by a sequence in SQL Server"},"content":{"rendered":"\n<p>I&#8217;ve been a fan of sequences ever since they were added in <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/\" target=\"_blank\" rel=\"noreferrer noopener\">SQL Server<\/a> 2012. Prior to that, developers had a choice of <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/working-with-sql-server-identity-columns\/\" target=\"_blank\" rel=\"noreferrer noopener\"><code>IDENTITY<\/code> columns<\/a> or a roll-your-own table mechanism.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-what-are-sequences-in-sql-server\">What are sequences in SQL Server?<\/h2>\n\n\n\n<p><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/introduction-to-sql-server-sequence-objects\/\" target=\"_blank\" rel=\"noreferrer noopener\">Sequences<\/a> allow us to create a schema-bound object that is not associated with any specific table.<\/p>\n\n\n\n<p>For example, if I have a Sales.HotelBookings table, a Sales.FlightBookings table, and a Sales.VehicleBookings table, I might want to have a common BookingID used as the key for each table. If more than the BookingID was involved, you could argue that there is a normalization problem with the tables, but we\u2019ll leave that discussion for another day.<\/p>\n\n\n\n<p>Another reason I like sequences is that they make it much easier to override the auto-generated value, without the need for code like <code>SET IDENTITY_INSERT<\/code> that we need with <code>IDENTITY<\/code> columns. This is particularly powerful if you ever need to do this across <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/linked-servers\/linked-servers-database-engine?view=sql-server-ver17\" target=\"_blank\" rel=\"noreferrer noopener\">linked servers<\/a>, as you\u2019ll quickly find out that it doesn\u2019t work.<\/p>\n\n\n\n<p>Sequences let me avoid these types of issues: they perform identically to <code>IDENTITY<\/code> columns, and they also give me more control over the cache for available values.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-exploring-an-issue-not-obvious-to-most-people\">Exploring an issue not obvious to most people<\/h2>\n\n\n\n<p>I felt there was a problem with how some of the code associated with sequences was implemented.&nbsp;It worked as documented, but wasn&#8217;t useful.&nbsp;Let me show you why. We\u2019ll start by creating a schema and a sequence:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">USE tempdb;\nGO\n\nCREATE SCHEMA Sales AUTHORIZATION dbo;\nGO\n\nCREATE SEQUENCE Sales.BookingID\nAS bigint\nSTART WITH 1\nINCREMENT BY 1\nCACHE 100;\nGO<\/pre><\/div>\n\n\n\n<p>We could then use this schema as the default value for each of the three tables:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">CREATE TABLE Sales.FlightBookings\n(\n    BookingID bigint NOT NULL\n        CONSTRAINT PK_Sales_FlightBookings PRIMARY KEY\n        CONSTRAINT DF_Sales_FlightBookings_BookingID\n        DEFAULT (NEXT VALUE FOR Sales.BookingID),\n    ...\n);\n\nCREATE TABLE Sales.HotelBookings\n(\n    BookingID bigint NOT NULL\n        CONSTRAINT PK_Sales_HotelBookings PRIMARY KEY\n        CONSTRAINT DF_Sales_HotelBookings_BookingID\n        DEFAULT (NEXT VALUE FOR Sales.BookingID),\n    ...\n);\n\nCREATE TABLE Sales.VehicleBookings\n(\n    BookingID bigint NOT NULL\n        CONSTRAINT PK_Sales_VehicleBookings PRIMARY KEY\n        CONSTRAINT DF_Sales_VehicleBookings_BookingID\n        DEFAULT (NEXT VALUE FOR Sales.BookingID),\n    ...\n);<\/pre><\/div>\n\n\n\n<p>All this is as expected. However, one question often arises: how do I know the last value for a given sequence? The answer provided by the documentation at the time was to query the&nbsp;<code>sys.sequences<\/code>&nbsp;view. We could do this as follows:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT s.current_value \nFROM sys.sequences AS s\nWHERE SCHEMA_NAME(s.schema_id) = N'Sales'\nAND OBJECT_NAME(s.object_id) = N'BookingID';\nGO<\/pre><\/div>\n\n\n\n<p>The&nbsp;<code>current_value<\/code>&nbsp;column in <code>sys.sequences<\/code> is defined as follows:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">Datatype: sql_variant NOT NULL<\/pre><\/div>\n\n\n\n<p>The use of <code>sql_variant<\/code> here makes sense as the view needs to be able to provide the current value for all sequences, regardless of data type. Sequences can be created with any built-in <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/t-sql\/data-types\/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-ver17\" target=\"_blank\" rel=\"noreferrer noopener\">integer type<\/a>. According to the documentation, the possible values are:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>tinyint &#8211; Range 0 to 255<\/li>\n\n\n\n<li>smallint &#8211; Range -32,768 to 32,767<\/li>\n\n\n\n<li>int &#8211; Range -2,147,483,648 to 2,147,483,647<\/li>\n\n\n\n<li>bigint &#8211; Range -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807<\/li>\n\n\n\n<li>decimal and numeric with a scale of 0.<\/li>\n\n\n\n<li>Any user-defined data type (alias type) that is based on one of the allowed types.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>The output of the <code>current_value<\/code> column is described as:<\/p>\n\n\n\n<p><em>The last value obligated. That is, the value returned from the most recent execution of the <code>NEXT VALUE FOR<\/code> function or the last value from executing the <code>sp_sequence_get_range<\/code> procedure.<\/em><\/p>\n\n\n\n<p>However, it also says:&nbsp;<em>Returns the <code>START WITH<\/code> value if the sequence has never been used.<\/em> That&#8217;s a problem &#8211; but why?<\/p>\n\n\n\n<section id=\"my-first-block-block_0778768c08fd4a37da85395818dbfb8c\" class=\"my-first-block alignwide\">\n    <div class=\"bg-brand-600 text-base-white py-5xl px-4xl rounded-sm bg-gradient-to-r from-brand-600 to-brand-500 red\">\n        <div class=\"gap-4xl items-start md:items-center flex flex-col md:flex-row justify-between\">\n            <div class=\"flex-1 col-span-10 lg:col-span-7\">\n                <h3 class=\"mt-0 font-display mb-2 text-display-sm\">Fast, reliable and consistent SQL Server development&#8230;<\/h3>\n                <div class=\"child:last-of-type:mb-0\">\n                                            &#8230;with SQL Toolbelt Essentials. 10 ingeniously simple tools for accelerating development, reducing risk, and standardizing workflows.                                    <\/div>\n            <\/div>\n                            <a href=\"https:\/\/www.red-gate.com\/products\/sql-toolbelt-essentials\/\" class=\"btn btn--secondary btn--lg\">Learn more &amp; try for free<\/a>\n                    <\/div>\n    <\/div>\n<\/section>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-the-problem-with-how-the-sequence-is-defined-in-sql-server\">The problem with how the sequence is defined in SQL Server<\/h2>\n\n\n\n<p>If you haven&#8217;t retrieved a value from the sequence, there is no last value. What it returns is the first value generated &#8211; but this hasn&#8217;t happened yet:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"480\" height=\"177\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-55.png\" alt=\"An image showing that the value hasn't been generated yet.\" class=\"wp-image-108493\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-55.png 480w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-55-300x111.png 300w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/figure>\n\n\n\n<p>The documentation was correct, but&nbsp;the behavior was bizarre. In this situation, I believe this column should have returned <code>NULL<\/code>. Otherwise,&nbsp;there was no way to tell that this value has not yet been generated.<\/p>\n\n\n\n<p>If I generated a new value and then queried it again i.e:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT NEXT VALUE FOR Sales.BookingID;\n\nSELECT c.current_value \nFROM sys.sequences AS s\nWHERE SCHEMA_NAME(s.schema_id) = N'Sales'\nAND OBJECT_NAME(s.object_id) = N'BookingID';\nGO\n<\/pre><\/div>\n\n\n\n<p>&#8230;the same value was returned:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"480\" height=\"177\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-56.png\" alt=\"An image showing that the same value was returned.\" class=\"wp-image-108494\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-56.png 480w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-56-300x111.png 300w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/figure>\n\n\n\n<p>So, even though the state of the sequence had changed, there was no change in the <code>current_value<\/code> column. It was only when I requested it another time, that I saw the expected value:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"503\" height=\"220\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-57.png\" alt=\"Image showing the expected value.\" class=\"wp-image-108520\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-57.png 503w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2026\/02\/image-57-300x131.png 300w\" sizes=\"auto, (max-width: 503px) 100vw, 503px\" \/><\/figure>\n\n\n\n<p>So, the problem was that when you read the current value from the <code>sys.sequences<\/code> view, there was no way to know if this was the last value obligated or the next one to be used.<\/p>\n\n\n\n<p>I really wanted to see this behavior changed. That column should have returned <code>NULL<\/code> when it\u2019s first set up, not the start value.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-but-it-was-fixed\">But it was fixed!<\/h2>\n\n\n\n<p>Back in 2016, I posted about how I thought this was broken. I also mentioned that, given the SQL Server team\u2019s aims for backwards compatibility, it was unlikely that they would <em>fix<\/em>\u00a0it. <\/p>\n\n\n\n<p>Instead, I hoped they\u2019d add another column to <code>sys.sequences<\/code> &#8211; one that somehow indicated that the sequence has never been used, even though that felt like a hack instead of a bug fix. There was already a column for <code>is_exhausted<\/code>, so they already had a state-tracking column. I hoped they\u2019d just add another one.<\/p>\n\n\n\n<p>Well, the great news is that this was fixed in SQL Server 2017, even though I didn\u2019t hear anyone mention it, and I don&#8217;t even recall seeing anyone writing about it. And even better than an extra state-tracking column, the team added a new <code>last_used_value<\/code> column\u00a0that works the way I expected\u00a0<code>current_value<\/code>\u00a0to have worked.<\/p>\n\n\n\n<p>So, the message here is: if you want to check the last value issued by a sequence,\u00a0do <em>not<\/em> use <code>current_value<\/code>. It&#8217;s now a pointless column. Instead, use the\u00a0<code>last_used_value<\/code><strong> <\/strong>column. It works as expected. I\u2019m not sure who it was on the product team that fixed this, but thank you!<\/p>\n\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs: How to determine the last value used by a sequence in SQL Server<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. What is a sequence in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p>A SQL Server sequence is a schema-bound object that generates numeric values independently of any table. It\u2019s useful when multiple tables need a common key, like <code data-start=\"323\" data-end=\"334\">BookingID<\/code> for <code data-start=\"339\" data-end=\"355\">FlightBookings<\/code>, <code data-start=\"357\" data-end=\"372\">HotelBookings<\/code>, and <code data-start=\"378\" data-end=\"395\">VehicleBookings<\/code>.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. How is a sequence different from an IDENTITY column in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <ul>\n<li data-start=\"461\" data-end=\"508\">\n<p data-start=\"463\" data-end=\"508\">SQL Server sequences are not tied to a specific table.<\/p>\n<\/li>\n<li data-start=\"509\" data-end=\"582\">\n<p data-start=\"511\" data-end=\"582\">You can override the next value easily without <code data-start=\"558\" data-end=\"579\">SET IDENTITY_INSERT<\/code>.<\/p>\n<\/li>\n<li data-start=\"583\" data-end=\"643\">\n<p data-start=\"585\" data-end=\"643\">They allow more control over caching and value generation.<\/p>\n<\/li>\n<\/ul>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. How do I create and use a sequence in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Use the following code:<\/p>\n<div class=\"pointer-events-none absolute inset-x-4 top-12 bottom-4\">\n<div class=\"pointer-events-none sticky z-40 shrink-0 z-1!\">\n<div class=\"sticky bg-token-border-light\">\u00a0<\/div>\n<\/div>\n<\/div>\n<div class=\"pointer-events-none absolute inset-x-px top-0 bottom-96\">\n<div class=\"pointer-events-none sticky z-40 shrink-0 z-1!\">\n<div class=\"sticky bg-token-bg-elevated-secondary\">\u00a0<\/div>\n<\/div>\n<\/div>\n<div class=\"corner-superellipse\/1.1 rounded-3xl bg-token-bg-elevated-secondary\">\n<div class=\"relative z-0 flex max-w-full\">\n<div id=\"code-block-viewer\" class=\"q9tKkq_viewer cm-editor z-10 light:cm-light dark:cm-light flex h-full w-full flex-col items-stretch \u037c5 \u037cj\" dir=\"ltr\">\n<div class=\"cm-scroller\">\n<div class=\"cm-content q9tKkq_readonly\"><code><span class=\"\u037c8\">CREATE<\/span> SEQUENCE Sales.BookingID<\/code><br \/>\n<code><span class=\"\u037c8\">\u00a0 AS<\/span> bigint<\/code><br \/>\n<code><span class=\"\u037c8\">\u00a0 START<\/span> <span class=\"\u037c8\">WITH<\/span> <span class=\"\u037cb\">1<\/span><\/code><br \/>\n<code>\u00a0 INCREMENT <span class=\"\u037c8\">BY<\/span> <span class=\"\u037cb\">1<\/span><\/code><br \/>\n<code>\u00a0 CACHE <span class=\"\u037cb\">100<\/span>;<\/code><\/p>\n<p><code><span class=\"\u037c8\">CREATE<\/span> <span class=\"\u037c8\">TABLE<\/span> Sales.FlightBookings (<\/code><br \/>\n<code>\u00a0 BookingID bigint <span class=\"\u037c8\">DEFAULT<\/span> (<span class=\"\u037c8\">NEXT<\/span> <span class=\"\u037c8\">VALUE<\/span> <span class=\"\u037c8\">FOR<\/span> Sales.BookingID) <\/code><\/div>\n<div class=\"cm-content q9tKkq_readonly\"><code>\u00a0 \u00a0\u00a0<span class=\"\u037c8\">PRIMARY <\/span><span class=\"\u037c8\">KEY<\/span>,...<\/code><br \/>\n<code>);<\/code><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. How do I check the last value issued by a sequence in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p data-start=\"975\" data-end=\"1076\">Do <em>not<\/em> use <code data-start=\"988\" data-end=\"1003\">current_value<\/code> &#8211; it may return the start value even if no value has been generated. Instead, use <code data-start=\"1085\" data-end=\"1102\">last_used_value<\/code> in SQL Server 2017+ for accurate results.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">5. Why use sequences in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <ul>\n<li data-start=\"1177\" data-end=\"1224\">\n<p data-start=\"1179\" data-end=\"1224\">Share a numeric key across multiple tables.<\/p>\n<\/li>\n<li data-start=\"1225\" data-end=\"1264\">\n<p data-start=\"1227\" data-end=\"1264\">Easily control and override values.<\/p>\n<\/li>\n<li data-start=\"1265\" data-end=\"1319\">\n<p data-start=\"1267\" data-end=\"1319\">Avoid limitation issues with <code>IDENTITY<\/code>\u00a0across servers.<\/p>\n<\/li>\n<\/ul>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Learn how SQL Server sequences work, how they differ from IDENTITY columns, and how to track the last value with last_used_value for multiple tables&hellip;<\/p>\n","protected":false},"author":346483,"featured_media":107513,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143523,53,143524],"tags":[4168,4170,4150,4151],"coauthors":[159368],"class_list":["post-108492","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-databases","category-featured","category-sql-server","tag-database","tag-database-administration","tag-sql","tag-sql-server"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/108492","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/346483"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=108492"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/108492\/revisions"}],"predecessor-version":[{"id":109230,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/108492\/revisions\/109230"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/107513"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=108492"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=108492"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=108492"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=108492"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}