从R执行SQL Server查询失败

时间:2019-03-07 13:39:56

标签: r sql-server rodbc

我有以下简单的SQL Server代码:

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)但是,如果我通过注释subq.obj_name定义中的subq.obj_dt#B字段来修改上面的查询,那么代码将成功返回预期的数据集

obj_id
1      1
2      2
3      2

来自R。

那么这是怎么回事?这两个sql查询都是有效的,并且可以在Microsoft SQL Server环境中成功运行,但是通过R进行管道传输时只有一个有效。我无法弄清楚是什么原因导致RODBC代码无法处理第二个查询。

2 个答案:

答案 0 :(得分:1)

这是关于本地临时表(#mytable而非##mytable)的已知问题,不仅在R中,而且在Microsoft工具(如SSMS)中都对临时表的所有外部调用(请参阅第一个链接的注释)下面)。

查看这些链接:

在阅读了这些链接之后,因此很奇怪,它没有subq.obj_namesubq.obj_dt也可以工作:也许是有效的,因为查询是在唯一的调用中进行的。

答案 1 :(得分:0)

好的,所以我想我已经弄明白了这里出了什么问题。子查询

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程序包中解决此问题,因为它很可能会触发其他行为,并且要找出根本原因并进行故障排除可能有些棘手。