SQL Server将标识符传递给存储过程/动态SQL

Luk*_*zda 14 sql t-sql sql-server ssms

背景:

SQL Server Management Studio允许定义自己的查询快捷方式(Tools > Options > Environment > Keyboard > Query Shortcuts):

在此输入图像描述

图片来自:http://social.technet.microsoft.com/wiki/contents/articles/3178.how-to-create-query-shortcuts-in-sql-server-management-studio.aspx

my_schema.my_table
-- highlight it
-- press CTRL + 3 and you will get the number of rows in table
Run Code Online (Sandbox Code Playgroud)

它工作正常,但它以基本形式连接查询(据我所知只在最后).查询:

SELECT COUNT(*) FROM my_schema.my_table;
Run Code Online (Sandbox Code Playgroud)

尝试#1

现在我想要写的东西更具体的,例如通过/串连表的名字下面的查询(这只是例子):

SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(...)
Run Code Online (Sandbox Code Playgroud)

所以当我写入查询快捷方式时:

SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID('
Run Code Online (Sandbox Code Playgroud)

我必须使用:

my_schema.my_table')
-- highlight it
-- press CTRL + 3
Run Code Online (Sandbox Code Playgroud)

额外 ')的非常难看和不方便.

尝试#2:

第二个试验是使用Dynamic-SQL:

EXEC dbo.sp_executesql
      N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(@obj_name)'
     ,N'@obj_name SYSNAME'
     ,
Run Code Online (Sandbox Code Playgroud)

执行:

 my_table
 -- highligt it 
 -- and run 
Run Code Online (Sandbox Code Playgroud)

LiveDemo

引用表名时也可以使用[my_table].只要对象在dbo(默认)模式中.

问题是,当表有架构时,它将无法工作:

EXEC dbo.sp_executesql
      N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(@obj_name)'
     ,N'@obj_name SYSNAME'
     ,
Run Code Online (Sandbox Code Playgroud)

执行:

my_schema.my_table
[my_schema].[my_table]
Run Code Online (Sandbox Code Playgroud)

LiveDemo2

'.'附近的语法不正确.

我当然可以写:

EXEC dbo.sp_executesql
      N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(@obj_name)'
     ,N'@obj_name SYSNAME'
     ,'
Run Code Online (Sandbox Code Playgroud)

并称之为:

 [my_schema].[my_table]'
Run Code Online (Sandbox Code Playgroud)

但是额外'的也是丑陋和不方便的.

问题:

  1. 是否可以在中间(位置或甚至多个值)传递值,查询快捷方式窗口?

  2. 是否可以传递do stored_procedure/dynamic-sql限定标识符而不用包装',"

备注:

  • 我不搜索SSMS的插件
  • 我不想将object_name包装为 "my_schema.my_table"
  • 我知道有sp_helptext(这只是一个例子,我搜索方法)
  • 第一个问题是特定于工具(我知道它),但第二个问题是关于SQL Server.

编辑:

要澄清传递标识符到SP没有'":

CREATE TABLE dbo.my_table(col INT);
GO

CREATE PROCEDURE dbo.my_proc
  @a SYSNAME
AS
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(@a)
GO

EXEC dbo.my_proc
   @a = my_table;

EXEC dbo.my_proc
   @a = dbo.my_table;
-- Incorrect syntax near '.'.
Run Code Online (Sandbox Code Playgroud)

LiveDemo3

AXM*_*MIM 6

1.是否可以在中间传递值,查询快捷方式窗口?

据我所知,没有解决方法来实现这一目标.

1-B.是否可以传递多个值?

可以使用分隔符对字符串值进行操作,然后在另一侧分割值.遗憾的是,完成这项工作的特殊人物并不多,因为它们几乎都会引发语法错误.但是'#'可能是明智的选择,因为它已经是临时表中临时表的SQL的特殊字符.只检查你是否还没有使用它的标识符,因为它是SQL允许的(很难,它被禁止作为第一个字符).

下面是一个示例:
创建一个存储过程以将参数接收到一个单独的字符串中,并将该字符串拆分为包含每个参数.

    CREATE PROCEDURE sp_PassingMultipleStringValues 
        @Param1 NVARCHAR(MAX)
    AS

    --Here I'm using a XML split, but feel free to use any string split function you already have.
    DECLARE @xml        AS XML,
            @separator  AS VARCHAR(1)

    SELECT  @separator ='#',
            @xml = CAST('<X>'+ (REPLACE(@Param1,@separator ,'</X><X>') +'</X>') AS XML)

    SELECT N.value('.', 'VARCHAR(200)') AS value 
    FROM @xml.nodes('X') as T(N)
    --Do whatever is needed with them
Run Code Online (Sandbox Code Playgroud)

然后在此图像上配置您的快捷方式.(注意末尾的空格) 在此输入图像描述

结果:
在此输入图像描述

2.是否可以传递给stored_procedure/dynamic-sql限定标识符而不用','包裹它?

您是否有多个具有相同标识符的架构?
因为如果没有,那么使用sys.schemas而不是传递它在另一侧检索它呢?
你可以输入更少的东西,而不是在最后输入一个不方便的字符.

使用检索到的模式,您可以根据需要执行动态SQL.

    SELECT @Param1 = REPLACE(REPLACE(@Param1, '[', ''), ']', '')

    SELECT TOP 1 @Param1 = [Schema].name + '.' + @Param1
    FROM     sys.objects AS obj
    JOIN     sys.schemas AS [Schema] ON obj.schema_id = [Schema].schema_id
    WHERE    obj.name = @Param1

    SELECT * 
    FROM sys.columns 
    WHERE [object_id] = OBJECT_ID(@Param1)

    DECLARE @Query NVARCHAR(MAX) = 'SELECT TOP 1 * FROM ' + @Param1
    EXEC sp_sqlexec @Query
Run Code Online (Sandbox Code Playgroud)

如果您确实希望处理具有相同标识符的两个不同模式,那么通过使用在答案1-b中解释的方法将模式和标识符作为两个参数传递,它仍然是可行的.

一个例子中的一切

由于这里我们想要传递多个标识符并指定它们的模式,因此需要两个分隔符.

CREATE PROCEDURE sp_MultiArgsWithSchema
    @Param1 NVARCHAR(MAX)
AS

SELECT @Param1 = REPLACE(REPLACE(@Param1, '[', ''), ']', '')

--Here I'm using a XML split, but feel free to use any string split function you already have.
DECLARE @xml            AS XML,
        @ArgSeparator   AS VARCHAR(2),
        @SchemaSeparor  AS VARCHAR(1)

SELECT  @ArgSeparator = '##',
        @SchemaSeparor = '#',
        @xml = CAST('<X>'+ (REPLACE(@Param1,@ArgSeparator, '</X><X>') +'</X>') AS XML)

IF OBJECT_ID('tempdb..#QualifiedIdentifiers') IS NOT NULL 
    DROP TABLE #QualifiedIdentifiers;

--While splitting, we are putting back the dot instead of '#' between schema and name of object
SELECT QualifiedIdentifier = REPLACE(N.value('.', 'VARCHAR(200)'), @SchemaSeparor, '.') 
INTO #QualifiedIdentifiers
FROM @xml.nodes('X') as T(N)

SELECT * FROM #QualifiedIdentifiers

--From here, use what is inside #QualifiedIdentifiers and Dynamic SQL if need to achieve what is needed
DECLARE @QualifiedIdentifier    NVARCHAR(500)
WHILE EXISTS(SELECT TOP 1 1 FROM #QualifiedIdentifiers)
BEGIN
    SELECT TOP 1 @QualifiedIdentifier = QualifiedIdentifier
    FROM #QualifiedIdentifiers

    SELECT * 
    FROM sys.columns 
    WHERE [object_id] = OBJECT_ID(@QualifiedIdentifier)

    DELETE TOP (1) 
    FROM #QualifiedIdentifiers
    WHERE QualifiedIdentifier = @QualifiedIdentifier
END
Run Code Online (Sandbox Code Playgroud)

用法(请注意,指定模式不是必需的):
在此输入图像描述

因此,由于不得不将分割字符加倍,因此如果可以如上所述猜测模式,那将是最好的.