Microsoft SQL Server – 如何将所有表和视图中的`ntext`列转换为`nvarchar(max)`?

huangapple go评论54阅读模式
英文:

Microsoft SQL Server - How to convert all `ntext` columns to `nvarchar(max)` in tables and views?

问题

我需要在整个数据库中将所有 ntext 列替换为 nvarchar(max)。在这种情况下,您需要对所有表和所有视图执行此操作。
我有以下代码,对于表格效果很好,但对于视图不起作用:

-- 创建一个临时表,其中将包含包含 ntext 类型字段的所有表
CREATE TABLE #TablesToModify
(
    TableName NVARCHAR(255),
    ColumnName NVARCHAR(255)
)

-- 用 ntext 类型的表和字段列表填充临时表
INSERT INTO #TablesToModify
SELECT c.TABLE_NAME, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.DATA_TYPE = 'ntext'

-- 遍历每个表格并执行 ALTER TABLE 更改数据类型
DECLARE @TableName NVARCHAR(255)
DECLARE @ColumnName NVARCHAR(255)

DECLARE cur CURSOR FOR
SELECT TableName, ColumnName
FROM #TablesToModify

OPEN cur

FETCH NEXT FROM cur INTO @TableName, @ColumnName

WHILE @@FETCH_STATUS = 0
BEGIN
    -- 执行 ALTER TABLE 更改数据类型
    EXEC ('ALTER TABLE ' + @TableName + ' ALTER COLUMN ' + @ColumnName + ' NVARCHAR(MAX)')

    FETCH NEXT FROM cur INTO @TableName, @ColumnName
END

CLOSE cur
DEALLOCATE cur

-- 删除临时表
DROP TABLE #TablesToModify

我应该添加什么来将 ntext 列类型更改为视图中的 nvarchar(max)
我在stackoverflow上找到了如何更改表中的所有列的解决方案,但没有找到如何在视图中更改它们的方法。
在互联网上,所有与此主题相关的信息都只涉及表格。

英文:

I need to replace all ntext columns with nvarchar(max) in the entire database. In this case, you need to do this for all tables and for all views.
I have the following code which works great for tables but doesn't work for views:

-- Create a temporary table that will contain all tables containing fields of type ntext
CREATE TABLE #TablesToModify
(
    TableName NVARCHAR(255),
    ColumnName NVARCHAR(255)
)

-- Fill the temporary table with a list of tables and fields of type ntext
INSERT INTO #TablesToModify
SELECT c.TABLE_NAME, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.DATA_TYPE = 'ntext'

-- Go through each table and ALTER TABLE to change the data type
DECLARE @TableName NVARCHAR(255)
DECLARE @ColumnName NVARCHAR(255)

DECLARE cur CURSOR FOR
SELECT TableName, ColumnName
FROM #TablesToModify

OPEN cur

FETCH NEXT FROM cur INTO @TableName, @ColumnName

WHILE @@FETCH_STATUS = 0
BEGIN
    -- Execute ALTER TABLE to change the data type
    EXEC ('ALTER TABLE ' + @TableName + ' ALTER COLUMN ' + @ColumnName + ' NVARCHAR(MAX)')

    FETCH NEXT FROM cur INTO @TableName, @ColumnName
END

CLOSE cur
DEALLOCATE cur

-- Delete temporary table
DROP TABLE #TablesToModify

What should I add to change the ntext column type to nvarchar(max) in views as well?

I found a solution on stackoverflow how to change all columns in tables but didn't find how to change them in views.
On the Internet, too, all information related to this topic refers only to tables.

答案1

得分: 3

你只需要在引用这些表的每个视图上调用 sp_refreshviewsp_refreshsqlmodule。你可以从 sys.sql_expression_dependencies 中获取这些信息。

  • 你需要添加模式名称。
  • 对象名称应该是 sysname
  • 不要使用 INFORMATION_SCHEMA,它仅用于兼容性,并且可能不可靠。
  • 你需要保持列的可空性。
  • 对系统表上的游标可能不稳定。要么使用 STATIC 游标,要么更好地使用 STRING_AGG 生成一个大的 SQL 脚本。
CREATE TABLE #TablesToModify
(
    ObjectId bigint,
    SchemaName sysname,
    TableName sysname,
    ColumnName sysname,
    IsNullable bit
);

-- 使用 ntext 类型的表和字段列表填充临时表
INSERT INTO #TablesToModify (ObjectId, SchemaName, TableName, ColumnName, IsNullable)
SELECT
  t.object_id, s.name, t.name, c.name, c.is_nullable
FROM sys.columns c
JOIN sys.types typ ON typ.user_type_id = c.user_type_id
JOIN sys.tables t ON t.object_id = c.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE typ.name = 'ntext';

DECLARE @sql nvarchar(max);

SELECT @sql = STRING_AGG(CAST(CONCAT(
    'ALTER TABLE ',
    QUOTENAME(SchemaName),
    '.',
    QUOTENAME(TableName),
    ' ALTER COLUMN ',
    QUOTENAME(ColumnName),
    ' NVARCHAR(MAX)',
    IIF(IsNullable = 1, N' NOT NULL;', N';')
  ) AS nvarchar(max)), ';
  ')
FROM #TablesToModify;

SELECT @sql += '
' + STRING_AGG(CAST(CONCAT(
    'EXEC sp_refreshsqlmodule ''',
    REPLACE(QUOTENAME(s.name) + '.' + QUOTENAME(o.name), '''', ''''''),
    '''''
  ) AS nvarchar(max)), ';
  ')
FROM (
    SELECT DISTINCT ObjectId
    FROM #TablesToModify
) t
JOIN sys.sql_expression_dependencies d ON d.referenced_id = t.ObjectId
JOIN sys.objects o ON o.object_id = d.referencing_id
JOIN sys.schemas s ON s.schema_id = o.schema_id
GROUP BY
  d.referencing_id;

PRINT @sql;  -- your friend

EXEC sp_executesql @sql;

-- 删除临时表
DROP TABLE #TablesToModify
英文:

You just need to call sp_refreshview or sp_refreshsqlmodule on each view that references these tables. You can get this information out of sys.sql_expression_dependencies

  • You need to add the schema name also.
  • Object names should be sysname.
  • Don't use INFORMATION_SCHEMA it's for compatibility only and can be unreliable.
  • You need to maintain nullability of the column.
  • Cursors on system tables can be iffy. Either use a STATIC cursor, or better just generate one big SQL script using STRING_AGG.
CREATE TABLE #TablesToModify
(
    ObjectId bigint,
    SchemaName sysname,
    TableName sysname,
    ColumnName sysname,
    IsNullable bit
);

-- Fill the temporary table with a list of tables and fields of type ntext
INSERT INTO #TablesToModify (ObjectId, SchemaName, TableName, ColumnName, IsNullable)
SELECT
  t.object_id, s.name, t.name, c.name, c.is_nullable
FROM sys.columns c
JOIN sys.types typ ON typ.user_type_id = c.user_type_id
JOIN sys.tables t ON t.object_id = c.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE typ.name = 'ntext';

DECLARE @sql nvarchar(max);

SELECT @sql = STRING_AGG(CAST(CONCAT(
    'ALTER TABLE ',
    QUOTENAME(SchemaName),
    '.',
    QUOTENAME(TableName),
    ' ALTER COLUMN ',
    QUOTENAME(ColumnName),
    ' NVARCHAR(MAX)',
    IIF(IsNullable = 1, N' NOT NULL;', N';')
  ) AS nvarchar(max)), ';
'  )
FROM #TablesToModify;


SELECT @sql += '
' + STRING_AGG(CAST(CONCAT(
    'EXEC sp_refreshsqlmodule ''',
    REPLACE(QUOTENAME(s.name) + '.' + QUOTENAME(o.name), '''', ''''''),
    ''''
  ) AS nvarchar(max)), '
'  )
FROM (
    SELECT DISTINCT ObjectId
    FROM #TablesToModify
) t
JOIN sys.sql_expression_dependencies d ON d.referenced_id = t.ObjectId
JOIN sys.objects o ON o.object_id = d.referencing_id
JOIN sys.schemas s ON s.schema_id = o.schema_id
GROUP BY
  d.referencing_id;


PRINT @sql;  -- your friend

EXEC sp_executesql @sql;


-- Delete temporary table
DROP TABLE #TablesToModify

huangapple
  • 本文由 发表于 2023年7月6日 19:57:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76628585.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定