首页 > 解决方案 > 在 OpenQuery 中执行存储过程我缺少什么

问题描述

我正在尝试使用 OpenQuery 将数据插入临时表。OpenQuery 假设执行一个输出数百行的存储过程。

为了不定义Create Table #temp1,我正在尝试执行 OpenQuery 并在查询#temp1中使用 into 语句将结果插入表中。Select我想知道是什么导致它不执行?

  1. 似乎它可能会引用未正确放置的问题。我如何获得与此相关的帮助?

  2. 我的服务器包含多个数据库(实例)。我需要如何在这里定义它?

我在这里提供我的查询示例

DECLARE @startDate DATETIME = CONVERT(DATE, GETDATE());
DECLARE @endDate DATETIME = CONVERT(DATE, GETDATE()+1);

DECLARE @stDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), @startDate, 23)+ CHAR(39) + ',';
DECLARE @enDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), @endDate, 23) + CHAR(39);
DECLARE @execCommand NVARCHAR(MAX) = CHAR(39) + 'EXEC dbo.getRecordsByOrderDate ' ;
DECLARE @concatCommand NVARCHAR(MAX) = @execCommand + @stDate + @enDate + CHAR(39);

DECLARE @opQuery Nvarchar(MAX) = 'Select * Into #Temp1 from Openquery(LOCALSERVER, '+ @concateCommand +') oq'

EXEC (@opQuery);

错误信息:

消息 102,级别 15,状态 1,第 20 行“2020”附近的语法不正确。

如果我尝试以以下格式执行

Select * Into #Temp1 from Openquery(LOCALSERVER, 'EXEC dbo.getRecordsByOrderDate ''2020-12-11'',''''2020-12-12''''') oq

消息 11529,级别 16,状态 1,过程 sys.sp_describe_first_result_set,第 1 行 [批处理开始第 31 行] 无法确定元数据,因为每个代码路径都会导致错误;请参阅之前的一些错误。

消息 2812,级别 16,状态 62,过程 sys.sp_describe_first_result_set,第 1 行 [批处理开始第 31 行] 找不到存储过程 'dbo.getRecordsByOrderDate'。

标签: sql-serverstored-proceduresopenquery

解决方案


问题是您缺乏对注入参数的引号进行转义。调试动态代码最简单的方法是PRINT/ SELECTit。如果你这样做,你会很快看到问题:

DECLARE @startDate DATETIME = CONVERT(DATE, GETDATE());
DECLARE @endDate DATETIME = CONVERT(DATE, GETDATE()+1);

DECLARE @stDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), @startDate, 23)+ CHAR(39) + ',';
DECLARE @enDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), @endDate, 23) + CHAR(39);
DECLARE @execCommand NVARCHAR(MAX) = CHAR(39) + 'EXEC dbo.getRecordsByOrderDate ' ;
DECLARE @concatCommand NVARCHAR(MAX) = @execCommand + @stDate + @enDate + CHAR(39);

DECLARE @opQuery Nvarchar(MAX) = 'Select * Into #Temp1 from Openquery(LOCALSERVER, '+ @concatCommand +') oq'

PRINT @opQuery;

哪个返回...

Select *
Into #Temp1
from Openquery(LOCALSERVER, 'EXEC dbo.getRecordsByOrderDate '2020-12-11','2020-12-12'') oq

瞧,您的第一个参数会转义第二个参数,从而导致错误。(我添加了额外的行,因为 SO 选择的“美化器”认为#是 SQL 中的注释字符,我希望在着色中突出显示转义。)

在文字字符串中使用单引号时,您需要通过“将它们加倍”('')来转义它们。因此,最后的陈述需要我以下:

Select *
Into #Temp1
from Openquery(LOCALSERVER, 'EXEC dbo.getRecordsByOrderDate ''20201211'',''20201212''') oq

(为再次演示添加了额外的行。)

因此,您需要修复 2 个注入值的定义:

DECLARE @stDate NVARCHAR(8) = CHAR(39) + CHAR(39) + CONVERT(NVARCHAR(8), @startDate, 112)+ CHAR(39) + CHAR(39) + ',';
DECLARE @enDate NVARCHAR(8) = CHAR(39) + CHAR(39) + CONVERT(NVARCHAR(8), @endDate, 112) + CHAR(39) + CHAR(39);

注意我也更改了数据类型和样式。在 SQL Server 和数据类型中,样式yyyy-MM-dd并不明确,因为您不需要 20 亿个字符作为日期。


但是请注意,执行此操作后,您仍然无法访问#Temp1. 临时表仅在创建它的范围内持续存在,并且该范围是动态 SQL 的。您需要在动态语句内部使用永久表,或者CREATE在动态语句外部使用临时表才能在其外部使用它。


推荐阅读