I ended up creating my subclass of Select, copy/pasting the __init__ and 
__str__ methods and filled in my own functionality, and then monkey-patched 
it as described above.

It is by no means full featured, but it works alright for my use case. I've 
posted my implementation below for your viewing pleasure ;)


class SelectWithDistinct(sql.Select):
    """Select definition that allows for DISTINCT queries.

    DISTINCT is - unfortunately - not yet available in the python-sql module,
    so we implement this ourselves in this class, which can be monkey-patched
    into the python-sql library. Not ideal, but it is robust enough.

    The entry point for the monkey-patching would be in sql.From.select(..)
    This method needs to be replaced with one that uses this Select
    implementation instead of the default one.
    """
    __slots__ = ('_columns', 'distincts', '_where', '_group_by', '_having',
                 '_for_', 'from_')

    def __init__(self, columns, distincts=None, from_=None, where=None, 
group_by=None,
                 having=None, for_=None, **kwargs):
        self._columns = None
        self._where = None
        self._group_by = None
        self._having = None
        self._for_ = None
        super(SelectWithDistinct, self).__init__(columns, **kwargs)
        self.distincts = distincts
        self.columns = columns
        self.from_ = from_
        self.where = where
        self.group_by = group_by
        self.having = having
        self.for_ = for_

    def __str__(self):
        if (
            Flavor.get().limitstyle == 'rownum'
            and (self.limit is not None or self.offset is not None)
        ):
            return self._rownum(str)

        with AliasManager():
            from_ = str(self.from_)
            if self.columns:
                columns = ', '.join(map(self._format_column, self.columns))
            else:
                columns = '*'

            if self.distincts is not None:
                if len(self.distincts) == 0:
                    distinct = 'DISTINCT '
                else:
                    distinct = 'DISTINCT ON ({}) '.format(
                        ', '.join(map(self._format_column, self.distincts))
                    )
                columns = distinct + columns

            where = ''
            if self.where:
                where = ' WHERE ' + str(self.where)
            group_by = ''
            if self.group_by:
                group_by = ' GROUP BY ' + ', '.join(map(str, self.group_by))
            having = ''
            if self.having:
                having = ' HAVING ' + str(self.having)
            window = ''
            windows = [f.window for f in self._window_functions()]
            if windows:
                window = ' WINDOW ' + ', '.join(
                    '"%s" AS (%s)' % (w.alias, w) for w in windows)
            for_ = ''
            if self.for_ is not None:
                for_ = ' ' + ' '.join(map(str, self.for_))
            return (self._with_str()
                    + 'SELECT %s FROM %s' % (columns, from_)
                    + where + group_by + having + window + self._order_by_str
                    + self._limit_offset_str + for_)


# Monkey-patch the python-sql library with an implementation of Select
# that supports DISTINCT
def monkey_select(self, *args, **kwargs):
    return SelectWithDistinct(args, from_=self, **kwargs)
sql.From.select = monkey_select


On Wednesday, September 14, 2016 at 11:35:03 AM UTC+2, Cédric Krier wrote:
>
> On 2016-09-14 10:35, Cédric Krier wrote: 
> > On 2016-09-14 00:10, Ruben Nielsen wrote: 
> > > Any plans on adding SELECT DISTINCT? I see in the code, that there is 
> a 
> > > TODO comment in place. 
> > 
> > Usually DISTINCT can be avoided by using a GROUP BY. 
> > But it should not be too difficult to implement. 
>
> Here is: https://python-sql.tryton.org/bug53 
>
> -- 
> Cédric Krier - B2CK SPRL 
> Email/Jabber: cedric...@b2ck.com <javascript:> 
> Tel: +32 472 54 46 59 
> Website: http://www.b2ck.com/ 
>

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

Reply via email to