{"id":1757,"date":"2014-02-06T00:00:00","date_gmt":"2014-02-06T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/sql-server-sequence-basics\/"},"modified":"2021-08-16T15:01:59","modified_gmt":"2021-08-16T15:01:59","slug":"sql-server-sequence-basics","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/sql-server-sequence-basics\/","title":{"rendered":"SQL Server SEQUENCE Basics"},"content":{"rendered":"<div id=\"pretty\">\n<p>SQL Server now has the ANSI\/ISO Standard <code>CREATE SEQUENCE<\/code> statement. Hooray! The bad news is that most  programmers will not be aware of the significance of the underlying math. A <code>SEQUENCE <\/code>is not an <code>IDENTITY<\/code>. That propriety  feature in T-SQL is a table property inherited from the old Sybase\/UNIX days. It counts the number of insertion  attempts, not even successes, on one particular machine. This goes back to how files were managed on UNIX systems in the  1970s. In those systems, you needed record numbers to locate the data, so T-SQL exposed this count as <code>IDENTITY<\/code>. Also,  when a record was deleted, a bit flag on each record might be set to signal a garbage collection routine to remove this  data during a file utility clean up. <\/p>\n<p>Obviously, <code>IDENTITY<\/code> increments its value from physical insertion to physical insertion; no big jumps, no  gaps. Again, <code>IDENTITY<\/code> is not a column; it is a table property. <i>That means it cannot be a key by definition.<\/i>  Remember a key is a subset of <b><i>columns<\/i><\/b> that are unique in every row of a table. It is not an integer; you  cannot do meaningful math on it. It is non-deterministic. If you insert a set of more than one row into a table, the  rows will be inserted one at time in an order determined by the indexes, internal state of the hardware and number of  sessions open at the time. <\/p>\n<p>We have, for a long time, created a table of integers that has all sorts of uses. It starts at 1 and goes  to some sufficiently large value. Its name depends on the author of the table. You will see &#8220;Numbers&#8221;, &#8220;Sequence&#8221;,  &#8220;Tally_Table&#8221; and &#8220;Series&#8221; among others. Obviously, we can no longer use &#8220;Sequence&#8221;; it is a reserved word! I used it  myself, and so I&#8217;ll have to re-write my books from now on. Darn. I always thought that &#8220;Numbers&#8221; was too generic; which  numbers?? I never liked &#8220;Tally&#8221;, since a tally is a current score or amount, a running total, or count. It is not a set,  but a process. I settled on &#8220;Series&#8221; for my stuff since a series is a completed (infinite) set, but it is not the right  word. <\/p>\n<p>Now, let&#8217;s do math.<\/p>\n<h3><b>What is the Difference Between a Sequence and a Series? <\/b> <\/h3>\n<p>A <b>sequence<\/b> is a list of numbers. <i>The order in which the  numbers are listed is important,<\/i> so for instance {1, 2, 3, 4, 5, &#8230;} is one sequence, and {2, 1, 4, 3, 6, 5, &#8230;} is <i> an entirely different sequence<\/i>. This is important. It means we can talk about the<i> i-th member <\/i>of the  sequence. <\/p>\n<p>A <b>series<\/b> is a<i> sum<\/i> of numbers. A classic example is: 1 +  1\/2 + 1\/4 + 1\/8 + 1\/16 + &#8230; which converge to 2 (or you can loosely say it will equal 2 at infinite). The order of terms  can change the limit to which the series converges or it might not (&#8220;absolutely convergent&#8221;). Okay, too much math for a  database article.<\/p>\n<p>Sequences and series are closely related to each other. But a sequence is not summed.  <\/p>\n<h3><b>Tag Numbers versus Sequence <\/b> <\/h3>\n<p>A tag number is string, usually of fixed length, made up of digits. The digits are in sequence to make them  easy to sort and to generate. Think of a serial number on a manufactured product. The most common example is a&#160;vehicle  identification number (VIN). This is a unique code is used by the&#160;<a href=\"http:\/\/en.wikipedia.org\/wiki\/Automotive_industry\">automotive  industry<\/a>&#160;to identify individual&#160;<a href=\"http:\/\/en.wikipedia.org\/wiki\/Motor_vehicle\">motor  vehicles<\/a>,&#160;&#160;as defined in&#160;<a href=\"http:\/\/en.wikipedia.org\/wiki\/International_Organization_for_Standardization\">ISO<\/a>&#160;3833.  The positions 12 to 17 are a sequence prefixed by codes for the Manufacturer Identifier, some vehicle attributes, a  check digit, model year, and plant code. <\/p>\n<p>The check digit is a major reason we like tag numbers. This  is a topic in itself, but the idea is that we can take each digit in the tag number and run it thru a formula as an  integer. We get a result, usually another digit, and we attach it to the tag number. For example, the Luhn algorithm is  a common method <\/p>\n<p>defined by ISO\/IEC 7812-1. We like it because it is simple  to put in hardware. <\/p>\n<p class=\"MsoBodyText\"> 1.&#160;&#160;&#160;&#160;&#160; Compute the sum of the digits .<\/p>\n<p class=\"MsoBodyText\"> 2.&#160;&#160;&#160;&#160;&#160; Take the units digit from this total.<\/p>\n<p class=\"MsoBodyText\"> 3.&#160;&#160;&#160;&#160;&#160; Subtract it from 10. <\/p>\n<p class=\"MsoBodyText\">It&#8217;s not a great check digit,  but it catches <i>most <\/i>of the common input errors &#8211; missing digits, extra digits, wrong digits and pairwise  transposes. <\/p>\n<p class=\"MsoBodyText\">Now let&#8217;s into the SQL.<b><\/b><\/p>\n<h2><b>The CREATE SEQUENCE Statement <\/b> <\/h2>\n<p>This statement creates a schema level object that is accessible to any user. It is not part of a table. It  is not a procedure that belong to one user. The idea is that a user can invoke the <code>SEQUENCE<\/code> with a special syntax that  is used wherever an integer value of the <code>SEQUENCE<\/code> data type would work. <\/p>\n<p>If you want a physical model, imagine you are in the butcher store. You walk in and pull a service ticket  number from a roll of tickets on the counter. Sequence numbers are generated outside the scope of the current  transaction, just like the tickets. The numbers are consumed whether the transaction using the ticket number is actually  served (committed) or they walk out (rolled back).  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;NEXT VALUE FOR [&lt;database_name&gt;.] [&lt;schema_name&gt;.] &lt;sequence_name&gt;\n&#160;[OVER (&lt;over_order_by_clause&gt;)]\n<\/pre>\n<p>I will explain the <code>OVER() <\/code>clause later; just keep the simple butcher store model in mind for now. Let&#8217;s  look at the roll of tickets (i.e. <code>CREATE SEQUENCE<\/code>). It has to be declared with parameters that define behavior.  <b> <\/b><\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">CREATE SEQUENCE [&lt;schema_name&gt;.] &lt;sequence_name&gt;\n&#160;[AS [built_in_integer_type | user-defined_integer_type]]\n&#160;[START WITH &lt;constant&gt;]\n&#160;[INCREMENT BY &lt;constant&gt;]\n&#160;[{MINVALUE [&lt;constant&gt;]} | {NO MINVALUE}]\n&#160;[{MAXVALUE [&lt;constant&gt;]} | {NO MAXVALUE}]\n&#160;[CYCLE | {NO CYCLE}]\n&#160;[{CACHE [&lt;constant&gt;]} | {NO CACHE}]\n&#160;[;]\n&#160;\n<\/pre>\n<p>Let&#8217;s go thru the BNF in detail. The <code>&lt;sequence_name&gt;<\/code> and its qualifiers explains itself. This is pure SQL.  Sequence numbers are generated outside the scope of the current transaction. They are consumed whether the transaction  using the sequence number is committed or rolled back. Think about the butcher shop ticket that gets dropped on the  floor. <\/p>\n<p>A sequence can be defined as any integer type: That means <code>TINYINT, SMALLINT, INTEGER and BIGINT;<\/code> but it  also allows <code>DECIMAL (s, 0)<\/code> and <code>NUMERIC(s, 0)<\/code> data types. You can also a user-defined data type that is based on one of  the allowed types. Do not do that if you value portability.<\/p>\n<p>If no data type is provided,<code> BIGINT<\/code> is the default. Do not use this unless you really need  &#160;a range of  -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807), which makes &#8216;Big Data&#8217; seem like note on the back of the hand. As with most defaults, this is the largest, safest value in the problem space.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">START WITH &lt;constant&gt;<\/pre>\n<p>This is the first value returned by the sequence. The START value must be a value between the minimum and  maximum values. The default start value for a new sequence is the minimum value for an ascending sequence and the  maximum value for a descending sequence. Note this is a constant; no function calls. <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">INCREMENT BY &lt;constant&gt;<\/pre>\n<p>Value used to increment (or decrement if negative) the value of the sequence for each call to the  <code>NEXT  VALUE FOR<\/code>. If the increment is a negative value, the sequence is descending; otherwise, it is ascending. The increment  cannot be 0, obviously. The default increment for a new sequence is 1. Again, this is a constant and not a function  call. <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">[MINVALUE &lt;constant&gt; | NO MINVALUE]<\/pre>\n<p>Specifies the bounds for the sequence. The default minimum value for a new sequence is the minimum value of  the data type of the sequence. This is zero for the <code>TINYINT<\/code> data type and a negative number for all other data types.<\/p>\n<p><code>NO MINVALUE<\/code> is probably a really bad design choice . You probably wanted zero or one.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">[MAXVALUE &lt;constant&gt; | NO MAXVALUE<\/pre>\n<p>Specifies the bounds for the sequence. The default maximum value for a new sequence is the maximum value of  the data type of the sequence. <\/p>\n<p><code>NO MAXVALUE<\/code> is probably another bad design. If you are going to use this to create a tag number, you have  to worry about overflowing the length of your string.  <\/p>\n<p>If you are casting the numeric data type to strings for tag numbers, you will want to be sure that the  numbers do not overflow in the conversion. And you probably do not need the upper limit of a data type.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">[CYCLE | NO CYCLE]<\/pre>\n<p>Property that specifies whether the sequence should restart from the minimum value (or maximum for  descending sequences) or throw an exception when its minimum or maximum value is exceeded. The default cycle option for  new sequences is <code>NO CYCLE<\/code>. <i>Note that cycling restarts from the minimum or maximum value, not from the start value.<\/i><\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">[CACHE [&lt;constant&gt;] | NO CACHE]<\/pre>\n<p>I am not going to explain Cache management. This is an implementation detail and I do programming.  <\/p>\n<p>In many financial applications, you cannot afford gaps. For example in Italy, invoice numbers have to be in  a strict sequence <i>by law.<\/i> But you can lose all of the numbers in cache in the event of a major failure, so while  it is faster, it is also dangerous. Remember that today &#8220;ROI&#8221; means &#8220;Risk of Incarceration&#8221; <\/p>\n<h3><b><code>OVER (ORDER BY ..) <\/code>Clause<\/b><\/h3>\n<p><b>&#160;<\/b>Remember earlier in this article when I mentioned that how <code>IDENTITY<\/code> in assigned to each element of a a set  insertion was not deterministic? <code>SEQUENCE<\/code> has a way to fix this problem; you can order the sequence! If another process  is accessing the sequence object at the same time, the numbers returned could have gaps.<\/p>\n<p>An <code>OVER<\/code> clause applied to the <code>NEXT VALUE FOR<\/code> function does not support the  <code>PARTITION BY<\/code> or the<code> [ROW |  RANGE] <\/code>subclauses for obvious reasons. The following additional rules apply when using the <code>NEXT VALUE FOR<\/code> function with  the <code>OVER<\/code> clause:<\/p>\n<p>Multiple calls to the <code>NEXT VALUE FOR<\/code> function for the same sequence generator in a single statement<i> must <\/i>all use the same OVER clause definition. Again, this is obvious. <\/p>\n<p>Multiple calls to the <code>NEXT VALUE FOR<\/code> function that reference different sequence generators in a single  statement can have different OVER clause definitions. They are separate schema objects. <\/p>\n<p>If all calls to the <code>NEXT VALUE FOR<\/code> function in a <code>SELECT<\/code> statement specifies the  <code>OVER <\/code>clause, an <code>ORDER BY<\/code>  clause may be used in the<code> SELECT<\/code> statement. Again, the <code>SEQUENCE<\/code> is a separate schema object. <\/p>\n<p>The <code>OVER<\/code> clause is allowed with the <code>NEXT VALUE FOR<\/code> function when used in a  <code>SELECT<\/code> statement or <code>INSERT ...  SELECT ... <\/code>statement. The <code>NEXT VALUE FOR<\/code> function is not allowed in <code>UPDATE <\/code>or <code>MERGE <\/code>statements.<\/p>\n<h2><b>Programming Examples <\/b> <\/h2>\n<p>To get a feel for how this works, create a simple sequence and play with it.&#160; <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;\nCREATE SEQUENCE Invoice_Seq\n&#160;AS INTEGER\n&#160;START WITH 1\n&#160;INCREMENT BY 1\n&#160;MINVALUE 1\n&#160;MAXVALUE 99\n&#160;NO CYCLE; \n<\/pre>\n<p> Now, just play with it. Just hit  &#160;&#8221;<code>SELECT NEXT VALUE FOR Invoice_Seq;<\/code>&#8221; a few times, or in SSMS execute &#8230;<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">SELECT NEXT VALUE FOR Invoice_Seq;\n\tGO 99\nSELECT NEXT VALUE FOR Invoice_Seq;\n&#160;\n<\/pre>\n<p> After you hit 99 and then invoke the next value, you will get this message.<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;\nMsg 11728, Level 16, State 1, Line 1\nThe sequence object 'Invoice_Seq' has reached its minimum or maximum value. Restart the sequence object to allow new values to be generated.\n&#160;\n<\/pre>\n<p>  We did not talk about this &#8220;restart&#8221; option yet. It is a straightforward <code>ALTER<\/code> statement.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">ALTER SEQUENCE &lt;sequence name&gt; RESTART [WITH &lt;constant&gt;];<\/pre>\n<p> &#160;The <code>WITH<\/code> option lets you assign the new starting value. If you do not give a specific value, the default is  the original starting value. In this example, we can use: <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;&#160;ALTER SEQUENCE Invoice_Seq RESTART WITH 3;\n&#160; SELECT NEXT VALUE FOR Invoice_Seq;\n<\/pre>\n<p> &#160;this will return 3. Most of the situations where you want to re-start a sequence can be done with the  <code>CYCLE<\/code>  clause. <\/p>\n<p> &#160;The use of the <code>ORDER BY<\/code> clause can let you build groupings. Create a sequence groups of ten:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">CREATE SEQUENCE Ten_Seq\n&#160;AS INTEGER\n&#160;START WITH 1\n&#160;INCREMENT BY 1\n&#160;MINVALUE 1\n&#160;MAXVALUE 10\n&#160;CYCLE; \n<\/pre>\n<p> Now use it in a query that breaks the students into groups of ten <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;SELECT student_id, student_name,\n&#160;&#160;&#160;&#160;&#160;&#160; (NEXT VALUE FOR Ten_Seq OVER(ORDER BY student_id))\n&#160;&#160;&#160;&#160;&#160;&#160; AS student_grouping\n&#160; FROM Students;\n<\/pre>\n<p> &#160;Converting the sequence into, say, a four digit invoice serial number is pretty simple. It is important to  use <code>VARCHAR(n).<\/code>  <\/p>\n<p> &#160;SELECT &#8216;IN:&#8217; + RIGHT (&#8216;0000&#8217; + CAST (NEXT VALUE FOR Invoice_Seq AS VARCHAR(5)), 4);<\/p>\n<p> &#160;But a fun example is that of using the same sequence in more than one table. Let&#8217;s go back the original  service ticket example. When you come into the shop, you pull a ticket.  &#160;<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">\t\tCREATE SEQUENCE Service_Ticket_Seq\n&#160;AS INTEGER\n&#160;START WITH 1\n&#160;INCREMENT BY 1\n&#160;MINVALUE 1\n&#160;MAXVALUE 100\n&#160;CYCLE; \n&#160;\n<\/pre>\n<p> We have two departments in this delicatessen, meats and fish. If you have been to&#160; a Kosher market, you know that these two areas are kept separate. A ticket can be used in only one department.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;CREATE TABLE Meats\n(ticket_seq INTEGER NOT NULL PRIMARY KEY,\n&#160;meat_type VARCHAR(15) NOT NULL);\n&#160;\nCREATE TABLE Fish\n(ticket_seq INTEGER NOT NULL PRIMARY KEY,\n&#160;fish_type VARCHAR(15) NOT NULL);\n&#160;\nCREATE PROCEDURE Ticket_Service\n(@in_market_code CHAR(1),\n&#160;@in_product_name VARCHAR(15))\nAS\nBEGIN \nDECLARE @local_ticket_seq INTEGER;\nSET @local_ticket_seq = NEXT VALUE FOR Service_Ticket_Seq; \nIF @in_market_code = 'M'\nINSERT INTO Meats\nVALUES (@local_ticket_seq, @in_product_name);\nELSE IF @in_market_code = 'F'\n&#160;&#160; INSERT INTO Fish\n&#160;&#160; VALUES (@local_ticket_seq, @in_product_name);\nEND; \n<\/pre>\n<p>&#160;Now, let&#8217; call the procedure a few times:  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">EXEC Ticket_Service 'M', 'Brisket';\nEXEC Ticket_Service 'F', 'Lox';\nEXEC Ticket_Service 'M', 'Chicken';\nEXEC Ticket_Service 'M', 'Brisket';\nEXEC Ticket_Service 'F', 'Sturgeon'; \nEXEC Ticket_Service 'F', 'Haddock';\n<\/pre>\n<p> &#160;And now let&#8217;s see how this works.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;SELECT * FROM Meats;<\/pre>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p> \t\t1<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\tBrisket<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p> \t\t3<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\tChicken<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p> \t\t4<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\tBrisket<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;SELECT * FROM Fish;<\/pre>\n<table class=\"MsoNormalTable\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p> \t\t2<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\tLox<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p> \t\t5<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\tSturgeon<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p> \t\t6<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\tHaddock<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> &#160;If I <code>UNION<\/code> the two tables, I get a complete sequence and I am sure their intersection is empty. Doing this  without a <code>SEQUENCE<\/code> is a lot harder. But I did resort to if-then-else flow control because I have two different tables.  UGH!<\/p>\n<p>I can put a <code>SEQUENCE<\/code> in the <code>DEFAULT<\/code> clause of the DDL for table:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">CREATE TABLE&#160;Service_Tickets\n(ticket_nbr&#160;INTEGER&#160;DEFAULT&#160;NEXT&#160;VALUE FOR Service_Ticket_Seq,\n&#160;department_code CHAR(1) NOT NULL\n&#160; &#160;CHECK (department_code IN ('M', 'F'))); \n&#160;\n<\/pre>\n<p> Now play with this code.  <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">&#160;\nINSERT INTO Service_Tickets (department_code)\nVALUES ('M');\n&#160;\nSELECT * FROM Service_Tickets;\n<\/pre>\n<p> &#160;That is cool! But do not stop here. Let&#8217;s re-do the Meats and Fish tables with this feature, because  we can then do inserts without the need for a procedure and still be sure of an  empty intersection: <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">CREATE TABLE Meats\n(ticket_seq INTEGER DEFAULT&#160;NEXT&#160;VALUE FOR Service_Ticket_Seq \n&#160;&#160;&#160;&#160;&#160;&#160; PRIMARY KEY,\n&#160;meat_type VARCHAR(15) NOT NULL);\n&#160;\nCREATE TABLE Fish\n(ticket_seq INTEGER DEFAULT&#160;NEXT&#160;VALUE FOR Service_Ticket_Seq \n&#160;&#160;&#160;&#160;&#160;&#160; PRIMARY KEY,\n&#160;fish_type VARCHAR(15) NOT NULL);\n<\/pre>\n<p>  Now, to get you started,&#160; try these statements. I dropped the kosher theme \ud83d\ude42<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">INSERT INTO Meats (meat_type) VALUES ('pig');\nINSERT INTO Fish (fish_type) VALUES ('squid');\nSELECT * FROM Meats;\nSELECT * FROM Fish;\n<\/pre>\n<p> &#160;There are no guarantees as to how the sequence numbers will be assigned; it is pretty much first-come,  first-served in the system. Did you notice that the sequences are the <code>PRIMARY KEY<\/code>? <\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">INSERT INTO Meats VALUES (8, 'Cat');<\/pre>\n<p>will give us:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql highlight:0 decode:true\">Msg 2627, Level 14, State 1, Line 1\nViolation of PRIMARY KEY constraint 'PK__Meats__467BFD06C5684404'. Cannot insert duplicate key in object 'dbo.Meats'. The duplicate key value is (8).\nThe statement has been terminated.\n<\/pre>\n<p>And this is all declarative code! <\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>The SEQUENCE statement  introduced in SQL Server 2012 brings the ANSI SQL 2003 standard method of generating IDs. This is a great relief to database professionals as it solves some problems what are awkward to solve with the IDENTITY property. Joe Celko explains the basics of using a SEQUENCE&hellip;<\/p>\n","protected":false},"author":96214,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143525],"tags":[4242,4168,4149,4150,5134,4151],"coauthors":[6781],"class_list":["post-1757","post","type-post","status-publish","format-standard","hentry","category-learn","tag-basics","tag-database","tag-learn-sql-server","tag-sql","tag-sql-prompt","tag-sql-server"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1757","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\/96214"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1757"}],"version-history":[{"count":3,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1757\/revisions"}],"predecessor-version":[{"id":40997,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1757\/revisions\/40997"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1757"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1757"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1757"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}