我在VS 2008中使用C#从具有两个输入参数和两个输出参数的PostgreSQL存储过程中检索数据。当我创建程序时,PostgreSQL告诉我,我必须指定它返回一条记录。
在VS2008中,我第一次尝试使用该过程涉及创建类型为OdbcCommand
的{{1}}对象,并为其提供四个参数,两个参数为Input,两个为方向Output。执行该命令时没有错误,首先使用CommandType.StoredProcedure
然后使用ExecuteNonQuery()
,但输出参数的值为null。我调用了读者的ExecuteReader()
函数,发现结果是包含字符串GetValues()
的单个对象。
然后,根据StackOverflow的建议,我将命令文本更改为: {call nearest_idle_cover(?,?,?,?)}
这也有效,"{3,4}"
给了我一个两个int类型对象的数组,一个用3个,另一个用4个。这个好一点,因为我不需要解析一个字符串。但是输出参数仍然具有空值,实际上,如果我只传入两个输入参数,该命令也可以正常工作。
所以,虽然我有一个有效的解决方案,但我仍然很好奇:如何将值输入到我的输出参数中?
这是PostgreSQL存储过程:
GetValues()
答案 0 :(得分:1)
您正在使用OUT
参数,但后来还使用RETURNS record
子句,而在函数体中没有明确的RETURN
语句。这种组合不起作用。比使用OUT
参数更优雅的解决方案是定义输出表格式 - 更明显的是发生了什么:
CREATE OR REPLACE FUNCTION plant_genie.closest_idle_cover(current_x int, current_y int)
RETURNS TABLE (target_x int, target_y int) AS $BODY$
DECLARE
coverLocations ic_storage_locations%rowtype;
BEGIN
SELECT INTO coverLocations *
FROM ic_storage_locations
WHERE inner_cover IS NOT NULL
ORDER BY pow(current_x - ic_storage_locations.x_coordinate, 2) +
pow(current_y - ic_storage_locations.y_coordinate, 2)
LIMIT 1;
IF FOUND THEN
INSERT INTO op_messages (message) VALUES ('Found a cover location record.');
RETURN QUERY SELECT coverLocations.x_coordinate, coverLocations.y_coordinate;
ELSE
INSERT INTO op_messages (message) VALUES ('Could not find a cover location record.');
END IF;
END; $BODY$ LANGUAGE 'plpgsql' STRICT;
因此,如果您调用此函数,如果至少1个ic_storage_location不为null,则返回一条记录:
SELECT * FROM plant_genie.closest_idle_cover(1, 2);
您可以在C#代码中处理它,就像从数据库中提取的任何其他数据一样。
一些观察结果:
SQRT()
函数调用,这在计算上非常昂贵。仅使用平方和就具有与当前位置距离排序记录的相同属性。STRICT
,因为它要求两个参数的值都能正常工作。COST
个值,除非 真的 知道您在做什么。