What is the purpose of a Row_GUID column?

ROWGUIDCOL is primarily used for MERGE replication, and is also required for FILESTREAM, but can be used in any scenario where you want an immutable column separate from the primary key (e.g. in the case where a primary key value can change, but you still want to be able to tell which row was which before and after the change).

USE tempdb;
GO

CREATE TABLE dbo.example
(
  name sysname PRIMARY KEY, 
  rowguid uniqueidentifier NOT NULL DEFAULT NEWID() ROWGUIDCOL
);

INSERT dbo.example(name) VALUES(N'bob'),(N'frank');

SELECT * FROM dbo.example;

UPDATE dbo.example SET name = N'pat' WHERE name = N'bob';
UPDATE dbo.example SET name = N'bob' WHERE name = N'frank';

SELECT * FROM dbo.example;

DROP TABLE dbo.example;

Now, if replication, or your application, or what have you is paying attention, it will notice that:

enter image description here

See here, here, and the "Snapshot Considerations" section here for more info.


Marking a column as ROWGUIDCOL allows it to be referenced via $ROWGUID in queries. This allows for making queries more generic since you wouldn't need to look up, per each table, what the "unique" column is (this is quite useful for features such as Replication and FileStream as noted by @Aaron and @Martin, respectively). You could have a query constructed in the app layer, or in Dynamic SQL even, that does something like SELECT $ROWGUID AS [ID] FROM {table_name} and simply iterate over a list of tables.

Just keep in mind that the ROWGUIDCOL designation does not enforce uniqueness. You will still need to enforce that via a Primary Key, a Unique Index, or a Unique Constraint. Nor does this option enforce that the column is immutable. For that you would need either an AFTER UPDATE Trigger or column-level permissions to DENY UPDATE on that column.

For example:

SET NOCOUNT ON;
CREATE TABLE #RowGuidColTest
(
  ID UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()) ROWGUIDCOL,
  SomeValue INT
);

INSERT INTO #RowGuidColTest (SomeValue) VALUES (12), (14), (1231);

DECLARE @Search UNIQUEIDENTIFIER;

SELECT TOP (1) @Search = $ROWGUID
FROM   #RowGuidColTest;

SELECT @Search AS [@Search]

SELECT *, $ROWGUID AS [$ROWGUID]
FROM   #RowGuidColTest;

SELECT *
FROM   #RowGuidColTest
WHERE  $ROWGUID = @Search;

-- No enforced uniqueness without a PK, Unique Index, or Unique Constraint.
UPDATE tmp
SET    $ROWGUID = @Search
FROM   #RowGuidColTest tmp

SELECT *
FROM   #RowGuidColTest
WHERE  $ROWGUID = @Search;

Returns something similar to:

@Search
E7166D18-5003-4D20-8983-E2402472CF82


ID                                      SomeValue    $ROWGUID
E7166D18-5003-4D20-8983-E2402472CF82    12           E7166D18-5003-4D20-8983-E2402472CF82
44FD48A4-AF38-41BF-AE4E-8A12D26B5B57    14           44FD48A4-AF38-41BF-AE4E-8A12D26B5B57
2D50C5C7-1E43-4ADA-A03B-ED202FC88D20    1231         2D50C5C7-1E43-4ADA-A03B-ED202FC88D20


ID                                      SomeValue
E7166D18-5003-4D20-8983-E2402472CF82    12


ID                                      SomeValue
E7166D18-5003-4D20-8983-E2402472CF82    12
E7166D18-5003-4D20-8983-E2402472CF82    14
E7166D18-5003-4D20-8983-E2402472CF82    1231

Similarly, one could use $IDENTITY for tables that have an IDENTITY column.