我该如何以程序化的方式将所有bigint类型的列更改为int类型?这是可能的吗?会不会引起任何现有的约束等问题?
我只想更改表格和特定数据库中的内容。
我正在使用SQL Server 2008 R2。
我需要对数百个字段执行此操作,希望一次运行即可更新所有表格字段。我想保留任何现有的约束、空值状态和默认值。
因此,基本上是将整个数据库中的bigint类型更改为int类型,除了字段类型之外不更改任何其他内容。
谢谢!
我曾经遇到过这种问题。我需要将int
更改为bigint
。这很困难,但是可以实现。使用以下语句更改数据类型非常容易:
Alter table myTable alter column targetcolumn bigint not null
但是,如果您的列涉及约束关系,则必须先删除约束,然后进行更改,最后重新创建约束。
Alter table myTable drop constraint [fkconstraintname]
Alter table myTable alter column targetcolumn int not null
Alter table othertable alter column targetcolumn int not null
Alter table myTable add constraint [fkconstraintname] foreign key (targetcolumn) references othertable(targetcolumn)
编辑
如果有很多约束条件,那么更改它会非常麻烦。如果有很多带有约束条件的表格,并且没有极端的紧急情况需要更改,请不要这样做。
编辑
然后你可以这样做。通过管理工具连接到Sql Server,右键单击必要的数据库 => 任务 => 生成脚本。
下一步 => 下一步
在此时按高级选项。将要脚本化的数据类型
设置为模式和数据。选择任何适合您的输出(文件、查询窗口)?单击“确定”并继续执行。它将为您生成完整的DDL和DML,如下所示:
USE [master]
GO
/****** Object: Database [Zafarga] Script Date: 02/02/2012 19:31:55 ******/
CREATE DATABASE [Zafarga] ON PRIMARY
GO
ALTER DATABASE [Zafarga] SET COMPATIBILITY_LEVEL = 100
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [Zafarga].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [Zafarga] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [Zafarga] SET ANSI_NULLS OFF
GO
ALTER DATABASE [Zafarga] SET ANSI_PADDING OFF
GO
ALTER DATABASE [Zafarga] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [Zafarga] SET ARITHABORT OFF
GO
ALTER DATABASE [Zafarga] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [Zafarga] SET AUTO_CREATE_STATISTICS ON
GO
ALTER DATABASE [Zafarga] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [Zafarga] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [Zafarga] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [Zafarga] SET CURSOR_DEFAULT GLOBAL
GO
ALTER DATABASE [Zafarga] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [Zafarga] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [Zafarga] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [Zafarga] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [Zafarga] SET ENABLE_BROKER
GO
ALTER DATABASE [Zafarga] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [Zafarga] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [Zafarga] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [Zafarga] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [Zafarga] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [Zafarga] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [Zafarga] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [Zafarga] SET READ_WRITE
GO
ALTER DATABASE [Zafarga] SET RECOVERY FULL
GO
ALTER DATABASE [Zafarga] SET MULTI_USER
GO
ALTER DATABASE [Zafarga] SET PAGE_VERIFY CHECKSUM
GO
ALTER DATABASE [Zafarga] SET DB_CHAINING OFF
GO
EXEC sys.sp_db_vardecimal_storage_format N'Zafarga', N'ON'
GO
USE [Zafarga]
GO
/****** Object: Table [dbo].[Category] Script Date: 02/02/2012 19:31:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Category](
[CategoryId] [bigint] IDENTITY(1,1) NOT NULL,
[CategoryName] [nvarchar](max) NULL,
PRIMARY KEY CLUSTERED
(
[CategoryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Product] Script Date: 02/02/2012 19:31:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Product](
[ProductId] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[Price] [decimal](18, 2) NOT NULL,
[CategoryId] [bigint] NOT NULL,
PRIMARY KEY CLUSTERED
(
[ProductId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: ForeignKey [Category_Products] Script Date: 02/02/2012 19:31:56 ******/
ALTER TABLE [dbo].[Product] WITH CHECK ADD CONSTRAINT [Category_Products] FOREIGN KEY([CategoryId])
REFERENCES [dbo].[Category] ([CategoryId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Product] CHECK CONSTRAINT [Category_Products]
GO
适当更改所有数据类型,然后运行。
您说所有数据都不到5000行。因此,无需修改插入语句。
准备好需要花费很长时间。
编辑
这将生成一个新的数据库,因此请准备好重命名您的原始数据库或新创建的数据库。
使用 SSMS 脚本整个数据库。 (在对象资源管理器窗格中右键单击数据库,选择“脚本数据库”,选择“创建到”,然后将其添加到新查询窗口并保存为文件。
搜索和替换所有 bigints 为 ints。(慢慢来,确保只更改必须更改的内容。)
修改脚本以创建新数据库(不同名称,不同文件)
运行并创建数据库。
难点:将旧数据库的表中的数据复制到新数据库。
如果像您说的那样,所有 bigints 都适合 ints,那么您不应该遇到任何问题;难点是找出实际执行所有操作的方法。肯定可以通过 SSMS 导入或导出向导来完成此操作,但我对这些工具并不太熟悉。如果没有,创建一系列 INSERT… SELECT… 语句按父级到子级表的顺序执行,并根据需要设置 IDENTITY INSERT,应该可以解决问题。
关于Martin Smith的问题 - 它比我想象的要简单得多:
ALTER TABLE YourTable MODIFY COLUMN OldColumn INT [NOT] NULL
就是这样
回答的旧版本:
如果新列不应该为空:
ALTER TABLE YourTable ADD NewFIeld INT NOT NULL DEFAULT (CAST(OldField AS INT))
GO
ALTER TABLE YourTable DROP COLUMN OldField
GO
exec sp_rename 'YourTable.NewField', 'OldField', 'COLUMN'
OR(或者)基本上是相同的,对于可空列更加宽松 - 在执行更新操作时不会锁定系统表
ALTER TABLE YourTable ADD NewFIeld INT NULL
GO
UPDATE YourTable SET NewField=OldField
GO
ALTER TABLE YourTable DROP COLUMN OldField
GO
exec sp_rename 'YourTable.NewField', 'OldField', 'COLUMN'
ALTER TABLE ... ALTER COLUMN
虽然可以正常工作,但两者仍会浪费空间,直到重建。 - Martin SmithALTER TABLE ... ALTER COLUMN
中指定。你的代码缺少任何锁来确保其他进程不会更新 OldField
。 - Martin Smith我会这样做:
我想这可能是最快的方法。如果逐列进行转换,则需要逐列进行转换。这涉及大量IO,可能会成为问题,具体取决于您的表的大小。
敬礼 GJ
除了答案之外,不要忘记检查所有列上的值是否在整数范围内(介于-2,147,483,648和2,147,483,647之间)。
为了自动化@Oleg Dok的答案,您可以在脚本中运行他的解决方案,该脚本循环遍历您的DB上的所有表和所有列。
smallint
?相比于bigint
的8个字节,它只有2个字节,并且可以具有超过32k的值。 - JNK