使用SQLCMD进行动态调用的更智能方式

时间:2016-04-28 15:12:07

标签: sql sql-server sqlcmd

我有这个MSSQL SQLCMD代码,它可以登录数据库,并且只需执行SELECT语句:

   :CONNECT czasql-001
   SELECT * FROM [Lps_Hepper_Cz].[config].[LpsPlant]
  GO

    :CONNECT LS_Hepper_DK

    SELECT * FROM [LPS_Hepper_NY].[config].[LpsPlant]

    :CONNECT LS_Hepper_DK
    SELECT * FROM [LPS_Hepper_DK].[config].[LpsPlant]

    :CONNECT LS_Hepper_DK
    SELECT * FROM [LPS_Hepper_SUPPLIER].[config].[LpsPlant]
    GO

           :CONNECT LS_Hepper_372
    SELECT * FROM [LPS_Hepper_MO].[config].[LpsPlant]
    GO

           :CONNECT LS_Hepper_678
    SELECT * FROM [LPS_Hepper_678].[config].[LpsPlant]
    GO

此解决方案可以正常工作,但要求我多次复制粘贴副本以更改数据库名称。但是有人可以通过使用循环来帮助我改进这一点。我试过使用临时表。像这样:

 declare @tbl table (ServerName nvarchar(50), DbName nvarchar(50), IsDone bit default(0))
 insert into @tbl (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
 insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_DK]')
 insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_NY]')
 insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_Supplier]')
 insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
 insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')

但是,当我的数据是nvarchar时,我无法想出通过数据库迭代连接到服务器并设置数据库名称的逻辑。 有人有建议吗?

更新 我只会将其用于INSERT / UPDATE或DELETE。所以我不使用存储过程。我喜欢用它来更新我们所有数据库的数据。这就是为什么我只使用应该成为脚本一部分的临时表。

Servernames和数据库名称将来自上面的临时表。表名在所有数据库中都是相同的,因为我们在全球范围内拥有数据库副本以限制数据下载,我需要确保在更新时,我还会更新其余数据库。

更新2: 我试图玩它,但我一直停滞不前,因为无法使用临时表中的值。这意味着我无法使用:SETVAR来设置服务器名称:

  declare @tbl table (ServerName nvarchar(50), DbName nvarchar(50), IsDone bit default(0))
     insert into @tbl (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
     insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_DK]')
     insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_NY]')
     insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_Supplier]')
     insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
     insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')

      WHILE (SELECT COUNT(*) FROM @tbl WHERE IsDone = 0) > 0
        BEGIN

        DECLARE @selectedRow INT = (SELECT TOP 1 Id FROM @tbl WHERE IsDone = 0)
        --DECLARE @ServerName NVARCHAR(50)= (SELECT ServerName FROM @tbl WHERE Id = @selectedRow)
        --DECLARE @DatabaseName NVARCHAR(50) = (SELECT DbName FROM @tbl WHERE Id = @selectedRow)
         DECLARE @ServerName sysname= (SELECT ServerName FROM @tbl WHERE Id = @selectedRow)
        DECLARE @DatabaseName sysname = (SELECT DbName FROM @tbl WHERE Id = @selectedRow)

        :SETVAR DatabaseName @DatabaseName
        :SETVAR ServerName @ServerName
        SELECT ServerName --This looks correctly
        print CONVERT(NVARCHAR(100),@selectedRow)
        :CONNECT ServerName

           USE @DatabaseName
           GO
          SELECT * FROM [config].[LpsPlant]
         GO

         UPDATE @tbl SET IsDone = 1 WHERE Id = @selectedRow
    END;

4 个答案:

答案 0 :(得分:1)

  

我只会将其用于INSERT / UPDATE或DELETE。所以我不使用存储过程。我喜欢用它来更新我们所有数据库的数据

如果是这种情况,您可以考虑使用 Registered Servers

  

注册服务器的好处

     

使用已注册的服务器,您可以:

     
      
  • 注册服务器以保留连接信息。

  •   
  • 确定注册的服务器是否正在运行。

  •   
  • 轻松将对象资源管理器和查询编辑器连接到已注册的服务器。

  •   
  • 编辑或删除已注册服务器的注册信息。

  •   
  • 创建服务器组。

  •   
  • 通过在注册服务器名称框中提供与其不同的值,为注册服务器提供用户友好名称   服务器名称列表。

  •   
  • 提供已注册服务器的详细说明。

  •   
  • 提供已注册服务器组的详细说明。

  •   
  • 导出已注册的服务器组。

  •   
  • 导入已注册的服务器组。

  •   
  • 查看SQL Server的联机或脱机实例的SQL Server日志文件

  •   
  • Execute Statements Against Multiple Servers Simultaneously
  •   

您可以根据以下内容创建多个组:服务器/数据库/环境(DEV / PROD / QA)。

另一种可能性是将注册的服务器导出到文件,放入源控制系统(SVN / Git)并与其他开发人员共享。

使用SSMS,您可以根据服务器组单击新查询,并立即对多个数据库执行相同的查询。

enter image description here

图片来自:http://sqlmag.com/site-files/sqlmag.com/files/archive/sqlmag.com/content/content/142469/Greenwood-SQL2331-Fig5-sm.jpg

答案 1 :(得分:1)

执行以下步骤:

1)创建链接服务器。

2)运行以下脚本我修改了你的代码片段

IF OBJECT_ID('tempdb..##Results') IS NOT NULL
    Truncate TABLE ##Results
else
    CREATE TABLE ##Results
    (id int identity ,ServerName nvarchar(50), DbName nvarchar(50), IsDone bit default(0))
      -- populat link server name and db name 
     insert into ##Results (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
     insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_DK]')
     insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_NY]')
     insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_Supplier]')
     insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
     insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')

      WHILE (SELECT COUNT(*) FROM ##Results WHERE IsDone = 0) > 0
        BEGIN

        DECLARE @selectedRow INT = (SELECT TOP 1 Id FROM ##Results WHERE IsDone = 0)
        DECLARE @sq1 varchar (100) ='SELECT * FROM ' ; --
         DECLARE @sql varchar (8000) = '';
        DECLARE @FROM varchar (100) ='[config].[LpsPlant]' ;
                 select @sql = @sq1 + ServerName + '.'+ DbName+ @FROM FROM ##Results WHERE Id = @selectedRow

        print @sql
         exec @sql

         UPDATE ##Results SET IsDone = 1 WHERE Id = @selectedRow
    END;

答案 2 :(得分:1)

使用光标,可能是:

CREATE TABLE #TEMP (ServerName nvarchar(50), DbName nvarchar(50))
insert into #TEMP (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_DK]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_NY]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_DK',  '[Lps_Hepper_Supplier]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')

DECLARE @ServerName VARCHAR(100),
@DatabaseName VARCHAR(100);

DECLARE CRS CURSOR LOCAL
FOR SELECT * FROM #TEMP

FETCH NEXT FROM CRS INTO @ServerName, @DatabaseName;

WHILE @@FETCH_STATUS=0
BEGIN
    print CONVERT(NVARCHAR(100),@selectedRow)

    :CONNECT @ServerName
    GO
    USE @DatabaseName
    GO
    SELECT * FROM [config].[LpsPlant]
    GO

    FETCH NEXT FROM CRS INTO @ServerName, @DatabaseName;
END

DROP TABLE #TEMP

答案 3 :(得分:1)

我没有运行你的代码,但我发现使用单词GO可能存在问题,这不是SQL关键字,而是SQL Server / SqlCmd关键字意味着“这里结束了一个脚本块,运行一切在其中等待所有后果“。我不确定它是否可以在WHILE循环内工作。

然后我看到你正在尝试

:CONNECT ServerName

但在documentation中,我看到语法为

:CONNECT $(ServerName)

还有你的循环问题。如果不使用SELECT,SQL Server不保证ORDER BY指令的顺序。如果你不关心执行指令的顺序,那就没关系,否则你需要用光标更改它,或者至少添加一个数字列,并在你选择TOP 1时按顺序排序。