繁体   English   中英

如何将输出值转换为输出参数?

[英]How can I get output values into output parameters?

我在VS 2008中使用C#从具有两个输入参数和两个输出参数的PostgreSQL存储过程中检索数据。 创建该过程时,PostgreSQL告诉我必须指定它返回一条记录。

在VS2008中,我首次尝试使用该过程涉及创建类型为CommandType.StoredProcedureOdbcCommand对象,并为其提供四个参数,两个参数为Input方向,两个参数为Output方向。 执行该命令没有错误,首先使用ExecuteNonQuery() ,然后使用ExecuteReader() ,但是输出参数的值为null。 我调用了读者的GetValues()函数,发现结果是一个包含字符串"{3,4}"的单个对象。

然后,根据StackOverflow的建议,我将命令文本更改为:{call hidden_​​idle_cover(?,?,?,?)}

这也起作用,并且GetValues()给我一个数组,其中包含两个类型为int的对象,一个对象为3,另一个对象为4。这要好很多,因为我不必解析字符串。 但是输出参数仍然具有空值,并且实际上,如果我仅传递两个输入参数,该命令也可以正常工作。

因此,尽管我有一个可行的解决方案,但我仍然感到好奇:如何将这些值输入到输出参数中?

这是PostgreSQL存储过程:

CREATE OR REPLACE FUNCTION plant_genie.closest_idle_cover(IN int, IN int, OUT int, OUT int)
  RETURNS record AS
$BODY$
DECLARE
    current_x ALIAS FOR $1;
    current_y ALIAS FOR $2;
    target_x ALIAS FOR $3;
    target_y ALIAS FOR $4;
    coverLocations ic_storage_locations%rowtype;
BEGIN
    target_x := 3;
    target_y := 4;  

    SELECT INTO coverLocations * 
    FROM ic_storage_locations 
    WHERE inner_cover IS NOT NULL 
    ORDER BY sqrt(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.');
        target_x := coverLocations.x_coordinate;
        target_y := coverLocations.y_coordinate;
    ELSE
        INSERT INTO op_messages (message) VALUES ('Could not find a cover location record.');
    END IF;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100;

您正在使用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#代码中进行处理。

一些观察:

  • 由于您正在寻找最接近的ic_storage_location,因此可以省去SQRT()函数调用,这在计算上是昂贵的。 仅仅使用平方和具有与从当前位置的距离对记录进行排序的相同属性。
  • 该函数定义为STRICT因为它需要两个参数的值才能正常工作。
  • 除非您真的知道自己在做什么,否则不要自己分配COST值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM