3

我正在将 Python 与 SQLAlchemy(在我的特定情况下是 GeoAlchemy)一起使用,并且我有一个查询会产生单列的行对象。我希望从这些行对象中提取特定值,但 SQLAlchemy 将行对象解释为单个实体(并将它们作为字符串返回,如果我是正确的)。如何在不使用 Python 解析它们的情况下更干净地取回这些单独的值?

我现实生活中的用例:PostgreSQL 的 PostGIS 扩展提供了一个名为ST_IsValidDetail. 此函数旨在返回valid_detail一行,其中包含 boolean valid、 stringreasonlocation发生无效的几何。我已经放弃了 PostGIS 标签,因为我觉得这个问题比这更笼统。我的查询类似于SELECT ST_IsValidDetail('POINT(1 1)'::GEOMETRY);(当然,具有更复杂的几何形状)。

4

2 回答 2

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)来告诉解析器您指的是一个值,而不是表名。

演示:

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)
于 2013-05-16T02:26:13.730 回答
2

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

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

注意函数调用周围的reasonand “调用”;location返回的行中的列名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。)

于 2013-05-16T02:33:57.523 回答