2016-11-11 2 views
2

Ich habe ein CREATE TABLE Skript. Wenn ich es über die -Befehlszeile ausführe, erstellt es keine nullfähigen Spalten. Wenn ich es manuell über SQL Server Query Browser ausführen, tut es. Was vermisse ich?Warum behandelt SQL Server dieselbe SQL anders?

über die Kommandozeile

ich versucht ist Lehre 2 Schema-Kommandozeilen-Tool zu verwenden, um mein Schema in SQL Server 2014 (1) zu erstellen.

Hier ist die SQL ist es aus meiner Entität Anmerkungen erstellt (2) (beachten Sie, address_2 ist nullable) (der Abstand Pfeil und sind von mir):

# 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 

Nach SQL Server Profiler, erhält SQL Server die folgende Befehle (beachten Sie, sollte address_2 noch nullable sein) (der Abstand Pfeil und sind von mir):

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 

jedoch, wenn Sie die erstellte Tabelle inspizieren, address_2 ist NOT NULL.

Hier ist ein Screenshot der Tabelle Browser sowie die Ausgabe von SQL Server's equivalent to MySQL's SHOW CREATE TABLE (der Abstand Pfeil und ist von mir):

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 

über den Query Browser

Jetzt, Hier kommt der lustige Teil.

Wenn Sie die genau gleichen Befehle ausführen, die SQL Server (nach dem SQL Server Profiler) in dem SQL Server Query Browser empfangen wird (der Abstand Pfeil und ist von mir):

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 

Die address_2 Feld ist 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 

Fazit

Was in der Welt ist los? Wie kann das gleiche SQL-Skript produzieren verschiedene Ergebnisse?

Ich habe im Internet nach Hilfe gesucht, aber ich kann keine Erklärung oder Lösung für das Problem finden. Jede Hilfe würde sehr geschätzt werden!

In meinem Kopf:

  • Die SET Flaggen sollten keine Rolle spielen, da die Abfrage in dem SQL Server Query Browser mit ihnen arbeitet. Außerdem habe ich nach ihnen gesucht, und keiner von ihnen scheint das Verhalten von T-SQL gegenüber optionalen Spalten zu ändern.
  • Die Hoops, die ich durchsprang, um Doctrine mit SQL Server von einem * nix-Rechner zu verbinden, sollten keine Rolle spielen (1), da die Befehle, die SQL Server erreichen (wie vom SQL Server Profiler gezeigt), im Query Browser funktionieren.

Fußnoten

  1. Ich verbinde Lehre zu SQL Server von einem CentOS Maschine. Ich verwende FreeTDS, um eine Verbindung zum SQL Server herzustellen, und ich verwende einen DBlib Doctrine Driver von Drittanbietern. Ich weiß, das ist gewunden, haha.
  2. Ich habe die Entität nicht eingeschlossen, weil ich nicht sicher bin, dass es helfen wird. Das von Doctrine generierte SQL ist korrekt.
+4

['SET ANSI_NULL_DFLT_ON'] (https://msdn.microsoft.com/library/ms187375). Und jetzt weißt du, warum du immer explizit sein solltest. –

+0

Spot auf Bemerkung von Jeroen :). Kleine Frage: Wenn Sie "SQL Server Query Browser" erwähnen, meinen Sie "SQL Server Management Studio"? –

+0

@JeroenMostert du bist mein Held! Ich konnte die erstellte SQL Doctrine nicht ändern. Aber ich habe die globale Option für die Datenbank (Rechtsklick-Datenbank> Eigenschaften> Optionen> ANSI NULL Default auf true gesetzt), und es wurde behoben! Lektion gelernt! Können Sie Ihr _comment_ stattdessen als _answer_ hinzufügen, damit ich es akzeptieren kann? – Jack

Antwort

2

Wenn Sie nicht explizit angeben, ob eine Spalte NULL oder NOT NULL in Ihrem CREATE TABLE, werden die Dinge kompliziert. Unnötig, könnte man sagen.

In ihrer Weisheit die Entwickler von SQL Server (oder wahrscheinlicher, um die Abwärtskompatibilität zu sorgen) sah fit dies nicht weniger als drei Optionen regiert haben:

  • Wenn die (Session-Ebene) Option ANSI_NULL_DFLT_ON ist ON, dann sind nicht angegebene Spalten nullfähig.
  • Wenn die Option ANSI_NULL_DFLT_OFF (Sitzungsebene) ON ist, können nicht angegebene Spalten keine Nullwerte enthalten.
  • Diese Optionen sind exklusiv, so dass sie nicht beide ON sein können. Sie können jedoch beide OFF sein. Wenn dies der Fall ist, wird die NULL-Zulässigkeit durch die Option ANSI_NULL_DEFAULT auf Datenbankebene bestimmt, die entweder ON (nicht angegebene Spalten sind nullwertfähig) oder OFF (nicht angegebene Spalten sind nicht nullfähig) sein kann.

Die Mehrheit der Kunden über ODBC oder OLE DB, wird eine Verbindung, die ANSI_NULL_DFLT_ON beide eingestellt werden (es ist alles nicht ANSI für nichts, nachdem genannt). Dies bedeutet, dass die meisten "modernen" Clients immer nullfähige Spalten erhalten, wenn nichts angegeben ist. Aber Clients, die sich über die (alte) DB-Library und scheinbar auch FreeTDS in diesem speziellen Setup verbinden, geben diese Optionen nicht an, und so kommt die Datenbankeinstellung ins Spiel.

Bei der Datenbankerstellung werden die Einstellungen aus der Datenbank model übernommen und sind documented. Sie betonen die Rückwärtskompatibilität und es sollte nicht überraschen, dass ANSI_NULL_DEFAULT für neu erstellte Datenbanken standardmäßig OFF ist. Aber auch hier zumindest haben Sie die Möglichkeit, in Schritt und die Dinge zu ändern, mit

ALTER DATABASE [db] SET ANSI_NULL_DEFAULT ON 

Unabhängig davon, ob es eine gute Idee, diese auf Ihrem Setup zu tun, hängt davon ab. Wenn möglich, sollten Sie sich durch Treiber verbinden, die die Option ANSI_NULL_DLFT_ON setzen (oder tun Sie dies explizit selbst), damit alle Anwendungen, ob alt oder neu, das bekommen, was sie erwarten. Das Festlegen von Standardeinstellungen für die Datenbank (oder sogar model, damit alle Datenbanken sie erben) kann eine gute Sache sein, da sie Konsistenz gewährleistet, oder es könnte eine schlechte Sache sein, da sie alte Clients zerstört.

Als Books Online wisely notes on this subject:

Für einen zuverlässigeren Betrieb von Transact-SQL-Skripte, die in Datenbanken mit unterschiedlichen NULL-Zulässigkeit Einstellungen verwendet werden, ist es besser NULL oder NOT NULL in CREATE TABLE und ALTER TABLE Aussagen zu spezifizieren.

Wenn die Doctrine-Autoren dies getan hätten, hätten Sie alles über den obigen Text vergessen können.


Während FreeTDS immer noch eine beliebte Wahl ist, möchte ich darauf hinweisen, dass Microsoft hat in der letzten Zeit mehr Ressourcen verpflichtet, ihre ehemals schmachtend Cross-Plattform-ODBC-Unterstützung. Die Microsoft ODBC Driver for SQL Server on Linux ist zum Zeitpunkt der Erstellung der besten Konnektivität Option für Linux in Bezug auf Funktionen und Kompatibilität, und es sollte die Probleme mit SET Optionen mit unerwartet alten Standards vermeiden. Wenn Ihre Software ODBC-Unterstützung hat, ist es eine Überlegung wert.

+0

Über und über meinem Freund haha! Danke nochmal. – Jack

Verwandte Themen