3

I would love to be able to write a SQL query, without enumerating the columns, which will return me all the columns, and any ntext column converted to varchar(max). I was wondering if there is a clever way to do this.

This would be great because then I could do the comparison based operators such as UNION, EXCEPT etc. on such queries. The netxt column is not comparable so it fails when using those operators.

My current idea:

Create a function to build the query as dynamic sql. Something similar to this: http://lotsacode.wordpress.com/2010/03/23/sql-server-ntext-cannot-be-selected-as-distinct/

Is there a better way?

Thanks for your input!

4

3 回答 3

5

NTEXT无论如何都会从 SQl-Server 的未来版本中删除(连同 Image 和 text),所以为什么不硬着头皮将列更改为NVARCHAR(MAX)?一次可能很昂贵,但它可能是值得的:

ALTER TABLE dbo.T ALTER COLUMN NTextColumn NVARCHAR(MAX) NULL; -- OR NOT NULL

您可以使用以下命令为整个数据库生成和执行脚本:

DECLARE @SQL NVARCHAR(MAX) = 
    (   SELECT  'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + 
                                QUOTENAME(OBJECT_NAME(object_id)) + 
                                ' ALTER COLUMN ' + QUOTENAME(Name) + 
                                ' NVARCHAR(MAX) ' + 
                                CASE WHEN is_nullable = 0 THEN 'NOT' ELSE '' END + 
                                ' NULL;' + CHAR(13) + 'GO' + CHAR(13)
        FROM    sys.columns
        WHERE   system_type_id = 99 --NTEXT
        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');

EXECUTE sp_executesql @SQL;
于 2013-09-13T15:21:14.493 回答
4

我使用了这个光标(在这里,恐怕没有基于集合的替代方案)来做到这一点:

DECLARE TableCursor CURSOR FAST_FORWARD 
FOR
    SELECT 
        t.Name,
        c.name,
        c.is_nullable, 
        typ.user_type_id
    FROM 
        sys.columns c 
    INNER JOIN 
        sys.tables t ON c.object_id = t.object_id
    INNER JOIN 
        sys.types typ ON c.system_type_id = typ.system_type_id
    WHERE   
        typ.name IN ('text', 'ntext')    -- user_type_id: text = 35, ntext = 99 

DECLARE @TableName sysname, @ColumnName sysname, @IsNullable BIT, @TypeID INT

OPEN TableCursor

FETCH NEXT FROM TableCursor INTO @TableName, @ColumnName, @IsNullable, @TypeID

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @Stmt NVARCHAR(999)

    SET @Stmt = 'ALTER TABLE dbo.[' + @TableName + '] ALTER COLUMN [' + @ColumnName + '] ' + 
              CASE @TypeID 
                WHEN 35 THEN ' VARCHAR(MAX) '
                WHEN 99 THEN ' NVARCHAR(MAX) '
              END  + 
                CASE WHEN @IsNullable = 1 THEN 'NULL' ELSE 'NOT NULL' END

    PRINT @Stmt
    EXEC (@Stmt)

    FETCH NEXT FROM TableCursor INTO @TableName, @ColumnName, @IsNullable, @TypeID
END

CLOSE TableCursor
DEALLOCATE TableCursor

通过假设我的所有表都在dbo模式中,我稍微简化了我的代码 - 如果您不是这种情况,您也必须从sys.schema目录视图中包含模式。

运行这段代码将把一切都text变成一劳永逸,你所有的问题都一去不复返了!:-)varchar(max)ntextnvarchar(max)text/ntext

于 2013-09-13T15:26:28.227 回答
0

这是我对 GarethD 上面答案的修改版本。遇到 SQL 找不到某些表的问题,所以我使用 sys.tables 与 sys.columns 连接。此外,is_nullable 行不正确(如果该字段不可为空,则将其设置为 NOT NULL)。

DECLARE @SQL NVARCHAR(MAX) = ' ';

SELECT  @SQL = @SQL + ' ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(sys.columns.object_id)) + '.' + 
                        QUOTENAME(OBJECT_NAME(sys.columns.object_id)) + 
                        ' ALTER COLUMN ' + QUOTENAME(sys.columns.Name) + 
                        ' NVARCHAR(MAX) ' + 
                        CASE WHEN is_nullable = 0 THEN 'NOT NULL' ELSE '' END 

FROM    sys.Tables
inner join sys.columns on sys.tables.object_id = sys.columns.object_id
WHERE   sys.columns.system_type_id = 99 ; --NTEXT 

EXECUTE sp_executesql @SQL;
GO
于 2017-11-06T21:32:43.557 回答