SQL 从 R 执行时服务器查询失败
SQL Server Query failing when executed from R
我有以下简单的 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 中执行时 returns 以下数据:
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
字段来修改上面的查询,那么代码成功 returns 预期数据集
obj_id
1 1
2 2
3 2
来自 R.
那么这是怎么回事?在 Microsoft SQL 服务器环境中,sql 两个查询均有效且 运行 成功,但只有一个在通过 R 进行管道传输时有效。我无法弄清楚是什么导致了 RODBC 的失败处理第二个查询的代码。
这是一个关于本地临时 table(#mytable
而不是 ##mytable
)的已知问题,不仅在 R 中,而且所有临时 table 的外部调用甚至在 Microsoft 工具中像 SSMS(见下面第一个 link 的评论)。
看看那些 links:
- https://github.com/r-dbi/odbc/issues/127 and in particular https://github.com/r-dbi/odbc/issues/127#issuecomment-396343426
- RODBC Temporary Table Issue when connecting to MS SQL Server
读完那些 links 之后,很奇怪它在没有 subq.obj_name
和 subq.obj_dt
的情况下也能工作:也许它能工作是因为查询是在一个独特的调用中。
好的,我想我已经弄清楚这里出了什么问题。子查询
select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
from #A
group by obj_id
产生一个隐藏警告。如果您只是 运行 原样的代码,您不会看到警告,但如果您将输出存储在临时 table 中,则会产生警告消息:
select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
into #C
from #A
group by obj_id
Warning: Null value is eliminated by an aggregate or other SET
operation.
当这是 运行 作为问题中原始 SQL 代码中子查询的一部分时,警告被隐藏。我相信此消息在某种程度上是 R 是 "seeing" 的输出的一部分,一旦 R 看到该输出,它就会终止查询。但是由于没有返回结果,R 中的输出为空(即 character(0)
)。
为了解决这个问题,我将计算最大值的变量合并为一些最小值(我不确定 sql 服务器排序规则中的最小字符是什么,但 '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 包中解决此行为,因为它很可能会误导其他人,并且追踪根本原因和排除故障可能有点棘手。
作为 Rookatu 答案的扩展,您可以通过将以下内容添加到查询的开头来关闭警告:
SET ANSI_WARNINGS OFF
当然,如果您正在尝试捕获其他警告,这可能不是理想的选择,但在紧要关头可能更容易实施解决方案。
我有以下简单的 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 中执行时 returns 以下数据:
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
字段来修改上面的查询,那么代码成功 returns 预期数据集
obj_id
1 1
2 2
3 2
来自 R.
那么这是怎么回事?在 Microsoft SQL 服务器环境中,sql 两个查询均有效且 运行 成功,但只有一个在通过 R 进行管道传输时有效。我无法弄清楚是什么导致了 RODBC 的失败处理第二个查询的代码。
这是一个关于本地临时 table(#mytable
而不是 ##mytable
)的已知问题,不仅在 R 中,而且所有临时 table 的外部调用甚至在 Microsoft 工具中像 SSMS(见下面第一个 link 的评论)。
看看那些 links:
- https://github.com/r-dbi/odbc/issues/127 and in particular https://github.com/r-dbi/odbc/issues/127#issuecomment-396343426
- RODBC Temporary Table Issue when connecting to MS SQL Server
读完那些 links 之后,很奇怪它在没有 subq.obj_name
和 subq.obj_dt
的情况下也能工作:也许它能工作是因为查询是在一个独特的调用中。
好的,我想我已经弄清楚这里出了什么问题。子查询
select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
from #A
group by obj_id
产生一个隐藏警告。如果您只是 运行 原样的代码,您不会看到警告,但如果您将输出存储在临时 table 中,则会产生警告消息:
select
obj_id,
max(obj_name) as obj_name,
max(obj_dt) as obj_dt
into #C
from #A
group by obj_id
Warning: Null value is eliminated by an aggregate or other SET operation.
当这是 运行 作为问题中原始 SQL 代码中子查询的一部分时,警告被隐藏。我相信此消息在某种程度上是 R 是 "seeing" 的输出的一部分,一旦 R 看到该输出,它就会终止查询。但是由于没有返回结果,R 中的输出为空(即 character(0)
)。
为了解决这个问题,我将计算最大值的变量合并为一些最小值(我不确定 sql 服务器排序规则中的最小字符是什么,但 '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 包中解决此行为,因为它很可能会误导其他人,并且追踪根本原因和排除故障可能有点棘手。
作为 Rookatu 答案的扩展,您可以通过将以下内容添加到查询的开头来关闭警告:
SET ANSI_WARNINGS OFF
当然,如果您正在尝试捕获其他警告,这可能不是理想的选择,但在紧要关头可能更容易实施解决方案。