使用SQLAlchemy从PostgreSQL行对象中获取单个值

时间:2013-05-16 02:23:22

标签: python postgresql sqlalchemy

我在SQLAlchemy中使用Python(在我的特定情况下使用GeoAlchemy),并且我有一个查询导致一列行对象。我希望从这些行对象中提取特定值,但SQLAlchemy将行对象解释为单个实体(如果我是正确的,则将它们作为字符串返回)。如果不在Python中解析它们,我怎样才能更清晰地获得这些单个值呢?

我的真实用例: PostgreSQL的PostGIS扩展提供了一个名为ST_IsValidDetail的函数。此函数旨在返回valid_detail行,其中包含布尔valid,字符串reason和无效的几何location。我已经离开了PostGIS标签,因为我觉得这个问题比这更普遍。我的查询类似于SELECT ST_IsValidDetail('POINT(1 1)'::GEOMETRY);(当然,几何形状更复杂)。

2 个答案:

答案 0 :(得分:2)

您可以使用:

SELECT (ST_IsValidDetail(the_value)).* FROM the_table;

...但遗憾的是PostgreSQL实际上为每一行执行了一次ST_IsValidDetail函数。作为一种解决方法,您可以更多地查询查询,通过公共表表达式实现,然后在第二遍中提取元组:

WITH interim_result(v) AS (
    SELECT ST_IsValidDetail(the_value) FROM the_table
)
SELECT (v).* FROM interim_result;

(v)周围的parens需要告诉解析器你引用的是一个值,而不是表名。

演示:

CREATE OR REPLACE FUNCTION multirows(x IN integer, a OUT integer, b OUT integer, c OUT integer) AS
$$
BEGIN
    RAISE NOTICE 'multirows(%) invoked', x;
    a := x;
    b := x+1;
    c := x+2;
    RETURN;
END;
$$ LANGUAGE plpgsql;

craig=> SELECT multirows(x) FROM generate_series(1,2) x;
NOTICE:  multirows(1) invoked
NOTICE:  multirows(2) invoked
 multirows 
-----------
 (1,2,3)
 (2,3,4)
(2 rows)

craig=> SELECT (multirows(x)).* FROM generate_series(1,2) x;
NOTICE:  multirows(1) invoked
NOTICE:  multirows(1) invoked
NOTICE:  multirows(1) invoked
NOTICE:  multirows(2) invoked
NOTICE:  multirows(2) invoked
NOTICE:  multirows(2) invoked
 a | b | c 
---+---+---
 1 | 2 | 3
 2 | 3 | 4
(2 rows)




craig=> WITH interim(v) AS (SELECT multirows(x) FROM generate_series(1,2) x)
SELECT (v).* FROM interim;
NOTICE:  multirows(1) invoked
NOTICE:  multirows(2) invoked
 a | b | c 
---+---+---
 1 | 2 | 3
 2 | 3 | 4
(2 rows)

答案 1 :(得分:2)

我找到了一种从ST_IsValidDetail页面上的示例中获取的方法。显然,以下语法有效:

SELECT gid, reason(ST_IsValidDetail(the_geom)), ST_AsText(location(ST_IsValidDetail(the_geom)))

请注意函数调用附带的reasonlocation“调用”; ST_IsValidDetail返回的行中列的名称几乎与函数一样。事实证明,你可以欺骗SQLAlchemy做同样的事情。 (假设session是先前设置的Session对象,db_geom是GeoAlchemy几何对象。)

from sqlalchemy import func as sqlfunc
result = session.query(sqlfunc.reason(sqlfunc.ST_IsValidDetail(db_geom)), sqlfunc.ST_AsText(sqlfunc.location(sqlfunc.ST_IsValidDetail(db_geom)))).one()

result[0]将包含原因,result[1]将包含该位置的WKT。 (我们可以使用label为列提供实际名称。)

在不使用PostGIS功能的情况下将其修剪:

from sqlalchemy import func as sqlfunc
result = session.query(sqlfunc.columnname(sqlfunc.myrowfunc('some input string')).label('mylabel')).one()

这使得SQLAlchemy认为columnname是一个函数,并以表格

的形式将SQL发送到数据库
SELECT columnname(myrowfunc('some input string')) AS mylabel;

我还没有尝试过,但是如果有办法让SQLAlchemy认为我们的行是我们选择FROM的表,那么这也可能有用。 (请参阅ST_IsValidDetail页面的最底部。)