SQL Server将标识符传递给存储过程/动态SQL 背景:
SQL Server将标识符传递给存储过程/动态SQL 背景:,sql,sql-server,tsql,ssms,Sql,Sql Server,Tsql,Ssms,SQL Server Management Studio允许定义自己的查询快捷方式(工具>选项>环境>键盘>查询快捷方式): 图片来源: 它工作正常,但它以基本形式连接查询(据我所知,仅在最后)。查询: 尝试#1 现在我想写一些更具体的东西,例如将表名传递/连接到以下查询(这只是一个示例): 因此,当我在查询快捷方式中写入时: SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(' 我必须使用: my_schema.my_tabl
SQL Server Management Studio
允许定义自己的查询快捷方式(工具>选项>环境>键盘>查询快捷方式
):
图片来源:
它工作正常,但它以基本形式连接查询(据我所知,仅在最后)。查询:
尝试#1 现在我想写一些更具体的东西,例如将表名传递/连接到以下查询(这只是一个示例): 因此,当我在查询快捷方式中写入时:
SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID('
我必须使用:
my_schema.my_table')
-- highlight it
-- press CTRL + 3
附加的”)
非常难看和不方便。
尝试#2:
第二次尝试是使用动态SQL:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(@obj_name)'
,N'@obj_name SYSNAME'
,
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
my_schema.my_table
[my_schema].[my_table]
当引用表名时也有效[my\u table]
。只要对象位于dbo
(默认)模式中
问题是,当表具有架构时,它将无法工作:
执行:
my_table
-- highligt it
-- and run
my_schema.my_table
[my_schema].[my_table]
“.”附近的语法不正确
我当然可以写:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(@obj_name)'
,N'@obj_name SYSNAME'
,'
并称之为:
[my_schema].[my_table]'
但是附加的”
也很难看,也很不方便。
问题:
'
,“
- 我不搜索SSM的插件
- 我不想将对象名称包装为“我的模式.我的表”
- 我知道有
(这只是一个例子,我搜索方法)sp_helptext
- 第一个问题是特定于工具的(我知道),但第二个问题是关于
SQLServer
或的情况下将标识符传递给SP,请执行以下操作:
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
如果您确实希望使用相同的标识符处理两个不同的模式,那么仍然可以使用答案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
创建过程sp_MultiArgsWithSchema
@参数1 NVARCHAR(最大值)
作为
选择@Param1=REPLACE(REPLACE(@Param1,“[”,”,“],”)
--这里我使用的是XML拆分,但是可以随意使用您已有的任何字符串拆分函数。
将@xml声明为xml,
@ArgSeparator作为VARCHAR(2),
@SchemaSeparor作为VARCHAR(1)
选择@ArgSeparator='##',
@SchemaSeparor='#',
@xml=CAST(“”+(将(@Param1,@ArgSeparator,)+“”)替换为xml)
如果对象ID('tempdb..#QualifiedIdentifiers')不为空
删除表格#限定标识符;
--拆分时,我们将在模式和对象名称之间放回点而不是“#”
选择QualifiedIdentifier=REPLACE(N.value(‘.,‘VARCHAR(200)’,@SchemaSeparor,’)
进入资格鉴定人
从@xml.nodes('X')作为T(N)
从限定标识符中选择*
--从这里开始,如果需要实现所需的功能,请使用#限定标识符和动态SQL
声明@QualifiedIdentifier NVARCHAR(500)
存在时(从#限定标识符中选择前1名)
开始
选择TOP 1@QualifiedIdentifier=QualifiedIdentifier
来自资格鉴定人
选择*
从sys.columns
其中[object\u id]=object\u id(@QualifiedIdentifier)
删除顶部(1)
来自资格鉴定人
其中QualifiedIdentifier=@QualifiedIdentifier
结束
用法(请注意,指定架构不是强制性的):
因此,由于必须将拆分字符加倍是不方便的,因此最好能像上面所述那样猜测模式。在传递多部分标识符时不必用引号括起来
解决方案:
查询快捷方式将在数据库中创建一个具有特定名称的同义词,并截取该特定同义词的创建
在查询快捷方式中设置以下快捷方式。(确保包含最后一个空格)
正如@Vladimir所建议的,这里我们使用“sp_executesql”能够同时创建触发器和同义词
这是触发器的代码,没有内联
CREATE TRIGGER DDLTrigger_QueryShortcutX ON DATABASE FOR CREATE_SYNONYM
AS
BEGIN
DECLARE @EventData XML = EVENTDATA(),
@SynonymName NVARCHAR(255),
@DbName NVARCHAR(255),
@SchemaName NVARCHAR(255),
@ObjectName NVARCHAR(255),
@Alias NVARCHAR(255)
SELECT @SynonymName = @EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
--Safety in case someone else really create a synonym meanwhile.
IF(@SynonymName = 'QueryShortcutX')
BEGIN
--2. Clean up what we created
DROP SYNONYM QueryShortcutX
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
--3. Parsing identifier code here
SELECT @DbName = @EventData.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'NVARCHAR(255)'),
@SchemaName = @EventData.value('(/EVENT_INSTANCE/TargetSchemaName)[1]', 'NVARCHAR(255)'),
@ObjectName = @EventData.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'NVARCHAR(255)'),
@Alias = (CASE WHEN LEN(@SchemaName) > 0 THEN @SchemaName + '.' ELSE '' END) + @ObjectName
--4. Here, write any print/select statement you want.
--For maintenance, it would be easier to just call a stored procedure from here with parameter and put the desired print/select there.
--Thus avoiding to redo inlining the whole trigger each time.
--EXEC yourStoredProcHere @Param = @Alias
SELECT DbName = @DbName,
SchemaName = @SchemaName,
ObjectName = @ObjectName,
Alias = @Alias,
ObjectId = OBJECT_ID(@Alias)
END
END
这是没有内联的快捷方式的代码
DECLARE @CreateTriggerSQL NVARCHAR(MAX) = 'Trigger creation code here...'
IF EXISTS(SELECT TOP 1 1 FROM sys.triggers WHERE name = 'DDLTrigger_QueryShortcutX')
BEGIN
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
END
EXEC sp_executeSQL @CreateTriggerSQL
IF EXISTS(SELECT TOP 1 1 FROM sys.synonyms WHERE name = 'QueryShortcutX')
BEGIN
DROP SYNONYM QueryShortcutX
END
CREATE SYNONYM QueryShortcutX FOR
触发器本身和同义词都会删除,以避免模式污染
触发器解析信息以检索标识符
根据您的需要使用标识符。(如果需要,请使用动态SQL)
每个测试项目的结果
1.RealColumnName
2.WhatEverText
3.dbo.tests
4.[No selection]
5.dbo.tests.very.much
DbName SchemaName ObjectName Alias ObjectId
1.TEST RealColumnName RealColumnName NULL --FN OBJECT_ID doesn't return value with only column name
2.TEST WhatEverText WhatEverText NULL
3.TEST dbo tests dbo.tests 245575913
4.Incorrect syntax near 'FOR'.
5.TEST very much very.much NULL
我所做的解析无法正确处理包含两个以上多部分的标识符。如果你想改进它。下面的XML显示了要使用的标记
<TargetServerName>dbo</TargetServerName>
<TargetDatabaseName>tests</TargetDatabaseName>
<TargetSchemaName>very</TargetSchemaName>
<TargetObjectName>much</TargetObjectName>
dbo
测验
非常
很
注意:
- 如果愿意,可以让触发器永久保留在数据库中
- 还有,如果你想通过mult
CREATE TRIGGER DDLTrigger_QueryShortcutX ON DATABASE FOR CREATE_SYNONYM
AS
BEGIN
DECLARE @EventData XML = EVENTDATA(),
@SynonymName NVARCHAR(255),
@DbName NVARCHAR(255),
@SchemaName NVARCHAR(255),
@ObjectName NVARCHAR(255),
@Alias NVARCHAR(255)
SELECT @SynonymName = @EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
--Safety in case someone else really create a synonym meanwhile.
IF(@SynonymName = 'QueryShortcutX')
BEGIN
--2. Clean up what we created
DROP SYNONYM QueryShortcutX
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
--3. Parsing identifier code here
SELECT @DbName = @EventData.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'NVARCHAR(255)'),
@SchemaName = @EventData.value('(/EVENT_INSTANCE/TargetSchemaName)[1]', 'NVARCHAR(255)'),
@ObjectName = @EventData.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'NVARCHAR(255)'),
@Alias = (CASE WHEN LEN(@SchemaName) > 0 THEN @SchemaName + '.' ELSE '' END) + @ObjectName
--4. Here, write any print/select statement you want.
--For maintenance, it would be easier to just call a stored procedure from here with parameter and put the desired print/select there.
--Thus avoiding to redo inlining the whole trigger each time.
--EXEC yourStoredProcHere @Param = @Alias
SELECT DbName = @DbName,
SchemaName = @SchemaName,
ObjectName = @ObjectName,
Alias = @Alias,
ObjectId = OBJECT_ID(@Alias)
END
END
DECLARE @CreateTriggerSQL NVARCHAR(MAX) = 'Trigger creation code here...'
IF EXISTS(SELECT TOP 1 1 FROM sys.triggers WHERE name = 'DDLTrigger_QueryShortcutX')
BEGIN
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
END
EXEC sp_executeSQL @CreateTriggerSQL
IF EXISTS(SELECT TOP 1 1 FROM sys.synonyms WHERE name = 'QueryShortcutX')
BEGIN
DROP SYNONYM QueryShortcutX
END
CREATE SYNONYM QueryShortcutX FOR
1.RealColumnName
2.WhatEverText
3.dbo.tests
4.[No selection]
5.dbo.tests.very.much
DbName SchemaName ObjectName Alias ObjectId
1.TEST RealColumnName RealColumnName NULL --FN OBJECT_ID doesn't return value with only column name
2.TEST WhatEverText WhatEverText NULL
3.TEST dbo tests dbo.tests 245575913
4.Incorrect syntax near 'FOR'.
5.TEST very much very.much NULL
<TargetServerName>dbo</TargetServerName>
<TargetDatabaseName>tests</TargetDatabaseName>
<TargetSchemaName>very</TargetSchemaName>
<TargetObjectName>much</TargetObjectName>