我需要创建一个 SQL Server 查询来清理旧数据库,方法是确保具有唯一约束的列中的所有非唯一值都更新为唯一。
为此,我想找到数据库中具有唯一约束的所有列。然后遍历这些列中的所有值以查找任何非唯一值。最后,考虑在任何非唯一值的末尾添加后缀。当使用后缀时,它会增加 1。
对于所有重复项,需要将表、列、旧的非唯一值和新的唯一值写入控制台。
对我来说,似乎我需要使用动态 SQL 来实现这一点。
有更好的方法吗?
这是我目前拥有的:
DECLARE @tableName NVARCHAR(255)
DECLARE @columnName NVARCHAR(255)
DECLARE @sql NVARCHAR(MAX)
DECLARE uniqueColumns CURSOR FOR
SELECT
cu.TABLE_NAME,
cu.COLUMN_NAME
FROM
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc ON cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE
tc.CONSTRAINT_TYPE = 'UNIQUE'
OPEN uniqueColumns
FETCH NEXT FROM uniqueColumns INTO @tableName, @columnName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = N'
WITH DuplicatesCTE AS (
SELECT
ColumnNameString AS ColumnName,
ColumnNameString AS OriginalValue,
ColumnNameString + ''_'' + CAST(ROW_NUMBER() OVER (PARTITION BY ColumnNameString ORDER BY (SELECT 1)) AS NVARCHAR(MAX)) AS NewValue
FROM TableNameString
WHERE ColumnNameString IN (
SELECT ColumnNameString
FROM TableNameString
GROUP BY ColumnNameString
HAVING COUNT(*) > 1
)
)
UPDATE DuplicatesCTE
SET OriginalValue = NewValue
OUTPUT INSERTED.ColumnName, INSERTED.NewValue
';
SET @sql = REPLACE(@sql, 'TableNameString', QUOTENAME(@tableName))
SET @sql = REPLACE(@sql, 'ColumnNameString', QUOTENAME(@columnName))
--EXEC sp_executesql @sql
PRINT @sql
FETCH NEXT FROM uniqueColumns INTO @tableName, @columnName
END
CLOSE uniqueColumns
DEALLOCATE uniqueColumns
我收到此错误:
消息 402,第 16 级,状态 1,第 6 行
数据类型 uniqueidentifier 和 varchar 在添加运算符中不兼容。
如果我打印
@sql
而不是执行它,我会得到以下 SQL:
WITH DuplicatesCTE AS (
SELECT
[AdminRoleId] AS ColumnName,
[AdminRoleId] AS OriginalValue,
[AdminRoleId] + '_' + CAST(ROW_NUMBER() OVER (PARTITION BY [AdminRoleId] ORDER BY (SELECT 1)) AS NVARCHAR(MAX)) AS NewValue
FROM [AdminRoleModules]
WHERE [AdminRoleId] IN (
SELECT [AdminRoleId]
FROM [AdminRoleModules]
GROUP BY [AdminRoleId]
HAVING COUNT(*) > 1
)
)
UPDATE DuplicatesCTE
SET OriginalValue = NewValue
我也遇到同样的错误:
消息 402,第 16 级,状态 1,第 5 行
数据类型 uniqueidentifier 和 varchar 在添加运算符中不兼容。
看起来我的动态 SQL 中有几个语法错误。此外,我忘记只在字符串上运行它,而不是在主键或外键上运行。这些问题已在以下 SQL 中得到修复:
DECLARE @tableName NVARCHAR(255)
DECLARE @columnName NVARCHAR(255)
DECLARE @sql NVARCHAR(MAX)
DECLARE uniqueColumns CURSOR FOR
SELECT
cu.TABLE_NAME,
cu.COLUMN_NAME
FROM
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc ON cu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.COLUMNS col ON cu.COLUMN_NAME = col.COLUMN_NAME AND cu.TABLE_NAME = col.TABLE_NAME
WHERE
tc.CONSTRAINT_TYPE = 'UNIQUE'
AND col.DATA_TYPE = 'NVARCHAR'
OPEN uniqueColumns
FETCH NEXT FROM uniqueColumns INTO @tableName, @columnName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = N'
WITH DuplicatesCTE AS (
SELECT
ColumnNameString AS ColumnName,
ColumnNameString AS OriginalValue,
(ColumnNameString + ''_'' + CAST(ROW_NUMBER() OVER (PARTITION BY ColumnNameString ORDER BY (SELECT 1)) AS NVARCHAR(MAX))) AS NewValue
FROM TableNameString
WHERE ColumnNameString IN (
SELECT ColumnNameString
FROM TableNameString
GROUP BY ColumnNameString
HAVING COUNT(*) > 1
)
)
UPDATE DuplicatesCTE
SET OriginalValue = NewValue
OUTPUT INSERTED.ColumnName--, INSERTED.NewValue
';
SET @sql = REPLACE(@sql, 'TableNameString', QUOTENAME(@tableName))
SET @sql = REPLACE(@sql, 'ColumnNameString', QUOTENAME(@columnName))
EXEC sp_executesql @sql
--PRINT @sql
FETCH NEXT FROM uniqueColumns INTO @tableName, @columnName
END
CLOSE uniqueColumns
DEALLOCATE uniqueColumns
然而,这在输出表名、列名、旧值和新值方面仍然存在不足,因此可以审核更改。