GDPR-Export Classified Data

I needed a solution to script out the classified data so we can deploy those changes to our Test, Acceptance and Production environment. I created a stored procedure and marked it as a system object so it can be called from any database.

USE [master]
GO
CREATE OR ALTER PROCEDURE [dbo].[sp_ExportClassifiedData]
(
	 @SchemaName sysname = NULL
	,@TableName sysname = NULL
	,@ColumName sysname = NULL
)
AS

-- PROCESS
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

DECLARE @curSchemaName SYSNAME
DECLARE @curTableName SYSNAME
DECLARE @curColumnName SYSNAME
DECLARE @LabelName SQL_VARIANT
DECLARE @LabelValue SQL_VARIANT
DECLARE @DbName NVARCHAR(128) = (SELECT CONCAT('USE ',QUOTENAME(DB_NAME(DB_ID()))))

PRINT @DbName+char(10)+'GO'
PRINT 'SET NOCOUNT ON;'

DECLARE ListextendedPropertyCursor CURSOR FOR 

SELECT schema_name(schema_id) as 'SchemaName'
,name as 'TableName'
FROM sys.tables 
WHERE (schema_name(schema_id) = @SchemaName or @SchemaName IS NULL)
AND (name = @TableName OR @TableName IS NULL)
ORDER BY schema_name(schema_id) ASC, NAME ASC

OPEN ListextendedPropertyCursor
FETCH NEXT FROM ListextendedPropertyCursor INTO @curSchemaName, @curTableName

WHILE @@FETCH_STATUS = 0 
BEGIN 
	DECLARE ClassificationCursor CURSOR FOR 

	WITH CteListextendedproperty (SchemaName, TableName, ColumnName, LabelName, LabelValue)
	AS
	(
		SELECT @curSchemaName as 'SchemaName'
			, @curTableName AS 'TableName'
			, objname
			, name
			, value  
		FROM fn_listextendedproperty (NULL, 'schema', @curSchemaName, 'table', @curTableName, 'column', default)
	)
	SELECT SchemaName, TableName, ColumnName, LabelName, LabelValue 
	FROM CteListextendedproperty
	WHERE ColumnName = @ColumName or @ColumName is null

	OPEN ClassificationCursor
	FETCH NEXT FROM ClassificationCursor INTO @curSchemaName,@curTableName,@curColumnName,@LabelName, @LabelValue

	WHILE @@FETCH_STATUS = 0  
	BEGIN  
		
		DECLARE @SqlCommand nvarchar(max)

		SET @SqlCommand = concat('
IF NOT EXISTS (SELECT 1 FROM fn_listextendedproperty (NULL, ''schema'', ''',@curSchemaName,''', ''table'', ''',@curTableName,''', ''column'', ''',@curColumnName,''') WHERE NAME = N''',cast(@LabelName as nvarchar(255)),''')
BEGIN
',char(9),'PRINT '' Add the extended property to table ',quotename(@curSchemaname),'.',quotename(@curTableName),' column ',quotename(@curColumnName),' property ',quotename(cast(@LabelName as nvarchar(255))),'''','
',char(9),'EXEC sp_addextendedproperty
',char(9),'@name = N''',cast(@LabelName as nvarchar(255)),''',
',char(9),'@value = ''',replace(cast(@LabelValue as nvarchar(255)),'''',''''''),''',
',char(9),'@level0type = N''Schema'', @level0name = ''',@curSchemaname,''',
',char(9),'@level1type = N''Table'',  @level1name = ''',@curTableName,''',
',char(9),'@level2type = N''Column'', @level2name = ''',@curColumnName,''';
END ELSE
BEGIN
',char(9),'PRINT '' Update the extended property from table ',quotename(@curSchemaname),'.',quotename(@curTableName),' column ',quotename(@curColumnName),' property ',quotename(cast(@LabelName as nvarchar(255))),'''','
',char(9),'EXEC sp_updateextendedproperty
',char(9),'@name = N''',cast(@LabelName as nvarchar(255)),''',
',char(9),'@value = ''',replace(cast(@LabelValue as nvarchar(255)),'''',''''''),''',
',char(9),'@level0type = N''Schema'', @level0name = ''',@curSchemaname,''',
',char(9),'@level1type = N''Table'',  @level1name = ''',@curTableName,''',
',char(9),'@level2type = N''Column'', @level2name = ''',@curColumnName,''';
END',CHAR(10),'GO')

		PRINT @SqlCommand

		FETCH NEXT FROM ClassificationCursor INTO @curSchemaName,@curTableName,@curColumnName,@LabelName, @LabelValue
	END 
	CLOSE ClassificationCursor  
	DEALLOCATE ClassificationCursor

FETCH NEXT FROM ListextEndedpropertyCursor INTO @curSchemaName, @curTableName
END 
CLOSE ListextEndedpropertyCursor
DEALLOCATE ListextEndedpropertyCursor
GO

use master
go
EXEC sp_MS_marksystemobject 'dbo.sp_ExportClassifiedData'
GO

samples

-- script out one schema.table.column
use <database_name, sysname, your_database_name>
GO
EXECUTE dbo.sp_ExportClassifiedData @SchemaName = '<schema_name, sysname, your_schema_name>', @TableName = '<table_name, sysname, your_table_name>', @ColumName =  '<column_name, sysname, column_name>'

-- script out one specific column found in all schemas.tables
use <database_name, sysname, your_database_name>
GO
EXECUTE dbo.sp_ExportClassifiedData @SchemaName = NULL, @TableName = NULL, @ColumName = '<column_name, sysname, column_name>'

-- script out all columns from a specific schema.table
use <database_name, sysname, your_database_name>
GO
EXECUTE dbo.sp_ExportClassifiedData @SchemaName = '<schema_name, sysname, your_schema_name>', @TableName = '<table_name, sysname, your_table_name>', @ColumName = NULL

-- script out all schemas.tables.columns
use <database_name, sysname, your_database_name>
GO
EXECUTE dbo.sp_ExportClassifiedData @SchemaName = NULL, @TableName = NULL, @ColumName = NULL