<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SQL Server & Azure Database Development, Tuning & Optimization Blog]]></title><description><![CDATA[Explore SQL Server and Azure Database tuning, development tips, and cloud services. MSSQLServer.dev offers guides, scripts, and expert advices for database & software developments]]></description><link>https://mssqlserver.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 23:47:40 GMT</lastBuildDate><atom:link href="https://mssqlserver.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Learning Real-World Performance Skills from SQL & PostgreSQL Interview Experiences]]></title><description><![CDATA[I recently completed a series of interviews for engineering roles, and one key theme stood out: SQL and PostgreSQL aren’t just about writing queries — they’re about knowing how data systems work under pressure.
On my main blog, I broke down:

The exa...]]></description><link>https://mssqlserver.dev/learning-real-world-performance-skills-from-sql-and-postgresql-interview-experiences</link><guid isPermaLink="true">https://mssqlserver.dev/learning-real-world-performance-skills-from-sql-and-postgresql-interview-experiences</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[SQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Sat, 12 Jul 2025 16:19:47 GMT</pubDate><content:encoded><![CDATA[<p>I recently completed a series of interviews for engineering roles, and one key theme stood out: <strong>SQL and PostgreSQL aren’t just about writing queries — they’re about knowing how data systems work under pressure.</strong></p>
<p>On my main blog, I broke down:</p>
<ul>
<li><p>The exact SQL problems I was asked (recursive queries, windowing, multi-level filtering)</p>
</li>
<li><p>Advanced PostgreSQL internals, like execution plans, sharding design, and logical replication</p>
</li>
<li><p>Real discussions around performance bottlenecks, indexing decisions, and CDC strategies</p>
</li>
</ul>
<p>🎯 Whether you’re prepping for a systems-heavy role or improving your Postgres stack, this walkthrough will help.</p>
<p><a target="_blank" href="https://kiransabne.dev/cracking-the-sql-interview-real-questions-and-postgresql-internals-you-should-know">👉 Read the full post here</a></p>
]]></content:encoded></item><item><title><![CDATA[In-Memory OLTP for Faster SQL Server: Your Complete Guide]]></title><description><![CDATA[In today's data-driven world, speed and performance are crucial for staying ahead. SQL Server's In-Memory OLTP (Hekaton) is a great feature that helps businesses meet the needs of high-performance, low-latency applications. Whether you're working on ...]]></description><link>https://mssqlserver.dev/in-memory-oltp-for-faster-sql-server-your-complete-guide</link><guid isPermaLink="true">https://mssqlserver.dev/in-memory-oltp-for-faster-sql-server-your-complete-guide</guid><category><![CDATA[SQL Server]]></category><category><![CDATA[#SQLtutorial ]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[Azure SQL Database]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Mon, 09 Dec 2024 18:32:22 GMT</pubDate><content:encoded><![CDATA[<p>In today's data-driven world, speed and performance are crucial for staying ahead. SQL Server's <strong>In-Memory OLTP (Hekaton)</strong> is a great feature that helps businesses meet the needs of high-performance, low-latency applications. Whether you're working on real-time analytics, high-throughput transaction systems, or caching solutions, In-Memory OLTP can be a game-changer.</p>
<p>In this blog, we'll explore everything about Microsoft SQL Server In-Memory OLTP—what it is, its use cases, benefits, limitations, and practical examples using the <strong>AdventureWorks</strong> database. This guide will also cover best practices, monitoring tips, and how to optimize hash bucket counts for memory-optimized tables.</p>
<h3 id="heading-what-is-sql-server-in-memory-oltp">What is SQL Server In-Memory OLTP?</h3>
<p>SQL Server In-Memory OLTP is a memory-optimized database engine designed to dramatically improve the performance of transaction-heavy workloads. By keeping tables and indexes in memory and using natively compiled stored procedures, it minimizes latency and maximizes throughput.</p>
<h4 id="heading-key-features"><strong>Key Features</strong></h4>
<ol>
<li><p><strong>Memory-Optimized Tables</strong>: Store tables entirely in memory for ultra-fast access.</p>
</li>
<li><p><strong>Natively Compiled Stored Procedures</strong>: Execute T-SQL procedures as native machine code.</p>
</li>
<li><p><strong>Optimistic Concurrency</strong>: Reduce lock contention for highly concurrent workloads.</p>
</li>
<li><p><strong>Hybrid Durability</strong>: Choose between fully durable (persistent to disk) and non-durable (memory-only) options.</p>
</li>
<li><p><strong>Optimized Indexing</strong>: Supports hash and range indexes tailored for specific query patterns.</p>
</li>
</ol>
<h3 id="heading-when-to-use-in-memory-oltp">When to Use In-Memory OLTP</h3>
<p>Not every situation requires In-Memory OLTP. It's most effective for:</p>
<ul>
<li><p><strong>High-Throughput Applications</strong>: Payment systems, stock trading platforms.</p>
</li>
<li><p><strong>Real-Time Analytics</strong>: IoT dashboards, e-commerce order analytics.</p>
</li>
<li><p><strong>Session Management</strong>: Web applications handling large user sessions.</p>
</li>
<li><p><strong>Caching Layers</strong>: Storing frequently accessed reference data.</p>
</li>
<li><p><strong>Gaming Leaderboards</strong>: Fast-paced updates and queries.</p>
</li>
</ul>
<h3 id="heading-limitations-of-in-memory-oltp">Limitations of In-Memory OLTP</h3>
<ol>
<li><p><strong>RAM Dependency</strong>: Requires sufficient physical memory to store tables and indexes.</p>
</li>
<li><p><strong>T-SQL Limitations</strong>: Not all T-SQL features (e.g., triggers, foreign keys) are supported.</p>
</li>
<li><p><strong>Durability Trade-Offs</strong>: Non-durable tables lose data on server restart.</p>
</li>
<li><p><strong>Indexing Constraints</strong>: Supports only hash and range indexes.</p>
</li>
<li><p><strong>Maintenance Overhead</strong>: Requires careful schema planning and memory monitoring.</p>
</li>
</ol>
<hr />
<h3 id="heading-hands-on-implementing-in-memory-oltp-with-adventureworks">Hands-On: Implementing In-Memory OLTP with AdventureWorks</h3>
<p>Let's get practical and implement In-Memory OLTP using the <strong>AdventureWorks</strong> database. We'll create a memory-optimized table to cache product data and boost query performance.</p>
<h4 id="heading-step-1-set-up-the-adventureworks-database"><strong>Step 1: Set Up the AdventureWorks Database</strong></h4>
<p>First, download and restore the AdventureWorks database:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">RESTORE</span> <span class="hljs-keyword">DATABASE</span> AdventureWorks
<span class="hljs-keyword">FROM</span> DISK = <span class="hljs-string">'C:\AdventureWorks.bak'</span>
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">MOVE</span> <span class="hljs-string">'AdventureWorks_Data'</span> <span class="hljs-keyword">TO</span> <span class="hljs-string">'C:\AdventureWorks_Data.mdf'</span>,
     <span class="hljs-keyword">MOVE</span> <span class="hljs-string">'AdventureWorks_Log'</span> <span class="hljs-keyword">TO</span> <span class="hljs-string">'C:\AdventureWorks_Log.ldf'</span>;
</code></pre>
<hr />
<h4 id="heading-step-2-add-a-memory-optimized-filegroup"><strong>Step 2: Add a Memory-Optimized Filegroup</strong></h4>
<p>Memory-optimized tables require a special filegroup:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">DATABASE</span> AdventureWorks
<span class="hljs-keyword">ADD</span> FILEGROUP InMemoryFG CONTAINS MEMORY_OPTIMIZED_DATA;

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">DATABASE</span> AdventureWorks
<span class="hljs-keyword">ADD</span> <span class="hljs-keyword">FILE</span> (<span class="hljs-keyword">NAME</span> = <span class="hljs-string">'InMemoryFile'</span>, FILENAME = <span class="hljs-string">'C:\InMemoryFile'</span>) 
<span class="hljs-keyword">TO</span> FILEGROUP InMemoryFG;
</code></pre>
<hr />
<h4 id="heading-step-3-create-a-memory-optimized-table"><strong>Step 3: Create a Memory-Optimized Table</strong></h4>
<p>We'll create a memory-optimized table to cache product data:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> dbo.MemoryOptimizedProductCache (
    ProductID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> PRIMARY <span class="hljs-keyword">KEY</span> NONCLUSTERED <span class="hljs-keyword">HASH</span> <span class="hljs-keyword">WITH</span> (BUCKET_COUNT = <span class="hljs-number">10000</span>),
    <span class="hljs-keyword">Name</span> <span class="hljs-keyword">NVARCHAR</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    ListPrice MONEY <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
) <span class="hljs-keyword">WITH</span> (MEMORY_OPTIMIZED = <span class="hljs-keyword">ON</span>, DURABILITY = SCHEMA_ONLY);
</code></pre>
<hr />
<h4 id="heading-step-4-populate-the-table"><strong>Step 4: Populate the Table</strong></h4>
<p>Load data from the <code>Production.Product</code> table:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> dbo.MemoryOptimizedProductCache (ProductID, <span class="hljs-keyword">Name</span>, ListPrice)
<span class="hljs-keyword">SELECT</span> ProductID, <span class="hljs-keyword">Name</span>, ListPrice
<span class="hljs-keyword">FROM</span> Production.Product;
</code></pre>
<hr />
<h4 id="heading-step-5-query-the-memory-optimized-table"><strong>Step 5: Query the Memory-Optimized Table</strong></h4>
<p>Run a query to retrieve high-value products:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * 
<span class="hljs-keyword">FROM</span> dbo.MemoryOptimizedProductCache
<span class="hljs-keyword">WHERE</span> ListPrice &gt; <span class="hljs-number">500</span>;
</code></pre>
<hr />
<h4 id="heading-step-6-create-a-natively-compiled-stored-procedure"><strong>Step 6: Create a Natively Compiled Stored Procedure</strong></h4>
<p>Boost performance further with a natively compiled stored procedure:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">PROCEDURE</span> dbo.UpdateProductPrice
<span class="hljs-keyword">WITH</span> NATIVE_COMPILATION, SCHEMABINDING
<span class="hljs-keyword">AS</span> <span class="hljs-keyword">BEGIN</span> ATOMIC <span class="hljs-keyword">WITH</span> (<span class="hljs-keyword">TRANSACTION</span> <span class="hljs-keyword">ISOLATION</span> <span class="hljs-keyword">LEVEL</span> = <span class="hljs-keyword">SNAPSHOT</span>, <span class="hljs-keyword">LANGUAGE</span> = <span class="hljs-string">'English'</span>)
    <span class="hljs-keyword">UPDATE</span> dbo.MemoryOptimizedProductCache
    <span class="hljs-keyword">SET</span> ListPrice = ListPrice * <span class="hljs-number">1.10</span>
    <span class="hljs-keyword">WHERE</span> ProductID = <span class="hljs-number">1</span>;
<span class="hljs-keyword">END</span>;
</code></pre>
<p>Execute the procedure:</p>
<pre><code class="lang-sql">EXEC dbo.UpdateProductPrice;
</code></pre>
<p>Verify the changes:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * 
<span class="hljs-keyword">FROM</span> dbo.MemoryOptimizedProductCache
<span class="hljs-keyword">WHERE</span> ProductID = <span class="hljs-number">1</span>;
</code></pre>
<h3 id="heading-optimizing-hash-bucket-count">Optimizing Hash Bucket Count</h3>
<p>The <code>BUCKET_COUNT</code> in a hash index determines the number of "slots" for rows. Setting it correctly reduces hash collisions and enhances query performance.</p>
<h4 id="heading-guidelines-for-setting-bucketcount"><strong>Guidelines for Setting BUCKET_COUNT</strong></h4>
<ol>
<li><p><strong>Match Row Count</strong>: Set <code>BUCKET_COUNT</code> equal to or slightly greater than the estimated row count. Example: For 1 million rows, use:</p>
<pre><code class="lang-sql"> BUCKET_COUNT = 1000000;
</code></pre>
</li>
<li><p><strong>Avoid Over-Provisioning</strong>: Too high a <code>BUCKET_COUNT</code> wastes memory.</p>
</li>
<li><p><strong>Use Powers of 2</strong>: SQL Server performs better with bucket counts as powers of 2.</p>
</li>
</ol>
<h4 id="heading-monitor-collisions"><strong>Monitor Collisions</strong></h4>
<p>Use DMVs to check hash index statistics:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> object_name(object_id) <span class="hljs-keyword">AS</span> TableName,
       bucket_count,
       <span class="hljs-keyword">row_count</span>,
       hash_collisions
<span class="hljs-keyword">FROM</span> sys.dm_db_xtp_hash_index_stats
<span class="hljs-keyword">WHERE</span> object_id = OBJECT_ID(<span class="hljs-string">'dbo.MemoryOptimizedProductCache'</span>);
</code></pre>
<hr />
<h3 id="heading-cleaning-and-maintaining-in-memory-oltp-tables">Cleaning and Maintaining In-Memory OLTP Tables</h3>
<h4 id="heading-1-cleaning-the-table"><strong>1. Cleaning the Table</strong></h4>
<ul>
<li><p><strong>TRUNCATE</strong>:</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">TRUNCATE</span> <span class="hljs-keyword">TABLE</span> dbo.MemoryOptimizedProductCache;
</code></pre>
</li>
<li><p><strong>DELETE</strong>:</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> dbo.MemoryOptimizedProductCache <span class="hljs-keyword">WHERE</span> ListPrice &lt; <span class="hljs-number">100</span>;
</code></pre>
</li>
</ul>
<h4 id="heading-2-shrinking-checkpoint-files"><strong>2. Shrinking Checkpoint Files</strong></h4>
<p>For durable tables (<code>SCHEMA_AND_DATA</code>), reduce checkpoint file size:</p>
<pre><code class="lang-sql">CHECKPOINT;
</code></pre>
<h3 id="heading-monitoring-in-memory-oltp">Monitoring In-Memory OLTP</h3>
<p>Use the following DMVs to monitor memory-optimized tables:</p>
<ol>
<li><p><strong>Memory Usage</strong>:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> sys.dm_db_xtp_memory_consumers;
</code></pre>
</li>
<li><p><strong>Checkpoint Stats</strong>:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> sys.dm_db_xtp_checkpoint_stats;
</code></pre>
</li>
<li><p><strong>Garbage Collection</strong>:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> sys.dm_xtp_gc_stats;
</code></pre>
</li>
</ol>
<h3 id="heading-points-to-note">Points to Note</h3>
<ol>
<li><p><strong>Plan Memory Usage</strong>: Allocate sufficient RAM and monitor usage.</p>
</li>
<li><p><strong>Index Smartly</strong>: Use hash indexes for equality searches and range indexes for range queries.</p>
</li>
<li><p><strong>Choose Durability Wisely</strong>: Use <code>SCHEMA_ONLY</code> for non-critical data and <code>SCHEMA_AND_DATA</code> for persistence.</p>
</li>
<li><p><strong>Monitor Regularly</strong>: Use DMVs to identify bottlenecks and optimize performance.</p>
</li>
</ol>
<hr />
<h3 id="heading-summary"><strong>Summary</strong></h3>
<p>SQL Server In-Memory OLTP is a powerful tool for high-performance applications. By using memory-optimized tables and natively compiled procedures, you can achieve unprecedented speed and scalability for transaction-heavy workloads. However, success requires careful planning, proper configuration, and regular monitoring. Implement the techniques in this hands-on guide with the AdventureWorks database and see the difference it makes to your application's performance. Have your insights? Share them in the comments below! For more detailed documentation, visit the official doc’s page.</p>
]]></content:encoded></item><item><title><![CDATA[Integrating Azure SQL Database with External REST APIs using sp_invoke_external_rest_endpoint and Azure API Management]]></title><description><![CDATA[This post demonstrates the integration of external Rest APIs with Azure SQL Database and Azure API Management Service. By utilizing the system-stored procedure sp_invoke_external_rest_endpoint, you can make REST calls to endpoints such as Azure Funct...]]></description><link>https://mssqlserver.dev/integrating-azure-sql-database-with-external-rest-apis-using-sp-invoke-external-rest-endpoint-and-azure-api-management</link><guid isPermaLink="true">https://mssqlserver.dev/integrating-azure-sql-database-with-external-rest-apis-using-sp-invoke-external-rest-endpoint-and-azure-api-management</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure SQL Database]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Azure Functions]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Mon, 30 Oct 2023 08:24:22 GMT</pubDate><content:encoded><![CDATA[<p>This post demonstrates the integration of external Rest APIs with Azure SQL Database and Azure API Management Service. By utilizing the system-stored procedure sp_invoke_external_rest_endpoint, you can make REST calls to endpoints such as Azure Functions in just a few lines of code. The sp_invoke_external_rest_endpoint works with various services including Azure Functions, Apps Service, App Service Environment, Static Web Apps, Container Instances, Logic Apps, Event Grids, Event Hubs, PowerApps, Cognitive Services, Power BI, Microsoft Graph, IoT Central, Analysis Services, and API management. If you wish to invoke an external REST API service not mentioned above, you can use the API management service to securely expose the desired service for use with sp_invoke_external_rest_endpoint. This post details how to make API calls from Azure SQL Database to a dummy JSON API by adding the REST endpoints to your Azure API Management Service.</p>
<p>To make REST API calls to external endpoints of dummy JSON, let's create API resources and add endpoints. Then API Management Service acts as a gateway for the external API calls and provides features such as caching and throttling.</p>
<h3 id="heading-azure-api-management-service-configuration">Azure API Management Service Configuration:</h3>
<p>When you log into your Azure portal, go to API Management Service, and create a new resource, if you don't have one already. When you open the resource, you will see the APIs tab on the left. When you click on APIs within the APIs tab, you will open a screen on the right where you can create and configure APIs as well as add operations to those APIs. To define a new API, click on the Add API tab and select http on the newly generated screen.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698652849369/bbb1aa2e-2c29-40b4-8607-5579df1bd35c.png" alt="azure_api_management_service_for_new_http_api_call" class="image--center mx-auto" /></p>
<p>A modal will open as shown below. Keep the type Basic and then provide Display Name and Name. Also, input the Web Service URL, we are using dummyjson for demonstration so input the base URL path of the same which is <a target="_blank" href="https://dummyjson.com">https://dummyjson.com</a> . After that click on create button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698652986902/2b2251dd-4039-4cd9-8e4e-9f9a87c3d9f8.png" alt class="image--center mx-auto" /></p>
<p>A new screen will be presented, allowing you to add and configure REST endpoint operations, as well as a Frontend Card for OpenAPI specification editor, Inbound and outbound processing to modify requests or responses, and finally, a Backend Card providing a form-based editor as well as a code-based editor.</p>
<p>By clicking on Add Operation, the Frontend form-based editor will open. Enter the desired details like Display Name and Name. In the URL input field, choose the HTTP method as GET to fetch all product data. Then, enter the endpoint path in the accompanying field, in our case, we added "/products". You may also provide descriptions and relevant tags. Below Description, there are several tabs such as Template, Query, Headers, Request, and Responses that allow you to specify necessary URL template parameters, additional query parameters, important request headers, request body information and define response status codes, content-types and schemas respectively. Finally, save your changes by clicking on the save button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698653096413/a1bf55da-cb2c-421d-8797-eddb23e20063.png" alt="creating GET http endpoint method in Azure API Management Services for external API call" class="image--center mx-auto" /></p>
<p>Then, select the operation we just created and click on the Test tab above to get the HTTP Request URL and Ocp-Apim Subscription Key. You can find them by scrolling down in the HTTP Request Section, inside the code snippet, and clicking on the eye icon.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698653285315/48721b2d-f2c5-4779-be8f-28be9c461f37.png" alt class="image--center mx-auto" /></p>
<p>Click the Send button below to test out the API call and see the response.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698653306921/36c41859-ef9c-48fb-948b-775844000097.png" alt="Testing GET http endpoint response in Azure API Management Services for external API call" class="image--center mx-auto" /></p>
<p>We have to connect Azure SQL Database, to call the API from T-SQL code. Below is the code for both the GET method and the POST method. You can add the POST endpoint operation to API Management Service with all the required fields and test it out.</p>
<h3 id="heading-making-external-api-endpoint-call-with-azure-sql-database">Making External API endpoint call with Azure SQL Database</h3>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span> @ret <span class="hljs-keyword">as</span> <span class="hljs-built_in">int</span>, @response <span class="hljs-keyword">as</span> <span class="hljs-keyword">nvarchar</span>(<span class="hljs-keyword">max</span>), @headers <span class="hljs-keyword">nvarchar</span>(<span class="hljs-number">4000</span>);
<span class="hljs-keyword">set</span> @headers = N<span class="hljs-string">'{"Ocp-Apim-Subscription-Key": "&lt;YourOcpApimSubscriptionKey&gt;"}'</span>;

exec @ret = sp_invoke_external_rest_endpoint 
    @method = 'GET',
    @url = 'https://api-management-service-kiran04.azure-api.net/products',
    @headers = @headers,
    @response = @response output,
    @timeout=30;
<span class="hljs-keyword">select</span> @ret <span class="hljs-keyword">as</span> ReturnCode, @response <span class="hljs-keyword">as</span> Response;

```
Below is the example for POST method for reference. You can try adding the POST endpoint operation in API Management Service <span class="hljs-keyword">with</span> <span class="hljs-keyword">all</span> the needed <span class="hljs-keyword">fields</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">test</span> it out. <span class="hljs-keyword">After</span> that you can try <span class="hljs-keyword">out</span> the POST operation <span class="hljs-keyword">with</span> below example code.
<span class="hljs-string">``</span><span class="hljs-string">`
declare @ret int, @response nvarchar(max), @payload nvarchar(max), @headers nvarchar(4000)
set @payload = N'{
  "title": "Large Paint Brush",
  "description": "An Large Paint Brush for painting on walls or large surface.",
  "price": 900,
  "discountPercentage": 1.96,
  "rating": 4.69,
  "stock": 94,
  "brand": "ABCXYZ",
  "category": "home appliances"
}'
set @headers = N'{"Ocp-Apim-Subscription-Key": "&lt;YourOcpApimSubscriptionKey&gt;"}';

exec @ret = sp_invoke_external_rest_endpoint
    @method = 'POST',
    @url = 'https://api-management-service-kiran04.azure-api.net/products/add',
    @headers = @headers,
    @payload = @payload,
    @timeout = 30,
    @response = @response output;

select @ret as ReturnCode, @response as Response;</span>
</code></pre>
<p>API Management Service is required since we were using external API endpoints for demonstration. As mentioned earlier, this is not required for using other Azure services.</p>
]]></content:encoded></item><item><title><![CDATA[Implementing History Table or System Version Temporal Table to Track Data History]]></title><description><![CDATA[System-Versioned Temporal Tables, also known as History Tables are a built-in feature that keeps track of data changes in SQL Server. Unlike regular tables that only show the current data state, these tables help in seamlessly capturing and preservin...]]></description><link>https://mssqlserver.dev/implementing-history-table-or-system-version-temporal-table-to-track-data-history</link><guid isPermaLink="true">https://mssqlserver.dev/implementing-history-table-or-system-version-temporal-table-to-track-data-history</guid><category><![CDATA[SQL Server]]></category><category><![CDATA[SQL]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[Databases]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Tue, 01 Aug 2023 10:41:10 GMT</pubDate><content:encoded><![CDATA[<p>System-Versioned Temporal Tables, also known as History Tables are a built-in feature that keeps track of data changes in SQL Server. Unlike regular tables that only show the current data state, these tables help in seamlessly capturing and preserving the complete history of data changes. This innovative feature eliminates the need for developers to create complex triggers or manage separate tables for tracking historical updates or deletions. By effortlessly recording and managing data history, System-Versioned Temporal Tables empower database administrators and developers to gain deeper insights, simplify auditing processes, and ensure compliance with ease.</p>
<p>As we normally know Tables provide a static representation of data, displaying only the latest updates. The historical changes or deleted records are lost, posing significant challenges for auditing, analysis, and regulatory compliance. Developers needed to resort to manual techniques, such as triggers and auxiliary tables, to maintain a record of the data's evolution. These methods are cumbersome, error-prone, and lack efficiency.</p>
<p>Hence, Here SQL Server's System Versioned Temporal Table is an apt solution to the limitations mentioned before. As it provides built-in support to automatically track the complete history of data changes without any external script. Each row in the table is associated with two timestamp columns of the datetime2 data type. This timestamp indicates the period during which the particular version of the record was valid. And these timestamps are automatically updated with every modification. The main table that stores current data is referred to as the current table, or simply as the temporal table.</p>
<p>During temporal table creation, users can specify an existing history table (which must be schema compliant) or let the system create a default history table. Some of the use cases are,</p>
<ul>
<li><p>With built-in history tracking of every data modification, auditing and compliance reporting task becomes a breeze increasing transparency and accountability.</p>
</li>
<li><p>This built-in feature helps to meet compliance standards and ensures adherence to regulatory guidelines.</p>
</li>
<li><p>It also provides a mechanism to Audit the data changes as the complete history is maintained Recovering from accidental data changes. For instance, if someone has wrongly deleted a record, because of the availability of the history data we can easily recover these deleted records.</p>
</li>
</ul>
<h2 id="heading-creating-temporal-table">Creating Temporal Table</h2>
<p>The syntax for an example temporal Table creation is as below,</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> dbo.department
(
  dept_id <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> PRIMARY <span class="hljs-keyword">KEY</span> CLUSTERED,
  dept_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  manager_id <span class="hljs-built_in">INT</span> <span class="hljs-literal">NULL</span>,
  parent_dept_id <span class="hljs-built_in">INT</span> <span class="hljs-literal">NULL</span>,
  valid_from DATETIME2 <span class="hljs-keyword">GENERATED</span> <span class="hljs-keyword">ALWAYS</span> <span class="hljs-keyword">AS</span> <span class="hljs-keyword">ROW</span> <span class="hljs-keyword">START</span> HIDDEN <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  valid_to DATETIME2 <span class="hljs-keyword">GENERATED</span> <span class="hljs-keyword">ALWAYS</span> <span class="hljs-keyword">AS</span> <span class="hljs-keyword">ROW</span> <span class="hljs-keyword">END</span> HIDDEN <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  <span class="hljs-keyword">PERIOD</span> <span class="hljs-keyword">FOR</span> SYSTEM_TIME (valid_from, valid_to)
)
<span class="hljs-keyword">WITH</span> (SYSTEM_VERSIONING = <span class="hljs-keyword">ON</span> (HISTORY_TABLE=dbo.department_history));
</code></pre>
<p>Few points to remember while creating a System Versioned table.</p>
<ol>
<li><p>The table must have a Primary Key, otherwise, it would raise the error.</p>
</li>
<li><p>The table must also have two DATETIME2 columns which store the start and end timestamps of the row's validity period. The "GENERATED ALWAYS AS ROW START" clause indicates the start time for the row, similarly "GENERATED ALWAYS AS ROW END" clause indicates the end time for the row.</p>
</li>
<li><p>The two columns that store the start time and end time for the rows shouldn't be null, otherwise, it will raise an error. Hence, the NOT NULL constraint is used.</p>
</li>
<li><p>The use of the HIDDEN flag for the period columns in System-Versioned Temporal Tables makes them effectively hidden from query results, ensuring a clean and streamlined view of the data. And when performing an INSERT INTO statement without specifying the column list, there is no need to provide values for these hidden columns in the values list. It's optional.</p>
</li>
<li><p>The PERIOD FOR SYSTEM_TIME(valid_from, valid_to) clause takes the names of the columns which was made for start and end timestamps. SQL Server Engine will use the columns to record the period for which a record is valid.</p>
</li>
<li><p>HISTORY_TABLE: This input parameter is used to specify the name of the History Table. And it's optional.</p>
</li>
<li><p>SYSTEM_VERSIONING: This argument is used to enable/disable system versioning on the table.</p>
</li>
</ol>
<p>After executing the above statement, if we look into the SSMS window we can see that a dbo.department table was created and it is marked as a System-Versioned table. Inside this table we can see a nested table dbo.department_history table created and marked as History Table as shown in the below image:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690882982565/6c2778b3-98b3-4ae9-8dd2-d6789ccf2ad8.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-dml-operations-on-temporal-table">DML operations on Temporal Table</h2>
<h3 id="heading-insert-operation">Insert Operation:</h3>
<p>Let us perform the insert operation to add a new record in the dbo.department table, with the statement below,</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> dbo.department (dept_id, dept_name, manager_id, parent_dept_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'HR Department'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> dbo.department (dept_id, dept_name, manager_id, parent_dept_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-string">'Sales Department'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>);
</code></pre>
<p>Since the columns valid_from and valid_to are marked as HIDDEN, we can skip to specify it in the insert statement. If these columns were not marked as HIDDEN, then we would have to pass DEFAULT as values for the columns. Let's check the records in the dbo.department table and dbo.department_history table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department;
<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department_history;
<span class="hljs-keyword">select</span> dept_id, dept_name, manager_id, parent_dept_id, valid_from, valid_to <span class="hljs-keyword">from</span> department;
</code></pre>
<p>We can see that the insert operation adds new records in the department (Temporal) table and not in the department_history history table. If you want to see the period's columns in the select statement, you need to mention it explicitly in the select statement. Since while creating the Temporal table, we marked these columns as HIDDEN it won't show unless mentioned explicitly like in the third select statement above.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690885076979/491a8b3e-b91e-451c-a74b-ac5430a0de2b.png" alt="sql_server_temporal_table_history_table_insert_example" class="image--center mx-auto" /></p>
<p>In the image, which is showing the outputs of the select statements of the Temporal &amp; History table also notice the periods columns valid_from and valid_to. The columns hold date-time value, valid_from represents the time of the execution of the insert statement and valid_to represents the maximum value of the DATETIME2 data type. This also indicates that the record is active.</p>
<h3 id="heading-update-operation">Update Operation:</h3>
<p>Now, let's try to update the department table to assign the manager_id value to HR Department and see how it reflects in the main (Temporal) table and History table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">update</span> department <span class="hljs-keyword">set</span> manager_id = <span class="hljs-number">1</span> <span class="hljs-keyword">where</span> dept_id = <span class="hljs-number">1</span>;
</code></pre>
<p>Again perform select queries on both department table and department_history table to check the output.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> dept_id, dept_name, manager_id, parent_dept_id, valid_from, valid_to <span class="hljs-keyword">from</span> department;
<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department_history;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690885231540/3016d345-eddf-48da-8e14-8519ae3bc941.png" alt="sql_server_temporal_table_history_table_update_example" class="image--center mx-auto" /></p>
<p>In the above image showing the outputs, you can see that the update of a record in the temporal table has resulted in inserting the record in its history table with the state of the record before the update and the end time i.e. valid_to column value will be the time at which the update statement is executed. And if you noticed, the temporal table which only holds the current state of the record is updated and the manager_id value is assigned. But the important part is that it has also updated the valid_from column value to the time at which the update statement is executed. The record is still active and has the maximum value of the DATETIME2 data type for the valid_to column.</p>
<p>Important point to note that, you cannot update the PERIOD column values (valid_from, valid_to) when the SYSTEM_VERSIONING is ON. If you need to update the PERIOD columns then first we need to disable the system versioning and then drop the PERIOD definition from the department table, which will make the tables become like any regular table and can perform any operations.</p>
<h3 id="heading-delete-operation">Delete Operation:</h3>
<p>Now we will perform a DELETE operation by deleting the record of the Sales department, which has dept_id of value 2.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> department <span class="hljs-keyword">WHERE</span> dept_id = <span class="hljs-number">2</span>;
</code></pre>
<p>After executing the above statement, we will perform the select queries like earlier and see how the delete operation has caused any changes in the Temporal table and History table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> dept_id, dept_name, manager_id, parent_dept_id, valid_from, valid_to <span class="hljs-keyword">from</span> department;
<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department_history;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690885367259/afd27511-10c9-4274-a62a-b7e2874b7e69.png" alt="sql_server_temporal_table_history_table_delete_example" class="image--center mx-auto" /></p>
<p>As per the results shown in the image just above, we can see that the record for department id 2 which was the Sales department, was removed from the Temporal table, and the state of the record before the delete operation is stored in the History table with valid_to value showing when the delete operation has taken place.</p>
<p>Furthermore, it is important to note that, the TRUNCATE operation on the Temporal Table is not supported like regular tables. And as long as System Versioning is enabled, DML operation on the History table is not supported.</p>
<h3 id="heading-drop-temporal-table">Drop Temporal Table:</h3>
<p>To clean up and Drop Temporal and History Tables, we need to first disable the system versioning. And also need to drop the period definition. Below is the script based on our example.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- disable system versioning</span>
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> dbo.department <span class="hljs-keyword">SET</span> (SYSTEM_VERSIONING = <span class="hljs-keyword">OFF</span>)
<span class="hljs-keyword">GO</span>

<span class="hljs-comment">-- drop period definition</span>
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> dbo.department <span class="hljs-keyword">DROP</span> <span class="hljs-keyword">PERIOD</span> <span class="hljs-keyword">FOR</span> SYSTEM_TIME
<span class="hljs-keyword">GO</span>

<span class="hljs-comment">-- drop department and department_history tables</span>
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> dbo.department
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> dbo.department_history
</code></pre>
<p>With this, we wind up the post about the intro for Temporal Table or SYSTEM-VERSIONED Table. To summarize, a system-versioned table, also called a temporal table, is a type of user-defined table to automatically keep track of the full history of data changes or mutations in table rows. Since it tracks the full history of data changes in the separate history table, with the database engine managing validity for each row, helping us to know the state of data at any given point in time in history. In the next post, we will look into Querying the System-Versioned Temporal Table and How to enable System Versioning for the existing regular table and more related topics.</p>
]]></content:encoded></item><item><title><![CDATA[Handling Exceptions with Try-Catch in SQL Server]]></title><description><![CDATA[When SQL statements are being executed, errors may occur. The approach of handling them in SQL Server can be done with TRY-CATCH exception handling. It makes code debugging easier for developers because it enables them to locate the root of any mista...]]></description><link>https://mssqlserver.dev/handling-exceptions-with-try-catch-in-sql-server</link><guid isPermaLink="true">https://mssqlserver.dev/handling-exceptions-with-try-catch-in-sql-server</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[software development]]></category><category><![CDATA[#SQLtutorial ]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Mon, 03 Apr 2023 11:56:11 GMT</pubDate><content:encoded><![CDATA[<p>When SQL statements are being executed, errors may occur. The approach of handling them in SQL Server can be done with TRY-CATCH exception handling. It makes code debugging easier for developers because it enables them to locate the root of any mistakes that may have occurred. We'll demonstrate it in this post and also understand its other aspects.</p>
<p>An exception is an error or problem that occurs during the execution of a Transact-SQL statement or batch. When an exception occurs, SQL Server raises an error message that includes information about the error such as the error number, severity, state, and message text.</p>
<p>Some common examples of exceptions in SQL Server include:</p>
<ol>
<li><p>Constraint violation errors (e.g. foreign key violation, unique constraint violation)</p>
</li>
<li><p>Data type conversion errors</p>
</li>
<li><p>Divide-by-zero errors</p>
</li>
<li><p>Permission errors</p>
</li>
<li><p>Object not found errors</p>
</li>
<li><p>Deadlock errors</p>
</li>
</ol>
<p>To handle exceptions in SQL Server, we have to use the TRY-CATCH construct. The TRY block contains the code that might raise an exception, and the CATCH block contains the code that handles the exception. By using TRY-CATCH, you can gracefully handle errors and prevent them from terminating your application. In addition to TRY-CATCH, SQL Server also provides other error-handling mechanisms such as RAISERROR and THROW. RAISERROR is used to generate a custom error message and THROW is used to re-throw an exception that has been caught in a TRY block. Handling exceptions is an important part of developing stable and reliable SQL Server applications. Note that the try-catch mechanism won't work in UDF(User Defined Functions).</p>
<h3 id="heading-understanding-the-try-catch-block">Understanding the Try Catch block:</h3>
<p>The exception handling of the SQL Try-Catch block is the same as the try-catch block in other programming languages. When the SQL statements are executed in the try block, if any exception arises, then the control is immediately transferred to the catch block which handles the flow of the program in case of exceptions. In catch, we write statements or call procedures to properly handle the exceptions that occurred in the try block as per our requirement. We can also take advantage of system functions, to get detailed information about the error.</p>
<p>ERROR_MESSAGE() - you can take advantage of this function to get the complete error message.</p>
<p>ERROR_LINE() - this function can be used to get the line number on which the error occurred.</p>
<p>ERROR_NUMBER() - this function can be used to get the error number of the error. ERROR_SEVERITY() - this function can be used to get the severity level of the error. ERROR_STATE() - this function can be used to get the state number of the error. ERROR_PROCEDURE() - this function can be used to know the name of the stored procedure or trigger that has caused the error.</p>
<h3 id="heading-syntax">Syntax:</h3>
<p>Below is the syntax for the TRY CATCH.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">BEGIN</span> TRY
    <span class="hljs-comment">-- SQL statements executing queries and batches</span>
<span class="hljs-keyword">END</span> TRY
<span class="hljs-keyword">BEGIN</span> CATCH
    <span class="hljs-comment">-- SQL statements to handle exceptions</span>
<span class="hljs-keyword">END</span> CATCH
</code></pre>
<p>Below is the syntax for the Nested TRY CATCH</p>
<pre><code class="lang-sql"><span class="hljs-keyword">BEGIN</span> TRY
    <span class="hljs-comment">-- SQL statements executing queries and batches that might cause exceptions</span>
<span class="hljs-keyword">END</span> TRY
<span class="hljs-keyword">BEGIN</span> CATCH
    <span class="hljs-comment">-- SQL statements to handle exceptions</span>
    <span class="hljs-keyword">BEGIN</span> TRY
        <span class="hljs-comment">-- Nested TRY block.</span>
    <span class="hljs-keyword">END</span> TRY
    <span class="hljs-keyword">BEGIN</span> CATCH
        <span class="hljs-comment">-- Nested CATCH block.</span>
    <span class="hljs-keyword">END</span> CATCH
<span class="hljs-keyword">END</span> CATCH
</code></pre>
<p>For example and the demonstration, we create a table and populate it with data. let's have a simple employee table having column Name, Age, Salary, and Department. Use the below statement to create a table and populate it with data.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- drop table employee</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> employee(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>),
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">150</span>),
    age <span class="hljs-built_in">tinyint</span>,
    salary <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>),
    department <span class="hljs-built_in">varchar</span>(<span class="hljs-number">50</span>)
);
<span class="hljs-keyword">set</span> identity_insert employee <span class="hljs-keyword">on</span>;
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'Brittany Jeynes'</span>, <span class="hljs-number">34</span>, <span class="hljs-number">75348.30</span>, <span class="hljs-string">'Support'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-string">'Rita Grahamslaw'</span>, <span class="hljs-number">31</span>, <span class="hljs-number">48472.11</span>, <span class="hljs-string">'Marketing'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-string">'Eloise Stovin'</span>, <span class="hljs-number">42</span>, <span class="hljs-number">92411.91</span>, <span class="hljs-string">'Research and Development'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-string">'Angeline Blaszczyk'</span>, <span class="hljs-number">30</span>, <span class="hljs-number">71372.13</span>, <span class="hljs-string">'Research and Development'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-string">'Kata Yakobowitz'</span>, <span class="hljs-number">42</span>, <span class="hljs-number">86797.11</span>, <span class="hljs-string">'Business Development'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-string">'Minnnie Marling'</span>, <span class="hljs-number">21</span>, <span class="hljs-number">101031.2</span>, <span class="hljs-string">'Human Resources'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-string">'Brnaba Fenney'</span>, <span class="hljs-number">42</span>, <span class="hljs-number">98107.23</span>, <span class="hljs-string">'Product Management'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-string">'Verina Dyson'</span>, <span class="hljs-number">42</span>, <span class="hljs-number">83881.92</span>, <span class="hljs-string">'Support'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-string">'Timothee Pelz'</span>, <span class="hljs-number">28</span>, <span class="hljs-number">117771.98</span>, <span class="hljs-string">'Accounting'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-string">'Terrance Fomichkin'</span>, <span class="hljs-number">30</span>, <span class="hljs-number">79487.77</span>, <span class="hljs-string">'Sales'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-string">'Sanderson Olpin'</span>, <span class="hljs-number">47</span>, <span class="hljs-number">137815.37</span>, <span class="hljs-string">'Training'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-string">'Leona Melsom'</span>, <span class="hljs-number">31</span>, <span class="hljs-number">142223.11</span>, <span class="hljs-string">'Engineering'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-string">'Ingrid Lys'</span>, <span class="hljs-number">42</span>, <span class="hljs-number">87863.52</span>, <span class="hljs-string">'Research and Development'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-string">'Sophia Dungate'</span>, <span class="hljs-number">25</span>, <span class="hljs-number">114351.43</span>, <span class="hljs-string">'Accounting'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">15</span>, <span class="hljs-string">'Estrella Kille'</span>, <span class="hljs-number">31</span>, <span class="hljs-number">45259.00</span>, <span class="hljs-string">'Legal'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">16</span>, <span class="hljs-string">'Jonah Collecott'</span>, <span class="hljs-number">28</span>, <span class="hljs-number">70264.52</span>, <span class="hljs-string">'Accounting'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">17</span>, <span class="hljs-string">'Urbain Squirrel'</span>, <span class="hljs-number">21</span>, <span class="hljs-number">53957.32</span>, <span class="hljs-string">'Product Management'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">18</span>, <span class="hljs-string">'Karin Castellani'</span>, <span class="hljs-number">31</span>, <span class="hljs-number">89995.29</span>, <span class="hljs-string">'Product Management'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">19</span>, <span class="hljs-string">'Bethena Armin'</span>, <span class="hljs-number">28</span>, <span class="hljs-number">41844.10</span>, <span class="hljs-string">'Human Resources'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-number">20</span>, <span class="hljs-string">'Zonnya Trevna'</span>, <span class="hljs-number">28</span>, <span class="hljs-number">56519.36</span>, <span class="hljs-string">'Training'</span>);
<span class="hljs-keyword">set</span> identity_insert employee <span class="hljs-keyword">off</span>;
</code></pre>
<h3 id="heading-sql-try-catch-example">SQL TRY CATCH Example:</h3>
<p>For a simple try-catch example, let's try to insert a row in the employee table we created with an age column value out of the range of the tinyint data type and see how the SQL Server handles the exception.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">BEGIN</span> TRY
    <span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee(<span class="hljs-keyword">name</span>, age, salary, department) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Sana Giggs'</span>, <span class="hljs-number">256</span>, <span class="hljs-number">40999</span>, <span class="hljs-string">'Sales'</span>);
<span class="hljs-keyword">END</span> TRY
<span class="hljs-keyword">BEGIN</span> CATCH
    <span class="hljs-keyword">SELECT</span>  
        ERROR_MESSAGE() <span class="hljs-keyword">AS</span> [<span class="hljs-keyword">Error</span> Message]
        ,ERROR_LINE() <span class="hljs-keyword">AS</span> ErrorLine
        ,ERROR_NUMBER() <span class="hljs-keyword">AS</span> [<span class="hljs-keyword">Error</span> <span class="hljs-built_in">Number</span>]  
        ,ERROR_SEVERITY() <span class="hljs-keyword">AS</span> [<span class="hljs-keyword">Error</span> Severity]  
        ,ERROR_STATE() <span class="hljs-keyword">AS</span> [<span class="hljs-keyword">Error</span> State] ; 
<span class="hljs-keyword">END</span> CATCH
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680522260120/6d547c5b-e535-4995-bfbf-5da022f4f938.png" alt class="image--center mx-auto" /></p>
<p>As guessed correctly, we naturally will get the error while trying to insert the above statement, as the upper bound of the tinyint data type is 255 and we are trying to insert 256 in the age column, so we received an "Arithmetic overflow error for data type tinyint, value = 256." error.</p>
<h3 id="heading-sql-try-catch-example-in-transaction">SQL TRY CATCH Example in Transaction:</h3>
<p>Similar, to the above example, we can TRY CATCH with transactions also. Let's modify the above example and include transactions in it.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">BEGIN</span> <span class="hljs-keyword">TRANSACTION</span>;
<span class="hljs-keyword">BEGIN</span> TRY
    <span class="hljs-keyword">update</span> employee <span class="hljs-keyword">set</span> age = <span class="hljs-number">256</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>; <span class="hljs-comment">-- will cause same arithmetic overflow error</span>
<span class="hljs-keyword">END</span> TRY
<span class="hljs-keyword">BEGIN</span> CATCH
    <span class="hljs-keyword">SELECT</span>   
        ERROR_NUMBER() <span class="hljs-keyword">AS</span> ErrorNumber  
        ,ERROR_SEVERITY() <span class="hljs-keyword">AS</span> ErrorSeverity  
        ,ERROR_STATE() <span class="hljs-keyword">AS</span> ErrorState  
        ,ERROR_PROCEDURE() <span class="hljs-keyword">AS</span> ErrorProcedure  
        ,ERROR_LINE() <span class="hljs-keyword">AS</span> ErrorLine  
        ,ERROR_MESSAGE() <span class="hljs-keyword">AS</span> ErrorMessage;  
  <span class="hljs-comment">-- @@TRANCOUNT will return a running open transaction count in the session which is not yet committed or rolled back.</span>
    IF @@TRANCOUNT &gt; 0  
        <span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>; 
<span class="hljs-keyword">END</span> CATCH
<span class="hljs-keyword">IF</span> @@TRANCOUNT &gt; <span class="hljs-number">0</span>  
    <span class="hljs-keyword">COMMIT</span> <span class="hljs-keyword">TRANSACTION</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680522366255/bf1d45cf-f7d2-4c69-a669-1c3ca3d047d2.png" alt class="image--center mx-auto" /></p>
<p>With the execution of the above script we can see that, we received the same error. The only reason it was demonstrated, was to show an example of a transaction.</p>
<h3 id="heading-using-try-catch-in-procedures">Using TRY CATCH in procedures:</h3>
<p>To Handle exceptions in procedures lets use the below script and execute the procedure, This example is basically for showing the syntax of using try-catch in the procedure.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">PROCEDURE</span> [dbo].[usp_update_employee_age]
    (@input_age <span class="hljs-built_in">int</span>, @person_id <span class="hljs-built_in">int</span>)
    <span class="hljs-keyword">AS</span>
    <span class="hljs-keyword">BEGIN</span>
        <span class="hljs-keyword">BEGIN</span> TRY
            <span class="hljs-keyword">declare</span> @message <span class="hljs-built_in">varchar</span>(<span class="hljs-number">500</span>);
            <span class="hljs-keyword">BEGIN</span> <span class="hljs-keyword">TRANSACTION</span>;
                <span class="hljs-comment">-- update age of employee</span>
                <span class="hljs-keyword">update</span> employee <span class="hljs-keyword">set</span> age =  @input_age <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = @person_id;
                <span class="hljs-keyword">SELECT</span> @message = <span class="hljs-keyword">CONVERT</span>(<span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">30</span>), <span class="hljs-keyword">GETDATE</span>(), <span class="hljs-number">121</span>) + <span class="hljs-string">': Transaction Committed'</span>
                print @message;
            <span class="hljs-keyword">COMMIT</span> <span class="hljs-keyword">TRANSACTION</span>;
        <span class="hljs-keyword">END</span> TRY
        <span class="hljs-keyword">BEGIN</span> CATCH
            <span class="hljs-keyword">IF</span> @@TRANCOUNT &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">ROLLBACK</span> TRAN;
            <span class="hljs-keyword">SELECT</span> @message = <span class="hljs-keyword">CONVERT</span>(<span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">30</span>), <span class="hljs-keyword">GETDATE</span>(), <span class="hljs-number">121</span>) + <span class="hljs-string">': Transaction rolledback'</span>;
            <span class="hljs-keyword">SELECT</span>   
                ERROR_NUMBER() <span class="hljs-keyword">AS</span> ErrorNumber  
                ,ERROR_SEVERITY() <span class="hljs-keyword">AS</span> ErrorSeverity  
                ,ERROR_STATE() <span class="hljs-keyword">AS</span> ErrorState  
                ,ERROR_LINE () <span class="hljs-keyword">AS</span> ErrorLine  
                ,ERROR_PROCEDURE() <span class="hljs-keyword">AS</span> ErrorProcedure  
                ,ERROR_MESSAGE() <span class="hljs-keyword">AS</span> ErrorMessage;  
            print @message;
            THROW;
        <span class="hljs-keyword">END</span> CATCH
    <span class="hljs-keyword">END</span>
</code></pre>
<p>After creating the above procedure, we can call and execute the procedure with the below statement</p>
<pre><code class="lang-sql">EXEC usp_update_employee_age 200, 1;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680522461543/ab963c26-6d51-4ec7-ba7c-3e04873c93dd.png" alt class="image--center mx-auto" /></p>
<p>It will return an error with the same exception, this is a way to use try catch the transaction in the procedure. Change the value within the range of the tinyint data type and execute, it will work without any error. Now, the last important usage of try-catch which must be covered is a custom exception in SQL procedure.</p>
<h3 id="heading-custom-exception-in-procedure">Custom Exception in procedure:</h3>
<p>Similar to custom exceptions in java and other languages, we can also have our custom exception handling inside the procedure. There are many scenarios where we need to handle certain cases and if satisfied, we need to send a custom JSON output message with an error or else a custom message with success. We can use RAISERROR or THROW for sending these custom exceptions. Note that both THROW and RAISERROR statements can be used to generate custom errors and re-throw exceptions. However, the THROW statement can re-throw the original exception that has been caught in the CATCH block and RAISERROR statement re-throws an altogether new exception and the original exception is lost. Check the script below. I am adding an extra part, wherein I validate the @input_age variable value first and raise an exception myself based on the requirement. I doing this for the demonstration and to show the syntax only, since nothing another example is coming to my mind now.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">PROCEDURE</span> [dbo].[usp_update_employee_age]
    (@input_age <span class="hljs-built_in">int</span>, @person_id <span class="hljs-built_in">int</span>, @output_json <span class="hljs-keyword">nvarchar</span>(<span class="hljs-keyword">max</span>) <span class="hljs-keyword">out</span>)
    <span class="hljs-keyword">AS</span>
    <span class="hljs-keyword">BEGIN</span>
        <span class="hljs-keyword">BEGIN</span> TRY
            <span class="hljs-keyword">declare</span> @message <span class="hljs-built_in">varchar</span>(<span class="hljs-number">500</span>);
            <span class="hljs-keyword">BEGIN</span> <span class="hljs-keyword">TRANSACTION</span>;

                if (@input_age &gt; 80) or (@input_age &lt; 18)
                <span class="hljs-keyword">begin</span>
                    <span class="hljs-comment">-- raise an exception, since we do not want to add employee who is below 18 or above 80 years of age</span>
                    <span class="hljs-keyword">select</span> @output_json = N<span class="hljs-string">'{
                        "status" : 0,
                        "description" : "age provided for the update is not within permitted range",
                        "data": {}
                    }'</span>;
                    raiserror(@output_json, 16, 1);
                    <span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>;
                <span class="hljs-keyword">end</span>
                <span class="hljs-keyword">else</span> 
                <span class="hljs-keyword">begin</span>
                    <span class="hljs-comment">-- update age of employee</span>
                    <span class="hljs-keyword">update</span> employee <span class="hljs-keyword">set</span> age =  @input_age <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = @person_id;
                    <span class="hljs-keyword">SELECT</span> @message = <span class="hljs-keyword">CONVERT</span>(<span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">30</span>), <span class="hljs-keyword">GETDATE</span>(), <span class="hljs-number">121</span>) + <span class="hljs-string">': Transaction Committed'</span>
                    print @message;
                    <span class="hljs-keyword">set</span> @output_json = N<span class="hljs-string">'{
                        "status" : 1,
                        "description" : "Employee age has been updated",
                        "data": {}
                    }'</span>;
                    RAISERROR(@output_json, 0, 1) <span class="hljs-keyword">WITH</span> <span class="hljs-keyword">NOWAIT</span>;
                    <span class="hljs-keyword">COMMIT</span> <span class="hljs-keyword">TRANSACTION</span>;
                <span class="hljs-keyword">end</span>

        <span class="hljs-keyword">END</span> TRY
        <span class="hljs-keyword">BEGIN</span> CATCH
            <span class="hljs-keyword">IF</span> @@TRANCOUNT &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">ROLLBACK</span> TRAN;
            <span class="hljs-keyword">SELECT</span> @message = <span class="hljs-keyword">CONVERT</span>(<span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">30</span>), <span class="hljs-keyword">GETDATE</span>(), <span class="hljs-number">121</span>) + <span class="hljs-string">': Transaction rolledback'</span>;
            <span class="hljs-keyword">SELECT</span>   
                ERROR_NUMBER() <span class="hljs-keyword">AS</span> ErrorNumber  
                ,ERROR_SEVERITY() <span class="hljs-keyword">AS</span> ErrorSeverity  
                ,ERROR_STATE() <span class="hljs-keyword">AS</span> ErrorState  
                ,ERROR_LINE () <span class="hljs-keyword">AS</span> ErrorLine  
                ,ERROR_PROCEDURE() <span class="hljs-keyword">AS</span> ErrorProcedure  
                ,ERROR_MESSAGE() <span class="hljs-keyword">AS</span> ErrorMessage;  

            RAISERROR(@message, 0, 1) <span class="hljs-keyword">WITH</span> <span class="hljs-keyword">NOWAIT</span>;
            THROW;
        <span class="hljs-keyword">END</span> CATCH
    <span class="hljs-keyword">END</span>
</code></pre>
<p>After creating the above procedure, we can call and execute the procedure with the below statement</p>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span> @output_json <span class="hljs-keyword">nvarchar</span>(<span class="hljs-keyword">max</span>);
EXEC usp_update_employee_age 105, 1, @output_json;
</code></pre>
<p>After executing the procedure, we can see the returning variable returning the response as per the case and inputs provided. The above script demonstrates the usage of custom user exceptions, and I prefer to do it this way in many cases.</p>
<p>The following types of errors are not handled by a CATCH block when they occur at the same level of execution as the TRY...CATCH construct:</p>
<ol>
<li><p>Compile errors, such as syntax errors, prevent a batch from running.</p>
</li>
<li><p>Errors that occur during statement-level recompilation, such as object name resolution errors occur after compilation because of deferred name resolution.</p>
</li>
<li><p>Object name resolution errors</p>
</li>
</ol>
<p>If any points are missing then you can add them in a comment below.</p>
<p>A few Things to note again are,</p>
<ol>
<li><p>We can use the THROW function, without any parameters, but not RAISERROR.</p>
</li>
<li><p>Error Number for THROW function should be greater than or equal to 50000;</p>
</li>
<li><p>Error Severity level should be above 10 and below 19 in RAISERROR to trigger the exception and jump to catch block.</p>
</li>
<li><p>As may be mentioned earlier, TRY CATCH cant be used in a user-defined function.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Understanding Database Normalization]]></title><description><![CDATA[Intro
Database Normalization is a concept & design technique we follow to efficiently organize data and design proper schema, to avoid redundant & data duplication in multiple tables. It also sets up relations between the tables, to ensure data depen...]]></description><link>https://mssqlserver.dev/understanding-database-normalization</link><guid isPermaLink="true">https://mssqlserver.dev/understanding-database-normalization</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[#SQLtutorial ]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Fri, 10 Feb 2023 12:45:39 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-intro">Intro</h2>
<p>Database Normalization is a concept &amp; design technique we follow to efficiently organize data and design proper schema, to avoid redundant &amp; data duplication in multiple tables. It also sets up relations between the tables, to ensure data dependency and room for future additions.</p>
<p>If tables are not properly normalized, then may eat up extra memory space and resources, while causing insertions, updates and deletions anomalies and complex queries.</p>
<h2 id="heading-case">Case</h2>
<p>Suppose we have an LMS System for the college and no normalization design was followed while making it, then we may have many difficulties, to name a few.</p>
<table><tbody><tr><td><p>student_id</p></td><td><p>student_name</p></td><td><p>email</p></td><td><p>program_name</p></td><td><p>program_abbr</p></td></tr><tr><td><p>710002</p></td><td><p>Suraj Peth</p></td><td><p><a target="_blank" href="mailto:suraj@eample.com">suraj@eample.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a>.</p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:saion@example.com">saion@example.com</a></p></td><td><p>Bachelor of science,</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a>.,<a target="_blank" href="http://B.Ph">B.Ph</a>.</p></td></tr><tr><td><p>710004</p></td><td><p>Cycil L</p></td><td><p><a target="_blank" href="mailto:cycil@example.com">cycil@example.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a></p></td></tr><tr><td><p>710005</p></td><td><p>Deo Bobby</p></td><td><p><a target="_blank" href="mailto:Deo@example.com">Deo@example.com</a></p></td><td><p>Bachelor of Physics</p></td><td><p><a target="_blank" href="http://B.Ph">B.Ph</a>.</p></td></tr><tr><td><p>710006</p></td><td><p>Albert Doo</p></td><td><p><a target="_blank" href="mailto:albert@example.com">albert@example.com</a></p></td><td><p>Bachelor of Commerce</p></td><td><p><a target="_blank" href="http://B.Com">B.Com</a>.</p></td></tr></tbody></table>

<p>In the above design of the student table, we have a few issues</p>
<p>Firstly, row number 2 of student_id 710003 has grouped values for an attribute(column) of program_name.</p>
<p>Secondly, we have added program-related attributes like program_name, and program_abbr which were unrelated to the student entity(table). We could have created a separate program table or entity and used its primary key to reference it here in the student's table and the rest program related attributes can be stored in the program table.</p>
<p>Thirdly, there is the repetition of data like program_name values, as many students have to opt for programs from a selected list, we can have avoided this repetition through separate program tables and maintaining the reference of keys.</p>
<p>While Inserting new students' data, every time the data will be repeated for program_name and abbr. And if someone had earlier made a mistake in program_name during its creation, then we will have to update each row of the said program_name in the current design. </p>
<p>Normalizations are guidelines and a way, for database schema &amp; structure to be laid down.</p>
<p>Normally, the Third Normal Form is enough, however, you can extend it as you deem fit.</p>
<h3 id="heading-first-normal-form1nf">First Normal Form(1NF)</h3>
<p>First Normal Form sets below a few guidelines for designing database table schema;</p>
<ol>
<li><p>Define only the required and related attributes(columns) in the table.</p>
</li>
<li><p>Should have single-valued attributes/columns.</p>
</li>
<li><p>Attributes(columns) should be unique in names and the order doesn't matter.</p>
</li>
<li><p>Should also contain a column denoting as primary keys</p>
</li>
</ol>
<p>Taking forward the previous table we used as an example,</p>
<table><tbody><tr><td><p>id</p></td><td><p>student_id</p></td><td><p>student_name</p></td><td><p>email</p></td><td><p>program_name</p></td><td><p>program_abbr</p></td></tr><tr><td><p>1</p></td><td><p>710002</p></td><td><p>Suraj Peth</p></td><td><p><a target="_blank" href="mailto:suraj@eample.com">suraj@eample.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a>.</p></td></tr><tr><td><p>2</p></td><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>Bachelor of science,</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a>.,<a target="_blank" href="http://B.Ph">B.Ph</a>.</p></td></tr><tr><td><p>3</p></td><td><p>710004</p></td><td><p>Cycil L</p></td><td><p><a target="_blank" href="mailto:cycil@example.com">cycil@example.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a></p></td></tr><tr><td><p>4</p></td><td><p>710005</p></td><td><p>Deo Bobby</p></td><td><p><a target="_blank" href="mailto:Deo@example.com">Deo@example.com</a></p></td><td><p>Bachelor of Physics</p></td><td><p><a target="_blank" href="http://B.Ph">B.Ph</a>.</p></td></tr><tr><td><p>5</p></td><td><p>710006</p></td><td><p>Albert Doo</p></td><td><p><a target="_blank" href="mailto:albert@example.com">albert@example.com</a></p></td><td><p>Bachelor of Commerce</p></td><td><p><a target="_blank" href="http://B.Com">B.Com</a>.</p></td></tr></tbody></table>

<p>Let's re-design the structure fulfilling all the guidelines.</p>
<p>Looking at the above table, we can see that a student with student_id 710003 has applied for 2 programs and it is inserted in comma-separated format. As we should have single-valued attributes as per the guidelines, let's restructure it and insert the second program as a new row.</p>
<p>The table now looks like,</p>
<table><tbody><tr><td><p>id</p></td><td><p>student_id</p></td><td><p>student_name</p></td><td><p>email</p></td><td><p>program_name</p></td><td><p>program_abbr</p></td></tr><tr><td><p>1</p></td><td><p>710002</p></td><td><p>Suraj Peth</p></td><td><p><a target="_blank" href="mailto:suraj@eample.com">suraj@eample.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a>.</p></td></tr><tr><td><p>2</p></td><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a>.</p></td></tr><tr><td><p>3</p></td><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>Bachelor of Physics</p></td><td><p><a target="_blank" href="http://B.Ph">B.Ph</a>.</p></td></tr><tr><td><p>4</p></td><td><p>710004</p></td><td><p>Cycil L</p></td><td><p><a target="_blank" href="mailto:cycil@example.com">cycil@example.com</a></p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a></p></td></tr><tr><td><p>5</p></td><td><p>710005</p></td><td><p>Deo Bobby</p></td><td><p><a target="_blank" href="mailto:Deo@example.com">Deo@example.com</a></p></td><td><p>Bachelor of Physics</p></td><td><p><a target="_blank" href="http://B.Ph">B.Ph</a>.</p></td></tr><tr><td><p>6</p></td><td><p>710006</p></td><td><p>Albert Doo</p></td><td><p><a target="_blank" href="mailto:albert@example.com">albert@example.com</a></p></td><td><p>Bachelor of Commerce</p></td><td><p><a target="_blank" href="http://B.Com">B.Com</a>.</p></td></tr></tbody></table>

<p>By doing so, although a few values are getting repeated, values for the program_name column are now atomic for each record/row.</p>
<p>Using the First Normal Form, data redundancy increases, as there will be many columns with the same data in multiple rows but each row as a whole will be unique.</p>
<h3 id="heading-second-normal-form2nf">Second Normal Form(2NF)</h3>
<p>The transformation of 1NF to 2NF involves the removal of partial dependencies. If a partial dependency exists, we remove the partially dependent attribute(s) from the relation by placing them in a new relation along with a copy of their determinant.</p>
<p>To further normalize and ensure non-repetition of data, we can break the above output table in First Normal Form into 3 different tables, as the single table above also contains information regarding program attributes that are not primary.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> STUDENT(
    STUDENT_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    STUDENT_NAME <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    EMAIL <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>),
    ACTIVE <span class="hljs-built_in">CHAR</span>(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">DEFAULT</span>(<span class="hljs-string">'Y'</span>),
    PRIMARY <span class="hljs-keyword">KEY</span>(STUDENT_ID)
);
</code></pre>
<p>The above table will have the following recordset,</p>
<table><tbody><tr><td><p>student_id</p></td><td><p>student_name</p></td><td><p>email</p></td></tr><tr><td><p>710002</p></td><td><p>Suraj Peth</p></td><td><p><a target="_blank" href="mailto:suraj@eample.com">suraj@eample.com</a></p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td></tr><tr><td><p>710004</p></td><td><p>Cycil L</p></td><td><p><a target="_blank" href="mailto:cycil@example.com">cycil@example.com</a></p></td></tr><tr><td><p>710005</p></td><td><p>Deo Bobby</p></td><td><p><a target="_blank" href="mailto:Deo@example.com">Deo@example.com</a></p></td></tr><tr><td><p>710006</p></td><td><p>Albert Doo</p></td><td><p><a target="_blank" href="mailto:albert@example.com">albert@example.com</a></p></td></tr></tbody></table>

<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> PROGRAM(
    PROGRAM_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    PROGRAM_NAME <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">500</span>),
    PROGRAM_ABBR <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">50</span>),
    ACTIVE <span class="hljs-built_in">CHAR</span>(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">DEFAULT</span>(<span class="hljs-string">'Y'</span>),
    PRIMARY <span class="hljs-keyword">KEY</span>(PROGRAM_ID)
);
</code></pre>
<p>And the program table will have the following data,</p>
<table><tbody><tr><td><p>program_id</p></td><td><p>program_name</p></td><td><p>program_abbr</p></td></tr><tr><td><p>5120036</p></td><td><p>Bachelor of science</p></td><td><p><a target="_blank" href="http://B.Sc">B.Sc</a></p></td></tr><tr><td><p>5120042</p></td><td><p>Bachelor of Physics</p></td><td><p><a target="_blank" href="http://B.Ph">B.Ph</a></p></td></tr><tr><td><p>5120040</p></td><td><p>Bachelor of Commerce</p></td><td><p><a target="_blank" href="http://B.Com">B.Com</a></p></td></tr></tbody></table>

<p>And, finally, we will create another table for storing students and their applied Programs, as we allow students to enroll in multiple programs.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> STUDENT_PROGRAM(
    STUDENT_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    PROGRAM_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    PRIMARY <span class="hljs-keyword">KEY</span>(STUDENT_ID, PROGRAM_ID),
    <span class="hljs-keyword">FOREIGN</span> <span class="hljs-keyword">KEY</span>(STUDENT_ID) <span class="hljs-keyword">REFERENCES</span> STUDENT(STUDENT_ID),
    <span class="hljs-keyword">FOREIGN</span> <span class="hljs-keyword">KEY</span>(PROGRAM_ID) <span class="hljs-keyword">REFERENCES</span> PROGRAM(PROGRAM_ID)
);
</code></pre>
<table><tbody><tr><td><p>student_id</p></td><td><p>program_id</p></td></tr><tr><td><p>710002</p></td><td><p>5120036</p></td></tr><tr><td><p>710003</p></td><td><p>5120036</p></td></tr><tr><td><p>710003</p></td><td><p>5120042</p></td></tr><tr><td><p>710004</p></td><td><p>5120036</p></td></tr><tr><td><p>710005</p></td><td><p>5120042</p></td></tr><tr><td><p>710006</p></td><td><p>5120040</p></td></tr></tbody></table>

<h3 id="heading-third-normal-form3nf">Third Normal Form(3NF)</h3>
<p>The rule for 3NF is that the table should be in Second Normal Form and we have to ensure that non-prime attributes should not be transitively dependent on the super key(primary key). It violates the rule of the third normal form.</p>
<p>Again taking forward the examples we used previously, let's add state and country-related attributes to the student table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> STUDENT(
    STUDENT_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    STUDENT_NAME <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    EMAIL <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>),
    STATE <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>),
    COUNTRY <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">155</span>),
    ACTIVE <span class="hljs-built_in">CHAR</span>(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">DEFAULT</span>(<span class="hljs-string">'Y'</span>),
    PRIMARY <span class="hljs-keyword">KEY</span>(STUDENT_ID)
);
</code></pre>
<table><tbody><tr><td><p>student_id</p></td><td><p>student_name</p></td><td><p>email</p></td><td><p>state</p></td><td><p>country</p></td></tr><tr><td><p>710002</p></td><td><p>Suraj Peth</p></td><td><p><a target="_blank" href="mailto:suraj@eample.com">suraj@eample.com</a></p></td><td><p>Maharashtra</p></td><td><p>India</p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>Karnataka</p></td><td><p>India</p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>Karnataka</p></td><td><p>India</p></td></tr><tr><td><p>710004</p></td><td><p>Cycil L</p></td><td><p><a target="_blank" href="mailto:cycil@example.com">cycil@example.com</a></p></td><td><p>Maharashtra</p></td><td><p>India</p></td></tr><tr><td><p>710005</p></td><td><p>Deo Bobby</p></td><td><p><a target="_blank" href="mailto:Deo@example.com">Deo@example.com</a></p></td><td><p>Kerala</p></td><td><p>India</p></td></tr><tr><td><p>710006</p></td><td><p>Albert Doo</p></td><td><p><a target="_blank" href="mailto:albert@example.com">albert@example.com</a></p></td><td><p>Tamil Nadu</p></td><td><p>India</p></td></tr></tbody></table>

<p>Here the State and Country in the above table are dependent on the student, so to normalize it as per Third Normalized Form, we can have another table storing the state &amp; country list and referencing it with the id in the student's table. below is the normalized form,</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> STATE_COUNTRY(
    <span class="hljs-keyword">ID</span> <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    STATE <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>),
    COUNTRY <span class="hljs-built_in">VARCHAR</span> (<span class="hljs-number">155</span>),
    PRIMARY <span class="hljs-keyword">KEY</span>(<span class="hljs-keyword">ID</span>)
);
</code></pre>
<table><tbody><tr><td><p>id</p></td><td><p>state</p></td><td><p>country</p></td></tr><tr><td><p>1</p></td><td><p>Maharashtra</p></td><td><p>India</p></td></tr><tr><td><p>2</p></td><td><p>Karnataka</p></td><td><p>India</p></td></tr><tr><td><p>3</p></td><td><p>Kerala</p></td><td><p>India</p></td></tr><tr><td><p>4</p></td><td><p>Tamil Nadu</p></td><td><p>India</p></td></tr></tbody></table>

<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> STUDENT(
    STUDENT_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    STUDENT_NAME <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    EMAIL <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>),
    STATE_ID <span class="hljs-built_in">INT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    ACTIVE <span class="hljs-built_in">CHAR</span>(<span class="hljs-number">1</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">DEFAULT</span>(<span class="hljs-string">'Y'</span>),
    PRIMARY <span class="hljs-keyword">KEY</span>(STUDENT_ID),
    <span class="hljs-keyword">FOREIGN</span> <span class="hljs-keyword">KEY</span> (STATE_ID) <span class="hljs-keyword">REFERENCES</span> STATE_COUNTRY(<span class="hljs-keyword">ID</span>)
);
</code></pre>
<table><tbody><tr><td><p>student_id</p></td><td><p>student_name</p></td><td><p>email</p></td><td><p>state_id</p></td></tr><tr><td><p>710002</p></td><td><p>Suraj Peth</p></td><td><p><a target="_blank" href="mailto:suraj@eample.com">suraj@eample.com</a></p></td><td><p>1</p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>2</p></td></tr><tr><td><p>710003</p></td><td><p>Shion Y</p></td><td><p><a target="_blank" href="mailto:aion@example.com">aion@example.com</a></p></td><td><p>2</p></td></tr><tr><td><p>710004</p></td><td><p>Cycil L</p></td><td><p><a target="_blank" href="mailto:cycil@example.com">cycil@example.com</a></p></td><td><p>1</p></td></tr><tr><td><p>710005</p></td><td><p>Deo Bobby</p></td><td><p><a target="_blank" href="mailto:Deo@example.com">Deo@example.com</a></p></td><td><p>3</p></td></tr><tr><td><p>710006</p></td><td><p>Albert Doo</p></td><td><p><a target="_blank" href="mailto:albert@example.com">albert@example.com</a></p></td><td><p>4</p></td></tr></tbody></table>

<h3 id="heading-bcnf-normalization-form">BCNF Normalization Form:</h3>
<p>BCNF stands for Boyce-Codd Normal Form, which is an extension of 3NF. In BCNF, a table must not only contain only one type of data, have a unique identifier, and not have any transitive dependencies, but it must also not contain any repeating groups. This means that data in the table must not be repeated.</p>
<p>The benefit of BCNF is that it helps to improve data integrity. By eliminating repeating groups, it ensures that data is stored in the most efficient way possible. This helps to reduce data inconsistency and improve query performance.</p>
<h2 id="heading-summary">Summary</h2>
<ol>
<li><p>Database normalization has both pros and cons. The pros include improved data integrity, reduced data redundancy, and improve query performance. The cons include increased complexity, as normalizing a database can make queries look complex due to an increase in multiple tables. It can also lead to increased storage costs, as more data may need to be stored to maintain data integrity.</p>
</li>
<li><p>As mentioned earlier in the start, Database normalization is an important process that helps to maintain the integrity of a database. It helps to reduce data redundancy, minimize data inconsistency, and improve query performance. It can be broken down into four major forms of normalization: 1NF, 2NF, 3NF, BCNF and more. </p>
</li>
<li><p>There are also pros and cons to database normalization, and it is important to understand them before implementing a database normalization strategy. Also, note that the Over-normalization of database schema also leads to an increase in complexity. </p>
</li>
<li><p>Denormalization is one of the last resorts for accelerating data retrieval in normalized databases when techniques like indexing are insufficient.</p>
</li>
</ol>
<p>Finally, there are some tips and examples of database normalization that can be used to help achieve the best results.</p>
]]></content:encoded></item><item><title><![CDATA[Making REST-API call from SQL Server procedure]]></title><description><![CDATA[Recently I had a requirement, wherein I had to import the data from one of the internal applications to the SQL Server for further processing. We had REST-API open at a particular endpoint so any other service can consume the API and fetch data for i...]]></description><link>https://mssqlserver.dev/making-rest-api-call-from-sql-server</link><guid isPermaLink="true">https://mssqlserver.dev/making-rest-api-call-from-sql-server</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[Databases]]></category><category><![CDATA[#SQLtutorial ]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Fri, 23 Sep 2022 11:37:34 GMT</pubDate><content:encoded><![CDATA[<p>Recently I had a requirement, wherein I had to import the data from one of the internal applications to the SQL Server for further processing. We had REST-API open at a particular endpoint so any other service can consume the API and fetch data for inserting/updating into tables in SQL Server.</p>
<p>For this purpose, I ended up creating a stored procedure using the OLE Automation procedure, which will make an HTTP request call and we can be able to perform GET and POST request methods.</p>
<p>OLE Automation Procedures are extended stored procedures allowing users to execute external functions to SQL Server. These can perform use cases like making HTTP calls, Reading and Writing files, Accessing File System objects, etc. The use of these extended procedures is sensitive and should be closely monitored.</p>
<p>The full set of OLE automation procedures are:</p>
<ul>
<li><p>sp_OACreate</p>
</li>
<li><p>sp_OAGetProperty</p>
</li>
<li><p>sp_OASetProperty</p>
</li>
<li><p>sp_OAMethod</p>
</li>
<li><p>sp_OAGetErrorInfo</p>
</li>
<li><p>sp_OAStop</p>
</li>
<li><p>sp_OADestroy</p>
</li>
</ul>
<p>By default, the OLE Automation is disabled in SQL Server and has to be enabled. Below is the script to check and enable OLE Automation.</p>
<pre><code class="lang-sql">sp_configure '<span class="hljs-keyword">show</span> <span class="hljs-keyword">advanced</span> options<span class="hljs-string">', 1;
GO
RECONFIGURE;
GO
sp_configure '</span>Ole Automation Procedures<span class="hljs-string">', 1;
GO
RECONFIGURE;
GO</span>
</code></pre>
<p>Let's continue forward with our demonstration.</p>
<h2 id="heading-get-method-call">GET Method call:</h2>
<p>Below is the script I used in the stored procedure, for making HTTP call of GET method request type.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DECLARE</span> @user_id <span class="hljs-built_in">int</span> = <span class="hljs-number">2</span>; <span class="hljs-comment">-- input parameter, to be passed with GET Request</span>
<span class="hljs-keyword">DECLARE</span> @<span class="hljs-keyword">URL</span> <span class="hljs-keyword">NVARCHAR</span>(<span class="hljs-keyword">MAX</span>) = <span class="hljs-keyword">concat</span>(<span class="hljs-string">'https://reqres.in/api/users/'</span>, @user_id); <span class="hljs-comment">-- our URL for http call</span>
print '@URL -&gt; '+ @URL;
<span class="hljs-keyword">Declare</span> @<span class="hljs-keyword">Object</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">Int</span>; <span class="hljs-comment">-- declare object</span>
<span class="hljs-keyword">Declare</span> @ResponseText <span class="hljs-keyword">as</span> <span class="hljs-built_in">Varchar</span>(<span class="hljs-number">8000</span>);

Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT; <span class="hljs-comment">-- creating OLE object and assigning it to variable @Object</span>
<span class="hljs-comment">-- print @Object; -- 16711422</span>

<span class="hljs-comment">-- passing the @Object created above, with our http call and handling the response with help of sp_OAMethod </span>
Exec sp_OAMethod @Object, 'open', NULL, 'get',
       @URL,
       'False'
Exec sp_OAMethod @Object, 'send'
Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
IF((<span class="hljs-keyword">Select</span> @ResponseText) &lt;&gt; <span class="hljs-string">''</span>)
<span class="hljs-keyword">BEGIN</span>
     <span class="hljs-keyword">DECLARE</span> @<span class="hljs-keyword">json</span> <span class="hljs-keyword">NVARCHAR</span>(<span class="hljs-keyword">MAX</span>) = (<span class="hljs-keyword">Select</span> @ResponseText)
     print(@<span class="hljs-keyword">json</span>); <span class="hljs-comment">-- printing the json output</span>

     <span class="hljs-keyword">select</span> 
        rs.id, rs.email, rs.first_name, rs.last_name, rs.avatar
     <span class="hljs-keyword">from</span> openjson(@<span class="hljs-keyword">json</span>, <span class="hljs-string">'$.data'</span>) <span class="hljs-keyword">with</span>  <span class="hljs-comment">-- only parsing data json array object of the responseText</span>
     (
        <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-string">'$.id'</span>,
        email <span class="hljs-built_in">varchar</span>(<span class="hljs-number">200</span>) <span class="hljs-string">'$.email'</span>,
        first_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">200</span>) <span class="hljs-string">'$.first_name'</span>,
        last_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">200</span>) <span class="hljs-string">'$.last_name'</span>,
        avatar <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-string">'$.avatar'</span>
     ) rs; <span class="hljs-comment">-- select query to further process the data.</span>
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">ELSE</span>
<span class="hljs-keyword">BEGIN</span>
     <span class="hljs-keyword">DECLARE</span> @ErroMsg <span class="hljs-keyword">NVARCHAR</span>(<span class="hljs-number">30</span>) = <span class="hljs-string">'No data found.'</span>;
     Print @ErroMsg;
<span class="hljs-keyword">END</span>
Exec sp_OADestroy @<span class="hljs-keyword">Object</span>; <span class="hljs-comment">-- destory the object when not needed anymore. If not called, the OLE object will be destroyed automatically when the batch execution is completed.</span>
</code></pre>
<h2 id="heading-post-method-call">POST Method call:</h2>
<p>Below is the script, which can be used in the stored procedure, for making HTTP calls of POST method request type.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DECLARE</span> @<span class="hljs-keyword">URL</span> <span class="hljs-keyword">NVARCHAR</span>(<span class="hljs-keyword">MAX</span>) = <span class="hljs-string">'https://reqres.in/api/users/'</span>; <span class="hljs-comment">-- our URL for post request</span>
<span class="hljs-keyword">DECLARE</span> @<span class="hljs-keyword">Object</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">INT</span>; <span class="hljs-comment">-- object declaration</span>
<span class="hljs-keyword">DECLARE</span> @ResponseText <span class="hljs-keyword">AS</span> <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">8000</span>);
<span class="hljs-keyword">DECLARE</span> @<span class="hljs-keyword">Body</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">8000</span>) =

<span class="hljs-string">'{
    "name": "kiran sabne",
    "job": "leader"
}'</span>;
EXEC sp_OACreate 'MSXML2.XMLHTTP', @Object OUT; <span class="hljs-comment">-- creating OLE object and assigning it to variable @Object</span>

<span class="hljs-comment">-- passing the @Object created above, with our http call and handling the response with help of sp_OAMethod </span>
EXEC sp_OAMethod @Object, 'open', NULL, 'post',
                 @URL,
                 'false'
EXEC sp_OAMethod @Object, 'setRequestHeader', null, 'Content-Type', 'application/json'
EXEC sp_OAMethod @Object, 'send', null, @body
EXEC sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
<span class="hljs-comment">-- print 'responseText -&gt; ' + @ResponseText;</span>
IF CHARINDEX('false',(<span class="hljs-keyword">SELECT</span> @ResponseText)) &gt; <span class="hljs-number">0</span>
<span class="hljs-keyword">BEGIN</span>
 <span class="hljs-keyword">SELECT</span> @ResponseText <span class="hljs-keyword">As</span> <span class="hljs-string">'Message'</span>
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">ELSE</span>
<span class="hljs-keyword">BEGIN</span>
 <span class="hljs-keyword">SELECT</span> @ResponseText <span class="hljs-keyword">As</span> <span class="hljs-string">'New User Added Detail'</span>
<span class="hljs-keyword">END</span>
EXEC sp_OADestroy @<span class="hljs-keyword">Object</span>
</code></pre>
<h2 id="heading-summary">Summary</h2>
<p>As mentioned earlier, the usage of OLE Procedures is sensitive and must be strictly monitored. Similarly, we can also perform File Object modifications with the OLE procedures. The other obvious and preferred alternatives are creating another application server for doing work and that application having access to the database.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding SQL Server PIVOT and UNPIVOT with example]]></title><description><![CDATA[PIVOT and UNPIVOT are relational operators for converting table expressions into one another. If we want to turn the unique row values of a column into multiple columns we use the PIVOT operator. And when we want to converge multiple columns to colum...]]></description><link>https://mssqlserver.dev/understanding-sql-server-pivot-and-unpivot-with-example</link><guid isPermaLink="true">https://mssqlserver.dev/understanding-sql-server-pivot-and-unpivot-with-example</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[#SQLtutorial ]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Sat, 14 May 2022 05:14:14 GMT</pubDate><content:encoded><![CDATA[<p>PIVOT and UNPIVOT are relational operators for converting table expressions into one another. If we want to turn the unique row values of a column into multiple columns we use the PIVOT operator. And when we want to converge multiple columns to column rows of records we use UNPIVOT operator. This transformation and aggregation of the dataset are also known as transpose. Using the PIVOT operator we can transpose rows to columns and perform aggregations during the process, and with UNPIVOT operator we transpose multiple columns to a single column with multiple rows of records. This transposing of the dataset from rows to columns and from columns to a column with rows of records is useful many times, mostly in cases of generating comparison reports, etc. For this post, we will also be using a similar dataset, maintaining order_date and total order_amount for the date in the orders_demo table, for a better understanding of the PIVOT and UNPIVOT operators.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> orders_demo;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> orders_demo(
    order_date datetime2 <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    order_amount <span class="hljs-built_in">numeric</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0.0</span>)
);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-08-29 06:24:36'</span>, <span class="hljs-number">96645.23</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-08-17 12:57:42'</span>, <span class="hljs-number">2799.66</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-12-08 01:21:10'</span>, <span class="hljs-number">36855.52</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-09-04 02:58:29'</span>, <span class="hljs-number">12745.25</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-06-02 05:52:27'</span>, <span class="hljs-number">19305.53</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-08-01 21:35:38'</span>, <span class="hljs-number">44003.67</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-06-29 07:31:51'</span>, <span class="hljs-number">9620.3</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-05-16 13:41:58'</span>, <span class="hljs-number">83331.23</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-05-14 10:34:52'</span>, <span class="hljs-number">52047.06</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-10-28 10:52:08'</span>, <span class="hljs-number">87767.65</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-09-07 15:30:38'</span>, <span class="hljs-number">79037.05</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-06-26 17:09:48'</span>, <span class="hljs-number">45204.9</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-05-23 17:32:55'</span>, <span class="hljs-number">1529.24</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-08-07 15:40:40'</span>, <span class="hljs-number">40596.98</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-07-18 07:45:15'</span>, <span class="hljs-number">72129.59</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-10-29 16:29:39'</span>, <span class="hljs-number">5195.02</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-10-14 10:21:15'</span>, <span class="hljs-number">21266.39</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-09-13 06:21:35'</span>, <span class="hljs-number">43578.89</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-06-25 04:57:38'</span>, <span class="hljs-number">5705.68</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-10-04 17:41:11'</span>, <span class="hljs-number">48334.64</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-09-24 08:54:28'</span>, <span class="hljs-number">90635.05</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-11-01 07:47:06'</span>, <span class="hljs-number">9952.95</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-05-17 09:05:54'</span>, <span class="hljs-number">82753.71</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-06-21 21:11:44'</span>, <span class="hljs-number">44711.68</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-06-20 09:02:21'</span>, <span class="hljs-number">95524.26</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-08-11 17:24:09'</span>, <span class="hljs-number">51805.88</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-07-08 02:23:24'</span>, <span class="hljs-number">56710.13</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-12-14 14:15:48'</span>, <span class="hljs-number">39827.63</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-09-08 09:04:30'</span>, <span class="hljs-number">70854.91</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders_demo (order_date, order_amount) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-07-23 01:42:31'</span>, <span class="hljs-number">36303.79</span>);

<span class="hljs-comment">-- select * from orders_demo</span>
</code></pre>
<h2 id="heading-pivot">PIVOT</h2>
<p>Looking at the dataset we can see that it has a date range of a few months. Now suppose we want to arrange and transpose the dataset in such a way that, we want to show average order amounts for each month in the data set as month-wise columns.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> 
    <span class="hljs-string">'average_order_amount'</span> <span class="hljs-keyword">as</span> avg_order_amounts,
    [<span class="hljs-number">1</span>], [<span class="hljs-number">2</span>], [<span class="hljs-number">3</span>], [<span class="hljs-number">4</span>], [<span class="hljs-number">5</span>], [<span class="hljs-number">6</span>], [<span class="hljs-number">7</span>], [<span class="hljs-number">8</span>], [<span class="hljs-number">9</span>], [<span class="hljs-number">10</span>], [<span class="hljs-number">11</span>], [<span class="hljs-number">12</span>]
<span class="hljs-keyword">from</span> 
(
    <span class="hljs-keyword">select</span> <span class="hljs-keyword">month</span>(order_date) <span class="hljs-keyword">as</span> month_num, order_amount
        <span class="hljs-keyword">from</span> 
    orders_demo
) <span class="hljs-keyword">as</span> s
<span class="hljs-keyword">pivot</span> 
(
    <span class="hljs-keyword">avg</span>(order_amount)
    <span class="hljs-keyword">for</span> month_num <span class="hljs-keyword">in</span> ([<span class="hljs-number">1</span>], [<span class="hljs-number">2</span>], [<span class="hljs-number">3</span>], [<span class="hljs-number">4</span>], [<span class="hljs-number">5</span>], [<span class="hljs-number">6</span>], [<span class="hljs-number">7</span>], [<span class="hljs-number">8</span>], [<span class="hljs-number">9</span>], [<span class="hljs-number">10</span>], [<span class="hljs-number">11</span>], [<span class="hljs-number">12</span>])
) <span class="hljs-keyword">as</span> avg_pivot_month
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652504992809/IIjZuh2cM.PNG" alt="sql server pivot example.PNG" /></p>
<p>The above SQL snippet will return a row with columns for all 12 months and the average order total as its value. The first 4 months will be having NULL value as we don't have a dataset for those date ranges.</p>
<h2 id="heading-unpivot">UNPIVOT</h2>
<p>As mentioned earlier in the introduction part, UNPIVOT operator transposes multiple columns to a single column with multiple rows of records and returns as a dataset. In the earlier part, we used the PIVOT operator on the orders_demo table and returned a row containing a name column and 12 other columns for each month of the year. Now suppose, if we want the result set such that, it will have only two columns, one named month_num depicting the month number and the other average_order_amount depicting the average of all the order amount for the month from the orders_demo table.</p>
<p>To transpose the dataset in such a way, we will use the above pivot query as a source and return the values of the multiple columns of the source result set in a single column as the average order amount for the month.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span>
    month_num,
    average_amounts
<span class="hljs-keyword">from</span>
(
    <span class="hljs-keyword">select</span> 
        <span class="hljs-string">'average_order_amount'</span> <span class="hljs-keyword">as</span> avg_order_amounts,
        [<span class="hljs-number">1</span>], [<span class="hljs-number">2</span>], [<span class="hljs-number">3</span>], [<span class="hljs-number">4</span>], [<span class="hljs-number">5</span>], [<span class="hljs-number">6</span>], [<span class="hljs-number">7</span>], [<span class="hljs-number">8</span>], [<span class="hljs-number">9</span>], [<span class="hljs-number">10</span>], [<span class="hljs-number">11</span>], [<span class="hljs-number">12</span>]
    <span class="hljs-keyword">from</span> 
    (
        <span class="hljs-keyword">select</span> <span class="hljs-keyword">month</span>(order_date) <span class="hljs-keyword">as</span> month_num, order_amount
            <span class="hljs-keyword">from</span> 
        orders_demo
    ) <span class="hljs-keyword">as</span> s
    <span class="hljs-keyword">pivot</span> 
    (
        <span class="hljs-keyword">avg</span>(order_amount)
        <span class="hljs-keyword">for</span> month_num <span class="hljs-keyword">in</span> ([<span class="hljs-number">1</span>], [<span class="hljs-number">2</span>], [<span class="hljs-number">3</span>], [<span class="hljs-number">4</span>], [<span class="hljs-number">5</span>], [<span class="hljs-number">6</span>], [<span class="hljs-number">7</span>], [<span class="hljs-number">8</span>], [<span class="hljs-number">9</span>], [<span class="hljs-number">10</span>], [<span class="hljs-number">11</span>], [<span class="hljs-number">12</span>])
    ) <span class="hljs-keyword">as</span> avg_pivot_month
) source_set 
<span class="hljs-keyword">unpivot</span>
(
    average_amounts <span class="hljs-keyword">for</span> month_num <span class="hljs-keyword">in</span> ([<span class="hljs-number">1</span>], [<span class="hljs-number">2</span>], [<span class="hljs-number">3</span>], [<span class="hljs-number">4</span>], [<span class="hljs-number">5</span>], [<span class="hljs-number">6</span>], [<span class="hljs-number">7</span>], [<span class="hljs-number">8</span>], [<span class="hljs-number">9</span>], [<span class="hljs-number">10</span>], [<span class="hljs-number">11</span>], [<span class="hljs-number">12</span>])
) <span class="hljs-keyword">as</span> avg_unpivot;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652505017290/3BsDEanDK.PNG" alt="sql server unpivot example.PNG" /></p>
<p>In the above SQL snippet, we first used the PIVOT operator to return a row containing a name for the average_name column along with 12 other columns containing the values of the average order amount for each month, the result set is named avg_pivot_month. Later using that result set with UNPIVOT operator we transposed those 12 multiple columns of the month to 1 column named month_num and its values in the average_amounts column. And remember that since there is no record for the first 4 months in our table set, we will not get those months in the month_num column. Note that UNPIVOT operator doesn't split up the aggregated results, hence UNPIVOT operator is not exactly the opposite of the PIVOT operator.</p>
<p>In the next post regarding PIVOT and UNPIVOT, we will be trying to implement a dynamic SQL PIVOT and UNPIVOT script/function with an example dataset.</p>
]]></content:encoded></item><item><title><![CDATA[Track Data Changes in SQL Server with Change Tracking]]></title><description><![CDATA[SQL Server provides three mechanisms to track data changes in the table objects. This mechanism is also a useful solution for implementing the audit and logging process for the SQL Server Instance. The mechanisms are Change Tracking also known as CT,...]]></description><link>https://mssqlserver.dev/track-data-changes-in-sql-server-with-change-tracking</link><guid isPermaLink="true">https://mssqlserver.dev/track-data-changes-in-sql-server-with-change-tracking</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[Azure SQL Database]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Sun, 10 Apr 2022 05:43:25 GMT</pubDate><content:encoded><![CDATA[<p>SQL Server provides three mechanisms to track data changes in the table objects. This mechanism is also a useful solution for implementing the audit and logging process for the SQL Server Instance. The mechanisms are Change Tracking also known as CT, Change Data Capture also known as CDC, and Temporal Table (System Versioned Table). We can also implement a custom logging and auditing process with help of Triggers on DML Events, which we illustrated in our previous <a target="_blank" href="https://mssqlserver.dev/auditing-and-implementing-data-change-capture-with-triggers-in-sql-server">post here</a>. Change Tracking or CT is a lightweight synchronous solution that only tracks the row changes in the table but doesn't capture the data changes. Due to this limitation of capturing changes in data and its history, the mechanism has less overhead cost compared to others. In simpler terms, CT tracks DML events on the table causing data modifications, and it will return by providing the Primary Key column value of the modified row, the changed column, and the modification type, it doesn't return the data changes done for the columns and it doesn't also provide the previous data before change event. For example, if a row is inserted, then updated multiple times, and finally deleted, CT will record only the last delete operation in the transaction, we will illustrate this with an example later. Thus, to implement CT, the table should have a primary key column. Before moving forward and playing with CT implementation, let's create a database and a table with data in it.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> DemoDB;

<span class="hljs-keyword">use</span> DemoDB;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> products(
   <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> primary <span class="hljs-keyword">key</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>),
   item_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
   item_description <span class="hljs-built_in">varchar</span>(<span class="hljs-number">40</span>),
   unit_price <span class="hljs-built_in">decimal</span>(<span class="hljs-number">8</span>,<span class="hljs-number">2</span>)
);

<span class="hljs-keyword">SET</span> IDENTITY_INSERT [dbo].[products] <span class="hljs-keyword">ON</span> 
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, N<span class="hljs-string">'Compactor'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">7145.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, N<span class="hljs-string">'Crawler'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">9549.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, N<span class="hljs-string">'Excavator'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">39549.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, N<span class="hljs-string">'Scraper'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">4883.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, N<span class="hljs-string">'Grader'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">9549.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">6</span>, N<span class="hljs-string">'Trencher'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">7347.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">7</span>, N<span class="hljs-string">'Backhoe'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">1275.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">8</span>, N<span class="hljs-string">'Dragline'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">9549.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, N<span class="hljs-string">'Dump Truck'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">25241.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">INSERT</span> [dbo].[products] ([<span class="hljs-keyword">id</span>], [item_name], [item_description], [unit_price]) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">10</span>, N<span class="hljs-string">'Item 1'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-keyword">CAST</span>(<span class="hljs-number">500.00</span> <span class="hljs-keyword">AS</span> <span class="hljs-built_in">Decimal</span>(<span class="hljs-number">8</span>, <span class="hljs-number">2</span>)))
<span class="hljs-keyword">GO</span>
<span class="hljs-keyword">SET</span> IDENTITY_INSERT [dbo].[products] <span class="hljs-keyword">OFF</span>
<span class="hljs-keyword">GO</span>

<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products;
</code></pre>
<h2 id="heading-enabling-change-tracking">Enabling Change Tracking</h2>
<p>To enable CT on the table, we have to enable it on the database level first. Since we have created a demo database for the illustration with the table and its data, let's enable Change Tracking for our DemoDB database.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">use</span> DemoDB;

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">DATABASE</span> DemoDB
<span class="hljs-keyword">SET</span> CHANGE_TRACKING = <span class="hljs-keyword">ON</span>
(CHANGE_RETENTION = <span class="hljs-number">2</span> <span class="hljs-keyword">DAYS</span>, AUTO_CLEANUP = <span class="hljs-keyword">ON</span>);
</code></pre>
<p>As the alter statement above enables Change_Tracking on Database Level, we need to mention retention value and CleanUp value. Change_retention field requires value and unit, so the data can be retained for the mentioned period in the internal on-disk tables and the Auto_cleanup field takes ON or OFF as value, for enabling or disabling the auto cleanup process. If auto cleanup is enabled then it will delete the internal on-disk tables data after the mentioned retention period automatically. After enabling CT on the Database level, we also have to enable it for each table we want to track.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">USE</span> DemoDB
<span class="hljs-keyword">GO</span>

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> products
<span class="hljs-keyword">ENABLE</span> CHANGE_TRACKING
<span class="hljs-keyword">WITH</span> (TRACK_COLUMNS_UPDATED = <span class="hljs-keyword">ON</span>);
</code></pre>
<p>With the alter statement above, we enabled the change tracking for the table we wanted. We could also do the enabling of both, the database level and table level through the management studio, by visiting database properties and table properties respectively. Now let's see how Change Tracking works with each DML event.</p>
<p>Before moving forward, we need to know one thing, it is about the version number counter, and is incremented automatically with any DML operation on the tracked table. To check the current version of the tracked table, use the below query</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> CHANGE_TRACKING_CURRENT_VERSION();
</code></pre>
<h2 id="heading-dml-events-making-changes">DML Events making Changes</h2>
<h3 id="heading-insert-operation">Insert Operation</h3>
<p>To see the working of Change Tracking in the case of an Insert operation, let's insert 2 new records in our product table which is a tracked table, and see how we can track the new insertions</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(item_name, unit_price) <span class="hljs-keyword">VALUES</span>
    (<span class="hljs-string">'Item 1'</span>, <span class="hljs-number">322.45</span>),
    (<span class="hljs-string">'Item 2'</span>, <span class="hljs-number">137.90</span>);
</code></pre>
<p>We can utilize the Change Tracking functions and CHANGETABLE system function, to access the data saved in the internal table after the INSERT statement executed above. Each DML event causing data modifications increments the version number counter. The function returns all the changes made on the tracked table with the version counter. Query the select statement given below to view the modifications in the tracked table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> CHANGETABLE 
(CHANGES products,<span class="hljs-number">0</span>) <span class="hljs-keyword">as</span> CT <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> SYS_CHANGE_VERSION;
</code></pre>
<p>image: In the image, we can see the version counter, type of DML Event, which is I in our case as we did inserts along with the primary key column as value for the newly inserted rows. We also see that SYS_CHANGE_COLUMNS, SYS_CHANGE_CONTEXT column currently has a NULL value. SYS_CHANGE_COLUMNS returns the list of columns which was modified since the last version counter and are of binary data type. Also, note that Inserts and Deletes will always have an SYS_CHANGE_COLUMNS value "null", a whole row is affected by an insert or a delete. SYS_CHANGE_CONTEXT is optional and is used to specify the context changes using WITH clause while performing DML changes.</p>
<h3 id="heading-update-operation">Update Operation</h3>
<p>Like the insert operation, let's perform the update operation, by updating unit_price to 500.00 for product id 10 and also two updates for product id 11 in the products table. Before proceeding to execute the update statement, check the current version number.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> products <span class="hljs-keyword">SET</span> unit_price = <span class="hljs-number">500.00</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">10</span>;
<span class="hljs-keyword">UPDATE</span> products <span class="hljs-keyword">SET</span> unit_price = <span class="hljs-number">500.00</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">11</span>;
<span class="hljs-keyword">UPDATE</span> products <span class="hljs-keyword">SET</span> unit_price = <span class="hljs-number">520.00</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">11</span>;
</code></pre>
<p>Now let's see the effect of the above update statement in our internal table, with the same select statement executed above.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> CHANGETABLE 
(CHANGES products, <span class="hljs-number">1</span>) <span class="hljs-keyword">as</span> CT <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> SYS_CHANGE_VERSION;
</code></pre>
<p>image:</p>
<p>In the snapshot above, we can see that SYS_CHANGE_VERSION which is maintaining the counter incremented for the id 10 along with U Char for the SYS_CHANGE_OPERATION column denoting that the last operation on the row was an update statement, and SYS_CHANGE_COLUMNS contains the binary value for the columns modified. Notice that the above select statement is a little different than the previous select statement we used in the Insert part. Along with the table name in the CHANGES sub-clause we also provided 1 as a literal value which was my current version counter before the update operation. Mentioning it in the select query from the changetable, we get the record of the modification made after the last version mentioned. Even though product id 11 has been updated twice, we only can get the record of the most recent modification made to the row. It doesn't provide the history of data changes made. Now let's see how a delete operation is recorded in the Changetable internal table.</p>
<h3 id="heading-delete">Delete</h3>
<p>Now, let's delete the product having id 11 from the products table, by executing the below delete statement. Before that, you can check the current version, which we use to query changetable later. My current counter value is 4.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">11</span>;
</code></pre>
<p>Now let's query the changetable and see the records reflecting our delete operation</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> CHANGETABLE 
(CHANGES products, <span class="hljs-number">4</span>) <span class="hljs-keyword">as</span> CT <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> SYS_CHANGE_VERSION;
</code></pre>
<p>image: In the above select query to fetch the records from the changetable for the table products, we passed the literal value 4 after the comma in the CHANGES sub-clause, it was my version counter value before the delete statement was executed. And we can see the version counter has incremented and the SYS_CHANGE_OPERATION value is Character D denoting the Delete operation. SYS_CHANGE_COLUMNS depicting the list of the columns changed will be null, as it was a delete operation. Now, let's run the same select query on the changetable for the products table, but this time we will provide literal value 1 in place of 4 for the CHANGES clause within the brackets. This will return the last modifications made in the products table after our first insertion for the records.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> CHANGETABLE 
(CHANGES products, <span class="hljs-number">1</span>) <span class="hljs-keyword">as</span> CT <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> SYS_CHANGE_VERSION;
</code></pre>
<p>image: In the snapshot of the output above, we can infer that the changetable only records the last modification made for the particular record row. Earlier in the Update part, we perform an update operation twice on product id 11 still it only shows the record of the last operation for product id 11.</p>
<h2 id="heading-disable-changetracking">Disable Change_Tracking</h2>
<p>To disable the Change_Tracking (CT) function, we need to first disable tracking for the tracked tables. After disabling tracking on the table, we can disable it for the database with the T-SQL code below</p>
<pre><code class="lang-sql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> products
<span class="hljs-keyword">DISABLE</span> CHANGE_TRACKING
<span class="hljs-keyword">GO</span>

<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">DATABASE</span> DemoDB
<span class="hljs-keyword">SET</span> CHANGE_TRACKING = <span class="hljs-keyword">OFF</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>The Change_Tracking function has limited usage and it's mainly the best use case where we want to track the data changes on the table, but we have no requirement for the pre and post-data modifications, or we only want to know if the row is modified or not. One such use case is implementing a custom cache layer for the application where we can synchronize our cache database for the application or reinitialize it as the case may be. In the next post for Change Tracking, we will be looking at a few Change Tracking Functions.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Isolation levels in SQL Server]]></title><description><![CDATA[A transaction is a group of T-SQL statements performing single or multiple operations on objects as a single unit. If any of the statements in the transaction fails, then the whole operation reverts due to transaction rollback. This assures that thos...]]></description><link>https://mssqlserver.dev/understanding-isolation-levels-in-sql-server</link><guid isPermaLink="true">https://mssqlserver.dev/understanding-isolation-levels-in-sql-server</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Wed, 06 Apr 2022 09:20:09 GMT</pubDate><content:encoded><![CDATA[<p>A transaction is a group of T-SQL statements performing single or multiple operations on objects as a single unit. If any of the statements in the transaction fails, then the whole operation reverts due to transaction rollback. This assures that those multiple statements in the transaction work as a single unit and either commit as a single unit or rollback all the modifications it was performing and return with an error. And we also know that we have 3 types of Transaction Modes namely Auto-commit transactions, Implicit transactions, and Explicit transactions. The integrity of the Transactions and concurrent users is determined by the Isolation level. The Isolation level defines how the Transaction must be isolated from other Transactions and their data modifications. These Isolation levels manage the locking of the resources between Transactions. The isolation levels we will be understanding in this post are</p>
<ul>
<li><p>Read Uncommitted</p>
</li>
<li><p>Read Committed (The default)</p>
</li>
<li><p>Repeatable Read</p>
</li>
<li><p>Serializable</p>
</li>
<li><p>Snapshot Isolation and its example are already covered in another post links to them are at the end of this post. Before moving forward to Isolation levels one by one, let's create a table with some mock data for some illustrations later.</p>
</li>
</ul>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> product_listing;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> product_listing(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>),
    item_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    description <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>),
    unit_price <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>)
);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Compactor'</span>, <span class="hljs-number">7145.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Crawler'</span>, <span class="hljs-number">9549.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Excavator'</span>, <span class="hljs-number">39549.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Scraper'</span>, <span class="hljs-number">4883.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Grader'</span>, <span class="hljs-number">9549.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Trencher'</span>, <span class="hljs-number">7347.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Backhoe'</span>, <span class="hljs-number">1275.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Dragline'</span>, <span class="hljs-number">9549.00</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Dump Truck'</span>, <span class="hljs-number">25241.00</span>);
</code></pre>
<p>Now, let's start.</p>
<ol>
<li>Read Uncommitted; Read Uncommitted is the lowest level of isolation, it enables the Transaction to read uncommitted data modifications made by other transactions concurrently on the same resources. The transaction can read the row values even when locks are applied on that row by other transactions and that other transaction has not committed or rollbacked either yet. This case is also known as Dirty Reads. Since the other transaction modifying the rows hasn't yet made a commit or rollback, we may see unexpected results. However, there are cases where we might be required to read uncommitted data.</li>
</ol>
<p>Run both the below transactions in two separate query editor tabs. In our example, let's try to update the unit_price of the product having id as 1 in the product_listing table. And let's try to read that product id row in another transaction.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">Begin</span> <span class="hljs-keyword">Transaction</span>

<span class="hljs-keyword">Update</span> product_listing <span class="hljs-keyword">set</span> unit_price = <span class="hljs-number">10000.00</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;

waitfor delay '00:00:10';

<span class="hljs-keyword">Rollback</span> <span class="hljs-keyword">Transaction</span> ;
</code></pre>
<p>Now in another window tab, try to read the product_listing table for that same id, i.e. 1</p>
<pre><code class="lang-sql"><span class="hljs-keyword">set</span> <span class="hljs-keyword">transaction</span> <span class="hljs-keyword">isolation</span> <span class="hljs-keyword">level</span> <span class="hljs-keyword">read</span> uncommitted;

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>; 

waitfor delay '00:00:10';
</code></pre>
<p>In the first transaction, we updated the unit_price of product id 1 of the product_listing table and simulated a delay so we can read the value of product id 1 in the second transaction. On the other query editor screen when executing the second transaction we can see that even though the update statement in the first transaction has an exclusive lock for the row, it's readable by the select statements in the second transaction. The first select statement in the second transaction returns the updated unit_price of the product_id 1 and then waits for the first transaction to roll back, to read again for the same product and find out that the unit_price is changed again and it reverted to the old value. Simply saying the second transaction returned the value that was there at that time. Another syntax for reading uncommitted data is to use the NOLOCK table hint, which then read uncommitted data even if the isolation level is not mentioned in the transaction.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span> <span class="hljs-keyword">with</span>(NOLOCK);
</code></pre>
<ol>
<li>Read Committed: This is the default isolation level and it guarantees that the return of any data read is the committed value at the time of reading. In simpler terms, the read operation will wait, for any pending transaction on the same table to complete and will return the committed value. The shared lock request on the data will wait for the exclusive lock to commit if any pending in other transactions for the same data. Let's simulate it with example table data.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">BEGIN</span> <span class="hljs-keyword">TRANSACTION</span>

<span class="hljs-keyword">Update</span> product_listing <span class="hljs-keyword">set</span> unit_price = <span class="hljs-number">10000.00</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;

waitfor delay '00:00:10';

<span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>;
</code></pre>
<p>In another query editor window tab, we will read the data for the same id.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;
</code></pre>
<p>Executing both transactions in a different window, we can see that the second transaction, even though it's only a read operation, it waits for the first transaction to complete (i.e. either commit or rollback) and on completion of the first transaction, the second transaction can read the data. We have to remember that the read operation will issue shared lock requests against data we want to read, and it will wait if another transaction already has an exclusive lock on that data. If both the transactions working on the same data want only a shared lock, then there won't be any execution delay for the transaction, as they don't need to wait for the other transaction to complete. The transaction holds a read or write lock on the current row, and thus prevents other transactions from reading, updating, or deleting it.</p>
<ol>
<li>Repeatable Read IN THIS ISOLATION LEVEL, every time we read the same record set it returns the same value till the end of the transaction. It blocks the write operation trying to update the same record set we are reading, by holding a shared lock till the transaction is complete. Thus we see the same results within the transaction. It is to note here that, Repeatable Read blocks update and delete operation for the same recordset which obtained the shared lock, but it doesn't block insert operation. If the new records are satisfying the condition of the select statement, it will also return those newly added records along with the previous record set. Let's simulate both cases.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span> <span class="hljs-keyword">transaction</span>;
<span class="hljs-keyword">set</span> <span class="hljs-keyword">transaction</span> <span class="hljs-keyword">isolation</span> <span class="hljs-keyword">level</span> repeatable <span class="hljs-keyword">read</span>;

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> unit_price &lt; <span class="hljs-number">2000</span>; 

waitfor delay '00:00:10';

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> unit_price &lt; <span class="hljs-number">2000</span>;

<span class="hljs-keyword">commit</span> <span class="hljs-keyword">transaction</span>;
</code></pre>
<p>In the second transaction in the new window, we will try to update the unit_price of product id 7 to 1900.</p>
<pre><code class="lang-plaintext">-- transaction 2
Update product_listing set unit_price = 1900 where id = 7;
</code></pre>
<p>But if we read the data after all the transactions are completed, we can see that unit_price of the product id 7 is updated to 1900.00 This shows us how Repeatable Read Isolation prevents data modification till the end of the transaction. Let's also simulate the second case, to see how the insert operation will work with the isolation level.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span> <span class="hljs-keyword">transaction</span>;
<span class="hljs-keyword">set</span> <span class="hljs-keyword">transaction</span> <span class="hljs-keyword">isolation</span> <span class="hljs-keyword">level</span> repeatable <span class="hljs-keyword">read</span>;

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> unit_price &lt; <span class="hljs-number">2000</span>;

waitfor delay '00:00:10'; 

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> unit_price &lt; <span class="hljs-number">2000</span>; 

<span class="hljs-keyword">commit</span> <span class="hljs-keyword">transaction</span>;
</code></pre>
<p>In the second transaction, another window, we will insert another new product having unit_price below 2000.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'new item 1'</span>, <span class="hljs-number">1500.00</span>);
</code></pre>
<p>As we can see on both the transaction execution, even though the first transaction has obtained a shared lock on the same read condition, still the second transaction returns immediately without waiting for the first transaction execution to finish. Now when we perform the read operation for the second time, in transaction one after transaction two completes its insertion, we get two rows returned, old records along with new records as it satisfies the WHERE conditions. Do remember that, Repeatable Read doesn't block insert operation, thus leading to phantom read in some cases.</p>
<ol>
<li>Serializable This is similar to the Repeatable Read isolation level with an extra added layer that prevents insert operations also. This eradicates the problem of phantom reads. Serializable Isolation level uses range locks on the record set, so it can't be modified, inserted, or deleted till the end of the transaction. Let's simulate the previous example to see if the insert operations are blocked till the end of the transaction.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span> <span class="hljs-keyword">transaction</span>;
<span class="hljs-keyword">set</span> <span class="hljs-keyword">transaction</span> <span class="hljs-keyword">isolation</span> <span class="hljs-keyword">level</span> <span class="hljs-keyword">serializable</span>;

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> unit_price &lt; <span class="hljs-number">2000</span>;

waitfor delay '00:00:10'; 

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> product_listing <span class="hljs-keyword">where</span> unit_price &lt; <span class="hljs-number">2000</span>;

<span class="hljs-keyword">commit</span> <span class="hljs-keyword">transaction</span>;
</code></pre>
<p>In the second transaction, another window, we will insert another new product having unit_price below 2000.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> product_listing(item_name, unit_price) <span class="hljs-keyword">values</span> (<span class="hljs-string">'new item 2'</span>, <span class="hljs-number">1700.00</span>);
</code></pre>
<p>With both transaction execution, we can see that the second transaction which has an insert operation doesn't return immediately like in Repeatable Read Isolation. The second transaction waits till the first transaction is complete and on completion of the first transaction, the second transaction performs the insert operation for adding a new record. This demonstrates the blocking of all DML operations from another transaction, till the current transaction is completed under Serializable Isolation. It is to be noted that, if the table has an index on it, then the records are locked based on those index ranges used in the WHERE clause, otherwise it locks the complete table for the transaction.</p>
<p>This completes our small post of transaction isolation level. For the Snapshot Isolation, kindly look at the below-given links.</p>
<ul>
<li><a target="_blank" href="https://mssqlserver.dev/sql-server-concurrency-with-row-versioning">SQL Server Concurrency with Row Versioning</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Auditing & Implementing Data Change Capture with Triggers in SQL Server]]></title><description><![CDATA[Database Auditing is a process of tracking and logging all events and capturing data changes in database objects, it not only helps businesses but is also a compliance requirement. In most cases when we want to implement capturing of data changes in ...]]></description><link>https://mssqlserver.dev/auditing-and-implementing-data-change-capture-with-triggers-in-sql-server</link><guid isPermaLink="true">https://mssqlserver.dev/auditing-and-implementing-data-change-capture-with-triggers-in-sql-server</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Sun, 03 Apr 2022 09:37:44 GMT</pubDate><content:encoded><![CDATA[<p>Database Auditing is a process of tracking and logging all events and capturing data changes in database objects, it not only helps businesses but is also a compliance requirement. In most cases when we want to implement capturing of data changes in database objects, we create a log table for that object and track all changes made by DML queries on that table. We can also implement database object changes made by DDL statements. In this post, we will be implementing and creating a log table for auditing and logging DML event data changes with help of triggers. To understand Trigger and its working with examples please refer to the <a target="_blank" href="https://mssqlserver.dev/understanding-triggers-in-sql-server-with-examples">previous post</a> mentioned below. As said earlier we can create a trigger on tables containing critical data to audit and log the data before and after the modification. We can also use a trigger to disable the particular DML operation and can execute something else instead of performing that change. Let's illustrate auditing and capturing data changes with triggers. The following T-SQL codes create a simple sales table seeded with its data and a sales_log table with the required columns. The sales_log table will have all columns of the sales table and a few extra columns for logging the old value and new values of the sales table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> [dbo].sales;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> [dbo].sales(
    sales_id <span class="hljs-built_in">int</span> primary <span class="hljs-keyword">key</span>,
    customer_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    sales_person_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    order_date <span class="hljs-built_in">date</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    total_amount_including_taxes <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>),
    tax_amount <span class="hljs-built_in">decimal</span>(<span class="hljs-number">8</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>),
    delivery_date <span class="hljs-built_in">date</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    extra_instruction <span class="hljs-built_in">varchar</span>(<span class="hljs-number">500</span>),
    updated_by <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    updated_timestamp datetime2(<span class="hljs-number">0</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">current_timestamp</span>
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-09-27'</span>, <span class="hljs-number">1704.69</span>, <span class="hljs-number">49.81</span>, <span class="hljs-string">'2021-09-29'</span>, <span class="hljs-string">'in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae mattis nibh ligula nec sem duis aliquam convallis nunc'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-09-27'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-10-25'</span>, <span class="hljs-number">3314.02</span>, <span class="hljs-number">99.97</span>, <span class="hljs-string">'2021-10-27'</span>, <span class="hljs-string">'consectetuer eget rutrum at lorem integer tincidunt ante vel ipsum praesent blandit lacinia erat vestibulum sed magna'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-10-25'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-09-25'</span>, <span class="hljs-number">9147.42</span>, <span class="hljs-number">54.77</span>, <span class="hljs-string">'2021-09-30'</span>, <span class="hljs-string">'nisl ut volutpat sapien arcu sed augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-09-25'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-number">9</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-01-27'</span>, <span class="hljs-number">5173.06</span>, <span class="hljs-number">26.01</span>, <span class="hljs-string">'2022-01-30'</span>, <span class="hljs-string">'ipsum dolor sit amet consectetuer adipiscing elit proin risus praesent'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-01-27'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-04-27'</span>, <span class="hljs-number">8838.68</span>, <span class="hljs-number">33.07</span>, <span class="hljs-string">'2022-04-30'</span>, <span class="hljs-string">'ac tellus semper interdum mauris ullamcorper purus sit amet nulla quisque arcu libero rutrum ac lobortis'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-04-27'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">6</span>, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-05-02'</span>, <span class="hljs-number">5959.05</span>, <span class="hljs-number">61.41</span>, <span class="hljs-string">'2021-05-27'</span>, <span class="hljs-string">'ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-05-02'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">7</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-04-15'</span>, <span class="hljs-number">1521.54</span>, <span class="hljs-number">78.27</span>, <span class="hljs-string">'2021-04-21'</span>, <span class="hljs-string">'vel lectus in quam fringilla rhoncus mauris enim leo rhoncus'</span>, <span class="hljs-number">3</span>,  <span class="hljs-string">'2022-04-15'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">8</span>, <span class="hljs-number">9</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-08-25'</span>, <span class="hljs-number">6301.25</span>, <span class="hljs-number">66.37</span>, <span class="hljs-string">'2021-08-30'</span>, <span class="hljs-string">'ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-08-25'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-09-29'</span>, <span class="hljs-number">6894.79</span>, <span class="hljs-number">15.74</span>, <span class="hljs-string">'2021-10-29'</span>, <span class="hljs-string">'pede ullamcorper augue a suscipit nulla elit ac nulla sed vel'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-09-29'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">10</span>, <span class="hljs-number">5</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-12-08'</span>, <span class="hljs-number">8310.35</span>, <span class="hljs-number">35.54</span>, <span class="hljs-string">'2021-12-31'</span>, <span class="hljs-string">'mi integer ac neque duis bibendum morbi non quam nec'</span>, <span class="hljs-number">4</span>,  <span class="hljs-string">'2021-12-08'</span>);
 <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">11</span>, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-10-13'</span>, <span class="hljs-number">5815.76</span>, <span class="hljs-number">95.91</span>, <span class="hljs-string">'2021-10-20'</span>, <span class="hljs-string">'non mi integer ac neque duis bibendum morbi non quam nec dui luctus rutrum'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-10-13'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">12</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-04-24'</span>, <span class="hljs-number">1860.23</span>, <span class="hljs-number">65.36</span>, <span class="hljs-string">'2022-04-24'</span>, <span class="hljs-string">'odio porttitor id consequat in consequat ut nulla sed accumsan felis ut at dolor quis odio consequat varius integer'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-04-24'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">13</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2022-01-22'</span>, <span class="hljs-number">8716.47</span>, <span class="hljs-number">31.77</span>, <span class="hljs-string">'2022-01-28'</span>, <span class="hljs-string">'nec condimentum neque sapien placerat ante nulla justo aliquam quis turpis eget'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2022-01-22'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">14</span>, <span class="hljs-number">6</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-03-26'</span>, <span class="hljs-number">9954.56</span>, <span class="hljs-number">29.54</span>, <span class="hljs-string">'2022-03-27'</span>, <span class="hljs-string">'in purus eu magna vulputate luctus cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus'</span>, <span class="hljs-number">2</span>,<span class="hljs-string">'2022-03-26'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">15</span>, <span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-07-31'</span>, <span class="hljs-number">4671.74</span>, <span class="hljs-number">43.64</span>, <span class="hljs-string">'2021-08-16'</span>, <span class="hljs-string">'nisl nunc rhoncus dui vel sem sed sagittis nam congue risus semper porta'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-07-31'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">16</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-02-25'</span>, <span class="hljs-number">3511.53</span>, <span class="hljs-number">74.65</span>, <span class="hljs-string">'2022-02-25'</span>, <span class="hljs-string">'pede ac diam cras pellentesque volutpat dui maecenas tristique est et tempus semper est quam pharetra magna ac consequat'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-02-25'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">17</span>, <span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-10-01'</span>, <span class="hljs-number">8507.02</span>, <span class="hljs-number">59.93</span>, <span class="hljs-string">'2021-10-14'</span>, <span class="hljs-string">'amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla ac enim in tempor'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-10-01'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">18</span>, <span class="hljs-number">6</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2022-01-08'</span>, <span class="hljs-number">8008.41</span>, <span class="hljs-number">69.92</span>, <span class="hljs-string">'2022-01-28'</span>, <span class="hljs-string">'venenatis lacinia aenean sit amet justo morbi ut odio cras mi pede malesuada in imperdiet et commodo vulputate'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2022-01-08'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">19</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-02-11'</span>, <span class="hljs-number">1291.84</span>, <span class="hljs-number">19.51</span>, <span class="hljs-string">'2022-02-15'</span>, <span class="hljs-string">'eget elit sodales scelerisque mauris sit amet eros suspendisse accumsan tortor quis turpis sed ante vivamus'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2022-02-11'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">20</span>, <span class="hljs-number">8</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2022-03-25'</span>, <span class="hljs-number">2948.43</span>, <span class="hljs-number">22.37</span>, <span class="hljs-string">'2022-03-27'</span>, <span class="hljs-string">'curae nulla dapibus dolor vel est donec odio justo sollicitudin'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2022-03-25'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">21</span>, <span class="hljs-number">5</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-06-12'</span>, <span class="hljs-number">5466.84</span>, <span class="hljs-number">35.58</span>, <span class="hljs-string">'2021-06-30'</span>, <span class="hljs-string">'in faucibus orci luctus et ultrices posuere cubilia curae mauris viverra'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-06-12'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">22</span>, <span class="hljs-number">9</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-11-30'</span>, <span class="hljs-number">8762.52</span>, <span class="hljs-number">22.53</span>, <span class="hljs-string">'2021-12-30'</span>, <span class="hljs-string">'ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-06-12'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">23</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-05-18'</span>, <span class="hljs-number">7894.89</span>, <span class="hljs-number">51.04</span>, <span class="hljs-string">'2021-05-18'</span>, <span class="hljs-string">'id pretium iaculis diam erat fermentum justo nec condimentum neque'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-05-18'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">24</span>, <span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-01-20'</span>, <span class="hljs-number">9051.32</span>, <span class="hljs-number">22.23</span>, <span class="hljs-string">'2022-01-20'</span>, <span class="hljs-string">'nibh in hac habitasse platea dictumst aliquam augue quam sollicitudin'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-01-20'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">values</span> (<span class="hljs-number">25</span>, <span class="hljs-number">7</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-03-20'</span>, <span class="hljs-number">2537.84</span>, <span class="hljs-number">36.42</span>, <span class="hljs-string">'2022-03-30'</span>, <span class="hljs-string">'velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-03-20'</span>);

<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> [dbo].sales_log;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> [dbo].sales_log(
    log_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>),
    sales_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    customer_id_old <span class="hljs-built_in">int</span>,
    customer_id_new <span class="hljs-built_in">int</span>,
    sales_person_id_old <span class="hljs-built_in">int</span>,
    sales_person_id_new <span class="hljs-built_in">int</span>,
    order_date_old <span class="hljs-built_in">date</span>,
    order_date_new <span class="hljs-built_in">date</span>,
    total_amount_including_taxes_old <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>),
    total_amount_including_taxes_new <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>),
    tax_amount_old <span class="hljs-built_in">decimal</span>(<span class="hljs-number">8</span>,<span class="hljs-number">2</span>),
    tax_amount_new <span class="hljs-built_in">decimal</span>(<span class="hljs-number">5</span>,<span class="hljs-number">2</span>),
    delivery_date_old <span class="hljs-built_in">date</span>,
    delivery_date_new <span class="hljs-built_in">date</span>,
    extra_instruction_old <span class="hljs-built_in">varchar</span>(<span class="hljs-number">500</span>),
    extra_instruction_new <span class="hljs-built_in">varchar</span>(<span class="hljs-number">500</span>),
    updated_by_old <span class="hljs-built_in">int</span>,
    updated_by_new <span class="hljs-built_in">int</span>,
    updated_timestamp_old datetime2(<span class="hljs-number">0</span>),
    updated_timestamp_new datetime2(<span class="hljs-number">0</span>),
    action_done <span class="hljs-built_in">varchar</span>(<span class="hljs-number">6</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    action_time datetime2(<span class="hljs-number">0</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    username <span class="hljs-built_in">varchar</span>(<span class="hljs-number">128</span>) <span class="hljs-literal">null</span>
);
</code></pre>
<p>The sales_log table inserts both old and new values of the columns, for every write operation in the sales table. It helps in tracking data changes and the columns action_done, action_time, and username in the sales_log table with DML operation which caused the change, timestamp, and database user. Normally we create a different user in the database for the application, so it's necessary to know the database user. Now let's create a trigger that tracks data changes in the sales table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TRIGGER</span> TR_audit_sales_table
    <span class="hljs-keyword">ON</span> [dbo].sales
    <span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">INSERT</span>, <span class="hljs-keyword">UPDATE</span>, <span class="hljs-keyword">DELETE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">SET</span> NOCOUNT <span class="hljs-keyword">ON</span>;
    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> [dbo].sales_log 
        (sales_id,
        customer_id_old,
        customer_id_new,
        sales_person_id_old,
        sales_person_id_new,
        order_date_old,
        order_date_new,
        total_amount_including_taxes_old,
        total_amount_including_taxes_new,
        tax_amount_old,
        tax_amount_new,
        delivery_date_old,
        delivery_date_new,
        extra_instruction_old,
        extra_instruction_new,
        updated_by_old,
        updated_by_new,
        updated_timestamp_old,
        updated_timestamp_new,
        action_done,
        action_time,
        username
        )
    <span class="hljs-keyword">SELECT</span>
        <span class="hljs-keyword">ISNULL</span>(i.sales_id, d.sales_id) <span class="hljs-keyword">AS</span> sales_id,
        d.customer_id,
        i.customer_id,
        d.sales_person_id,
        i.sales_person_id,
        d.order_date,
        i.order_date,
        d.total_amount_including_taxes,
        i.total_amount_including_taxes,
        d.tax_amount,
        i.tax_amount,
        d.delivery_date,
        i.delivery_date,
        d.extra_instruction,
        i.extra_instruction,
        d.updated_by,
        i.updated_by,
        d.updated_timestamp,
        i.updated_timestamp,
        <span class="hljs-keyword">CASE</span>
            <span class="hljs-keyword">WHEN</span> i.sales_id <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">THEN</span> <span class="hljs-string">'DELETE'</span>
            <span class="hljs-keyword">WHEN</span> d.sales_id <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">THEN</span> <span class="hljs-string">'INSERT'</span>
            <span class="hljs-keyword">ELSE</span> <span class="hljs-string">'UPDATE'</span>
        <span class="hljs-keyword">END</span> <span class="hljs-keyword">AS</span> action_done,
        <span class="hljs-keyword">SYSUTCDATETIME</span>(),
        SUSER_SNAME()
    <span class="hljs-keyword">FROM</span> inserted i
    <span class="hljs-keyword">FULL</span> <span class="hljs-keyword">JOIN</span> deleted d
    <span class="hljs-keyword">ON</span> i.sales_id = d.sales_id;
<span class="hljs-keyword">END</span>
</code></pre>
<p>The above trigger code inserts new rows in the sales_log table for every write operation on the sales table and it can be further modified as per the requirements.</p>
<p>With the trigger created and executed, now we will test the working with some write operations in the sales table. Let us insert a new sale record in the sales table and see the information captured in the sales_log table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales (sales_id, customer_id, sales_person_id, order_date, total_amount_including_taxes, tax_amount, delivery_date, extra_instruction, updated_by, updated_timestamp) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">26</span>, <span class="hljs-number">7</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-03-22'</span>, <span class="hljs-number">25337.84</span>, <span class="hljs-number">361.42</span>, <span class="hljs-string">'2022-05-01'</span>, <span class="hljs-string">'velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2022-03-20'</span>);
</code></pre>
<p>With a new sale record added having sales_id as 26, we can see the captured data in the sales_log table with the action type and database username which made those changes. A few of the columns in the sales_log table will be NULL since old data does not exist in the insert operation. Now let's update the same sale record updating the sales_person_id, total_amount_including_taxes and tax_amount.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> sales <span class="hljs-keyword">SET</span>
    sales_person_id = <span class="hljs-number">2</span>,
    total_amount_including_taxes = <span class="hljs-number">30000.00</span>,
    tax_amount = <span class="hljs-number">300.00</span>
<span class="hljs-keyword">WHERE</span> sales_id = <span class="hljs-number">26</span>;
</code></pre>
<p>When we check the log of the update operation in the sales_log table we can see that the trigger has captured and inserted both old data values and new data values for all columns and also see that the action_done is set to 'UPDATE'; Now let's delete a sale record from the sales table and see its insert in the sales_log table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> sales <span class="hljs-keyword">WHERE</span> sales_id = <span class="hljs-number">26</span>;
</code></pre>
<p>Now when we inspect the sales_log table for the above delete operation, we only see old values for the columns and NULL for the corresponding columns holding new values. This is how we can use the trigger for auditing and implementing data changes capture in SQL Server.</p>
<p>Related Post: <a target="_blank" href="https://mssqlserver.dev/understanding-triggers-in-sql-server-with-examples">Understanding Triggers in SQL Server</a></p>
]]></content:encoded></item><item><title><![CDATA[Understanding Triggers in SQL Server]]></title><description><![CDATA[A trigger is an object having a collection of code or codes which fires automatically when an event occurs in the database server. The most used database events which cause the database to execute triggers are DDL(DATA DEFINITION LANGUAGE) Event and ...]]></description><link>https://mssqlserver.dev/understanding-triggers-in-sql-server-with-examples</link><guid isPermaLink="true">https://mssqlserver.dev/understanding-triggers-in-sql-server-with-examples</guid><category><![CDATA[SQL Server]]></category><category><![CDATA[SQL]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Fri, 01 Apr 2022 05:19:31 GMT</pubDate><content:encoded><![CDATA[<p>A trigger is an object having a collection of code or codes which fires automatically when an event occurs in the database server. The most used database events which cause the database to execute triggers are DDL(DATA DEFINITION LANGUAGE) Event and DML(DATA MANIPULATION LANGUAGE) Event. DDL Triggers are used for TSQL statements like CREATE, ALTER, DROP, and also some system stored procedures, on the other hand, DML triggers get fired when the user tries to modify or change the data with INSERT, UPDATE, DELETE statements on table or views. These DML triggers can be defined to execute on INSERT, UPDATE, and DELETE operations, or for any combination of these operations. MERGE operation also fires triggers based on operations made within the MERGE statement.</p>
<p>The Trigger definition can either be of type INSTEAD OF or AFTER or FOR. When we perform a write operation on a table, the INSTEAD OF trigger replaces the operation and executes trigger content instead and in the case of AFTER trigger the trigger gets fired once the write operation is completed. Do Note that if the AFTER Trigger fails, the original write operation also fails.</p>
<p>The automated execution of code on every change event is the main plus point of the trigger and also if the trigger code fails, the event which fired the trigger will fail. A few cases where triggers serve their purpose are tracking database changes including schema or object changes, writing table logs, and validation checks and also they can implement custom validation functions, enforcing other business rules, and exert control when performing an insert, update, or delete operations and decide what to do with data. Before moving forward let's create a simple trigger example.</p>
<h2 id="heading-basic-trigger-example">Basic Trigger Example</h2>
<p>Consider a case, wherein we want to log all update operations on the Users table and record those operations in the users_log table for our future audit purpose. Let's start by creating a Users table and inserting some data in it.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-keyword">users</span>;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">users</span>(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INT</span> <span class="hljs-keyword">IDENTITY</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) PRIMARY <span class="hljs-keyword">KEY</span>,
    first_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">30</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    last_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">35</span>),
    date_of_birth <span class="hljs-built_in">DATE</span>,
    user_type_id <span class="hljs-built_in">INT</span>
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Lamont'</span>, <span class="hljs-string">'Lantiffe'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'1996-10-03'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Xenia'</span>, <span class="hljs-string">'Donovin'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'1996-10-19'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Eleen'</span>, <span class="hljs-string">'Joriot'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'1997-01-19'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'De'</span>, <span class="hljs-string">'Alpe'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'1996-12-04'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Skipton'</span>, <span class="hljs-string">'Myrick'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'1996-03-23'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Kariotta'</span>, <span class="hljs-string">'Sapsforde'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'1996-12-10'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Darill'</span>, <span class="hljs-string">'De Moreno'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'1996-09-22'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Sayre'</span>, <span class="hljs-string">'Critch'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'1996-07-29'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Chrissy'</span>, <span class="hljs-string">'Vedekhov'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'1996-08-27'</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (first_name, last_name, user_type_id, date_of_birth) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Dalis'</span>, <span class="hljs-string">'Dutnall'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'1996-08-20'</span>);

<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> users_log ;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> users_log (
    users_log_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    users_id <span class="hljs-built_in">int</span>,
    first_name_old <span class="hljs-built_in">varchar</span>(<span class="hljs-number">30</span>),
    first_name_new <span class="hljs-built_in">varchar</span>(<span class="hljs-number">30</span>),
    last_name_old <span class="hljs-built_in">varchar</span>(<span class="hljs-number">35</span>),
    last_name_new <span class="hljs-built_in">varchar</span>(<span class="hljs-number">35</span>),
    date_of_birth_old <span class="hljs-built_in">date</span>,
    date_of_birth_new <span class="hljs-built_in">date</span>,
    user_type_id_old <span class="hljs-built_in">int</span>,
    user_type_id_new <span class="hljs-built_in">int</span>,
    action_type <span class="hljs-built_in">varchar</span>(<span class="hljs-number">10</span>),
    action_time datetime2 <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    user_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">128</span>)
);

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TRIGGER</span> dbo.TR_U_Users_Audit 
<span class="hljs-keyword">on</span> dbo.Users
<span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">UPDATE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">SET</span> NOCOUNT <span class="hljs-keyword">ON</span>;

    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> dbo.users_log
        (users_id, first_name_old, first_name_new, last_name_old, last_name_new, date_of_birth_old, date_of_birth_new, user_type_id_old, user_type_id_new, action_type, action_time, user_name)
    <span class="hljs-keyword">SELECT</span> i.id, d.first_name <span class="hljs-keyword">as</span> first_name_old, i.first_name <span class="hljs-keyword">as</span> first_name_new, d.last_name <span class="hljs-keyword">as</span> last_name_old, i.last_name <span class="hljs-keyword">as</span> last_name_new, d.date_of_birth <span class="hljs-keyword">as</span> date_of_birth_old, i.date_of_birth <span class="hljs-keyword">as</span> date_of_birth_new, d.user_type_id <span class="hljs-keyword">as</span> user_type_id_old, i.user_type_id <span class="hljs-keyword">as</span> user_type_id_new,
    <span class="hljs-string">'Update'</span>, <span class="hljs-keyword">SYSUTCDATETIME</span>() action_time,
        SUSER_SNAME() <span class="hljs-keyword">AS</span> user_name 
    <span class="hljs-keyword">FROM</span> Inserted i
    <span class="hljs-keyword">FULL</span> <span class="hljs-keyword">JOIN</span> Deleted d
        <span class="hljs-keyword">ON</span> i.id = d.id;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>The above-created triggers' sole purpose is to insert records in Users_Audit Table, one for each UPDATE operation modifying the data in the Users table. It's simple and we can further modify it if we want to track any other details regarding it.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>;

<span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">SET</span> first_name = <span class="hljs-string">'Leaim'</span>, last_name = <span class="hljs-string">'Lantiffe'</span>, date_of_birth = <span class="hljs-string">'1994-01-13'</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;

<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> users_log;
</code></pre>
<p>With the above update operation, the old and the new data of the record are captured in the Users_Log Table. The Users_log Table contains both old and new data for the updated user_id 1. We have joined Inserted and Deleted pseudo tables in the triggers to get both the old and new data of the record. Let's understand INSERTED and DELETED pseudo tables more, so we can use them to write better triggers.</p>
<h2 id="heading-inserted-and-deleted-table">INSERTED and DELETED table.</h2>
<p>INSERTED and DELETED are special pseudo tables, available for the write operations. This pseudo table is available during the execution of DML events. Insert operation will have INSERTED table, Delete operation will have DELETED table, and Update operation will have both INSERTED and DELETED table. In the case of Insert operations, the INSERTED table will contain new values for each column in a table and the DELETED table will have no data. Similarly, for the Delete operation, the DELETED table will contain old values for each column in a table and the INSERTED table will have no data. And for the Update operation, the INSERTED table will contain new data for each column in a table and the DELETED table will contain old data. This construct makes it easier to identify the type of writing operation being conducted on a table. If both the INSERTED and DELETED table has data, then it was an Update Operation, if only the DELETED table didn't have any data then it's an Insert operation and if the INSERTED table didn't have any data then it's a Delete operation. This helps us in understanding why we had joined INSERTED and DELETED tables in the trigger written above for logging all update operations on the Users Table. Now we will see more examples for each DML operation with the 'AFTER' and 'INSTEAD OF' triggers.</p>
<p>For further examples, let's create two tables one containing the records of Invoices and the other containing the invoice line items for each invoice with minimum columns for the sake of simplicity.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> invoices;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> invoices(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    raised_date <span class="hljs-built_in">date</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    raised_by <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    customer_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    payment_date <span class="hljs-built_in">date</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    total_amount <span class="hljs-built_in">numeric</span>(<span class="hljs-number">12</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>),
    is_paid <span class="hljs-built_in">bit</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>)
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">71450.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">543020.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">514290.00</span>, <span class="hljs-number">0</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">10</span>, <span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">1233400.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">1951707.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">7</span>, <span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">39549.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">10</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">25500.00</span>, <span class="hljs-number">0</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">22950.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">9</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">818274.00</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoices (raised_date, raised_by, customer_id, payment_date, total_amount, is_paid) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">454338.00</span>, <span class="hljs-number">1</span>);

<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> invoice_lines;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> invoice_lines(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    invoice_id <span class="hljs-built_in">int</span>,
    product_id <span class="hljs-built_in">int</span>,
    unit_count <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>),
    unit_price <span class="hljs-built_in">numeric</span>(<span class="hljs-number">8</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> 
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">49</span>, <span class="hljs-number">7145</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-number">7145</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-number">1</span>, <span class="hljs-number">33</span>, <span class="hljs-number">7145</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-number">9</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-number">2</span>, <span class="hljs-number">7</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-number">3</span>, <span class="hljs-number">9</span>, <span class="hljs-number">39549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-number">10</span>, <span class="hljs-number">8227</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-number">4</span>, <span class="hljs-number">54</span>, <span class="hljs-number">4883</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-number">5</span>, <span class="hljs-number">41</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">70</span>, <span class="hljs-number">7347</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">8</span>, <span class="hljs-number">7</span>, <span class="hljs-number">18</span>, <span class="hljs-number">1275</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">27</span>, <span class="hljs-number">7145</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-number">2</span>, <span class="hljs-number">60</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-number">5</span>, <span class="hljs-number">13</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-number">4</span>, <span class="hljs-number">84</span>, <span class="hljs-number">4883</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-number">6</span>, <span class="hljs-number">67</span>, <span class="hljs-number">7347</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-number">8</span>, <span class="hljs-number">88</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-number">7</span>, <span class="hljs-number">64</span>, <span class="hljs-number">1275</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">7</span>, <span class="hljs-number">7</span>, <span class="hljs-number">20</span>, <span class="hljs-number">1275</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">10</span>, <span class="hljs-number">9</span>, <span class="hljs-number">18</span>, <span class="hljs-number">25241</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines (invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">39549</span>);

<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> products;
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> products(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> primary <span class="hljs-keyword">key</span>,
    item_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    item_description <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>),
    unit_price <span class="hljs-built_in">numeric</span>(<span class="hljs-number">8</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>)
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'Compactor'</span>, <span class="hljs-number">7145</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-string">'Crawler'</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-string">'Excavator'</span>, <span class="hljs-number">39549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">4</span>, <span class="hljs-string">'Scraper'</span>, <span class="hljs-number">4883</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">5</span>, <span class="hljs-string">'Grader'</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">6</span>, <span class="hljs-string">'Trencher'</span>, <span class="hljs-number">7347</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">7</span>, <span class="hljs-string">'Backhoe'</span>, <span class="hljs-number">1275</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">8</span>, <span class="hljs-string">'Dragline'</span>, <span class="hljs-number">9549</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">9</span>, <span class="hljs-string">'Dump Truck'</span>, <span class="hljs-number">25241</span>);

<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> product_approvals
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> product_approvals(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    product_id <span class="hljs-built_in">int</span>,
    item_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">50</span>),
    item_description <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>),
    unit_price <span class="hljs-built_in">numeric</span>(<span class="hljs-number">8</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>),
    is_approved <span class="hljs-built_in">bit</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>)
)
</code></pre>
<p>With our table and data set up as we wanted, let's do those few examples.</p>
<h2 id="heading-dml-trigger-examples">DML Trigger Examples</h2>
<h3 id="heading-for-insert-trigger">FOR Insert Trigger</h3>
<p>FOR Insert Trigger will be useful in cases where we want to set up some simple validation or check the existence of data before performing any operations. This Trigger can be used to run some t-SQL statements before the insert operation in the table. In our case of invoices and invoice_lines table, say we want to implement a rule that once the invoice is settled i.e. paid then new items can't be added to that invoice. The below snippet will help to create a trigger for the same.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TRIGGER</span> TR_F_I_invoice_lines_validate_invoice_id
<span class="hljs-keyword">ON</span> dbo.invoice_lines
<span class="hljs-keyword">FOR</span> <span class="hljs-keyword">INSERT</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> (<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices t1 <span class="hljs-keyword">JOIN</span> inserted i <span class="hljs-keyword">ON</span> t1.id = i.invoice_id <span class="hljs-keyword">WHERE</span> t1.is_paid = <span class="hljs-number">0</span>)
<span class="hljs-keyword">BEGIN</span>
    RAISERROR(<span class="hljs-string">'Invoice doesnt exists or is already paid. Hence cant be modified'</span>, <span class="hljs-number">16</span>, <span class="hljs-number">1</span>);
    <span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines(invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">7145.00</span>); <span class="hljs-comment">-- return error</span>

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines(invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">7145.00</span>); <span class="hljs-comment">-- perfrom the insert operation on invoice_lines table</span>
</code></pre>
<p>When we try to insert an invoice line item for invoice_id 2 it returns and rolls back with the error we have mentioned, but in the case of invoice_id = 3, it passes this validation since invoice_id 3 is not paid yet and it also exists in the invoices table.</p>
<h3 id="heading-after-insert-trigger">AFTER Insert Trigger</h3>
<p>AFTER Insert Trigger will be useful where we want to execute some T-SQL code after each insertion we have done in that table. Suppose, in our example case, we want to calculate the total amount each time an invoice item is added to the invoice_lines table, one way to do this is to update the invoice total_amount every time a new item is added to the invoice_lines table for that invoice. This is can be done with the 'AFTER Insert trigger' as with the insert operation done in the invoice_line table, we will update the total_amount value in the invoices tables.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_A_I_invoice_lines_update_invoice_total_amount
<span class="hljs-keyword">ON</span> dbo.invoice_lines
<span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">INSERT</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">UPDATE</span> t1
        <span class="hljs-keyword">SET</span> t1.total_amount = t1.total_amount + (t2.unit_price * t2.unit_count)
    <span class="hljs-keyword">FROM</span> invoices t1
    <span class="hljs-keyword">JOIN</span> inserted t2
        <span class="hljs-keyword">ON</span> t1.id = t2.invoice_id;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>The above code snippet is an AFTER INSERT trigger, wherein we update the total_amount value of the invoice table in case of the new addition of the invoice_items. The below code will show you the example. It updates the total_amount column in the invoices table when that invoice is unpaid, but if it's paid invoice and we try to add new items for it invoice_items table, then it returns with the error from the previous validation trigger we made.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> 
    *
<span class="hljs-keyword">FROM</span> invoices i
<span class="hljs-keyword">JOIN</span> invoice_lines il
    <span class="hljs-keyword">ON</span> i.id = il.invoice_id
<span class="hljs-keyword">WHERE</span> i.id = <span class="hljs-number">3</span>;

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines(invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4883.00</span>);
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> invoice_lines(invoice_id, product_id, unit_count, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">9549.00</span>);

<span class="hljs-keyword">SELECT</span> 
    *
<span class="hljs-keyword">FROM</span> invoices i
<span class="hljs-keyword">JOIN</span> invoice_lines il
    <span class="hljs-keyword">ON</span> i.id = il.invoice_id
<span class="hljs-keyword">WHERE</span> i.id = <span class="hljs-number">3</span>;
</code></pre>
<h3 id="heading-instead-of-insert-trigger">INSTEAD OF Insert Trigger</h3>
<p>Now, we will see a working example for the usage of INSTEAD OF Insert Trigger. It can be helpful in cases where we want to replace the insert operation with some other T-SQL code and execute that code. It mostly is used with views, which is acting as an interface on top of one or multiple table objects for the application server. In our case, we will be using it to change the flow of how the products are added to our catalog i.e. products table. Let's say earlier the company used to directly add the products which they wants to sell directly in the products table. But recently the company has decided to implement an approval process for the products. For every new product being added, it will have to be approved by the company to appear in the products section. In such a scenario we can use INSTEAD OF Insert Trigger to replace the product insert operation in the products table to prdoucts_approvals table. Let's see the trigger for the same.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_IN_instead_products_insert_in_product_approvals
<span class="hljs-keyword">ON</span> dbo.products
INSTEAD <span class="hljs-keyword">OF</span> <span class="hljs-keyword">INSERT</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> product_approvals(product_id, item_name, item_description, unit_price) 
    <span class="hljs-keyword">SELECT</span> i.id, i.item_name, i.item_description, i.unit_price <span class="hljs-keyword">FROM</span> Inserted i;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>The above trigger definition replaces the insert operation in the products table with the product_approvals table. This way the change in the company product approval process can be altered. Let's try to perform some insert operations.</p>
<pre><code class="lang-sql"><span class="hljs-comment">--select * from products;</span>
<span class="hljs-comment">--select * from product_approvals;</span>

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products(<span class="hljs-keyword">id</span>, item_name, item_description, unit_price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">10</span>, <span class="hljs-string">'Pavement Blocks'</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-number">500.78</span>);

<span class="hljs-comment">--select * from products;</span>
<span class="hljs-comment">--select * from product_approvals;</span>
</code></pre>
<p>With the above example, we can see that the insert operation on the products table is replaced by the product_approvals table. Next, we will be seeing examples of the update operations.</p>
<h3 id="heading-for-update-trigger">FOR Update Trigger</h3>
<p>It is similar to the 'FOR Insert Trigger' we had seen before, but for the update operations. We can have a small validation check or some other T-SQL code executed for each update operation. Earlier in the 'FOR INSERT Trigger' part we created a trigger for validating if the invoice is settled or not and if the invoice is settled, then no new items can be added to that invoice. This trigger won't work in the case of the Update operation of the invoice_lines table. We can test it by updating the invoice_lines table for the invoice_id is 2 and invoice_line_id is 12, even if invoice_id 2 is a paid invoice.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">2</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">2</span>

<span class="hljs-keyword">UPDATE</span> invoice_lines <span class="hljs-keyword">SET</span> unit_count = unit_count + <span class="hljs-number">1</span> <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">12</span>;

<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">2</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">2</span>
</code></pre>
<p>Let's prevent this update operation on the invoice_lines table when the invoice is paid and settled. '</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TRIGGER</span> TR_F_U_invoice_lines_validate_for_invoice_id
<span class="hljs-keyword">ON</span> dbo.invoice_lines
<span class="hljs-keyword">FOR</span> <span class="hljs-keyword">UPDATE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span>(<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices t1 <span class="hljs-keyword">JOIN</span> inserted i <span class="hljs-keyword">ON</span> t1.id = i.invoice_id <span class="hljs-keyword">WHERE</span> t1.is_paid = <span class="hljs-number">0</span>)
<span class="hljs-keyword">BEGIN</span>
    RAISERROR(<span class="hljs-string">'Invoice doesnt exists or is already paid. Hence cant e modified'</span>, <span class="hljs-number">16</span>, <span class="hljs-number">1</span>);
    <span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>After creating FOR Update Trigger on the invoice_lines table, let's again try to update the invoice_lines table where the id is 12 and invoice_id is 2. It will return with an error we mentioned in trigger and rollback since the invoice which we were updating was already a settled invoice, but it successfully updates in the case of invoice id 3 as it is the unpaid invoice. You can try with the below SQL snippet.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">2</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">2</span>

<span class="hljs-keyword">UPDATE</span> invoice_lines <span class="hljs-keyword">SET</span> unit_count = unit_count + <span class="hljs-number">1</span> <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">12</span>;

<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">2</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">2</span>
</code></pre>
<p>Next, we will see is AFTER Update Trigger;</p>
<h3 id="heading-after-update-trigger">AFTER Update Trigger</h3>
<p>AFTER Update trigger fires and execute the trigger content when the update operation is completed. Note that if the trigger fails, then the update operation also fails. Earlier in 'FOR Update Trigger', we made a trigger to block the updates of the invoices which are already settled, and not of unpaid invoices. Since the unpaid invoices represent that the customer is still in process of shortlisting the items he wants to purchase, we should be able to show the updated total amount of the invoice, every time he updates his invoice items.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_A_U_invoice_lines_update_invoice_total_amount
<span class="hljs-keyword">ON</span> dbo.invoice_lines
<span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">UPDATE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">UPDATE</span> t1
        <span class="hljs-keyword">SET</span> t1.total_amount = t1.total_amount + ((t2.unit_count - t3.unit_count) * t2.unit_price)
    <span class="hljs-keyword">FROM</span> invoices t1
    <span class="hljs-keyword">JOIN</span> inserted t2
        <span class="hljs-keyword">ON</span> t1.id = t2.invoice_id
    <span class="hljs-keyword">JOIN</span> deleted t3
        <span class="hljs-keyword">ON</span> t2.id = t3.id
        ;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>With the trigger above, every time the invoice_lines table is modified or altered for the invoice id which is not been paid yet, the total amount column in the invoices table will be updated to reflect the new amount.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">3</span>;
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">3</span>;

<span class="hljs-keyword">UPDATE</span> invoice_lines <span class="hljs-keyword">SET</span> unit_count = unit_count + <span class="hljs-number">1</span> <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">3</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">10</span>;

<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">3</span>;
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">3</span>;
</code></pre>
<p>With every update operation in the invoice_lines table, we update the total amount value in the invoices table, having a column named total_amount.</p>
<h3 id="heading-instead-of-update-trigger">INSTEAD OF Update Trigger</h3>
<p>Similar to INSTEAD OF Insert Trigger, this trigger can be used for a view referencing two or more tables. INSTEAD OF Update Trigger can be used when we want to perform something else instead of the update operation on that table. Let's continue with our example. Earlier we implemented a product_approvals table wherein any new products will have to be approved first by the company before making them available for sale. Similarly, now the company wants to add another flow to it. The change in the price of the product should also be approved by the company before begin passed down to new customers. Let's make a Trigger for that case.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_IN_products_price_update_needs_product_approvals
<span class="hljs-keyword">ON</span> dbo.products
INSTEAD <span class="hljs-keyword">OF</span> <span class="hljs-keyword">UPDATE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> product_approvals(product_id, item_name, item_description, unit_price)
    <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, item_name, item_description, unit_price <span class="hljs-keyword">FROM</span> inserted
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>When someone tries to update the price of the product, the trigger will instead execute its content. It will insert data in the product_approvals table for that product_id with new column values and set the is_approved flag 0. So it will be reflected on the approvals page and once approved then the changes can be reflected in the products table.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> products <span class="hljs-keyword">SET</span> unit_price = <span class="hljs-number">7545</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;
</code></pre>
<p>The above update query operation will instead execute the trigger content we created replacing it with inserting the modified row data in the product_approvals table. Now we will be exploring triggers for the DML Delete operation.</p>
<h3 id="heading-for-delete-trigger">FOR Delete Trigger</h3>
<p>Similar to FOR Insert Trigger and FOR Update Trigger, FOR delete trigger can be used to perform simple validation before the delete operation, or for some other code execution before the delete operation. Here let's say, before deleting the product from the products table, we have to make sure that there are no pending invoices that have those products in its invoice item list. If the product is in the list then, we have to return an error with a reason for the failed delete operation.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_F_D_product_delete_validate_with_invoice_lines
<span class="hljs-keyword">ON</span> dbo.products
<span class="hljs-keyword">FOR</span> <span class="hljs-keyword">DELETE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span>(
    <span class="hljs-keyword">SELECT</span> * 
    <span class="hljs-keyword">FROM</span> invoice_lines il 
    <span class="hljs-keyword">JOIN</span> invoices i
        <span class="hljs-keyword">ON</span> i.id = il.invoice_id
    <span class="hljs-keyword">JOIN</span> deleted d 
        <span class="hljs-keyword">ON</span> il.product_id = d.id <span class="hljs-keyword">WHERE</span> i.is_paid = <span class="hljs-number">0</span>)
<span class="hljs-keyword">BEGIN</span>
    RAISERROR(<span class="hljs-string">'Product is added in unsettled invoice bill. cant delete at this instance. Try later.'</span>, <span class="hljs-number">16</span>, <span class="hljs-number">1</span>);
    <span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>

<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">6</span>; <span class="hljs-comment">-- return error</span>

<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>; <span class="hljs-comment">-- success</span>
</code></pre>
<p>This trigger prevents the deletion of the product which is in the invoice and hasn't yet been settled. Similarly, you can also use FOR DELETE Trigger to validate the delete operation of the already paid invoice.</p>
<h3 id="heading-after-delete-trigger">AFTER Delete Trigger</h3>
<p>The AFTER Delete Trigger is used to perform operations when the delete operation is executed. Continuing with our example, let's write a trigger for the case where the invoice item of an unpaid invoice is deleted, then the total amount of that invoice should get updated as well.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_A_D_invoice_lines_update_invoice_total_amount
<span class="hljs-keyword">ON</span> dbo.invoice_lines
<span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">DELETE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-comment">-- select * from deleted;</span>
    <span class="hljs-keyword">UPDATE</span> t1
        <span class="hljs-keyword">SET</span> t1.total_amount = t1.total_amount - (t2.unit_price * t2.unit_count)
    <span class="hljs-keyword">FROM</span> invoices t1
    <span class="hljs-keyword">JOIN</span> deleted t2
        <span class="hljs-keyword">ON</span> t1.id = t2.invoice_id;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>This trigger updates the total amount of the invoice once the invoice item is deleted. With this, we see the usage of the AFTER Delete trigger. Run the below SQL code to see them working.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">3</span>;
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">3</span>;

<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">23</span>;

<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">3</span>;
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> invoice_lines <span class="hljs-keyword">WHERE</span> invoice_id = <span class="hljs-number">3</span>;
</code></pre>
<h3 id="heading-instead-of-delete-trigger">INSTEAD OF Delete Trigger</h3>
<p>Continuing our example further, we want to prevent the delete operation on invoices that are already settled and instead return an error. This works similarly to the INSTEAD OF Insert Trigger and INSTEAD OF Update Trigger. Below is the Trigger definition, which prevents the delete operation and returns an error.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TRIGGER</span> TR_IN_paid_invoice_cant_be_deleted
<span class="hljs-keyword">ON</span> dbo.invoices
INSTEAD <span class="hljs-keyword">OF</span> <span class="hljs-keyword">DELETE</span>
<span class="hljs-keyword">AS</span>
<span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span>(
    <span class="hljs-keyword">SELECT</span> * 
    <span class="hljs-keyword">FROM</span> invoices i 
    <span class="hljs-keyword">JOIN</span> deleted
        <span class="hljs-keyword">ON</span> i.id = deleted.id
    <span class="hljs-keyword">WHERE</span> i.is_paid = <span class="hljs-number">1</span>
    )
<span class="hljs-keyword">BEGIN</span>
    RAISERROR(<span class="hljs-string">'You cant delete an paid invoice.'</span>, <span class="hljs-number">16</span>, <span class="hljs-number">1</span>);
    <span class="hljs-keyword">ROLLBACK</span> <span class="hljs-keyword">TRANSACTION</span>;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">ELSE</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">DELETE</span>
        i
    <span class="hljs-keyword">FROM</span> invoices i
    <span class="hljs-keyword">JOIN</span> deleted d
        <span class="hljs-keyword">ON</span> i.id = d.id
    <span class="hljs-keyword">WHERE</span> i.is_paid = <span class="hljs-number">0</span>;
<span class="hljs-keyword">END</span>
<span class="hljs-keyword">GO</span>
</code></pre>
<p>In the trigger defined above when the delete operation is executed for the invoices table, we just verify if the invoice we are deleting is already a paid invoice or not. If it's a paid invoice then we prevented the delete operation and instead returned with the error, but if the invoice is unpaid then we can delete that invoice. The below statements help us to verify if the trigger created earlier is working as expected or not.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;

<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> invoices <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">7</span>;

<span class="hljs-comment">-- select * from invoices</span>
</code></pre>
<p>This completes our little post regarding the Trigger and its example for all the DML events. In the upcoming post, related to Trigger, we will see how Trigger can be used for multiple or combined DML events like using Trigger to Log Table Data Changes, Nested and Recursive Triggers and DDL Triggers with Events to track database alteration and its example trying to log database changes.</p>
]]></content:encoded></item><item><title><![CDATA[Find the overlapping date or time range in SQL Server]]></title><description><![CDATA[Recently I was working on a project, where the company wanted to track and manage all its assets and infrastructure in multiple locations. The tracking and management were done for all the types of assets including rooms, cubicles, and cabins trackin...]]></description><link>https://mssqlserver.dev/find-the-overlapping-date-or-time-range-in-sql-server</link><guid isPermaLink="true">https://mssqlserver.dev/find-the-overlapping-date-or-time-range-in-sql-server</guid><category><![CDATA[SQL Server]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[MySQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Thu, 17 Mar 2022 05:39:03 GMT</pubDate><content:encoded><![CDATA[<p>Recently I was working on a project, where the company wanted to track and manage all its assets and infrastructure in multiple locations. The tracking and management were done for all the types of assets including rooms, cubicles, and cabins tracking for the full current financial year. They also had a provision wherein the employee or any other person having access to the portal can request asset booking for a particular date and time range. This was to be approved by the respective asset manager on the request received. However, if the requested asset is already booked by some other uses for the same date-time range or in the conflicting date-time range then, the application should show an error when accepting and validating the user's request. Let's tone down the above case for a simple illustration. We have a room which we want to rent out, The room can be rented for a maximum of a week. So let's create a room_series table to track a room for the week with 5 min granularity. Since our booking times are rounded off to the nearest 5 min.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> room_series
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> room_series(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    <span class="hljs-keyword">day</span> <span class="hljs-built_in">int</span>,
    start_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    end_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    time_id <span class="hljs-built_in">int</span>,
    room_id <span class="hljs-built_in">int</span>,
    is_booked <span class="hljs-built_in">bit</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">default</span>(<span class="hljs-number">0</span>)
);

<span class="hljs-keyword">with</span> weeks (<span class="hljs-keyword">day</span>) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>
    <span class="hljs-keyword">select</span> <span class="hljs-keyword">day</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">from</span> weeks
    <span class="hljs-keyword">where</span> <span class="hljs-keyword">day</span> &lt; <span class="hljs-number">7</span>
), five_min_series (start_time, end_time, time_id) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> <span class="hljs-keyword">cast</span> (<span class="hljs-string">'00:00:00'</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> start_time, <span class="hljs-keyword">cast</span> (<span class="hljs-string">'00:05:00'</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> end_time, <span class="hljs-number">1</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">level</span>
    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span> 
    <span class="hljs-keyword">select</span>
        <span class="hljs-keyword">cast</span>(<span class="hljs-keyword">DATEADD</span>(mi, <span class="hljs-number">5</span>, start_time) <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> start_time,
        <span class="hljs-keyword">cast</span>(<span class="hljs-keyword">DATEADD</span>(mi, <span class="hljs-number">5</span>, end_time) <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> end_time,
        time_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">from</span> five_min_series t1
    <span class="hljs-keyword">where</span> time_id &lt; <span class="hljs-number">288</span> <span class="hljs-comment">-- their are 288 block of 5 munities in a 24 hrs.</span>
), rooms (room_id) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>
    <span class="hljs-keyword">select</span> room_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">from</span> rooms <span class="hljs-keyword">where</span> room_id &lt; <span class="hljs-number">2</span>
)
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> room_series (<span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id) 
<span class="hljs-keyword">select</span> <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id <span class="hljs-keyword">from</span> weeks, five_min_series, rooms
 <span class="hljs-keyword">option</span>(maxrecursion <span class="hljs-number">0</span>); <span class="hljs-comment">-- populating records in room_series table</span>

 <span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> room_series <span class="hljs-comment">-- 4032 records</span>
</code></pre>
<p>We have created a room_series table that holds records for rooms number 1 and 2 for the 7 days of the week with 5 min granularity. This room_series table contains a column for day reference for a day of the week, start_time, end_time, time_id, and room_id reference for the room number, and the is_booked column default is 0, meaning the particular room_series is not booked and is available for booking or renting as in our case. Now to simulate the situation of finding or validating the request for room booking for a particular day and for a particular time. let's consider that someone has already reserved room number 1 for day 2 and for a start time '08:00:00' am till the end time '16:30:00' pm, we need to simulate this with the below update statement.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">update</span> room_series <span class="hljs-keyword">set</span> is_booked = <span class="hljs-number">1</span> <span class="hljs-keyword">where</span> room_id = <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">day</span> = <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> start_time &gt;= <span class="hljs-string">'08:00:00'</span> <span class="hljs-keyword">and</span> end_time &lt;= <span class="hljs-string">'16:30:00'</span>;
</code></pre>
<p>Room number 1 is booked or reserved by someone for day 2 and for the time between '08:00:00' and '16:30:00'. Now suppose, we received the asset booking request for room number 1 for the same day i.e day number 2, and was requested for the time between '16:00:00' pm till '21:00:00' pm. With the new request received the request, we need to find that whether his request is overlapping with any other already approved requests. We know that the new request is already overlapping with the booked request for the time frame of '16:00:00' till '16:30:00' pm, due to this half-hour overlap we have to show the user that his request is overlapping/ conflicting and hence canceled. There are 4 cases where we can say that the overlap can occur and they are partial overlap either at the beginning or at the end, complete overlap, and complete within limits, let's consider these scenarios with our illustration, and also for simplicity lets consider the booked room timing as EventA and request for room booking as EventB.</p>
<ol>
<li><p>When EventB start_time is less than EventA start_time and EventB end_time is greater than or equal to EventA start_time. Essentially when EventB starts before EventA but also ends before EventA. It's a case of partial overlap for the beginning part.</p>
</li>
<li><p>When EventB start_time is greater than or equal to EventA start_time AND EventB end_time is less than or equal to EventA end_time. meaning EventB starts at the same time or after EventA starts AND EventB ends before or at the same time as EventA. A case of complete overlap.</p>
</li>
<li><p>Similar to case 2 when EventB starts after EventA AND ends before EventA, where the EventB is completely contained within the boundaries of EventA.</p>
</li>
<li><p>When EventB start_time is less than or equal to EventA end_time AND EventB end_time is greater than EventA end_time. It means EventB starts before or at the same time as the end of EventA AND EventB ends after EventA. It's a case of partial overlap for the ending part.</p>
</li>
</ol>
<p>But for checking if there is any overlap occurrence, we need to keep in mind two cases.</p>
<ol>
<li><p>EventB end_time is greater than or equal to EventA start_time.</p>
</li>
<li><p>EventB start_time is less than or equal to EventA end_time. Let's check it in our case with the below query</p>
</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span> @eventB_start_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>) = <span class="hljs-string">'16:00:00'</span> , @eventB_end_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>) = <span class="hljs-string">'21:00:00'</span>;
<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> room_series <span class="hljs-keyword">where</span> <span class="hljs-keyword">day</span> = <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> room_id = <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> start_time &lt;= @eventB_end_time <span class="hljs-keyword">and</span> end_time &gt;= @eventB_start_time <span class="hljs-keyword">and</span> is_booked = <span class="hljs-number">1</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648618723117/UEUdCkUN9.PNG" alt="sql server find overlapping rows.PNG" /></p>
<p>The above result set shows the overlapping or conflicting rows between EventA and EventB. In our case, we knew that there is an overlapping time range from '16:00:00' pm till '16:30:00' pm as eventA is already booked for that time range and eventB also includes that time range in its request for booking, for the same day and the same room number. Note we can adjust the comparison operator as per our requirement in the query. To further optimize, if we don't want to return overlapping rows and show them to the user and only want to check if the user request is overlapping or not. We can use the 'Where NOT EXISTS' clause and the inner query returning the overlapping rows. Below is the snippet.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span> @eventB_start_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>) = <span class="hljs-string">'16:00:00'</span> , @eventB_end_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>) = <span class="hljs-string">'21:00:00'</span>;
<span class="hljs-keyword">select</span> <span class="hljs-number">1</span> <span class="hljs-keyword">as</span> is_overlapped
<span class="hljs-keyword">where</span> <span class="hljs-keyword">exists</span> 
(
    <span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> room_series <span class="hljs-keyword">where</span> <span class="hljs-keyword">day</span> = <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> room_id = <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> start_time &lt;= @eventB_end_time <span class="hljs-keyword">and</span> end_time &gt;= @eventB_start_time <span class="hljs-keyword">and</span> is_booked = <span class="hljs-number">1</span>
);
</code></pre>
<p>With this, we return the flag in case we get the overlapping rows between the date or time range as per our requirement.</p>
]]></content:encoded></item><item><title><![CDATA[SQL Join on NULL column value]]></title><description><![CDATA[It happens many times that, while designing the table structure, we allow NULL for some of the columns and then later on we get the need to perform the join on Null column values to retrieve the required result-set. One example to think of is the sal...]]></description><link>https://mssqlserver.dev/join-on-null-column-values-in-sql</link><guid isPermaLink="true">https://mssqlserver.dev/join-on-null-column-values-in-sql</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[MSSQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Tue, 15 Mar 2022 14:57:08 GMT</pubDate><content:encoded><![CDATA[<p>It happens many times that, while designing the table structure, we allow NULL for some of the columns and then later on we get the need to perform the join on Null column values to retrieve the required result-set. One example to think of is the sales table and branch table. In the branch table, we have records of the branches of the company with their name, branch number, and branch location. And in the sales table, each of the sales records is maintained along with the branch number which made the sales. But some orders in the orders table have NULL values in the branch_number column, and similarly, some rows of the branch table have branch_number values as NULL. The below script creates the table and inserts the data for further illustrations.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> branch
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> branch(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span>,
    branch_number <span class="hljs-built_in">int</span> ,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    location <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
);
<span class="hljs-keyword">create</span>  nonclustered <span class="hljs-keyword">index</span> IX_branch_branch_number  
  <span class="hljs-keyword">on</span> dbo.branch (branch_number, <span class="hljs-keyword">name</span>, location); 

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> sales
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> sales(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> primary <span class="hljs-keyword">key</span>,
    sales_date <span class="hljs-built_in">date</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    total_amount <span class="hljs-built_in">decimal</span>(<span class="hljs-number">10</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    customer_id <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    branch_number <span class="hljs-built_in">int</span> <span class="hljs-comment">-- we permitted null values</span>
);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> branch (<span class="hljs-keyword">id</span>, branch_number, <span class="hljs-keyword">name</span>, location) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">101</span>, <span class="hljs-string">'Douglas-Block'</span>, <span class="hljs-string">'Dengyue'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> branch (<span class="hljs-keyword">id</span>, branch_number, <span class="hljs-keyword">name</span>, location) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">102</span>, <span class="hljs-string">'Veum-Jones'</span>, <span class="hljs-string">'Coyah'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> branch (<span class="hljs-keyword">id</span>, branch_number, <span class="hljs-keyword">name</span>, location) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-string">'Hansen and Sons'</span>, <span class="hljs-string">'Halimpu'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> branch (<span class="hljs-keyword">id</span>, branch_number, <span class="hljs-keyword">name</span>, location) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">104</span>, <span class="hljs-string">'Braun-Kemmer'</span>, <span class="hljs-string">'Saint Louis'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> branch (<span class="hljs-keyword">id</span>, branch_number, <span class="hljs-keyword">name</span>, location) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-number">105</span>, <span class="hljs-string">'Beatty, Bernhard and Schmitt'</span>, <span class="hljs-string">'Dalmacio Vélez Sársfield'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> branch (<span class="hljs-keyword">id</span>, branch_number, <span class="hljs-keyword">name</span>, location) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">106</span>, <span class="hljs-string">'Kub, Zboncak and Berge'</span>, <span class="hljs-string">'Plyussa'</span>);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'2021-03-06'</span>, <span class="hljs-number">9103.52</span>, <span class="hljs-number">7</span>, <span class="hljs-number">101</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">6513.04</span>, <span class="hljs-number">6</span>, <span class="hljs-number">101</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-string">'2021-03-04'</span>, <span class="hljs-number">5018.44</span>, <span class="hljs-number">8</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-string">'2021-03-05'</span>, <span class="hljs-number">12187.21</span>, <span class="hljs-number">1</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">8951.13</span>, <span class="hljs-number">8</span>, <span class="hljs-number">102</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-string">'2021-03-04'</span>, <span class="hljs-number">2109.0</span>, <span class="hljs-number">8</span>, <span class="hljs-number">105</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-string">'2021-03-05'</span>, <span class="hljs-number">4745.6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">104</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-string">'2021-03-05'</span>, <span class="hljs-number">5326.41</span>, <span class="hljs-number">7</span>, <span class="hljs-number">106</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-string">'2021-03-08'</span>, <span class="hljs-number">3672.56</span>, <span class="hljs-number">5</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-string">'2021-03-04'</span>, <span class="hljs-number">4038.51</span>, <span class="hljs-number">7</span>, <span class="hljs-number">103</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-string">'2021-03-04'</span>, <span class="hljs-number">11874.09</span>, <span class="hljs-number">5</span>, <span class="hljs-number">104</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-string">'2021-03-07'</span>, <span class="hljs-number">8632.73</span>, <span class="hljs-number">6</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">14909.73</span>, <span class="hljs-number">5</span>, <span class="hljs-number">102</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">4014.49</span>, <span class="hljs-number">7</span>, <span class="hljs-number">105</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> sales (<span class="hljs-keyword">id</span>, sales_date, total_amount, customer_id, branch_number) <span class="hljs-keyword">values</span> (<span class="hljs-number">15</span>, <span class="hljs-string">'2021-03-04'</span>, <span class="hljs-number">6320.8</span>, <span class="hljs-number">2.3</span>, <span class="hljs-number">106</span>);
</code></pre>
<p>Now if we wanted to see the branch details for each sale in the sales table, we need to perform an inner join on both the sales and branch tables.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> sales;
<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> branch;

<span class="hljs-keyword">select</span> 
    s.id <span class="hljs-keyword">as</span> sales_id,
    s.sales_date,
    s.total_amount,
    s.customer_id,
    b.name <span class="hljs-keyword">as</span> branch_name,
    b.branch_number,
    b.location
<span class="hljs-keyword">from</span> sales s
<span class="hljs-keyword">join</span> branch b
    <span class="hljs-keyword">on</span> s.branch_number = b.branch_number;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648392964045/53LixnDXO.PNG" alt="joining on null columns doesnt return rows having null values.PNG" /></p>
<p>The above image showing the result set of the query doesn't have any data regarding order IDs 3, 4, 9, and 12 as all of these ids have null values. There are ways to join on NULL values, one of which is making those columns NOT NULL and adding default values to them. But what if, we don't have access or permission to change the table structure in the database? We had to make it a workout with what we had.</p>
<h2 id="heading-using-isnull-or-coalesce-function">Using ISNULL OR COALESCE function:</h2>
<p>If we cant alter the table structure of the database, then we have to convert those NULL to NON-NULL values using a function like ISNULL or COALESCE. ISNULL function takes two parameters, first is the value of the expression we want to check if it's NULL or NON-NULL and if it's NULL, then it returns the second value we provided for the NULL. While COALESCE returns the first NON-NULL value in the list provided.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">ISNULL</span>(<span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-number">0</span>);
<span class="hljs-keyword">select</span> <span class="hljs-keyword">COALESCE</span>(<span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>, <span class="hljs-number">1</span>);
</code></pre>
<p>The first statement using the ISNULL function returns 0 and the second statement returns 1. Now let's again perform the join operation with the help of these functions for the null column values and see if we get the expected output.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> 
    s.id <span class="hljs-keyword">as</span> sales_id,
    s.sales_date,
    s.total_amount,
    s.customer_id,
    b.name <span class="hljs-keyword">as</span> branch_name,
    b.branch_number,
    b.location
<span class="hljs-keyword">from</span> sales s
<span class="hljs-keyword">join</span> branch b
    <span class="hljs-keyword">on</span> <span class="hljs-keyword">ISNULL</span>(s.branch_number, <span class="hljs-number">0</span>) = <span class="hljs-keyword">ISNULL</span>(b.branch_number, <span class="hljs-number">0</span>);

<span class="hljs-comment">-- using coalesce</span>
<span class="hljs-keyword">select</span> 
    s.id <span class="hljs-keyword">as</span> sales_id,
    s.sales_date,
    s.total_amount,
    s.customer_id,
    b.name <span class="hljs-keyword">as</span> branch_name,
    b.branch_number,
    b.location
<span class="hljs-keyword">from</span> sales s
<span class="hljs-keyword">join</span> branch b
    <span class="hljs-keyword">on</span> <span class="hljs-keyword">COALESCE</span>(s.branch_number, <span class="hljs-number">0</span>) = <span class="hljs-keyword">COALESCE</span>(b.branch_number, <span class="hljs-number">0</span>);
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648392993427/Sg3ekisPb.PNG" alt="joining on null column values using coalesce or isnull function.PNG" /></p>
<p>With the above image, we can see that both statements have returned the required result-set as we wanted. But We have used COALESCE or ISNULL function to get our results. This usage of the function on joining column disables the use of indexes in some databases it does disables index seek. And with a heavy increase in the data set of these tables, the computation cost will rise and will have a performance hit due to computing scaler operation. we can see the flow in the execution plan.</p>
<h2 id="heading-using-or-and-is-null-operator">Using OR and IS NULL operator</h2>
<p>The below query returns the same result set as the above queries and doesn't add extra computation cost and also enables the index to seek for us on the branch table. While creating the branch table before in the first SQL Snippet, we mentioned branch table columns in the non-clustered index we created.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span>
    s.id <span class="hljs-keyword">as</span> sales_id,
    s.sales_date,
    s.total_amount,
    s.customer_id,
    b.name <span class="hljs-keyword">as</span> branch_name,
    b.branch_number,
    b.location
<span class="hljs-keyword">from</span> sales s
<span class="hljs-keyword">join</span> branch b
    <span class="hljs-keyword">on</span> (s.branch_number = b.branch_number <span class="hljs-keyword">OR</span> (s.branch_number <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">and</span> b.branch_number <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>));
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648393015986/B3jbTEsK-.PNG" alt="joining on null column values using OR and IS NULL Operator.PNG" /></p>
<p>The above query doesn't use any function like the previous two statements above and the left side of the operands mentioning column name is as it is, so it can take the advantage of the indexes. In the above query statement, our branch table performs an index seek retrieval operation. The above approach avoids extra computations and is also performance-friendly for large recordsets. The queries which can take the advantage of the indexes play an important role where the dataset is large and performance is very important.</p>
]]></content:encoded></item><item><title><![CDATA[Clustered Table and Heap Table in SQL Server]]></title><description><![CDATA[In this post, we will be exploring the meaning of clustered tables and heap tables along with their working and logical structures. I will also be sharing my understanding of them and their scenarios. This understanding helps us to make better querie...]]></description><link>https://mssqlserver.dev/clustered-table-and-heap-table-in-sql-server</link><guid isPermaLink="true">https://mssqlserver.dev/clustered-table-and-heap-table-in-sql-server</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[#SQLtutorial ]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Fri, 11 Mar 2022 05:19:20 GMT</pubDate><content:encoded><![CDATA[<p>In this post, we will be exploring the meaning of clustered tables and heap tables along with their working and logical structures. I will also be sharing my understanding of them and their scenarios. This understanding helps us to make better queries and affects the performance of the queries. To understand the logical structuring or arrangement of a heap table or clustered table, we need to understand what a page is and what is meant by IAM (Index Allocation Map) page and IAM chains.</p>
<p>A Page is a basic unit of data storage in SQL Server and the data files are fully comprised of pages numbered consecutively from 1 to n. The read-write operations that we execute or perform are all made on these pages and they are of various types. An IAM page is a type of page that stores information about the extent (manage space) used by the table or index allocation. It tracks approximately 4GB worth of space in a single file. If a file is more than 4GB or has multiple data file entities, then we need multiple IAM pages to track all the space usage. As some entity requires multiple IAM pages to track their space usage, these IAM pages are linked together and are called IAM chains.</p>
<h2 id="heading-heap-tables">Heap Tables:</h2>
<p>In a literal sense, it can be defined as an unordered and unstructured collection of objects placed on top of each other like a pile of books, where books are placed on top of each other without any ordering or anything. Similarly, heap tables are table that holds records or rows without any ordering or any structuring. Since it's just a pile of rows then to find any particular row or record in a table, requires us to perform a scan of rows till we find what we were looking for. This scanning of rows for finding a record in a heap table is known as TableScan Operation. Think of looking for a particular book in a pile of unordered and unstructured books placed on top of each other. And again do note that data order is unpredictable and not guaranteed to retain order. We can add non-clustered indexes to the heap table to speed up the data retrieval process for finding a row. Since the ordering of rows (underlying pages) is absent, heap tables are suitable for heavy data insertions or bulk records. It will just allocate a page and write the data in it and put the page with other pages.</p>
<p>Now with the understanding of the page and IAM page given above, it will be simpler to visualize and understand the logical structuring of the heap table. The heap table is comprised of IAM pages and these IAM pages that are used to manage space allocated to the heap also helps SQL Server to traverse through the heap. The Data Pages and rows within them are not in any specific order and these data pages are not linked to each other. The only connection between these data pages is their information recorded on IAM pages. All reads and writes must contact the IAM first to read all pages within a heap.</p>
<p>Due to the absence of innate ordering or structuring of the pages or data in the heap table, it is suitable for the scenario where heavy insertion activity is required. Each Individual row in the heap table is identified by row identifier (RID). For large unordered insertions, the heap is preferred as we don't need any particular ordering. Thus, insertions in the heap table are generally faster compared to the same insertion in the clustered table. And as discussed earlier, if a heap table does not have any unclustered indexes, then an entire table scan is required to find any row or record.</p>
<p>If we need the data in a particular sorted order frequently, then it is better to not use heap and then sort row sets on return with ORDER BY clause. A Heap table is also not advisable where data grouping or querying for data ranges is frequently made. If a large table without any non-clustered indexes is needed to be queried with or without any particular sorting, grouping, or order condition, in that case, it is suitable to not use a heap. For Frequent data updates, the heap table is not suitable.</p>
<h2 id="heading-clustered-table">Clustered Table</h2>
<p>It is an ordered and structured collection of objects. The Clustered index provides underlying ordering and structuring of the data set in the table. The columns for the ordering can be defined at the time of table creation as Primary Key or by defining a clustered index on an existing heap table. To use the earlier example of a pile of books, this can be said as a set of ordered books arranged in either ascending or descending order based on the name of the book or author's name or publish date or combinations of it. As this is an ordered set of books, then finding any particular book requires us to perform seek operation and locate the required book we were finding.</p>
<p>In the clustered table the record is stored in a Binary Tree structure (B-Tree), wherein the anchor point or starting point is a root node and expands to intermediate nodes and leaf nodes till it covers the entire table for index. These nodes provide the pointers to the previous node and next node in a data set and the rows or records are only stored at the leaf nodes which are at the lowest level of the clustered index structure and are ordered by the clustered index columns. Due to this structuring and ordering of the data set, any insert, update or delete operation of the underlying ordering of the data is retained.</p>
<p>As mentioned earlier with its innate ordering, finding a particular row in an ordered table is to seek operations at the required multiple levels and locate the required rows. Every child node it traverses to reach the leaf node, reduces and filters out the rows which are not needed to be scanned or sought. This is why seek operation is only available in the clustered index table and not in the heap table, making the read or retrieval speed of data faster compared to the heap table. We can create clustered indexes on a single column or multiple columns together as a composite key. Each table can only have one clustered index as one order sorting criteria can be used.</p>
<p>Since the rows are ordered and sorted as per the criteria mentioned with the required columns during the creation of the clustered index, the clustered table is suitable for scenarios where heavy read activity is necessary. It stores the data rows sorted based on the clustered index key values.</p>
<p>For heavy bulk insertions, the clustered table is needed to maintain and retain the clustered index while doing insert, update or delete operations. This is because if the data rows which are to be inserted are not in sorted order then, sorting the data set will be done first, which adds up the extra cost. But this need sorting data is not needed while inserting the same data rows in the heap table. Since heap tables don't care about the ordering of the rows. It will only find the space within each page and then write on those pages. Let's try a simple example for analyzing the performance of both clustered tables and heap tables.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- creates room_series table with clustered index on id column</span>
<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> room_series
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> room_series(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    <span class="hljs-keyword">day</span> <span class="hljs-built_in">int</span>,
    start_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    end_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    time_id <span class="hljs-built_in">int</span>,
    room_id <span class="hljs-built_in">int</span>
);

<span class="hljs-keyword">with</span> weeks (<span class="hljs-keyword">day</span>) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>
    <span class="hljs-keyword">select</span> <span class="hljs-keyword">day</span> + <span class="hljs-number">1</span>
    <span class="hljs-keyword">from</span> weeks
    <span class="hljs-keyword">where</span> <span class="hljs-keyword">day</span> &lt; <span class="hljs-number">7</span>
), five_min_series (start_time, end_time, time_id) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> <span class="hljs-keyword">cast</span> (<span class="hljs-string">'00:00:00'</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> start_time, <span class="hljs-keyword">cast</span> (<span class="hljs-string">'00:05:00'</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> end_time, <span class="hljs-number">1</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">level</span>
    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span> 
    <span class="hljs-keyword">select</span>
        <span class="hljs-keyword">cast</span>(<span class="hljs-keyword">DATEADD</span>(mi, <span class="hljs-number">5</span>, start_time) <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> start_time,
        <span class="hljs-keyword">cast</span>(<span class="hljs-keyword">DATEADD</span>(mi, <span class="hljs-number">5</span>, end_time) <span class="hljs-keyword">as</span> <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>)) <span class="hljs-keyword">as</span> end_time,
        time_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">from</span> five_min_series t1
    <span class="hljs-keyword">where</span> time_id &lt; <span class="hljs-number">288</span> <span class="hljs-comment">-- there are 288 blocks of 5 minutes in 24 hrs.</span>
), rooms (room_id) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>
    <span class="hljs-keyword">select</span> room_id + <span class="hljs-number">1</span>
    <span class="hljs-keyword">from</span> rooms <span class="hljs-keyword">where</span> room_id &lt; <span class="hljs-number">100</span>
)
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> room_series (<span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id) 
<span class="hljs-keyword">select</span> <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id <span class="hljs-keyword">from</span> weeks, five_min_series, rooms
 <span class="hljs-keyword">option</span>(maxrecursion <span class="hljs-number">0</span>); <span class="hljs-comment">-- populating records in room_series table</span>

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> clustered_room_series;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> clustered_room_series(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> primary <span class="hljs-keyword">key</span>, <span class="hljs-comment">-- doesnot have identity(1,1) property</span>
    <span class="hljs-keyword">day</span> <span class="hljs-built_in">int</span>,
    start_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    end_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    time_id <span class="hljs-built_in">int</span>,
    room_id <span class="hljs-built_in">int</span>
);

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> heap_room_series;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> heap_room_series(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    <span class="hljs-keyword">day</span> <span class="hljs-built_in">int</span>,
    start_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    end_time <span class="hljs-built_in">time</span>(<span class="hljs-number">0</span>),
    time_id <span class="hljs-built_in">int</span>,
    room_id <span class="hljs-built_in">int</span>
);
</code></pre>
<p>For the illustration first, we created a room_series table that holds our data to simulate insertions. Then we created two tables above, one is a clustered table named clustered_room_series and the other begins a heap table named heap_room_series. The clustered table has a primary key on the id column, so it will create a clustered index on the clustered_room_series table. Now we will be performing inserts from a table named room_series where we have 201600 rows as data. It has clustered index on the id column. We will simulate insertions to see how both tables respond.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> clustered_room_series(<span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id) <span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id <span class="hljs-keyword">from</span> room_series;

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> heap_room_series(<span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id) <span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id <span class="hljs-keyword">from</span> room_series;

<span class="hljs-comment">-- Table 'clustered_room_series'. Scan count 0, logical reads 5998, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>
<span class="hljs-comment">-- Table 'room_series'. Scan count 1, logical reads 1132, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>

<span class="hljs-comment">-- (201600 rows affected)</span>

<span class="hljs-comment">-- (1 row affected)</span>
<span class="hljs-comment">-- Table 'heap_room_series'. Scan count 0, logical reads 202726, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>
<span class="hljs-comment">-- Table 'room_series'. Scan count 1, logical reads 1132, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>

<span class="hljs-comment">-- (201600 rows affected)</span>

<span class="hljs-comment">-- (1 row affected)</span>

<span class="hljs-comment">-- Completion time: 2022-03-24T05:09:40.6912041+05:30</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648098988612/SVCK73iaG.PNG" alt="execution plan for insertions when source table has clustered index.PNG" /></p>
<p>As we can see with the above image of the query plan for both insertions, it can be understood that the cost is the same. Since the room_series table, our source table is already clustered table, it doesn't need to spend any extra to sort the rows before insertion in the clustered_room_series table. There is a difference in logical reads for both insertions. Insertion in clustered table required 5998 logical reads and heap table required 202726 reads.</p>
<p>With a low logical reads count, we can say that clustered table works better than a heap table when the source data set is also properly indexed. Various combination of indexes gives various output. For the table with the clustered index, a new data row must be inserted into the correct location as per the column definition in an index. And in the heap table, the new data row itself can be inserted into any page on which space is available, or on a new page at the end of the chain.</p>
<p>Now let's simulate the above script again but this time the source table i.e. room_series will be a heap table. And we will be performing the insertions in both clustered and heap tables.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> clustered_room_series(<span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id) <span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id <span class="hljs-keyword">from</span> room_series;

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> heap_room_series(<span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id) <span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">day</span>, start_time, end_time, time_id, room_id <span class="hljs-keyword">from</span> room_series;
<span class="hljs-comment">--Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>
<span class="hljs-comment">--Table 'room_series'. Scan count 9, logical reads 1127, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>
<span class="hljs-comment">--Table 'clustered_room_series'. Scan count 0, logical reads 5998, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>

<span class="hljs-comment">--(201600 rows affected)</span>

<span class="hljs-comment">--(1 row affected)</span>
<span class="hljs-comment">--Table 'heap_room_series'. Scan count 0, logical reads 202726, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>
<span class="hljs-comment">--Table 'room_series'. Scan count 1, logical reads 1127, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.</span>

<span class="hljs-comment">--(201600 rows affected)</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648099107061/74cpplaEx.PNG" alt="execution plan for insertion when source table is heap table.PNG" /></p>
<p>With the involved statistics and image above. we can see one major difference and it's the change in the process flow. Since this time the source data, i.e. room_series table is not indexed in any way, the insertion operation for the clustered table in clustered_room_series will sort operation after table scan, and then only clustered index insert can take place.</p>
<p>While with the heap table, it does not matter the ordering of the row sets in any case. The operation is fairly straightforward for heap tables, doing table scans and then table inserts. The query cost is also different from the then first scenario where the source table was clustered table. In this second scenario, the query cost for insertion in the clustered table is about 65 % and in the heap table, it is about 35 %. The logical reads have been the same as the first scenario.</p>
<p>With both scenarios' we can say that with different variants we get different statistics to analyze. In the case of logical I/O, the heap table is at disadvantage compared to the clustered table. Space taken by each table index is also a factor to be considered. The statistics change as we make changes and test out with various modifications, for better performance with optimum cost.</p>
]]></content:encoded></item><item><title><![CDATA[Compare and Find Row changes in SQL Server with CHECKSUM(), BINARY_CHECKSUM(),  HASHBYTES()]]></title><description><![CDATA[In this post, we will be looking at how to detect and identify row changes in SQL Server with CHECKSUM(), BINARY_CHECKSUM(), and HASHBYTE() functions. There are use cases where comparing or detecting row changes in the table is necessary like when a ...]]></description><link>https://mssqlserver.dev/compare-and-find-row-changes-in-sql-server-with-checksum-binarychecksum-hashbytes</link><guid isPermaLink="true">https://mssqlserver.dev/compare-and-find-row-changes-in-sql-server-with-checksum-binarychecksum-hashbytes</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[Azure SQL Database]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Thu, 10 Mar 2022 05:30:26 GMT</pubDate><content:encoded><![CDATA[<p>In this post, we will be looking at how to detect and identify row changes in SQL Server with CHECKSUM(), BINARY_CHECKSUM(), and HASHBYTE() functions. There are use cases where comparing or detecting row changes in the table is necessary like when a long transaction is taking place on a certain row set. We want to be sure that those certain row set hasn’t been updated or changed before by other sessions before we do the final commit. Of course, the 'rowversion' data type is the most suitable option for that use case and we had covered it in <a target="_blank" href="https://mssqlserver.dev/sql-server-implementing-concurrency-with-rowversion-data-type">this post</a> with examples. Another cause may be, checking if the incoming data set is already present in the table, if both the data are the same then we want to ignore the incoming data and if the data is different, we may wanna update the row (conditional updates). We will be discussing how to use these functions to find row changes.</p>
<p>We will be exploring these TSQL functions and understanding the differences between them with examples.</p>
<h2 id="heading-checksum">CHECKSUM()</h2>
<p>The CHECKSUM() function returns the hash index for an expression or over a row. This hash value can be stored in another column for the row in the entire table, and later can be used for comparison in case of update operations or detecting row changes. As with every update operation, the hash value is also updated mostly based on the expression or column inputs.</p>
<p>CHECKSUM ( * | expression [,...n ] )  Two lists return the same values if their types, and attribute values are the same and they are specified in the same order. However, the function does not accept values of these types:</p>
<ol>
<li><p>CURSOR,</p>
</li>
<li><p>IMAGE,</p>
</li>
<li><p>NTEXT</p>
</li>
<li><p>TEXT</p>
</li>
<li><p>XML If of same data types ten NULLS are considered as equal for equality operator check. The dash character is ignored for NCHAR and NVARCHAR data types. And trailing white spaces are also ignored.</p>
</li>
</ol>
<p>As mentioned on the Microsoft SQL Server documentation page “we recommend the use of CHECKSUM only if your application can tolerate an occasional missed change. Otherwise, consider using HASHBYTES instead. With a specified MD5 hash algorithm, the probability that HASHBYTES will return the same result, for two different inputs, is much lower compared to CHECKSUM.”</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">checksum</span>(<span class="hljs-string">'test          '</span>);
<span class="hljs-keyword">select</span> <span class="hljs-keyword">checksum</span>(<span class="hljs-string">'Test'</span>)
</code></pre>
<p>Returns the same hash value for the above to two checksum statements (assuming that we have a case-insensitive installation of the instance).</p>
<h2 id="heading-binarychecksm">BINARY_CHECKSM()</h2>
<p>Similar to CHECKSUM(), returns the binary checksum value computed over a row or list of expressions. It is more precise compared to CHECKSUM(), and hence computation overhead is more than CHECKSUM(). Like CHECKSUM(), BINARY_CHECKSUM() value can be stored in another column for the row in the entire table, and later can be used for comparison in case of update operations or detecting row changes.</p>
<p>BINARY_CHECKSUM ( * | expression [ ,...n ] )</p>
<p>As BINARY_CHECKSUM() computation returns the same value as long as the row isn’t modified later. Unlike CHECKSUM(), the collisions will be less in the case of BINARY_CHECKSUM(). Two lists return the same value if both corresponding attributes have the same data type and are equal when compared using the equals (=) operator or more precise byte representation. However, the function does not accept values of these types:</p>
<ol>
<li><p>CURSOR,</p>
</li>
<li><p>IMAGE,</p>
</li>
<li><p>NTEXT</p>
</li>
<li><p>TEXT</p>
</li>
<li><p>XML</p>
</li>
</ol>
<p>The Microsoft SQL Server Documentation page also mentions similar thoughts for BINARY_CHECKSUM  "so to detect whether values have changed, we recommend the use of BINARY_CHECKSUM only if your application can tolerate an occasional missed change. Otherwise, consider using HASHBYTES instead. With a specified MD5 hash algorithm, the probability that HASHBYTES will return the same result, for two different inputs, is much lower than BINARY_CHECKSUM."</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> BINARY_CHECKSUM(<span class="hljs-string">'test'</span>);
<span class="hljs-keyword">select</span> BINARY_CHECKSUM(<span class="hljs-string">'Test'</span>);
</code></pre>
<p>Both above statements return a different value. Do note that BINARY_CHECKSUM() is case-sensitive and it does not ignore dash characters like CHECKSUM().</p>
<h2 id="heading-hashbytes">HASHBYTES()</h2>
<p>The HASHBYTES() function is primarily used for hashing values for use within cryptographic situations. It can be also used for comparison or detecting changes in rows. It returns the hash values based on the specified algorithm as input.</p>
<p>HASHBYTES ( '', { @input | 'input' } )</p>
<p>::= MD2 | MD4 | MD5 | SHA | SHA1 | SHA2_256 | SHA2_512</p>
<p>As HASHBYTES is a more accurate hashing function unlike BINARY_CHECKSUM, it also has a high overhead cost for computations as compared to CHECKSUM() and BINARY_CHECKSUM(). As of SQL Server 2016, all the algorithms are deprecated, except SHA2_256 and SHA2_512. It works on all data types and treats NULL the same as CHECKSUM() and BINARY_CHECKSUM().</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> HASHBYTES(<span class="hljs-string">'SHA2_256'</span>, <span class="hljs-string">'test'</span>);
<span class="hljs-keyword">select</span> HASHBYTES(<span class="hljs-string">'SHA2_256'</span>, <span class="hljs-string">'Test'</span>);
</code></pre>
<p>It is also case-sensitive like BINARY_CHECKSUM(). Due to overhead costs, it is intensive, but also suitable for change detection. Though it was limited to 8000 bytes in earlier versions. Fortunately, in SQL Server 2016 and later, that limitation was removed. However, it is correct that the more powerful the hashing algorithm is the more remote are changes of the collisions for different inputs, but this also increases the computational and overhead costs of the resources.</p>
<h2 id="heading-summary">Summary</h2>
<ol>
<li><p>We have to make choices as per the requirement and restrictions based on data types.</p>
</li>
<li><p>If want cross-platform implementations, then better to use HASH_BYTES().</p>
</li>
<li><p>If dash character or case sensitivity does matter then go for BINARY_CHECKSUM() as it also has lower collisions than CHECKSUM().</p>
</li>
<li><p>HASH_BYTES algorithm has its computational overhead, so use it only if necessary.</p>
</li>
</ol>
<p>As mentioned in the post above, the post for the 'rowversion' data type to detect and find changes in rows can be found <a target="_blank" href="https://mssqlserver.dev/sql-server-implementing-concurrency-with-rowversion-data-type">HERE</a></p>
]]></content:encoded></item><item><title><![CDATA[Recursive CTE in SQL Server with examples]]></title><description><![CDATA[After understanding the basics of CTE, Multiple CTEs, and Nested CTEs in the previous post of this CTE series, we will be exploring Recursive CTE in this post. Recursion takes place when we invoke the block of code inside itself to perform repeated p...]]></description><link>https://mssqlserver.dev/recursive-cte-in-sql-server-with-examples</link><guid isPermaLink="true">https://mssqlserver.dev/recursive-cte-in-sql-server-with-examples</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[MSSQL]]></category><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Wed, 09 Mar 2022 03:58:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1647662151870/NqWXFd7Vg.PNG" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After understanding the basics of CTE, Multiple CTEs, and Nested CTEs in the previous post of this CTE series, we will be exploring Recursive CTE in this post. Recursion takes place when we invoke the block of code inside itself to perform repeated procedural loops. Likewise, Recursive CTE is used to perform repeated procedural loops, the recursive query will call itself until the query satisfies the clause in which condition to terminate the recursion. This makes it clear that Recursive CTE refers to itself and is helpful where we are dealing with hierarchical structures or where the pattern is repeating like employees hierarchy in the company, railway connections, applications navigational menus, etc.</p>
<p>Let's create a simple Recursive query to display rows containing 1 to 10.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> counter(previous_value) <span class="hljs-keyword">as</span> (
  <span class="hljs-keyword">select</span>
    <span class="hljs-number">1</span>                            <span class="hljs-comment">-- anchor part</span>

  <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>            

  <span class="hljs-keyword">select</span>
    previous_value + <span class="hljs-number">1</span>
  <span class="hljs-keyword">from</span> counter                    <span class="hljs-comment">-- recursive part</span>
  <span class="hljs-keyword">where</span> previous_value &lt; <span class="hljs-number">10</span>        <span class="hljs-comment">-- termination clause</span>
)

<span class="hljs-keyword">select</span>
  *
<span class="hljs-keyword">from</span> counter;                    <span class="hljs-comment">-- invocation with outer query</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647661440173/H1Y9mTb-_.PNG" alt="recursive cte example generate number from 1 to 10.PNG" /></p>
<p>The above SQL snippet showcases the simple Recursive CTE implementation. Let's analyze each part of the above script in detail. Recursive CTE is similar to normal CTE with the exception that we must give a list of columns inside the parentheses, so we can refer to the column value and use it as the recursive part of the query. Our CTE named Counter has only one column named previous_value. In the above SQL snippets, we can see the commented words for some lines, mentioning what it is called. These are also essential elements of the Recursive CTE: an anchor member, a recursive member, and a termination clause.</p>
<p>As the name suggests, an anchor member is something like an anchor point or a starting point to start with. Like in our snippet, we wanted to show a number between 1 to 10, in which case the starting point or anchor point is number 1. In the above SQL snippet, we expressed the anchor member as "select 1".</p>
<p>Then comes the recursive member which tells us what to do in each step. In our case, after expressing the anchor member and considering number 1 as starting point, we will add another row with a number that is incrementing by 1 than the most recently generated row. The below snippets depict recursive members in our original snippet above generating a number between 1 to 10. "select previous_value + 1 from counter" At this point, the CTE Counter refers to itself (FROM Counter).</p>
<p>After this comes the termination clause part, wherein the condition mentioned helps us to eventually stop our recursion, otherwise, it will be an endless loop and never stops. In our case "where previous_value &lt; 10 " means that we will continue recursion until we reach number 10 and then terminate.</p>
<p>Do remember that <strong>only UNION ALL is permitted in a recursive CTE.</strong> To remove the duplicate values, we can use DISTINCT in the invocation part or outer query. And we can have n number of columns in our recursive CTE, but the only thing is <strong>both the anchor part and recursive part should have the same number of columns.</strong></p>
<h2 id="heading-maxrecursion">MAXRECURSION</h2>
<p>In the above SQL snippet, we tried to generate numbers between 1 to 10, but want if we wanted to generate numbers from say 1 to 150. our CTE will terminate with an error stating that "The statement terminated. The maximum recursion 100 has been exhausted before statement completion." This is because, as mentioned in the error statement by default SQL only allows a maximum recursion depth of 100. We can change the default setting of the recursion depth with the MAXRECURSION n option, so we can use this option when we are sure of the computations and depth we require. Let's illustrate by modifying the previous SQL snippet and generating numbers from 1 to 150 this time.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> counter(previous_value) <span class="hljs-keyword">as</span> (
  <span class="hljs-keyword">select</span>
    <span class="hljs-number">1</span>                            

  <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>            

  <span class="hljs-keyword">select</span>
    previous_value + <span class="hljs-number">1</span>
  <span class="hljs-keyword">from</span> counter                    
  <span class="hljs-keyword">where</span> previous_value &lt; <span class="hljs-number">150</span>        
)

<span class="hljs-keyword">select</span>
  *
<span class="hljs-keyword">from</span> counter
<span class="hljs-keyword">option</span> (MAXRECURSION <span class="hljs-number">150</span>);
</code></pre>
<p>The part "OPTION (MAXRECURSION 150)" in the invocation or outer query part tells SQL Server to override the default recursion depth and set it to 150. However, do note that <strong>valid values for the integers are between 0 and 32767</strong>. Here 0 value means that there is no limit on the depth of recursion and the query ay run infinitely which is risky, but you may require it to write a very deep recursion.</p>
<p>Let's see one practical illustration of recursive CTE for a hierarchical / tree-based structure with our classic example. We have a company with an organizational hierarchy in place, i.e. each employee has a superior (except for the boss). An employee has precisely one superior, but one superior may have multiple subordinates. To represent the structure in the table format, we will have another column or attribute for the table employee named superior_id, containing the id of the employee who is their superior and reports to. It is also a classic example of a self-join case. Let's create a dataset for the same.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> employee;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> employee (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">INT</span>,
    first_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">50</span>),
    last_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">50</span>),
    superior_id <span class="hljs-built_in">INT</span>
);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'Rollo'</span>, <span class="hljs-string">'Peris'</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-string">'Christi'</span>, <span class="hljs-string">'Ploughwright'</span>, <span class="hljs-literal">NULL</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-string">'Alon'</span>, <span class="hljs-string">'Manntschke'</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-string">'Fabiano'</span>, <span class="hljs-string">'Duchart'</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-string">'Gustie'</span>, <span class="hljs-string">'MacCostigan'</span>, <span class="hljs-number">2</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-string">'Valentine'</span>, <span class="hljs-string">'Shutler'</span>, <span class="hljs-number">3</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-string">'Kaitlynn'</span>, <span class="hljs-string">'Dowrey'</span>, <span class="hljs-number">3</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-string">'Bonnie'</span>, <span class="hljs-string">'Pamphilon'</span>, <span class="hljs-number">4</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-string">'Wayland'</span>, <span class="hljs-string">'Richel'</span>, <span class="hljs-number">5</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-string">'Shena'</span>, <span class="hljs-string">'Mattessen'</span>, <span class="hljs-number">5</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-string">'Al'</span>, <span class="hljs-string">'Broy'</span>, <span class="hljs-number">6</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-string">'Wallas'</span>, <span class="hljs-string">'Rofe'</span>, <span class="hljs-number">7</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-string">'Suellen'</span>, <span class="hljs-string">'Burtonshaw'</span>, <span class="hljs-number">7</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-string">'Hillard'</span>, <span class="hljs-string">'Tisor'</span>, <span class="hljs-number">8</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">15</span>, <span class="hljs-string">'Lolly'</span>, <span class="hljs-string">'Vasiliev'</span>, <span class="hljs-number">9</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">16</span>, <span class="hljs-string">'Gaylord'</span>, <span class="hljs-string">'Sivyour'</span>, <span class="hljs-number">10</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">17</span>, <span class="hljs-string">'Fitzgerald'</span>, <span class="hljs-string">'Trask'</span>, <span class="hljs-number">10</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">18</span>, <span class="hljs-string">'Aveline'</span>, <span class="hljs-string">'Mouget'</span>, <span class="hljs-number">12</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">19</span>, <span class="hljs-string">'Alys'</span>, <span class="hljs-string">'Rydeard'</span>, <span class="hljs-number">13</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">20</span>, <span class="hljs-string">'Brianna'</span>, <span class="hljs-string">'Vannozzii'</span>, <span class="hljs-number">13</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">21</span>, <span class="hljs-string">'Sibylla'</span>, <span class="hljs-string">'Ferfulle'</span>, <span class="hljs-number">14</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">22</span>, <span class="hljs-string">'Gwynne'</span>, <span class="hljs-string">'Okie'</span>, <span class="hljs-number">15</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">23</span>, <span class="hljs-string">'Cortney'</span>, <span class="hljs-string">'Mellhuish'</span>, <span class="hljs-number">20</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">24</span>, <span class="hljs-string">'Nikos'</span>, <span class="hljs-string">'Muscroft'</span>, <span class="hljs-number">20</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">25</span>, <span class="hljs-string">'Lorinda'</span>, <span class="hljs-string">'Barsham'</span>, <span class="hljs-number">21</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">26</span>, <span class="hljs-string">'Hephzibah'</span>, <span class="hljs-string">'Keat'</span>, <span class="hljs-number">22</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">27</span>, <span class="hljs-string">'Patrice'</span>, <span class="hljs-string">'Reardon'</span>, <span class="hljs-number">22</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">28</span>, <span class="hljs-string">'Gregorius'</span>, <span class="hljs-string">'Larkkem'</span>, <span class="hljs-number">24</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">29</span>, <span class="hljs-string">'Kaylyn'</span>, <span class="hljs-string">'Gaiger'</span>, <span class="hljs-number">23</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employee (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id) <span class="hljs-keyword">values</span> (<span class="hljs-number">30</span>, <span class="hljs-string">'Constantina'</span>, <span class="hljs-string">'Jane'</span>, <span class="hljs-number">19</span>);
</code></pre>
<p>Now let's see how to use a recursive query for the hierarchical structure like the employee table, we will draw their path to the boss.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> employee_tree (<span class="hljs-keyword">id</span>, first_name, last_name, superior_id, <span class="hljs-keyword">path</span>) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        <span class="hljs-keyword">id</span>,
        first_name,
        last_name,
        superior_id,
        <span class="hljs-keyword">cast</span>(first_name +<span class="hljs-string">' '</span>+last_name <span class="hljs-keyword">as</span> <span class="hljs-keyword">nvarchar</span>(<span class="hljs-keyword">max</span>)) <span class="hljs-keyword">as</span> <span class="hljs-keyword">path</span>
    <span class="hljs-keyword">from</span> employee
    <span class="hljs-keyword">where</span> superior_id <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>

    <span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>

    <span class="hljs-keyword">select</span> 
        e.id,
        e.first_name,
        e.last_name,
        e.superior_id,
        t.path + N<span class="hljs-string">' -&gt; '</span>+ e.first_name + N<span class="hljs-string">' '</span>+ e.last_name
    <span class="hljs-keyword">from</span> employee e
    <span class="hljs-keyword">join</span> employee_tree t
        <span class="hljs-keyword">on</span> e.superior_id = t.id
)

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> employee_tree;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647662151870/NqWXFd7Vg.PNG" alt="recursive cte with hierarchal tree based structure.PNG" /></p>
<p>In the anchor part of the employee_tree, CTE we started with the anchor point "BOSS" i.e employee who doesn't have anyone superior, and hence their superior_id was null. With getting superiors or boss in the anchor part, in the recursive part, we perform the join between the employee table and employee_tree table with union all to club the result set of both the part. As you can see in the image above which the output of the employee_tree SQL snippet rows 1 and 2 did not have superior_id has only their names as the path value, indicating they are the boss or the most superior in the company. The rest of the rows have path values from their boss's name to themselves including any superiors in between. This represents the path of the superior to the subordinate employee.</p>
<h2 id="heading-summary">Summary</h2>
<ol>
<li><p>Can have Multiple CTEs some of which can be recursive CTE.</p>
</li>
<li><p>Only UNION ALL is permitted in the recursive CTE, to only return unique values for the columns, you can use distinct in our outer part or invocation query.</p>
</li>
<li><p>Both the anchor part and recursive part should have the same number of columns and data types.</p>
</li>
<li><p>In case of string columns want to do any operation on string data type like concatenation etc, it is better to cast those string columns as nvarchar(max) in both the part of the query</p>
</li>
<li><p>Valid integer value for the option of maxrecursion is between 0 and 32767.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[SQL Server Nested CTE with examples]]></title><description><![CDATA[After understanding the basics of CTE, multiple CTEs, and the explanation in the previous post, in this post we will be exploring Nested CTEs in this post. As discussed, we can say that CTE is a named temporary set of rows similar to subqueries. Like...]]></description><link>https://mssqlserver.dev/sql-server-nested-cte-with-examples</link><guid isPermaLink="true">https://mssqlserver.dev/sql-server-nested-cte-with-examples</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Azure SQL Database]]></category><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Tue, 08 Mar 2022 03:36:46 GMT</pubDate><content:encoded><![CDATA[<p>After understanding the basics of CTE, multiple CTEs, and the explanation in the <a target="_blank" href="https://mssqlserver.dev/understanding-sql-server-common-table-expression-cte">previous post</a>, in this post we will be exploring Nested CTEs in this post. As discussed, we can say that CTE is a named temporary set of rows similar to subqueries. Like subqueries, you can't put one CTE definition inside another CTE definition. The syntax structure for the CTE is as follows</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> cte_expression_1 <span class="hljs-keyword">as</span> (
    cte_query_1
),
cte_expression_2 <span class="hljs-keyword">as</span> (
    cte_query_2 <span class="hljs-comment">-- (in the FROM clause refers cte_expression_1)</span>
)
<span class="hljs-keyword">select</span> <span class="hljs-keyword">from</span> cte_epression_2 <span class="hljs-comment">-- outer query</span>
</code></pre>
<p>As mentioned in the syntax above, the second CTE definition cte_expression_2 uses the first CTE definition cte_expression_1. That's why there is a comment with cte_query in the second CTE definition cte_query_2. This means that, once a CTE is defined we can freely use it in subsequent CTEs. This is helpful in use cases where it's impossible to use one aggregate function inside another like finding the average maximum, average minimum, an average of an average, group comparisons for reports, etc.</p>
<p>Let's create a table and seed it with data for illustrations. We are having a scenario wherein the cab service company wants to know the average maximum distance their driver rides in each city they provide the service.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> city
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> city(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">30</span>) <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    country_code <span class="hljs-built_in">varchar</span>(<span class="hljs-number">5</span>)
);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Fanhu'</span>, <span class="hljs-string">'USA'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Goodlands'</span>, <span class="hljs-string">'USA'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Furong'</span>, <span class="hljs-string">'USA'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Guxian'</span>, <span class="hljs-string">'JPN'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Ar Rahad'</span>, <span class="hljs-string">'OMN'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Uitenhage'</span>, <span class="hljs-string">'USA'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Yanglinshi'</span>, <span class="hljs-string">'JPN'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> city (<span class="hljs-keyword">name</span>, country_code) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Mengjia'</span>, <span class="hljs-string">'JPN'</span>);

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> driver
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> driver(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    first_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">20</span>),
    last_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">20</span>),
    vehicle_id <span class="hljs-built_in">int</span>,
    city_id <span class="hljs-built_in">int</span>
);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Cicely'</span>, <span class="hljs-string">'Heaker'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">5</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Brandy'</span>, <span class="hljs-string">'Rizzone'</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Hewitt'</span>, <span class="hljs-string">'Foden'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Freddie'</span>, <span class="hljs-string">'Rohfsen'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Johann'</span>, <span class="hljs-string">'McRill'</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Arabella'</span>, <span class="hljs-string">'MacKeague'</span>, <span class="hljs-number">6</span>, <span class="hljs-number">4</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Jonie'</span>, <span class="hljs-string">'Greenan'</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Alysa'</span>, <span class="hljs-string">'Hanselman'</span>, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Vale'</span>, <span class="hljs-string">'Heathwood'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Kennedy'</span>, <span class="hljs-string">'Headon'</span>, <span class="hljs-number">10</span>, <span class="hljs-number">7</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Ugo'</span>, <span class="hljs-string">'Rapper'</span>, <span class="hljs-number">11</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Laverna'</span>, <span class="hljs-string">'Harkin'</span>, <span class="hljs-number">12</span>, <span class="hljs-number">3</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Washington'</span>, <span class="hljs-string">'Kingdon'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">8</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Rogers'</span>, <span class="hljs-string">'Ferronet'</span>, <span class="hljs-number">14</span>, <span class="hljs-number">7</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> driver (first_name, last_name, vehicle_id, city_id) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Raleigh'</span>, <span class="hljs-string">'Norgan'</span>, <span class="hljs-number">15</span>, <span class="hljs-number">5</span>);

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> daily_ride
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> daily_ride(
    <span class="hljs-built_in">date</span> <span class="hljs-built_in">date</span>,
    driver_id <span class="hljs-built_in">int</span>,
    amount_earned <span class="hljs-built_in">decimal</span>(<span class="hljs-number">6</span>,<span class="hljs-number">2</span>),
    ride_distance <span class="hljs-built_in">decimal</span>(<span class="hljs-number">5</span>,<span class="hljs-number">2</span>)
);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-11'</span>, <span class="hljs-number">8</span>, <span class="hljs-number">198.41</span>, <span class="hljs-number">29.67</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-09'</span>, <span class="hljs-number">10</span>, <span class="hljs-number">65.82</span>, <span class="hljs-number">23.39</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">8</span>, <span class="hljs-number">187.77</span>, <span class="hljs-number">5.77</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-28'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">273.41</span>, <span class="hljs-number">41.34</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">102.92</span>, <span class="hljs-number">94.51</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-02'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">74.85</span>, <span class="hljs-number">38.8</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-06'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">312.21</span>, <span class="hljs-number">70.7</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-19'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">148.68</span>, <span class="hljs-number">59.91</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-21'</span>, <span class="hljs-number">14</span>, <span class="hljs-number">167.77</span>, <span class="hljs-number">35.76</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-24'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">223.94</span>, <span class="hljs-number">7.49</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-16'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">5.88</span>, <span class="hljs-number">6.5</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-19'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">38.31</span>, <span class="hljs-number">25.31</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-24'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">33.94</span>, <span class="hljs-number">71.32</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-14'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">71.26</span>, <span class="hljs-number">94.04</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-23'</span>, <span class="hljs-number">8</span>, <span class="hljs-number">152.09</span>, <span class="hljs-number">1.5</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-06'</span>, <span class="hljs-number">6</span>, <span class="hljs-number">206.48</span>, <span class="hljs-number">8.88</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-20'</span>, <span class="hljs-number">7</span>, <span class="hljs-number">261.01</span>, <span class="hljs-number">97.81</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">119.72</span>, <span class="hljs-number">6.63</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-13'</span>, <span class="hljs-number">10</span>, <span class="hljs-number">77.95</span>, <span class="hljs-number">8.86</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-06'</span>, <span class="hljs-number">14</span>, <span class="hljs-number">102.9</span>, <span class="hljs-number">36.22</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-17'</span>, <span class="hljs-number">7</span>, <span class="hljs-number">263.06</span>, <span class="hljs-number">63.85</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-05'</span>, <span class="hljs-number">6</span>, <span class="hljs-number">125.6</span>, <span class="hljs-number">83.41</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-18'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">80.19</span>, <span class="hljs-number">81.05</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-18'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">349.35</span>, <span class="hljs-number">60.93</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-18'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">230.82</span>, <span class="hljs-number">35.77</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-31'</span>, <span class="hljs-number">11</span>, <span class="hljs-number">156.39</span>, <span class="hljs-number">4.28</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">10</span>, <span class="hljs-number">376.38</span>, <span class="hljs-number">72.98</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-05'</span>, <span class="hljs-number">7</span>, <span class="hljs-number">114.81</span>, <span class="hljs-number">14.06</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-23'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11.3</span>, <span class="hljs-number">75.65</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-21'</span>, <span class="hljs-number">5</span>, <span class="hljs-number">398.57</span>, <span class="hljs-number">11.91</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-28'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">178.44</span>, <span class="hljs-number">66.02</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-22'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">266.44</span>, <span class="hljs-number">12.16</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-27'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">382.47</span>, <span class="hljs-number">37.16</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-28'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">327.74</span>, <span class="hljs-number">79.3</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-14'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">74.7</span>, <span class="hljs-number">26.2</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-03'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">157.97</span>, <span class="hljs-number">36.15</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-22'</span>, <span class="hljs-number">13</span>, <span class="hljs-number">212.57</span>, <span class="hljs-number">23.22</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-13'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">301.57</span>, <span class="hljs-number">36.76</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-30'</span>, <span class="hljs-number">5</span>, <span class="hljs-number">31.8</span>, <span class="hljs-number">73.93</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-12'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">396.49</span>, <span class="hljs-number">30.46</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-21'</span>, <span class="hljs-number">2</span>, <span class="hljs-number">222.17</span>, <span class="hljs-number">57.34</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-12'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">363.4</span>, <span class="hljs-number">41.21</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-12'</span>, <span class="hljs-number">9</span>, <span class="hljs-number">227.96</span>, <span class="hljs-number">11.48</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-21'</span>, <span class="hljs-number">5</span>, <span class="hljs-number">77.59</span>, <span class="hljs-number">71.0</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-14'</span>, <span class="hljs-number">8</span>, <span class="hljs-number">275.88</span>, <span class="hljs-number">97.34</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-16'</span>, <span class="hljs-number">5</span>, <span class="hljs-number">365.88</span>, <span class="hljs-number">96.7</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-14'</span>, <span class="hljs-number">4</span>, <span class="hljs-number">271.33</span>, <span class="hljs-number">59.66</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-18'</span>, <span class="hljs-number">3</span>, <span class="hljs-number">383.73</span>, <span class="hljs-number">79.69</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-08'</span>, <span class="hljs-number">6</span>, <span class="hljs-number">245.05</span>, <span class="hljs-number">79.13</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> daily_ride (<span class="hljs-built_in">date</span>, driver_id, amount_earned, ride_distance) <span class="hljs-keyword">values</span> (<span class="hljs-string">'2021-03-14'</span>, <span class="hljs-number">6</span>, <span class="hljs-number">328.01</span>, <span class="hljs-number">91.68</span>);
</code></pre>
<p>With all the tables and data-set ready, let's dive in further. ' We have table name city, driver, and daily_rides which have respective records about them. Our cab service company wants to know the average total maximum distance traveling for each city they operate in.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> total_distance_ride <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        <span class="hljs-keyword">sum</span>(r.ride_distance) <span class="hljs-keyword">as</span> total_distance,
        r.driver_id,
        d.city_id
    <span class="hljs-keyword">from</span> daily_ride r
    <span class="hljs-keyword">join</span> driver d
        <span class="hljs-keyword">on</span> r.driver_id = d.id
    <span class="hljs-keyword">join</span> city c
        <span class="hljs-keyword">on</span> d.city_id = c.id
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> r.driver_id, d.city_id
), max_ride_distance <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        <span class="hljs-keyword">max</span>(total_distance) <span class="hljs-keyword">as</span> max_distance,
        city_id
    <span class="hljs-keyword">from</span> total_distance_ride
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> city_id
)

<span class="hljs-keyword">select</span> <span class="hljs-keyword">avg</span>(max_distance) <span class="hljs-keyword">as</span> avg_max_distance, city_id <span class="hljs-keyword">from</span> max_ride_distance <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> city_id
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647660469658/_RAxTG37K.PNG" alt="nested cte example finding average total maximum distance travelled.PNG" /></p>
<p>As you see the above image which shows the output of the above Nested CTE finds the average total maximum distance of ride occurs in each city. In the first CTE, we find the total distance driven in each city for each date. In the second CTE, we take this total_distance which is the sum of the ride_distance for that date and city and choose the maximum amongst each city_id. Finally, in the outer query, we return the average maximum ride distance across all the cities. After finding the average maximum distance across those cities, No company wants to find the number of days where the average maximum amount earned exceeded 50 USD. For this we first need to find the maximum amount earned on a given date for each city, then with the previous result set, we need to calculate the average maximal amount across all the cities for a given date. finally, we count the number of dates where the average maximum amount exceeded 50 USD.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> max_amount_earned <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
    <span class="hljs-keyword">max</span>(r.amount_earned) <span class="hljs-keyword">as</span> max_earned,
    r.date,
    d.city_id
    <span class="hljs-keyword">from</span> daily_ride r
    <span class="hljs-keyword">join</span> driver d
        <span class="hljs-keyword">on</span> r.driver_id = d.id
    <span class="hljs-keyword">join</span> city c
        <span class="hljs-keyword">on</span> d.city_id = c.id
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> r.date, d.city_id
), average_maximal_amount <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        <span class="hljs-keyword">avg</span>(max_earned) <span class="hljs-keyword">as</span> day_average,
        <span class="hljs-built_in">date</span>
    <span class="hljs-keyword">from</span> max_amount_earned
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> <span class="hljs-built_in">date</span>
)

<span class="hljs-keyword">select</span> <span class="hljs-keyword">count</span>(<span class="hljs-built_in">date</span>) <span class="hljs-keyword">as</span> number_of_days <span class="hljs-keyword">from</span> average_maximal_amount <span class="hljs-keyword">where</span> day_average &gt; <span class="hljs-number">50</span>;

<span class="hljs-comment">-- output </span>
number_of_days
<span class="hljs-comment">--------------</span>
22

(1 row affected)


Completion time: 2022-03-19T09:00:10.2015488+05:30
</code></pre>
<p>The above snippet returns the count of days where the average maximum amount earned was more than 50 USD. Now one last example wherein we will be using nested CTE for comparing two groups of the result set. We want to know the average earning of the cities of the USA and other country codes.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> <span class="hljs-keyword">grouping</span> <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> 
        <span class="hljs-keyword">id</span> <span class="hljs-keyword">as</span> city_id,
        <span class="hljs-keyword">case</span> <span class="hljs-keyword">when</span>
            country_code = N<span class="hljs-string">'USA'</span>
                <span class="hljs-keyword">then</span> N<span class="hljs-string">'US Cities'</span>
            <span class="hljs-keyword">else</span> N<span class="hljs-string">'Other'</span>
        <span class="hljs-keyword">end</span> <span class="hljs-keyword">as</span> group_name
    <span class="hljs-keyword">from</span> city
), total_amount_earned <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        r.driver_id,
        group_name,
        <span class="hljs-keyword">sum</span>(r.amount_earned) <span class="hljs-keyword">as</span> total_earned
    <span class="hljs-keyword">from</span> daily_ride r
    <span class="hljs-keyword">join</span> driver d 
        <span class="hljs-keyword">on</span> r.driver_id = d.id
    <span class="hljs-keyword">join</span> <span class="hljs-keyword">grouping</span> g
        <span class="hljs-keyword">on</span> g.city_id = d.city_id
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> r.driver_id, group_name
)

<span class="hljs-keyword">select</span>
    group_name,
    <span class="hljs-keyword">avg</span>(total_earned) <span class="hljs-keyword">as</span> average_total_earned
<span class="hljs-keyword">from</span> total_amount_earned
<span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> group_name <span class="hljs-keyword">order</span> <span class="hljs-keyword">by</span> group_name <span class="hljs-keyword">desc</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647660874356/3j60fHXC2.PNG" alt="nested cte with grouping example.PNG" /></p>
<p>With the above image, showing the output, we can that the script above returned the average total amount earned based on our city grouping. In the first CTE - grouping, we just only segregated and clubbed cities as per our grouping requirement based on country_code with help of the case statement. We labeled cities having country_code value 'USA' as 'US Cities' and the rest other as 'Other'. In the second CTE - total_amount_earned we computed total_earned which depicts the sum of amount_earned by the driver and combined it with the grouping label we created in the first CTE. Then in the outer query, we computed the group-level average as the average total earned.</p>
<h2 id="heading-summary">Summary</h2>
<ol>
<li><p>Like Subqueries we cant define CTE inside CTE. But we can refer to the previously defined CTE in subsequent CTEs in the FROM clause.</p>
</li>
<li><p>Nested CTEs are more useful in cases where we need to compute aggregate functions on several levels and also to compare two or more grouping of rows.</p>
</li>
<li><p>We can use a subquery in the outer query part of the CTE script.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Understanding SQL Server Common Table Expression - CTE]]></title><description><![CDATA[Common Table Expressions shortly called CTE or WITH clauses are named subqueries returning the data set. With CTE, we can break a long query into smaller parts making it simpler to understand and readable, and also supporting recursive implementation...]]></description><link>https://mssqlserver.dev/understanding-sql-server-common-table-expression-cte</link><guid isPermaLink="true">https://mssqlserver.dev/understanding-sql-server-common-table-expression-cte</guid><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[#SQLtutorial ]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Mon, 07 Mar 2022 03:04:07 GMT</pubDate><content:encoded><![CDATA[<p>Common Table Expressions shortly called CTE or WITH clauses are named subqueries returning the data set. With CTE, we can break a long query into smaller parts making it simpler to understand and readable, and also supporting recursive implementation where traversal of hierarchical models is needed. In this post, we will be exploring the basics of CTE with examples.</p>
<h2 id="heading-syntax">Syntax</h2>
<p>The most basic syntax of CTE is as follows,</p>
<pre><code class="lang-sql"><span class="hljs-keyword">WITH</span> expression_name  ( column_names )  <span class="hljs-keyword">AS</span> (
  CTE_query <span class="hljs-comment">-- inner query</span>
) <span class="hljs-comment">--- cte defination</span>

<span class="hljs-keyword">SELECT</span>
  ...
<span class="hljs-keyword">FROM</span> expression_name <span class="hljs-comment">-- outer query</span>
</code></pre>
<p><em>expression_name:</em> it is an identifier for the CTE. The same expression_name is not allowed in the case of nested or recursive CTE. Any reference to the identifier in the statement uses CTE.</p>
<p><em>column_names:</em> its list of names for the columns or attributes of CTE is optional. And the number of column_names should match the number of columns in the result set of the CTE_query.</p>
<p><em>CTE_query:</em> denotes a SELECT statement to populate the common table expression with the result set. Also known as an inner query. In the rest part of the post, we will also refer to it as an inner query for simplicity. If more than one CTE_query statement is mentioned then, it must be joined using set operators namely UNION ALL, UNION, EXCEPT, and INTERSECT This is the most basic version of the CTE definition and its select outer query. We need to provide a name for CTE and define the CTE within the parentheses. After the parentheses, we can select from the CTE as we do with tables.</p>
<p>To illustrate CTE with examples, let's create a table with some data. In the table, we will be having our employees, departments, and department_expenses. As the names suggest, the employees' table holds records of the employee in a company, the departments' table holds the data of all the departments in a company, and department_expenses records the expenditure made by each department.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> departments;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> departments(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">40</span>),
    description <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>),
    petty_cash_alloted <span class="hljs-built_in">decimal</span>(<span class="hljs-number">6</span>,<span class="hljs-number">2</span>)
);

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> employees;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> employees(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    first_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">30</span>),
    last_name <span class="hljs-built_in">varchar</span>(<span class="hljs-number">30</span>),
    department_id <span class="hljs-built_in">int</span>,
    joining_date <span class="hljs-built_in">date</span>
);

<span class="hljs-keyword">drop</span> <span class="hljs-keyword">table</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">exists</span> department_expenses;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> department_expenses(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    employee_id <span class="hljs-built_in">int</span>,
    department_id <span class="hljs-built_in">int</span>,
    expense_amount <span class="hljs-built_in">decimal</span>(<span class="hljs-number">6</span>,<span class="hljs-number">2</span>),
    expense_date <span class="hljs-built_in">date</span>
);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> departments(<span class="hljs-keyword">name</span>, petty_cash_alloted) <span class="hljs-keyword">values</span> (<span class="hljs-string">'accounting'</span>, <span class="hljs-number">324.50</span>), (<span class="hljs-string">'human resources'</span>, <span class="hljs-number">1000</span>), (<span class="hljs-string">'technical support'</span>, <span class="hljs-number">780</span>), (<span class="hljs-string">'cleaning staff'</span>, <span class="hljs-number">890.50</span>), (<span class="hljs-string">'legal'</span>, <span class="hljs-number">770.60</span>);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Kaitlynn'</span>, <span class="hljs-string">'Epelett'</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'2021-03-24'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Bernhard'</span>, <span class="hljs-string">'Cuttell'</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'2021-03-27'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Zitella'</span>, <span class="hljs-string">'Griniov'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-03-25'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Janelle'</span>, <span class="hljs-string">'Raxworthy'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Isabeau'</span>, <span class="hljs-string">'Handsheart'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-03-06'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Rowland'</span>, <span class="hljs-string">'Jewess'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-03-02'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Yevette'</span>, <span class="hljs-string">'Featenby'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'2021-03-27'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Cammy'</span>, <span class="hljs-string">'Silverton'</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'2021-03-03'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Derward'</span>, <span class="hljs-string">'Joules'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-03-30'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Neilla'</span>, <span class="hljs-string">'Hincham'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-03-25'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Seumas'</span>, <span class="hljs-string">'Cribbins'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-03-13'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Star'</span>, <span class="hljs-string">'Bladon'</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'2021-03-07'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Britta'</span>, <span class="hljs-string">'Waddilow'</span>, <span class="hljs-number">5</span>, <span class="hljs-string">'2021-03-15'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Beth'</span>, <span class="hljs-string">'Burch'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-03-16'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> employees (first_name, last_name, department_id, joining_date) <span class="hljs-keyword">values</span> (<span class="hljs-string">'Essa'</span>, <span class="hljs-string">'Gebhardt'</span>, <span class="hljs-number">2</span>, <span class="hljs-string">'2021-03-22'</span>);

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">134.51</span>, <span class="hljs-string">'2021-04-20'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">71.18</span>, <span class="hljs-string">'2021-03-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">756.75</span>, <span class="hljs-string">'2021-03-04'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">84.88</span>, <span class="hljs-string">'2021-03-11'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">115.41</span>, <span class="hljs-string">'2021-03-18'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">56.15</span>, <span class="hljs-string">'2021-03-04'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">771.54</span>, <span class="hljs-string">'2021-04-27'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65.9</span>, <span class="hljs-string">'2021-04-26'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">281.28</span>, <span class="hljs-string">'2021-04-20'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">72.35</span>, <span class="hljs-string">'2021-03-09'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">62.28</span>, <span class="hljs-string">'2021-04-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">137.1</span>, <span class="hljs-string">'2021-04-13'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">61.91</span>, <span class="hljs-string">'2021-05-01'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">389.08</span>, <span class="hljs-string">'2021-04-27'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">46.78</span>, <span class="hljs-string">'2021-03-30'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">81.24</span>, <span class="hljs-string">'2021-03-29'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">177.91</span>, <span class="hljs-string">'2021-04-26'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">114.13</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">146.22</span>, <span class="hljs-string">'2021-04-29'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">144.58</span>, <span class="hljs-string">'2021-03-11'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">150.95</span>, <span class="hljs-string">'2021-04-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">122.52</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-number">4</span>, <span class="hljs-number">86.35</span>, <span class="hljs-string">'2021-04-28'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">148.5</span>, <span class="hljs-string">'2021-03-29'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">442.45</span>, <span class="hljs-string">'2021-03-21'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">93.41</span>, <span class="hljs-string">'2021-03-18'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">51.72</span>, <span class="hljs-string">'2021-03-23'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">138.73</span>, <span class="hljs-string">'2021-04-10'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-number">2</span>, <span class="hljs-number">46.89</span>, <span class="hljs-string">'2021-03-13'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">551.32</span>, <span class="hljs-string">'2021-04-01'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">62.44</span>, <span class="hljs-string">'2021-04-28'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">95.08</span>, <span class="hljs-string">'2021-04-13'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-number">2</span>, <span class="hljs-number">56.33</span>, <span class="hljs-string">'2021-03-28'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">146.43</span>, <span class="hljs-string">'2021-04-08'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">43.98</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">124.71</span>, <span class="hljs-string">'2021-03-03'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">41.12</span>, <span class="hljs-string">'2021-04-14'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">102.71</span>, <span class="hljs-string">'2021-04-22'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">94.0</span>, <span class="hljs-string">'2021-03-29'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-number">2</span>, <span class="hljs-number">46.05</span>, <span class="hljs-string">'2021-04-08'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-number">2</span>, <span class="hljs-number">95.15</span>, <span class="hljs-string">'2021-04-04'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">81.07</span>, <span class="hljs-string">'2021-03-26'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">112.0</span>, <span class="hljs-string">'2021-03-23'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">147.27</span>, <span class="hljs-string">'2021-04-18'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">47.96</span>, <span class="hljs-string">'2021-05-01'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">129.75</span>, <span class="hljs-string">'2021-03-05'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">95.6</span>, <span class="hljs-string">'2021-03-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">98.88</span>, <span class="hljs-string">'2021-03-13'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">91.24</span>, <span class="hljs-string">'2021-05-01'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">47.64</span>, <span class="hljs-string">'2021-03-14'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">773.39</span>, <span class="hljs-string">'2021-04-22'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">115.93</span>, <span class="hljs-string">'2021-04-25'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">86.04</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">53.06</span>, <span class="hljs-string">'2021-03-07'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">141.01</span>, <span class="hljs-string">'2021-04-02'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">41.77</span>, <span class="hljs-string">'2021-04-05'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">63.59</span>, <span class="hljs-string">'2021-04-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">71.02</span>, <span class="hljs-string">'2021-04-29'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">49.68</span>, <span class="hljs-string">'2021-04-18'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">909.59</span>, <span class="hljs-string">'2021-04-06'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-number">4</span>, <span class="hljs-number">954.25</span>, <span class="hljs-string">'2021-04-25'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">121.98</span>, <span class="hljs-string">'2021-03-03'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">108.31</span>, <span class="hljs-string">'2021-03-11'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">96.56</span>, <span class="hljs-string">'2021-03-04'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">15</span>, <span class="hljs-number">3</span>, <span class="hljs-number">140.92</span>, <span class="hljs-string">'2021-03-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">239.05</span>, <span class="hljs-string">'2021-03-20'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">14</span>, <span class="hljs-number">2</span>, <span class="hljs-number">72.51</span>, <span class="hljs-string">'2021-03-27'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-number">4</span>, <span class="hljs-number">591.58</span>, <span class="hljs-string">'2021-03-25'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">646.08</span>, <span class="hljs-string">'2021-04-13'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">116.68</span>, <span class="hljs-string">'2021-04-22'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">109.93</span>, <span class="hljs-string">'2021-04-16'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">42.47</span>, <span class="hljs-string">'2021-04-07'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">146.0</span>, <span class="hljs-string">'2021-03-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">94.43</span>, <span class="hljs-string">'2021-04-20'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-number">4</span>, <span class="hljs-number">152.56</span>, <span class="hljs-string">'2021-03-31'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">60.98</span>, <span class="hljs-string">'2021-03-23'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">78.66</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">15</span>, <span class="hljs-number">1</span>, <span class="hljs-number">152.08</span>, <span class="hljs-string">'2021-03-28'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">58.16</span>, <span class="hljs-string">'2021-03-24'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">62.87</span>, <span class="hljs-string">'2021-03-09'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">79.71</span>, <span class="hljs-string">'2021-04-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">249.22</span>, <span class="hljs-string">'2021-03-10'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">378.52</span>, <span class="hljs-string">'2021-04-23'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">142.84</span>, <span class="hljs-string">'2021-03-10'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">63.81</span>, <span class="hljs-string">'2021-04-18'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">12</span>, <span class="hljs-number">4</span>, <span class="hljs-number">106.42</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">13</span>, <span class="hljs-number">5</span>, <span class="hljs-number">82.64</span>, <span class="hljs-string">'2021-04-19'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">120.39</span>, <span class="hljs-string">'2021-04-02'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">244.59</span>, <span class="hljs-string">'2021-04-07'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">50.45</span>, <span class="hljs-string">'2021-03-10'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">44.8</span>, <span class="hljs-string">'2021-03-28'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">104.68</span>, <span class="hljs-string">'2021-04-05'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">136.04</span>, <span class="hljs-string">'2021-03-05'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">113.32</span>, <span class="hljs-string">'2021-03-04'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">11</span>, <span class="hljs-number">4</span>, <span class="hljs-number">128.12</span>, <span class="hljs-string">'2021-03-31'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">9</span>, <span class="hljs-number">4</span>, <span class="hljs-number">576.22</span>, <span class="hljs-string">'2021-04-27'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">127.25</span>, <span class="hljs-string">'2021-03-22'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">129.69</span>, <span class="hljs-string">'2021-03-12'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">116.48</span>, <span class="hljs-string">'2021-03-24'</span>);
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> department_expenses (employee_id, department_id, expense_amount, expense_date) <span class="hljs-keyword">values</span> (<span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">144.76</span>, <span class="hljs-string">'2021-04-02'</span>);
</code></pre>
<p>The above script will create a table and populate with data for the examples in this post.</p>
<h2 id="heading-basic-cte-example">Basic CTE Example</h2>
<p>We wanted to return the department name as department_name, total expenses of the departments as total_expenses for each department</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> department_expenditures <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        d.name,
        <span class="hljs-keyword">sum</span>(de.expense_amount) <span class="hljs-keyword">as</span> total_expenses
    <span class="hljs-keyword">from</span> departments d
    <span class="hljs-keyword">join</span> department_expenses de
        <span class="hljs-keyword">on</span> d.id = de.department_id
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> d.name
)

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department_expenditures;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647655805789/1Hy26fHh8.PNG" alt="basic cte example.PNG" /></p>
<p>With the definition of department_expenditure CTE as name and CTE query inside the parenthesis, we return the required data set i.e. name of each department and their total expenses. This is the most basic example of CTE implementation.</p>
<h2 id="heading-cte-with-columns">CTE with columns</h2>
<p>As mentioned earlier the alternative syntax is a CTE definition with a column list before the parenthesis of the CTE query. The only change is that an extra pair of parenthesis is added before the parathesis of the CTE inner query part. The columns list mentioned are the columns we want our CTE definition to have and we need to construct our CTE query based on these columns we are returning. The column name part is optional and not mandatory, as we did in the above illustration. But we need to use it when we have to return aggregate or analytic function values, we want to use it in another nested or recursive CTE, or even when we want to refer to the values of these functions in the outer query part. We can always use an alias as did in the previous example snippet and not use a column list in the CTE definition, either way, is fine. We will update the above code snippets, to use a column list with a CTE definition.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> department_expenditures (department_name, total_expenses) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        d.name,
        <span class="hljs-keyword">sum</span>(de.expense_amount)
    <span class="hljs-keyword">from</span> departments d
    <span class="hljs-keyword">join</span> department_expenses de
        <span class="hljs-keyword">on</span> d.id = de.department_id
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> d.name
)

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department_expenditures;
</code></pre>
<p>Now let's modify the return required a little, we only wanted to return those departments who had made total expenses more than 75 percent of their allotted petty cash amount. So we wanted to return those departments that made total expenses more than 75 percent of their allotted petty cash amount.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> department_expenditures (department_name, total_expenses) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        d.name,
        <span class="hljs-keyword">sum</span>(de.expense_amount)
    <span class="hljs-keyword">from</span> departments d
    <span class="hljs-keyword">join</span> department_expenses de
        <span class="hljs-keyword">on</span> d.id = de.department_id
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> d.name, d.petty_cash_alloted
    <span class="hljs-keyword">having</span> <span class="hljs-keyword">sum</span>(de.expense_amount) &gt; d.petty_cash_alloted * <span class="hljs-number">0.75</span>
)

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> department_expenditures;
</code></pre>
<p>The above query will return those department names and their total expenses whose total expenses have crossed more than 75 percent of the allotted petty cash to them. In the above case, all department names and their amount will be returned as all departments have crossed the limit of expenditure.</p>
<h2 id="heading-multiple-ctes">Multiple CTEs</h2>
<p>These CTE are separated by commas and commas should not be given at the end of the CTE. The WITH keyword will be mentioned only once during the start of the CTE definition. This comma-separated multiple CTE makes sense when we have to refer to the return of one CTE in another CTE and so on. For multiple CTE we need to do set-based operations like UNION, UNION ALL, etc. Let's see an example. We wanted to show the list of employees who had made expenses of more than 1.5 times the allotted petty cash amount of both the accounting and cleaning departments.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> accounting_department_expenditure (first_name, last_name, department_name, total_expenses) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        e.first_name,
        e.last_name,
        d.name,
        <span class="hljs-keyword">sum</span>(de.expense_amount)
    <span class="hljs-keyword">from</span> employees e
    <span class="hljs-keyword">join</span> departments d
        <span class="hljs-keyword">on</span> e.department_id = d.id
    <span class="hljs-keyword">join</span> department_expenses de
        <span class="hljs-keyword">on</span> de.employee_id = e.id
        <span class="hljs-keyword">and</span> de.department_id = d.id
    <span class="hljs-keyword">where</span> d.name = <span class="hljs-string">'accounting'</span>
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> e.first_name, e.last_name, d.name, d.petty_cash_alloted
    <span class="hljs-keyword">having</span> <span class="hljs-keyword">sum</span>(de.expense_amount) &gt; <span class="hljs-number">1.5</span> * d.petty_cash_alloted
), cleaning_department_expenditure (first_name, last_name, department_name, total_expenses) <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span>
        e.first_name,
        e.last_name,
        d.name,
        <span class="hljs-keyword">sum</span>(de.expense_amount)
    <span class="hljs-keyword">from</span> employees e
    <span class="hljs-keyword">join</span> departments d
        <span class="hljs-keyword">on</span> e.department_id = d.id
    <span class="hljs-keyword">join</span> department_expenses de
        <span class="hljs-keyword">on</span> de.employee_id = e.id
        <span class="hljs-keyword">and</span> de.department_id = d.id
    <span class="hljs-keyword">where</span> d.name = <span class="hljs-string">'cleaning staff'</span>
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> e.first_name, e.last_name, d.name, d.petty_cash_alloted
    <span class="hljs-keyword">having</span> <span class="hljs-keyword">sum</span>(de.expense_amount) &gt; <span class="hljs-number">1.5</span> * d.petty_cash_alloted
)

<span class="hljs-keyword">select</span>  
    first_name, 
    last_name, 
    department_name, 
    total_expenses
<span class="hljs-keyword">from</span> accounting_department_expenditure
<span class="hljs-keyword">union</span> <span class="hljs-keyword">all</span>
<span class="hljs-keyword">select</span>
    first_name, 
    last_name, 
    department_name, 
    total_expenses
<span class="hljs-keyword">from</span> cleaning_department_expenditure;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647658785491/VI3HN91nh.PNG" alt="multple cte example.PNG" /></p>
<p>After defining both CTEs we will show the result of those, together with the SET operator in the outer query, here we are using UNION ALL. This will output by combining the output of the above two CTE definitions as in the image above. Do remember that it is not possible to create correlated subqueries with CTEs.</p>
<h2 id="heading-summary">Summary</h2>
<ol>
<li><p>CTEs are named temporary sets of rows similar to subqueries.</p>
</li>
<li><p>CTEs are placed at the start of the query. They are introduced with WITH.</p>
</li>
<li><p>You can skip column definitions if you provide aliases for columns containing aggregates and other function results.</p>
</li>
<li><p>Not possible to create correlated subqueries with CTEs.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[SQL Server implementing Concurrency with RowVersion Data Type]]></title><description><![CDATA[In the previous post, we tried to understand transactions and concurrency in SQL Server. We also looked into the problems occurring with concurrent transactions from multiple session instances. To understand it in layman's terms an example is when ma...]]></description><link>https://mssqlserver.dev/sql-server-implementing-concurrency-with-rowversion-data-type</link><guid isPermaLink="true">https://mssqlserver.dev/sql-server-implementing-concurrency-with-rowversion-data-type</guid><category><![CDATA[SQL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[Databases]]></category><category><![CDATA[MSSQL]]></category><dc:creator><![CDATA[kiran sabne]]></dc:creator><pubDate>Sat, 05 Mar 2022 05:28:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1647408423029/GEEys1KJ2.PNG" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous post, we tried to understand transactions and concurrency in SQL Server. We also looked into the problems occurring with concurrent transactions from multiple session instances. To understand it in layman's terms an example is when many users are trying to access the same data set of the same object, some for reading the data, some for manipulating the data, etc at the same time. These concurrent reads write operations can lead to data inconsistency and unexpected results. We also dived into Optimistic and Pessimistic Approaches to understand ways to tackle the concurrency problems. Optimistic Concurrency is implemented using the row versioning technique and it doesn't block concurrent read and write requests from multiple session instances. However do note that in the Optimistic approach, the write operation will still block other write operations. This post is to understand and implement row version data types in SQL Server. ' Rowversion is auto-generated unique binary numbers within the database and is generally used to version-stamp rows in tables. Each database has its counter which gets incremented when any manipulation operations are performed on a table that has a rowversion column. A table can have only one rowversion column and with every insertion or updation of the rows in the table, the incremented database rowversion value is inserted in the rowversion column. Hence rowversion columns should not be used as keys. Even if the actual value of the attribute of the table entity is not changed, the counter will still increment the rowversion column due to the update operation. To understand, supposing you have a row in the table with a column having a value of 2 and you perform the update operation on that row and again assign the value 2 to that column, the rowversion counter will still be incremented. To check the current value of the counter, we can use the below select query, which returns the current counter value.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> @@DBTS;
</code></pre>
<h2 id="heading-create-a-table-with-rowversion-column">Create a table with rowversion column</h2>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">database</span> TestDB;
<span class="hljs-keyword">use</span> TestDB;
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> products(
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">int</span> <span class="hljs-keyword">identity</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>) primary <span class="hljs-keyword">key</span>,
    product_id <span class="hljs-built_in">int</span>,
    category_id <span class="hljs-built_in">int</span>,
    price <span class="hljs-built_in">decimal</span>(<span class="hljs-number">6</span>,<span class="hljs-number">2</span>),
    last_changed rowversion <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span> <span class="hljs-comment">--column for rowversion</span>
);

<span class="hljs-keyword">select</span> @@DBTS <span class="hljs-keyword">as</span> <span class="hljs-string">'Before insert in products table'</span>;

<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> products(product_id, category_id, price) <span class="hljs-keyword">values</span> (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">109.23</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">450.78</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">890.99</span>);

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> products; <span class="hljs-comment">-- returns all the rows in table</span>

<span class="hljs-keyword">select</span> @@DBTS <span class="hljs-keyword">as</span> <span class="hljs-string">'After insert in products table'</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647408423029/GEEys1KJ2.PNG" alt="dbts change and inserts.PNG" /></p>
<p>The above image depicts the counter value before the start of the insert and after the insert operations, which incremented with the 3 inserts we made after creating the table. At the start, the counter value was 0x00000000000007D0 and after 3 insert operations, the counter current value is 0x00000000000007D3.</p>
<p>Now we will demonstrate update operations, in both cases wherein we change the column value of one row and not of the column in another row, to see if the rowversion value gets updated.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span> <span class="hljs-keyword">transaction</span>;
<span class="hljs-keyword">select</span> @@DBTS;
<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> products;

<span class="hljs-keyword">update</span> products <span class="hljs-keyword">set</span> price = <span class="hljs-number">100</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>; <span class="hljs-comment">-- update which actually change the price from 109.23 to 100,</span>
<span class="hljs-keyword">update</span> products <span class="hljs-keyword">set</span> price = <span class="hljs-number">450.78</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">2</span>; <span class="hljs-comment">-- update which sets same price as before;</span>

<span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> products;
<span class="hljs-keyword">select</span> @@DBTS;
<span class="hljs-keyword">commit</span> <span class="hljs-keyword">transaction</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647408469707/ap30khX-V.PNG" alt="update operation on table having rowversion column.PNG" /></p>
<p>As you can see in the above image, we had a rowversion counter value of 0x00000000000007D3 before any update operation. We had two select statements in the transaction to show last_changed column values before and after update statements. Before the update operation, the last_changed value of the rows were 0x00000000000007D1 and 0x00000000000007D2. After the update operation last_changed value which is rowversion counter also updated to 0x00000000000007D4 and 0x00000000000007D5. The rowversion counter i.e. our last_changed column value updated even if there was no actual change in our price during the update.</p>
<h2 id="heading-using-rowversion-in-sql-server-for-concurrency">Using ROWVERSION in SQL Server for Concurrency</h2>
<p>In this part, we will see how to implement and use the rowversion of the table for concurrent requests. We will use the same table we created above. Now the scenario is that in the transaction - 1 we will be performing the update on our product table having the id value 1, but after simulating time delay depicting some other work. During that time transaction - 2 will also update the same product having id value 1 and commit the transaction. After transaction 2 commits, and after completing complex work in the transaction - 1, we will again try to update our product with the same id. Below is a demonstration of the above case.</p>
<p>-- transaction - 1</p>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span> <span class="hljs-keyword">transaction</span>;
<span class="hljs-keyword">declare</span> @last_changed rowversion;

<span class="hljs-keyword">select</span> @last_changed = last_changed 
<span class="hljs-keyword">from</span> products
<span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>; <span class="hljs-comment">-- returning last_changed value in @last_changed variable.</span>

waitfor delay '00:00:20'; <span class="hljs-comment">-- simulate time delay to depeict work process.</span>

<span class="hljs-keyword">update</span> products
<span class="hljs-keyword">set</span> price = <span class="hljs-number">50</span>
<span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span> 
<span class="hljs-keyword">and</span> last_changed = @last_changed; <span class="hljs-comment">-- update statement runnig after transation 2 updates the price to something else.</span>

if @@ROWCOUNT == 0 
<span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exists</span>(<span class="hljs-keyword">select</span> <span class="hljs-number">1</span> <span class="hljs-keyword">from</span> products <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>)
    <span class="hljs-keyword">begin</span>
        print <span class="hljs-string">'The data was deleted by other session. Try again with updated records.'</span>;
        <span class="hljs-keyword">rollback</span> <span class="hljs-keyword">transaction</span>;
    <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">else</span> 
    <span class="hljs-keyword">begin</span>
        print <span class="hljs-string">'The data row was updated by some other sessions. Try again with updated records.'</span>
        <span class="hljs-keyword">rollback</span> <span class="hljs-keyword">transaction</span>;
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
<span class="hljs-keyword">else</span> 
<span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">commit</span> <span class="hljs-keyword">transaction</span>;
<span class="hljs-keyword">end</span>
</code></pre>
<p>In another tab or session of the management, studio try to run the below update query transaction</p>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span> <span class="hljs-keyword">transaction</span>

<span class="hljs-keyword">update</span> products 
<span class="hljs-keyword">set</span> price = <span class="hljs-number">70</span> 
<span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;

<span class="hljs-keyword">commit</span> <span class="hljs-keyword">transaction</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1647408501181/B0sRAo0UO.PNG" alt="sql concurrent updates with row version data type.PNG" /></p>
<p>When we execute the above two scripts in different tabs or sessions of management studio, the transaction - 2 commits and closes and the transaction - 1 rollback's and we get the message which we directed to print. It shows that since the row is updated by another session, transaction - 1 fails to update the row as it was holding an older value of the rowversion in variable and when transaction - 2 updates the same row, the rowversion counter auto-incremented. Hence while updating the row in the transaction - 1 we don't find the row and it print's the instructed statement as output and rollbacks. We can leverage the rowversion counter as used in the above illustration to solve concurrent transaction problems.</p>
]]></content:encoded></item></channel></rss>