SQL SERVER—将所有表的cjsj字段改为datetime2(0),去掉毫秒

主要目的是去掉毫秒:

sql 复制代码
DECLARE @SchemaName NVARCHAR(128)
DECLARE @TableName NVARCHAR(256)
DECLARE @FullTable NVARCHAR(517)
DECLARE @SQL NVARCHAR(MAX)
DECLARE @ConstraintName NVARCHAR(300)

-- 游标:查找所有含 cjsj 列的用户表
DECLARE TableCursor CURSOR FOR
SELECT 
    s.name,
    t.name
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE c.name = 'cjsj'
  AND t.is_ms_shipped = 0
ORDER BY s.name, t.name

OPEN TableCursor
FETCH NEXT FROM TableCursor INTO @SchemaName, @TableName

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @FullTable = QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName)
    PRINT 'Processing: ' + @FullTable

    BEGIN TRY
        -- === 合规性检查(兼容旧版)===
        DECLARE @IsCompliant BIT = 0

        SELECT 
            @IsCompliant = CASE 
                WHEN 
                    TYPE_NAME(c.user_type_id) = 'datetime2'
                    AND c.scale = 0               -- 注意:datetime2 的小数位数存储在 scale(不是 precision!)
                    AND c.is_nullable = 0
                    AND dc.definition = '(getdate())'
                THEN 1 
                WHEN 
                    TYPE_NAME(c.user_type_id) = 'datetime'
                    AND c.is_nullable = 0
                    AND dc.definition = '(getdate())'
                THEN 0  -- datetime 需要升级到 datetime2(0),不算合规
                ELSE 0 
            END
        FROM sys.columns c
        LEFT JOIN sys.default_constraints dc 
            ON c.object_id = dc.parent_object_id 
            AND c.column_id = dc.parent_column_id
        WHERE c.object_id = OBJECT_ID(@FullTable) 
          AND c.name = 'cjsj'

        IF ISNULL(@IsCompliant, 0) = 1
        BEGIN
            PRINT '  -> Already compliant (datetime2(0) NOT NULL DEFAULT GETDATE()), skipping.'
            FETCH NEXT FROM TableCursor INTO @SchemaName, @TableName
            CONTINUE
        END

        -- === 处理不合规表 ===
        BEGIN TRANSACTION

        -- 获取当前列信息
        DECLARE @CurrentType NVARCHAR(128), @IsNullable BIT
        SELECT 
            @CurrentType = TYPE_NAME(c.user_type_id),
            @IsNullable = c.is_nullable
        FROM sys.columns c
        WHERE c.object_id = OBJECT_ID(@FullTable) AND c.name = 'cjsj'

        -- 数据清洗(兼容旧版)
        IF @CurrentType NOT IN ('datetime', 'datetime2')
        BEGIN
            PRINT '  -> Cleaning non-date values in cjsj (using ISDATE)...'
            -- 使用 ISDATE 安全转换
            SET @SQL = '
                UPDATE ' + @FullTable + ' 
                SET cjsj = CASE 
                    WHEN cjsj IS NULL THEN GETDATE()
                    WHEN ISDATE(cjsj) = 1 THEN CONVERT(datetime, cjsj)
                    ELSE GETDATE()
                END
                WHERE cjsj IS NULL OR ISDATE(cjsj) = 0'
            EXEC sp_executesql @SQL
        END
        ELSE
        BEGIN
            -- 仅填充 NULL
            SET @SQL = 'UPDATE ' + @FullTable + ' SET cjsj = GETDATE() WHERE cjsj IS NULL'
            EXEC sp_executesql @SQL
            PRINT '  -> Updated NULLs to GETDATE()'
        END

        -- 删除依赖对象(默认约束、CHECK、索引)
        DECLARE @DropDependentsSQL NVARCHAR(MAX) = ''

        -- 默认约束
        SELECT @DropDependentsSQL += 'ALTER TABLE ' + @FullTable + ' DROP CONSTRAINT ' + QUOTENAME(dc.name) + ';'
        FROM sys.default_constraints dc
        JOIN sys.columns c ON dc.parent_object_id = c.object_id AND dc.parent_column_id = c.column_id
        WHERE dc.parent_object_id = OBJECT_ID(@FullTable) AND c.name = 'cjsj'

        -- CHECK 约束
        SELECT @DropDependentsSQL += 'ALTER TABLE ' + @FullTable + ' DROP CONSTRAINT ' + QUOTENAME(cc.name) + ';'
        FROM sys.check_constraints cc
        JOIN sys.columns c ON cc.parent_object_id = c.object_id AND cc.parent_column_id = c.column_id
        WHERE cc.parent_object_id = OBJECT_ID(@FullTable) AND c.name = 'cjsj'

        -- 非主键索引
        DECLARE @IndexName NVARCHAR(128)
        DECLARE IndexCursor CURSOR FOR
        SELECT i.name
        FROM sys.indexes i
        JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
        JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
        WHERE c.object_id = OBJECT_ID(@FullTable) 
          AND c.name = 'cjsj' 
          AND i.is_primary_key = 0
          AND i.is_unique_constraint = 0

        OPEN IndexCursor
        FETCH NEXT FROM IndexCursor INTO @IndexName
        WHILE @@FETCH_STATUS = 0
        BEGIN
            SET @DropDependentsSQL += 'DROP INDEX ' + QUOTENAME(@IndexName) + ' ON ' + @FullTable + ';'
            FETCH NEXT FROM IndexCursor INTO @IndexName
        END
        CLOSE IndexCursor
        DEALLOCATE IndexCursor

        IF LEN(@DropDependentsSQL) > 0
        BEGIN
            EXEC sp_executesql @DropDependentsSQL
            PRINT '  -> Dropped dependent objects'
        END

        -- 修改列为 datetime2(0) NOT NULL
        SET @SQL = 'ALTER TABLE ' + @FullTable + ' ALTER COLUMN cjsj datetime2(0) NOT NULL'
        EXEC sp_executesql @SQL
        PRINT '  -> Altered column to datetime2(0) NOT NULL'

        -- 添加默认约束
        SET @ConstraintName = 'DF_' + @SchemaName + '_' + @TableName + '_cjsj'
        IF LEN(@ConstraintName) > 128 
            SET @ConstraintName = LEFT(@ConstraintName, 120) + '_' + CAST(ABS(CHECKSUM(NEWID())) % 1000 AS VARCHAR(3))

        SET @SQL = '
        IF NOT EXISTS (
            SELECT 1 FROM sys.default_constraints dc
            JOIN sys.columns c ON dc.parent_object_id = c.object_id AND dc.parent_column_id = c.column_id
            WHERE dc.parent_object_id = OBJECT_ID(''' + REPLACE(@FullTable, '''', '''''') + ''')
              AND c.name = ''cjsj''
        )
        ALTER TABLE ' + @FullTable + ' ADD CONSTRAINT ' + QUOTENAME(@ConstraintName) + ' DEFAULT GETDATE() FOR cjsj'
        EXEC sp_executesql @SQL
        PRINT '  -> Added default constraint: ' + @ConstraintName

        COMMIT TRANSACTION
        PRINT '  -> SUCCESS'

    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION
        PRINT 'ERROR in ' + @FullTable + ': ' + ERROR_MESSAGE()
    END CATCH

    FETCH NEXT FROM TableCursor INTO @SchemaName, @TableName
END

CLOSE TableCursor
DEALLOCATE TableCursor
相关推荐
随身数智备忘录14 小时前
财务数据分析如何与业务场景结合?财务数据分析如何从数出有据到数出有用?
数据库
这个DBA有点耶15 小时前
数据库教程:从零基础到实战的完整学习路径(2026版)
数据库·程序员·代码规范
forestsea16 小时前
从零构建 Java 智能体 RAG 系统:Milvus 向量数据库实战指南
java·数据库·milvus
probex_16 小时前
从 ByConity 到 VictoriaMetrics:一次指标数据迁移引发的四种存储对比
数据库
Patrick在香港17 小时前
Python 审计香港开放数据目录:两个端点差 10 倍,只有 9.3% 的资源标了「最后修改时间」
开发语言·数据库·python·数据分析·api·数据治理·开放数据
这个DBA有点耶17 小时前
自增主键用尽了怎么办?INT溢出、在线迁移与预防策略全解析
数据库·mysql·代码规范
老纪的技术唠嗑局17 小时前
Agent 习惯性删库跑路,数据库纷纷学 Git 续命
数据库·人工智能
Data_Journal18 小时前
使用 AutoScraper 进行网页抓取:分步教程
大数据·开发语言·数据库·python·scrapy
白远山18 小时前
健身场馆无人自动化解决方案:从架构到落地实践
java·开发语言·数据库·数据挖掘·需求分析
虎虎(_ _)。゜zzZ19 小时前
SQLAlchemy入门教程
数据库·后端·python·sql·ai·sqlalchemy