{"id":1811,"date":"2014-06-04T12:02:54","date_gmt":"2014-06-04T12:02:54","guid":{"rendered":"http:\/\/www.sqlshack.com\/?p=1811"},"modified":"2020-03-10T12:19:47","modified_gmt":"2020-03-10T12:19:47","slug":"sql-server-cursor-tutorial","status":"publish","type":"post","link":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/","title":{"rendered":"SQL Server cursor tutorial"},"content":{"rendered":"<br \/>\n<h2>Introduction<\/h2>\n<p>Most people that work with Microsoft SQL Server will have at least heard talk of cursors and often, even if people know on a basic level what SQL Server cursors do, they are not always certain when to use them and how to write the code behind them. So this article takes a step back and provides an explanation as to what SQL Server cursors can be used for as well as a basic example that you can run for yourself to test.<br \/>\n    <!--more--><\/p>\n<h2>Transactional versus Procedural Programming<\/h2>\n<p>SQL Server is a relational database management system (RDBMS), and T-SQL is a transactional programming language. This means that it is designed to execute its work in all-or-nothing runs. The database engine is optimized to work in this manner and, in general, it is more than sufficient to execute simple all-in-one type transactions.<\/p>\n<p>Many other programming languages including C# and Visual Basic are iterative or procedural programming languages whereby the general flow of things is to treat each instance of an object separately and when dealing with many objects one would tend to loop over the same code until the stack is diminished and processed. <\/p>\n<p>Cursors however, like <a href=\"https:\/\/docs.microsoft.com\/en-us\/previous-versions\/sql\/sql-server-2008-r2\/ms190385(v=sql.105)\" target=\"_blank\" rel=\"noopener noreferrer\">WHILE<\/a> loops, break away from the transactional nature of T-SQL and allow for programmers to treat each result of a SELECT statement in a certain way by looping through them.<\/p>\n<p>In the IT Engineering world it is common place for people to learn languages like C#, VB, java, C++ or any other the other iterative-type languages before having to deal with SQL in any real\/advanced way. It is for this reason, and sadly so, that SQL Server cursors are often very prolific in some applications. It is a common trap that developers fall into and for good reason. The logic behind cursors can be perfect and the idea of writing one can seem good but one runs into real problems when it comes to performance because SQL Server is no longer about to treat whole chunks of data at once and instead has to repeat reads and writes for each result (which can be catastrophic for I\/O performance)<\/p>\n<p>Therefore, as a general rule of thumb, and for good performance do not use cursors.<\/p>\n<p>However, there are some situations in which cursors can be lifesavers. I can think of a couple right off the bat:<\/p>\n<ol>\n<li>Concurrent queries: Sometimes, in OLTP (OnLine Transaction Processing) systems, there are just too many users actively querying a specific table. This is OK for small transactions as they are lightning fast and do not require locks on large chunks of the underlying tables. But in order to be able to update the entire table SQL Server often has to create a huge lock that blocks all other activity on the same table. This is in order to protect data consistency. If it was not the case a concurrent use could come along and SELECT rows from the table that are half updated and half not updated. There are server level options to handle the type of read commitments, these are called <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/statements\/set-transaction-isolation-level-transact-sql?view=sql-server-ver15\">transaction isolation levels<\/a> and they are outside of the scope of this article. However, if one has a READ COMMITTED transaction isolation level which is the case by default, SQL Server cursors or while loops can be helpful to break full table updates into multiple smaller batches. <\/li>\n<li>The second case where cursors may be useful is to create a \u201cfor each\u201d type logic in T-SQL scripts. For example, if one would like to handle the deployment of individual tables to another database one could use a cursor and sp_executeSql to run a chunk of T-SQL for each table in a give list.<\/li>\n<\/ol>\n<p>In the example below we will loop through the contents of a table and select the description of each ID we find.<\/p>\n<p>Take this simple table as an example:<\/p>\n<pre class=\"lang:tsql\">CREATE TABLE #ITEMS (ITEM_ID uniqueidentifier NOT NULL, ITEM_DESCRIPTION VARCHAR(250) NOT NULL)\r\nINSERT INTO #ITEMS\r\nVALUES\r\n(NEWID(), 'This is a wonderful car'),\r\n(NEWID(), 'This is a fast bike'),\r\n(NEWID(), 'This is a expensive aeroplane'),\r\n(NEWID(), 'This is a cheap bicycle'),\r\n(NEWID(), 'This is a dream holiday')<\/pre>\n<p>Here are the results of a SELECT * FROM #ITEMS query:<\/p>\n<p><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" data-src=\"\/wp-content\/uploads\/2014\/06\/QueryResults.png\" alt=\"Dialog showing the results of a SELECT * FROM #ITEMS query\" \/><noscript><img decoding=\"async\" src=\"\/wp-content\/uploads\/2014\/06\/QueryResults.png\" alt=\"Dialog showing the results of a SELECT * FROM #ITEMS query\" \/><\/noscript><\/p>\n<p>Now say we want to cut the selection of each description into 5 separate transactions. Here is the basic T-SQL cursor syntax to do that. <\/p>\n<pre class=\"lang:tsql\">DECLARE @ITEM_ID uniqueidentifier  -- Here we create a variable that will contain the ID of each row.\r\n\r\nDECLARE ITEM_CURSOR CURSOR  -- Here we prepare the cursor and give the select statement to iterate through\r\nFOR\r\nSELECT ITEM_ID\r\nFROM #ITEMS\r\n\r\nOPEN ITEM_CURSOR -- This charges the results to memory\r\n\r\nFETCH NEXT FROM ITEM_CURSOR INTO @ITEM_ID -- We fetch the first result\r\n\r\nWHILE @@FETCH_STATUS = 0 --If the fetch went well then we go for it\r\nBEGIN\r\n\r\nSELECT ITEM_DESCRIPTION -- Our select statement (here you can do whatever work you wish)\r\nFROM #ITEMS\r\nWHERE ITEM_ID = @ITEM_ID -- In regards to our latest fetched ID\r\n\r\nFETCH NEXT FROM ITEM_CURSOR INTO @ITEM_ID -- Once the work is done we fetch the next result\r\n\r\nEND\r\n-- We arrive here when @@FETCH_STATUS shows there are no more results to treat\r\nCLOSE ITEM_CURSOR  \r\nDEALLOCATE ITEM_CURSOR -- CLOSE and DEALLOCATE remove the data from memory and clean up the process<\/pre>\n<p>Running the basic SQL Server cursor above will loop through each ID in the #ITEMS table and SELECT its corresponding ITEM_DESCRIPTION in 5 separate transactions. You should get the following results after executing the cursor:<\/p>\n<p><a href=\"\/wp-content\/uploads\/2014\/06\/CursorResults.png\" rel=\"lightbox[1]\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" data-src=\"\/wp-content\/uploads\/2014\/06\/CursorResults_s.png\" alt=\"Dialog showing the results after executing the SQL Server cursor\" \/><noscript><img decoding=\"async\" src=\"\/wp-content\/uploads\/2014\/06\/CursorResults_s.png\" alt=\"Dialog showing the results after executing the SQL Server cursor\" \/><\/noscript><\/a><\/p>\n<p>This example may see pointless but consider the fact that you can write any T-SQL you like in between<\/p>\n<pre class=\"lang:tsql\">WHILE @@FETCH_STATUS = 0 \r\nBEGIN\r\n\u2026and\u2026\r\n\r\nFETCH NEXT FROM [CursorName]<\/pre>\n<p>You can certainly imagine many possible usages.<\/p>\n<h2>Conclusion<\/h2>\n<p>This article is not meant to be used to proliferate the use of SQL Server cursors even more throughout your applications. As a general rule of thumb one should always think twice, even three times whether the use of a cursor is acceptable for their current problem. 99% of the time the same problem can be dealt with in a purely transactional manner, as is the norm in T-SQL. However, as mentioned above, there are certain exceptions to that rule when it becomes perfectly acceptable to sacrifice performance to avoid blocking the application or just because there is no other option (this is very rarely the case in IT)<\/p>\n<p>So, if you have determined that you absolutely need to use a SQL Server cursor, go ahead and build on the example above.<\/p>\n<div id=\"see_more\"><\/div>\n<p><script>\ndisplay_see_more(text='plan', video='plan', banner='plan', banner_link='plan');\n<\/script><br \/>\n<\/br><\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Introduction Most people that work with Microsoft SQL Server will have at least heard talk of cursors and often, even if people know on a basic level what SQL Server cursors do, they are not always certain when to use them and how to write the code behind them. So this article takes a step [&hellip;]<!-- AddThis Advanced Settings generic via filter on wp_trim_excerpt --><!-- AddThis Share Buttons generic via filter on wp_trim_excerpt --><\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[],"class_list":["post-1811","post","type-post","status-publish","format-standard","hentry","category-sql-server-cursors"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>SQL Server cursor tutorial<\/title>\n<meta name=\"description\" content=\"This article provides an explanation for what SQL Server cursors can be used , as well as a basic example that you can run for yourself to test.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server cursor tutorial\" \/>\n<meta property=\"og:description\" content=\"This article provides an explanation for what SQL Server cursors can be used , as well as a basic example that you can run for yourself to test.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/\" \/>\n<meta property=\"og:site_name\" content=\"SQL Shack - articles about database auditing, server performance, data recovery, and more\" \/>\n<meta property=\"article:published_time\" content=\"2014-06-04T12:02:54+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-03-10T12:19:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.sqlshack.com\/wp-content\/uploads\/2014\/06\/QueryResults.png\" \/>\n<meta name=\"author\" content=\"Evan Barke\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Evan Barke\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/sql-server-cursor-tutorial\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/sql-server-cursor-tutorial\\\/\"},\"author\":{\"name\":\"Evan Barke\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#\\\/schema\\\/person\\\/ab4f2034466266f96b18d70277ef5f3b\"},\"headline\":\"SQL Server cursor tutorial\",\"datePublished\":\"2014-06-04T12:02:54+00:00\",\"dateModified\":\"2020-03-10T12:19:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/sql-server-cursor-tutorial\\\/\"},\"wordCount\":876,\"commentCount\":3,\"publisher\":{\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#organization\"},\"articleSection\":[\"Cursors\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/sql-server-cursor-tutorial\\\/\",\"url\":\"https:\\\/\\\/www.sqlshack.com\\\/sql-server-cursor-tutorial\\\/\",\"name\":\"SQL Server cursor tutorial\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#website\"},\"datePublished\":\"2014-06-04T12:02:54+00:00\",\"dateModified\":\"2020-03-10T12:19:47+00:00\",\"description\":\"This article provides an explanation for what SQL Server cursors can be used , as well as a basic example that you can run for yourself to test.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.sqlshack.com\\\/sql-server-cursor-tutorial\\\/\"]}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#website\",\"url\":\"https:\\\/\\\/www.sqlshack.com\\\/\",\"name\":\"SQL Shack - articles about database auditing, server performance, data recovery, and more\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.sqlshack.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#organization\",\"name\":\"SQL Shack\",\"url\":\"https:\\\/\\\/www.sqlshack.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.sqlshack.com\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/sqlshack-default.png\",\"contentUrl\":\"https:\\\/\\\/www.sqlshack.com\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/sqlshack-default.png\",\"width\":1200,\"height\":630,\"caption\":\"SQL Shack\"},\"image\":{\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.sqlshack.com\\\/#\\\/schema\\\/person\\\/ab4f2034466266f96b18d70277ef5f3b\",\"name\":\"Evan Barke\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce31fd9e332521654d48f46d4a93ca1aeb234bb56695a75489830d2e9aea1770?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce31fd9e332521654d48f46d4a93ca1aeb234bb56695a75489830d2e9aea1770?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce31fd9e332521654d48f46d4a93ca1aeb234bb56695a75489830d2e9aea1770?s=96&d=mm&r=g\",\"caption\":\"Evan Barke\"},\"description\":\"Having worked on highly transactional production systems and advanced corporate business intelligence, Evan is now using this experience make a difference in the eHealth world. He is driven by the love of technology and a desire to solve complex problems creatively. View all posts by Evan Barke\",\"url\":\"https:\\\/\\\/www.sqlshack.com\\\/author\\\/evan-barke\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"SQL Server cursor tutorial","description":"This article provides an explanation for what SQL Server cursors can be used , as well as a basic example that you can run for yourself to test.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/","og_locale":"en_US","og_type":"article","og_title":"SQL Server cursor tutorial","og_description":"This article provides an explanation for what SQL Server cursors can be used , as well as a basic example that you can run for yourself to test.","og_url":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/","og_site_name":"SQL Shack - articles about database auditing, server performance, data recovery, and more","article_published_time":"2014-06-04T12:02:54+00:00","article_modified_time":"2020-03-10T12:19:47+00:00","og_image":[{"url":"https:\/\/www.sqlshack.com\/wp-content\/uploads\/2014\/06\/QueryResults.png","type":"","width":"","height":""}],"author":"Evan Barke","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Evan Barke","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/#article","isPartOf":{"@id":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/"},"author":{"name":"Evan Barke","@id":"https:\/\/www.sqlshack.com\/#\/schema\/person\/ab4f2034466266f96b18d70277ef5f3b"},"headline":"SQL Server cursor tutorial","datePublished":"2014-06-04T12:02:54+00:00","dateModified":"2020-03-10T12:19:47+00:00","mainEntityOfPage":{"@id":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/"},"wordCount":876,"commentCount":3,"publisher":{"@id":"https:\/\/www.sqlshack.com\/#organization"},"articleSection":["Cursors"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/","url":"https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/","name":"SQL Server cursor tutorial","isPartOf":{"@id":"https:\/\/www.sqlshack.com\/#website"},"datePublished":"2014-06-04T12:02:54+00:00","dateModified":"2020-03-10T12:19:47+00:00","description":"This article provides an explanation for what SQL Server cursors can be used , as well as a basic example that you can run for yourself to test.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlshack.com\/sql-server-cursor-tutorial\/"]}]},{"@type":"WebSite","@id":"https:\/\/www.sqlshack.com\/#website","url":"https:\/\/www.sqlshack.com\/","name":"SQL Shack - articles about database auditing, server performance, data recovery, and more","description":"","publisher":{"@id":"https:\/\/www.sqlshack.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlshack.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.sqlshack.com\/#organization","name":"SQL Shack","url":"https:\/\/www.sqlshack.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlshack.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.sqlshack.com\/wp-content\/uploads\/2019\/03\/sqlshack-default.png","contentUrl":"https:\/\/www.sqlshack.com\/wp-content\/uploads\/2019\/03\/sqlshack-default.png","width":1200,"height":630,"caption":"SQL Shack"},"image":{"@id":"https:\/\/www.sqlshack.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.sqlshack.com\/#\/schema\/person\/ab4f2034466266f96b18d70277ef5f3b","name":"Evan Barke","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ce31fd9e332521654d48f46d4a93ca1aeb234bb56695a75489830d2e9aea1770?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/ce31fd9e332521654d48f46d4a93ca1aeb234bb56695a75489830d2e9aea1770?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ce31fd9e332521654d48f46d4a93ca1aeb234bb56695a75489830d2e9aea1770?s=96&d=mm&r=g","caption":"Evan Barke"},"description":"Having worked on highly transactional production systems and advanced corporate business intelligence, Evan is now using this experience make a difference in the eHealth world. He is driven by the love of technology and a desire to solve complex problems creatively. View all posts by Evan Barke","url":"https:\/\/www.sqlshack.com\/author\/evan-barke\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/posts\/1811","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/comments?post=1811"}],"version-history":[{"count":10,"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/posts\/1811\/revisions"}],"predecessor-version":[{"id":37735,"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/posts\/1811\/revisions\/37735"}],"wp:attachment":[{"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/media?parent=1811"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/categories?post=1811"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlshack.com\/wp-json\/wp\/v2\/tags?post=1811"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}