3

私は SQLAlchemy (および私の特定のケースでは GeoAlchemy) で Python を使用しており、行オブジェクトの単一の列になるクエリがあります。これらの行オブジェクトから特定の値を抽出したいのですが、SQLAlchemy は行オブジェクトを単一のエンティティとして解釈します (正しい場合は、それらを文字列として返します)。Python で解析せずに、これらの個々の値をよりきれいに戻すにはどうすればよいですか?

私の実際の使用例: PostgreSQL の PostGIS 拡張機能は、 という関数を提供しますST_IsValidDetail。この関数は、 boolean 、 string 、および無効が発生したジオメトリでvalid_detail構成される行を返すように設計されています。この質問はそれよりも一般的だと思うので、PostGIS タグを省略しました。私のクエリは次のようなものです(もちろん、より複雑なジオメトリを使用します)。validreasonlocationSELECT ST_IsValidDetail('POINT(1 1)'::GEOMETRY);

4

2 に答える 2

2

ページの例から取った方法を見つけましたST_IsValidDetail。どうやら、次の構文が有効です。

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

関数呼び出しを囲んでいる「呼び出し」reasonと「呼び出し」に注意してください。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 に答える
2

You can use:

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

... but unfortunately PostgreSQL actually executes the ST_IsValidDetail function once for each row. As a workaround you can mangle the query a little more, materializing via a common table expression then extracting the tuples in a second pass:

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

The parens around (v) are required to tell the parser you're referring to a value, not to a table name.

Demo:

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 に答える