Skip to content

Create Partition Check Constraints

A script that generates IN-list check constraints on low-cardinality columns to support table partitioning.

Published Oct 24, 2006

If you are partitioning a table by a low-cardinality column (a code, a group, a region), the cleanest way to keep the right rows in the right partitions is a CHECK constraint per value. This script finds candidate columns (by naming convention - columns containing 'Co' or 'Group'), scans their distinct values, and for any column with fewer than @DistinctValueThreshold distinct values it drops any existing constraint of the same name and recreates it as an IN (...) check constraint.

Tune the column-name filters and the exclusion list at the top before running it on your own schema.

SET NOCOUNT ON;
GO

--Columns with distinct counts greater then this will not have check constraints created.
DECLARE @DistinctValueThreshold INT
SET @DistinctValueThreshold = 100 

------------------------------------------------------------------------------------------
DECLARE @ConstraintName nVarChar(128)
DECLARE @SchemaName nVarChar(128)
DECLARE @ObjectName nVarChar(128)
DECLARE @ColumnName nVarChar(128)
DECLARE @DistinctValue nVarChar(MAX)
DECLARE @DistinctValues nVarChar(MAX)
DECLARE @tSQL nVarChar(MAX)

CREATE TABLE #DistinctValues
(
	Value nVarChar(2000)
)

DECLARE PrimaryKeys CURSOR FAST_FORWARD FOR
	SELECT DISTINCT
		schema_name(O.schema_id) AS SchemaName,
		O.name AS ObjectName,
		C.name AS ColumnName
	FROM
		sys.objects AS O
	INNER JOIN sys.indexes AS I
		ON I.object_id = O.object_id
	INNER JOIN sys.index_columns AS IC
		ON IC.object_id = I.object_id
		AND IC.index_id = I.index_id
	INNER JOIN sys.columns AS C
		ON C.object_id = IC.object_id
		AND C.column_id = IC.column_id
	WHERE
		O.is_ms_shipped = 0
		AND O.type = 'U'
		AND (
			C.name LIKE '%Co'
			OR C.name LIKE '%Group'
		)
		AND C.name NOT IN 
		(
			'StdMaintGroup'
		)
	ORDER BY
		schema_name(O.schema_id),
		O.name,
		C.name
OPEN PrimaryKeys

FETCH FROM PrimaryKeys INTO @SchemaName, @ObjectName, @ColumnName

WHILE(@@FETCH_STATUS = 0)
BEGIN--WHILE
	------------------------------------------------------------------------------------

	SET @ConstraintName = 'CK_Consol_' + @SchemaName + '_' + @ObjectName + '_' + @ColumnName

	IF @ConstraintName NOT IN ('CK_Consol_dbo_budoEMTH_Co')
	BEGIN--IF
		SET @DistinctValues = NULL

		SET @tSQL = 'INSERT INTO #DistinctValues(Value)'
			+ 'SELECT DISTINCT Convert(nVarChar(2000), [' + @ColumnName + ']) AS Value'
			+ ' FROM [' + @SchemaName + '].[' + @ObjectName + ']'
		EXEC(@tSQL)
			
		IF((SELECT COUNT(0) FROM #DistinctValues) < @DistinctValueThreshold)
		BEGIN--IF
			DECLARE PresentValues CURSOR FAST_FORWARD FOR
				SELECT Value FROM #DistinctValues ORDER BY Value
			OPEN PresentValues

			FETCH FROM PresentValues INTO @DistinctValue

			WHILE(@@FETCH_STATUS = 0)
			BEGIN--WHILE
				------------------------------------------------------------------------------------
				SET @DistinctValues = IsNull(@DistinctValues, '') + '''' + @DistinctValue + ''''
				------------------------------------------------------------------------------------
				FETCH FROM PresentValues INTO @DistinctValue
				
				IF(@@FETCH_STATUS = 0)
				BEGIN--IF
					SET @DistinctValues = @DistinctValues + ','
				END--IF
			END--WHILE

			CLOSE PresentValues DEALLOCATE PresentValues
		END--IF
		
		TRUNCATE TABLE #DistinctValues

		SET @tSQL = 'IF EXISTS (SELECT * FROM sys.check_constraints WHERE object_id = OBJECT_ID(N''[' + @SchemaName + '].[' + @ConstraintName + ']'') AND parent_object_id = OBJECT_ID(N''[' + @SchemaName + '].[' + @ObjectName + ']''))'
			+ 'ALTER TABLE [' + @SchemaName + '].[' + @ObjectName + '] DROP CONSTRAINT [' + @ConstraintName + ']'
		EXEC(@tSQL)
		
		IF(@DistinctValues IS NOT NULL)
		BEGIN--IF
			PRINT 'Creating: ' + @ConstraintName + ' (' + @DistinctValues + ')'

			SET @tSQL = 'ALTER TABLE [' + @SchemaName + '].[' + @ObjectName + '] WITH CHECK ADD CONSTRAINT [' + @ConstraintName + '] CHECK ([' + @ColumnName + '] IN (' + @DistinctValues + '))'
			EXEC(@tSQL)
			--SET @tSQL = 'ALTER TABLE [' + @SchemaName + '].[' + @ObjectName + '] CHECK CONSTRAINT [' + @ConstraintName + ']'
			--EXEC(@tSQL)
		END--IF
	END--IF	
	------------------------------------------------------------------------------------
	FETCH FROM PrimaryKeys INTO @SchemaName, @ObjectName, @ColumnName
END--WHILE

CLOSE PrimaryKeys DEALLOCATE PrimaryKeys

DROP TABLE #DistinctValues
An unhandled error has occurred. Reload 🗙