从 R 执行时 SQL Server 查询失败
Posted
技术标签:
【中文标题】从 R 执行时 SQL Server 查询失败【英文标题】:SQL Server Query failing when executed from R 【发布时间】:2019-03-07 13:39:55 【问题描述】:我有以下简单的 SQL 服务器代码:
set nocount on;
if OBJECT_ID('tempdb..#A') IS NOT NULL DROP TABLE #A;
set nocount on;
create table #A
( obj_id int,
obj_name varchar(50),
obj_dt datetime);
insert into #A (
obj_id,
obj_name,
obj_dt)
values
( 1
,'name'
,'2019-01-01 00:00:00'
),
( 2
,NULL
,NULL
),
( 2
,'alias'
,'2019-02-01 00:00:00'
);
set nocount on;
if OBJECT_ID('tempdb..#B') IS NOT NULL DROP TABLE #B;
set nocount on;
select
#A.obj_id
,subq.obj_name
,subq.obj_dt
into #B
from #A
join (select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
from #A
group by obj_id) as subq
on #A.obj_id = subq.obj_id;
set nocount on;
select * from #B;
正如预期的那样,在 Microsoft SQL Server Management Studio 中执行时返回以下数据:
obj_id obj_name obj_dt
1 name 2019-01-01 00:00:00.000
2 alias 2019-02-01 00:00:00.000
2 alias 2019-02-01 00:00:00.000
到目前为止一切顺利。现在我希望从 R 运行此代码并将相同的输出返回到 R。我将上面的查询存储在字符串 query
和我的 RODBC 连接中存储在变量 connection
中,并尝试检索数据与
sqlQuery(connection,query)
结果是character(0)
。 然而,如果我通过注释掉#B
定义中的subq.obj_name
和subq.obj_dt
字段来修改上面的查询,那么代码会成功返回预期的数据集
obj_id
1 1
2 2
3 2
来自R。
那么这里发生了什么?两个 sql 查询都有效并且在 Microsoft SQL Server 环境中成功运行,但只有一个在通过 R 管道时有效。我不知道是什么原因导致 RODBC 代码无法处理第二个查询。
【问题讨论】:
不是答案,但您绝对应该尝试通过您的 R 脚本从 SQL Server 获取错误输出。 通常,如果有错误消息,它将存储在输出变量中。在这种情况下,它只会产生character(0)
,所以我认为没有实际错误,而是什么都没有返回?虽然不确定...
【参考方案1】:
这是一个关于本地临时表的已知问题(#mytable
不是 ##mytable
),不仅在 R 中,而且在 SSMS 等 Microsoft 工具中对临时表的所有外部调用(参见下面第一个链接的评论)。
看看那些链接:
https://github.com/r-dbi/odbc/issues/127 尤其是https://github.com/r-dbi/odbc/issues/127#issuecomment-396343426 RODBC Temporary Table Issue when connecting to MS SQL Server在阅读了这些链接之后,奇怪的是它在没有 subq.obj_name
和 subq.obj_dt
的情况下仍然有效:也许它可以工作,因为查询是在一个唯一的调用中。
【讨论】:
您提供的链接表明问题是返回的行数导致 RODBC 表现得好像整个查询已完成,解决方法是将set nocount
放在每个语句的开头。你会注意到我上面的代码就是这样做的,所以我相信这是一个与这些链接中引用的问题(我之前已经遇到过并按照指示处理过的问题)不同的问题。我猜 RODBC 包不再积极开发了?
自 18 年 11 月以来,我已经从 RODBC 切换到 DBI 和 RStudio/odbc,我的许多问题都已经解决,但在这种情况下,它与一个或多个外部调用中的多查询有关,并且不仅在 R 中,而且在 SSMS 中。也许它会解决你的问题,但我怀疑。告诉我们是不是这样。从 RODBC 切换到 DBI 和 RStudio/odbc 后,我没有再次尝试使用 #table。
是的,我也一直在考虑切换,但考虑到 RODBC 方法在我所有资产中的集成程度,这是一个令人生畏的想法。如果时间允许,我肯定会探索其他选择。不过,在这种情况下,我已经确定了根本原因并实施了一种解决方法(请参见下面的答案),并且我认为该问题与您的答案中的链接有关,因为它似乎与 R 在看到任何类型时终止查询有关输出。【参考方案2】:
好的,所以我想我已经弄清楚这里出了什么问题。子查询
select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
from #A
group by obj_id
产生隐藏警告。如果您只是按原样运行代码,则看不到警告,但如果将输出存储在临时表中,则会产生警告消息:
select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
into #C
from #A
group by obj_id
警告:空值被聚合或其他 SET 消除 操作。
当它作为问题中原始 SQL 代码中的子查询的一部分运行时,该警告会被隐藏。我相信这条消息在某种程度上是 R 正在“看到”的输出的一部分,一旦 R 看到该输出,它就会终止查询。但由于没有返回任何结果,但 R 中的输出为空(即character(0)
)。
为了解决这个问题,我将计算最大值的变量合并为一些最小值(我不确定 sql server 排序规则中的最小字符是什么,但 '0'
可以满足我的目的)。这个想法是在聚合之前删除 NULL
值,因此不会生成警告。最终的工作 SQL 代码如下:
set nocount on;
if OBJECT_ID('tempdb..#A') IS NOT NULL DROP TABLE #A;
set nocount on;
create table #A
( obj_id int,
obj_name varchar(50),
obj_dt datetime);
insert into #A (
obj_id,
obj_name,
obj_dt)
values
( 1
,'name'
,'2019-01-01 00:00:00'
),
( 2
,NULL
,NULL
),
( 2
,'alias'
,'2019-02-01 00:00:00'
);
set nocount on;
if OBJECT_ID('tempdb..#B') IS NOT NULL DROP TABLE #B;
set nocount on;
select
#A.obj_id
,subq.obj_name
,subq.obj_dt
into #B
from #A
join
(select
obj_id,
max(isnull(obj_name,'0')) as obj_name,
max(isnull(obj_dt,cast(-1 as datetime))) as obj_dt
from #A
group by obj_id) as subq
on #A.obj_id = subq.obj_id;
set nocount on;
select * from #B;
我认为这种行为应该在 RODBC 包中得到解决,因为它很可能会绊倒其他人,而且要找出根本原因并进行故障排除会有些棘手。
【讨论】:
【参考方案3】:作为 Rookatu 答案的扩展,您可以通过在查询开头添加以下内容来关闭警告:
SET ANSI_WARNINGS OFF
当然,如果您尝试捕获其他警告,这可能并不理想,但在紧要关头可能更容易实施。
【讨论】:
以上是关于从 R 执行时 SQL Server 查询失败的主要内容,如果未能解决你的问题,请参考以下文章
T-SQL Server 代理作业失败“用户无权执行此操作”
当我从 SQL Server 代理运行 Python 脚本时,为啥它会失败?
从其他SQL Server连接时,用户'NT AUTHORITY ANONYMOUS LOGON'登录失败