<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DML &#8211; SQLpowered.com</title>
	<atom:link href="https://sqlpowered.com/command-category/dml/feed/" rel="self" type="application/rss+xml" />
	<link>https://sqlpowered.com</link>
	<description>SQL Server + BI</description>
	<lastBuildDate>Mon, 05 Oct 2026 17:02:17 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://sqlpowered.com/wp-content/uploads/2020/07/FavIcon-e1594067873682-99x100.png</url>
	<title>DML &#8211; SQLpowered.com</title>
	<link>https://sqlpowered.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>MERGE</title>
		<link>https://sqlpowered.com/t-sql-commands/merge/</link>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Fri, 31 Dec 2021 20:20:41 +0000</pubDate>
				<category><![CDATA[T-SQLpowered]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?post_type=t-sql-commands&#038;p=5298</guid>

					<description><![CDATA[Using OUTPUT clause: MERGE INTO [dbo].[TargetTable] [trg] USING ( SELECT [ID], [Value], [OtherValue] FROM [dbo].[SourceTable] ) AS [src] ON 1 = 0 WHEN NOT MATCHED THEN INSERT ( [ID],[Value] ) VALUES ([src].[ID], [src].[Value]) OUTPUT [Inserted].[ID], [Inserted].[Value], [src].[OtherValue] &#160;]]></description>
										<content:encoded><![CDATA[<p>Using OUTPUT clause:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">MERGE INTO [dbo].[TargetTable] [trg]
USING ( SELECT [ID], [Value], [OtherValue]
		FROM [dbo].[SourceTable]
	  ) AS [src] ON 1 = 0
WHEN NOT MATCHED THEN
	INSERT ( [ID],[Value] )
	VALUES ([src].[ID], [src].[Value])
		OUTPUT [Inserted].[ID], [Inserted].[Value], [src].[OtherValue]</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>UPDATE</title>
		<link>https://sqlpowered.com/t-sql-commands/update/</link>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Fri, 31 Dec 2021 20:09:38 +0000</pubDate>
				<category><![CDATA[T-SQLpowered]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?post_type=t-sql-commands&#038;p=5293</guid>

					<description><![CDATA[Examples for SQL Server 2025. Each block is a separate example. Replace the table and column names as needed; Id is assumed to be unique. Basics Values and expressions Large strings and binary data Values from another source Conditions and changed values CTEs and batches OUTPUT and variables SQL Server...]]></description>
										<content:encoded><![CDATA[<p>Examples for SQL Server 2025. Each block is a separate example. Replace the table and column names as needed; Id is assumed to be unique.</p>
<ul>
<li><a href="#update-basics">Basics</a></li>
<li><a href="#update-values">Values and expressions</a></li>
<li><a href="#update-large-values">Large strings and binary data</a></li>
<li><a href="#update-sources">Values from another source</a></li>
<li><a href="#update-filters">Conditions and changed values</a></li>
<li><a href="#update-batches">CTEs and batches</a></li>
<li><a href="#update-output">OUTPUT and variables</a></li>
<li><a href="#update-2025">SQL Server 2025</a></li>
<li><a href="#update-json-xml">JSON and XML</a></li>
<li><a href="#update-targets">Other update targets</a></li>
<li><a href="#update-transactions">Transactions and concurrency</a></li>
<li><a href="#update-other">Other forms</a></li>
</ul>
<h2 id="update-basics">Basics</h2>
<p>Update one row by its Id:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;</pre>
<p>Update multiple columns in one statement:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value',
	[Col2] = NULL
WHERE [Id] = 1;</pre>
<p>Update all rows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Status] = N'Archived';</pre>
<p>Update using a variable:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT = 1;
DECLARE @NewValue NVARCHAR(100) = N'New Value';

UPDATE [dbo].[SampleTable]
SET [Col1] = @NewValue
WHERE [Id] = @Id;</pre>
<p>Set a column to NULL or its default value:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- NULL
UPDATE [dbo].[SampleTable]
SET [Col1] = NULL
WHERE [Id] = 1;

-- column default
UPDATE [dbo].[SampleTable]
SET [Status] = DEFAULT
WHERE [Id] = 1;</pre>
<h2 id="update-values">Values and expressions</h2>
<p>Set a value using CASE:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Status] = CASE
	WHEN [Quantity] &lt;= 0 THEN N'Empty'
	WHEN [Quantity] &lt; 10 THEN N'Low'
	ELSE N'Available'
END;</pre>
<p>Increase or decrease a numeric value:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- add
UPDATE [dbo].[SampleTable]
SET [Value] += 10
WHERE [Id] = 1;

-- subtract
UPDATE [dbo].[SampleTable]
SET [Value] -= 5
WHERE [Id] = 1;

-- multiply
UPDATE [dbo].[SampleTable]
SET [Value] *= 1.10
WHERE [Id] = 1;

-- divide
UPDATE [dbo].[SampleTable]
SET [Value] /= 2
WHERE [Id] = 1;

-- remainder (integer column)
UPDATE [dbo].[SampleTable]
SET [Quantity] %= 10
WHERE [Id] = 1;</pre>
<p>Set, clear or toggle a bit flag:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- set flag 4
UPDATE [dbo].[SampleTable]
SET [Flags] |= 4
WHERE [Id] = 1;

-- clear flag 4
UPDATE [dbo].[SampleTable]
SET [Flags] &amp;= ~4
WHERE [Id] = 1;

-- toggle flag 4
UPDATE [dbo].[SampleTable]
SET [Flags] ^= 4
WHERE [Id] = 1;</pre>
<p>Replace NULL values with a fallback:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Value] = COALESCE([Value], 0)
WHERE [Value] IS NULL;</pre>
<p>Replace text or append a suffix:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- replace text
UPDATE [dbo].[SampleTable]
SET [TextValue] = REPLACE([TextValue], N'Old', N'New')
WHERE [Id] = 1;

-- append text, treating NULL as empty text
UPDATE [dbo].[SampleTable]
SET [TextValue] = CONCAT([TextValue], N' suffix')
WHERE [Id] = 1;</pre>
<p>Add one day or store the current UTC time:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- add one day
UPDATE [dbo].[SampleTable]
SET [DueDate] = DATEADD(DAY, 1, [DueDate])
WHERE [Id] = 1;

-- UTC timestamp
UPDATE [dbo].[SampleTable]
SET [ModifiedAt] = SYSUTCDATETIME()
WHERE [Id] = 1;</pre>
<p>Swap values between two columns:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Col1] = [Col2],
	[Col2] = [Col1]
WHERE [Id] = 1;</pre>
<p>Convert text to a number:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Quantity] = TRY_CONVERT(INT, [TextValue])
WHERE [Id] = 1;</pre>
<p>Invalid numeric text returns NULL. Quantity must allow NULL.</p>
<p>Replace part of a normal string using STUFF:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Col1] = STUFF([Col1], 1, 3, N'New')
WHERE [Id] = 1;</pre>
<p>STUFF starts at 1. This replaces the first three characters and also works with non-MAX string columns.</p>
<p>Update with the expression:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable] SET [Col1] = @a + @b + @c
</pre>
<h2 id="update-large-values">Large strings and binary data</h2>
<p>.WRITE() works with VARCHAR(MAX), NVARCHAR(MAX) and VARBINARY(MAX). The value must not be NULL. Offsets start at 0: bytes for VARCHAR/VARBINARY and UTF-16 units for NVARCHAR. TextValue in these examples is NVARCHAR(MAX).</p>
<p>Update using the .WRITE() clause:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable] SET [Col1].WRITE('New Value', 0, NULL)
UPDATE [dbo].[SampleTable] SET [Col1].WRITE(@a + @b + @c, 0, NULL)
UPDATE [dbo].[SampleTable] SET [Col1].WRITE(@x, 500, 1000)</pre>
<p>Append text using .WRITE():</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(N' appended text', NULL, 0)
WHERE [Id] = 1;</pre>
<p>Insert text at the beginning using .WRITE():</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(N'Prefix: ', 0, 0)
WHERE [Id] = 1;</pre>
<p>Replace or remove part of a value using .WRITE():</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- replace the first 3 UTF-16 units
UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(N'New', 0, 3)
WHERE [Id] = 1;

-- remove the first 3 UTF-16 units
UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(N'', 0, 3)
WHERE [Id] = 1;</pre>
<p>Truncate a value or replace everything after an offset:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- keep the first 5 UTF-16 units
UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(NULL, 5, 0)
WHERE [Id] = 1;

-- replace everything after the first 5 UTF-16 units
UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(N'New ending', 5, NULL)
WHERE [Id] = 1;</pre>
<p>The offset must not exceed the current value length.</p>
<p>Initialize a NULL value before using .WRITE():</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [TextValue] = N''
WHERE [Id] = 1
	AND [TextValue] IS NULL;

UPDATE [dbo].[SampleTable]
SET [TextValue].WRITE(N'New Value', NULL, 0)
WHERE [Id] = 1;</pre>
<p>Replace or append binary data:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- BinaryData is VARBINARY(MAX)
UPDATE [dbo].[SampleTable]
SET [BinaryData] = 0x01020304
WHERE [Id] = 1;

UPDATE [dbo].[SampleTable]
SET [BinaryData].WRITE(0x0506, NULL, 0)
WHERE [Id] = 1;</pre>
<p>Read a file into a binary column:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [BinaryData] = (
	SELECT [BulkColumn]
	FROM OPENROWSET(
		BULK N'C:\Data\Sample.bin',
		SINGLE_BLOB
	) AS [f]
)
WHERE [Id] = 1;</pre>
<p>The file path is on the SQL Server host. Requires bulk-read permission and file access.</p>
<p>Replace or clear FILESTREAM data:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- FileData is a VARBINARY(MAX) FILESTREAM column
UPDATE [dbo].[SampleTable]
SET [FileData] = 0x01020304
WHERE [Id] = 1;

UPDATE [dbo].[SampleTable]
SET [FileData] = NULL
WHERE [Id] = 1;</pre>
<p>FILESTREAM does not support partial updates with .WRITE(). FileData must allow NULL for the second example.</p>
<h2 id="update-sources">Values from another source</h2>
<p>Update using values from another table:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = [s].[Col1]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN [dbo].[SourceTable] AS [s]
	ON [s].[Id] = [t].[Id];</pre>
<p>The source must provide at most one matching row for each target row; otherwise the chosen source value is undefined.</p>
<p>Keep the current value when a LEFT JOIN has no match:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = CASE
	WHEN [s].[Id] IS NULL THEN [t].[Col1]
	ELSE [s].[Col1]
END
FROM [dbo].[SampleTable] AS [t]
LEFT JOIN [dbo].[SourceTable] AS [s]
	ON [s].[Id] = [t].[Id];</pre>
<p>Source Id must be unique. A matched source row containing NULL still sets Col1 to NULL.</p>
<p>Update from another row in the same table:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [child]
SET [ParentName] = [parent].[Name]
FROM [dbo].[SampleTable] AS [child]
INNER JOIN [dbo].[SampleTable] AS [parent]
	ON [parent].[Id] = [child].[ParentId];</pre>
<p>Update using a correlated subquery:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = (
	SELECT [s].[Col1]
	FROM [dbo].[SourceTable] AS [s]
	WHERE [s].[Id] = [t].[Id]
)
FROM [dbo].[SampleTable] AS [t];</pre>
<p>No matching row returns NULL. More than one matching row raises an error.</p>
<p>Update using aggregated source values:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [TotalAmount] = [s].[TotalAmount]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN (
	SELECT
		[SampleId],
		SUM([Amount]) AS [TotalAmount]
	FROM [dbo].[SourceTable]
	GROUP BY [SampleId]
) AS [s]
	ON [s].[SampleId] = [t].[Id];</pre>
<p>Update multiple rows with different values using VALUES:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = [s].[Col1]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN (VALUES
	(1, N'First value'),
	(2, N'Second value'),
	(3, N'Third value')
) AS [s] ([Id], [Col1])
	ON [s].[Id] = [t].[Id];</pre>
<p>Use each Id once in the VALUES list.</p>
<p>Update using the latest matching source row:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = [s].[Col1]
FROM [dbo].[SampleTable] AS [t]
CROSS APPLY (
	SELECT TOP (1)
		[src].[Col1]
	FROM [dbo].[SourceTable] AS [src]
	WHERE [src].[SampleId] = [t].[Id]
	ORDER BY [src].[ModifiedAt] DESC, [src].[Id] DESC
) AS [s];</pre>
<p>Source Id must be unique to break timestamp ties. CROSS APPLY skips targets with no match.</p>
<p>Update using a JSON array of changes:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Changes NVARCHAR(MAX) =
	N'[{"Id":1,"Col1":"First value"},{"Id":2,"Col1":"Second value"}]';

UPDATE [t]
SET [Col1] = [s].[Col1]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN OPENJSON(@Changes)
WITH
(
	[Id] INT '$.Id',
	[Col1] NVARCHAR(100) '$.Col1'
) AS [s]
	ON [s].[Id] = [t].[Id];</pre>
<p>Use one JSON item per Id. OPENJSON requires compatibility level 130 or higher.</p>
<p>Update from a table-valued parameter:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- create once
CREATE TYPE [dbo].[utt_UpdateValues] AS TABLE
(
	[Id] INT NOT NULL PRIMARY KEY,
	[Col1] NVARCHAR(100) NULL
);
GO

CREATE OR ALTER PROCEDURE [dbo].[p_UpdateValues]
	@Changes [dbo].[utt_UpdateValues] READONLY
AS
BEGIN
	SET NOCOUNT ON;

	UPDATE [t]
	SET [Col1] = [s].[Col1]
	FROM [dbo].[SampleTable] AS [t]
	INNER JOIN @Changes AS [s]
		ON [s].[Id] = [t].[Id];
END;
GO

DECLARE @Changes [dbo].[utt_UpdateValues];

INSERT INTO @Changes ([Id], [Col1])
VALUES (1, N'First value'), (2, N'Second value');

EXEC [dbo].[p_UpdateValues] @Changes = @Changes;</pre>
<h2 id="update-filters">Conditions and changed values</h2>
<p>Update only changed values, including NULL (SQL Server 2022+):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @NewValue NVARCHAR(100) = N'New Value';

UPDATE [dbo].[SampleTable]
SET [Col1] = @NewValue
WHERE [Id] = 1
	AND [Col1] IS DISTINCT FROM @NewValue;</pre>
<p>IS DISTINCT FROM also detects changes to or from NULL.</p>
<p>Update a list of Ids:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Status] = N'Archived'
WHERE [Id] IN (1, 2, 3);</pre>
<p>Update rows from a date range:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @FromDate DATE = '20250101';
DECLARE @ToDate DATE = '20250201';

UPDATE [dbo].[SampleTable]
SET [Status] = N'Archived'
WHERE [CreatedAt] &gt;= @FromDate
	AND [CreatedAt] &lt; @ToDate;</pre>
<p>Includes January 2025. The upper boundary is excluded.</p>
<p>Update rows containing NULL or matching a text pattern:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- NULL values
UPDATE [dbo].[SampleTable]
SET [Col1] = N'Unknown'
WHERE [Col1] IS NULL;

-- text pattern
UPDATE [dbo].[SampleTable]
SET [Status] = N'Archived'
WHERE [Name] LIKE N'Old%';</pre>
<p>Update rows with or without a matching source row:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- matching source row
UPDATE [t]
SET [Status] = N'Matched'
FROM [dbo].[SampleTable] AS [t]
WHERE EXISTS (
	SELECT 1
	FROM [dbo].[SourceTable] AS [s]
	WHERE [s].[Id] = [t].[Id]
);

-- no matching source row
UPDATE [t]
SET [Status] = N'Missing'
FROM [dbo].[SampleTable] AS [t]
WHERE NOT EXISTS (
	SELECT 1
	FROM [dbo].[SourceTable] AS [s]
	WHERE [s].[Id] = [t].[Id]
);</pre>
<p>Update only when at least one column changed (SQL Server 2022+):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = [s].[Col1],
	[Col2] = [s].[Col2]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN [dbo].[SourceTable] AS [s]
	ON [s].[Id] = [t].[Id]
WHERE [t].[Col1] IS DISTINCT FROM [s].[Col1]
	OR [t].[Col2] IS DISTINCT FROM [s].[Col2];</pre>
<p>Source Id must be unique. NULL values are compared too.</p>
<h2 id="update-batches">CTEs and batches</h2>
<p>Update the next 100 pending rows selected by Id:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">;WITH [Batch] AS
(
	SELECT TOP (100)
		[Id],
		[Status]
	FROM [dbo].[SampleTable]
	WHERE [Status] = N'Pending'
	ORDER BY [Id]
)
UPDATE [Batch]
SET [Status] = N'Processed';</pre>
<p>Assumes Id is unique. ORDER BY selects the batch; it does not guarantee modification order. UPDATE TOP (100) alone does not define which qualifying rows are selected.</p>
<p>Update a filtered CTE:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">;WITH [RowsToUpdate] AS
(
	SELECT [Id], [Status]
	FROM [dbo].[SampleTable]
	WHERE [Status] = N'Pending'
)
UPDATE [RowsToUpdate]
SET [Status] = N'Ready';</pre>
<p>Store row numbers in a column:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">;WITH [NumberedRows] AS
(
	SELECT
		[Id],
		ROW_NUMBER() OVER (ORDER BY [Id]) AS [SequenceNo]
	FROM [dbo].[SampleTable]
)
UPDATE [t]
SET [SequenceNo] = [s].[SequenceNo]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN [NumberedRows] AS [s]
	ON [s].[Id] = [t].[Id];</pre>
<p>Id must be unique. ROW_NUMBER returns BIGINT.</p>
<p>Mark the latest row in each group:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">;WITH [RankedRows] AS
(
	SELECT
		[Id],
		ROW_NUMBER() OVER (
			PARTITION BY [GroupId]
			ORDER BY [CreatedAt] DESC, [Id] DESC
		) AS [RowNo]
	FROM [dbo].[SampleTable]
)
UPDATE [t]
SET [IsLatest] = CASE WHEN [s].[RowNo] = 1 THEN 1 ELSE 0 END
FROM [dbo].[SampleTable] AS [t]
INNER JOIN [RankedRows] AS [s]
	ON [s].[Id] = [t].[Id];</pre>
<p>Id must be unique to break timestamp ties.</p>
<p>Update a parent row and all its descendants:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @RootId INT = 1;

;WITH [Descendants] AS
(
	SELECT [Id]
	FROM [dbo].[SampleTable]
	WHERE [Id] = @RootId

	UNION ALL

	SELECT [child].[Id]
	FROM [dbo].[SampleTable] AS [child]
	INNER JOIN [Descendants] AS [parent]
		ON [child].[ParentId] = [parent].[Id]
)
UPDATE [t]
SET [Status] = N'Archived'
FROM [dbo].[SampleTable] AS [t]
INNER JOIN [Descendants] AS [d]
	ON [d].[Id] = [t].[Id]
OPTION (MAXRECURSION 100);</pre>
<p>Assumes a tree without cycles. Increase MAXRECURSION if deeper branches are expected.</p>
<p>Limit the number or percentage of updated rows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- fixed count
UPDATE TOP (100) [dbo].[SampleTable]
SET [Status] = N'Processed'
WHERE [Status] = N'Pending';

-- variable count
DECLARE @BatchSize INT = 100;

UPDATE TOP (@BatchSize) [dbo].[SampleTable]
SET [Status] = N'Processed'
WHERE [Status] = N'Pending';

-- percentage
UPDATE TOP (10) PERCENT [dbo].[SampleTable]
SET [Status] = N'Processed'
WHERE [Status] = N'Pending';</pre>
<p>These forms do not define row order.</p>
<p>Update in batches until no pending rows remain:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @BatchSize INT = 1000;
DECLARE @RowsUpdated INT = 1;

WHILE @RowsUpdated &gt; 0
BEGIN
	;WITH [Batch] AS
	(
		SELECT TOP (@BatchSize)
			[Id],
			[Status]
		FROM [dbo].[SampleTable]
		WHERE [Status] = N'Pending'
		ORDER BY [Id]
	)
	UPDATE [Batch]
	SET [Status] = N'Processed';

	SET @RowsUpdated = @@ROWCOUNT;
END;</pre>
<p>Id must be unique. Run without an outer transaction for separate batch commits. Processed rows leave the filter.</p>
<h2 id="update-output">OUTPUT and variables</h2>
<p>Capture old and new values using OUTPUT:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Changes TABLE
(
	[Id] INT,
	[OldValue] NVARCHAR(MAX),
	[NewValue] NVARCHAR(MAX)
);

UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value'
OUTPUT
	[Inserted].[Id],
	[Deleted].[Col1],
	[Inserted].[Col1]
INTO @Changes ([Id], [OldValue], [NewValue])
WHERE [Id] = 1;

SELECT [Id], [OldValue], [NewValue]
FROM @Changes;</pre>
<p>OUTPUT captures values before subsequent AFTER trigger changes. Returned values alone do not confirm that the transaction committed.</p>
<p>Return old and new values directly:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value'
OUTPUT
	[Inserted].[Id],
	[Deleted].[Col1] AS [OldValue],
	[Inserted].[Col1] AS [NewValue]
WHERE [Id] = 1;</pre>
<p>Use OUTPUT INTO instead if the target has an enabled UPDATE trigger.</p>
<p>Return a value from the joined source:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [t]
SET [Col1] = [s].[Col1]
OUTPUT
	[Inserted].[Id],
	[Deleted].[Col1] AS [OldValue],
	[Inserted].[Col1] AS [NewValue],
	[s].[SourceCode]
FROM [dbo].[SampleTable] AS [t]
INNER JOIN [dbo].[SourceTable] AS [s]
	ON [s].[Id] = [t].[Id];</pre>
<p>Source Id must be unique. Direct OUTPUT requires a target without enabled UPDATE triggers.</p>
<p>Save changed rows into a temporary table:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">CREATE TABLE #Changes
(
	[Id] INT,
	[OldValue] NVARCHAR(MAX),
	[NewValue] NVARCHAR(MAX)
);

UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value'
OUTPUT
	[Inserted].[Id],
	[Deleted].[Col1],
	[Inserted].[Col1]
INTO #Changes ([Id], [OldValue], [NewValue])
WHERE [Id] IN (1, 2, 3);

SELECT [Id], [OldValue], [NewValue]
FROM #Changes;

DROP TABLE #Changes;</pre>
<p>A permanent capture table can be used too. The OUTPUT INTO table cannot have enabled triggers, CHECK constraints, or foreign-key participation.</p>
<p>Get the number of updated rows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @RowsUpdated INT;

UPDATE [dbo].[SampleTable]
SET [Status] = N'Archived'
WHERE [Id] IN (1, 2, 3);

SET @RowsUpdated = @@ROWCOUNT;

SELECT @RowsUpdated AS [RowsUpdated];</pre>
<p>Read @@ROWCOUNT immediately after UPDATE. It counts affected rows, including unchanged values.</p>
<p>Capture a single row&#8217;s new or previous value into a variable:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- new value
DECLARE @NewValue NVARCHAR(100);

UPDATE [dbo].[SampleTable]
SET @NewValue = [Col1] = N'New Value'
WHERE [Id] = 1;

SELECT @NewValue AS [NewValue];

-- previous value
DECLARE @OldValue NVARCHAR(100);

UPDATE [dbo].[SampleTable]
SET @OldValue = [Col1],
	[Col1] = N'Another Value'
WHERE [Id] = 1;

SELECT @OldValue AS [OldValue];

-- new value after a compound assignment
DECLARE @NewQuantity INT;

UPDATE [dbo].[SampleTable]
SET @NewQuantity = [Quantity] += 1
WHERE [Id] = 1;

SELECT @NewQuantity AS [NewQuantity];</pre>
<p>Id must identify one row. Use OUTPUT for multiple rows.</p>
<p>Assign a variable from the updated row:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT = 1;
DECLARE @PreviousQuantity INT;

UPDATE [dbo].[SampleTable]
SET @PreviousQuantity = [Quantity],
	[Status] = N'Processed'
WHERE [Id] = @Id;

SELECT @PreviousQuantity AS [PreviousQuantity];</pre>
<p>Id must identify one row. If no row matches, the variable keeps its previous value.</p>
<h2 id="update-2025">SQL Server 2025</h2>
<p>Collapse repeated spaces using a regular expression (SQL Server 2025):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [TextValue] =
	REGEXP_REPLACE([TextValue], N' {2,}', N' ')
WHERE [Id] = 1;</pre>
<p>Replaces runs of two or more ordinary spaces with one space.<br />
<a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/regexp-replace-transact-sql?view=sql-server-ver17">REGEXP_REPLACE reference on Microsoft Learn</a>.</p>
<p>Remove non-digit characters (SQL Server 2025):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [Phone] = REGEXP_REPLACE([Phone], N'[^0-9]', N'')
WHERE [Id] = 1;</pre>
<p>Replace a native JSON document or modify one property (SQL Server 2025):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- JsonData has the native JSON data type
UPDATE [dbo].[SampleTable]
SET [JsonData] = CAST(N'{"status":"Pending","count":1}' AS JSON)
WHERE [Id] = 1;

UPDATE [dbo].[SampleTable]
SET [JsonData].modify('$.status', N'Processed')
WHERE [Id] = 1;</pre>
<p>Native JSON columns use the .modify() method. <a href="https://learn.microsoft.com/en-us/sql/t-sql/data-types/json-data-type?view=sql-server-ver17">JSON data type reference</a>.</p>
<p>Replace a vector value (SQL Server 2025):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- Embedding is VECTOR(3)
DECLARE @Embedding VECTOR(3) = '[0.15, 0.25, 0.35]';

UPDATE [dbo].[SampleTable]
SET [Embedding] = @Embedding
WHERE [Id] = 1;</pre>
<p>Match the column dimension. Vector-index update support depends on the index version. <a href="https://learn.microsoft.com/en-us/sql/t-sql/statements/create-vector-index-transact-sql?view=sql-server-ver17">Current vector-index limitations</a>.</p>
<h2 id="update-json-xml">JSON and XML</h2>
<p>Change or add a property in JSON text:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- JsonText is NVARCHAR(MAX) containing a JSON object
UPDATE [dbo].[SampleTable]
SET [JsonText] = JSON_MODIFY([JsonText], '$.status', N'Processed')
WHERE [Id] = 1;</pre>
<p>Adds status when missing from the root object. JsonText must contain valid JSON.</p>
<p>Delete a JSON property:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [JsonText] = JSON_MODIFY([JsonText], '$.status', NULL)
WHERE [Id] = 1;</pre>
<p>In the default lax mode, SQL NULL removes the property.</p>
<p>Set an existing JSON property to JSON null:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [JsonText] = JSON_MODIFY([JsonText], 'strict $.status', NULL)
WHERE [Id] = 1;</pre>
<p>Strict mode keeps the property with a JSON null value. The property must exist.</p>
<p>Append a value to a JSON array:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [JsonText] = JSON_MODIFY([JsonText], 'append $.tags', N'SQL Server')
WHERE [Id] = 1;</pre>
<p>Assumes tags is an existing array.</p>
<p>Store an object instead of an escaped JSON string:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [JsonText] = JSON_MODIFY(
	[JsonText],
	'$.address',
	JSON_QUERY(N'{"city":"Prague","country":"CZ"}')
)
WHERE [Id] = 1;</pre>
<p>Change multiple JSON properties:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE [dbo].[SampleTable]
SET [JsonText] = JSON_MODIFY(
	JSON_MODIFY([JsonText], '$.status', N'Processed'),
	'$.count',
	2
)
WHERE [Id] = 1;</pre>
<p>The number stays numeric. <a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/json-modify-transact-sql?view=sql-server-ver17">JSON_MODIFY reference</a>.</p>
<p>Replace XML text or an attribute value:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- XmlData is XML, for example:
-- &lt;Root Status="Pending"&gt;&lt;Value&gt;Old&lt;/Value&gt;&lt;/Root&gt;

UPDATE [dbo].[SampleTable]
SET [XmlData].modify('
	replace value of (/Root/Value/text())[1]
	with "New"
')
WHERE [Id] = 1
	AND [XmlData] IS NOT NULL;

UPDATE [dbo].[SampleTable]
SET [XmlData].modify('
	replace value of (/Root/@Status)[1]
	with "Processed"
')
WHERE [Id] = 1
	AND [XmlData] IS NOT NULL;</pre>
<p>The [1] selects a single node.</p>
<p>Insert or delete an XML element:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- insert under the existing Root element
UPDATE [dbo].[SampleTable]
SET [XmlData].modify('
	insert &lt;Note&gt;New note&lt;/Note&gt;
	as last into (/Root)[1]
')
WHERE [Id] = 1
	AND [XmlData] IS NOT NULL;

-- delete Note elements
UPDATE [dbo].[SampleTable]
SET [XmlData].modify('delete /Root/Note')
WHERE [Id] = 1
	AND [XmlData] IS NOT NULL;</pre>
<p>Examples use untyped XML without namespaces. <a href="https://learn.microsoft.com/en-us/sql/t-sql/xml/modify-method-xml-data-type?view=sql-server-ver17">XML modify() reference</a>.</p>
<h2 id="update-targets">Other update targets</h2>
<p>Update a temporary table or a table variable:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- temporary table
CREATE TABLE #SampleTable
(
	[Id] INT NOT NULL PRIMARY KEY,
	[Col1] NVARCHAR(100) NULL
);

INSERT INTO #SampleTable ([Id], [Col1])
VALUES (1, N'Old Value');

UPDATE #SampleTable
SET [Col1] = N'New Value'
WHERE [Id] = 1;

SELECT * FROM #SampleTable;

DROP TABLE #SampleTable;

-- table variable
DECLARE @SampleTable TABLE
(
	[Id] INT NOT NULL PRIMARY KEY,
	[Col1] NVARCHAR(100) NULL
);

INSERT INTO @SampleTable ([Id], [Col1])
VALUES (1, N'Old Value');

UPDATE @SampleTable
SET [Col1] = N'New Value'
WHERE [Id] = 1;

SELECT * FROM @SampleTable;</pre>
<p>Update through a view:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">CREATE OR ALTER VIEW [dbo].[v_SampleTable]
AS
	SELECT [Id], [Col1]
	FROM [dbo].[SampleTable];
GO

UPDATE [dbo].[v_SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;</pre>
<p>The change is stored in SampleTable. The updated columns must belong to one base table and meet the view-update rules.</p>
<p>Update through a synonym:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- create once
CREATE SYNONYM [dbo].[SampleAlias]
FOR [dbo].[SampleTable];
GO

UPDATE [dbo].[SampleAlias]
SET [Col1] = N'New Value'
WHERE [Id] = 1;</pre>
<p>Update a table in another database or on a linked server:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- another database on the same instance
UPDATE [SampleDb].[dbo].[SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;

-- configured linked server
UPDATE [RemoteServer].[SampleDb].[dbo].[SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;</pre>
<p>Remote updates require a writable provider and the appropriate login mapping. OUTPUT is not supported for remote targets.</p>
<p>Update through OPENQUERY:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE OPENQUERY(
	[RemoteServer],
	'SELECT [Id], [Col1]
	 FROM [SampleDb].[dbo].[SampleTable]
	 WHERE [Id] = 1'
)
SET [Col1] = N'New Value';</pre>
<p>Uses a configured linked server. The provider must return an updatable rowset.</p>
<p>Update through OPENROWSET:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE OPENROWSET(
	'MSOLEDBSQL19',
	'Data Source=RemoteServer;Initial Catalog=SampleDb;Integrated Security=SSPI;Use Encryption for Data=Mandatory;',
	'SELECT [Id], [Col1]
	 FROM [dbo].[SampleTable]
	 WHERE [Id] = 1'
)
SET [Col1] = N'New Value';</pre>
<p>Requires OLE DB Driver 19, allowed ad hoc access, a trusted server certificate and remote access for the Windows login. <a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/openrowset-transact-sql?view=sql-server-ver17">OPENROWSET reference</a>.</p>
<p>Update through OPENDATASOURCE:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">UPDATE OPENDATASOURCE(
	'MSOLEDBSQL19',
	'Data Source=RemoteServer;Integrated Security=SSPI;Use Encryption for Data=Mandatory;'
).[SampleDb].[dbo].[SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;</pre>
<p>Uses the same driver, ad hoc access and authentication requirements as the OPENROWSET example. <a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/opendatasource-transact-sql?view=sql-server-ver17">OPENDATASOURCE reference</a>.</p>
<p>Update a system-versioned temporal table:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- SampleTemporalTable already has SYSTEM_VERSIONING = ON
UPDATE [dbo].[SampleTemporalTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;</pre>
<p>Update the current table. SQL Server stores the previous version in the history table. Period columns and the history table cannot be updated directly while system versioning is on. <a href="https://learn.microsoft.com/en-us/sql/relational-databases/tables/temporal/modify-data?view=sql-server-ver17">Temporal update reference</a>.</p>
<p>Restore a current row from temporal history:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT = 1;
DECLARE @AsOf DATETIME2 = '2025-01-15T12:00:00';

UPDATE [t]
SET [Col1] = [h].[Col1]
FROM [dbo].[SampleTemporalTable] AS [t]
INNER JOIN [dbo].[SampleTemporalTable]
	FOR SYSTEM_TIME AS OF @AsOf AS [h]
	ON [h].[Id] = [t].[Id]
WHERE [t].[Id] = @Id;</pre>
<p>Updates the current row and creates another history version. It does not insert a row that has already been deleted.</p>
<h2 id="update-transactions">Transactions and concurrency</h2>
<p>Inspect an update and roll it back:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">BEGIN TRANSACTION;

UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = 1;

SELECT [Id], [Col1]
FROM [dbo].[SampleTable]
WHERE [Id] = 1;

ROLLBACK TRANSACTION;
-- use COMMIT TRANSACTION instead to save the change</pre>
<p>Run as a separate transaction.</p>
<p>Update two tables in one transaction:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SET XACT_ABORT ON;

BEGIN TRY
	BEGIN TRANSACTION;

	UPDATE [dbo].[SampleTable]
	SET [Status] = N'Processed'
	WHERE [Id] = 1;

	UPDATE [dbo].[SourceTable]
	SET [Status] = N'Processed'
	WHERE [Id] = 1;

	COMMIT TRANSACTION;
END TRY
BEGIN CATCH
	IF XACT_STATE() &lt;&gt; 0
		ROLLBACK TRANSACTION;

	THROW;
END CATCH;</pre>
<p>Assumes no transaction is already open. An error rolls back both changes.</p>
<p>Decrease stock only when enough stock is available:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT = 1;
DECLARE @Requested INT = 3;

IF @Requested &lt;= 0
	THROW 50000, 'Requested quantity must be positive.', 1;

UPDATE [dbo].[SampleTable]
SET [Quantity] -= @Requested
WHERE [Id] = @Id
	AND [Quantity] &gt;= @Requested;

IF @@ROWCOUNT = 0
	THROW 50001, 'Row not found or insufficient stock.', 1;</pre>
<p>Id must be unique. The check and decrease happen in one statement.</p>
<p>Update only if the rowversion still matches:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT = 1;
-- rowversion returned by the previous read
DECLARE @ExpectedVersion BINARY(8) = 0x0000000000000123;

UPDATE [dbo].[SampleTable]
SET [Col1] = N'New Value'
WHERE [Id] = @Id
	AND [RowVersion] = @ExpectedVersion;

IF @@ROWCOUNT = 0
	THROW 50002, 'Row was changed or deleted.', 1;</pre>
<p>RowVersion must be a ROWVERSION column. SQL Server generates its value; it is not a date or time. <a href="https://learn.microsoft.com/en-us/sql/t-sql/data-types/rowversion-transact-sql?view=sql-server-ver17">ROWVERSION reference</a>.</p>
<p>Update an existing row or insert a missing row:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT = 1;
DECLARE @NewValue NVARCHAR(100) = N'New Value';

SET XACT_ABORT ON;

BEGIN TRY
	BEGIN TRANSACTION;

	UPDATE [dbo].[SampleTable] WITH (UPDLOCK, SERIALIZABLE)
	SET [Col1] = @NewValue
	WHERE [Id] = @Id;

	IF @@ROWCOUNT = 0
	BEGIN
		INSERT INTO [dbo].[SampleTable] ([Id], [Col1])
		VALUES (@Id, @NewValue);
	END;

	COMMIT TRANSACTION;
END TRY
BEGIN CATCH
	IF XACT_STATE() &lt;&gt; 0
		ROLLBACK TRANSACTION;

	THROW;
END CATCH;</pre>
<p>Id needs a unique key and must allow the explicit inserted value. Assumes no transaction is already open. The lock protects the missing-key check until commit.</p>
<p>Claim the next pending row while skipping locked rows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- READ COMMITTED isolation, READ_COMMITTED_SNAPSHOT OFF
DECLARE @Claimed TABLE
(
	[Id] INT,
	[Col1] NVARCHAR(100)
);

SET XACT_ABORT ON;

BEGIN TRY
	BEGIN TRANSACTION;

	;WITH [NextRow] AS
	(
		SELECT TOP (1) [Id], [Col1], [Status]
		FROM [dbo].[SampleTable] WITH (UPDLOCK, READPAST, ROWLOCK)
		WHERE [Status] = N'Pending'
		ORDER BY [Id]
	)
	UPDATE [NextRow]
	SET [Status] = N'Processing'
	OUTPUT [Inserted].[Id], [Inserted].[Col1]
	INTO @Claimed ([Id], [Col1]);

	COMMIT TRANSACTION;

	SELECT [Id], [Col1]
	FROM @Claimed;
END TRY
BEGIN CATCH
	IF XACT_STATE() &lt;&gt; 0
		ROLLBACK TRANSACTION;

	THROW;
END CATCH;</pre>
<p>Use a rowstore table with unique Id and no outer transaction. READPAST skips row locks, not page locks. RCSI needs a different hint combination. <a href="https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver17">Table-hint reference</a>.</p>
<h2 id="update-other">Other forms</h2>
<p>Update the current cursor row:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Id INT;
DECLARE @Col1 NVARCHAR(100);

DECLARE [UpdateCursor] CURSOR LOCAL KEYSET
FOR
	SELECT [Id], [Col1]
	FROM [dbo].[SampleTable]
	WHERE [Status] = N'Pending'
FOR UPDATE OF [Col1];

OPEN [UpdateCursor];

FETCH NEXT FROM [UpdateCursor] INTO @Id, @Col1;

WHILE @@FETCH_STATUS = 0
BEGIN
	UPDATE [dbo].[SampleTable]
	SET [Col1] = N'New Value'
	WHERE CURRENT OF [UpdateCursor];

	FETCH NEXT FROM [UpdateCursor] INTO @Id, @Col1;
END;

CLOSE [UpdateCursor];
DEALLOCATE [UpdateCursor];</pre>
<p>The table needs a unique index for this KEYSET cursor. FAST_FORWARD cursors are read-only.</p>
<p>Update a CLR user-defined type property or call its mutator method:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- Location is a custom CLR type with a writable X property
UPDATE [dbo].[SampleTable]
SET [Location].[X] = 10
WHERE [Id] = 1;

-- the CLR type exposes a SetXY mutator method
UPDATE [dbo].[SampleTable]
SET [Location].SetXY(10, 20)
WHERE [Id] = 1;</pre>
<p>Requires an installed CLR type defining these members and a non-NULL Location. SetXY must be marked as a mutator. <a href="https://learn.microsoft.com/en-us/sql/relational-databases/clr-integration-database-objects-user-defined-types/working-with-user-defined-types-manipulating-udt-data?view=sql-server-ver17">CLR type update reference</a>.</p>
<p>Use a table hint or query hint:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- request row locks
UPDATE [dbo].[SampleTable] WITH (ROWLOCK)
SET [Col1] = N'New Value'
WHERE [Id] = 1;

-- recompile this statement and limit parallelism
UPDATE [dbo].[SampleTable]
SET [Status] = N'Archived'
WHERE [GroupId] = 1
OPTION (RECOMPILE, MAXDOP 2);</pre>
<p>ROWLOCK does not prevent lock escalation and cannot be used on a table with a clustered columnstore index.</p>
<p>Update a table selected by name using dynamic SQL:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @SchemaName SYSNAME = N'dbo';
DECLARE @TableName SYSNAME = N'SampleTable';
DECLARE @Id INT = 1;
DECLARE @NewValue NVARCHAR(100) = N'New Value';

DECLARE @Sql NVARCHAR(MAX) =
	N'UPDATE ' + QUOTENAME(@SchemaName) + N'.' + QUOTENAME(@TableName) + N'
	SET [Col1] = @NewValue
	WHERE [Id] = @Id;';

EXEC [sys].[sp_executesql]
	@Sql,
	N'@Id INT, @NewValue NVARCHAR(100)',
	@Id = @Id,
	@NewValue = @NewValue;</pre>
<p>QUOTENAME handles object names. Pass data values as parameters.</p>
<p>Return the affected-row count from a stored procedure:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">CREATE OR ALTER PROCEDURE [dbo].[p_UpdateSample]
	@Id INT,
	@NewValue NVARCHAR(100),
	@RowsUpdated INT OUTPUT
AS
BEGIN
	SET NOCOUNT ON;

	UPDATE [dbo].[SampleTable]
	SET [Col1] = @NewValue
	WHERE [Id] = @Id;

	SET @RowsUpdated = @@ROWCOUNT;
END;
GO

DECLARE @RowsUpdated INT;

EXEC [dbo].[p_UpdateSample]
	@Id = 1,
	@NewValue = N'New Value',
	@RowsUpdated = @RowsUpdated OUTPUT;

SELECT @RowsUpdated AS [RowsUpdated];</pre>
<p>Update inside a natively compiled stored procedure:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- SampleMemoryTable is an existing memory-optimized table
CREATE PROCEDURE [dbo].[p_UpdateSampleNative]
	@Id INT,
	@NewValue NVARCHAR(100)
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS
BEGIN ATOMIC WITH
(
	TRANSACTION ISOLATION LEVEL = SNAPSHOT,
	LANGUAGE = N'us_english'
)
	UPDATE [dbo].[SampleMemoryTable]
	SET [Col1] = @NewValue
	WHERE [Id] = @Id;
END;
GO

EXEC [dbo].[p_UpdateSampleNative]
	@Id = 1,
	@NewValue = N'New Value';</pre>
<p>Create the procedure once. Native procedures have a smaller supported T-SQL surface. <a href="https://learn.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/creating-natively-compiled-stored-procedures?view=sql-server-ver17">Native procedure reference</a>.</p>
<p>Update a local return table inside a function:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">CREATE OR ALTER FUNCTION [dbo].[f_SampleValues]()
RETURNS @Result TABLE
(
	[Id] INT,
	[Col1] NVARCHAR(100)
)
AS
BEGIN
	INSERT INTO @Result ([Id], [Col1])
	SELECT [Id], [Col1]
	FROM [dbo].[SampleTable];

	UPDATE @Result
	SET [Col1] = N'Unknown'
	WHERE [Col1] IS NULL;

	RETURN;
END;
GO

SELECT [Id], [Col1]
FROM [dbo].[f_SampleValues]();</pre>
<p>A T-SQL function can update its local table variables. It cannot update permanent tables.</p>
<p><a href="https://learn.microsoft.com/en-us/sql/t-sql/queries/update-transact-sql?view=sql-server-ver17">Full UPDATE syntax and restrictions on Microsoft Learn</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>INSERT &#8211; Basic</title>
		<link>https://sqlpowered.com/t-sql-commands/insert-basic/</link>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Tue, 28 Dec 2021 19:46:03 +0000</pubDate>
				<category><![CDATA[T-SQLpowered]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?post_type=t-sql-commands&#038;p=5271</guid>

					<description><![CDATA[Insert one row with default values for all table columns: INSERT INTO [dbo].[SampleTable] DEFAULT VALUES SELECT INTO and specify a filegroup (2016 SP2+): SELECT * INTO [dbo].[SampleTable_Copy] ON [OtherFilegoup] FROM [dbo].[SampleTable] &#160;]]></description>
										<content:encoded><![CDATA[<p>Insert one row with default values for all table columns:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">INSERT INTO [dbo].[SampleTable] DEFAULT VALUES</pre>
<p>SELECT INTO and specify a filegroup (2016 SP2+):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT * 
    INTO [dbo].[SampleTable_Copy] ON [OtherFilegoup]
FROM [dbo].[SampleTable]</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
