12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713 |
- # sql/selectable.py
- # Copyright (C) 2005-2017 the SQLAlchemy authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of SQLAlchemy and is released under
- # the MIT License: http://www.opensource.org/licenses/mit-license.php
- """The :class:`.FromClause` class of SQL expression elements, representing
- SQL tables and derived rowsets.
- """
- from .elements import ClauseElement, TextClause, ClauseList, \
- and_, Grouping, UnaryExpression, literal_column, BindParameter
- from .elements import _clone, \
- _literal_as_text, _interpret_as_column_or_from, _expand_cloned,\
- _select_iterables, _anonymous_label, _clause_element_as_expr,\
- _cloned_intersection, _cloned_difference, True_, \
- _literal_as_label_reference, _literal_and_labels_as_label_reference
- from .base import Immutable, Executable, _generative, \
- ColumnCollection, ColumnSet, _from_objects, Generative
- from . import type_api
- from .. import inspection
- from .. import util
- from .. import exc
- from operator import attrgetter
- from . import operators
- import operator
- import collections
- from .annotation import Annotated
- import itertools
- from sqlalchemy.sql.visitors import Visitable
- def _interpret_as_from(element):
- insp = inspection.inspect(element, raiseerr=False)
- if insp is None:
- if isinstance(element, util.string_types):
- util.warn_limited(
- "Textual SQL FROM expression %(expr)r should be "
- "explicitly declared as text(%(expr)r), "
- "or use table(%(expr)r) for more specificity",
- {"expr": util.ellipses_string(element)})
- return TextClause(util.text_type(element))
- try:
- return insp.selectable
- except AttributeError:
- raise exc.ArgumentError("FROM expression expected")
- def _interpret_as_select(element):
- element = _interpret_as_from(element)
- if isinstance(element, Alias):
- element = element.original
- if not isinstance(element, SelectBase):
- element = element.select()
- return element
- class _OffsetLimitParam(BindParameter):
- @property
- def _limit_offset_value(self):
- return self.effective_value
- def _offset_or_limit_clause(element, name=None, type_=None):
- """Convert the given value to an "offset or limit" clause.
- This handles incoming integers and converts to an expression; if
- an expression is already given, it is passed through.
- """
- if element is None:
- return None
- elif hasattr(element, '__clause_element__'):
- return element.__clause_element__()
- elif isinstance(element, Visitable):
- return element
- else:
- value = util.asint(element)
- return _OffsetLimitParam(name, value, type_=type_, unique=True)
- def _offset_or_limit_clause_asint(clause, attrname):
- """Convert the "offset or limit" clause of a select construct to an
- integer.
- This is only possible if the value is stored as a simple bound parameter.
- Otherwise, a compilation error is raised.
- """
- if clause is None:
- return None
- try:
- value = clause._limit_offset_value
- except AttributeError:
- raise exc.CompileError(
- "This SELECT structure does not use a simple "
- "integer value for %s" % attrname)
- else:
- return util.asint(value)
- def subquery(alias, *args, **kwargs):
- r"""Return an :class:`.Alias` object derived
- from a :class:`.Select`.
- name
- alias name
- \*args, \**kwargs
- all other arguments are delivered to the
- :func:`select` function.
- """
- return Select(*args, **kwargs).alias(alias)
- def alias(selectable, name=None, flat=False):
- """Return an :class:`.Alias` object.
- An :class:`.Alias` represents any :class:`.FromClause`
- with an alternate name assigned within SQL, typically using the ``AS``
- clause when generated, e.g. ``SELECT * FROM table AS aliasname``.
- Similar functionality is available via the
- :meth:`~.FromClause.alias` method
- available on all :class:`.FromClause` subclasses.
- When an :class:`.Alias` is created from a :class:`.Table` object,
- this has the effect of the table being rendered
- as ``tablename AS aliasname`` in a SELECT statement.
- For :func:`.select` objects, the effect is that of creating a named
- subquery, i.e. ``(select ...) AS aliasname``.
- The ``name`` parameter is optional, and provides the name
- to use in the rendered SQL. If blank, an "anonymous" name
- will be deterministically generated at compile time.
- Deterministic means the name is guaranteed to be unique against
- other constructs used in the same statement, and will also be the
- same name for each successive compilation of the same statement
- object.
- :param selectable: any :class:`.FromClause` subclass,
- such as a table, select statement, etc.
- :param name: string name to be assigned as the alias.
- If ``None``, a name will be deterministically generated
- at compile time.
- :param flat: Will be passed through to if the given selectable
- is an instance of :class:`.Join` - see :meth:`.Join.alias`
- for details.
- .. versionadded:: 0.9.0
- """
- return _interpret_as_from(selectable).alias(name=name, flat=flat)
- def lateral(selectable, name=None):
- """Return a :class:`.Lateral` object.
- :class:`.Lateral` is an :class:`.Alias` subclass that represents
- a subquery with the LATERAL keyword applied to it.
- The special behavior of a LATERAL subquery is that it appears in the
- FROM clause of an enclosing SELECT, but may correlate to other
- FROM clauses of that SELECT. It is a special case of subquery
- only supported by a small number of backends, currently more recent
- PostgreSQL versions.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- return _interpret_as_from(selectable).lateral(name=name)
- def tablesample(selectable, sampling, name=None, seed=None):
- """Return a :class:`.TableSample` object.
- :class:`.TableSample` is an :class:`.Alias` subclass that represents
- a table with the TABLESAMPLE clause applied to it.
- :func:`~.expression.tablesample`
- is also available from the :class:`.FromClause` class via the
- :meth:`.FromClause.tablesample` method.
- The TABLESAMPLE clause allows selecting a randomly selected approximate
- percentage of rows from a table. It supports multiple sampling methods,
- most commonly BERNOULLI and SYSTEM.
- e.g.::
- from sqlalchemy import func
- selectable = people.tablesample(
- func.bernoulli(1),
- name='alias',
- seed=func.random())
- stmt = select([selectable.c.people_id])
- Assuming ``people`` with a column ``people_id``, the above
- statement would render as::
- SELECT alias.people_id FROM
- people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
- REPEATABLE (random())
- .. versionadded:: 1.1
- :param sampling: a ``float`` percentage between 0 and 100 or
- :class:`.functions.Function`.
- :param name: optional alias name
- :param seed: any real-valued SQL expression. When specified, the
- REPEATABLE sub-clause is also rendered.
- """
- return _interpret_as_from(selectable).tablesample(
- sampling, name=name, seed=seed)
- class Selectable(ClauseElement):
- """mark a class as being selectable"""
- __visit_name__ = 'selectable'
- is_selectable = True
- @property
- def selectable(self):
- return self
- class HasPrefixes(object):
- _prefixes = ()
- @_generative
- def prefix_with(self, *expr, **kw):
- r"""Add one or more expressions following the statement keyword, i.e.
- SELECT, INSERT, UPDATE, or DELETE. Generative.
- This is used to support backend-specific prefix keywords such as those
- provided by MySQL.
- E.g.::
- stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")
- Multiple prefixes can be specified by multiple calls
- to :meth:`.prefix_with`.
- :param \*expr: textual or :class:`.ClauseElement` construct which
- will be rendered following the INSERT, UPDATE, or DELETE
- keyword.
- :param \**kw: A single keyword 'dialect' is accepted. This is an
- optional string dialect name which will
- limit rendering of this prefix to only that dialect.
- """
- dialect = kw.pop('dialect', None)
- if kw:
- raise exc.ArgumentError("Unsupported argument(s): %s" %
- ",".join(kw))
- self._setup_prefixes(expr, dialect)
- def _setup_prefixes(self, prefixes, dialect=None):
- self._prefixes = self._prefixes + tuple(
- [(_literal_as_text(p, warn=False), dialect) for p in prefixes])
- class HasSuffixes(object):
- _suffixes = ()
- @_generative
- def suffix_with(self, *expr, **kw):
- r"""Add one or more expressions following the statement as a whole.
- This is used to support backend-specific suffix keywords on
- certain constructs.
- E.g.::
- stmt = select([col1, col2]).cte().suffix_with(
- "cycle empno set y_cycle to 1 default 0", dialect="oracle")
- Multiple suffixes can be specified by multiple calls
- to :meth:`.suffix_with`.
- :param \*expr: textual or :class:`.ClauseElement` construct which
- will be rendered following the target clause.
- :param \**kw: A single keyword 'dialect' is accepted. This is an
- optional string dialect name which will
- limit rendering of this suffix to only that dialect.
- """
- dialect = kw.pop('dialect', None)
- if kw:
- raise exc.ArgumentError("Unsupported argument(s): %s" %
- ",".join(kw))
- self._setup_suffixes(expr, dialect)
- def _setup_suffixes(self, suffixes, dialect=None):
- self._suffixes = self._suffixes + tuple(
- [(_literal_as_text(p, warn=False), dialect) for p in suffixes])
- class FromClause(Selectable):
- """Represent an element that can be used within the ``FROM``
- clause of a ``SELECT`` statement.
- The most common forms of :class:`.FromClause` are the
- :class:`.Table` and the :func:`.select` constructs. Key
- features common to all :class:`.FromClause` objects include:
- * a :attr:`.c` collection, which provides per-name access to a collection
- of :class:`.ColumnElement` objects.
- * a :attr:`.primary_key` attribute, which is a collection of all those
- :class:`.ColumnElement` objects that indicate the ``primary_key`` flag.
- * Methods to generate various derivations of a "from" clause, including
- :meth:`.FromClause.alias`, :meth:`.FromClause.join`,
- :meth:`.FromClause.select`.
- """
- __visit_name__ = 'fromclause'
- named_with_column = False
- _hide_froms = []
- _is_join = False
- _is_select = False
- _is_from_container = False
- _textual = False
- """a marker that allows us to easily distinguish a :class:`.TextAsFrom`
- or similar object from other kinds of :class:`.FromClause` objects."""
- schema = None
- """Define the 'schema' attribute for this :class:`.FromClause`.
- This is typically ``None`` for most objects except that of
- :class:`.Table`, where it is taken as the value of the
- :paramref:`.Table.schema` argument.
- """
- def _translate_schema(self, effective_schema, map_):
- return effective_schema
- _memoized_property = util.group_expirable_memoized_property(["_columns"])
- @util.deprecated(
- '1.1',
- message="``FromClause.count()`` is deprecated. Counting "
- "rows requires that the correct column expression and "
- "accommodations for joins, DISTINCT, etc. must be made, "
- "otherwise results may not be what's expected. "
- "Please use an appropriate ``func.count()`` expression "
- "directly.")
- @util.dependencies("sqlalchemy.sql.functions")
- def count(self, functions, whereclause=None, **params):
- """return a SELECT COUNT generated against this
- :class:`.FromClause`.
- The function generates COUNT against the
- first column in the primary key of the table, or against
- the first column in the table overall. Explicit use of
- ``func.count()`` should be preferred::
- row_count = conn.scalar(
- select([func.count('*')]).select_from(table)
- )
- .. seealso::
- :data:`.func`
- """
- if self.primary_key:
- col = list(self.primary_key)[0]
- else:
- col = list(self.columns)[0]
- return Select(
- [functions.func.count(col).label('tbl_row_count')],
- whereclause,
- from_obj=[self],
- **params)
- def select(self, whereclause=None, **params):
- """return a SELECT of this :class:`.FromClause`.
- .. seealso::
- :func:`~.sql.expression.select` - general purpose
- method which allows for arbitrary column lists.
- """
- return Select([self], whereclause, **params)
- def join(self, right, onclause=None, isouter=False, full=False):
- """Return a :class:`.Join` from this :class:`.FromClause`
- to another :class:`FromClause`.
- E.g.::
- from sqlalchemy import join
- j = user_table.join(address_table,
- user_table.c.id == address_table.c.user_id)
- stmt = select([user_table]).select_from(j)
- would emit SQL along the lines of::
- SELECT user.id, user.name FROM user
- JOIN address ON user.id = address.user_id
- :param right: the right side of the join; this is any
- :class:`.FromClause` object such as a :class:`.Table` object, and
- may also be a selectable-compatible object such as an ORM-mapped
- class.
- :param onclause: a SQL expression representing the ON clause of the
- join. If left at ``None``, :meth:`.FromClause.join` will attempt to
- join the two tables based on a foreign key relationship.
- :param isouter: if True, render a LEFT OUTER JOIN, instead of JOIN.
- :param full: if True, render a FULL OUTER JOIN, instead of LEFT OUTER
- JOIN. Implies :paramref:`.FromClause.join.isouter`.
- .. versionadded:: 1.1
- .. seealso::
- :func:`.join` - standalone function
- :class:`.Join` - the type of object produced
- """
- return Join(self, right, onclause, isouter, full)
- def outerjoin(self, right, onclause=None, full=False):
- """Return a :class:`.Join` from this :class:`.FromClause`
- to another :class:`FromClause`, with the "isouter" flag set to
- True.
- E.g.::
- from sqlalchemy import outerjoin
- j = user_table.outerjoin(address_table,
- user_table.c.id == address_table.c.user_id)
- The above is equivalent to::
- j = user_table.join(
- address_table,
- user_table.c.id == address_table.c.user_id,
- isouter=True)
- :param right: the right side of the join; this is any
- :class:`.FromClause` object such as a :class:`.Table` object, and
- may also be a selectable-compatible object such as an ORM-mapped
- class.
- :param onclause: a SQL expression representing the ON clause of the
- join. If left at ``None``, :meth:`.FromClause.join` will attempt to
- join the two tables based on a foreign key relationship.
- :param full: if True, render a FULL OUTER JOIN, instead of
- LEFT OUTER JOIN.
- .. versionadded:: 1.1
- .. seealso::
- :meth:`.FromClause.join`
- :class:`.Join`
- """
- return Join(self, right, onclause, True, full)
- def alias(self, name=None, flat=False):
- """return an alias of this :class:`.FromClause`.
- This is shorthand for calling::
- from sqlalchemy import alias
- a = alias(self, name=name)
- See :func:`~.expression.alias` for details.
- """
- return Alias(self, name)
- def lateral(self, name=None):
- """Return a LATERAL alias of this :class:`.FromClause`.
- The return value is the :class:`.Lateral` construct also
- provided by the top-level :func:`~.expression.lateral` function.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- return Lateral(self, name)
- def tablesample(self, sampling, name=None, seed=None):
- """Return a TABLESAMPLE alias of this :class:`.FromClause`.
- The return value is the :class:`.TableSample` construct also
- provided by the top-level :func:`~.expression.tablesample` function.
- .. versionadded:: 1.1
- .. seealso::
- :func:`~.expression.tablesample` - usage guidelines and parameters
- """
- return TableSample(self, sampling, name, seed)
- def is_derived_from(self, fromclause):
- """Return True if this FromClause is 'derived' from the given
- FromClause.
- An example would be an Alias of a Table is derived from that Table.
- """
- # this is essentially an "identity" check in the base class.
- # Other constructs override this to traverse through
- # contained elements.
- return fromclause in self._cloned_set
- def _is_lexical_equivalent(self, other):
- """Return True if this FromClause and the other represent
- the same lexical identity.
- This tests if either one is a copy of the other, or
- if they are the same via annotation identity.
- """
- return self._cloned_set.intersection(other._cloned_set)
- @util.dependencies("sqlalchemy.sql.util")
- def replace_selectable(self, sqlutil, old, alias):
- """replace all occurrences of FromClause 'old' with the given Alias
- object, returning a copy of this :class:`.FromClause`.
- """
- return sqlutil.ClauseAdapter(alias).traverse(self)
- def correspond_on_equivalents(self, column, equivalents):
- """Return corresponding_column for the given column, or if None
- search for a match in the given dictionary.
- """
- col = self.corresponding_column(column, require_embedded=True)
- if col is None and col in equivalents:
- for equiv in equivalents[col]:
- nc = self.corresponding_column(equiv, require_embedded=True)
- if nc:
- return nc
- return col
- def corresponding_column(self, column, require_embedded=False):
- """Given a :class:`.ColumnElement`, return the exported
- :class:`.ColumnElement` object from this :class:`.Selectable`
- which corresponds to that original
- :class:`~sqlalchemy.schema.Column` via a common ancestor
- column.
- :param column: the target :class:`.ColumnElement` to be matched
- :param require_embedded: only return corresponding columns for
- the given :class:`.ColumnElement`, if the given
- :class:`.ColumnElement` is actually present within a sub-element
- of this :class:`.FromClause`. Normally the column will match if
- it merely shares a common ancestor with one of the exported
- columns of this :class:`.FromClause`.
- """
- def embedded(expanded_proxy_set, target_set):
- for t in target_set.difference(expanded_proxy_set):
- if not set(_expand_cloned([t])
- ).intersection(expanded_proxy_set):
- return False
- return True
- # don't dig around if the column is locally present
- if self.c.contains_column(column):
- return column
- col, intersect = None, None
- target_set = column.proxy_set
- cols = self.c._all_columns
- for c in cols:
- expanded_proxy_set = set(_expand_cloned(c.proxy_set))
- i = target_set.intersection(expanded_proxy_set)
- if i and (not require_embedded
- or embedded(expanded_proxy_set, target_set)):
- if col is None:
- # no corresponding column yet, pick this one.
- col, intersect = c, i
- elif len(i) > len(intersect):
- # 'c' has a larger field of correspondence than
- # 'col'. i.e. selectable.c.a1_x->a1.c.x->table.c.x
- # matches a1.c.x->table.c.x better than
- # selectable.c.x->table.c.x does.
- col, intersect = c, i
- elif i == intersect:
- # they have the same field of correspondence. see
- # which proxy_set has fewer columns in it, which
- # indicates a closer relationship with the root
- # column. Also take into account the "weight"
- # attribute which CompoundSelect() uses to give
- # higher precedence to columns based on vertical
- # position in the compound statement, and discard
- # columns that have no reference to the target
- # column (also occurs with CompoundSelect)
- col_distance = util.reduce(
- operator.add,
- [sc._annotations.get('weight', 1) for sc in
- col.proxy_set if sc.shares_lineage(column)])
- c_distance = util.reduce(
- operator.add,
- [sc._annotations.get('weight', 1) for sc in
- c.proxy_set if sc.shares_lineage(column)])
- if c_distance < col_distance:
- col, intersect = c, i
- return col
- @property
- def description(self):
- """a brief description of this FromClause.
- Used primarily for error message formatting.
- """
- return getattr(self, 'name', self.__class__.__name__ + " object")
- def _reset_exported(self):
- """delete memoized collections when a FromClause is cloned."""
- self._memoized_property.expire_instance(self)
- @_memoized_property
- def columns(self):
- """A named-based collection of :class:`.ColumnElement` objects
- maintained by this :class:`.FromClause`.
- The :attr:`.columns`, or :attr:`.c` collection, is the gateway
- to the construction of SQL expressions using table-bound or
- other selectable-bound columns::
- select([mytable]).where(mytable.c.somecolumn == 5)
- """
- if '_columns' not in self.__dict__:
- self._init_collections()
- self._populate_column_collection()
- return self._columns.as_immutable()
- @_memoized_property
- def primary_key(self):
- """Return the collection of Column objects which comprise the
- primary key of this FromClause."""
- self._init_collections()
- self._populate_column_collection()
- return self.primary_key
- @_memoized_property
- def foreign_keys(self):
- """Return the collection of ForeignKey objects which this
- FromClause references."""
- self._init_collections()
- self._populate_column_collection()
- return self.foreign_keys
- c = property(attrgetter('columns'),
- doc="An alias for the :attr:`.columns` attribute.")
- _select_iterable = property(attrgetter('columns'))
- def _init_collections(self):
- assert '_columns' not in self.__dict__
- assert 'primary_key' not in self.__dict__
- assert 'foreign_keys' not in self.__dict__
- self._columns = ColumnCollection()
- self.primary_key = ColumnSet()
- self.foreign_keys = set()
- @property
- def _cols_populated(self):
- return '_columns' in self.__dict__
- def _populate_column_collection(self):
- """Called on subclasses to establish the .c collection.
- Each implementation has a different way of establishing
- this collection.
- """
- def _refresh_for_new_column(self, column):
- """Given a column added to the .c collection of an underlying
- selectable, produce the local version of that column, assuming this
- selectable ultimately should proxy this column.
- this is used to "ping" a derived selectable to add a new column
- to its .c. collection when a Column has been added to one of the
- Table objects it ultimtely derives from.
- If the given selectable hasn't populated its .c. collection yet,
- it should at least pass on the message to the contained selectables,
- but it will return None.
- This method is currently used by Declarative to allow Table
- columns to be added to a partially constructed inheritance
- mapping that may have already produced joins. The method
- isn't public right now, as the full span of implications
- and/or caveats aren't yet clear.
- It's also possible that this functionality could be invoked by
- default via an event, which would require that
- selectables maintain a weak referencing collection of all
- derivations.
- """
- if not self._cols_populated:
- return None
- elif (column.key in self.columns and
- self.columns[column.key] is column):
- return column
- else:
- return None
- class Join(FromClause):
- """represent a ``JOIN`` construct between two :class:`.FromClause`
- elements.
- The public constructor function for :class:`.Join` is the module-level
- :func:`.join()` function, as well as the :meth:`.FromClause.join` method
- of any :class:`.FromClause` (e.g. such as :class:`.Table`).
- .. seealso::
- :func:`.join`
- :meth:`.FromClause.join`
- """
- __visit_name__ = 'join'
- _is_join = True
- def __init__(self, left, right, onclause=None, isouter=False, full=False):
- """Construct a new :class:`.Join`.
- The usual entrypoint here is the :func:`~.expression.join`
- function or the :meth:`.FromClause.join` method of any
- :class:`.FromClause` object.
- """
- self.left = _interpret_as_from(left)
- self.right = _interpret_as_from(right).self_group()
- if onclause is None:
- self.onclause = self._match_primaries(self.left, self.right)
- else:
- self.onclause = onclause
- self.isouter = isouter
- self.full = full
- @classmethod
- def _create_outerjoin(cls, left, right, onclause=None, full=False):
- """Return an ``OUTER JOIN`` clause element.
- The returned object is an instance of :class:`.Join`.
- Similar functionality is also available via the
- :meth:`~.FromClause.outerjoin()` method on any
- :class:`.FromClause`.
- :param left: The left side of the join.
- :param right: The right side of the join.
- :param onclause: Optional criterion for the ``ON`` clause, is
- derived from foreign key relationships established between
- left and right otherwise.
- To chain joins together, use the :meth:`.FromClause.join` or
- :meth:`.FromClause.outerjoin` methods on the resulting
- :class:`.Join` object.
- """
- return cls(left, right, onclause, isouter=True, full=full)
- @classmethod
- def _create_join(cls, left, right, onclause=None, isouter=False,
- full=False):
- """Produce a :class:`.Join` object, given two :class:`.FromClause`
- expressions.
- E.g.::
- j = join(user_table, address_table,
- user_table.c.id == address_table.c.user_id)
- stmt = select([user_table]).select_from(j)
- would emit SQL along the lines of::
- SELECT user.id, user.name FROM user
- JOIN address ON user.id = address.user_id
- Similar functionality is available given any
- :class:`.FromClause` object (e.g. such as a :class:`.Table`) using
- the :meth:`.FromClause.join` method.
- :param left: The left side of the join.
- :param right: the right side of the join; this is any
- :class:`.FromClause` object such as a :class:`.Table` object, and
- may also be a selectable-compatible object such as an ORM-mapped
- class.
- :param onclause: a SQL expression representing the ON clause of the
- join. If left at ``None``, :meth:`.FromClause.join` will attempt to
- join the two tables based on a foreign key relationship.
- :param isouter: if True, render a LEFT OUTER JOIN, instead of JOIN.
- :param full: if True, render a FULL OUTER JOIN, instead of JOIN.
- .. versionadded:: 1.1
- .. seealso::
- :meth:`.FromClause.join` - method form, based on a given left side
- :class:`.Join` - the type of object produced
- """
- return cls(left, right, onclause, isouter, full)
- @property
- def description(self):
- return "Join object on %s(%d) and %s(%d)" % (
- self.left.description,
- id(self.left),
- self.right.description,
- id(self.right))
- def is_derived_from(self, fromclause):
- return fromclause is self or \
- self.left.is_derived_from(fromclause) or \
- self.right.is_derived_from(fromclause)
- def self_group(self, against=None):
- return FromGrouping(self)
- @util.dependencies("sqlalchemy.sql.util")
- def _populate_column_collection(self, sqlutil):
- columns = [c for c in self.left.columns] + \
- [c for c in self.right.columns]
- self.primary_key.extend(sqlutil.reduce_columns(
- (c for c in columns if c.primary_key), self.onclause))
- self._columns.update((col._label, col) for col in columns)
- self.foreign_keys.update(itertools.chain(
- *[col.foreign_keys for col in columns]))
- def _refresh_for_new_column(self, column):
- col = self.left._refresh_for_new_column(column)
- if col is None:
- col = self.right._refresh_for_new_column(column)
- if col is not None:
- if self._cols_populated:
- self._columns[col._label] = col
- self.foreign_keys.update(col.foreign_keys)
- if col.primary_key:
- self.primary_key.add(col)
- return col
- return None
- def _copy_internals(self, clone=_clone, **kw):
- self._reset_exported()
- self.left = clone(self.left, **kw)
- self.right = clone(self.right, **kw)
- self.onclause = clone(self.onclause, **kw)
- def get_children(self, **kwargs):
- return self.left, self.right, self.onclause
- def _match_primaries(self, left, right):
- if isinstance(left, Join):
- left_right = left.right
- else:
- left_right = None
- return self._join_condition(left, right, a_subset=left_right)
- @classmethod
- def _join_condition(cls, a, b, ignore_nonexistent_tables=False,
- a_subset=None,
- consider_as_foreign_keys=None):
- """create a join condition between two tables or selectables.
- e.g.::
- join_condition(tablea, tableb)
- would produce an expression along the lines of::
- tablea.c.id==tableb.c.tablea_id
- The join is determined based on the foreign key relationships
- between the two selectables. If there are multiple ways
- to join, or no way to join, an error is raised.
- :param ignore_nonexistent_tables: Deprecated - this
- flag is no longer used. Only resolution errors regarding
- the two given tables are propagated.
- :param a_subset: An optional expression that is a sub-component
- of ``a``. An attempt will be made to join to just this sub-component
- first before looking at the full ``a`` construct, and if found
- will be successful even if there are other ways to join to ``a``.
- This allows the "right side" of a join to be passed thereby
- providing a "natural join".
- """
- constraints = cls._joincond_scan_left_right(
- a, a_subset, b, consider_as_foreign_keys)
- if len(constraints) > 1:
- cls._joincond_trim_constraints(
- a, b, constraints, consider_as_foreign_keys)
- if len(constraints) == 0:
- if isinstance(b, FromGrouping):
- hint = " Perhaps you meant to convert the right side to a "\
- "subquery using alias()?"
- else:
- hint = ""
- raise exc.NoForeignKeysError(
- "Can't find any foreign key relationships "
- "between '%s' and '%s'.%s" %
- (a.description, b.description, hint))
- crit = [(x == y) for x, y in list(constraints.values())[0]]
- if len(crit) == 1:
- return (crit[0])
- else:
- return and_(*crit)
- @classmethod
- def _joincond_scan_left_right(
- cls, a, a_subset, b, consider_as_foreign_keys):
- constraints = collections.defaultdict(list)
- for left in (a_subset, a):
- if left is None:
- continue
- for fk in sorted(
- b.foreign_keys,
- key=lambda fk: fk.parent._creation_order):
- if consider_as_foreign_keys is not None and \
- fk.parent not in consider_as_foreign_keys:
- continue
- try:
- col = fk.get_referent(left)
- except exc.NoReferenceError as nrte:
- if nrte.table_name == left.name:
- raise
- else:
- continue
- if col is not None:
- constraints[fk.constraint].append((col, fk.parent))
- if left is not b:
- for fk in sorted(
- left.foreign_keys,
- key=lambda fk: fk.parent._creation_order):
- if consider_as_foreign_keys is not None and \
- fk.parent not in consider_as_foreign_keys:
- continue
- try:
- col = fk.get_referent(b)
- except exc.NoReferenceError as nrte:
- if nrte.table_name == b.name:
- raise
- else:
- continue
- if col is not None:
- constraints[fk.constraint].append((col, fk.parent))
- if constraints:
- break
- return constraints
- @classmethod
- def _joincond_trim_constraints(
- cls, a, b, constraints, consider_as_foreign_keys):
- # more than one constraint matched. narrow down the list
- # to include just those FKCs that match exactly to
- # "consider_as_foreign_keys".
- if consider_as_foreign_keys:
- for const in list(constraints):
- if set(f.parent for f in const.elements) != set(
- consider_as_foreign_keys):
- del constraints[const]
- # if still multiple constraints, but
- # they all refer to the exact same end result, use it.
- if len(constraints) > 1:
- dedupe = set(tuple(crit) for crit in constraints.values())
- if len(dedupe) == 1:
- key = list(constraints)[0]
- constraints = {key: constraints[key]}
- if len(constraints) != 1:
- raise exc.AmbiguousForeignKeysError(
- "Can't determine join between '%s' and '%s'; "
- "tables have more than one foreign key "
- "constraint relationship between them. "
- "Please specify the 'onclause' of this "
- "join explicitly." % (a.description, b.description))
- def select(self, whereclause=None, **kwargs):
- r"""Create a :class:`.Select` from this :class:`.Join`.
- The equivalent long-hand form, given a :class:`.Join` object
- ``j``, is::
- from sqlalchemy import select
- j = select([j.left, j.right], **kw).\
- where(whereclause).\
- select_from(j)
- :param whereclause: the WHERE criterion that will be sent to
- the :func:`select()` function
- :param \**kwargs: all other kwargs are sent to the
- underlying :func:`select()` function.
- """
- collist = [self.left, self.right]
- return Select(collist, whereclause, from_obj=[self], **kwargs)
- @property
- def bind(self):
- return self.left.bind or self.right.bind
- @util.dependencies("sqlalchemy.sql.util")
- def alias(self, sqlutil, name=None, flat=False):
- r"""return an alias of this :class:`.Join`.
- The default behavior here is to first produce a SELECT
- construct from this :class:`.Join`, then to produce an
- :class:`.Alias` from that. So given a join of the form::
- j = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
- The JOIN by itself would look like::
- table_a JOIN table_b ON table_a.id = table_b.a_id
- Whereas the alias of the above, ``j.alias()``, would in a
- SELECT context look like::
- (SELECT table_a.id AS table_a_id, table_b.id AS table_b_id,
- table_b.a_id AS table_b_a_id
- FROM table_a
- JOIN table_b ON table_a.id = table_b.a_id) AS anon_1
- The equivalent long-hand form, given a :class:`.Join` object
- ``j``, is::
- from sqlalchemy import select, alias
- j = alias(
- select([j.left, j.right]).\
- select_from(j).\
- with_labels(True).\
- correlate(False),
- name=name
- )
- The selectable produced by :meth:`.Join.alias` features the same
- columns as that of the two individual selectables presented under
- a single name - the individual columns are "auto-labeled", meaning
- the ``.c.`` collection of the resulting :class:`.Alias` represents
- the names of the individual columns using a
- ``<tablename>_<columname>`` scheme::
- j.c.table_a_id
- j.c.table_b_a_id
- :meth:`.Join.alias` also features an alternate
- option for aliasing joins which produces no enclosing SELECT and
- does not normally apply labels to the column names. The
- ``flat=True`` option will call :meth:`.FromClause.alias`
- against the left and right sides individually.
- Using this option, no new ``SELECT`` is produced;
- we instead, from a construct as below::
- j = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
- j = j.alias(flat=True)
- we get a result like this::
- table_a AS table_a_1 JOIN table_b AS table_b_1 ON
- table_a_1.id = table_b_1.a_id
- The ``flat=True`` argument is also propagated to the contained
- selectables, so that a composite join such as::
- j = table_a.join(
- table_b.join(table_c,
- table_b.c.id == table_c.c.b_id),
- table_b.c.a_id == table_a.c.id
- ).alias(flat=True)
- Will produce an expression like::
- table_a AS table_a_1 JOIN (
- table_b AS table_b_1 JOIN table_c AS table_c_1
- ON table_b_1.id = table_c_1.b_id
- ) ON table_a_1.id = table_b_1.a_id
- The standalone :func:`~.expression.alias` function as well as the
- base :meth:`.FromClause.alias` method also support the ``flat=True``
- argument as a no-op, so that the argument can be passed to the
- ``alias()`` method of any selectable.
- .. versionadded:: 0.9.0 Added the ``flat=True`` option to create
- "aliases" of joins without enclosing inside of a SELECT
- subquery.
- :param name: name given to the alias.
- :param flat: if True, produce an alias of the left and right
- sides of this :class:`.Join` and return the join of those
- two selectables. This produces join expression that does not
- include an enclosing SELECT.
- .. versionadded:: 0.9.0
- .. seealso::
- :func:`~.expression.alias`
- """
- if flat:
- assert name is None, "Can't send name argument with flat"
- left_a, right_a = self.left.alias(flat=True), \
- self.right.alias(flat=True)
- adapter = sqlutil.ClauseAdapter(left_a).\
- chain(sqlutil.ClauseAdapter(right_a))
- return left_a.join(right_a, adapter.traverse(self.onclause),
- isouter=self.isouter, full=self.full)
- else:
- return self.select(use_labels=True, correlate=False).alias(name)
- @property
- def _hide_froms(self):
- return itertools.chain(*[_from_objects(x.left, x.right)
- for x in self._cloned_set])
- @property
- def _from_objects(self):
- return [self] + \
- self.onclause._from_objects + \
- self.left._from_objects + \
- self.right._from_objects
- class Alias(FromClause):
- """Represents an table or selectable alias (AS).
- Represents an alias, as typically applied to any table or
- sub-select within a SQL statement using the ``AS`` keyword (or
- without the keyword on certain databases such as Oracle).
- This object is constructed from the :func:`~.expression.alias` module
- level function as well as the :meth:`.FromClause.alias` method available
- on all :class:`.FromClause` subclasses.
- """
- __visit_name__ = 'alias'
- named_with_column = True
- _is_from_container = True
- def __init__(self, selectable, name=None):
- baseselectable = selectable
- while isinstance(baseselectable, Alias):
- baseselectable = baseselectable.element
- self.original = baseselectable
- self.supports_execution = baseselectable.supports_execution
- if self.supports_execution:
- self._execution_options = baseselectable._execution_options
- self.element = selectable
- if name is None:
- if self.original.named_with_column:
- name = getattr(self.original, 'name', None)
- name = _anonymous_label('%%(%d %s)s' % (id(self), name
- or 'anon'))
- self.name = name
- def self_group(self, target=None):
- if isinstance(target, CompoundSelect) and \
- isinstance(self.original, Select) and \
- self.original._needs_parens_for_grouping():
- return FromGrouping(self)
- return super(Alias, self).self_group(target)
- @property
- def description(self):
- if util.py3k:
- return self.name
- else:
- return self.name.encode('ascii', 'backslashreplace')
- def as_scalar(self):
- try:
- return self.element.as_scalar()
- except AttributeError:
- raise AttributeError("Element %s does not support "
- "'as_scalar()'" % self.element)
- def is_derived_from(self, fromclause):
- if fromclause in self._cloned_set:
- return True
- return self.element.is_derived_from(fromclause)
- def _populate_column_collection(self):
- for col in self.element.columns._all_columns:
- col._make_proxy(self)
- def _refresh_for_new_column(self, column):
- col = self.element._refresh_for_new_column(column)
- if col is not None:
- if not self._cols_populated:
- return None
- else:
- return col._make_proxy(self)
- else:
- return None
- def _copy_internals(self, clone=_clone, **kw):
- # don't apply anything to an aliased Table
- # for now. May want to drive this from
- # the given **kw.
- if isinstance(self.element, TableClause):
- return
- self._reset_exported()
- self.element = clone(self.element, **kw)
- baseselectable = self.element
- while isinstance(baseselectable, Alias):
- baseselectable = baseselectable.element
- self.original = baseselectable
- def get_children(self, column_collections=True, **kw):
- if column_collections:
- for c in self.c:
- yield c
- yield self.element
- @property
- def _from_objects(self):
- return [self]
- @property
- def bind(self):
- return self.element.bind
- class Lateral(Alias):
- """Represent a LATERAL subquery.
- This object is constructed from the :func:`~.expression.lateral` module
- level function as well as the :meth:`.FromClause.lateral` method available
- on all :class:`.FromClause` subclasses.
- While LATERAL is part of the SQL standard, curently only more recent
- PostgreSQL versions provide support for this keyword.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- __visit_name__ = 'lateral'
- class TableSample(Alias):
- """Represent a TABLESAMPLE clause.
- This object is constructed from the :func:`~.expression.tablesample` module
- level function as well as the :meth:`.FromClause.tablesample` method available
- on all :class:`.FromClause` subclasses.
- .. versionadded:: 1.1
- .. seealso::
- :func:`~.expression.tablesample`
- """
- __visit_name__ = 'tablesample'
- def __init__(self, selectable, sampling,
- name=None,
- seed=None):
- self.sampling = sampling
- self.seed = seed
- super(TableSample, self).__init__(selectable, name=name)
- @util.dependencies("sqlalchemy.sql.functions")
- def _get_method(self, functions):
- if isinstance(self.sampling, functions.Function):
- return self.sampling
- else:
- return functions.func.system(self.sampling)
- class CTE(Generative, HasSuffixes, Alias):
- """Represent a Common Table Expression.
- The :class:`.CTE` object is obtained using the
- :meth:`.SelectBase.cte` method from any selectable.
- See that method for complete examples.
- .. versionadded:: 0.7.6
- """
- __visit_name__ = 'cte'
- def __init__(self, selectable,
- name=None,
- recursive=False,
- _cte_alias=None,
- _restates=frozenset(),
- _suffixes=None):
- self.recursive = recursive
- self._cte_alias = _cte_alias
- self._restates = _restates
- if _suffixes:
- self._suffixes = _suffixes
- super(CTE, self).__init__(selectable, name=name)
- def _copy_internals(self, clone=_clone, **kw):
- super(CTE, self)._copy_internals(clone, **kw)
- if self._cte_alias is not None:
- self._cte_alias = self
- self._restates = frozenset([
- clone(elem, **kw) for elem in self._restates
- ])
- @util.dependencies("sqlalchemy.sql.dml")
- def _populate_column_collection(self, dml):
- if isinstance(self.element, dml.UpdateBase):
- for col in self.element._returning:
- col._make_proxy(self)
- else:
- for col in self.element.columns._all_columns:
- col._make_proxy(self)
- def alias(self, name=None, flat=False):
- return CTE(
- self.original,
- name=name,
- recursive=self.recursive,
- _cte_alias=self,
- _suffixes=self._suffixes
- )
- def union(self, other):
- return CTE(
- self.original.union(other),
- name=self.name,
- recursive=self.recursive,
- _restates=self._restates.union([self]),
- _suffixes=self._suffixes
- )
- def union_all(self, other):
- return CTE(
- self.original.union_all(other),
- name=self.name,
- recursive=self.recursive,
- _restates=self._restates.union([self]),
- _suffixes=self._suffixes
- )
- class HasCTE(object):
- """Mixin that declares a class to include CTE support.
- .. versionadded:: 1.1
- """
- def cte(self, name=None, recursive=False):
- r"""Return a new :class:`.CTE`, or Common Table Expression instance.
- Common table expressions are a SQL standard whereby SELECT
- statements can draw upon secondary statements specified along
- with the primary statement, using a clause called "WITH".
- Special semantics regarding UNION can also be employed to
- allow "recursive" queries, where a SELECT statement can draw
- upon the set of rows that have previously been selected.
- CTEs can also be applied to DML constructs UPDATE, INSERT
- and DELETE on some databases, both as a source of CTE rows
- when combined with RETURNING, as well as a consumer of
- CTE rows.
- SQLAlchemy detects :class:`.CTE` objects, which are treated
- similarly to :class:`.Alias` objects, as special elements
- to be delivered to the FROM clause of the statement as well
- as to a WITH clause at the top of the statement.
- .. versionchanged:: 1.1 Added support for UPDATE/INSERT/DELETE as
- CTE, CTEs added to UPDATE/INSERT/DELETE.
- :param name: name given to the common table expression. Like
- :meth:`._FromClause.alias`, the name can be left as ``None``
- in which case an anonymous symbol will be used at query
- compile time.
- :param recursive: if ``True``, will render ``WITH RECURSIVE``.
- A recursive common table expression is intended to be used in
- conjunction with UNION ALL in order to derive rows
- from those already selected.
- The following examples include two from PostgreSQL's documentation at
- http://www.postgresql.org/docs/current/static/queries-with.html,
- as well as additional examples.
- Example 1, non recursive::
- from sqlalchemy import (Table, Column, String, Integer,
- MetaData, select, func)
- metadata = MetaData()
- orders = Table('orders', metadata,
- Column('region', String),
- Column('amount', Integer),
- Column('product', String),
- Column('quantity', Integer)
- )
- regional_sales = select([
- orders.c.region,
- func.sum(orders.c.amount).label('total_sales')
- ]).group_by(orders.c.region).cte("regional_sales")
- top_regions = select([regional_sales.c.region]).\
- where(
- regional_sales.c.total_sales >
- select([
- func.sum(regional_sales.c.total_sales)/10
- ])
- ).cte("top_regions")
- statement = select([
- orders.c.region,
- orders.c.product,
- func.sum(orders.c.quantity).label("product_units"),
- func.sum(orders.c.amount).label("product_sales")
- ]).where(orders.c.region.in_(
- select([top_regions.c.region])
- )).group_by(orders.c.region, orders.c.product)
- result = conn.execute(statement).fetchall()
- Example 2, WITH RECURSIVE::
- from sqlalchemy import (Table, Column, String, Integer,
- MetaData, select, func)
- metadata = MetaData()
- parts = Table('parts', metadata,
- Column('part', String),
- Column('sub_part', String),
- Column('quantity', Integer),
- )
- included_parts = select([
- parts.c.sub_part,
- parts.c.part,
- parts.c.quantity]).\
- where(parts.c.part=='our part').\
- cte(recursive=True)
- incl_alias = included_parts.alias()
- parts_alias = parts.alias()
- included_parts = included_parts.union_all(
- select([
- parts_alias.c.sub_part,
- parts_alias.c.part,
- parts_alias.c.quantity
- ]).
- where(parts_alias.c.part==incl_alias.c.sub_part)
- )
- statement = select([
- included_parts.c.sub_part,
- func.sum(included_parts.c.quantity).
- label('total_quantity')
- ]).\
- group_by(included_parts.c.sub_part)
- result = conn.execute(statement).fetchall()
- Example 3, an upsert using UPDATE and INSERT with CTEs::
- from datetime import date
- from sqlalchemy import (MetaData, Table, Column, Integer,
- Date, select, literal, and_, exists)
- metadata = MetaData()
- visitors = Table('visitors', metadata,
- Column('product_id', Integer, primary_key=True),
- Column('date', Date, primary_key=True),
- Column('count', Integer),
- )
- # add 5 visitors for the product_id == 1
- product_id = 1
- day = date.today()
- count = 5
- update_cte = (
- visitors.update()
- .where(and_(visitors.c.product_id == product_id,
- visitors.c.date == day))
- .values(count=visitors.c.count + count)
- .returning(literal(1))
- .cte('update_cte')
- )
- upsert = visitors.insert().from_select(
- [visitors.c.product_id, visitors.c.date, visitors.c.count],
- select([literal(product_id), literal(day), literal(count)])
- .where(~exists(update_cte.select()))
- )
- connection.execute(upsert)
- .. seealso::
- :meth:`.orm.query.Query.cte` - ORM version of
- :meth:`.HasCTE.cte`.
- """
- return CTE(self, name=name, recursive=recursive)
- class FromGrouping(FromClause):
- """Represent a grouping of a FROM clause"""
- __visit_name__ = 'grouping'
- def __init__(self, element):
- self.element = element
- def _init_collections(self):
- pass
- @property
- def columns(self):
- return self.element.columns
- @property
- def primary_key(self):
- return self.element.primary_key
- @property
- def foreign_keys(self):
- return self.element.foreign_keys
- def is_derived_from(self, element):
- return self.element.is_derived_from(element)
- def alias(self, **kw):
- return FromGrouping(self.element.alias(**kw))
- @property
- def _hide_froms(self):
- return self.element._hide_froms
- def get_children(self, **kwargs):
- return self.element,
- def _copy_internals(self, clone=_clone, **kw):
- self.element = clone(self.element, **kw)
- @property
- def _from_objects(self):
- return self.element._from_objects
- def __getattr__(self, attr):
- return getattr(self.element, attr)
- def __getstate__(self):
- return {'element': self.element}
- def __setstate__(self, state):
- self.element = state['element']
- class TableClause(Immutable, FromClause):
- """Represents a minimal "table" construct.
- This is a lightweight table object that has only a name and a
- collection of columns, which are typically produced
- by the :func:`.expression.column` function::
- from sqlalchemy import table, column
- user = table("user",
- column("id"),
- column("name"),
- column("description"),
- )
- The :class:`.TableClause` construct serves as the base for
- the more commonly used :class:`~.schema.Table` object, providing
- the usual set of :class:`~.expression.FromClause` services including
- the ``.c.`` collection and statement generation methods.
- It does **not** provide all the additional schema-level services
- of :class:`~.schema.Table`, including constraints, references to other
- tables, or support for :class:`.MetaData`-level services. It's useful
- on its own as an ad-hoc construct used to generate quick SQL
- statements when a more fully fledged :class:`~.schema.Table`
- is not on hand.
- """
- __visit_name__ = 'table'
- named_with_column = True
- implicit_returning = False
- """:class:`.TableClause` doesn't support having a primary key or column
- -level defaults, so implicit returning doesn't apply."""
- _autoincrement_column = None
- """No PK or default support so no autoincrement column."""
- def __init__(self, name, *columns):
- """Produce a new :class:`.TableClause`.
- The object returned is an instance of :class:`.TableClause`, which
- represents the "syntactical" portion of the schema-level
- :class:`~.schema.Table` object.
- It may be used to construct lightweight table constructs.
- .. versionchanged:: 1.0.0 :func:`.expression.table` can now
- be imported from the plain ``sqlalchemy`` namespace like any
- other SQL element.
- :param name: Name of the table.
- :param columns: A collection of :func:`.expression.column` constructs.
- """
- super(TableClause, self).__init__()
- self.name = self.fullname = name
- self._columns = ColumnCollection()
- self.primary_key = ColumnSet()
- self.foreign_keys = set()
- for c in columns:
- self.append_column(c)
- def _init_collections(self):
- pass
- @util.memoized_property
- def description(self):
- if util.py3k:
- return self.name
- else:
- return self.name.encode('ascii', 'backslashreplace')
- def append_column(self, c):
- self._columns[c.key] = c
- c.table = self
- def get_children(self, column_collections=True, **kwargs):
- if column_collections:
- return [c for c in self.c]
- else:
- return []
- @util.dependencies("sqlalchemy.sql.dml")
- def insert(self, dml, values=None, inline=False, **kwargs):
- """Generate an :func:`.insert` construct against this
- :class:`.TableClause`.
- E.g.::
- table.insert().values(name='foo')
- See :func:`.insert` for argument and usage information.
- """
- return dml.Insert(self, values=values, inline=inline, **kwargs)
- @util.dependencies("sqlalchemy.sql.dml")
- def update(
- self, dml, whereclause=None, values=None, inline=False, **kwargs):
- """Generate an :func:`.update` construct against this
- :class:`.TableClause`.
- E.g.::
- table.update().where(table.c.id==7).values(name='foo')
- See :func:`.update` for argument and usage information.
- """
- return dml.Update(self, whereclause=whereclause,
- values=values, inline=inline, **kwargs)
- @util.dependencies("sqlalchemy.sql.dml")
- def delete(self, dml, whereclause=None, **kwargs):
- """Generate a :func:`.delete` construct against this
- :class:`.TableClause`.
- E.g.::
- table.delete().where(table.c.id==7)
- See :func:`.delete` for argument and usage information.
- """
- return dml.Delete(self, whereclause, **kwargs)
- @property
- def _from_objects(self):
- return [self]
- class ForUpdateArg(ClauseElement):
- @classmethod
- def parse_legacy_select(self, arg):
- """Parse the for_update argument of :func:`.select`.
- :param mode: Defines the lockmode to use.
- ``None`` - translates to no lockmode
- ``'update'`` - translates to ``FOR UPDATE``
- (standard SQL, supported by most dialects)
- ``'nowait'`` - translates to ``FOR UPDATE NOWAIT``
- (supported by Oracle, PostgreSQL 8.1 upwards)
- ``'read'`` - translates to ``LOCK IN SHARE MODE`` (for MySQL),
- and ``FOR SHARE`` (for PostgreSQL)
- ``'read_nowait'`` - translates to ``FOR SHARE NOWAIT``
- (supported by PostgreSQL). ``FOR SHARE`` and
- ``FOR SHARE NOWAIT`` (PostgreSQL).
- """
- if arg in (None, False):
- return None
- nowait = read = False
- if arg == 'nowait':
- nowait = True
- elif arg == 'read':
- read = True
- elif arg == 'read_nowait':
- read = nowait = True
- elif arg is not True:
- raise exc.ArgumentError("Unknown for_update argument: %r" % arg)
- return ForUpdateArg(read=read, nowait=nowait)
- @property
- def legacy_for_update_value(self):
- if self.read and not self.nowait:
- return "read"
- elif self.read and self.nowait:
- return "read_nowait"
- elif self.nowait:
- return "nowait"
- else:
- return True
- def _copy_internals(self, clone=_clone, **kw):
- if self.of is not None:
- self.of = [clone(col, **kw) for col in self.of]
- def __init__(
- self, nowait=False, read=False, of=None,
- skip_locked=False, key_share=False):
- """Represents arguments specified to :meth:`.Select.for_update`.
- .. versionadded:: 0.9.0
- """
- self.nowait = nowait
- self.read = read
- self.skip_locked = skip_locked
- self.key_share = key_share
- if of is not None:
- self.of = [_interpret_as_column_or_from(elem)
- for elem in util.to_list(of)]
- else:
- self.of = None
- class SelectBase(HasCTE, Executable, FromClause):
- """Base class for SELECT statements.
- This includes :class:`.Select`, :class:`.CompoundSelect` and
- :class:`.TextAsFrom`.
- """
- def as_scalar(self):
- """return a 'scalar' representation of this selectable, which can be
- used as a column expression.
- Typically, a select statement which has only one column in its columns
- clause is eligible to be used as a scalar expression.
- The returned object is an instance of
- :class:`ScalarSelect`.
- """
- return ScalarSelect(self)
- def label(self, name):
- """return a 'scalar' representation of this selectable, embedded as a
- subquery with a label.
- .. seealso::
- :meth:`~.SelectBase.as_scalar`.
- """
- return self.as_scalar().label(name)
- @_generative
- @util.deprecated('0.6',
- message="``autocommit()`` is deprecated. Use "
- ":meth:`.Executable.execution_options` with the "
- "'autocommit' flag.")
- def autocommit(self):
- """return a new selectable with the 'autocommit' flag set to
- True.
- """
- self._execution_options = \
- self._execution_options.union({'autocommit': True})
- def _generate(self):
- """Override the default _generate() method to also clear out
- exported collections."""
- s = self.__class__.__new__(self.__class__)
- s.__dict__ = self.__dict__.copy()
- s._reset_exported()
- return s
- @property
- def _from_objects(self):
- return [self]
- class GenerativeSelect(SelectBase):
- """Base class for SELECT statements where additional elements can be
- added.
- This serves as the base for :class:`.Select` and :class:`.CompoundSelect`
- where elements such as ORDER BY, GROUP BY can be added and column
- rendering can be controlled. Compare to :class:`.TextAsFrom`, which,
- while it subclasses :class:`.SelectBase` and is also a SELECT construct,
- represents a fixed textual string which cannot be altered at this level,
- only wrapped as a subquery.
- .. versionadded:: 0.9.0 :class:`.GenerativeSelect` was added to
- provide functionality specific to :class:`.Select` and
- :class:`.CompoundSelect` while allowing :class:`.SelectBase` to be
- used for other SELECT-like objects, e.g. :class:`.TextAsFrom`.
- """
- _order_by_clause = ClauseList()
- _group_by_clause = ClauseList()
- _limit_clause = None
- _offset_clause = None
- _for_update_arg = None
- def __init__(self,
- use_labels=False,
- for_update=False,
- limit=None,
- offset=None,
- order_by=None,
- group_by=None,
- bind=None,
- autocommit=None):
- self.use_labels = use_labels
- if for_update is not False:
- self._for_update_arg = (ForUpdateArg.
- parse_legacy_select(for_update))
- if autocommit is not None:
- util.warn_deprecated('autocommit on select() is '
- 'deprecated. Use .execution_options(a'
- 'utocommit=True)')
- self._execution_options = \
- self._execution_options.union(
- {'autocommit': autocommit})
- if limit is not None:
- self._limit_clause = _offset_or_limit_clause(limit)
- if offset is not None:
- self._offset_clause = _offset_or_limit_clause(offset)
- self._bind = bind
- if order_by is not None:
- self._order_by_clause = ClauseList(
- *util.to_list(order_by),
- _literal_as_text=_literal_and_labels_as_label_reference)
- if group_by is not None:
- self._group_by_clause = ClauseList(
- *util.to_list(group_by),
- _literal_as_text=_literal_as_label_reference)
- @property
- def for_update(self):
- """Provide legacy dialect support for the ``for_update`` attribute.
- """
- if self._for_update_arg is not None:
- return self._for_update_arg.legacy_for_update_value
- else:
- return None
- @for_update.setter
- def for_update(self, value):
- self._for_update_arg = ForUpdateArg.parse_legacy_select(value)
- @_generative
- def with_for_update(self, nowait=False, read=False, of=None,
- skip_locked=False, key_share=False):
- """Specify a ``FOR UPDATE`` clause for this :class:`.GenerativeSelect`.
- E.g.::
- stmt = select([table]).with_for_update(nowait=True)
- On a database like PostgreSQL or Oracle, the above would render a
- statement like::
- SELECT table.a, table.b FROM table FOR UPDATE NOWAIT
- on other backends, the ``nowait`` option is ignored and instead
- would produce::
- SELECT table.a, table.b FROM table FOR UPDATE
- When called with no arguments, the statement will render with
- the suffix ``FOR UPDATE``. Additional arguments can then be
- provided which allow for common database-specific
- variants.
- :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle
- and PostgreSQL dialects.
- :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL,
- ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with
- ``nowait``, will render ``FOR SHARE NOWAIT``.
- :param of: SQL expression or list of SQL expression elements
- (typically :class:`.Column` objects or a compatible expression) which
- will render into a ``FOR UPDATE OF`` clause; supported by PostgreSQL
- and Oracle. May render as a table or as a column depending on
- backend.
- :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED``
- on Oracle and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` if
- ``read=True`` is also specified.
- .. versionadded:: 1.1.0
- :param key_share: boolean, will render ``FOR NO KEY UPDATE``,
- or if combined with ``read=True`` will render ``FOR KEY SHARE``,
- on the PostgreSQL dialect.
- .. versionadded:: 1.1.0
- """
- self._for_update_arg = ForUpdateArg(nowait=nowait, read=read, of=of,
- skip_locked=skip_locked,
- key_share=key_share)
- @_generative
- def apply_labels(self):
- """return a new selectable with the 'use_labels' flag set to True.
- This will result in column expressions being generated using labels
- against their table name, such as "SELECT somecolumn AS
- tablename_somecolumn". This allows selectables which contain multiple
- FROM clauses to produce a unique set of column names regardless of
- name conflicts among the individual FROM clauses.
- """
- self.use_labels = True
- @property
- def _limit(self):
- """Get an integer value for the limit. This should only be used
- by code that cannot support a limit as a BindParameter or
- other custom clause as it will throw an exception if the limit
- isn't currently set to an integer.
- """
- return _offset_or_limit_clause_asint(self._limit_clause, "limit")
- @property
- def _simple_int_limit(self):
- """True if the LIMIT clause is a simple integer, False
- if it is not present or is a SQL expression.
- """
- return isinstance(self._limit_clause, _OffsetLimitParam)
- @property
- def _simple_int_offset(self):
- """True if the OFFSET clause is a simple integer, False
- if it is not present or is a SQL expression.
- """
- return isinstance(self._offset_clause, _OffsetLimitParam)
- @property
- def _offset(self):
- """Get an integer value for the offset. This should only be used
- by code that cannot support an offset as a BindParameter or
- other custom clause as it will throw an exception if the
- offset isn't currently set to an integer.
- """
- return _offset_or_limit_clause_asint(self._offset_clause, "offset")
- @_generative
- def limit(self, limit):
- """return a new selectable with the given LIMIT criterion
- applied.
- This is a numerical value which usually renders as a ``LIMIT``
- expression in the resulting select. Backends that don't
- support ``LIMIT`` will attempt to provide similar
- functionality.
- .. versionchanged:: 1.0.0 - :meth:`.Select.limit` can now
- accept arbitrary SQL expressions as well as integer values.
- :param limit: an integer LIMIT parameter, or a SQL expression
- that provides an integer result.
- """
- self._limit_clause = _offset_or_limit_clause(limit)
- @_generative
- def offset(self, offset):
- """return a new selectable with the given OFFSET criterion
- applied.
- This is a numeric value which usually renders as an ``OFFSET``
- expression in the resulting select. Backends that don't
- support ``OFFSET`` will attempt to provide similar
- functionality.
- .. versionchanged:: 1.0.0 - :meth:`.Select.offset` can now
- accept arbitrary SQL expressions as well as integer values.
- :param offset: an integer OFFSET parameter, or a SQL expression
- that provides an integer result.
- """
- self._offset_clause = _offset_or_limit_clause(offset)
- @_generative
- def order_by(self, *clauses):
- """return a new selectable with the given list of ORDER BY
- criterion applied.
- The criterion will be appended to any pre-existing ORDER BY
- criterion.
- """
- self.append_order_by(*clauses)
- @_generative
- def group_by(self, *clauses):
- """return a new selectable with the given list of GROUP BY
- criterion applied.
- The criterion will be appended to any pre-existing GROUP BY
- criterion.
- """
- self.append_group_by(*clauses)
- def append_order_by(self, *clauses):
- """Append the given ORDER BY criterion applied to this selectable.
- The criterion will be appended to any pre-existing ORDER BY criterion.
- This is an **in-place** mutation method; the
- :meth:`~.GenerativeSelect.order_by` method is preferred, as it
- provides standard :term:`method chaining`.
- """
- if len(clauses) == 1 and clauses[0] is None:
- self._order_by_clause = ClauseList()
- else:
- if getattr(self, '_order_by_clause', None) is not None:
- clauses = list(self._order_by_clause) + list(clauses)
- self._order_by_clause = ClauseList(
- *clauses,
- _literal_as_text=_literal_and_labels_as_label_reference)
- def append_group_by(self, *clauses):
- """Append the given GROUP BY criterion applied to this selectable.
- The criterion will be appended to any pre-existing GROUP BY criterion.
- This is an **in-place** mutation method; the
- :meth:`~.GenerativeSelect.group_by` method is preferred, as it
- provides standard :term:`method chaining`.
- """
- if len(clauses) == 1 and clauses[0] is None:
- self._group_by_clause = ClauseList()
- else:
- if getattr(self, '_group_by_clause', None) is not None:
- clauses = list(self._group_by_clause) + list(clauses)
- self._group_by_clause = ClauseList(
- *clauses, _literal_as_text=_literal_as_label_reference)
- @property
- def _label_resolve_dict(self):
- raise NotImplementedError()
- def _copy_internals(self, clone=_clone, **kw):
- if self._limit_clause is not None:
- self._limit_clause = clone(self._limit_clause, **kw)
- if self._offset_clause is not None:
- self._offset_clause = clone(self._offset_clause, **kw)
- class CompoundSelect(GenerativeSelect):
- """Forms the basis of ``UNION``, ``UNION ALL``, and other
- SELECT-based set operations.
- .. seealso::
- :func:`.union`
- :func:`.union_all`
- :func:`.intersect`
- :func:`.intersect_all`
- :func:`.except`
- :func:`.except_all`
- """
- __visit_name__ = 'compound_select'
- UNION = util.symbol('UNION')
- UNION_ALL = util.symbol('UNION ALL')
- EXCEPT = util.symbol('EXCEPT')
- EXCEPT_ALL = util.symbol('EXCEPT ALL')
- INTERSECT = util.symbol('INTERSECT')
- INTERSECT_ALL = util.symbol('INTERSECT ALL')
- _is_from_container = True
- def __init__(self, keyword, *selects, **kwargs):
- self._auto_correlate = kwargs.pop('correlate', False)
- self.keyword = keyword
- self.selects = []
- numcols = None
- # some DBs do not like ORDER BY in the inner queries of a UNION, etc.
- for n, s in enumerate(selects):
- s = _clause_element_as_expr(s)
- if not numcols:
- numcols = len(s.c._all_columns)
- elif len(s.c._all_columns) != numcols:
- raise exc.ArgumentError(
- 'All selectables passed to '
- 'CompoundSelect must have identical numbers of '
- 'columns; select #%d has %d columns, select '
- '#%d has %d' %
- (1, len(self.selects[0].c._all_columns),
- n + 1, len(s.c._all_columns))
- )
- self.selects.append(s.self_group(self))
- GenerativeSelect.__init__(self, **kwargs)
- @property
- def _label_resolve_dict(self):
- d = dict(
- (c.key, c) for c in self.c
- )
- return d, d, d
- @classmethod
- def _create_union(cls, *selects, **kwargs):
- r"""Return a ``UNION`` of multiple selectables.
- The returned object is an instance of
- :class:`.CompoundSelect`.
- A similar :func:`union()` method is available on all
- :class:`.FromClause` subclasses.
- \*selects
- a list of :class:`.Select` instances.
- \**kwargs
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.UNION, *selects, **kwargs)
- @classmethod
- def _create_union_all(cls, *selects, **kwargs):
- r"""Return a ``UNION ALL`` of multiple selectables.
- The returned object is an instance of
- :class:`.CompoundSelect`.
- A similar :func:`union_all()` method is available on all
- :class:`.FromClause` subclasses.
- \*selects
- a list of :class:`.Select` instances.
- \**kwargs
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.UNION_ALL, *selects, **kwargs)
- @classmethod
- def _create_except(cls, *selects, **kwargs):
- r"""Return an ``EXCEPT`` of multiple selectables.
- The returned object is an instance of
- :class:`.CompoundSelect`.
- \*selects
- a list of :class:`.Select` instances.
- \**kwargs
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.EXCEPT, *selects, **kwargs)
- @classmethod
- def _create_except_all(cls, *selects, **kwargs):
- r"""Return an ``EXCEPT ALL`` of multiple selectables.
- The returned object is an instance of
- :class:`.CompoundSelect`.
- \*selects
- a list of :class:`.Select` instances.
- \**kwargs
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.EXCEPT_ALL, *selects, **kwargs)
- @classmethod
- def _create_intersect(cls, *selects, **kwargs):
- r"""Return an ``INTERSECT`` of multiple selectables.
- The returned object is an instance of
- :class:`.CompoundSelect`.
- \*selects
- a list of :class:`.Select` instances.
- \**kwargs
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.INTERSECT, *selects, **kwargs)
- @classmethod
- def _create_intersect_all(cls, *selects, **kwargs):
- r"""Return an ``INTERSECT ALL`` of multiple selectables.
- The returned object is an instance of
- :class:`.CompoundSelect`.
- \*selects
- a list of :class:`.Select` instances.
- \**kwargs
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(
- CompoundSelect.INTERSECT_ALL, *selects, **kwargs)
- def _scalar_type(self):
- return self.selects[0]._scalar_type()
- def self_group(self, against=None):
- return FromGrouping(self)
- def is_derived_from(self, fromclause):
- for s in self.selects:
- if s.is_derived_from(fromclause):
- return True
- return False
- def _populate_column_collection(self):
- for cols in zip(*[s.c._all_columns for s in self.selects]):
- # this is a slightly hacky thing - the union exports a
- # column that resembles just that of the *first* selectable.
- # to get at a "composite" column, particularly foreign keys,
- # you have to dig through the proxies collection which we
- # generate below. We may want to improve upon this, such as
- # perhaps _make_proxy can accept a list of other columns
- # that are "shared" - schema.column can then copy all the
- # ForeignKeys in. this would allow the union() to have all
- # those fks too.
- proxy = cols[0]._make_proxy(
- self, name=cols[0]._label if self.use_labels else None,
- key=cols[0]._key_label if self.use_labels else None)
- # hand-construct the "_proxies" collection to include all
- # derived columns place a 'weight' annotation corresponding
- # to how low in the list of select()s the column occurs, so
- # that the corresponding_column() operation can resolve
- # conflicts
- proxy._proxies = [
- c._annotate({'weight': i + 1}) for (i, c) in enumerate(cols)]
- def _refresh_for_new_column(self, column):
- for s in self.selects:
- s._refresh_for_new_column(column)
- if not self._cols_populated:
- return None
- raise NotImplementedError("CompoundSelect constructs don't support "
- "addition of columns to underlying "
- "selectables")
- def _copy_internals(self, clone=_clone, **kw):
- super(CompoundSelect, self)._copy_internals(clone, **kw)
- self._reset_exported()
- self.selects = [clone(s, **kw) for s in self.selects]
- if hasattr(self, '_col_map'):
- del self._col_map
- for attr in (
- '_order_by_clause', '_group_by_clause', '_for_update_arg'):
- if getattr(self, attr) is not None:
- setattr(self, attr, clone(getattr(self, attr), **kw))
- def get_children(self, column_collections=True, **kwargs):
- return (column_collections and list(self.c) or []) \
- + [self._order_by_clause, self._group_by_clause] \
- + list(self.selects)
- def bind(self):
- if self._bind:
- return self._bind
- for s in self.selects:
- e = s.bind
- if e:
- return e
- else:
- return None
- def _set_bind(self, bind):
- self._bind = bind
- bind = property(bind, _set_bind)
- class Select(HasPrefixes, HasSuffixes, GenerativeSelect):
- """Represents a ``SELECT`` statement.
- """
- __visit_name__ = 'select'
- _prefixes = ()
- _suffixes = ()
- _hints = util.immutabledict()
- _statement_hints = ()
- _distinct = False
- _from_cloned = None
- _correlate = ()
- _correlate_except = None
- _memoized_property = SelectBase._memoized_property
- _is_select = True
- def __init__(self,
- columns=None,
- whereclause=None,
- from_obj=None,
- distinct=False,
- having=None,
- correlate=True,
- prefixes=None,
- suffixes=None,
- **kwargs):
- """Construct a new :class:`.Select`.
- Similar functionality is also available via the
- :meth:`.FromClause.select` method on any :class:`.FromClause`.
- All arguments which accept :class:`.ClauseElement` arguments also
- accept string arguments, which will be converted as appropriate into
- either :func:`text()` or :func:`literal_column()` constructs.
- .. seealso::
- :ref:`coretutorial_selecting` - Core Tutorial description of
- :func:`.select`.
- :param columns:
- A list of :class:`.ColumnElement` or :class:`.FromClause`
- objects which will form the columns clause of the resulting
- statement. For those objects that are instances of
- :class:`.FromClause` (typically :class:`.Table` or :class:`.Alias`
- objects), the :attr:`.FromClause.c` collection is extracted
- to form a collection of :class:`.ColumnElement` objects.
- This parameter will also accept :class:`.Text` constructs as
- given, as well as ORM-mapped classes.
- .. note::
- The :paramref:`.select.columns` parameter is not available
- in the method form of :func:`.select`, e.g.
- :meth:`.FromClause.select`.
- .. seealso::
- :meth:`.Select.column`
- :meth:`.Select.with_only_columns`
- :param whereclause:
- A :class:`.ClauseElement` expression which will be used to form the
- ``WHERE`` clause. It is typically preferable to add WHERE
- criterion to an existing :class:`.Select` using method chaining
- with :meth:`.Select.where`.
- .. seealso::
- :meth:`.Select.where`
- :param from_obj:
- A list of :class:`.ClauseElement` objects which will be added to the
- ``FROM`` clause of the resulting statement. This is equivalent
- to calling :meth:`.Select.select_from` using method chaining on
- an existing :class:`.Select` object.
- .. seealso::
- :meth:`.Select.select_from` - full description of explicit
- FROM clause specification.
- :param autocommit:
- Deprecated. Use ``.execution_options(autocommit=<True|False>)``
- to set the autocommit option.
- .. seealso::
- :meth:`.Executable.execution_options`
- :param bind=None:
- an :class:`~.Engine` or :class:`~.Connection` instance
- to which the
- resulting :class:`.Select` object will be bound. The
- :class:`.Select` object will otherwise automatically bind to
- whatever :class:`~.base.Connectable` instances can be located within
- its contained :class:`.ClauseElement` members.
- :param correlate=True:
- indicates that this :class:`.Select` object should have its
- contained :class:`.FromClause` elements "correlated" to an enclosing
- :class:`.Select` object. It is typically preferable to specify
- correlations on an existing :class:`.Select` construct using
- :meth:`.Select.correlate`.
- .. seealso::
- :meth:`.Select.correlate` - full description of correlation.
- :param distinct=False:
- when ``True``, applies a ``DISTINCT`` qualifier to the columns
- clause of the resulting statement.
- The boolean argument may also be a column expression or list
- of column expressions - this is a special calling form which
- is understood by the PostgreSQL dialect to render the
- ``DISTINCT ON (<columns>)`` syntax.
- ``distinct`` is also available on an existing :class:`.Select`
- object via the :meth:`~.Select.distinct` method.
- .. seealso::
- :meth:`.Select.distinct`
- :param for_update=False:
- when ``True``, applies ``FOR UPDATE`` to the end of the
- resulting statement.
- .. deprecated:: 0.9.0 - use
- :meth:`.Select.with_for_update` to specify the
- structure of the ``FOR UPDATE`` clause.
- ``for_update`` accepts various string values interpreted by
- specific backends, including:
- * ``"read"`` - on MySQL, translates to ``LOCK IN SHARE MODE``;
- on PostgreSQL, translates to ``FOR SHARE``.
- * ``"nowait"`` - on PostgreSQL and Oracle, translates to
- ``FOR UPDATE NOWAIT``.
- * ``"read_nowait"`` - on PostgreSQL, translates to
- ``FOR SHARE NOWAIT``.
- .. seealso::
- :meth:`.Select.with_for_update` - improved API for
- specifying the ``FOR UPDATE`` clause.
- :param group_by:
- a list of :class:`.ClauseElement` objects which will comprise the
- ``GROUP BY`` clause of the resulting select. This parameter
- is typically specified more naturally using the
- :meth:`.Select.group_by` method on an existing :class:`.Select`.
- .. seealso::
- :meth:`.Select.group_by`
- :param having:
- a :class:`.ClauseElement` that will comprise the ``HAVING`` clause
- of the resulting select when ``GROUP BY`` is used. This parameter
- is typically specified more naturally using the
- :meth:`.Select.having` method on an existing :class:`.Select`.
- .. seealso::
- :meth:`.Select.having`
- :param limit=None:
- a numerical value which usually renders as a ``LIMIT``
- expression in the resulting select. Backends that don't
- support ``LIMIT`` will attempt to provide similar
- functionality. This parameter is typically specified more naturally
- using the :meth:`.Select.limit` method on an existing
- :class:`.Select`.
- .. seealso::
- :meth:`.Select.limit`
- :param offset=None:
- a numeric value which usually renders as an ``OFFSET``
- expression in the resulting select. Backends that don't
- support ``OFFSET`` will attempt to provide similar
- functionality. This parameter is typically specified more naturally
- using the :meth:`.Select.offset` method on an existing
- :class:`.Select`.
- .. seealso::
- :meth:`.Select.offset`
- :param order_by:
- a scalar or list of :class:`.ClauseElement` objects which will
- comprise the ``ORDER BY`` clause of the resulting select.
- This parameter is typically specified more naturally using the
- :meth:`.Select.order_by` method on an existing :class:`.Select`.
- .. seealso::
- :meth:`.Select.order_by`
- :param use_labels=False:
- when ``True``, the statement will be generated using labels
- for each column in the columns clause, which qualify each
- column with its parent table's (or aliases) name so that name
- conflicts between columns in different tables don't occur.
- The format of the label is <tablename>_<column>. The "c"
- collection of the resulting :class:`.Select` object will use these
- names as well for targeting column members.
- This parameter can also be specified on an existing
- :class:`.Select` object using the :meth:`.Select.apply_labels`
- method.
- .. seealso::
- :meth:`.Select.apply_labels`
- """
- self._auto_correlate = correlate
- if distinct is not False:
- if distinct is True:
- self._distinct = True
- else:
- self._distinct = [
- _literal_as_text(e)
- for e in util.to_list(distinct)
- ]
- if from_obj is not None:
- self._from_obj = util.OrderedSet(
- _interpret_as_from(f)
- for f in util.to_list(from_obj))
- else:
- self._from_obj = util.OrderedSet()
- try:
- cols_present = bool(columns)
- except TypeError:
- raise exc.ArgumentError("columns argument to select() must "
- "be a Python list or other iterable")
- if cols_present:
- self._raw_columns = []
- for c in columns:
- c = _interpret_as_column_or_from(c)
- if isinstance(c, ScalarSelect):
- c = c.self_group(against=operators.comma_op)
- self._raw_columns.append(c)
- else:
- self._raw_columns = []
- if whereclause is not None:
- self._whereclause = _literal_as_text(
- whereclause).self_group(against=operators._asbool)
- else:
- self._whereclause = None
- if having is not None:
- self._having = _literal_as_text(
- having).self_group(against=operators._asbool)
- else:
- self._having = None
- if prefixes:
- self._setup_prefixes(prefixes)
- if suffixes:
- self._setup_suffixes(suffixes)
- GenerativeSelect.__init__(self, **kwargs)
- @property
- def _froms(self):
- # would love to cache this,
- # but there's just enough edge cases, particularly now that
- # declarative encourages construction of SQL expressions
- # without tables present, to just regen this each time.
- froms = []
- seen = set()
- translate = self._from_cloned
- for item in itertools.chain(
- _from_objects(*self._raw_columns),
- _from_objects(self._whereclause)
- if self._whereclause is not None else (),
- self._from_obj
- ):
- if item is self:
- raise exc.InvalidRequestError(
- "select() construct refers to itself as a FROM")
- if translate and item in translate:
- item = translate[item]
- if not seen.intersection(item._cloned_set):
- froms.append(item)
- seen.update(item._cloned_set)
- return froms
- def _get_display_froms(self, explicit_correlate_froms=None,
- implicit_correlate_froms=None):
- """Return the full list of 'from' clauses to be displayed.
- Takes into account a set of existing froms which may be
- rendered in the FROM clause of enclosing selects; this Select
- may want to leave those absent if it is automatically
- correlating.
- """
- froms = self._froms
- toremove = set(itertools.chain(*[
- _expand_cloned(f._hide_froms)
- for f in froms]))
- if toremove:
- # if we're maintaining clones of froms,
- # add the copies out to the toremove list. only include
- # clones that are lexical equivalents.
- if self._from_cloned:
- toremove.update(
- self._from_cloned[f] for f in
- toremove.intersection(self._from_cloned)
- if self._from_cloned[f]._is_lexical_equivalent(f)
- )
- # filter out to FROM clauses not in the list,
- # using a list to maintain ordering
- froms = [f for f in froms if f not in toremove]
- if self._correlate:
- to_correlate = self._correlate
- if to_correlate:
- froms = [
- f for f in froms if f not in
- _cloned_intersection(
- _cloned_intersection(
- froms, explicit_correlate_froms or ()),
- to_correlate
- )
- ]
- if self._correlate_except is not None:
- froms = [
- f for f in froms if f not in
- _cloned_difference(
- _cloned_intersection(
- froms, explicit_correlate_froms or ()),
- self._correlate_except
- )
- ]
- if self._auto_correlate and \
- implicit_correlate_froms and \
- len(froms) > 1:
- froms = [
- f for f in froms if f not in
- _cloned_intersection(froms, implicit_correlate_froms)
- ]
- if not len(froms):
- raise exc.InvalidRequestError("Select statement '%s"
- "' returned no FROM clauses "
- "due to auto-correlation; "
- "specify correlate(<tables>) "
- "to control correlation "
- "manually." % self)
- return froms
- def _scalar_type(self):
- elem = self._raw_columns[0]
- cols = list(elem._select_iterable)
- return cols[0].type
- @property
- def froms(self):
- """Return the displayed list of FromClause elements."""
- return self._get_display_froms()
- def with_statement_hint(self, text, dialect_name='*'):
- """add a statement hint to this :class:`.Select`.
- This method is similar to :meth:`.Select.with_hint` except that
- it does not require an individual table, and instead applies to the
- statement as a whole.
- Hints here are specific to the backend database and may include
- directives such as isolation levels, file directives, fetch directives,
- etc.
- .. versionadded:: 1.0.0
- .. seealso::
- :meth:`.Select.with_hint`
- """
- return self.with_hint(None, text, dialect_name)
- @_generative
- def with_hint(self, selectable, text, dialect_name='*'):
- r"""Add an indexing or other executional context hint for the given
- selectable to this :class:`.Select`.
- The text of the hint is rendered in the appropriate
- location for the database backend in use, relative
- to the given :class:`.Table` or :class:`.Alias` passed as the
- ``selectable`` argument. The dialect implementation
- typically uses Python string substitution syntax
- with the token ``%(name)s`` to render the name of
- the table or alias. E.g. when using Oracle, the
- following::
- select([mytable]).\
- with_hint(mytable, "index(%(name)s ix_mytable)")
- Would render SQL as::
- select /*+ index(mytable ix_mytable) */ ... from mytable
- The ``dialect_name`` option will limit the rendering of a particular
- hint to a particular backend. Such as, to add hints for both Oracle
- and Sybase simultaneously::
- select([mytable]).\
- with_hint(mytable, "index(%(name)s ix_mytable)", 'oracle').\
- with_hint(mytable, "WITH INDEX ix_mytable", 'sybase')
- .. seealso::
- :meth:`.Select.with_statement_hint`
- """
- if selectable is None:
- self._statement_hints += ((dialect_name, text), )
- else:
- self._hints = self._hints.union(
- {(selectable, dialect_name): text})
- @property
- def type(self):
- raise exc.InvalidRequestError("Select objects don't have a type. "
- "Call as_scalar() on this Select "
- "object to return a 'scalar' version "
- "of this Select.")
- @_memoized_property.method
- def locate_all_froms(self):
- """return a Set of all FromClause elements referenced by this Select.
- This set is a superset of that returned by the ``froms`` property,
- which is specifically for those FromClause elements that would
- actually be rendered.
- """
- froms = self._froms
- return froms + list(_from_objects(*froms))
- @property
- def inner_columns(self):
- """an iterator of all ColumnElement expressions which would
- be rendered into the columns clause of the resulting SELECT statement.
- """
- return _select_iterables(self._raw_columns)
- @_memoized_property
- def _label_resolve_dict(self):
- with_cols = dict(
- (c._resolve_label or c._label or c.key, c)
- for c in _select_iterables(self._raw_columns)
- if c._allow_label_resolve)
- only_froms = dict(
- (c.key, c) for c in
- _select_iterables(self.froms) if c._allow_label_resolve)
- only_cols = with_cols.copy()
- for key, value in only_froms.items():
- with_cols.setdefault(key, value)
- return with_cols, only_froms, only_cols
- def is_derived_from(self, fromclause):
- if self in fromclause._cloned_set:
- return True
- for f in self.locate_all_froms():
- if f.is_derived_from(fromclause):
- return True
- return False
- def _copy_internals(self, clone=_clone, **kw):
- super(Select, self)._copy_internals(clone, **kw)
- # Select() object has been cloned and probably adapted by the
- # given clone function. Apply the cloning function to internal
- # objects
- # 1. keep a dictionary of the froms we've cloned, and what
- # they've become. This is consulted later when we derive
- # additional froms from "whereclause" and the columns clause,
- # which may still reference the uncloned parent table.
- # as of 0.7.4 we also put the current version of _froms, which
- # gets cleared on each generation. previously we were "baking"
- # _froms into self._from_obj.
- self._from_cloned = from_cloned = dict(
- (f, clone(f, **kw)) for f in self._from_obj.union(self._froms))
- # 3. update persistent _from_obj with the cloned versions.
- self._from_obj = util.OrderedSet(from_cloned[f] for f in
- self._from_obj)
- # the _correlate collection is done separately, what can happen
- # here is the same item is _correlate as in _from_obj but the
- # _correlate version has an annotation on it - (specifically
- # RelationshipProperty.Comparator._criterion_exists() does
- # this). Also keep _correlate liberally open with its previous
- # contents, as this set is used for matching, not rendering.
- self._correlate = set(clone(f) for f in
- self._correlate).union(self._correlate)
- # 4. clone other things. The difficulty here is that Column
- # objects are not actually cloned, and refer to their original
- # .table, resulting in the wrong "from" parent after a clone
- # operation. Hence _from_cloned and _from_obj supersede what is
- # present here.
- self._raw_columns = [clone(c, **kw) for c in self._raw_columns]
- for attr in '_whereclause', '_having', '_order_by_clause', \
- '_group_by_clause', '_for_update_arg':
- if getattr(self, attr) is not None:
- setattr(self, attr, clone(getattr(self, attr), **kw))
- # erase exported column list, _froms collection,
- # etc.
- self._reset_exported()
- def get_children(self, column_collections=True, **kwargs):
- """return child elements as per the ClauseElement specification."""
- return (column_collections and list(self.columns) or []) + \
- self._raw_columns + list(self._froms) + \
- [x for x in
- (self._whereclause, self._having,
- self._order_by_clause, self._group_by_clause)
- if x is not None]
- @_generative
- def column(self, column):
- """return a new select() construct with the given column expression
- added to its columns clause.
- E.g.::
- my_select = my_select.column(table.c.new_column)
- See the documentation for :meth:`.Select.with_only_columns`
- for guidelines on adding /replacing the columns of a
- :class:`.Select` object.
- """
- self.append_column(column)
- @util.dependencies("sqlalchemy.sql.util")
- def reduce_columns(self, sqlutil, only_synonyms=True):
- """Return a new :func`.select` construct with redundantly
- named, equivalently-valued columns removed from the columns clause.
- "Redundant" here means two columns where one refers to the
- other either based on foreign key, or via a simple equality
- comparison in the WHERE clause of the statement. The primary purpose
- of this method is to automatically construct a select statement
- with all uniquely-named columns, without the need to use
- table-qualified labels as :meth:`.apply_labels` does.
- When columns are omitted based on foreign key, the referred-to
- column is the one that's kept. When columns are omitted based on
- WHERE eqivalence, the first column in the columns clause is the
- one that's kept.
- :param only_synonyms: when True, limit the removal of columns
- to those which have the same name as the equivalent. Otherwise,
- all columns that are equivalent to another are removed.
- .. versionadded:: 0.8
- """
- return self.with_only_columns(
- sqlutil.reduce_columns(
- self.inner_columns,
- only_synonyms=only_synonyms,
- *(self._whereclause, ) + tuple(self._from_obj)
- )
- )
- @_generative
- def with_only_columns(self, columns):
- r"""Return a new :func:`.select` construct with its columns
- clause replaced with the given columns.
- This method is exactly equivalent to as if the original
- :func:`.select` had been called with the given columns
- clause. I.e. a statement::
- s = select([table1.c.a, table1.c.b])
- s = s.with_only_columns([table1.c.b])
- should be exactly equivalent to::
- s = select([table1.c.b])
- This means that FROM clauses which are only derived
- from the column list will be discarded if the new column
- list no longer contains that FROM::
- >>> table1 = table('t1', column('a'), column('b'))
- >>> table2 = table('t2', column('a'), column('b'))
- >>> s1 = select([table1.c.a, table2.c.b])
- >>> print s1
- SELECT t1.a, t2.b FROM t1, t2
- >>> s2 = s1.with_only_columns([table2.c.b])
- >>> print s2
- SELECT t2.b FROM t1
- The preferred way to maintain a specific FROM clause
- in the construct, assuming it won't be represented anywhere
- else (i.e. not in the WHERE clause, etc.) is to set it using
- :meth:`.Select.select_from`::
- >>> s1 = select([table1.c.a, table2.c.b]).\
- ... select_from(table1.join(table2,
- ... table1.c.a==table2.c.a))
- >>> s2 = s1.with_only_columns([table2.c.b])
- >>> print s2
- SELECT t2.b FROM t1 JOIN t2 ON t1.a=t2.a
- Care should also be taken to use the correct
- set of column objects passed to :meth:`.Select.with_only_columns`.
- Since the method is essentially equivalent to calling the
- :func:`.select` construct in the first place with the given
- columns, the columns passed to :meth:`.Select.with_only_columns`
- should usually be a subset of those which were passed
- to the :func:`.select` construct, not those which are available
- from the ``.c`` collection of that :func:`.select`. That
- is::
- s = select([table1.c.a, table1.c.b]).select_from(table1)
- s = s.with_only_columns([table1.c.b])
- and **not**::
- # usually incorrect
- s = s.with_only_columns([s.c.b])
- The latter would produce the SQL::
- SELECT b
- FROM (SELECT t1.a AS a, t1.b AS b
- FROM t1), t1
- Since the :func:`.select` construct is essentially being
- asked to select both from ``table1`` as well as itself.
- """
- self._reset_exported()
- rc = []
- for c in columns:
- c = _interpret_as_column_or_from(c)
- if isinstance(c, ScalarSelect):
- c = c.self_group(against=operators.comma_op)
- rc.append(c)
- self._raw_columns = rc
- @_generative
- def where(self, whereclause):
- """return a new select() construct with the given expression added to
- its WHERE clause, joined to the existing clause via AND, if any.
- """
- self.append_whereclause(whereclause)
- @_generative
- def having(self, having):
- """return a new select() construct with the given expression added to
- its HAVING clause, joined to the existing clause via AND, if any.
- """
- self.append_having(having)
- @_generative
- def distinct(self, *expr):
- r"""Return a new select() construct which will apply DISTINCT to its
- columns clause.
- :param \*expr: optional column expressions. When present,
- the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>>)``
- construct.
- """
- if expr:
- expr = [_literal_as_label_reference(e) for e in expr]
- if isinstance(self._distinct, list):
- self._distinct = self._distinct + expr
- else:
- self._distinct = expr
- else:
- self._distinct = True
- @_generative
- def select_from(self, fromclause):
- r"""return a new :func:`.select` construct with the
- given FROM expression
- merged into its list of FROM objects.
- E.g.::
- table1 = table('t1', column('a'))
- table2 = table('t2', column('b'))
- s = select([table1.c.a]).\
- select_from(
- table1.join(table2, table1.c.a==table2.c.b)
- )
- The "from" list is a unique set on the identity of each element,
- so adding an already present :class:`.Table` or other selectable
- will have no effect. Passing a :class:`.Join` that refers
- to an already present :class:`.Table` or other selectable will have
- the effect of concealing the presence of that selectable as
- an individual element in the rendered FROM list, instead
- rendering it into a JOIN clause.
- While the typical purpose of :meth:`.Select.select_from` is to
- replace the default, derived FROM clause with a join, it can
- also be called with individual table elements, multiple times
- if desired, in the case that the FROM clause cannot be fully
- derived from the columns clause::
- select([func.count('*')]).select_from(table1)
- """
- self.append_from(fromclause)
- @_generative
- def correlate(self, *fromclauses):
- r"""return a new :class:`.Select` which will correlate the given FROM
- clauses to that of an enclosing :class:`.Select`.
- Calling this method turns off the :class:`.Select` object's
- default behavior of "auto-correlation". Normally, FROM elements
- which appear in a :class:`.Select` that encloses this one via
- its :term:`WHERE clause`, ORDER BY, HAVING or
- :term:`columns clause` will be omitted from this :class:`.Select`
- object's :term:`FROM clause`.
- Setting an explicit correlation collection using the
- :meth:`.Select.correlate` method provides a fixed list of FROM objects
- that can potentially take place in this process.
- When :meth:`.Select.correlate` is used to apply specific FROM clauses
- for correlation, the FROM elements become candidates for
- correlation regardless of how deeply nested this :class:`.Select`
- object is, relative to an enclosing :class:`.Select` which refers to
- the same FROM object. This is in contrast to the behavior of
- "auto-correlation" which only correlates to an immediate enclosing
- :class:`.Select`. Multi-level correlation ensures that the link
- between enclosed and enclosing :class:`.Select` is always via
- at least one WHERE/ORDER BY/HAVING/columns clause in order for
- correlation to take place.
- If ``None`` is passed, the :class:`.Select` object will correlate
- none of its FROM entries, and all will render unconditionally
- in the local FROM clause.
- :param \*fromclauses: a list of one or more :class:`.FromClause`
- constructs, or other compatible constructs (i.e. ORM-mapped
- classes) to become part of the correlate collection.
- .. versionchanged:: 0.8.0 ORM-mapped classes are accepted by
- :meth:`.Select.correlate`.
- .. versionchanged:: 0.8.0 The :meth:`.Select.correlate` method no
- longer unconditionally removes entries from the FROM clause;
- instead, the candidate FROM entries must also be matched by a FROM
- entry located in an enclosing :class:`.Select`, which ultimately
- encloses this one as present in the WHERE clause, ORDER BY clause,
- HAVING clause, or columns clause of an enclosing :meth:`.Select`.
- .. versionchanged:: 0.8.2 explicit correlation takes place
- via any level of nesting of :class:`.Select` objects; in previous
- 0.8 versions, correlation would only occur relative to the
- immediate enclosing :class:`.Select` construct.
- .. seealso::
- :meth:`.Select.correlate_except`
- :ref:`correlated_subqueries`
- """
- self._auto_correlate = False
- if fromclauses and fromclauses[0] is None:
- self._correlate = ()
- else:
- self._correlate = set(self._correlate).union(
- _interpret_as_from(f) for f in fromclauses)
- @_generative
- def correlate_except(self, *fromclauses):
- r"""return a new :class:`.Select` which will omit the given FROM
- clauses from the auto-correlation process.
- Calling :meth:`.Select.correlate_except` turns off the
- :class:`.Select` object's default behavior of
- "auto-correlation" for the given FROM elements. An element
- specified here will unconditionally appear in the FROM list, while
- all other FROM elements remain subject to normal auto-correlation
- behaviors.
- .. versionchanged:: 0.8.2 The :meth:`.Select.correlate_except`
- method was improved to fully prevent FROM clauses specified here
- from being omitted from the immediate FROM clause of this
- :class:`.Select`.
- If ``None`` is passed, the :class:`.Select` object will correlate
- all of its FROM entries.
- .. versionchanged:: 0.8.2 calling ``correlate_except(None)`` will
- correctly auto-correlate all FROM clauses.
- :param \*fromclauses: a list of one or more :class:`.FromClause`
- constructs, or other compatible constructs (i.e. ORM-mapped
- classes) to become part of the correlate-exception collection.
- .. seealso::
- :meth:`.Select.correlate`
- :ref:`correlated_subqueries`
- """
- self._auto_correlate = False
- if fromclauses and fromclauses[0] is None:
- self._correlate_except = ()
- else:
- self._correlate_except = set(self._correlate_except or ()).union(
- _interpret_as_from(f) for f in fromclauses)
- def append_correlation(self, fromclause):
- """append the given correlation expression to this select()
- construct.
- This is an **in-place** mutation method; the
- :meth:`~.Select.correlate` method is preferred, as it provides
- standard :term:`method chaining`.
- """
- self._auto_correlate = False
- self._correlate = set(self._correlate).union(
- _interpret_as_from(f) for f in fromclause)
- def append_column(self, column):
- """append the given column expression to the columns clause of this
- select() construct.
- E.g.::
- my_select.append_column(some_table.c.new_column)
- This is an **in-place** mutation method; the
- :meth:`~.Select.column` method is preferred, as it provides standard
- :term:`method chaining`.
- See the documentation for :meth:`.Select.with_only_columns`
- for guidelines on adding /replacing the columns of a
- :class:`.Select` object.
- """
- self._reset_exported()
- column = _interpret_as_column_or_from(column)
- if isinstance(column, ScalarSelect):
- column = column.self_group(against=operators.comma_op)
- self._raw_columns = self._raw_columns + [column]
- def append_prefix(self, clause):
- """append the given columns clause prefix expression to this select()
- construct.
- This is an **in-place** mutation method; the
- :meth:`~.Select.prefix_with` method is preferred, as it provides
- standard :term:`method chaining`.
- """
- clause = _literal_as_text(clause)
- self._prefixes = self._prefixes + (clause,)
- def append_whereclause(self, whereclause):
- """append the given expression to this select() construct's WHERE
- criterion.
- The expression will be joined to existing WHERE criterion via AND.
- This is an **in-place** mutation method; the
- :meth:`~.Select.where` method is preferred, as it provides standard
- :term:`method chaining`.
- """
- self._reset_exported()
- self._whereclause = and_(
- True_._ifnone(self._whereclause), whereclause)
- def append_having(self, having):
- """append the given expression to this select() construct's HAVING
- criterion.
- The expression will be joined to existing HAVING criterion via AND.
- This is an **in-place** mutation method; the
- :meth:`~.Select.having` method is preferred, as it provides standard
- :term:`method chaining`.
- """
- self._reset_exported()
- self._having = and_(True_._ifnone(self._having), having)
- def append_from(self, fromclause):
- """append the given FromClause expression to this select() construct's
- FROM clause.
- This is an **in-place** mutation method; the
- :meth:`~.Select.select_from` method is preferred, as it provides
- standard :term:`method chaining`.
- """
- self._reset_exported()
- fromclause = _interpret_as_from(fromclause)
- self._from_obj = self._from_obj.union([fromclause])
- @_memoized_property
- def _columns_plus_names(self):
- if self.use_labels:
- names = set()
- def name_for_col(c):
- if c._label is None or not c._render_label_in_columns_clause:
- return (None, c)
- name = c._label
- if name in names:
- name = c.anon_label
- else:
- names.add(name)
- return name, c
- return [
- name_for_col(c)
- for c in util.unique_list(
- _select_iterables(self._raw_columns))
- ]
- else:
- return [
- (None, c)
- for c in util.unique_list(
- _select_iterables(self._raw_columns))
- ]
- def _populate_column_collection(self):
- for name, c in self._columns_plus_names:
- if not hasattr(c, '_make_proxy'):
- continue
- if name is None:
- key = None
- elif self.use_labels:
- key = c._key_label
- if key is not None and key in self.c:
- key = c.anon_label
- else:
- key = None
- c._make_proxy(self, key=key,
- name=name,
- name_is_truncatable=True)
- def _refresh_for_new_column(self, column):
- for fromclause in self._froms:
- col = fromclause._refresh_for_new_column(column)
- if col is not None:
- if col in self.inner_columns and self._cols_populated:
- our_label = col._key_label if self.use_labels else col.key
- if our_label not in self.c:
- return col._make_proxy(
- self,
- name=col._label if self.use_labels else None,
- key=col._key_label if self.use_labels else None,
- name_is_truncatable=True)
- return None
- return None
- def _needs_parens_for_grouping(self):
- return (
- self._limit_clause is not None or
- self._offset_clause is not None or
- bool(self._order_by_clause.clauses)
- )
- def self_group(self, against=None):
- """return a 'grouping' construct as per the ClauseElement
- specification.
- This produces an element that can be embedded in an expression. Note
- that this method is called automatically as needed when constructing
- expressions and should not require explicit use.
- """
- if isinstance(against, CompoundSelect) and \
- not self._needs_parens_for_grouping():
- return self
- return FromGrouping(self)
- def union(self, other, **kwargs):
- """return a SQL UNION of this select() construct against the given
- selectable."""
- return CompoundSelect._create_union(self, other, **kwargs)
- def union_all(self, other, **kwargs):
- """return a SQL UNION ALL of this select() construct against the given
- selectable.
- """
- return CompoundSelect._create_union_all(self, other, **kwargs)
- def except_(self, other, **kwargs):
- """return a SQL EXCEPT of this select() construct against the given
- selectable."""
- return CompoundSelect._create_except(self, other, **kwargs)
- def except_all(self, other, **kwargs):
- """return a SQL EXCEPT ALL of this select() construct against the
- given selectable.
- """
- return CompoundSelect._create_except_all(self, other, **kwargs)
- def intersect(self, other, **kwargs):
- """return a SQL INTERSECT of this select() construct against the given
- selectable.
- """
- return CompoundSelect._create_intersect(self, other, **kwargs)
- def intersect_all(self, other, **kwargs):
- """return a SQL INTERSECT ALL of this select() construct against the
- given selectable.
- """
- return CompoundSelect._create_intersect_all(self, other, **kwargs)
- def bind(self):
- if self._bind:
- return self._bind
- froms = self._froms
- if not froms:
- for c in self._raw_columns:
- e = c.bind
- if e:
- self._bind = e
- return e
- else:
- e = list(froms)[0].bind
- if e:
- self._bind = e
- return e
- return None
- def _set_bind(self, bind):
- self._bind = bind
- bind = property(bind, _set_bind)
- class ScalarSelect(Generative, Grouping):
- _from_objects = []
- _is_from_container = True
- def __init__(self, element):
- self.element = element
- self.type = element._scalar_type()
- @property
- def columns(self):
- raise exc.InvalidRequestError('Scalar Select expression has no '
- 'columns; use this object directly '
- 'within a column-level expression.')
- c = columns
- @_generative
- def where(self, crit):
- """Apply a WHERE clause to the SELECT statement referred to
- by this :class:`.ScalarSelect`.
- """
- self.element = self.element.where(crit)
- def self_group(self, **kwargs):
- return self
- class Exists(UnaryExpression):
- """Represent an ``EXISTS`` clause.
- """
- __visit_name__ = UnaryExpression.__visit_name__
- _from_objects = []
- def __init__(self, *args, **kwargs):
- """Construct a new :class:`.Exists` against an existing
- :class:`.Select` object.
- Calling styles are of the following forms::
- # use on an existing select()
- s = select([table.c.col1]).where(table.c.col2==5)
- s = exists(s)
- # construct a select() at once
- exists(['*'], **select_arguments).where(criterion)
- # columns argument is optional, generates "EXISTS (SELECT *)"
- # by default.
- exists().where(table.c.col2==5)
- """
- if args and isinstance(args[0], (SelectBase, ScalarSelect)):
- s = args[0]
- else:
- if not args:
- args = ([literal_column('*')],)
- s = Select(*args, **kwargs).as_scalar().self_group()
- UnaryExpression.__init__(self, s, operator=operators.exists,
- type_=type_api.BOOLEANTYPE,
- wraps_column_expression=True)
- def select(self, whereclause=None, **params):
- return Select([self], whereclause, **params)
- def correlate(self, *fromclause):
- e = self._clone()
- e.element = self.element.correlate(*fromclause).self_group()
- return e
- def correlate_except(self, *fromclause):
- e = self._clone()
- e.element = self.element.correlate_except(*fromclause).self_group()
- return e
- def select_from(self, clause):
- """return a new :class:`.Exists` construct, applying the given
- expression to the :meth:`.Select.select_from` method of the select
- statement contained.
- """
- e = self._clone()
- e.element = self.element.select_from(clause).self_group()
- return e
- def where(self, clause):
- """return a new exists() construct with the given expression added to
- its WHERE clause, joined to the existing clause via AND, if any.
- """
- e = self._clone()
- e.element = self.element.where(clause).self_group()
- return e
- class TextAsFrom(SelectBase):
- """Wrap a :class:`.TextClause` construct within a :class:`.SelectBase`
- interface.
- This allows the :class:`.TextClause` object to gain a ``.c`` collection
- and other FROM-like capabilities such as :meth:`.FromClause.alias`,
- :meth:`.SelectBase.cte`, etc.
- The :class:`.TextAsFrom` construct is produced via the
- :meth:`.TextClause.columns` method - see that method for details.
- .. versionadded:: 0.9.0
- .. seealso::
- :func:`.text`
- :meth:`.TextClause.columns`
- """
- __visit_name__ = "text_as_from"
- _textual = True
- def __init__(self, text, columns, positional=False):
- self.element = text
- self.column_args = columns
- self.positional = positional
- @property
- def _bind(self):
- return self.element._bind
- @_generative
- def bindparams(self, *binds, **bind_as_values):
- self.element = self.element.bindparams(*binds, **bind_as_values)
- def _populate_column_collection(self):
- for c in self.column_args:
- c._make_proxy(self)
- def _copy_internals(self, clone=_clone, **kw):
- self._reset_exported()
- self.element = clone(self.element, **kw)
- def _scalar_type(self):
- return self.column_args[0].type
- class AnnotatedFromClause(Annotated):
- def __init__(self, element, values):
- # force FromClause to generate their internal
- # collections into __dict__
- element.c
- Annotated.__init__(self, element, values)
|