Invoke-Sqlcmd runs script twice

大兔子大兔子 提交于 2021-02-08 13:59:16

问题


I experienced a very strange issue and can be repeated.

Basically, I use invoke-sqlcmd to call a script file by using -inputfile, but if the script file has some execution error (like insert into a table where a column should not be null), the script file will be executed twice. I can see the two executions from profiler as well.

Here is the way to reproduce the issue (My environment: Win 8.1 + SQL2014 + PS 5.0)

  1. create two tables in a database

    Use TestDB
    
    create table dbo.s (id int identity primary key, b varchar(50));
    
    create table dbo.t (id int primary key, s_id int, b varchar(50));
    alter table dbo.t add constraint fk_t foreign key (s_id) references dbo.s(id)
    
  2. Now create a sql file (let's call it, c:\temp\t.sql) with the following two lines

    insert into dbo.s ( b) select  'hello world'
    insert into dbo.t (s_id, b) -- purposely missing id to cause an error
    select 1, 'good morning'
    
  3. Run the following PS cmdlet

    invoke-sqlcmd -Server "<my_local_server>" -database TestDB -inputfile "c:\temp\t.sql"
    

Your PS will return an error, now if you open an SSMS query window and do the following

select * from TestDB.dbo.s

You will see two records there instead of one. On the other hand, if I run sqlcmd.exe, there is NO such issue, i.e. just one record in dbo.s. Is there some configuration in SQLPS I missed?


回答1:


I see you asked this same question on the MSDN Database Engine forum: https://social.msdn.microsoft.com/Forums/en-US/d4167226-2da7-49ec-a5c2-60e964785c2c/powershell-invokesqlcmd-calls-stored-procedure-second-time-after-query-timeout-is-expired. Below is the SMO workaround from that thread.

$SqlServerName = "YourServer";
$DatabaseName = "YourDatabase";
$ScriptFileName = "C:\Scripts\YourSqlScriptFile.sql";

Add-Type -Path "C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll";

$sr = New-Object System.IO.StreamReader($ScriptFileName);
$script = $sr.ReadToEnd();
$sr.Close();

$Server = New-Object Microsoft.SqlServer.Management.Smo.Server($SqlServerName);
$db = $Server.Databases[$DatabaseName];
$db.ExecuteNonQuery($script);



回答2:


Updating this tread with the fix from Microsoft:

Cumulative Update 2 for SQL Server 2016 SP1
Cumulative Update 4 for SQL Server 2014 Service Pack 2

FIX: "Invoke-sqlcmd" cmdlet executes a query statement multiple times if an error occurs in SQL Server 2014 or 2016




回答3:


Even i had a similar issue.

Fixed it by adding -QueryTimeout parameter to Invoke-Sqlcmd cmdlet.

Basically it seems that the query somehow times out and due to a bug in Invoke-Sqlcmd cmdlet it tries to insert it again. Strange but try this. Keep the query timeout big enough for the query to execute.




回答4:


I know this is a old thread, but maybe it can help someone.

I found out if you move your line "select 1, 'good morning'" in your example before the insert statement, which has the exception, it works like intended.

I had a similar Issue with try catch, that the first return value will be ignored when it's an exception, so I had to make sure that the first line was Select 1. Strange bug.



来源:https://stackoverflow.com/questions/33271446/invoke-sqlcmd-runs-script-twice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!