0

SQLAlchemy では、カスタム ビルドの group_concat 呼び出し内に組み込みの「concat」呼び出しをネストしようとしています。どちらもパラメーターとして文字列が渡されますが、クエリがレンダリング/実行されると文字列が逆になります。

例:

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql import expression
from sqlalchemy import create_engine, MetaData
from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.sql import select
from sqlalchemy.sql.functions import concat


class group_concat(expression.FunctionElement):
    name = "group_concat"


@compiles(group_concat, 'mysql')
def _group_concat_mysql(element, compiler, **kw):
    separator = compiler.process(element.clauses.clauses[1]) \
                    if len(element.clauses) == 2 else "','"
    return "GROUP_CONCAT(%s SEPARATOR %s)" % (
                compiler.process(element.clauses.clauses[0]),
                separator,
            )

table = Table(
    'test_constructs', MetaData(),
    Column('id', Integer, primary_key=True),
    Column('column1', String(255)),
    Column('column2', String(255)),
    Column('foreign_id', Integer(11)),
)


def select_records():
    column1 = table.c.column1
    column2 = table.c.column2
    test_query = select([
        table.c.foreign_id,
        expression.label('clean_test_column',
                         group_concat(concat(column1,
                                             ',',
                                             column2),
                                      '|')),
    ]).group_by(table.c.foreign_id)
    res = engine.execute(test_query)

これからのログ出力は次のとおりです。

2012-06-01 09:48:29,552 INFO sqlalchemy.engine.base.Engine SELECT test_constructs.foreign_id, GROUP_CONCAT(concat(test_constructs.column1, %s, test_constructs.column2) SEPARATOR %s) AS clean_test_column FROM test_constructs GROUP BY test_constructs.foreign_id
2012-06-01 09:48:29,552 INFO sqlalchemy.engine.base.Engine ('|', ',')

...クエリに代入されるパラメータの順序が逆になっていることに注意してください。'|' は CONCAT に代入され、',' は GROUP_CONCAT で使用されています。

4

1 に答える 1

0

この問題は、セパレーターが最初に「コンパイル」されたが、2 番目に文字列に追加されたためです。したがって、ステートメントでは正しい順序で終了していましたが、params では逆の順序でした。

代わりに私はやっています:

@compiles(group_concat, 'mysql')
def _group_concat_mysql(element, compiler, **kw):
    return "GROUP_CONCAT({0} SEPARATOR {1})".format(
                compiler.process(element.clauses.clauses[0]),
                compiler.process(element.clauses.clauses[1]) \
                    if len(element.clauses) == 2 else ",",
            )

...これは正常に動作しているようです。

于 2012-06-01T20:02:37.527 に答える