【问题标题】:Scalar function (NON table-valued function) in PostgreSQLPostgreSQL 中的标量函数(非表值函数)
【发布时间】:2016-05-09 17:39:26
【问题描述】:

我使用 PostgreSQL 作为 SQL Server 的链接服务器。现在,我需要调用 PostgreSQL 函数,它只返回一个整数(标量),但 SQL Server 不允许远程表值函数,并说此查询是表值函数。

CREATE OR REPLACE FUNCTION public.getpointinfo(
    IN lng double precision,
    IN lat double precision)
RETURNS integer
AS
$$
DECLARE result integer;
begin
result:= case when cwt.k like 'maxspeed' then cast(cwt.v as integer)
            else getmaxspeed(s.highway)
            end maxspeed
from snapPointToLine(ST_SetSRID(ST_MakePoint($1, $2), 4326)) s
   join current_way_tags cwt
   on s.id = cwt.way_id
where cwt.k in ('maxspeed', 'highway')
order by cwt.k desc
limit 1;
return result;
end
$$
  LANGUAGE plpgsql VOLATILE;

如何修改此 PostgreSQL 查询以返回标量值,或者能够将其用作 SQL Server 中的四部分名称函数,如

select objectid, s.data_source
from testData
outer apply
(
select maxspeed from MB24DB.MobTrack24DB.[public].getpointinfo(X, Y)
) s

openquery 不是一个选项。

【问题讨论】:

  • 贴出的函数有明显的语法错误。
  • 不应在from 子句中使用标量函数。因为你这样做,我猜 SQL Server 假设它是一个表值函数。而且因为它是一个标量函数,我认为首先不需要使用cross apply。只需将MB24DB.MobTrack24DB.[public].getpointinfo(X, Y) 放入select 列表(假设您的表testdata 有两列x 和y)
  • @a_horse_with_no_name 抛出错误:不允许远程函数引用“MB24DB.MobTrack24DB.public.getpointinfo”,并且列名“MB24DB”找不到或不明确。 testData 包含 X 和 Y 列。
  • 然后试试outer apply (select MB24DB.MobTrack24DB.[public].getpointinfo(X, Y)
  • @a_horse_with_no_name 同样的错误。

标签: sql-server postgresql remote-server linked-server


【解决方案1】:

我以前做过类似的事情。您可以使用三个基本技巧。

第一招:xp_cmdshell

您可以从 UDF 调用 xp_cmdshell。所以诀窍是让xp_cmdshell 调用sqlcmd(或osql)将结果放入表中,然后您可以从表中选择它们。您可以使用自己的 SPID 键入结果。

use tempdb
go
create table Results(
scope varchar(20) primary key,
result integer
)
go
    create function dbo.test(@x integer, @y integer)
returns integer
as
begin
    declare @sql nvarchar(max)
    declare @scope varchar(20) set @scope = 'dbo.test@' + cast(@@spid as varchar(36))
    set @sql = 'delete tempdb.dbo.Results where spid = '+@scope + '; '
    set @sql = 'insert tempdb.dbo.Results select '+@scope+', '+cast(@x as nvarchar(max))+' * '+cast(@y as nvarchar(max))+' as r; '
    declare @cmd varchar(max)
    set @cmd = 'sqlcmd -E -Q "' + @sql +'"'
    set @cmd = 'CMD /S /C "' + @cmd + ' 2>&1"'
    exec xp_cmdshell @sql, NO_OUTPUT
    declare @r integer 
    select @r = result from tempdb.dbo.results where scope = @scope
    return @r
end

或者,您也可以使用 UDF 中的 xp_cmdshell 对表变量执行 insert/exec ,然后解析输出数据。

declare @CMD nvarchar(max)
set @CMD = 'echo.Hello World!'
set @CMD = 'CMD /S/C "' + @cmd + ' 2>&1"'
declare @results table (ix int identity primary key, txt nvarchar(max)
declare @exitcode int
insert @results(txt)
exec @exitcode = xp_cmdshell @commandtext

-- You now have the results of your command.

第二个技巧:sp_OACreate

您可以使用来自 UDF 的 sp_OACreate。这意味着您可以创建一个 ADO 连接回到您自己的数据库并执行您希望的任何操作,包括将结果放在一个表中以供参考。 sp_OACreate 但是使用起来很痛苦,所以我将把你留给文档了解详细信息。

第三招:SQLCLR

您可以使用 CLR 函数解决所有这些限制,该函数可以直接连接到您的 postgres 数据库并做任何您想做的事情。

【讨论】:

  • 本,正如我在cmets中所说,它抛出一个错误:不允许远程函数引用'MB24DB.MobTrack24DB.public.getpointinfo',并且列名'MB24DB'找不到或者是模糊的。我已经尝试了所有建议。
猜你喜欢
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多