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

标签 sql sql-server tsql ssms

背景:

SQL Server Management Studio 允许定义自己的查询快捷方式(工具 > 选项 > 环境 > 键盘 > 查询快捷方式):

enter image description here

图片来自: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

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

SELECT COUNT(*) FROM my_schema.my_table;
<小时/>

尝试#1

现在我想写一些更具体的内容,例如将表名称传递/连接到以下查询(这只是示例):

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

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

SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID('

我必须使用:

my_schema.my_table')
-- highlight it
-- press CTRL + 3

附加的')非常丑陋且不方便。

尝试#2:

第二次尝试是使用Dynamic-SQL:

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

执行:

 my_table
 -- highligt it 
 -- and run 

LiveDemo

当表名被引用[my_table]时也有效。只要对象位于 dbo(默认)架构中。

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

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

执行:

my_schema.my_table
[my_schema].[my_table]

LiveDemo2

Incorrect syntax near '.'.

当然我可以写:

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

并将其命名为:

 [my_schema].[my_table]'

但是额外的 ' 也很丑陋且不方便。

问题:

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

  2. 是否可以传递 dostored_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 '.'.

LiveDemo3

最佳答案

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

据我所知,没有解决方法可以实现此目的。

1-b。是否可以传递多个值?

可以使用分隔符对字符串值进行处理,然后将值拆分到另一侧。遗憾的是,没有太多特殊字符来完成这项工作,因为它们几乎都会引发语法错误。然而,“#”可能是一个明智的选择,因为它已经是 tempDB 中临时表的 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

然后按照此图像所示配置您的快捷方式。 (注意最后的空格) enter image description here

结果:
enter image description here

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

如果您确实想处理具有相同标识符的两个不同模式,那么使用答案 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

用法(请注意,指定架构不是强制性的):
enter image description here

因此,由于必须将分割字符加倍很不方便,因此最好能够像上面所述那样猜测模式。

关于SQL Server 将标识符传递给存储过程/动态 SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38410040/

相关文章:

MYSQL - 根据单个 CASE 语句更新多个字段

sql - 根据 Key 求平均值

sql-server - 使用字节大小的列长度有什么意义吗?

sql - 使 SQL 查询更高效

sql-server - 表分组依据 - Sql -

sql - Access ODBC 问题 : ODBC--Call failed

mysql - 动态mysql查询两张表

sql - 如何优化SQL查询以达到最短执行时间

sql - 如何在MAC OSX中拆分SQL?

sql-server - 从数据库中删除实体时如何提高性能?