So everything I know about SQL says that this would be invalid SQL:

SELECT some_function(s) FROM (select <things> FROM <stuff>) AS s


because "s" is a FROM clause and "some_function()" is in the columns clause.  
"s" is not a SQL column expression.

Postgresql wants it like that huh?       For the moment I'd probably just hack 
it, func.row_to_json(literal_column('s')).





On Oct 2, 2014, at 11:54 PM, Jon Rosebaugh <chai...@gmail.com> wrote:

> I'm having some trouble with the Postgresql function row_to_json. It's 
> possible to use it on an entire table to turn each row from the table into a 
> JSON object, like select row_to_json(t) as j from some_table as t. You can 
> also use a subselect, and that's where the trouble lies.
> 
> I want to generate this SQL, or the equivalent:
> update sample set query_args=(select row_to_json(s) from (select 
> ARRAY[campaign] as campaign, ARRAY[keyword] as keyword from sample as 
> inner_sample where inner_sample.id = sample.id) as s);
> 
> Here's my table definition and attempt:
> 
> import sqlalchemy as sa
> from sqlalchemy.dialects.postgres import array, JSON
> 
> engine = sa.create_engine("postgres://foo")  # let engine be a valid postgres 
> engine
> meta = sa.MetaData()
> sample_table = sa.Table('sample', meta,
>     sa.Column('id', sa.Integer, primary_key=True),
>     sa.Column('campaign', sa.Unicode),
>     sa.Column('keyword', sa.Unicode),
>     sa.Column('query_args', JSON))
> sample_table.create(engine)
> # put in some sample rows
> engine.execute(sample_table.insert(), [{'campaign': 'one', 'keyword': 'foo'}, 
> {'campaign': 'two', 'keyword': 'bar'}])
> 
> inner_sample = sample_table.alias('inner_sample')
> s = sa.select([array([inner_sample.c.campaign]).label('campaign'), 
> array([inner_sample.c.keyword]).label('keyword')]).where(inner_sample.c.id == 
> sample_table.c.id).correlate(sample_table).alias('s')
> print s.compile(engine)
> # SELECT ARRAY[inner_sample.campaign] AS campaign, 
> ARRAY[inner_sample.keyword] AS keyword
> # FROM sample AS inner_sample, sample
> # WHERE inner_sample.id = sample.id
> 
> The FROM clause isn't quite right, but that will take care of itself later 
> thanks to the correlate call. This is the subselect that I want to turn into 
> JSON using row_to_json, and then store into the query_args column.
> 
> j = sa.func.row_to_json(s).select().select_from(s).as_scalar()
> 
> print sample_table.update().values(query_args=j).compile(db_session.bind)
> 
> # UPDATE sample SET query_args=(SELECT row_to_json(SELECT 
> ARRAY[inner_sample.campaign] AS campaign, ARRAY[inner_sample.keyword] AS 
> keyword
> # FROM sample AS inner_sample
> # WHERE inner_sample.id = sample.id) AS row_to_json_1
> # FROM (SELECT ARRAY[inner_sample.campaign] AS campaign, 
> ARRAY[inner_sample.keyword] AS keyword
> # FROM sample AS inner_sample
> # WHERE inner_sample.id = sample.id) AS s)
> 
> Now the FROM clause in the subselect is right, but the subselect gets 
> repeated inside the row_to_json call. The alias 's' does correctly get 
> rendered; how can I tell SQLAlchemy that row_to_json is a function that can 
> accept a selectable? It's basically right except the row_to_json call should 
> just be row_to_json(s).
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to