On Feb 26, 2010, at 6:28 AM, Gunnlaugur Briem wrote:

> This produces the equivalent SELECT ... UNION ALL ... UNION ALL ...
> using select, literal_column and union_all (and leaving aside the
> details of representing the literal values inside the VALUES clause)
> --- works just fine and PostgreSQL produces the same query plan for
> it:
> 
> num_columns = len(weights_and_valueids[0]) # assuming all are the same
> length
> weights_clause = union_all(*(
>    select([literal_column('%s' % weight_and_valueid[i]).label('column
> %d' % (i+1))
>            for i in xrange(0, num_columns)
>            ])
>    for weight_and_valueid in weights_and_valueids
>    )).alias('weights')
> 
> Is this more portable, and thus should be used in preference to VALUES
> as a literal table clause?


ah the literal values clause, just had to use that recently.     Probably 
should start cataloging recipes for these things:

from sqlalchemy import *
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import FromClause
from sqlalchemy.sql import table, column

class values(FromClause):
    def __init__(self, *args):
        self.list = args
        
    def _populate_column_collection(self):
        self._columns.update(
            [("column%d" % i, column("column%d" % i))
                    for i in xrange(1, len(self.list[0]) + 1)]
        )

@compiles(values)
def compile_values(element, compiler, asfrom=False, **kw):
    v = "VALUES %s" % ", ".join(
        "(%s)" % ", ".join(repr(elem) for elem in tup)
        for tup in element.list
    )
    if asfrom:
        v = "(%s)" % v
    return v
    
if __name__ == '__main__':
    t1 = table('t1', column('a'), column('b'))
    t2 = values((1, 0.5), (2, -0.5)).alias('weights')
    print select([t1, t2]).select_from(t1.join(t2, t1.c.a==t2.c.column2))
    

I will log a ticket to add a nicely subclassable/documented "FromElement" since 
that part above is non-obvious.




> 
> Regards,
> 
>    - Gulli
> 
> 
> 
> On Feb 26, 10:28 am, Gunnlaugur Briem <gunnlau...@gmail.com> wrote:
>> Hi,
>> 
>> I want to perform a weighted sum over one column, specifying the
>> weights in a literal table (a VALUES clause):
>> 
>> select a, sum(b*weights.column1)
>>     FROM (select a, b from whatever) foo
>>     JOIN (values (1, 0.5), (2, -0.5) ) weights ON weights.column2=a
>> GROUP BY 1;
>> 
>> This is on PostgreSQL 8.4. To represent this in
>> sqlalchemy.sql.expression terms:
>> 
>> select([subquery.c.a, func.sum(subquery.c.b *
>> weights_clause.c['column2']),
>>        weights_clause.c['column1']==subquery.c.a
>>        )
>> 
>> but how do I get the weights_clause? I want it to compile to VALUES
>> (1, 0.5), (2, -0.5) (and then wrap it with .alias('weights')) but it
>> seems like there is no expression for this in SQLAlchemy so far (just
>> the VALUES support in INSERT and UPDATE, which does not work for this
>> use).
>> 
>> Does this require a new subclass of FromClause, or is there an
>> existing way that I'm not seeing?
>> 
>> The column names 'column1', 'column2' are as specified 
>> herehttp://www.postgresql.org/docs/8.4/static/queries-values.html— the
>> names may be specific to PostgreSQL, not sure, but I believe (haven't
>> checked) that SQL generally allows VALUES to be used wherever SELECT
>> can be used.
>> 
>> Thanks,
>> 
>>     - Gulli
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalch...@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to