我有一个CREATE TABLE
脚本。当我通过命令行运行它时,它不会创建可为空的列。当我通过SQL Server的查询浏览器手动运行它时,它确实如此。我错过了什么?
我试图使用Doctrine 2的命令行架构工具在SQL Server 2014(1)中创建我的架构。
以下是它从我的实体注释中创建的SQL(2)(注意,address_2
可以为空)(间距和箭头是我的):
# dump the SQL Doctrine will use
vendor/bin/doctrine-module orm:schema-tool:create --dump-sql
CREATE TABLE company (
id INT IDENTITY NOT NULL,
address_1 NVARCHAR(255) NOT NULL,
address_2 NVARCHAR(255), <-- it should be optional
city NVARCHAR(31) NOT NULL,
email NVARCHAR(255),
name NVARCHAR(255) NOT NULL,
phone NVARCHAR(12),
state NVARCHAR(2) NOT NULL,
zip NVARCHAR(5) NOT NULL,
PRIMARY KEY (id)
);
# execute the command
vendor/bin/doctrine-module orm:schema-tool:create
根据SQL Server Profiler,SQL Server收到以下命令(注意,address_2
应该仍然可以为空)(间距和箭头是我的):
set textsize 20971520
go
set textsize 2147483647
set quoted_identifier on
go
SET ANSI_WARNINGS ON
go
SET ANSI_PADDING ON
go
SET ANSI_NULLS ON
go
SET QUOTED_IDENTIFIER ON
go
SET CONCAT_NULL_YIELDS_NULL ON
go
CREATE TABLE company (
id INT IDENTITY NOT NULL,
address_1 NVARCHAR(255) NOT NULL,
address_2 NVARCHAR(255), <-- it should be optional
city NVARCHAR(31) NOT NULL,
email NVARCHAR(255),
name NVARCHAR(255) NOT NULL,
phone NVARCHAR(12),
state NVARCHAR(2) NOT NULL,
zip NVARCHAR(5) NOT NULL,
PRIMARY KEY (id)
)
go
但是,当您检查创建的表格时,address_2
为NOT NULL
。
这是表格浏览器的屏幕截图以及SQL Server's equivalent to MySQL's SHOW CREATE TABLE
的输出(间距和箭头是我的):
Table created via command line
USE [mydatabase]
GO
/****** Object: Table [dbo].[company] Script Date: 11/11/2016 9:47:03 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[company](
[id] [int] IDENTITY(1,1) NOT NULL,
[address_1] [nvarchar](255) NOT NULL,
[address_2] [nvarchar](255) NOT NULL, <-- it's not optional!
[city] [nvarchar](31) NOT NULL,
[email] [nvarchar](255) NOT NULL,
[name] [nvarchar](255) NOT NULL,
[phone] [nvarchar](12) NOT NULL,
[state] [nvarchar](2) NOT NULL,
[zip] [nvarchar](5) NOT NULL,
PRIMARY KEY CLUSTERED
(
[id] 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
现在,这里有趣的部分。
如果在SQL Server查询浏览器中运行SQL Server收到的 exact 相同的命令(根据SQL Server Profiler)(间距和箭头是我的):
set textsize 20971520
go
set textsize 2147483647
set quoted_identifier on
go
SET ANSI_WARNINGS ON
go
SET ANSI_PADDING ON
go
SET ANSI_NULLS ON
go
SET QUOTED_IDENTIFIER ON
go
SET CONCAT_NULL_YIELDS_NULL ON
go
CREATE TABLE company (
id INT IDENTITY NOT NULL,
address_1 NVARCHAR(255) NOT NULL,
address_2 NVARCHAR(255), <-- it should be optional
city NVARCHAR(31) NOT NULL,
email NVARCHAR(255),
name NVARCHAR(255) NOT NULL,
phone NVARCHAR(12),
state NVARCHAR(2) NOT NULL,
zip NVARCHAR(5) NOT NULL,
PRIMARY KEY (id)
)
go
address_2
字段为NULL
:
Table created via query browser
USE [mydatabase]
GO
/****** Object: Table [dbo].[company] Script Date: 11/11/2016 9:49:41 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[company](
[id] [int] IDENTITY(1,1) NOT NULL,
[address_1] [nvarchar](255) NOT NULL,
[address_2] [nvarchar](255) NULL, <-- it's optional!
[city] [nvarchar](31) NOT NULL,
[email] [nvarchar](255) NULL,
[name] [nvarchar](255) NOT NULL,
[phone] [nvarchar](12) NULL,
[state] [nvarchar](2) NOT NULL,
[zip] [nvarchar](5) NOT NULL,
PRIMARY KEY CLUSTERED
(
[id] 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
世界上发生了什么? 相同的 SQL脚本如何产生不同的结果?
我已经在网上寻求帮助,但我似乎找不到解决问题的方法或解决方法。任何帮助将不胜感激!
在我的脑海里:
SET
标志不重要,因为查询在SQL Server查询浏览器中与它们一起工作。另外,我已经调查过它们,但它们似乎都没有改变T-SQL对可选列的行为。脚注
答案 0 :(得分:2)
如果您未明确指定NULL
中的列是NOT NULL
还是CREATE TABLE
,事情会变得复杂。不用说,你可能会说。
凭借他们的智慧(或者,更可能是为了迎合向后兼容性),SQL Server的开发人员认为这适合由至少三个选项控制:
ANSI_NULL_DFLT_ON
为ON
,则未指定的列可以为空。ANSI_NULL_DFLT_OFF
为ON
,则未指定的列不可为空。ON
。但是,它们都可以OFF
。如果是,那么可为空性由数据库级选项ANSI_NULL_DEFAULT
控制,该选项可以是ON
(未指定的列可以为空)或OFF
(未指定的列不可为空)。 / LI>
大多数客户端将通过ODBC或OLE DB进行连接,这些客户端都会设置ANSI_NULL_DFLT_ON
(毕竟,它不会被称为ANSI
)。这意味着大多数&#34;现代&#34;如果没有指定任何内容,客户端将始终获得可为空的列。但是通过(古老)DB-Library连接的客户端,以及在这个特定设置中显然也是FreeTDS,不指定这些选项,因此数据库设置发挥作用。 1
在数据库创建时,设置来自model
数据库,并且是documented。它们强调向后兼容性,对于新创建的数据库,ANSI_NULL_DEFAULT
默认为OFF
也就不足为奇了。但至少你有机会介入并改变一切,
ALTER DATABASE [db] SET ANSI_NULL_DEFAULT ON
这样做是否好主意取决于您的设置。如果可能,您应该通过设置ANSI_NULL_DLFT_ON
选项的驱动程序进行连接(或者自己明确地执行此操作),以便所有应用程序(无论新旧)获得他们期望的内容。设置数据库的默认值(甚至在model
上,所以所有数据库都继承它们)可能是一件好事,因为它可以确保一致性,或者它可能是一件坏事,因为它会破坏旧客户端。
作为Books Online wisely notes on this subject:
用于更可靠的Transact-SQL脚本操作 具有不同可空性设置的数据库,最好指定 <{1}}或
NULL
NOT NULL
和CREATE TABLE
语句中的ALTER TABLE
。
如果教条作者这样做了,你可能已经忘记了上述所有文本。
1 虽然FreeTDS仍然是一个受欢迎的选择,但我想指出,微软近来已经为其以前萎靡不振的跨平台ODBC支持投入了更多资源。 Microsoft ODBC Driver for SQL Server on Linux是在为功能和兼容性方面编写Linux最佳连接选项时,它应该避免SET
选项具有意外古老默认值的问题。如果您的软件具有ODBC支持,则值得考虑。