2016-10-10 70 views
1

我有一個DDL腳本,將創建一堆表,並且我正在使用this script在測試之間清理數據庫。爲什麼PDO不是第一次執行整個陳述?

我第一次運行這個腳本時,它會創建所有表,就像它應該那樣。

CleanMsSQLdb($pdo); 

$ddl = file_get_contents(__DIR__.'/ddl.sql'); 

$pdo->exec($ddl); 

enter image description here

但對於一些奇怪的原因,如果我嘗試運行該腳本第二次,我因爲它沒有丟棄所有的表像它應該得到一個錯誤。

PHP Fatal error: Uncaught PDOException: SQLSTATE[42S01]: Base table or view already exists: 2714 [Microsoft][ODBC Driver 13 for SQL Server][SQL Server] There is already an object named 'tmpDataRecordSAMPLE' in the database. (SQLExecDirect[2714] at /build/php7.0-41GaEn/php7.0-7.0.8/ext/pdo_odbc/odbc_driver.c:247)

enter image description here

真正擾亂我的是,如果我只是連續運行腳本清潔兩次,然後將其丟棄一切工作正常。

CleanMsSQLdb($pdo); 
CleanMsSQLdb($pdo); 

$ddl = file_get_contents(__DIR__.'/ddl.sql'); 

$pdo->exec($ddl); 

爲什麼它不會在第一次通過時刪除所有表格?

我在嘗試刪除表時沒有收到任何錯誤。

如果我運行在Microsoft SQL Server Management Studio中的語句,那麼它丟棄所有的表,因爲它應該在第一輪,那麼爲什麼不從PDO?


關於我

我運行Ubuntu Linux操作系統16.04.1用PHP 7.0.8-0ubuntu0.16.04.3(CLI)(NTS)連接到Microsoft SQL Server 2012(SP3)(KB3072779 ) - 11.0.6020.0(X64)使用Microsoft® ODBC Driver 13 (Preview) for SQL Server®

$hostname = 'sql.example.com'; 
$database = 'mydb'; 
$username = 'db_owner'; 
$password = '[email protected]'; 
$driver = 'ODBC Driver 13 for SQL Server'; 

$pdo = new PDO("odbc:Driver=$driver; 
    Server=$hostname; 
    Database=$database", 
    $username, 
    $password 
); 
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

ddl.sql

很抱歉的大數據轉儲,但我無法重現,這將小的腳本,所以有一些好奇日尤其是表格。

CREATE TABLE [tmpData] (
    [date] datetime, 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecord] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecord 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpData](jpetl_id), 
    [id] tinyint, 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLE] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLE 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecord](jpetl_id), 
    [id] tinyint, 
    [created] datetime, 
    [CONTRACT_TERM] varchar(8), 
    [PRICE] decimal(6,3), 
    [ABSTRACT] varchar(100), 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLEADMIN_DEP] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLEADMIN_DEP 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecordSAMPLE](jpetl_id), 
    [id] bigint, 
    [primaryKey] varchar(10), 
    [DEP] varchar(10), 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLESUPP_DEP] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLESUPP_DEP 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecordSAMPLE](jpetl_id), 
    [id] bigint, 
    [primaryKey] varchar(19), 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLESUPP_DEPDEP] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLESUPP_DEPDEP 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecordSAMPLESUPP_DEP](jpetl_id), 
    [DEP] varchar(19), 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLETITLE] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLETITLE 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecordSAMPLE](jpetl_id), 
    [TITLE] varchar(19), 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLESAMPLE_AUTH] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLESAMPLE_AUTH 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecordSAMPLE](jpetl_id), 
    [id] tinyint, 
    [FACULTY_NAME] smallint, 
    [FACULTY_NAMEfid] smallint, 
    [FNAME] varchar(4), 
    [MNAME] varchar(100), 
    [LNAME] varchar(3), 
    [ISSTUDENT] varchar(100), 
    [DISPLAY] varchar(2), 
    [INITIATION] datetime, 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [tmpDataRecordSAMPLESAMPLE_EDITOR] (
    jpetl_pid int, 
    CONSTRAINT fk_tmpDataRecordSAMPLESAMPLE_EDITOR 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [tmpDataRecordSAMPLE](jpetl_id), 
    [id] tinyint, 
    [FACULTY_NAME] varchar(100), 
    [FNAME] varchar(100), 
    [MNAME] varchar(100), 
    [LNAME] varchar(100), 
    [DISPLAY] varchar(100), 
    jpetl_id int IDENTITY PRIMARY KEY 
); 

CREATE TABLE [Data] (
    [date] datetime, 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecord] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecord 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [Data](jpetl_id), 
    [id] tinyint, 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLE] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLE 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecord](jpetl_id), 
    [id] tinyint, 
    [created] datetime, 
    [CONTRACT_TERM] varchar(8), 
    [PRICE] decimal(6,3), 
    [ABSTRACT] varchar(100), 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLEADMIN_DEP] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLEADMIN_DEP 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecordSAMPLE](jpetl_id), 
    [id] bigint, 
    [primaryKey] varchar(10), 
    [DEP] varchar(10), 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLESUPP_DEP] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLESUPP_DEP 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecordSAMPLE](jpetl_id), 
    [id] bigint, 
    [primaryKey] varchar(19), 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLESUPP_DEPDEP] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLESUPP_DEPDEP 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecordSAMPLESUPP_DEP](jpetl_id), 
    [DEP] varchar(19), 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLETITLE] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLETITLE 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecordSAMPLE](jpetl_id), 
    [TITLE] varchar(19), 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLESAMPLE_AUTH] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLESAMPLE_AUTH 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecordSAMPLE](jpetl_id), 
    [id] tinyint, 
    [FACULTY_NAME] smallint, 
    [FACULTY_NAMEfid] smallint, 
    [FNAME] varchar(4), 
    [MNAME] varchar(100), 
    [LNAME] varchar(3), 
    [ISSTUDENT] varchar(100), 
    [DISPLAY] varchar(2), 
    [INITIATION] datetime, 
    jpetl_id int PRIMARY KEY 
); 

CREATE TABLE [DataRecordSAMPLESAMPLE_EDITOR] (
    jpetl_pid int, 
    CONSTRAINT fk_DataRecordSAMPLESAMPLE_EDITOR 
     FOREIGN KEY (jpetl_pid) 
     REFERENCES [DataRecordSAMPLE](jpetl_id), 
    [id] tinyint, 
    [FACULTY_NAME] varchar(100), 
    [FNAME] varchar(100), 
    [MNAME] varchar(100), 
    [LNAME] varchar(100), 
    [DISPLAY] varchar(100), 
    jpetl_id int PRIMARY KEY 
); 

CleanMsSQLdb

這是相當多從this script一個複製粘貼只能分手批次GO陳述爲多個exec

function CleanMsSQLdb(PDO $pdo){ 
    $sql = " 
     /* Drop all non-system stored procs */ 
     DECLARE @name VARCHAR(128) 
     DECLARE @SQL VARCHAR(254) 

     SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 ORDER BY [name]) 

     WHILE @name is not null 
     BEGIN 
      SELECT @SQL = 'DROP PROCEDURE [dbo].[' + RTRIM(@name) +']' 
      EXEC (@SQL) 
      PRINT 'Dropped Procedure: ' + @name 
      SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 AND [name] > @name ORDER BY [name]) 
     END 
    "; 
    $pdo->exec($sql); 

    $sql = " 
     /* Drop all views */ 
     DECLARE @name VARCHAR(128) 
     DECLARE @SQL VARCHAR(254) 

     SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 ORDER BY [name]) 

     WHILE @name IS NOT NULL 
     BEGIN 
      SELECT @SQL = 'DROP VIEW [dbo].[' + RTRIM(@name) +']' 
      EXEC (@SQL) 
      PRINT 'Dropped View: ' + @name 
      SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 AND [name] > @name ORDER BY [name]) 
     END 
    "; 
    $pdo->exec($sql); 

    $sql = " 
     /* Drop all functions */ 
     DECLARE @name VARCHAR(128) 
     DECLARE @SQL VARCHAR(254) 

     SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 ORDER BY [name]) 

     WHILE @name IS NOT NULL 
     BEGIN 
      SELECT @SQL = 'DROP FUNCTION [dbo].[' + RTRIM(@name) +']' 
      EXEC (@SQL) 
      PRINT 'Dropped Function: ' + @name 
      SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 AND [name] > @name ORDER BY [name]) 
     END 
    "; 
    $pdo->exec($sql); 

    $sql = " 
     /* Drop all Foreign Key constraints */ 
     DECLARE @name VARCHAR(128) 
     DECLARE @constraint VARCHAR(254) 
     DECLARE @SQL VARCHAR(254) 

     SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME) 

     WHILE @name is not null 
     BEGIN 
      SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
      WHILE @constraint IS NOT NULL 
      BEGIN 
       SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']' 
       EXEC (@SQL) 
       PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name 
       SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
      END 
     SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME) 
     END 
    "; 
    $pdo->exec($sql); 

    $sql = " 
     /* Drop all Primary Key constraints */ 
     DECLARE @name VARCHAR(128) 
     DECLARE @constraint VARCHAR(254) 
     DECLARE @SQL VARCHAR(254) 

     SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME) 

     WHILE @name IS NOT NULL 
     BEGIN 
      SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
      WHILE @constraint is not null 
      BEGIN 
       SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint)+']' 
       EXEC (@SQL) 
       PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name 
       SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
      END 
     SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME) 
     END 
    "; 
    $pdo->exec($sql); 

    $sql = " 
     /* Drop all tables */ 
     DECLARE @name VARCHAR(128) 
     DECLARE @SQL VARCHAR(254) 

     SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name]) 

     WHILE @name IS NOT NULL 
     BEGIN 
      SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']' 
      EXEC (@SQL) 
      PRINT 'Dropped Table: ' + @name 
      SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name]) 
     END 
    "; 
    $pdo->exec($sql); 
} 
+0

嘗試遍歷結果和收到錯誤信息如下所述:https://phpdelusions.net/pdo#multiquery - 它應該報告錯誤,如果有任何錯誤(並且在清理過程失敗時應該有)。 –

+0

@YourCommonSense感謝您的輸入,但我試圖應用盡我所能,但因爲我的語句沒有返回結果集,試圖調用'$ stmt-> fetchAll()'會導致錯誤'遊標狀態無效SQLFetchScroll [0]' –

+0

是的,當然fetchall在這裏沒有意義。我希望你會閱讀解釋部分,返回多個查詢的結果 –

回答

0

原來所有這些PRINT語句用光標干擾,但只適用於外鍵丟失。

有兩個補丁,要麼刪除所有PRINT陳述或close the cursor

使用後者,我改變了所有的EXEC行:

$pdo->exec($sql); 

查詢和靠近光標:

$pdo->query($sql)->closeCursor(); 

TL;博士

批處理語句中的每一個之後,我通過結果集循環查看這樣的錯誤消息:

$stmt = $pdo->prepare($sql); 
$stmt->execute(); 
do { 
    var_dump($stmt->errorInfo()); 
} while ($stmt->nextRowset()); 

我得到了一些好奇的結果。首先,我得到其中3個,這是有道理的,因爲我沒有過程,視圖或功能。

array(4) { 
    [0] => 
    string(5) "00000" 
    [1] => 
    int(0) 
    [2] => 
    string(24) " ((null)[0] at (null):0)" 
    [3] => 
    string(0) "" 
} 

然後我得到了其中的16個。在18張桌子中,有16桌有外鍵,所以這也是有道理的。儘管我很好奇爲什麼我只看到循環中的最後一個打印語句(我預計fk_DataRecord最後被刪除),每循環迭代一次。我希望print語句對於每個被刪除的16個fk_constraints都是不同的。

array(4) { 
    [0] => 
    string(5) "01000" 
    [1] => 
    int(0) 
    [2] => 
    string(186) "[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Dropped FK Constraint: fk_DataRecord on Da 
taRecord (SQLExecute[0] at /build/php7.0-41GaEn/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:256)" 
    [3] => 
    string(5) "01000" 
} 

然後我很困惑,問題不存在了!

這使我發現在execute documentation一個有益的提示:

Note:
Some drivers require to close cursor before executing next statement.