1# sql/selectable.py
2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7
8"""The :class:`_expression.FromClause` class of SQL expression elements,
9representing
10SQL tables and derived rowsets.
11
12"""
13
14from __future__ import annotations
15
16import collections
17from enum import Enum
18import itertools
19from typing import AbstractSet
20from typing import Any as TODO_Any
21from typing import Any
22from typing import Callable
23from typing import cast
24from typing import Dict
25from typing import Generic
26from typing import Iterable
27from typing import Iterator
28from typing import List
29from typing import NamedTuple
30from typing import NoReturn
31from typing import Optional
32from typing import overload
33from typing import Sequence
34from typing import Set
35from typing import Tuple
36from typing import Type
37from typing import TYPE_CHECKING
38from typing import TypeVar
39from typing import Union
40
41from . import cache_key
42from . import coercions
43from . import operators
44from . import roles
45from . import traversals
46from . import type_api
47from . import visitors
48from ._typing import _ColumnsClauseArgument
49from ._typing import _no_kw
50from ._typing import _T
51from ._typing import _TP
52from ._typing import is_column_element
53from ._typing import is_select_statement
54from ._typing import is_subquery
55from ._typing import is_table
56from ._typing import is_text_clause
57from .annotation import Annotated
58from .annotation import SupportsCloneAnnotations
59from .base import _clone
60from .base import _cloned_difference
61from .base import _cloned_intersection
62from .base import _entity_namespace_key
63from .base import _EntityNamespace
64from .base import _expand_cloned
65from .base import _from_objects
66from .base import _generative
67from .base import _never_select_column
68from .base import _NoArg
69from .base import _select_iterables
70from .base import CacheableOptions
71from .base import ColumnCollection
72from .base import ColumnSet
73from .base import CompileState
74from .base import DedupeColumnCollection
75from .base import DialectKWArgs
76from .base import Executable
77from .base import Generative
78from .base import HasCompileState
79from .base import HasMemoized
80from .base import Immutable
81from .coercions import _document_text_coercion
82from .elements import _anonymous_label
83from .elements import BindParameter
84from .elements import BooleanClauseList
85from .elements import ClauseElement
86from .elements import ClauseList
87from .elements import ColumnClause
88from .elements import ColumnElement
89from .elements import DQLDMLClauseElement
90from .elements import GroupedElement
91from .elements import literal_column
92from .elements import TableValuedColumn
93from .elements import UnaryExpression
94from .operators import OperatorType
95from .sqltypes import NULLTYPE
96from .visitors import _TraverseInternalsType
97from .visitors import InternalTraversal
98from .visitors import prefix_anon_map
99from .. import exc
100from .. import util
101from ..util import HasMemoized_ro_memoized_attribute
102from ..util.typing import Literal
103from ..util.typing import Protocol
104from ..util.typing import Self
105
106
107and_ = BooleanClauseList.and_
108
109
110if TYPE_CHECKING:
111 from ._typing import _ColumnExpressionArgument
112 from ._typing import _ColumnExpressionOrStrLabelArgument
113 from ._typing import _FromClauseArgument
114 from ._typing import _JoinTargetArgument
115 from ._typing import _LimitOffsetType
116 from ._typing import _MAYBE_ENTITY
117 from ._typing import _NOT_ENTITY
118 from ._typing import _OnClauseArgument
119 from ._typing import _SelectStatementForCompoundArgument
120 from ._typing import _T0
121 from ._typing import _T1
122 from ._typing import _T2
123 from ._typing import _T3
124 from ._typing import _T4
125 from ._typing import _T5
126 from ._typing import _T6
127 from ._typing import _T7
128 from ._typing import _TextCoercedExpressionArgument
129 from ._typing import _TypedColumnClauseArgument as _TCCA
130 from ._typing import _TypeEngineArgument
131 from .base import _AmbiguousTableNameMap
132 from .base import ExecutableOption
133 from .base import ReadOnlyColumnCollection
134 from .cache_key import _CacheKeyTraversalType
135 from .compiler import SQLCompiler
136 from .dml import Delete
137 from .dml import Update
138 from .elements import BinaryExpression
139 from .elements import KeyedColumnElement
140 from .elements import Label
141 from .elements import NamedColumn
142 from .elements import TextClause
143 from .functions import Function
144 from .schema import ForeignKey
145 from .schema import ForeignKeyConstraint
146 from .sqltypes import TableValueType
147 from .type_api import TypeEngine
148 from .visitors import _CloneCallableType
149
150
151_ColumnsClauseElement = Union["FromClause", ColumnElement[Any], "TextClause"]
152_LabelConventionCallable = Callable[
153 [Union["ColumnElement[Any]", "TextClause"]], Optional[str]
154]
155
156
157class _JoinTargetProtocol(Protocol):
158 @util.ro_non_memoized_property
159 def _from_objects(self) -> List[FromClause]: ...
160
161 @util.ro_non_memoized_property
162 def entity_namespace(self) -> _EntityNamespace: ...
163
164
165_JoinTargetElement = Union["FromClause", _JoinTargetProtocol]
166_OnClauseElement = Union["ColumnElement[bool]", _JoinTargetProtocol]
167
168_ForUpdateOfArgument = Union[
169 # single column, Table, ORM Entity
170 Union[
171 "_ColumnExpressionArgument[Any]",
172 "_FromClauseArgument",
173 ],
174 # or sequence of single column elements
175 Sequence["_ColumnExpressionArgument[Any]"],
176]
177
178
179_SetupJoinsElement = Tuple[
180 _JoinTargetElement,
181 Optional[_OnClauseElement],
182 Optional["FromClause"],
183 Dict[str, Any],
184]
185
186
187_SelectIterable = Iterable[Union["ColumnElement[Any]", "TextClause"]]
188
189
190class _OffsetLimitParam(BindParameter[int]):
191 inherit_cache = True
192
193 @property
194 def _limit_offset_value(self) -> Optional[int]:
195 return self.effective_value
196
197
198class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement):
199 """The base-most class for Core constructs that have some concept of
200 columns that can represent rows.
201
202 While the SELECT statement and TABLE are the primary things we think
203 of in this category, DML like INSERT, UPDATE and DELETE can also specify
204 RETURNING which means they can be used in CTEs and other forms, and
205 PostgreSQL has functions that return rows also.
206
207 .. versionadded:: 1.4
208
209 """
210
211 _is_returns_rows = True
212
213 # sub-elements of returns_rows
214 _is_from_clause = False
215 _is_select_base = False
216 _is_select_statement = False
217 _is_lateral = False
218
219 @property
220 def selectable(self) -> ReturnsRows:
221 return self
222
223 @util.ro_non_memoized_property
224 def _all_selected_columns(self) -> _SelectIterable:
225 """A sequence of column expression objects that represents the
226 "selected" columns of this :class:`_expression.ReturnsRows`.
227
228 This is typically equivalent to .exported_columns except it is
229 delivered in the form of a straight sequence and not keyed
230 :class:`_expression.ColumnCollection`.
231
232 """
233 raise NotImplementedError()
234
235 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
236 """Return ``True`` if this :class:`.ReturnsRows` is
237 'derived' from the given :class:`.FromClause`.
238
239 An example would be an Alias of a Table is derived from that Table.
240
241 """
242 raise NotImplementedError()
243
244 def _generate_fromclause_column_proxies(
245 self,
246 fromclause: FromClause,
247 columns: ColumnCollection[str, KeyedColumnElement[Any]],
248 primary_key: ColumnSet,
249 foreign_keys: Set[KeyedColumnElement[Any]],
250 ) -> None:
251 """Populate columns into an :class:`.AliasedReturnsRows` object."""
252
253 raise NotImplementedError()
254
255 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
256 """reset internal collections for an incoming column being added."""
257 raise NotImplementedError()
258
259 @property
260 def exported_columns(self) -> ReadOnlyColumnCollection[Any, Any]:
261 """A :class:`_expression.ColumnCollection`
262 that represents the "exported"
263 columns of this :class:`_expression.ReturnsRows`.
264
265 The "exported" columns represent the collection of
266 :class:`_expression.ColumnElement`
267 expressions that are rendered by this SQL
268 construct. There are primary varieties which are the
269 "FROM clause columns" of a FROM clause, such as a table, join,
270 or subquery, the "SELECTed columns", which are the columns in
271 the "columns clause" of a SELECT statement, and the RETURNING
272 columns in a DML statement..
273
274 .. versionadded:: 1.4
275
276 .. seealso::
277
278 :attr:`_expression.FromClause.exported_columns`
279
280 :attr:`_expression.SelectBase.exported_columns`
281 """
282
283 raise NotImplementedError()
284
285
286class ExecutableReturnsRows(Executable, ReturnsRows):
287 """base for executable statements that return rows."""
288
289
290class TypedReturnsRows(ExecutableReturnsRows, Generic[_TP]):
291 """base for a typed executable statements that return rows."""
292
293
294class Selectable(ReturnsRows):
295 """Mark a class as being selectable."""
296
297 __visit_name__ = "selectable"
298
299 is_selectable = True
300
301 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
302 raise NotImplementedError()
303
304 def lateral(self, name: Optional[str] = None) -> LateralFromClause:
305 """Return a LATERAL alias of this :class:`_expression.Selectable`.
306
307 The return value is the :class:`_expression.Lateral` construct also
308 provided by the top-level :func:`_expression.lateral` function.
309
310 .. seealso::
311
312 :ref:`tutorial_lateral_correlation` - overview of usage.
313
314 """
315 return Lateral._construct(self, name=name)
316
317 @util.deprecated(
318 "1.4",
319 message="The :meth:`.Selectable.replace_selectable` method is "
320 "deprecated, and will be removed in a future release. Similar "
321 "functionality is available via the sqlalchemy.sql.visitors module.",
322 )
323 @util.preload_module("sqlalchemy.sql.util")
324 def replace_selectable(self, old: FromClause, alias: Alias) -> Self:
325 """Replace all occurrences of :class:`_expression.FromClause`
326 'old' with the given :class:`_expression.Alias`
327 object, returning a copy of this :class:`_expression.FromClause`.
328
329 """
330 return util.preloaded.sql_util.ClauseAdapter(alias).traverse(self)
331
332 def corresponding_column(
333 self, column: KeyedColumnElement[Any], require_embedded: bool = False
334 ) -> Optional[KeyedColumnElement[Any]]:
335 """Given a :class:`_expression.ColumnElement`, return the exported
336 :class:`_expression.ColumnElement` object from the
337 :attr:`_expression.Selectable.exported_columns`
338 collection of this :class:`_expression.Selectable`
339 which corresponds to that
340 original :class:`_expression.ColumnElement` via a common ancestor
341 column.
342
343 :param column: the target :class:`_expression.ColumnElement`
344 to be matched.
345
346 :param require_embedded: only return corresponding columns for
347 the given :class:`_expression.ColumnElement`, if the given
348 :class:`_expression.ColumnElement`
349 is actually present within a sub-element
350 of this :class:`_expression.Selectable`.
351 Normally the column will match if
352 it merely shares a common ancestor with one of the exported
353 columns of this :class:`_expression.Selectable`.
354
355 .. seealso::
356
357 :attr:`_expression.Selectable.exported_columns` - the
358 :class:`_expression.ColumnCollection`
359 that is used for the operation.
360
361 :meth:`_expression.ColumnCollection.corresponding_column`
362 - implementation
363 method.
364
365 """
366
367 return self.exported_columns.corresponding_column(
368 column, require_embedded
369 )
370
371
372class HasPrefixes:
373 _prefixes: Tuple[Tuple[DQLDMLClauseElement, str], ...] = ()
374
375 _has_prefixes_traverse_internals: _TraverseInternalsType = [
376 ("_prefixes", InternalTraversal.dp_prefix_sequence)
377 ]
378
379 @_generative
380 @_document_text_coercion(
381 "prefixes",
382 ":meth:`_expression.HasPrefixes.prefix_with`",
383 ":paramref:`.HasPrefixes.prefix_with.*prefixes`",
384 )
385 def prefix_with(
386 self,
387 *prefixes: _TextCoercedExpressionArgument[Any],
388 dialect: str = "*",
389 ) -> Self:
390 r"""Add one or more expressions following the statement keyword, i.e.
391 SELECT, INSERT, UPDATE, or DELETE. Generative.
392
393 This is used to support backend-specific prefix keywords such as those
394 provided by MySQL.
395
396 E.g.::
397
398 stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")
399
400 # MySQL 5.7 optimizer hints
401 stmt = select(table).prefix_with("/*+ BKA(t1) */", dialect="mysql")
402
403 Multiple prefixes can be specified by multiple calls
404 to :meth:`_expression.HasPrefixes.prefix_with`.
405
406 :param \*prefixes: textual or :class:`_expression.ClauseElement`
407 construct which
408 will be rendered following the INSERT, UPDATE, or DELETE
409 keyword.
410 :param dialect: optional string dialect name which will
411 limit rendering of this prefix to only that dialect.
412
413 """
414 self._prefixes = self._prefixes + tuple(
415 [
416 (coercions.expect(roles.StatementOptionRole, p), dialect)
417 for p in prefixes
418 ]
419 )
420 return self
421
422
423class HasSuffixes:
424 _suffixes: Tuple[Tuple[DQLDMLClauseElement, str], ...] = ()
425
426 _has_suffixes_traverse_internals: _TraverseInternalsType = [
427 ("_suffixes", InternalTraversal.dp_prefix_sequence)
428 ]
429
430 @_generative
431 @_document_text_coercion(
432 "suffixes",
433 ":meth:`_expression.HasSuffixes.suffix_with`",
434 ":paramref:`.HasSuffixes.suffix_with.*suffixes`",
435 )
436 def suffix_with(
437 self,
438 *suffixes: _TextCoercedExpressionArgument[Any],
439 dialect: str = "*",
440 ) -> Self:
441 r"""Add one or more expressions following the statement as a whole.
442
443 This is used to support backend-specific suffix keywords on
444 certain constructs.
445
446 E.g.::
447
448 stmt = (
449 select(col1, col2)
450 .cte()
451 .suffix_with(
452 "cycle empno set y_cycle to 1 default 0", dialect="oracle"
453 )
454 )
455
456 Multiple suffixes can be specified by multiple calls
457 to :meth:`_expression.HasSuffixes.suffix_with`.
458
459 :param \*suffixes: textual or :class:`_expression.ClauseElement`
460 construct which
461 will be rendered following the target clause.
462 :param dialect: Optional string dialect name which will
463 limit rendering of this suffix to only that dialect.
464
465 """
466 self._suffixes = self._suffixes + tuple(
467 [
468 (coercions.expect(roles.StatementOptionRole, p), dialect)
469 for p in suffixes
470 ]
471 )
472 return self
473
474
475class HasHints:
476 _hints: util.immutabledict[Tuple[FromClause, str], str] = (
477 util.immutabledict()
478 )
479 _statement_hints: Tuple[Tuple[str, str], ...] = ()
480
481 _has_hints_traverse_internals: _TraverseInternalsType = [
482 ("_statement_hints", InternalTraversal.dp_statement_hint_list),
483 ("_hints", InternalTraversal.dp_table_hint_list),
484 ]
485
486 @_generative
487 def with_statement_hint(self, text: str, dialect_name: str = "*") -> Self:
488 """Add a statement hint to this :class:`_expression.Select` or
489 other selectable object.
490
491 .. tip::
492
493 :meth:`_expression.Select.with_statement_hint` generally adds hints
494 **at the trailing end** of a SELECT statement. To place
495 dialect-specific hints such as optimizer hints at the **front** of
496 the SELECT statement after the SELECT keyword, use the
497 :meth:`_expression.Select.prefix_with` method for an open-ended
498 space, or for table-specific hints the
499 :meth:`_expression.Select.with_hint` may be used, which places
500 hints in a dialect-specific location.
501
502 This method is similar to :meth:`_expression.Select.with_hint` except
503 that it does not require an individual table, and instead applies to
504 the statement as a whole.
505
506 Hints here are specific to the backend database and may include
507 directives such as isolation levels, file directives, fetch directives,
508 etc.
509
510 .. seealso::
511
512 :meth:`_expression.Select.with_hint`
513
514 :meth:`_expression.Select.prefix_with` - generic SELECT prefixing
515 which also can suit some database-specific HINT syntaxes such as
516 MySQL or Oracle Database optimizer hints
517
518 """
519 return self._with_hint(None, text, dialect_name)
520
521 @_generative
522 def with_hint(
523 self,
524 selectable: _FromClauseArgument,
525 text: str,
526 dialect_name: str = "*",
527 ) -> Self:
528 r"""Add an indexing or other executional context hint for the given
529 selectable to this :class:`_expression.Select` or other selectable
530 object.
531
532 .. tip::
533
534 The :meth:`_expression.Select.with_hint` method adds hints that are
535 **specific to a single table** to a statement, in a location that
536 is **dialect-specific**. To add generic optimizer hints to the
537 **beginning** of a statement ahead of the SELECT keyword such as
538 for MySQL or Oracle Database, use the
539 :meth:`_expression.Select.prefix_with` method. To add optimizer
540 hints to the **end** of a statement such as for PostgreSQL, use the
541 :meth:`_expression.Select.with_statement_hint` method.
542
543 The text of the hint is rendered in the appropriate
544 location for the database backend in use, relative
545 to the given :class:`_schema.Table` or :class:`_expression.Alias`
546 passed as the
547 ``selectable`` argument. The dialect implementation
548 typically uses Python string substitution syntax
549 with the token ``%(name)s`` to render the name of
550 the table or alias. E.g. when using Oracle Database, the
551 following::
552
553 select(mytable).with_hint(mytable, "index(%(name)s ix_mytable)")
554
555 Would render SQL as:
556
557 .. sourcecode:: sql
558
559 select /*+ index(mytable ix_mytable) */ ... from mytable
560
561 The ``dialect_name`` option will limit the rendering of a particular
562 hint to a particular backend. Such as, to add hints for both Oracle
563 Database and MSSql simultaneously::
564
565 select(mytable).with_hint(
566 mytable, "index(%(name)s ix_mytable)", "oracle"
567 ).with_hint(mytable, "WITH INDEX ix_mytable", "mssql")
568
569 .. seealso::
570
571 :meth:`_expression.Select.with_statement_hint`
572
573 :meth:`_expression.Select.prefix_with` - generic SELECT prefixing
574 which also can suit some database-specific HINT syntaxes such as
575 MySQL or Oracle Database optimizer hints
576
577 """
578
579 return self._with_hint(selectable, text, dialect_name)
580
581 def _with_hint(
582 self,
583 selectable: Optional[_FromClauseArgument],
584 text: str,
585 dialect_name: str,
586 ) -> Self:
587 if selectable is None:
588 self._statement_hints += ((dialect_name, text),)
589 else:
590 self._hints = self._hints.union(
591 {
592 (
593 coercions.expect(roles.FromClauseRole, selectable),
594 dialect_name,
595 ): text
596 }
597 )
598 return self
599
600
601class FromClause(roles.AnonymizedFromClauseRole, Selectable):
602 """Represent an element that can be used within the ``FROM``
603 clause of a ``SELECT`` statement.
604
605 The most common forms of :class:`_expression.FromClause` are the
606 :class:`_schema.Table` and the :func:`_expression.select` constructs. Key
607 features common to all :class:`_expression.FromClause` objects include:
608
609 * a :attr:`.c` collection, which provides per-name access to a collection
610 of :class:`_expression.ColumnElement` objects.
611 * a :attr:`.primary_key` attribute, which is a collection of all those
612 :class:`_expression.ColumnElement`
613 objects that indicate the ``primary_key`` flag.
614 * Methods to generate various derivations of a "from" clause, including
615 :meth:`_expression.FromClause.alias`,
616 :meth:`_expression.FromClause.join`,
617 :meth:`_expression.FromClause.select`.
618
619
620 """
621
622 __visit_name__ = "fromclause"
623 named_with_column = False
624
625 @util.ro_non_memoized_property
626 def _hide_froms(self) -> Iterable[FromClause]:
627 return ()
628
629 _is_clone_of: Optional[FromClause]
630
631 _columns: ColumnCollection[Any, Any]
632
633 schema: Optional[str] = None
634 """Define the 'schema' attribute for this :class:`_expression.FromClause`.
635
636 This is typically ``None`` for most objects except that of
637 :class:`_schema.Table`, where it is taken as the value of the
638 :paramref:`_schema.Table.schema` argument.
639
640 """
641
642 is_selectable = True
643 _is_from_clause = True
644 _is_join = False
645
646 _use_schema_map = False
647
648 def select(self) -> Select[Any]:
649 r"""Return a SELECT of this :class:`_expression.FromClause`.
650
651
652 e.g.::
653
654 stmt = some_table.select().where(some_table.c.id == 5)
655
656 .. seealso::
657
658 :func:`_expression.select` - general purpose
659 method which allows for arbitrary column lists.
660
661 """
662 return Select(self)
663
664 def join(
665 self,
666 right: _FromClauseArgument,
667 onclause: Optional[_ColumnExpressionArgument[bool]] = None,
668 isouter: bool = False,
669 full: bool = False,
670 ) -> Join:
671 """Return a :class:`_expression.Join` from this
672 :class:`_expression.FromClause`
673 to another :class:`FromClause`.
674
675 E.g.::
676
677 from sqlalchemy import join
678
679 j = user_table.join(
680 address_table, user_table.c.id == address_table.c.user_id
681 )
682 stmt = select(user_table).select_from(j)
683
684 would emit SQL along the lines of:
685
686 .. sourcecode:: sql
687
688 SELECT user.id, user.name FROM user
689 JOIN address ON user.id = address.user_id
690
691 :param right: the right side of the join; this is any
692 :class:`_expression.FromClause` object such as a
693 :class:`_schema.Table` object, and
694 may also be a selectable-compatible object such as an ORM-mapped
695 class.
696
697 :param onclause: a SQL expression representing the ON clause of the
698 join. If left at ``None``, :meth:`_expression.FromClause.join`
699 will attempt to
700 join the two tables based on a foreign key relationship.
701
702 :param isouter: if True, render a LEFT OUTER JOIN, instead of JOIN.
703
704 :param full: if True, render a FULL OUTER JOIN, instead of LEFT OUTER
705 JOIN. Implies :paramref:`.FromClause.join.isouter`.
706
707 .. seealso::
708
709 :func:`_expression.join` - standalone function
710
711 :class:`_expression.Join` - the type of object produced
712
713 """
714
715 return Join(self, right, onclause, isouter, full)
716
717 def outerjoin(
718 self,
719 right: _FromClauseArgument,
720 onclause: Optional[_ColumnExpressionArgument[bool]] = None,
721 full: bool = False,
722 ) -> Join:
723 """Return a :class:`_expression.Join` from this
724 :class:`_expression.FromClause`
725 to another :class:`FromClause`, with the "isouter" flag set to
726 True.
727
728 E.g.::
729
730 from sqlalchemy import outerjoin
731
732 j = user_table.outerjoin(
733 address_table, user_table.c.id == address_table.c.user_id
734 )
735
736 The above is equivalent to::
737
738 j = user_table.join(
739 address_table, user_table.c.id == address_table.c.user_id, isouter=True
740 )
741
742 :param right: the right side of the join; this is any
743 :class:`_expression.FromClause` object such as a
744 :class:`_schema.Table` object, and
745 may also be a selectable-compatible object such as an ORM-mapped
746 class.
747
748 :param onclause: a SQL expression representing the ON clause of the
749 join. If left at ``None``, :meth:`_expression.FromClause.join`
750 will attempt to
751 join the two tables based on a foreign key relationship.
752
753 :param full: if True, render a FULL OUTER JOIN, instead of
754 LEFT OUTER JOIN.
755
756 .. seealso::
757
758 :meth:`_expression.FromClause.join`
759
760 :class:`_expression.Join`
761
762 """ # noqa: E501
763
764 return Join(self, right, onclause, True, full)
765
766 def alias(
767 self, name: Optional[str] = None, flat: bool = False
768 ) -> NamedFromClause:
769 """Return an alias of this :class:`_expression.FromClause`.
770
771 E.g.::
772
773 a2 = some_table.alias("a2")
774
775 The above code creates an :class:`_expression.Alias`
776 object which can be used
777 as a FROM clause in any SELECT statement.
778
779 .. seealso::
780
781 :ref:`tutorial_using_aliases`
782
783 :func:`_expression.alias`
784
785 """
786
787 return Alias._construct(self, name=name)
788
789 def tablesample(
790 self,
791 sampling: Union[float, Function[Any]],
792 name: Optional[str] = None,
793 seed: Optional[roles.ExpressionElementRole[Any]] = None,
794 ) -> TableSample:
795 """Return a TABLESAMPLE alias of this :class:`_expression.FromClause`.
796
797 The return value is the :class:`_expression.TableSample`
798 construct also
799 provided by the top-level :func:`_expression.tablesample` function.
800
801 .. seealso::
802
803 :func:`_expression.tablesample` - usage guidelines and parameters
804
805 """
806 return TableSample._construct(
807 self, sampling=sampling, name=name, seed=seed
808 )
809
810 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
811 """Return ``True`` if this :class:`_expression.FromClause` is
812 'derived' from the given ``FromClause``.
813
814 An example would be an Alias of a Table is derived from that Table.
815
816 """
817 # this is essentially an "identity" check in the base class.
818 # Other constructs override this to traverse through
819 # contained elements.
820 return fromclause in self._cloned_set
821
822 def _is_lexical_equivalent(self, other: FromClause) -> bool:
823 """Return ``True`` if this :class:`_expression.FromClause` and
824 the other represent the same lexical identity.
825
826 This tests if either one is a copy of the other, or
827 if they are the same via annotation identity.
828
829 """
830 return bool(self._cloned_set.intersection(other._cloned_set))
831
832 @util.ro_non_memoized_property
833 def description(self) -> str:
834 """A brief description of this :class:`_expression.FromClause`.
835
836 Used primarily for error message formatting.
837
838 """
839 return getattr(self, "name", self.__class__.__name__ + " object")
840
841 def _generate_fromclause_column_proxies(
842 self,
843 fromclause: FromClause,
844 columns: ColumnCollection[str, KeyedColumnElement[Any]],
845 primary_key: ColumnSet,
846 foreign_keys: Set[KeyedColumnElement[Any]],
847 ) -> None:
848 columns._populate_separate_keys(
849 col._make_proxy(
850 fromclause, primary_key=primary_key, foreign_keys=foreign_keys
851 )
852 for col in self.c
853 )
854
855 @util.ro_non_memoized_property
856 def exported_columns(
857 self,
858 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
859 """A :class:`_expression.ColumnCollection`
860 that represents the "exported"
861 columns of this :class:`_expression.Selectable`.
862
863 The "exported" columns for a :class:`_expression.FromClause`
864 object are synonymous
865 with the :attr:`_expression.FromClause.columns` collection.
866
867 .. versionadded:: 1.4
868
869 .. seealso::
870
871 :attr:`_expression.Selectable.exported_columns`
872
873 :attr:`_expression.SelectBase.exported_columns`
874
875
876 """
877 return self.c
878
879 @util.ro_non_memoized_property
880 def columns(
881 self,
882 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
883 """A named-based collection of :class:`_expression.ColumnElement`
884 objects maintained by this :class:`_expression.FromClause`.
885
886 The :attr:`.columns`, or :attr:`.c` collection, is the gateway
887 to the construction of SQL expressions using table-bound or
888 other selectable-bound columns::
889
890 select(mytable).where(mytable.c.somecolumn == 5)
891
892 :return: a :class:`.ColumnCollection` object.
893
894 """
895 return self.c
896
897 @util.ro_memoized_property
898 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
899 """
900 A synonym for :attr:`.FromClause.columns`
901
902 :return: a :class:`.ColumnCollection`
903
904 """
905 if "_columns" not in self.__dict__:
906 self._setup_collections()
907 return self._columns.as_readonly()
908
909 def _setup_collections(self) -> None:
910 assert "_columns" not in self.__dict__
911 assert "primary_key" not in self.__dict__
912 assert "foreign_keys" not in self.__dict__
913
914 _columns: ColumnCollection[Any, Any] = ColumnCollection()
915 primary_key = ColumnSet()
916 foreign_keys: Set[KeyedColumnElement[Any]] = set()
917
918 self._populate_column_collection(
919 columns=_columns,
920 primary_key=primary_key,
921 foreign_keys=foreign_keys,
922 )
923
924 # assigning these three collections separately is not itself atomic,
925 # but greatly reduces the surface for problems
926 self._columns = _columns
927 self.primary_key = primary_key # type: ignore
928 self.foreign_keys = foreign_keys # type: ignore
929
930 @util.ro_non_memoized_property
931 def entity_namespace(self) -> _EntityNamespace:
932 """Return a namespace used for name-based access in SQL expressions.
933
934 This is the namespace that is used to resolve "filter_by()" type
935 expressions, such as::
936
937 stmt.filter_by(address="some address")
938
939 It defaults to the ``.c`` collection, however internally it can
940 be overridden using the "entity_namespace" annotation to deliver
941 alternative results.
942
943 """
944 return self.c
945
946 @util.ro_memoized_property
947 def primary_key(self) -> Iterable[NamedColumn[Any]]:
948 """Return the iterable collection of :class:`_schema.Column` objects
949 which comprise the primary key of this :class:`_selectable.FromClause`.
950
951 For a :class:`_schema.Table` object, this collection is represented
952 by the :class:`_schema.PrimaryKeyConstraint` which itself is an
953 iterable collection of :class:`_schema.Column` objects.
954
955 """
956 self._setup_collections()
957 return self.primary_key
958
959 @util.ro_memoized_property
960 def foreign_keys(self) -> Iterable[ForeignKey]:
961 """Return the collection of :class:`_schema.ForeignKey` marker objects
962 which this FromClause references.
963
964 Each :class:`_schema.ForeignKey` is a member of a
965 :class:`_schema.Table`-wide
966 :class:`_schema.ForeignKeyConstraint`.
967
968 .. seealso::
969
970 :attr:`_schema.Table.foreign_key_constraints`
971
972 """
973 self._setup_collections()
974 return self.foreign_keys
975
976 def _reset_column_collection(self) -> None:
977 """Reset the attributes linked to the ``FromClause.c`` attribute.
978
979 This collection is separate from all the other memoized things
980 as it has shown to be sensitive to being cleared out in situations
981 where enclosing code, typically in a replacement traversal scenario,
982 has already established strong relationships
983 with the exported columns.
984
985 The collection is cleared for the case where a table is having a
986 column added to it as well as within a Join during copy internals.
987
988 """
989
990 for key in ["_columns", "columns", "c", "primary_key", "foreign_keys"]:
991 self.__dict__.pop(key, None)
992
993 @util.ro_non_memoized_property
994 def _select_iterable(self) -> _SelectIterable:
995 return (c for c in self.c if not _never_select_column(c))
996
997 @property
998 def _cols_populated(self) -> bool:
999 return "_columns" in self.__dict__
1000
1001 def _populate_column_collection(
1002 self,
1003 columns: ColumnCollection[str, KeyedColumnElement[Any]],
1004 primary_key: ColumnSet,
1005 foreign_keys: Set[KeyedColumnElement[Any]],
1006 ) -> None:
1007 """Called on subclasses to establish the .c collection.
1008
1009 Each implementation has a different way of establishing
1010 this collection.
1011
1012 """
1013
1014 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
1015 """Given a column added to the .c collection of an underlying
1016 selectable, produce the local version of that column, assuming this
1017 selectable ultimately should proxy this column.
1018
1019 this is used to "ping" a derived selectable to add a new column
1020 to its .c. collection when a Column has been added to one of the
1021 Table objects it ultimately derives from.
1022
1023 If the given selectable hasn't populated its .c. collection yet,
1024 it should at least pass on the message to the contained selectables,
1025 but it will return None.
1026
1027 This method is currently used by Declarative to allow Table
1028 columns to be added to a partially constructed inheritance
1029 mapping that may have already produced joins. The method
1030 isn't public right now, as the full span of implications
1031 and/or caveats aren't yet clear.
1032
1033 It's also possible that this functionality could be invoked by
1034 default via an event, which would require that
1035 selectables maintain a weak referencing collection of all
1036 derivations.
1037
1038 """
1039 self._reset_column_collection()
1040
1041 def _anonymous_fromclause(
1042 self, *, name: Optional[str] = None, flat: bool = False
1043 ) -> FromClause:
1044 return self.alias(name=name)
1045
1046 if TYPE_CHECKING:
1047
1048 def self_group(
1049 self, against: Optional[OperatorType] = None
1050 ) -> Union[FromGrouping, Self]: ...
1051
1052
1053class NamedFromClause(FromClause):
1054 """A :class:`.FromClause` that has a name.
1055
1056 Examples include tables, subqueries, CTEs, aliased tables.
1057
1058 .. versionadded:: 2.0
1059
1060 """
1061
1062 named_with_column = True
1063
1064 name: str
1065
1066 @util.preload_module("sqlalchemy.sql.sqltypes")
1067 def table_valued(self) -> TableValuedColumn[Any]:
1068 """Return a :class:`_sql.TableValuedColumn` object for this
1069 :class:`_expression.FromClause`.
1070
1071 A :class:`_sql.TableValuedColumn` is a :class:`_sql.ColumnElement` that
1072 represents a complete row in a table. Support for this construct is
1073 backend dependent, and is supported in various forms by backends
1074 such as PostgreSQL, Oracle Database and SQL Server.
1075
1076 E.g.:
1077
1078 .. sourcecode:: pycon+sql
1079
1080 >>> from sqlalchemy import select, column, func, table
1081 >>> a = table("a", column("id"), column("x"), column("y"))
1082 >>> stmt = select(func.row_to_json(a.table_valued()))
1083 >>> print(stmt)
1084 {printsql}SELECT row_to_json(a) AS row_to_json_1
1085 FROM a
1086
1087 .. versionadded:: 1.4.0b2
1088
1089 .. seealso::
1090
1091 :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
1092
1093 """
1094 return TableValuedColumn(self, type_api.TABLEVALUE)
1095
1096
1097class SelectLabelStyle(Enum):
1098 """Label style constants that may be passed to
1099 :meth:`_sql.Select.set_label_style`."""
1100
1101 LABEL_STYLE_NONE = 0
1102 """Label style indicating no automatic labeling should be applied to the
1103 columns clause of a SELECT statement.
1104
1105 Below, the columns named ``columna`` are both rendered as is, meaning that
1106 the name ``columna`` can only refer to the first occurrence of this name
1107 within a result set, as well as if the statement were used as a subquery:
1108
1109 .. sourcecode:: pycon+sql
1110
1111 >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_NONE
1112 >>> table1 = table("table1", column("columna"), column("columnb"))
1113 >>> table2 = table("table2", column("columna"), column("columnc"))
1114 >>> print(
1115 ... select(table1, table2)
1116 ... .join(table2, true())
1117 ... .set_label_style(LABEL_STYLE_NONE)
1118 ... )
1119 {printsql}SELECT table1.columna, table1.columnb, table2.columna, table2.columnc
1120 FROM table1 JOIN table2 ON true
1121
1122 Used with the :meth:`_sql.Select.set_label_style` method.
1123
1124 .. versionadded:: 1.4
1125
1126 """ # noqa: E501
1127
1128 LABEL_STYLE_TABLENAME_PLUS_COL = 1
1129 """Label style indicating all columns should be labeled as
1130 ``<tablename>_<columnname>`` when generating the columns clause of a SELECT
1131 statement, to disambiguate same-named columns referenced from different
1132 tables, aliases, or subqueries.
1133
1134 Below, all column names are given a label so that the two same-named
1135 columns ``columna`` are disambiguated as ``table1_columna`` and
1136 ``table2_columna``:
1137
1138 .. sourcecode:: pycon+sql
1139
1140 >>> from sqlalchemy import (
1141 ... table,
1142 ... column,
1143 ... select,
1144 ... true,
1145 ... LABEL_STYLE_TABLENAME_PLUS_COL,
1146 ... )
1147 >>> table1 = table("table1", column("columna"), column("columnb"))
1148 >>> table2 = table("table2", column("columna"), column("columnc"))
1149 >>> print(
1150 ... select(table1, table2)
1151 ... .join(table2, true())
1152 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
1153 ... )
1154 {printsql}SELECT table1.columna AS table1_columna, table1.columnb AS table1_columnb, table2.columna AS table2_columna, table2.columnc AS table2_columnc
1155 FROM table1 JOIN table2 ON true
1156
1157 Used with the :meth:`_sql.GenerativeSelect.set_label_style` method.
1158 Equivalent to the legacy method ``Select.apply_labels()``;
1159 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` is SQLAlchemy's legacy
1160 auto-labeling style. :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` provides a
1161 less intrusive approach to disambiguation of same-named column expressions.
1162
1163
1164 .. versionadded:: 1.4
1165
1166 """ # noqa: E501
1167
1168 LABEL_STYLE_DISAMBIGUATE_ONLY = 2
1169 """Label style indicating that columns with a name that conflicts with
1170 an existing name should be labeled with a semi-anonymizing label
1171 when generating the columns clause of a SELECT statement.
1172
1173 Below, most column names are left unaffected, except for the second
1174 occurrence of the name ``columna``, which is labeled using the
1175 label ``columna_1`` to disambiguate it from that of ``tablea.columna``:
1176
1177 .. sourcecode:: pycon+sql
1178
1179 >>> from sqlalchemy import (
1180 ... table,
1181 ... column,
1182 ... select,
1183 ... true,
1184 ... LABEL_STYLE_DISAMBIGUATE_ONLY,
1185 ... )
1186 >>> table1 = table("table1", column("columna"), column("columnb"))
1187 >>> table2 = table("table2", column("columna"), column("columnc"))
1188 >>> print(
1189 ... select(table1, table2)
1190 ... .join(table2, true())
1191 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
1192 ... )
1193 {printsql}SELECT table1.columna, table1.columnb, table2.columna AS columna_1, table2.columnc
1194 FROM table1 JOIN table2 ON true
1195
1196 Used with the :meth:`_sql.GenerativeSelect.set_label_style` method,
1197 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` is the default labeling style
1198 for all SELECT statements outside of :term:`1.x style` ORM queries.
1199
1200 .. versionadded:: 1.4
1201
1202 """ # noqa: E501
1203
1204 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY
1205 """The default label style, refers to
1206 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`.
1207
1208 .. versionadded:: 1.4
1209
1210 """
1211
1212 LABEL_STYLE_LEGACY_ORM = 3
1213
1214
1215(
1216 LABEL_STYLE_NONE,
1217 LABEL_STYLE_TABLENAME_PLUS_COL,
1218 LABEL_STYLE_DISAMBIGUATE_ONLY,
1219 _,
1220) = list(SelectLabelStyle)
1221
1222LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY
1223
1224
1225class Join(roles.DMLTableRole, FromClause):
1226 """Represent a ``JOIN`` construct between two
1227 :class:`_expression.FromClause`
1228 elements.
1229
1230 The public constructor function for :class:`_expression.Join`
1231 is the module-level
1232 :func:`_expression.join()` function, as well as the
1233 :meth:`_expression.FromClause.join` method
1234 of any :class:`_expression.FromClause` (e.g. such as
1235 :class:`_schema.Table`).
1236
1237 .. seealso::
1238
1239 :func:`_expression.join`
1240
1241 :meth:`_expression.FromClause.join`
1242
1243 """
1244
1245 __visit_name__ = "join"
1246
1247 _traverse_internals: _TraverseInternalsType = [
1248 ("left", InternalTraversal.dp_clauseelement),
1249 ("right", InternalTraversal.dp_clauseelement),
1250 ("onclause", InternalTraversal.dp_clauseelement),
1251 ("isouter", InternalTraversal.dp_boolean),
1252 ("full", InternalTraversal.dp_boolean),
1253 ]
1254
1255 _is_join = True
1256
1257 left: FromClause
1258 right: FromClause
1259 onclause: Optional[ColumnElement[bool]]
1260 isouter: bool
1261 full: bool
1262
1263 def __init__(
1264 self,
1265 left: _FromClauseArgument,
1266 right: _FromClauseArgument,
1267 onclause: Optional[_OnClauseArgument] = None,
1268 isouter: bool = False,
1269 full: bool = False,
1270 ):
1271 """Construct a new :class:`_expression.Join`.
1272
1273 The usual entrypoint here is the :func:`_expression.join`
1274 function or the :meth:`_expression.FromClause.join` method of any
1275 :class:`_expression.FromClause` object.
1276
1277 """
1278
1279 # when deannotate was removed here, callcounts went up for ORM
1280 # compilation of eager joins, since there were more comparisons of
1281 # annotated objects. test_orm.py -> test_fetch_results
1282 # was therefore changed to show a more real-world use case, where the
1283 # compilation is cached; there's no change in post-cache callcounts.
1284 # callcounts for a single compilation in that particular test
1285 # that includes about eight joins about 1100 extra fn calls, from
1286 # 29200 -> 30373
1287
1288 self.left = coercions.expect(
1289 roles.FromClauseRole,
1290 left,
1291 )
1292 self.right = coercions.expect(
1293 roles.FromClauseRole,
1294 right,
1295 ).self_group()
1296
1297 if onclause is None:
1298 self.onclause = self._match_primaries(self.left, self.right)
1299 else:
1300 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba
1301 # not merged yet
1302 self.onclause = coercions.expect(
1303 roles.OnClauseRole, onclause
1304 ).self_group(against=operators._asbool)
1305
1306 self.isouter = isouter
1307 self.full = full
1308
1309 @util.ro_non_memoized_property
1310 def description(self) -> str:
1311 return "Join object on %s(%d) and %s(%d)" % (
1312 self.left.description,
1313 id(self.left),
1314 self.right.description,
1315 id(self.right),
1316 )
1317
1318 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
1319 return (
1320 # use hash() to ensure direct comparison to annotated works
1321 # as well
1322 hash(fromclause) == hash(self)
1323 or self.left.is_derived_from(fromclause)
1324 or self.right.is_derived_from(fromclause)
1325 )
1326
1327 def self_group(
1328 self, against: Optional[OperatorType] = None
1329 ) -> FromGrouping:
1330 return FromGrouping(self)
1331
1332 @util.preload_module("sqlalchemy.sql.util")
1333 def _populate_column_collection(
1334 self,
1335 columns: ColumnCollection[str, KeyedColumnElement[Any]],
1336 primary_key: ColumnSet,
1337 foreign_keys: Set[KeyedColumnElement[Any]],
1338 ) -> None:
1339 sqlutil = util.preloaded.sql_util
1340 _columns: List[KeyedColumnElement[Any]] = [c for c in self.left.c] + [
1341 c for c in self.right.c
1342 ]
1343
1344 primary_key.extend(
1345 sqlutil.reduce_columns(
1346 (c for c in _columns if c.primary_key), self.onclause
1347 )
1348 )
1349 columns._populate_separate_keys(
1350 (col._tq_key_label, col) for col in _columns # type: ignore
1351 )
1352 foreign_keys.update(
1353 itertools.chain(*[col.foreign_keys for col in _columns]) # type: ignore # noqa: E501
1354 )
1355
1356 def _copy_internals(
1357 self, clone: _CloneCallableType = _clone, **kw: Any
1358 ) -> None:
1359 # see Select._copy_internals() for similar concept
1360
1361 # here we pre-clone "left" and "right" so that we can
1362 # determine the new FROM clauses
1363 all_the_froms = set(
1364 itertools.chain(
1365 _from_objects(self.left),
1366 _from_objects(self.right),
1367 )
1368 )
1369
1370 # run the clone on those. these will be placed in the
1371 # cache used by the clone function
1372 new_froms = {f: clone(f, **kw) for f in all_the_froms}
1373
1374 # set up a special replace function that will replace for
1375 # ColumnClause with parent table referring to those
1376 # replaced FromClause objects
1377 def replace(
1378 obj: Union[BinaryExpression[Any], ColumnClause[Any]],
1379 **kw: Any,
1380 ) -> Optional[KeyedColumnElement[Any]]:
1381 if isinstance(obj, ColumnClause) and obj.table in new_froms:
1382 newelem = new_froms[obj.table].corresponding_column(obj)
1383 return newelem
1384 return None
1385
1386 kw["replace"] = replace
1387
1388 # run normal _copy_internals. the clones for
1389 # left and right will come from the clone function's
1390 # cache
1391 super()._copy_internals(clone=clone, **kw)
1392
1393 self._reset_memoizations()
1394
1395 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
1396 super()._refresh_for_new_column(column)
1397 self.left._refresh_for_new_column(column)
1398 self.right._refresh_for_new_column(column)
1399
1400 def _match_primaries(
1401 self,
1402 left: FromClause,
1403 right: FromClause,
1404 ) -> ColumnElement[bool]:
1405 if isinstance(left, Join):
1406 left_right = left.right
1407 else:
1408 left_right = None
1409 return self._join_condition(left, right, a_subset=left_right)
1410
1411 @classmethod
1412 def _join_condition(
1413 cls,
1414 a: FromClause,
1415 b: FromClause,
1416 *,
1417 a_subset: Optional[FromClause] = None,
1418 consider_as_foreign_keys: Optional[
1419 AbstractSet[ColumnClause[Any]]
1420 ] = None,
1421 ) -> ColumnElement[bool]:
1422 """Create a join condition between two tables or selectables.
1423
1424 See sqlalchemy.sql.util.join_condition() for full docs.
1425
1426 """
1427 constraints = cls._joincond_scan_left_right(
1428 a, a_subset, b, consider_as_foreign_keys
1429 )
1430
1431 if len(constraints) > 1:
1432 cls._joincond_trim_constraints(
1433 a, b, constraints, consider_as_foreign_keys
1434 )
1435
1436 if len(constraints) == 0:
1437 if isinstance(b, FromGrouping):
1438 hint = (
1439 " Perhaps you meant to convert the right side to a "
1440 "subquery using alias()?"
1441 )
1442 else:
1443 hint = ""
1444 raise exc.NoForeignKeysError(
1445 "Can't find any foreign key relationships "
1446 "between '%s' and '%s'.%s"
1447 % (a.description, b.description, hint)
1448 )
1449
1450 crit = [(x == y) for x, y in list(constraints.values())[0]]
1451 if len(crit) == 1:
1452 return crit[0]
1453 else:
1454 return and_(*crit)
1455
1456 @classmethod
1457 def _can_join(
1458 cls,
1459 left: FromClause,
1460 right: FromClause,
1461 *,
1462 consider_as_foreign_keys: Optional[
1463 AbstractSet[ColumnClause[Any]]
1464 ] = None,
1465 ) -> bool:
1466 if isinstance(left, Join):
1467 left_right = left.right
1468 else:
1469 left_right = None
1470
1471 constraints = cls._joincond_scan_left_right(
1472 a=left,
1473 b=right,
1474 a_subset=left_right,
1475 consider_as_foreign_keys=consider_as_foreign_keys,
1476 )
1477
1478 return bool(constraints)
1479
1480 @classmethod
1481 @util.preload_module("sqlalchemy.sql.util")
1482 def _joincond_scan_left_right(
1483 cls,
1484 a: FromClause,
1485 a_subset: Optional[FromClause],
1486 b: FromClause,
1487 consider_as_foreign_keys: Optional[AbstractSet[ColumnClause[Any]]],
1488 ) -> collections.defaultdict[
1489 Optional[ForeignKeyConstraint],
1490 List[Tuple[ColumnClause[Any], ColumnClause[Any]]],
1491 ]:
1492 sql_util = util.preloaded.sql_util
1493
1494 a = coercions.expect(roles.FromClauseRole, a)
1495 b = coercions.expect(roles.FromClauseRole, b)
1496
1497 constraints: collections.defaultdict[
1498 Optional[ForeignKeyConstraint],
1499 List[Tuple[ColumnClause[Any], ColumnClause[Any]]],
1500 ] = collections.defaultdict(list)
1501
1502 for left in (a_subset, a):
1503 if left is None:
1504 continue
1505 for fk in sorted(
1506 b.foreign_keys,
1507 key=lambda fk: fk.parent._creation_order,
1508 ):
1509 if (
1510 consider_as_foreign_keys is not None
1511 and fk.parent not in consider_as_foreign_keys
1512 ):
1513 continue
1514 try:
1515 col = fk.get_referent(left)
1516 except exc.NoReferenceError as nrte:
1517 table_names = {t.name for t in sql_util.find_tables(left)}
1518 if nrte.table_name in table_names:
1519 raise
1520 else:
1521 continue
1522
1523 if col is not None:
1524 constraints[fk.constraint].append((col, fk.parent))
1525 if left is not b:
1526 for fk in sorted(
1527 left.foreign_keys,
1528 key=lambda fk: fk.parent._creation_order,
1529 ):
1530 if (
1531 consider_as_foreign_keys is not None
1532 and fk.parent not in consider_as_foreign_keys
1533 ):
1534 continue
1535 try:
1536 col = fk.get_referent(b)
1537 except exc.NoReferenceError as nrte:
1538 table_names = {t.name for t in sql_util.find_tables(b)}
1539 if nrte.table_name in table_names:
1540 raise
1541 else:
1542 continue
1543
1544 if col is not None:
1545 constraints[fk.constraint].append((col, fk.parent))
1546 if constraints:
1547 break
1548 return constraints
1549
1550 @classmethod
1551 def _joincond_trim_constraints(
1552 cls,
1553 a: FromClause,
1554 b: FromClause,
1555 constraints: Dict[Any, Any],
1556 consider_as_foreign_keys: Optional[Any],
1557 ) -> None:
1558 # more than one constraint matched. narrow down the list
1559 # to include just those FKCs that match exactly to
1560 # "consider_as_foreign_keys".
1561 if consider_as_foreign_keys:
1562 for const in list(constraints):
1563 if {f.parent for f in const.elements} != set(
1564 consider_as_foreign_keys
1565 ):
1566 del constraints[const]
1567
1568 # if still multiple constraints, but
1569 # they all refer to the exact same end result, use it.
1570 if len(constraints) > 1:
1571 dedupe = {tuple(crit) for crit in constraints.values()}
1572 if len(dedupe) == 1:
1573 key = list(constraints)[0]
1574 constraints = {key: constraints[key]}
1575
1576 if len(constraints) != 1:
1577 raise exc.AmbiguousForeignKeysError(
1578 "Can't determine join between '%s' and '%s'; "
1579 "tables have more than one foreign key "
1580 "constraint relationship between them. "
1581 "Please specify the 'onclause' of this "
1582 "join explicitly." % (a.description, b.description)
1583 )
1584
1585 def select(self) -> Select[Any]:
1586 r"""Create a :class:`_expression.Select` from this
1587 :class:`_expression.Join`.
1588
1589 E.g.::
1590
1591 stmt = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
1592
1593 stmt = stmt.select()
1594
1595 The above will produce a SQL string resembling:
1596
1597 .. sourcecode:: sql
1598
1599 SELECT table_a.id, table_a.col, table_b.id, table_b.a_id
1600 FROM table_a JOIN table_b ON table_a.id = table_b.a_id
1601
1602 """
1603 return Select(self.left, self.right).select_from(self)
1604
1605 @util.preload_module("sqlalchemy.sql.util")
1606 def _anonymous_fromclause(
1607 self, name: Optional[str] = None, flat: bool = False
1608 ) -> TODO_Any:
1609 sqlutil = util.preloaded.sql_util
1610 if flat:
1611 if isinstance(self.left, (FromGrouping, Join)):
1612 left_name = name # will recurse
1613 else:
1614 if name and isinstance(self.left, NamedFromClause):
1615 left_name = f"{name}_{self.left.name}"
1616 else:
1617 left_name = name
1618 if isinstance(self.right, (FromGrouping, Join)):
1619 right_name = name # will recurse
1620 else:
1621 if name and isinstance(self.right, NamedFromClause):
1622 right_name = f"{name}_{self.right.name}"
1623 else:
1624 right_name = name
1625 left_a, right_a = (
1626 self.left._anonymous_fromclause(name=left_name, flat=flat),
1627 self.right._anonymous_fromclause(name=right_name, flat=flat),
1628 )
1629 adapter = sqlutil.ClauseAdapter(left_a).chain(
1630 sqlutil.ClauseAdapter(right_a)
1631 )
1632
1633 return left_a.join(
1634 right_a,
1635 adapter.traverse(self.onclause),
1636 isouter=self.isouter,
1637 full=self.full,
1638 )
1639 else:
1640 return (
1641 self.select()
1642 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
1643 .correlate(None)
1644 .alias(name)
1645 )
1646
1647 @util.ro_non_memoized_property
1648 def _hide_froms(self) -> Iterable[FromClause]:
1649 return itertools.chain(
1650 *[_from_objects(x.left, x.right) for x in self._cloned_set]
1651 )
1652
1653 @util.ro_non_memoized_property
1654 def _from_objects(self) -> List[FromClause]:
1655 self_list: List[FromClause] = [self]
1656 return self_list + self.left._from_objects + self.right._from_objects
1657
1658
1659class NoInit:
1660 def __init__(self, *arg: Any, **kw: Any):
1661 raise NotImplementedError(
1662 "The %s class is not intended to be constructed "
1663 "directly. Please use the %s() standalone "
1664 "function or the %s() method available from appropriate "
1665 "selectable objects."
1666 % (
1667 self.__class__.__name__,
1668 self.__class__.__name__.lower(),
1669 self.__class__.__name__.lower(),
1670 )
1671 )
1672
1673
1674class LateralFromClause(NamedFromClause):
1675 """mark a FROM clause as being able to render directly as LATERAL"""
1676
1677
1678# FromClause ->
1679# AliasedReturnsRows
1680# -> Alias only for FromClause
1681# -> Subquery only for SelectBase
1682# -> CTE only for HasCTE -> SelectBase, DML
1683# -> Lateral -> FromClause, but we accept SelectBase
1684# w/ non-deprecated coercion
1685# -> TableSample -> only for FromClause
1686
1687
1688class AliasedReturnsRows(NoInit, NamedFromClause):
1689 """Base class of aliases against tables, subqueries, and other
1690 selectables."""
1691
1692 _is_from_container = True
1693
1694 _supports_derived_columns = False
1695
1696 element: ReturnsRows
1697
1698 _traverse_internals: _TraverseInternalsType = [
1699 ("element", InternalTraversal.dp_clauseelement),
1700 ("name", InternalTraversal.dp_anon_name),
1701 ]
1702
1703 @classmethod
1704 def _construct(
1705 cls,
1706 selectable: Any,
1707 *,
1708 name: Optional[str] = None,
1709 **kw: Any,
1710 ) -> Self:
1711 obj = cls.__new__(cls)
1712 obj._init(selectable, name=name, **kw)
1713 return obj
1714
1715 def _init(self, selectable: Any, *, name: Optional[str] = None) -> None:
1716 self.element = coercions.expect(
1717 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self
1718 )
1719 self.element = selectable
1720 self._orig_name = name
1721 if name is None:
1722 if (
1723 isinstance(selectable, FromClause)
1724 and selectable.named_with_column
1725 ):
1726 name = getattr(selectable, "name", None)
1727 if isinstance(name, _anonymous_label):
1728 name = None
1729 name = _anonymous_label.safe_construct(id(self), name or "anon")
1730 self.name = name
1731
1732 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
1733 super()._refresh_for_new_column(column)
1734 self.element._refresh_for_new_column(column)
1735
1736 def _populate_column_collection(
1737 self,
1738 columns: ColumnCollection[str, KeyedColumnElement[Any]],
1739 primary_key: ColumnSet,
1740 foreign_keys: Set[KeyedColumnElement[Any]],
1741 ) -> None:
1742 self.element._generate_fromclause_column_proxies(
1743 self, columns, primary_key=primary_key, foreign_keys=foreign_keys
1744 )
1745
1746 @util.ro_non_memoized_property
1747 def description(self) -> str:
1748 name = self.name
1749 if isinstance(name, _anonymous_label):
1750 return "anon_1"
1751
1752 return name
1753
1754 @util.ro_non_memoized_property
1755 def implicit_returning(self) -> bool:
1756 return self.element.implicit_returning # type: ignore
1757
1758 @property
1759 def original(self) -> ReturnsRows:
1760 """Legacy for dialects that are referring to Alias.original."""
1761 return self.element
1762
1763 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
1764 if fromclause in self._cloned_set:
1765 return True
1766 return self.element.is_derived_from(fromclause)
1767
1768 def _copy_internals(
1769 self, clone: _CloneCallableType = _clone, **kw: Any
1770 ) -> None:
1771 existing_element = self.element
1772
1773 super()._copy_internals(clone=clone, **kw)
1774
1775 # the element clone is usually against a Table that returns the
1776 # same object. don't reset exported .c. collections and other
1777 # memoized details if it was not changed. this saves a lot on
1778 # performance.
1779 if existing_element is not self.element:
1780 self._reset_column_collection()
1781
1782 @property
1783 def _from_objects(self) -> List[FromClause]:
1784 return [self]
1785
1786
1787class FromClauseAlias(AliasedReturnsRows):
1788 element: FromClause
1789
1790 @util.ro_non_memoized_property
1791 def description(self) -> str:
1792 name = self.name
1793 if isinstance(name, _anonymous_label):
1794 return f"Anonymous alias of {self.element.description}"
1795
1796 return name
1797
1798
1799class Alias(roles.DMLTableRole, FromClauseAlias):
1800 """Represents an table or selectable alias (AS).
1801
1802 Represents an alias, as typically applied to any table or
1803 sub-select within a SQL statement using the ``AS`` keyword (or
1804 without the keyword on certain databases such as Oracle Database).
1805
1806 This object is constructed from the :func:`_expression.alias` module
1807 level function as well as the :meth:`_expression.FromClause.alias`
1808 method available
1809 on all :class:`_expression.FromClause` subclasses.
1810
1811 .. seealso::
1812
1813 :meth:`_expression.FromClause.alias`
1814
1815 """
1816
1817 __visit_name__ = "alias"
1818
1819 inherit_cache = True
1820
1821 element: FromClause
1822
1823 @classmethod
1824 def _factory(
1825 cls,
1826 selectable: FromClause,
1827 name: Optional[str] = None,
1828 flat: bool = False,
1829 ) -> NamedFromClause:
1830 return coercions.expect(
1831 roles.FromClauseRole, selectable, allow_select=True
1832 ).alias(name=name, flat=flat)
1833
1834
1835class TableValuedAlias(LateralFromClause, Alias):
1836 """An alias against a "table valued" SQL function.
1837
1838 This construct provides for a SQL function that returns columns
1839 to be used in the FROM clause of a SELECT statement. The
1840 object is generated using the :meth:`_functions.FunctionElement.table_valued`
1841 method, e.g.:
1842
1843 .. sourcecode:: pycon+sql
1844
1845 >>> from sqlalchemy import select, func
1846 >>> fn = func.json_array_elements_text('["one", "two", "three"]').table_valued(
1847 ... "value"
1848 ... )
1849 >>> print(select(fn.c.value))
1850 {printsql}SELECT anon_1.value
1851 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1
1852
1853 .. versionadded:: 1.4.0b2
1854
1855 .. seealso::
1856
1857 :ref:`tutorial_functions_table_valued` - in the :ref:`unified_tutorial`
1858
1859 """ # noqa: E501
1860
1861 __visit_name__ = "table_valued_alias"
1862
1863 _supports_derived_columns = True
1864 _render_derived = False
1865 _render_derived_w_types = False
1866 joins_implicitly = False
1867
1868 _traverse_internals: _TraverseInternalsType = [
1869 ("element", InternalTraversal.dp_clauseelement),
1870 ("name", InternalTraversal.dp_anon_name),
1871 ("_tableval_type", InternalTraversal.dp_type),
1872 ("_render_derived", InternalTraversal.dp_boolean),
1873 ("_render_derived_w_types", InternalTraversal.dp_boolean),
1874 ]
1875
1876 def _init(
1877 self,
1878 selectable: Any,
1879 *,
1880 name: Optional[str] = None,
1881 table_value_type: Optional[TableValueType] = None,
1882 joins_implicitly: bool = False,
1883 ) -> None:
1884 super()._init(selectable, name=name)
1885
1886 self.joins_implicitly = joins_implicitly
1887 self._tableval_type = (
1888 type_api.TABLEVALUE
1889 if table_value_type is None
1890 else table_value_type
1891 )
1892
1893 @HasMemoized.memoized_attribute
1894 def column(self) -> TableValuedColumn[Any]:
1895 """Return a column expression representing this
1896 :class:`_sql.TableValuedAlias`.
1897
1898 This accessor is used to implement the
1899 :meth:`_functions.FunctionElement.column_valued` method. See that
1900 method for further details.
1901
1902 E.g.:
1903
1904 .. sourcecode:: pycon+sql
1905
1906 >>> print(select(func.some_func().table_valued("value").column))
1907 {printsql}SELECT anon_1 FROM some_func() AS anon_1
1908
1909 .. seealso::
1910
1911 :meth:`_functions.FunctionElement.column_valued`
1912
1913 """
1914
1915 return TableValuedColumn(self, self._tableval_type)
1916
1917 def alias(
1918 self, name: Optional[str] = None, flat: bool = False
1919 ) -> TableValuedAlias:
1920 """Return a new alias of this :class:`_sql.TableValuedAlias`.
1921
1922 This creates a distinct FROM object that will be distinguished
1923 from the original one when used in a SQL statement.
1924
1925 """
1926
1927 tva: TableValuedAlias = TableValuedAlias._construct(
1928 self,
1929 name=name,
1930 table_value_type=self._tableval_type,
1931 joins_implicitly=self.joins_implicitly,
1932 )
1933
1934 if self._render_derived:
1935 tva._render_derived = True
1936 tva._render_derived_w_types = self._render_derived_w_types
1937
1938 return tva
1939
1940 def lateral(self, name: Optional[str] = None) -> LateralFromClause:
1941 """Return a new :class:`_sql.TableValuedAlias` with the lateral flag
1942 set, so that it renders as LATERAL.
1943
1944 .. seealso::
1945
1946 :func:`_expression.lateral`
1947
1948 """
1949 tva = self.alias(name=name)
1950 tva._is_lateral = True
1951 return tva
1952
1953 def render_derived(
1954 self,
1955 name: Optional[str] = None,
1956 with_types: bool = False,
1957 ) -> TableValuedAlias:
1958 """Apply "render derived" to this :class:`_sql.TableValuedAlias`.
1959
1960 This has the effect of the individual column names listed out
1961 after the alias name in the "AS" sequence, e.g.:
1962
1963 .. sourcecode:: pycon+sql
1964
1965 >>> print(
1966 ... select(
1967 ... func.unnest(array(["one", "two", "three"]))
1968 ... .table_valued("x", with_ordinality="o")
1969 ... .render_derived()
1970 ... )
1971 ... )
1972 {printsql}SELECT anon_1.x, anon_1.o
1973 FROM unnest(ARRAY[%(param_1)s, %(param_2)s, %(param_3)s]) WITH ORDINALITY AS anon_1(x, o)
1974
1975 The ``with_types`` keyword will render column types inline within
1976 the alias expression (this syntax currently applies to the
1977 PostgreSQL database):
1978
1979 .. sourcecode:: pycon+sql
1980
1981 >>> print(
1982 ... select(
1983 ... func.json_to_recordset('[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]')
1984 ... .table_valued(column("a", Integer), column("b", String))
1985 ... .render_derived(with_types=True)
1986 ... )
1987 ... )
1988 {printsql}SELECT anon_1.a, anon_1.b FROM json_to_recordset(:json_to_recordset_1)
1989 AS anon_1(a INTEGER, b VARCHAR)
1990
1991 :param name: optional string name that will be applied to the alias
1992 generated. If left as None, a unique anonymizing name will be used.
1993
1994 :param with_types: if True, the derived columns will include the
1995 datatype specification with each column. This is a special syntax
1996 currently known to be required by PostgreSQL for some SQL functions.
1997
1998 """ # noqa: E501
1999
2000 # note: don't use the @_generative system here, keep a reference
2001 # to the original object. otherwise you can have re-use of the
2002 # python id() of the original which can cause name conflicts if
2003 # a new anon-name grabs the same identifier as the local anon-name
2004 # (just saw it happen on CI)
2005
2006 # construct against original to prevent memory growth
2007 # for repeated generations
2008 new_alias: TableValuedAlias = TableValuedAlias._construct(
2009 self.element,
2010 name=name,
2011 table_value_type=self._tableval_type,
2012 joins_implicitly=self.joins_implicitly,
2013 )
2014 new_alias._render_derived = True
2015 new_alias._render_derived_w_types = with_types
2016 return new_alias
2017
2018
2019class Lateral(FromClauseAlias, LateralFromClause):
2020 """Represent a LATERAL subquery.
2021
2022 This object is constructed from the :func:`_expression.lateral` module
2023 level function as well as the :meth:`_expression.FromClause.lateral`
2024 method available
2025 on all :class:`_expression.FromClause` subclasses.
2026
2027 While LATERAL is part of the SQL standard, currently only more recent
2028 PostgreSQL versions provide support for this keyword.
2029
2030 .. seealso::
2031
2032 :ref:`tutorial_lateral_correlation` - overview of usage.
2033
2034 """
2035
2036 __visit_name__ = "lateral"
2037 _is_lateral = True
2038
2039 inherit_cache = True
2040
2041 @classmethod
2042 def _factory(
2043 cls,
2044 selectable: Union[SelectBase, _FromClauseArgument],
2045 name: Optional[str] = None,
2046 ) -> LateralFromClause:
2047 return coercions.expect(
2048 roles.FromClauseRole, selectable, explicit_subquery=True
2049 ).lateral(name=name)
2050
2051
2052class TableSample(FromClauseAlias):
2053 """Represent a TABLESAMPLE clause.
2054
2055 This object is constructed from the :func:`_expression.tablesample` module
2056 level function as well as the :meth:`_expression.FromClause.tablesample`
2057 method
2058 available on all :class:`_expression.FromClause` subclasses.
2059
2060 .. seealso::
2061
2062 :func:`_expression.tablesample`
2063
2064 """
2065
2066 __visit_name__ = "tablesample"
2067
2068 _traverse_internals: _TraverseInternalsType = (
2069 AliasedReturnsRows._traverse_internals
2070 + [
2071 ("sampling", InternalTraversal.dp_clauseelement),
2072 ("seed", InternalTraversal.dp_clauseelement),
2073 ]
2074 )
2075
2076 @classmethod
2077 def _factory(
2078 cls,
2079 selectable: _FromClauseArgument,
2080 sampling: Union[float, Function[Any]],
2081 name: Optional[str] = None,
2082 seed: Optional[roles.ExpressionElementRole[Any]] = None,
2083 ) -> TableSample:
2084 return coercions.expect(roles.FromClauseRole, selectable).tablesample(
2085 sampling, name=name, seed=seed
2086 )
2087
2088 @util.preload_module("sqlalchemy.sql.functions")
2089 def _init( # type: ignore[override]
2090 self,
2091 selectable: Any,
2092 *,
2093 name: Optional[str] = None,
2094 sampling: Union[float, Function[Any]],
2095 seed: Optional[roles.ExpressionElementRole[Any]] = None,
2096 ) -> None:
2097 assert sampling is not None
2098 functions = util.preloaded.sql_functions
2099 if not isinstance(sampling, functions.Function):
2100 sampling = functions.func.system(sampling)
2101
2102 self.sampling: Function[Any] = sampling
2103 self.seed = seed
2104 super()._init(selectable, name=name)
2105
2106 def _get_method(self) -> Function[Any]:
2107 return self.sampling
2108
2109
2110class CTE(
2111 roles.DMLTableRole,
2112 roles.IsCTERole,
2113 Generative,
2114 HasPrefixes,
2115 HasSuffixes,
2116 AliasedReturnsRows,
2117):
2118 """Represent a Common Table Expression.
2119
2120 The :class:`_expression.CTE` object is obtained using the
2121 :meth:`_sql.SelectBase.cte` method from any SELECT statement. A less often
2122 available syntax also allows use of the :meth:`_sql.HasCTE.cte` method
2123 present on :term:`DML` constructs such as :class:`_sql.Insert`,
2124 :class:`_sql.Update` and
2125 :class:`_sql.Delete`. See the :meth:`_sql.HasCTE.cte` method for
2126 usage details on CTEs.
2127
2128 .. seealso::
2129
2130 :ref:`tutorial_subqueries_ctes` - in the 2.0 tutorial
2131
2132 :meth:`_sql.HasCTE.cte` - examples of calling styles
2133
2134 """
2135
2136 __visit_name__ = "cte"
2137
2138 _traverse_internals: _TraverseInternalsType = (
2139 AliasedReturnsRows._traverse_internals
2140 + [
2141 ("_cte_alias", InternalTraversal.dp_clauseelement),
2142 ("_restates", InternalTraversal.dp_clauseelement),
2143 ("recursive", InternalTraversal.dp_boolean),
2144 ("nesting", InternalTraversal.dp_boolean),
2145 ]
2146 + HasPrefixes._has_prefixes_traverse_internals
2147 + HasSuffixes._has_suffixes_traverse_internals
2148 )
2149
2150 element: HasCTE
2151
2152 @classmethod
2153 def _factory(
2154 cls,
2155 selectable: HasCTE,
2156 name: Optional[str] = None,
2157 recursive: bool = False,
2158 ) -> CTE:
2159 r"""Return a new :class:`_expression.CTE`,
2160 or Common Table Expression instance.
2161
2162 Please see :meth:`_expression.HasCTE.cte` for detail on CTE usage.
2163
2164 """
2165 return coercions.expect(roles.HasCTERole, selectable).cte(
2166 name=name, recursive=recursive
2167 )
2168
2169 def _init(
2170 self,
2171 selectable: Select[Any],
2172 *,
2173 name: Optional[str] = None,
2174 recursive: bool = False,
2175 nesting: bool = False,
2176 _cte_alias: Optional[CTE] = None,
2177 _restates: Optional[CTE] = None,
2178 _prefixes: Optional[Tuple[()]] = None,
2179 _suffixes: Optional[Tuple[()]] = None,
2180 ) -> None:
2181 self.recursive = recursive
2182 self.nesting = nesting
2183 self._cte_alias = _cte_alias
2184 # Keep recursivity reference with union/union_all
2185 self._restates = _restates
2186 if _prefixes:
2187 self._prefixes = _prefixes
2188 if _suffixes:
2189 self._suffixes = _suffixes
2190 super()._init(selectable, name=name)
2191
2192 def _populate_column_collection(
2193 self,
2194 columns: ColumnCollection[str, KeyedColumnElement[Any]],
2195 primary_key: ColumnSet,
2196 foreign_keys: Set[KeyedColumnElement[Any]],
2197 ) -> None:
2198 if self._cte_alias is not None:
2199 self._cte_alias._generate_fromclause_column_proxies(
2200 self,
2201 columns,
2202 primary_key=primary_key,
2203 foreign_keys=foreign_keys,
2204 )
2205 else:
2206 self.element._generate_fromclause_column_proxies(
2207 self,
2208 columns,
2209 primary_key=primary_key,
2210 foreign_keys=foreign_keys,
2211 )
2212
2213 def alias(self, name: Optional[str] = None, flat: bool = False) -> CTE:
2214 """Return an :class:`_expression.Alias` of this
2215 :class:`_expression.CTE`.
2216
2217 This method is a CTE-specific specialization of the
2218 :meth:`_expression.FromClause.alias` method.
2219
2220 .. seealso::
2221
2222 :ref:`tutorial_using_aliases`
2223
2224 :func:`_expression.alias`
2225
2226 """
2227 return CTE._construct(
2228 self.element,
2229 name=name,
2230 recursive=self.recursive,
2231 nesting=self.nesting,
2232 _cte_alias=self,
2233 _prefixes=self._prefixes,
2234 _suffixes=self._suffixes,
2235 )
2236
2237 def union(self, *other: _SelectStatementForCompoundArgument[Any]) -> CTE:
2238 r"""Return a new :class:`_expression.CTE` with a SQL ``UNION``
2239 of the original CTE against the given selectables provided
2240 as positional arguments.
2241
2242 :param \*other: one or more elements with which to create a
2243 UNION.
2244
2245 .. versionchanged:: 1.4.28 multiple elements are now accepted.
2246
2247 .. seealso::
2248
2249 :meth:`_sql.HasCTE.cte` - examples of calling styles
2250
2251 """
2252 assert is_select_statement(
2253 self.element
2254 ), f"CTE element f{self.element} does not support union()"
2255
2256 return CTE._construct(
2257 self.element.union(*other),
2258 name=self.name,
2259 recursive=self.recursive,
2260 nesting=self.nesting,
2261 _restates=self,
2262 _prefixes=self._prefixes,
2263 _suffixes=self._suffixes,
2264 )
2265
2266 def union_all(
2267 self, *other: _SelectStatementForCompoundArgument[Any]
2268 ) -> CTE:
2269 r"""Return a new :class:`_expression.CTE` with a SQL ``UNION ALL``
2270 of the original CTE against the given selectables provided
2271 as positional arguments.
2272
2273 :param \*other: one or more elements with which to create a
2274 UNION.
2275
2276 .. versionchanged:: 1.4.28 multiple elements are now accepted.
2277
2278 .. seealso::
2279
2280 :meth:`_sql.HasCTE.cte` - examples of calling styles
2281
2282 """
2283
2284 assert is_select_statement(
2285 self.element
2286 ), f"CTE element f{self.element} does not support union_all()"
2287
2288 return CTE._construct(
2289 self.element.union_all(*other),
2290 name=self.name,
2291 recursive=self.recursive,
2292 nesting=self.nesting,
2293 _restates=self,
2294 _prefixes=self._prefixes,
2295 _suffixes=self._suffixes,
2296 )
2297
2298 def _get_reference_cte(self) -> CTE:
2299 """
2300 A recursive CTE is updated to attach the recursive part.
2301 Updated CTEs should still refer to the original CTE.
2302 This function returns this reference identifier.
2303 """
2304 return self._restates if self._restates is not None else self
2305
2306
2307class _CTEOpts(NamedTuple):
2308 nesting: bool
2309
2310
2311class _ColumnsPlusNames(NamedTuple):
2312 required_label_name: Optional[str]
2313 """
2314 string label name, if non-None, must be rendered as a
2315 label, i.e. "AS <name>"
2316 """
2317
2318 proxy_key: Optional[str]
2319 """
2320 proxy_key that is to be part of the result map for this
2321 col. this is also the key in a fromclause.c or
2322 select.selected_columns collection
2323 """
2324
2325 fallback_label_name: Optional[str]
2326 """
2327 name that can be used to render an "AS <name>" when
2328 we have to render a label even though
2329 required_label_name was not given
2330 """
2331
2332 column: Union[ColumnElement[Any], TextClause]
2333 """
2334 the ColumnElement itself
2335 """
2336
2337 repeated: bool
2338 """
2339 True if this is a duplicate of a previous column
2340 in the list of columns
2341 """
2342
2343
2344class SelectsRows(ReturnsRows):
2345 """Sub-base of ReturnsRows for elements that deliver rows
2346 directly, namely SELECT and INSERT/UPDATE/DELETE..RETURNING"""
2347
2348 _label_style: SelectLabelStyle = LABEL_STYLE_NONE
2349
2350 def _generate_columns_plus_names(
2351 self,
2352 anon_for_dupe_key: bool,
2353 cols: Optional[_SelectIterable] = None,
2354 ) -> List[_ColumnsPlusNames]:
2355 """Generate column names as rendered in a SELECT statement by
2356 the compiler.
2357
2358 This is distinct from the _column_naming_convention generator that's
2359 intended for population of .c collections and similar, which has
2360 different rules. the collection returned here calls upon the
2361 _column_naming_convention as well.
2362
2363 """
2364
2365 if cols is None:
2366 cols = self._all_selected_columns
2367
2368 key_naming_convention = SelectState._column_naming_convention(
2369 self._label_style
2370 )
2371
2372 names = {}
2373
2374 result: List[_ColumnsPlusNames] = []
2375 result_append = result.append
2376
2377 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL
2378 label_style_none = self._label_style is LABEL_STYLE_NONE
2379
2380 # a counter used for "dedupe" labels, which have double underscores
2381 # in them and are never referred by name; they only act
2382 # as positional placeholders. they need only be unique within
2383 # the single columns clause they're rendered within (required by
2384 # some dbs such as mysql). So their anon identity is tracked against
2385 # a fixed counter rather than hash() identity.
2386 dedupe_hash = 1
2387
2388 for c in cols:
2389 repeated = False
2390
2391 if not c._render_label_in_columns_clause:
2392 effective_name = required_label_name = fallback_label_name = (
2393 None
2394 )
2395 elif label_style_none:
2396 if TYPE_CHECKING:
2397 assert is_column_element(c)
2398
2399 effective_name = required_label_name = None
2400 fallback_label_name = c._non_anon_label or c._anon_name_label
2401 else:
2402 if TYPE_CHECKING:
2403 assert is_column_element(c)
2404
2405 if table_qualified:
2406 required_label_name = effective_name = (
2407 fallback_label_name
2408 ) = c._tq_label
2409 else:
2410 effective_name = fallback_label_name = c._non_anon_label
2411 required_label_name = None
2412
2413 if effective_name is None:
2414 # it seems like this could be _proxy_key and we would
2415 # not need _expression_label but it isn't
2416 # giving us a clue when to use anon_label instead
2417 expr_label = c._expression_label
2418 if expr_label is None:
2419 repeated = c._anon_name_label in names
2420 names[c._anon_name_label] = c
2421 effective_name = required_label_name = None
2422
2423 if repeated:
2424 # here, "required_label_name" is sent as
2425 # "None" and "fallback_label_name" is sent.
2426 if table_qualified:
2427 fallback_label_name = (
2428 c._dedupe_anon_tq_label_idx(dedupe_hash)
2429 )
2430 dedupe_hash += 1
2431 else:
2432 fallback_label_name = c._dedupe_anon_label_idx(
2433 dedupe_hash
2434 )
2435 dedupe_hash += 1
2436 else:
2437 fallback_label_name = c._anon_name_label
2438 else:
2439 required_label_name = effective_name = (
2440 fallback_label_name
2441 ) = expr_label
2442
2443 if effective_name is not None:
2444 if TYPE_CHECKING:
2445 assert is_column_element(c)
2446
2447 if effective_name in names:
2448 # when looking to see if names[name] is the same column as
2449 # c, use hash(), so that an annotated version of the column
2450 # is seen as the same as the non-annotated
2451 if hash(names[effective_name]) != hash(c):
2452 # different column under the same name. apply
2453 # disambiguating label
2454 if table_qualified:
2455 required_label_name = fallback_label_name = (
2456 c._anon_tq_label
2457 )
2458 else:
2459 required_label_name = fallback_label_name = (
2460 c._anon_name_label
2461 )
2462
2463 if anon_for_dupe_key and required_label_name in names:
2464 # here, c._anon_tq_label is definitely unique to
2465 # that column identity (or annotated version), so
2466 # this should always be true.
2467 # this is also an infrequent codepath because
2468 # you need two levels of duplication to be here
2469 assert hash(names[required_label_name]) == hash(c)
2470
2471 # the column under the disambiguating label is
2472 # already present. apply the "dedupe" label to
2473 # subsequent occurrences of the column so that the
2474 # original stays non-ambiguous
2475 if table_qualified:
2476 required_label_name = fallback_label_name = (
2477 c._dedupe_anon_tq_label_idx(dedupe_hash)
2478 )
2479 dedupe_hash += 1
2480 else:
2481 required_label_name = fallback_label_name = (
2482 c._dedupe_anon_label_idx(dedupe_hash)
2483 )
2484 dedupe_hash += 1
2485 repeated = True
2486 else:
2487 names[required_label_name] = c
2488 elif anon_for_dupe_key:
2489 # same column under the same name. apply the "dedupe"
2490 # label so that the original stays non-ambiguous
2491 if table_qualified:
2492 required_label_name = fallback_label_name = (
2493 c._dedupe_anon_tq_label_idx(dedupe_hash)
2494 )
2495 dedupe_hash += 1
2496 else:
2497 required_label_name = fallback_label_name = (
2498 c._dedupe_anon_label_idx(dedupe_hash)
2499 )
2500 dedupe_hash += 1
2501 repeated = True
2502 else:
2503 names[effective_name] = c
2504
2505 result_append(
2506 _ColumnsPlusNames(
2507 required_label_name,
2508 key_naming_convention(c),
2509 fallback_label_name,
2510 c,
2511 repeated,
2512 )
2513 )
2514
2515 return result
2516
2517
2518class HasCTE(roles.HasCTERole, SelectsRows):
2519 """Mixin that declares a class to include CTE support."""
2520
2521 _has_ctes_traverse_internals: _TraverseInternalsType = [
2522 ("_independent_ctes", InternalTraversal.dp_clauseelement_list),
2523 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj),
2524 ]
2525
2526 _independent_ctes: Tuple[CTE, ...] = ()
2527 _independent_ctes_opts: Tuple[_CTEOpts, ...] = ()
2528
2529 name_cte_columns: bool = False
2530 """indicates if this HasCTE as contained within a CTE should compel the CTE
2531 to render the column names of this object in the WITH clause.
2532
2533 .. versionadded:: 2.0.42
2534
2535 """
2536
2537 @_generative
2538 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self:
2539 r"""Add one or more :class:`_sql.CTE` constructs to this statement.
2540
2541 This method will associate the given :class:`_sql.CTE` constructs with
2542 the parent statement such that they will each be unconditionally
2543 rendered in the WITH clause of the final statement, even if not
2544 referenced elsewhere within the statement or any sub-selects.
2545
2546 The optional :paramref:`.HasCTE.add_cte.nest_here` parameter when set
2547 to True will have the effect that each given :class:`_sql.CTE` will
2548 render in a WITH clause rendered directly along with this statement,
2549 rather than being moved to the top of the ultimate rendered statement,
2550 even if this statement is rendered as a subquery within a larger
2551 statement.
2552
2553 This method has two general uses. One is to embed CTE statements that
2554 serve some purpose without being referenced explicitly, such as the use
2555 case of embedding a DML statement such as an INSERT or UPDATE as a CTE
2556 inline with a primary statement that may draw from its results
2557 indirectly. The other is to provide control over the exact placement
2558 of a particular series of CTE constructs that should remain rendered
2559 directly in terms of a particular statement that may be nested in a
2560 larger statement.
2561
2562 E.g.::
2563
2564 from sqlalchemy import table, column, select
2565
2566 t = table("t", column("c1"), column("c2"))
2567
2568 ins = t.insert().values({"c1": "x", "c2": "y"}).cte()
2569
2570 stmt = select(t).add_cte(ins)
2571
2572 Would render:
2573
2574 .. sourcecode:: sql
2575
2576 WITH anon_1 AS (
2577 INSERT INTO t (c1, c2) VALUES (:param_1, :param_2)
2578 )
2579 SELECT t.c1, t.c2
2580 FROM t
2581
2582 Above, the "anon_1" CTE is not referenced in the SELECT
2583 statement, however still accomplishes the task of running an INSERT
2584 statement.
2585
2586 Similarly in a DML-related context, using the PostgreSQL
2587 :class:`_postgresql.Insert` construct to generate an "upsert"::
2588
2589 from sqlalchemy import table, column
2590 from sqlalchemy.dialects.postgresql import insert
2591
2592 t = table("t", column("c1"), column("c2"))
2593
2594 delete_statement_cte = t.delete().where(t.c.c1 < 1).cte("deletions")
2595
2596 insert_stmt = insert(t).values({"c1": 1, "c2": 2})
2597 update_statement = insert_stmt.on_conflict_do_update(
2598 index_elements=[t.c.c1],
2599 set_={
2600 "c1": insert_stmt.excluded.c1,
2601 "c2": insert_stmt.excluded.c2,
2602 },
2603 ).add_cte(delete_statement_cte)
2604
2605 print(update_statement)
2606
2607 The above statement renders as:
2608
2609 .. sourcecode:: sql
2610
2611 WITH deletions AS (
2612 DELETE FROM t WHERE t.c1 < %(c1_1)s
2613 )
2614 INSERT INTO t (c1, c2) VALUES (%(c1)s, %(c2)s)
2615 ON CONFLICT (c1) DO UPDATE SET c1 = excluded.c1, c2 = excluded.c2
2616
2617 .. versionadded:: 1.4.21
2618
2619 :param \*ctes: zero or more :class:`.CTE` constructs.
2620
2621 .. versionchanged:: 2.0 Multiple CTE instances are accepted
2622
2623 :param nest_here: if True, the given CTE or CTEs will be rendered
2624 as though they specified the :paramref:`.HasCTE.cte.nesting` flag
2625 to ``True`` when they were added to this :class:`.HasCTE`.
2626 Assuming the given CTEs are not referenced in an outer-enclosing
2627 statement as well, the CTEs given should render at the level of
2628 this statement when this flag is given.
2629
2630 .. versionadded:: 2.0
2631
2632 .. seealso::
2633
2634 :paramref:`.HasCTE.cte.nesting`
2635
2636
2637 """ # noqa: E501
2638 opt = _CTEOpts(nest_here)
2639 for cte in ctes:
2640 cte = coercions.expect(roles.IsCTERole, cte)
2641 self._independent_ctes += (cte,)
2642 self._independent_ctes_opts += (opt,)
2643 return self
2644
2645 def cte(
2646 self,
2647 name: Optional[str] = None,
2648 recursive: bool = False,
2649 nesting: bool = False,
2650 ) -> CTE:
2651 r"""Return a new :class:`_expression.CTE`,
2652 or Common Table Expression instance.
2653
2654 Common table expressions are a SQL standard whereby SELECT
2655 statements can draw upon secondary statements specified along
2656 with the primary statement, using a clause called "WITH".
2657 Special semantics regarding UNION can also be employed to
2658 allow "recursive" queries, where a SELECT statement can draw
2659 upon the set of rows that have previously been selected.
2660
2661 CTEs can also be applied to DML constructs UPDATE, INSERT
2662 and DELETE on some databases, both as a source of CTE rows
2663 when combined with RETURNING, as well as a consumer of
2664 CTE rows.
2665
2666 SQLAlchemy detects :class:`_expression.CTE` objects, which are treated
2667 similarly to :class:`_expression.Alias` objects, as special elements
2668 to be delivered to the FROM clause of the statement as well
2669 as to a WITH clause at the top of the statement.
2670
2671 For special prefixes such as PostgreSQL "MATERIALIZED" and
2672 "NOT MATERIALIZED", the :meth:`_expression.CTE.prefix_with`
2673 method may be
2674 used to establish these.
2675
2676 .. versionchanged:: 1.3.13 Added support for prefixes.
2677 In particular - MATERIALIZED and NOT MATERIALIZED.
2678
2679 :param name: name given to the common table expression. Like
2680 :meth:`_expression.FromClause.alias`, the name can be left as
2681 ``None`` in which case an anonymous symbol will be used at query
2682 compile time.
2683 :param recursive: if ``True``, will render ``WITH RECURSIVE``.
2684 A recursive common table expression is intended to be used in
2685 conjunction with UNION ALL in order to derive rows
2686 from those already selected.
2687 :param nesting: if ``True``, will render the CTE locally to the
2688 statement in which it is referenced. For more complex scenarios,
2689 the :meth:`.HasCTE.add_cte` method using the
2690 :paramref:`.HasCTE.add_cte.nest_here`
2691 parameter may also be used to more carefully
2692 control the exact placement of a particular CTE.
2693
2694 .. versionadded:: 1.4.24
2695
2696 .. seealso::
2697
2698 :meth:`.HasCTE.add_cte`
2699
2700 The following examples include two from PostgreSQL's documentation at
2701 https://www.postgresql.org/docs/current/static/queries-with.html,
2702 as well as additional examples.
2703
2704 Example 1, non recursive::
2705
2706 from sqlalchemy import (
2707 Table,
2708 Column,
2709 String,
2710 Integer,
2711 MetaData,
2712 select,
2713 func,
2714 )
2715
2716 metadata = MetaData()
2717
2718 orders = Table(
2719 "orders",
2720 metadata,
2721 Column("region", String),
2722 Column("amount", Integer),
2723 Column("product", String),
2724 Column("quantity", Integer),
2725 )
2726
2727 regional_sales = (
2728 select(orders.c.region, func.sum(orders.c.amount).label("total_sales"))
2729 .group_by(orders.c.region)
2730 .cte("regional_sales")
2731 )
2732
2733
2734 top_regions = (
2735 select(regional_sales.c.region)
2736 .where(
2737 regional_sales.c.total_sales
2738 > select(func.sum(regional_sales.c.total_sales) / 10)
2739 )
2740 .cte("top_regions")
2741 )
2742
2743 statement = (
2744 select(
2745 orders.c.region,
2746 orders.c.product,
2747 func.sum(orders.c.quantity).label("product_units"),
2748 func.sum(orders.c.amount).label("product_sales"),
2749 )
2750 .where(orders.c.region.in_(select(top_regions.c.region)))
2751 .group_by(orders.c.region, orders.c.product)
2752 )
2753
2754 result = conn.execute(statement).fetchall()
2755
2756 Example 2, WITH RECURSIVE::
2757
2758 from sqlalchemy import (
2759 Table,
2760 Column,
2761 String,
2762 Integer,
2763 MetaData,
2764 select,
2765 func,
2766 )
2767
2768 metadata = MetaData()
2769
2770 parts = Table(
2771 "parts",
2772 metadata,
2773 Column("part", String),
2774 Column("sub_part", String),
2775 Column("quantity", Integer),
2776 )
2777
2778 included_parts = (
2779 select(parts.c.sub_part, parts.c.part, parts.c.quantity)
2780 .where(parts.c.part == "our part")
2781 .cte(recursive=True)
2782 )
2783
2784
2785 incl_alias = included_parts.alias()
2786 parts_alias = parts.alias()
2787 included_parts = included_parts.union_all(
2788 select(
2789 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity
2790 ).where(parts_alias.c.part == incl_alias.c.sub_part)
2791 )
2792
2793 statement = select(
2794 included_parts.c.sub_part,
2795 func.sum(included_parts.c.quantity).label("total_quantity"),
2796 ).group_by(included_parts.c.sub_part)
2797
2798 result = conn.execute(statement).fetchall()
2799
2800 Example 3, an upsert using UPDATE and INSERT with CTEs::
2801
2802 from datetime import date
2803 from sqlalchemy import (
2804 MetaData,
2805 Table,
2806 Column,
2807 Integer,
2808 Date,
2809 select,
2810 literal,
2811 and_,
2812 exists,
2813 )
2814
2815 metadata = MetaData()
2816
2817 visitors = Table(
2818 "visitors",
2819 metadata,
2820 Column("product_id", Integer, primary_key=True),
2821 Column("date", Date, primary_key=True),
2822 Column("count", Integer),
2823 )
2824
2825 # add 5 visitors for the product_id == 1
2826 product_id = 1
2827 day = date.today()
2828 count = 5
2829
2830 update_cte = (
2831 visitors.update()
2832 .where(
2833 and_(visitors.c.product_id == product_id, visitors.c.date == day)
2834 )
2835 .values(count=visitors.c.count + count)
2836 .returning(literal(1))
2837 .cte("update_cte")
2838 )
2839
2840 upsert = visitors.insert().from_select(
2841 [visitors.c.product_id, visitors.c.date, visitors.c.count],
2842 select(literal(product_id), literal(day), literal(count)).where(
2843 ~exists(update_cte.select())
2844 ),
2845 )
2846
2847 connection.execute(upsert)
2848
2849 Example 4, Nesting CTE (SQLAlchemy 1.4.24 and above)::
2850
2851 value_a = select(literal("root").label("n")).cte("value_a")
2852
2853 # A nested CTE with the same name as the root one
2854 value_a_nested = select(literal("nesting").label("n")).cte(
2855 "value_a", nesting=True
2856 )
2857
2858 # Nesting CTEs takes ascendency locally
2859 # over the CTEs at a higher level
2860 value_b = select(value_a_nested.c.n).cte("value_b")
2861
2862 value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b"))
2863
2864 The above query will render the second CTE nested inside the first,
2865 shown with inline parameters below as:
2866
2867 .. sourcecode:: sql
2868
2869 WITH
2870 value_a AS
2871 (SELECT 'root' AS n),
2872 value_b AS
2873 (WITH value_a AS
2874 (SELECT 'nesting' AS n)
2875 SELECT value_a.n AS n FROM value_a)
2876 SELECT value_a.n AS a, value_b.n AS b
2877 FROM value_a, value_b
2878
2879 The same CTE can be set up using the :meth:`.HasCTE.add_cte` method
2880 as follows (SQLAlchemy 2.0 and above)::
2881
2882 value_a = select(literal("root").label("n")).cte("value_a")
2883
2884 # A nested CTE with the same name as the root one
2885 value_a_nested = select(literal("nesting").label("n")).cte("value_a")
2886
2887 # Nesting CTEs takes ascendency locally
2888 # over the CTEs at a higher level
2889 value_b = (
2890 select(value_a_nested.c.n)
2891 .add_cte(value_a_nested, nest_here=True)
2892 .cte("value_b")
2893 )
2894
2895 value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b"))
2896
2897 Example 5, Non-Linear CTE (SQLAlchemy 1.4.28 and above)::
2898
2899 edge = Table(
2900 "edge",
2901 metadata,
2902 Column("id", Integer, primary_key=True),
2903 Column("left", Integer),
2904 Column("right", Integer),
2905 )
2906
2907 root_node = select(literal(1).label("node")).cte("nodes", recursive=True)
2908
2909 left_edge = select(edge.c.left).join(
2910 root_node, edge.c.right == root_node.c.node
2911 )
2912 right_edge = select(edge.c.right).join(
2913 root_node, edge.c.left == root_node.c.node
2914 )
2915
2916 subgraph_cte = root_node.union(left_edge, right_edge)
2917
2918 subgraph = select(subgraph_cte)
2919
2920 The above query will render 2 UNIONs inside the recursive CTE:
2921
2922 .. sourcecode:: sql
2923
2924 WITH RECURSIVE nodes(node) AS (
2925 SELECT 1 AS node
2926 UNION
2927 SELECT edge."left" AS "left"
2928 FROM edge JOIN nodes ON edge."right" = nodes.node
2929 UNION
2930 SELECT edge."right" AS "right"
2931 FROM edge JOIN nodes ON edge."left" = nodes.node
2932 )
2933 SELECT nodes.node FROM nodes
2934
2935 .. seealso::
2936
2937 :meth:`_orm.Query.cte` - ORM version of
2938 :meth:`_expression.HasCTE.cte`.
2939
2940 """ # noqa: E501
2941 return CTE._construct(
2942 self, name=name, recursive=recursive, nesting=nesting
2943 )
2944
2945
2946class Subquery(AliasedReturnsRows):
2947 """Represent a subquery of a SELECT.
2948
2949 A :class:`.Subquery` is created by invoking the
2950 :meth:`_expression.SelectBase.subquery` method, or for convenience the
2951 :meth:`_expression.SelectBase.alias` method, on any
2952 :class:`_expression.SelectBase` subclass
2953 which includes :class:`_expression.Select`,
2954 :class:`_expression.CompoundSelect`, and
2955 :class:`_expression.TextualSelect`. As rendered in a FROM clause,
2956 it represents the
2957 body of the SELECT statement inside of parenthesis, followed by the usual
2958 "AS <somename>" that defines all "alias" objects.
2959
2960 The :class:`.Subquery` object is very similar to the
2961 :class:`_expression.Alias`
2962 object and can be used in an equivalent way. The difference between
2963 :class:`_expression.Alias` and :class:`.Subquery` is that
2964 :class:`_expression.Alias` always
2965 contains a :class:`_expression.FromClause` object whereas
2966 :class:`.Subquery`
2967 always contains a :class:`_expression.SelectBase` object.
2968
2969 .. versionadded:: 1.4 The :class:`.Subquery` class was added which now
2970 serves the purpose of providing an aliased version of a SELECT
2971 statement.
2972
2973 """
2974
2975 __visit_name__ = "subquery"
2976
2977 _is_subquery = True
2978
2979 inherit_cache = True
2980
2981 element: SelectBase
2982
2983 @classmethod
2984 def _factory(
2985 cls, selectable: SelectBase, name: Optional[str] = None
2986 ) -> Subquery:
2987 """Return a :class:`.Subquery` object."""
2988
2989 return coercions.expect(
2990 roles.SelectStatementRole, selectable
2991 ).subquery(name=name)
2992
2993 @util.deprecated(
2994 "1.4",
2995 "The :meth:`.Subquery.as_scalar` method, which was previously "
2996 "``Alias.as_scalar()`` prior to version 1.4, is deprecated and "
2997 "will be removed in a future release; Please use the "
2998 ":meth:`_expression.Select.scalar_subquery` method of the "
2999 ":func:`_expression.select` "
3000 "construct before constructing a subquery object, or with the ORM "
3001 "use the :meth:`_query.Query.scalar_subquery` method.",
3002 )
3003 def as_scalar(self) -> ScalarSelect[Any]:
3004 return self.element.set_label_style(LABEL_STYLE_NONE).scalar_subquery()
3005
3006
3007class FromGrouping(GroupedElement, FromClause):
3008 """Represent a grouping of a FROM clause"""
3009
3010 _traverse_internals: _TraverseInternalsType = [
3011 ("element", InternalTraversal.dp_clauseelement)
3012 ]
3013
3014 element: FromClause
3015
3016 def __init__(self, element: FromClause):
3017 self.element = coercions.expect(roles.FromClauseRole, element)
3018
3019 @util.ro_non_memoized_property
3020 def columns(
3021 self,
3022 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
3023 return self.element.columns
3024
3025 @util.ro_non_memoized_property
3026 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
3027 return self.element.columns
3028
3029 @property
3030 def primary_key(self) -> Iterable[NamedColumn[Any]]:
3031 return self.element.primary_key
3032
3033 @property
3034 def foreign_keys(self) -> Iterable[ForeignKey]:
3035 return self.element.foreign_keys
3036
3037 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
3038 return self.element.is_derived_from(fromclause)
3039
3040 def alias(
3041 self, name: Optional[str] = None, flat: bool = False
3042 ) -> NamedFromGrouping:
3043 return NamedFromGrouping(self.element.alias(name=name, flat=flat))
3044
3045 def _anonymous_fromclause(self, **kw: Any) -> FromGrouping:
3046 return FromGrouping(self.element._anonymous_fromclause(**kw))
3047
3048 @util.ro_non_memoized_property
3049 def _hide_froms(self) -> Iterable[FromClause]:
3050 return self.element._hide_froms
3051
3052 @util.ro_non_memoized_property
3053 def _from_objects(self) -> List[FromClause]:
3054 return self.element._from_objects
3055
3056 def __getstate__(self) -> Dict[str, FromClause]:
3057 return {"element": self.element}
3058
3059 def __setstate__(self, state: Dict[str, FromClause]) -> None:
3060 self.element = state["element"]
3061
3062 if TYPE_CHECKING:
3063
3064 def self_group(
3065 self, against: Optional[OperatorType] = None
3066 ) -> Self: ...
3067
3068
3069class NamedFromGrouping(FromGrouping, NamedFromClause):
3070 """represent a grouping of a named FROM clause
3071
3072 .. versionadded:: 2.0
3073
3074 """
3075
3076 inherit_cache = True
3077
3078 if TYPE_CHECKING:
3079
3080 def self_group(
3081 self, against: Optional[OperatorType] = None
3082 ) -> Self: ...
3083
3084
3085class TableClause(roles.DMLTableRole, Immutable, NamedFromClause):
3086 """Represents a minimal "table" construct.
3087
3088 This is a lightweight table object that has only a name, a
3089 collection of columns, which are typically produced
3090 by the :func:`_expression.column` function, and a schema::
3091
3092 from sqlalchemy import table, column
3093
3094 user = table(
3095 "user",
3096 column("id"),
3097 column("name"),
3098 column("description"),
3099 )
3100
3101 The :class:`_expression.TableClause` construct serves as the base for
3102 the more commonly used :class:`_schema.Table` object, providing
3103 the usual set of :class:`_expression.FromClause` services including
3104 the ``.c.`` collection and statement generation methods.
3105
3106 It does **not** provide all the additional schema-level services
3107 of :class:`_schema.Table`, including constraints, references to other
3108 tables, or support for :class:`_schema.MetaData`-level services.
3109 It's useful
3110 on its own as an ad-hoc construct used to generate quick SQL
3111 statements when a more fully fledged :class:`_schema.Table`
3112 is not on hand.
3113
3114 """
3115
3116 __visit_name__ = "table"
3117
3118 _traverse_internals: _TraverseInternalsType = [
3119 (
3120 "columns",
3121 InternalTraversal.dp_fromclause_canonical_column_collection,
3122 ),
3123 ("name", InternalTraversal.dp_string),
3124 ("schema", InternalTraversal.dp_string),
3125 ]
3126
3127 _is_table = True
3128
3129 fullname: str
3130
3131 implicit_returning = False
3132 """:class:`_expression.TableClause`
3133 doesn't support having a primary key or column
3134 -level defaults, so implicit returning doesn't apply."""
3135
3136 @util.ro_memoized_property
3137 def _autoincrement_column(self) -> Optional[ColumnClause[Any]]:
3138 """No PK or default support so no autoincrement column."""
3139 return None
3140
3141 def __init__(self, name: str, *columns: ColumnClause[Any], **kw: Any):
3142 super().__init__()
3143 self.name = name
3144 self._columns = DedupeColumnCollection()
3145 self.primary_key = ColumnSet() # type: ignore
3146 self.foreign_keys = set() # type: ignore
3147 for c in columns:
3148 self.append_column(c)
3149
3150 schema = kw.pop("schema", None)
3151 if schema is not None:
3152 self.schema = schema
3153 if self.schema is not None:
3154 self.fullname = "%s.%s" % (self.schema, self.name)
3155 else:
3156 self.fullname = self.name
3157 if kw:
3158 raise exc.ArgumentError("Unsupported argument(s): %s" % list(kw))
3159
3160 if TYPE_CHECKING:
3161
3162 @util.ro_non_memoized_property
3163 def columns(
3164 self,
3165 ) -> ReadOnlyColumnCollection[str, ColumnClause[Any]]: ...
3166
3167 @util.ro_non_memoized_property
3168 def c(self) -> ReadOnlyColumnCollection[str, ColumnClause[Any]]: ...
3169
3170 def __str__(self) -> str:
3171 if self.schema is not None:
3172 return self.schema + "." + self.name
3173 else:
3174 return self.name
3175
3176 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
3177 pass
3178
3179 @util.ro_memoized_property
3180 def description(self) -> str:
3181 return self.name
3182
3183 def append_column(self, c: ColumnClause[Any]) -> None:
3184 existing = c.table
3185 if existing is not None and existing is not self:
3186 raise exc.ArgumentError(
3187 "column object '%s' already assigned to table '%s'"
3188 % (c.key, existing)
3189 )
3190
3191 self._columns.add(c)
3192 c.table = self
3193
3194 @util.preload_module("sqlalchemy.sql.dml")
3195 def insert(self) -> util.preloaded.sql_dml.Insert:
3196 """Generate an :class:`_sql.Insert` construct against this
3197 :class:`_expression.TableClause`.
3198
3199 E.g.::
3200
3201 table.insert().values(name="foo")
3202
3203 See :func:`_expression.insert` for argument and usage information.
3204
3205 """
3206
3207 return util.preloaded.sql_dml.Insert(self)
3208
3209 @util.preload_module("sqlalchemy.sql.dml")
3210 def update(self) -> Update:
3211 """Generate an :func:`_expression.update` construct against this
3212 :class:`_expression.TableClause`.
3213
3214 E.g.::
3215
3216 table.update().where(table.c.id == 7).values(name="foo")
3217
3218 See :func:`_expression.update` for argument and usage information.
3219
3220 """
3221 return util.preloaded.sql_dml.Update(
3222 self,
3223 )
3224
3225 @util.preload_module("sqlalchemy.sql.dml")
3226 def delete(self) -> Delete:
3227 """Generate a :func:`_expression.delete` construct against this
3228 :class:`_expression.TableClause`.
3229
3230 E.g.::
3231
3232 table.delete().where(table.c.id == 7)
3233
3234 See :func:`_expression.delete` for argument and usage information.
3235
3236 """
3237 return util.preloaded.sql_dml.Delete(self)
3238
3239 @util.ro_non_memoized_property
3240 def _from_objects(self) -> List[FromClause]:
3241 return [self]
3242
3243
3244ForUpdateParameter = Union["ForUpdateArg", None, bool, Dict[str, Any]]
3245
3246
3247class ForUpdateArg(ClauseElement):
3248 _traverse_internals: _TraverseInternalsType = [
3249 ("of", InternalTraversal.dp_clauseelement_list),
3250 ("nowait", InternalTraversal.dp_boolean),
3251 ("read", InternalTraversal.dp_boolean),
3252 ("skip_locked", InternalTraversal.dp_boolean),
3253 ("key_share", InternalTraversal.dp_boolean),
3254 ]
3255
3256 of: Optional[Sequence[ClauseElement]]
3257 nowait: bool
3258 read: bool
3259 skip_locked: bool
3260
3261 @classmethod
3262 def _from_argument(
3263 cls, with_for_update: ForUpdateParameter
3264 ) -> Optional[ForUpdateArg]:
3265 if isinstance(with_for_update, ForUpdateArg):
3266 return with_for_update
3267 elif with_for_update in (None, False):
3268 return None
3269 elif with_for_update is True:
3270 return ForUpdateArg()
3271 else:
3272 return ForUpdateArg(**cast("Dict[str, Any]", with_for_update))
3273
3274 def __eq__(self, other: Any) -> bool:
3275 return (
3276 isinstance(other, ForUpdateArg)
3277 and other.nowait == self.nowait
3278 and other.read == self.read
3279 and other.skip_locked == self.skip_locked
3280 and other.key_share == self.key_share
3281 and other.of is self.of
3282 )
3283
3284 def __ne__(self, other: Any) -> bool:
3285 return not self.__eq__(other)
3286
3287 def __hash__(self) -> int:
3288 return id(self)
3289
3290 def __init__(
3291 self,
3292 *,
3293 nowait: bool = False,
3294 read: bool = False,
3295 of: Optional[_ForUpdateOfArgument] = None,
3296 skip_locked: bool = False,
3297 key_share: bool = False,
3298 ):
3299 """Represents arguments specified to
3300 :meth:`_expression.Select.for_update`.
3301
3302 """
3303
3304 self.nowait = nowait
3305 self.read = read
3306 self.skip_locked = skip_locked
3307 self.key_share = key_share
3308 if of is not None:
3309 self.of = [
3310 coercions.expect(roles.ColumnsClauseRole, elem)
3311 for elem in util.to_list(of)
3312 ]
3313 else:
3314 self.of = None
3315
3316
3317class Values(roles.InElementRole, HasCTE, Generative, LateralFromClause):
3318 """Represent a ``VALUES`` construct that can be used as a FROM element
3319 in a statement.
3320
3321 The :class:`_expression.Values` object is created from the
3322 :func:`_expression.values` function.
3323
3324 .. versionadded:: 1.4
3325
3326 """
3327
3328 __visit_name__ = "values"
3329
3330 _data: Tuple[Sequence[Tuple[Any, ...]], ...] = ()
3331
3332 _unnamed: bool
3333 _traverse_internals: _TraverseInternalsType = [
3334 ("_column_args", InternalTraversal.dp_clauseelement_list),
3335 ("_data", InternalTraversal.dp_dml_multi_values),
3336 ("name", InternalTraversal.dp_string),
3337 ("literal_binds", InternalTraversal.dp_boolean),
3338 ] + HasCTE._has_ctes_traverse_internals
3339
3340 name_cte_columns = True
3341
3342 def __init__(
3343 self,
3344 *columns: ColumnClause[Any],
3345 name: Optional[str] = None,
3346 literal_binds: bool = False,
3347 ):
3348 super().__init__()
3349 self._column_args = columns
3350
3351 if name is None:
3352 self._unnamed = True
3353 self.name = _anonymous_label.safe_construct(id(self), "anon")
3354 else:
3355 self._unnamed = False
3356 self.name = name
3357 self.literal_binds = literal_binds
3358 self.named_with_column = not self._unnamed
3359
3360 @property
3361 def _column_types(self) -> List[TypeEngine[Any]]:
3362 return [col.type for col in self._column_args]
3363
3364 @util.ro_non_memoized_property
3365 def _all_selected_columns(self) -> _SelectIterable:
3366 return self._column_args
3367
3368 @_generative
3369 def alias(self, name: Optional[str] = None, flat: bool = False) -> Self:
3370 """Return a new :class:`_expression.Values`
3371 construct that is a copy of this
3372 one with the given name.
3373
3374 This method is a VALUES-specific specialization of the
3375 :meth:`_expression.FromClause.alias` method.
3376
3377 .. seealso::
3378
3379 :ref:`tutorial_using_aliases`
3380
3381 :func:`_expression.alias`
3382
3383 """
3384 non_none_name: str
3385
3386 if name is None:
3387 non_none_name = _anonymous_label.safe_construct(id(self), "anon")
3388 else:
3389 non_none_name = name
3390
3391 self.name = non_none_name
3392 self.named_with_column = True
3393 self._unnamed = False
3394 return self
3395
3396 @_generative
3397 def lateral(self, name: Optional[str] = None) -> Self:
3398 """Return a new :class:`_expression.Values` with the lateral flag set,
3399 so that
3400 it renders as LATERAL.
3401
3402 .. seealso::
3403
3404 :func:`_expression.lateral`
3405
3406 """
3407 non_none_name: str
3408
3409 if name is None:
3410 non_none_name = self.name
3411 else:
3412 non_none_name = name
3413
3414 self._is_lateral = True
3415 self.name = non_none_name
3416 self._unnamed = False
3417 return self
3418
3419 @_generative
3420 def data(self, values: Sequence[Tuple[Any, ...]]) -> Self:
3421 """Return a new :class:`_expression.Values` construct,
3422 adding the given data to the data list.
3423
3424 E.g.::
3425
3426 my_values = my_values.data([(1, "value 1"), (2, "value2")])
3427
3428 :param values: a sequence (i.e. list) of tuples that map to the
3429 column expressions given in the :class:`_expression.Values`
3430 constructor.
3431
3432 """
3433
3434 self._data += (values,)
3435 return self
3436
3437 def scalar_values(self) -> ScalarValues:
3438 """Returns a scalar ``VALUES`` construct that can be used as a
3439 COLUMN element in a statement.
3440
3441 .. versionadded:: 2.0.0b4
3442
3443 """
3444 return ScalarValues(self._column_args, self._data, self.literal_binds)
3445
3446 def _populate_column_collection(
3447 self,
3448 columns: ColumnCollection[str, KeyedColumnElement[Any]],
3449 primary_key: ColumnSet,
3450 foreign_keys: Set[KeyedColumnElement[Any]],
3451 ) -> None:
3452 for c in self._column_args:
3453 if c.table is not None and c.table is not self:
3454 _, c = c._make_proxy(
3455 self, primary_key=primary_key, foreign_keys=foreign_keys
3456 )
3457 else:
3458 # if the column was used in other contexts, ensure
3459 # no memoizations of other FROM clauses.
3460 # see test_values.py -> test_auto_proxy_select_direct_col
3461 c._reset_memoizations()
3462 columns.add(c)
3463 c.table = self
3464
3465 @util.ro_non_memoized_property
3466 def _from_objects(self) -> List[FromClause]:
3467 return [self]
3468
3469
3470class ScalarValues(roles.InElementRole, GroupedElement, ColumnElement[Any]):
3471 """Represent a scalar ``VALUES`` construct that can be used as a
3472 COLUMN element in a statement.
3473
3474 The :class:`_expression.ScalarValues` object is created from the
3475 :meth:`_expression.Values.scalar_values` method. It's also
3476 automatically generated when a :class:`_expression.Values` is used in
3477 an ``IN`` or ``NOT IN`` condition.
3478
3479 .. versionadded:: 2.0.0b4
3480
3481 """
3482
3483 __visit_name__ = "scalar_values"
3484
3485 _traverse_internals: _TraverseInternalsType = [
3486 ("_column_args", InternalTraversal.dp_clauseelement_list),
3487 ("_data", InternalTraversal.dp_dml_multi_values),
3488 ("literal_binds", InternalTraversal.dp_boolean),
3489 ]
3490
3491 def __init__(
3492 self,
3493 columns: Sequence[ColumnClause[Any]],
3494 data: Tuple[Sequence[Tuple[Any, ...]], ...],
3495 literal_binds: bool,
3496 ):
3497 super().__init__()
3498 self._column_args = columns
3499 self._data = data
3500 self.literal_binds = literal_binds
3501
3502 @property
3503 def _column_types(self) -> List[TypeEngine[Any]]:
3504 return [col.type for col in self._column_args]
3505
3506 def __clause_element__(self) -> ScalarValues:
3507 return self
3508
3509 if TYPE_CHECKING:
3510
3511 def self_group(
3512 self, against: Optional[OperatorType] = None
3513 ) -> Self: ...
3514
3515 def _ungroup(self) -> ColumnElement[Any]: ...
3516
3517
3518class SelectBase(
3519 roles.SelectStatementRole,
3520 roles.DMLSelectRole,
3521 roles.CompoundElementRole,
3522 roles.InElementRole,
3523 HasCTE,
3524 SupportsCloneAnnotations,
3525 Selectable,
3526):
3527 """Base class for SELECT statements.
3528
3529
3530 This includes :class:`_expression.Select`,
3531 :class:`_expression.CompoundSelect` and
3532 :class:`_expression.TextualSelect`.
3533
3534
3535 """
3536
3537 _is_select_base = True
3538 is_select = True
3539
3540 _label_style: SelectLabelStyle = LABEL_STYLE_NONE
3541
3542 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
3543 self._reset_memoizations()
3544
3545 @util.ro_non_memoized_property
3546 def selected_columns(
3547 self,
3548 ) -> ColumnCollection[str, ColumnElement[Any]]:
3549 """A :class:`_expression.ColumnCollection`
3550 representing the columns that
3551 this SELECT statement or similar construct returns in its result set.
3552
3553 This collection differs from the :attr:`_expression.FromClause.columns`
3554 collection of a :class:`_expression.FromClause` in that the columns
3555 within this collection cannot be directly nested inside another SELECT
3556 statement; a subquery must be applied first which provides for the
3557 necessary parenthesization required by SQL.
3558
3559 .. note::
3560
3561 The :attr:`_sql.SelectBase.selected_columns` collection does not
3562 include expressions established in the columns clause using the
3563 :func:`_sql.text` construct; these are silently omitted from the
3564 collection. To use plain textual column expressions inside of a
3565 :class:`_sql.Select` construct, use the :func:`_sql.literal_column`
3566 construct.
3567
3568 .. seealso::
3569
3570 :attr:`_sql.Select.selected_columns`
3571
3572 .. versionadded:: 1.4
3573
3574 """
3575 raise NotImplementedError()
3576
3577 def _generate_fromclause_column_proxies(
3578 self,
3579 subquery: FromClause,
3580 columns: ColumnCollection[str, KeyedColumnElement[Any]],
3581 primary_key: ColumnSet,
3582 foreign_keys: Set[KeyedColumnElement[Any]],
3583 *,
3584 proxy_compound_columns: Optional[
3585 Iterable[Sequence[ColumnElement[Any]]]
3586 ] = None,
3587 ) -> None:
3588 raise NotImplementedError()
3589
3590 @util.ro_non_memoized_property
3591 def _all_selected_columns(self) -> _SelectIterable:
3592 """A sequence of expressions that correspond to what is rendered
3593 in the columns clause, including :class:`_sql.TextClause`
3594 constructs.
3595
3596 .. versionadded:: 1.4.12
3597
3598 .. seealso::
3599
3600 :attr:`_sql.SelectBase.exported_columns`
3601
3602 """
3603 raise NotImplementedError()
3604
3605 @property
3606 def exported_columns(
3607 self,
3608 ) -> ReadOnlyColumnCollection[str, ColumnElement[Any]]:
3609 """A :class:`_expression.ColumnCollection`
3610 that represents the "exported"
3611 columns of this :class:`_expression.Selectable`, not including
3612 :class:`_sql.TextClause` constructs.
3613
3614 The "exported" columns for a :class:`_expression.SelectBase`
3615 object are synonymous
3616 with the :attr:`_expression.SelectBase.selected_columns` collection.
3617
3618 .. versionadded:: 1.4
3619
3620 .. seealso::
3621
3622 :attr:`_expression.Select.exported_columns`
3623
3624 :attr:`_expression.Selectable.exported_columns`
3625
3626 :attr:`_expression.FromClause.exported_columns`
3627
3628
3629 """
3630 return self.selected_columns.as_readonly()
3631
3632 @property
3633 @util.deprecated(
3634 "1.4",
3635 "The :attr:`_expression.SelectBase.c` and "
3636 ":attr:`_expression.SelectBase.columns` attributes "
3637 "are deprecated and will be removed in a future release; these "
3638 "attributes implicitly create a subquery that should be explicit. "
3639 "Please call :meth:`_expression.SelectBase.subquery` "
3640 "first in order to create "
3641 "a subquery, which then contains this attribute. To access the "
3642 "columns that this SELECT object SELECTs "
3643 "from, use the :attr:`_expression.SelectBase.selected_columns` "
3644 "attribute.",
3645 )
3646 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
3647 return self._implicit_subquery.columns
3648
3649 @property
3650 def columns(
3651 self,
3652 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
3653 return self.c
3654
3655 def get_label_style(self) -> SelectLabelStyle:
3656 """
3657 Retrieve the current label style.
3658
3659 Implemented by subclasses.
3660
3661 """
3662 raise NotImplementedError()
3663
3664 def set_label_style(self, style: SelectLabelStyle) -> Self:
3665 """Return a new selectable with the specified label style.
3666
3667 Implemented by subclasses.
3668
3669 """
3670
3671 raise NotImplementedError()
3672
3673 @util.deprecated(
3674 "1.4",
3675 "The :meth:`_expression.SelectBase.select` method is deprecated "
3676 "and will be removed in a future release; this method implicitly "
3677 "creates a subquery that should be explicit. "
3678 "Please call :meth:`_expression.SelectBase.subquery` "
3679 "first in order to create "
3680 "a subquery, which then can be selected.",
3681 )
3682 def select(self, *arg: Any, **kw: Any) -> Select[Any]:
3683 return self._implicit_subquery.select(*arg, **kw)
3684
3685 @HasMemoized.memoized_attribute
3686 def _implicit_subquery(self) -> Subquery:
3687 return self.subquery()
3688
3689 def _scalar_type(self) -> TypeEngine[Any]:
3690 raise NotImplementedError()
3691
3692 @util.deprecated(
3693 "1.4",
3694 "The :meth:`_expression.SelectBase.as_scalar` "
3695 "method is deprecated and will be "
3696 "removed in a future release. Please refer to "
3697 ":meth:`_expression.SelectBase.scalar_subquery`.",
3698 )
3699 def as_scalar(self) -> ScalarSelect[Any]:
3700 return self.scalar_subquery()
3701
3702 def exists(self) -> Exists:
3703 """Return an :class:`_sql.Exists` representation of this selectable,
3704 which can be used as a column expression.
3705
3706 The returned object is an instance of :class:`_sql.Exists`.
3707
3708 .. seealso::
3709
3710 :func:`_sql.exists`
3711
3712 :ref:`tutorial_exists` - in the :term:`2.0 style` tutorial.
3713
3714 .. versionadded:: 1.4
3715
3716 """
3717 return Exists(self)
3718
3719 def scalar_subquery(self) -> ScalarSelect[Any]:
3720 """Return a 'scalar' representation of this selectable, which can be
3721 used as a column expression.
3722
3723 The returned object is an instance of :class:`_sql.ScalarSelect`.
3724
3725 Typically, a select statement which has only one column in its columns
3726 clause is eligible to be used as a scalar expression. The scalar
3727 subquery can then be used in the WHERE clause or columns clause of
3728 an enclosing SELECT.
3729
3730 Note that the scalar subquery differentiates from the FROM-level
3731 subquery that can be produced using the
3732 :meth:`_expression.SelectBase.subquery`
3733 method.
3734
3735 .. versionchanged: 1.4 - the ``.as_scalar()`` method was renamed to
3736 :meth:`_expression.SelectBase.scalar_subquery`.
3737
3738 .. seealso::
3739
3740 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
3741
3742 """
3743 if self._label_style is not LABEL_STYLE_NONE:
3744 self = self.set_label_style(LABEL_STYLE_NONE)
3745
3746 return ScalarSelect(self)
3747
3748 def label(self, name: Optional[str]) -> Label[Any]:
3749 """Return a 'scalar' representation of this selectable, embedded as a
3750 subquery with a label.
3751
3752 .. seealso::
3753
3754 :meth:`_expression.SelectBase.scalar_subquery`.
3755
3756 """
3757 return self.scalar_subquery().label(name)
3758
3759 def lateral(self, name: Optional[str] = None) -> LateralFromClause:
3760 """Return a LATERAL alias of this :class:`_expression.Selectable`.
3761
3762 The return value is the :class:`_expression.Lateral` construct also
3763 provided by the top-level :func:`_expression.lateral` function.
3764
3765 .. seealso::
3766
3767 :ref:`tutorial_lateral_correlation` - overview of usage.
3768
3769 """
3770 return Lateral._factory(self, name)
3771
3772 def subquery(self, name: Optional[str] = None) -> Subquery:
3773 """Return a subquery of this :class:`_expression.SelectBase`.
3774
3775 A subquery is from a SQL perspective a parenthesized, named
3776 construct that can be placed in the FROM clause of another
3777 SELECT statement.
3778
3779 Given a SELECT statement such as::
3780
3781 stmt = select(table.c.id, table.c.name)
3782
3783 The above statement might look like:
3784
3785 .. sourcecode:: sql
3786
3787 SELECT table.id, table.name FROM table
3788
3789 The subquery form by itself renders the same way, however when
3790 embedded into the FROM clause of another SELECT statement, it becomes
3791 a named sub-element::
3792
3793 subq = stmt.subquery()
3794 new_stmt = select(subq)
3795
3796 The above renders as:
3797
3798 .. sourcecode:: sql
3799
3800 SELECT anon_1.id, anon_1.name
3801 FROM (SELECT table.id, table.name FROM table) AS anon_1
3802
3803 Historically, :meth:`_expression.SelectBase.subquery`
3804 is equivalent to calling
3805 the :meth:`_expression.FromClause.alias`
3806 method on a FROM object; however,
3807 as a :class:`_expression.SelectBase`
3808 object is not directly FROM object,
3809 the :meth:`_expression.SelectBase.subquery`
3810 method provides clearer semantics.
3811
3812 .. versionadded:: 1.4
3813
3814 """
3815
3816 return Subquery._construct(
3817 self._ensure_disambiguated_names(), name=name
3818 )
3819
3820 def _ensure_disambiguated_names(self) -> Self:
3821 """Ensure that the names generated by this selectbase will be
3822 disambiguated in some way, if possible.
3823
3824 """
3825
3826 raise NotImplementedError()
3827
3828 def alias(
3829 self, name: Optional[str] = None, flat: bool = False
3830 ) -> Subquery:
3831 """Return a named subquery against this
3832 :class:`_expression.SelectBase`.
3833
3834 For a :class:`_expression.SelectBase` (as opposed to a
3835 :class:`_expression.FromClause`),
3836 this returns a :class:`.Subquery` object which behaves mostly the
3837 same as the :class:`_expression.Alias` object that is used with a
3838 :class:`_expression.FromClause`.
3839
3840 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias`
3841 method is now
3842 a synonym for the :meth:`_expression.SelectBase.subquery` method.
3843
3844 """
3845 return self.subquery(name=name)
3846
3847
3848_SB = TypeVar("_SB", bound=SelectBase)
3849
3850
3851class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]):
3852 """Represent a grouping of a :class:`_expression.SelectBase`.
3853
3854 This differs from :class:`.Subquery` in that we are still
3855 an "inner" SELECT statement, this is strictly for grouping inside of
3856 compound selects.
3857
3858 """
3859
3860 __visit_name__ = "select_statement_grouping"
3861 _traverse_internals: _TraverseInternalsType = [
3862 ("element", InternalTraversal.dp_clauseelement)
3863 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals
3864
3865 _is_select_container = True
3866
3867 element: _SB
3868
3869 def __init__(self, element: _SB) -> None:
3870 self.element = cast(
3871 _SB, coercions.expect(roles.SelectStatementRole, element)
3872 )
3873
3874 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]:
3875 new_element = self.element._ensure_disambiguated_names()
3876 if new_element is not self.element:
3877 return SelectStatementGrouping(new_element)
3878 else:
3879 return self
3880
3881 def get_label_style(self) -> SelectLabelStyle:
3882 return self.element.get_label_style()
3883
3884 def set_label_style(
3885 self, label_style: SelectLabelStyle
3886 ) -> SelectStatementGrouping[_SB]:
3887 return SelectStatementGrouping(
3888 self.element.set_label_style(label_style)
3889 )
3890
3891 @property
3892 def select_statement(self) -> _SB:
3893 return self.element
3894
3895 def self_group(self, against: Optional[OperatorType] = None) -> Self:
3896 return self
3897
3898 if TYPE_CHECKING:
3899
3900 def _ungroup(self) -> _SB: ...
3901
3902 # def _generate_columns_plus_names(
3903 # self, anon_for_dupe_key: bool
3904 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]:
3905 # return self.element._generate_columns_plus_names(anon_for_dupe_key)
3906
3907 def _generate_fromclause_column_proxies(
3908 self,
3909 subquery: FromClause,
3910 columns: ColumnCollection[str, KeyedColumnElement[Any]],
3911 primary_key: ColumnSet,
3912 foreign_keys: Set[KeyedColumnElement[Any]],
3913 *,
3914 proxy_compound_columns: Optional[
3915 Iterable[Sequence[ColumnElement[Any]]]
3916 ] = None,
3917 ) -> None:
3918 self.element._generate_fromclause_column_proxies(
3919 subquery,
3920 columns,
3921 proxy_compound_columns=proxy_compound_columns,
3922 primary_key=primary_key,
3923 foreign_keys=foreign_keys,
3924 )
3925
3926 @util.ro_non_memoized_property
3927 def _all_selected_columns(self) -> _SelectIterable:
3928 return self.element._all_selected_columns
3929
3930 @util.ro_non_memoized_property
3931 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]:
3932 """A :class:`_expression.ColumnCollection`
3933 representing the columns that
3934 the embedded SELECT statement returns in its result set, not including
3935 :class:`_sql.TextClause` constructs.
3936
3937 .. versionadded:: 1.4
3938
3939 .. seealso::
3940
3941 :attr:`_sql.Select.selected_columns`
3942
3943 """
3944 return self.element.selected_columns
3945
3946 @util.ro_non_memoized_property
3947 def _from_objects(self) -> List[FromClause]:
3948 return self.element._from_objects
3949
3950 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self:
3951 # SelectStatementGrouping not generative: has no attribute '_generate'
3952 raise NotImplementedError
3953
3954
3955class GenerativeSelect(DialectKWArgs, SelectBase, Generative):
3956 """Base class for SELECT statements where additional elements can be
3957 added.
3958
3959 This serves as the base for :class:`_expression.Select` and
3960 :class:`_expression.CompoundSelect`
3961 where elements such as ORDER BY, GROUP BY can be added and column
3962 rendering can be controlled. Compare to
3963 :class:`_expression.TextualSelect`, which,
3964 while it subclasses :class:`_expression.SelectBase`
3965 and is also a SELECT construct,
3966 represents a fixed textual string which cannot be altered at this level,
3967 only wrapped as a subquery.
3968
3969 """
3970
3971 _order_by_clauses: Tuple[ColumnElement[Any], ...] = ()
3972 _group_by_clauses: Tuple[ColumnElement[Any], ...] = ()
3973 _limit_clause: Optional[ColumnElement[Any]] = None
3974 _offset_clause: Optional[ColumnElement[Any]] = None
3975 _fetch_clause: Optional[ColumnElement[Any]] = None
3976 _fetch_clause_options: Optional[Dict[str, bool]] = None
3977 _for_update_arg: Optional[ForUpdateArg] = None
3978
3979 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT):
3980 self._label_style = _label_style
3981
3982 @_generative
3983 def with_for_update(
3984 self,
3985 *,
3986 nowait: bool = False,
3987 read: bool = False,
3988 of: Optional[_ForUpdateOfArgument] = None,
3989 skip_locked: bool = False,
3990 key_share: bool = False,
3991 ) -> Self:
3992 """Specify a ``FOR UPDATE`` clause for this
3993 :class:`_expression.GenerativeSelect`.
3994
3995 E.g.::
3996
3997 stmt = select(table).with_for_update(nowait=True)
3998
3999 On a database like PostgreSQL or Oracle Database, the above would
4000 render a statement like:
4001
4002 .. sourcecode:: sql
4003
4004 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT
4005
4006 on other backends, the ``nowait`` option is ignored and instead
4007 would produce:
4008
4009 .. sourcecode:: sql
4010
4011 SELECT table.a, table.b FROM table FOR UPDATE
4012
4013 When called with no arguments, the statement will render with
4014 the suffix ``FOR UPDATE``. Additional arguments can then be
4015 provided which allow for common database-specific
4016 variants.
4017
4018 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle
4019 Database and PostgreSQL dialects.
4020
4021 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL,
4022 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with
4023 ``nowait``, will render ``FOR SHARE NOWAIT``.
4024
4025 :param of: SQL expression or list of SQL expression elements,
4026 (typically :class:`_schema.Column` objects or a compatible expression,
4027 for some backends may also be a table expression) which will render
4028 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle
4029 Database, some MySQL versions and possibly others. May render as a
4030 table or as a column depending on backend.
4031
4032 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on
4033 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED``
4034 if ``read=True`` is also specified.
4035
4036 :param key_share: boolean, will render ``FOR NO KEY UPDATE``,
4037 or if combined with ``read=True`` will render ``FOR KEY SHARE``,
4038 on the PostgreSQL dialect.
4039
4040 """
4041 self._for_update_arg = ForUpdateArg(
4042 nowait=nowait,
4043 read=read,
4044 of=of,
4045 skip_locked=skip_locked,
4046 key_share=key_share,
4047 )
4048 return self
4049
4050 def get_label_style(self) -> SelectLabelStyle:
4051 """
4052 Retrieve the current label style.
4053
4054 .. versionadded:: 1.4
4055
4056 """
4057 return self._label_style
4058
4059 def set_label_style(self, style: SelectLabelStyle) -> Self:
4060 """Return a new selectable with the specified label style.
4061
4062 There are three "label styles" available,
4063 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`,
4064 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and
4065 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is
4066 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`.
4067
4068 In modern SQLAlchemy, there is not generally a need to change the
4069 labeling style, as per-expression labels are more effectively used by
4070 making use of the :meth:`_sql.ColumnElement.label` method. In past
4071 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to
4072 disambiguate same-named columns from different tables, aliases, or
4073 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now
4074 applies labels only to names that conflict with an existing name so
4075 that the impact of this labeling is minimal.
4076
4077 The rationale for disambiguation is mostly so that all column
4078 expressions are available from a given :attr:`_sql.FromClause.c`
4079 collection when a subquery is created.
4080
4081 .. versionadded:: 1.4 - the
4082 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the
4083 previous combination of ``.apply_labels()``, ``.with_labels()`` and
4084 ``use_labels=True`` methods and/or parameters.
4085
4086 .. seealso::
4087
4088 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`
4089
4090 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`
4091
4092 :data:`_sql.LABEL_STYLE_NONE`
4093
4094 :data:`_sql.LABEL_STYLE_DEFAULT`
4095
4096 """
4097 if self._label_style is not style:
4098 self = self._generate()
4099 self._label_style = style
4100 return self
4101
4102 @property
4103 def _group_by_clause(self) -> ClauseList:
4104 """ClauseList access to group_by_clauses for legacy dialects"""
4105 return ClauseList._construct_raw(
4106 operators.comma_op, self._group_by_clauses
4107 )
4108
4109 @property
4110 def _order_by_clause(self) -> ClauseList:
4111 """ClauseList access to order_by_clauses for legacy dialects"""
4112 return ClauseList._construct_raw(
4113 operators.comma_op, self._order_by_clauses
4114 )
4115
4116 def _offset_or_limit_clause(
4117 self,
4118 element: _LimitOffsetType,
4119 name: Optional[str] = None,
4120 type_: Optional[_TypeEngineArgument[int]] = None,
4121 ) -> ColumnElement[Any]:
4122 """Convert the given value to an "offset or limit" clause.
4123
4124 This handles incoming integers and converts to an expression; if
4125 an expression is already given, it is passed through.
4126
4127 """
4128 return coercions.expect(
4129 roles.LimitOffsetRole, element, name=name, type_=type_
4130 )
4131
4132 @overload
4133 def _offset_or_limit_clause_asint(
4134 self, clause: ColumnElement[Any], attrname: str
4135 ) -> NoReturn: ...
4136
4137 @overload
4138 def _offset_or_limit_clause_asint(
4139 self, clause: Optional[_OffsetLimitParam], attrname: str
4140 ) -> Optional[int]: ...
4141
4142 def _offset_or_limit_clause_asint(
4143 self, clause: Optional[ColumnElement[Any]], attrname: str
4144 ) -> Union[NoReturn, Optional[int]]:
4145 """Convert the "offset or limit" clause of a select construct to an
4146 integer.
4147
4148 This is only possible if the value is stored as a simple bound
4149 parameter. Otherwise, a compilation error is raised.
4150
4151 """
4152 if clause is None:
4153 return None
4154 try:
4155 value = clause._limit_offset_value
4156 except AttributeError as err:
4157 raise exc.CompileError(
4158 "This SELECT structure does not use a simple "
4159 "integer value for %s" % attrname
4160 ) from err
4161 else:
4162 return util.asint(value)
4163
4164 @property
4165 def _limit(self) -> Optional[int]:
4166 """Get an integer value for the limit. This should only be used
4167 by code that cannot support a limit as a BindParameter or
4168 other custom clause as it will throw an exception if the limit
4169 isn't currently set to an integer.
4170
4171 """
4172 return self._offset_or_limit_clause_asint(self._limit_clause, "limit")
4173
4174 def _simple_int_clause(self, clause: ClauseElement) -> bool:
4175 """True if the clause is a simple integer, False
4176 if it is not present or is a SQL expression.
4177 """
4178 return isinstance(clause, _OffsetLimitParam)
4179
4180 @property
4181 def _offset(self) -> Optional[int]:
4182 """Get an integer value for the offset. This should only be used
4183 by code that cannot support an offset as a BindParameter or
4184 other custom clause as it will throw an exception if the
4185 offset isn't currently set to an integer.
4186
4187 """
4188 return self._offset_or_limit_clause_asint(
4189 self._offset_clause, "offset"
4190 )
4191
4192 @property
4193 def _has_row_limiting_clause(self) -> bool:
4194 return (
4195 self._limit_clause is not None
4196 or self._offset_clause is not None
4197 or self._fetch_clause is not None
4198 )
4199
4200 @_generative
4201 def limit(self, limit: _LimitOffsetType) -> Self:
4202 """Return a new selectable with the given LIMIT criterion
4203 applied.
4204
4205 This is a numerical value which usually renders as a ``LIMIT``
4206 expression in the resulting select. Backends that don't
4207 support ``LIMIT`` will attempt to provide similar
4208 functionality.
4209
4210 .. note::
4211
4212 The :meth:`_sql.GenerativeSelect.limit` method will replace
4213 any clause applied with :meth:`_sql.GenerativeSelect.fetch`.
4214
4215 :param limit: an integer LIMIT parameter, or a SQL expression
4216 that provides an integer result. Pass ``None`` to reset it.
4217
4218 .. seealso::
4219
4220 :meth:`_sql.GenerativeSelect.fetch`
4221
4222 :meth:`_sql.GenerativeSelect.offset`
4223
4224 """
4225
4226 self._fetch_clause = self._fetch_clause_options = None
4227 self._limit_clause = self._offset_or_limit_clause(limit)
4228 return self
4229
4230 @_generative
4231 def fetch(
4232 self,
4233 count: _LimitOffsetType,
4234 with_ties: bool = False,
4235 percent: bool = False,
4236 **dialect_kw: Any,
4237 ) -> Self:
4238 r"""Return a new selectable with the given FETCH FIRST criterion
4239 applied.
4240
4241 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT}
4242 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting
4243 select. This functionality is is currently implemented for Oracle
4244 Database, PostgreSQL, MSSQL.
4245
4246 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset.
4247
4248 .. note::
4249
4250 The :meth:`_sql.GenerativeSelect.fetch` method will replace
4251 any clause applied with :meth:`_sql.GenerativeSelect.limit`.
4252
4253 .. versionadded:: 1.4
4254
4255 :param count: an integer COUNT parameter, or a SQL expression
4256 that provides an integer result. When ``percent=True`` this will
4257 represent the percentage of rows to return, not the absolute value.
4258 Pass ``None`` to reset it.
4259
4260 :param with_ties: When ``True``, the WITH TIES option is used
4261 to return any additional rows that tie for the last place in the
4262 result set according to the ``ORDER BY`` clause. The
4263 ``ORDER BY`` may be mandatory in this case. Defaults to ``False``
4264
4265 :param percent: When ``True``, ``count`` represents the percentage
4266 of the total number of selected rows to return. Defaults to ``False``
4267
4268 :param \**dialect_kw: Additional dialect-specific keyword arguments
4269 may be accepted by dialects.
4270
4271 .. versionadded:: 2.0.41
4272
4273 .. seealso::
4274
4275 :meth:`_sql.GenerativeSelect.limit`
4276
4277 :meth:`_sql.GenerativeSelect.offset`
4278
4279 """
4280 self._validate_dialect_kwargs(dialect_kw)
4281 self._limit_clause = None
4282 if count is None:
4283 self._fetch_clause = self._fetch_clause_options = None
4284 else:
4285 self._fetch_clause = self._offset_or_limit_clause(count)
4286 self._fetch_clause_options = {
4287 "with_ties": with_ties,
4288 "percent": percent,
4289 }
4290 return self
4291
4292 @_generative
4293 def offset(self, offset: _LimitOffsetType) -> Self:
4294 """Return a new selectable with the given OFFSET criterion
4295 applied.
4296
4297
4298 This is a numeric value which usually renders as an ``OFFSET``
4299 expression in the resulting select. Backends that don't
4300 support ``OFFSET`` will attempt to provide similar
4301 functionality.
4302
4303 :param offset: an integer OFFSET parameter, or a SQL expression
4304 that provides an integer result. Pass ``None`` to reset it.
4305
4306 .. seealso::
4307
4308 :meth:`_sql.GenerativeSelect.limit`
4309
4310 :meth:`_sql.GenerativeSelect.fetch`
4311
4312 """
4313
4314 self._offset_clause = self._offset_or_limit_clause(offset)
4315 return self
4316
4317 @_generative
4318 @util.preload_module("sqlalchemy.sql.util")
4319 def slice(
4320 self,
4321 start: int,
4322 stop: int,
4323 ) -> Self:
4324 """Apply LIMIT / OFFSET to this statement based on a slice.
4325
4326 The start and stop indices behave like the argument to Python's
4327 built-in :func:`range` function. This method provides an
4328 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the
4329 query.
4330
4331 For example, ::
4332
4333 stmt = select(User).order_by(User.id).slice(1, 3)
4334
4335 renders as
4336
4337 .. sourcecode:: sql
4338
4339 SELECT users.id AS users_id,
4340 users.name AS users_name
4341 FROM users ORDER BY users.id
4342 LIMIT ? OFFSET ?
4343 (2, 1)
4344
4345 .. note::
4346
4347 The :meth:`_sql.GenerativeSelect.slice` method will replace
4348 any clause applied with :meth:`_sql.GenerativeSelect.fetch`.
4349
4350 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice`
4351 method generalized from the ORM.
4352
4353 .. seealso::
4354
4355 :meth:`_sql.GenerativeSelect.limit`
4356
4357 :meth:`_sql.GenerativeSelect.offset`
4358
4359 :meth:`_sql.GenerativeSelect.fetch`
4360
4361 """
4362 sql_util = util.preloaded.sql_util
4363 self._fetch_clause = self._fetch_clause_options = None
4364 self._limit_clause, self._offset_clause = sql_util._make_slice(
4365 self._limit_clause, self._offset_clause, start, stop
4366 )
4367 return self
4368
4369 @_generative
4370 def order_by(
4371 self,
4372 __first: Union[
4373 Literal[None, _NoArg.NO_ARG],
4374 _ColumnExpressionOrStrLabelArgument[Any],
4375 ] = _NoArg.NO_ARG,
4376 *clauses: _ColumnExpressionOrStrLabelArgument[Any],
4377 ) -> Self:
4378 r"""Return a new selectable with the given list of ORDER BY
4379 criteria applied.
4380
4381 e.g.::
4382
4383 stmt = select(table).order_by(table.c.id, table.c.name)
4384
4385 Calling this method multiple times is equivalent to calling it once
4386 with all the clauses concatenated. All existing ORDER BY criteria may
4387 be cancelled by passing ``None`` by itself. New ORDER BY criteria may
4388 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.::
4389
4390 # will erase all ORDER BY and ORDER BY new_col alone
4391 stmt = stmt.order_by(None).order_by(new_col)
4392
4393 :param \*clauses: a series of :class:`_expression.ColumnElement`
4394 constructs
4395 which will be used to generate an ORDER BY clause.
4396
4397 .. seealso::
4398
4399 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial`
4400
4401 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial`
4402
4403 """
4404
4405 if not clauses and __first is None:
4406 self._order_by_clauses = ()
4407 elif __first is not _NoArg.NO_ARG:
4408 self._order_by_clauses += tuple(
4409 coercions.expect(
4410 roles.OrderByRole, clause, apply_propagate_attrs=self
4411 )
4412 for clause in (__first,) + clauses
4413 )
4414 return self
4415
4416 @_generative
4417 def group_by(
4418 self,
4419 __first: Union[
4420 Literal[None, _NoArg.NO_ARG],
4421 _ColumnExpressionOrStrLabelArgument[Any],
4422 ] = _NoArg.NO_ARG,
4423 *clauses: _ColumnExpressionOrStrLabelArgument[Any],
4424 ) -> Self:
4425 r"""Return a new selectable with the given list of GROUP BY
4426 criterion applied.
4427
4428 All existing GROUP BY settings can be suppressed by passing ``None``.
4429
4430 e.g.::
4431
4432 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name)
4433
4434 :param \*clauses: a series of :class:`_expression.ColumnElement`
4435 constructs
4436 which will be used to generate an GROUP BY clause.
4437
4438 .. seealso::
4439
4440 :ref:`tutorial_group_by_w_aggregates` - in the
4441 :ref:`unified_tutorial`
4442
4443 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial`
4444
4445 """ # noqa: E501
4446
4447 if not clauses and __first is None:
4448 self._group_by_clauses = ()
4449 elif __first is not _NoArg.NO_ARG:
4450 self._group_by_clauses += tuple(
4451 coercions.expect(
4452 roles.GroupByRole, clause, apply_propagate_attrs=self
4453 )
4454 for clause in (__first,) + clauses
4455 )
4456 return self
4457
4458
4459@CompileState.plugin_for("default", "compound_select")
4460class CompoundSelectState(CompileState):
4461 @util.memoized_property
4462 def _label_resolve_dict(
4463 self,
4464 ) -> Tuple[
4465 Dict[str, ColumnElement[Any]],
4466 Dict[str, ColumnElement[Any]],
4467 Dict[str, ColumnElement[Any]],
4468 ]:
4469 # TODO: this is hacky and slow
4470 hacky_subquery = self.statement.subquery()
4471 hacky_subquery.named_with_column = False
4472 d = {c.key: c for c in hacky_subquery.c}
4473 return d, d, d
4474
4475
4476class _CompoundSelectKeyword(Enum):
4477 UNION = "UNION"
4478 UNION_ALL = "UNION ALL"
4479 EXCEPT = "EXCEPT"
4480 EXCEPT_ALL = "EXCEPT ALL"
4481 INTERSECT = "INTERSECT"
4482 INTERSECT_ALL = "INTERSECT ALL"
4483
4484
4485class CompoundSelect(HasCompileState, GenerativeSelect, TypedReturnsRows[_TP]):
4486 """Forms the basis of ``UNION``, ``UNION ALL``, and other
4487 SELECT-based set operations.
4488
4489
4490 .. seealso::
4491
4492 :func:`_expression.union`
4493
4494 :func:`_expression.union_all`
4495
4496 :func:`_expression.intersect`
4497
4498 :func:`_expression.intersect_all`
4499
4500 :func:`_expression.except`
4501
4502 :func:`_expression.except_all`
4503
4504 """
4505
4506 __visit_name__ = "compound_select"
4507
4508 _traverse_internals: _TraverseInternalsType = (
4509 [
4510 ("selects", InternalTraversal.dp_clauseelement_list),
4511 ("_limit_clause", InternalTraversal.dp_clauseelement),
4512 ("_offset_clause", InternalTraversal.dp_clauseelement),
4513 ("_fetch_clause", InternalTraversal.dp_clauseelement),
4514 ("_fetch_clause_options", InternalTraversal.dp_plain_dict),
4515 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list),
4516 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list),
4517 ("_for_update_arg", InternalTraversal.dp_clauseelement),
4518 ("keyword", InternalTraversal.dp_string),
4519 ]
4520 + SupportsCloneAnnotations._clone_annotations_traverse_internals
4521 + HasCTE._has_ctes_traverse_internals
4522 + DialectKWArgs._dialect_kwargs_traverse_internals
4523 )
4524
4525 selects: List[SelectBase]
4526
4527 _is_from_container = True
4528 _auto_correlate = False
4529
4530 def __init__(
4531 self,
4532 keyword: _CompoundSelectKeyword,
4533 *selects: _SelectStatementForCompoundArgument[_TP],
4534 ):
4535 self.keyword = keyword
4536 self.selects = [
4537 coercions.expect(
4538 roles.CompoundElementRole, s, apply_propagate_attrs=self
4539 ).self_group(against=self)
4540 for s in selects
4541 ]
4542
4543 GenerativeSelect.__init__(self)
4544
4545 @classmethod
4546 def _create_union(
4547 cls, *selects: _SelectStatementForCompoundArgument[_TP]
4548 ) -> CompoundSelect[_TP]:
4549 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects)
4550
4551 @classmethod
4552 def _create_union_all(
4553 cls, *selects: _SelectStatementForCompoundArgument[_TP]
4554 ) -> CompoundSelect[_TP]:
4555 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects)
4556
4557 @classmethod
4558 def _create_except(
4559 cls, *selects: _SelectStatementForCompoundArgument[_TP]
4560 ) -> CompoundSelect[_TP]:
4561 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects)
4562
4563 @classmethod
4564 def _create_except_all(
4565 cls, *selects: _SelectStatementForCompoundArgument[_TP]
4566 ) -> CompoundSelect[_TP]:
4567 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects)
4568
4569 @classmethod
4570 def _create_intersect(
4571 cls, *selects: _SelectStatementForCompoundArgument[_TP]
4572 ) -> CompoundSelect[_TP]:
4573 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects)
4574
4575 @classmethod
4576 def _create_intersect_all(
4577 cls, *selects: _SelectStatementForCompoundArgument[_TP]
4578 ) -> CompoundSelect[_TP]:
4579 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects)
4580
4581 def _scalar_type(self) -> TypeEngine[Any]:
4582 return self.selects[0]._scalar_type()
4583
4584 def self_group(
4585 self, against: Optional[OperatorType] = None
4586 ) -> GroupedElement:
4587 return SelectStatementGrouping(self)
4588
4589 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
4590 for s in self.selects:
4591 if s.is_derived_from(fromclause):
4592 return True
4593 return False
4594
4595 def set_label_style(self, style: SelectLabelStyle) -> Self:
4596 if self._label_style is not style:
4597 self = self._generate()
4598 select_0 = self.selects[0].set_label_style(style)
4599 self.selects = [select_0] + self.selects[1:]
4600
4601 return self
4602
4603 def _ensure_disambiguated_names(self) -> Self:
4604 new_select = self.selects[0]._ensure_disambiguated_names()
4605 if new_select is not self.selects[0]:
4606 self = self._generate()
4607 self.selects = [new_select] + self.selects[1:]
4608
4609 return self
4610
4611 def _generate_fromclause_column_proxies(
4612 self,
4613 subquery: FromClause,
4614 columns: ColumnCollection[str, KeyedColumnElement[Any]],
4615 primary_key: ColumnSet,
4616 foreign_keys: Set[KeyedColumnElement[Any]],
4617 *,
4618 proxy_compound_columns: Optional[
4619 Iterable[Sequence[ColumnElement[Any]]]
4620 ] = None,
4621 ) -> None:
4622 # this is a slightly hacky thing - the union exports a
4623 # column that resembles just that of the *first* selectable.
4624 # to get at a "composite" column, particularly foreign keys,
4625 # you have to dig through the proxies collection which we
4626 # generate below.
4627 select_0 = self.selects[0]
4628
4629 if self._label_style is not LABEL_STYLE_DEFAULT:
4630 select_0 = select_0.set_label_style(self._label_style)
4631
4632 # hand-construct the "_proxies" collection to include all
4633 # derived columns place a 'weight' annotation corresponding
4634 # to how low in the list of select()s the column occurs, so
4635 # that the corresponding_column() operation can resolve
4636 # conflicts
4637 extra_col_iterator = zip(
4638 *[
4639 [
4640 c._annotate(dd)
4641 for c in stmt._all_selected_columns
4642 if is_column_element(c)
4643 ]
4644 for dd, stmt in [
4645 ({"weight": i + 1}, stmt)
4646 for i, stmt in enumerate(self.selects)
4647 ]
4648 ]
4649 )
4650
4651 # the incoming proxy_compound_columns can be present also if this is
4652 # a compound embedded in a compound. it's probably more appropriate
4653 # that we generate new weights local to this nested compound, though
4654 # i haven't tried to think what it means for compound nested in
4655 # compound
4656 select_0._generate_fromclause_column_proxies(
4657 subquery,
4658 columns,
4659 proxy_compound_columns=extra_col_iterator,
4660 primary_key=primary_key,
4661 foreign_keys=foreign_keys,
4662 )
4663
4664 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
4665 super()._refresh_for_new_column(column)
4666 for select in self.selects:
4667 select._refresh_for_new_column(column)
4668
4669 @util.ro_non_memoized_property
4670 def _all_selected_columns(self) -> _SelectIterable:
4671 return self.selects[0]._all_selected_columns
4672
4673 @util.ro_non_memoized_property
4674 def selected_columns(
4675 self,
4676 ) -> ColumnCollection[str, ColumnElement[Any]]:
4677 """A :class:`_expression.ColumnCollection`
4678 representing the columns that
4679 this SELECT statement or similar construct returns in its result set,
4680 not including :class:`_sql.TextClause` constructs.
4681
4682 For a :class:`_expression.CompoundSelect`, the
4683 :attr:`_expression.CompoundSelect.selected_columns`
4684 attribute returns the selected
4685 columns of the first SELECT statement contained within the series of
4686 statements within the set operation.
4687
4688 .. seealso::
4689
4690 :attr:`_sql.Select.selected_columns`
4691
4692 .. versionadded:: 1.4
4693
4694 """
4695 return self.selects[0].selected_columns
4696
4697
4698# backwards compat
4699for elem in _CompoundSelectKeyword:
4700 setattr(CompoundSelect, elem.name, elem)
4701
4702
4703@CompileState.plugin_for("default", "select")
4704class SelectState(util.MemoizedSlots, CompileState):
4705 __slots__ = (
4706 "from_clauses",
4707 "froms",
4708 "columns_plus_names",
4709 "_label_resolve_dict",
4710 )
4711
4712 if TYPE_CHECKING:
4713 default_select_compile_options: CacheableOptions
4714 else:
4715
4716 class default_select_compile_options(CacheableOptions):
4717 _cache_key_traversal = []
4718
4719 if TYPE_CHECKING:
4720
4721 @classmethod
4722 def get_plugin_class(
4723 cls, statement: Executable
4724 ) -> Type[SelectState]: ...
4725
4726 def __init__(
4727 self,
4728 statement: Select[Any],
4729 compiler: SQLCompiler,
4730 **kw: Any,
4731 ):
4732 self.statement = statement
4733 self.from_clauses = statement._from_obj
4734
4735 for memoized_entities in statement._memoized_select_entities:
4736 self._setup_joins(
4737 memoized_entities._setup_joins, memoized_entities._raw_columns
4738 )
4739
4740 if statement._setup_joins:
4741 self._setup_joins(statement._setup_joins, statement._raw_columns)
4742
4743 self.froms = self._get_froms(statement)
4744
4745 self.columns_plus_names = statement._generate_columns_plus_names(True)
4746
4747 @classmethod
4748 def _plugin_not_implemented(cls) -> NoReturn:
4749 raise NotImplementedError(
4750 "The default SELECT construct without plugins does not "
4751 "implement this method."
4752 )
4753
4754 @classmethod
4755 def get_column_descriptions(
4756 cls, statement: Select[Any]
4757 ) -> List[Dict[str, Any]]:
4758 return [
4759 {
4760 "name": name,
4761 "type": element.type,
4762 "expr": element,
4763 }
4764 for _, name, _, element, _ in (
4765 statement._generate_columns_plus_names(False)
4766 )
4767 ]
4768
4769 @classmethod
4770 def from_statement(
4771 cls, statement: Select[Any], from_statement: roles.ReturnsRowsRole
4772 ) -> ExecutableReturnsRows:
4773 cls._plugin_not_implemented()
4774
4775 @classmethod
4776 def get_columns_clause_froms(
4777 cls, statement: Select[Any]
4778 ) -> List[FromClause]:
4779 return cls._normalize_froms(
4780 itertools.chain.from_iterable(
4781 element._from_objects for element in statement._raw_columns
4782 )
4783 )
4784
4785 @classmethod
4786 def _column_naming_convention(
4787 cls, label_style: SelectLabelStyle
4788 ) -> _LabelConventionCallable:
4789 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL
4790
4791 dedupe = label_style is not LABEL_STYLE_NONE
4792
4793 pa = prefix_anon_map()
4794 names = set()
4795
4796 def go(
4797 c: Union[ColumnElement[Any], TextClause],
4798 col_name: Optional[str] = None,
4799 ) -> Optional[str]:
4800 if is_text_clause(c):
4801 return None
4802 elif TYPE_CHECKING:
4803 assert is_column_element(c)
4804
4805 if not dedupe:
4806 name = c._proxy_key
4807 if name is None:
4808 name = "_no_label"
4809 return name
4810
4811 name = c._tq_key_label if table_qualified else c._proxy_key
4812
4813 if name is None:
4814 name = "_no_label"
4815 if name in names:
4816 return c._anon_label(name) % pa
4817 else:
4818 names.add(name)
4819 return name
4820
4821 elif name in names:
4822 return (
4823 c._anon_tq_key_label % pa
4824 if table_qualified
4825 else c._anon_key_label % pa
4826 )
4827 else:
4828 names.add(name)
4829 return name
4830
4831 return go
4832
4833 def _get_froms(self, statement: Select[Any]) -> List[FromClause]:
4834 ambiguous_table_name_map: _AmbiguousTableNameMap
4835 self._ambiguous_table_name_map = ambiguous_table_name_map = {}
4836
4837 return self._normalize_froms(
4838 itertools.chain(
4839 self.from_clauses,
4840 itertools.chain.from_iterable(
4841 [
4842 element._from_objects
4843 for element in statement._raw_columns
4844 ]
4845 ),
4846 itertools.chain.from_iterable(
4847 [
4848 element._from_objects
4849 for element in statement._where_criteria
4850 ]
4851 ),
4852 ),
4853 check_statement=statement,
4854 ambiguous_table_name_map=ambiguous_table_name_map,
4855 )
4856
4857 @classmethod
4858 def _normalize_froms(
4859 cls,
4860 iterable_of_froms: Iterable[FromClause],
4861 check_statement: Optional[Select[Any]] = None,
4862 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None,
4863 ) -> List[FromClause]:
4864 """given an iterable of things to select FROM, reduce them to what
4865 would actually render in the FROM clause of a SELECT.
4866
4867 This does the job of checking for JOINs, tables, etc. that are in fact
4868 overlapping due to cloning, adaption, present in overlapping joins,
4869 etc.
4870
4871 """
4872 seen: Set[FromClause] = set()
4873 froms: List[FromClause] = []
4874
4875 for item in iterable_of_froms:
4876 if is_subquery(item) and item.element is check_statement:
4877 raise exc.InvalidRequestError(
4878 "select() construct refers to itself as a FROM"
4879 )
4880
4881 if not seen.intersection(item._cloned_set):
4882 froms.append(item)
4883 seen.update(item._cloned_set)
4884
4885 if froms:
4886 toremove = set(
4887 itertools.chain.from_iterable(
4888 [_expand_cloned(f._hide_froms) for f in froms]
4889 )
4890 )
4891 if toremove:
4892 # filter out to FROM clauses not in the list,
4893 # using a list to maintain ordering
4894 froms = [f for f in froms if f not in toremove]
4895
4896 if ambiguous_table_name_map is not None:
4897 ambiguous_table_name_map.update(
4898 (
4899 fr.name,
4900 _anonymous_label.safe_construct(
4901 hash(fr.name), fr.name
4902 ),
4903 )
4904 for item in froms
4905 for fr in item._from_objects
4906 if is_table(fr)
4907 and fr.schema
4908 and fr.name not in ambiguous_table_name_map
4909 )
4910
4911 return froms
4912
4913 def _get_display_froms(
4914 self,
4915 explicit_correlate_froms: Optional[Sequence[FromClause]] = None,
4916 implicit_correlate_froms: Optional[Sequence[FromClause]] = None,
4917 ) -> List[FromClause]:
4918 """Return the full list of 'from' clauses to be displayed.
4919
4920 Takes into account a set of existing froms which may be
4921 rendered in the FROM clause of enclosing selects; this Select
4922 may want to leave those absent if it is automatically
4923 correlating.
4924
4925 """
4926
4927 froms = self.froms
4928
4929 if self.statement._correlate:
4930 to_correlate = self.statement._correlate
4931 if to_correlate:
4932 froms = [
4933 f
4934 for f in froms
4935 if f
4936 not in _cloned_intersection(
4937 _cloned_intersection(
4938 froms, explicit_correlate_froms or ()
4939 ),
4940 to_correlate,
4941 )
4942 ]
4943
4944 if self.statement._correlate_except is not None:
4945 froms = [
4946 f
4947 for f in froms
4948 if f
4949 not in _cloned_difference(
4950 _cloned_intersection(
4951 froms, explicit_correlate_froms or ()
4952 ),
4953 self.statement._correlate_except,
4954 )
4955 ]
4956
4957 if (
4958 self.statement._auto_correlate
4959 and implicit_correlate_froms
4960 and len(froms) > 1
4961 ):
4962 froms = [
4963 f
4964 for f in froms
4965 if f
4966 not in _cloned_intersection(froms, implicit_correlate_froms)
4967 ]
4968
4969 if not len(froms):
4970 raise exc.InvalidRequestError(
4971 "Select statement '%r"
4972 "' returned no FROM clauses "
4973 "due to auto-correlation; "
4974 "specify correlate(<tables>) "
4975 "to control correlation "
4976 "manually." % self.statement
4977 )
4978
4979 return froms
4980
4981 def _memoized_attr__label_resolve_dict(
4982 self,
4983 ) -> Tuple[
4984 Dict[str, ColumnElement[Any]],
4985 Dict[str, ColumnElement[Any]],
4986 Dict[str, ColumnElement[Any]],
4987 ]:
4988 with_cols: Dict[str, ColumnElement[Any]] = {
4989 c._tq_label or c.key: c
4990 for c in self.statement._all_selected_columns
4991 if c._allow_label_resolve
4992 }
4993 only_froms: Dict[str, ColumnElement[Any]] = {
4994 c.key: c # type: ignore
4995 for c in _select_iterables(self.froms)
4996 if c._allow_label_resolve
4997 }
4998 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy()
4999 for key, value in only_froms.items():
5000 with_cols.setdefault(key, value)
5001
5002 return with_cols, only_froms, only_cols
5003
5004 @classmethod
5005 def determine_last_joined_entity(
5006 cls, stmt: Select[Any]
5007 ) -> Optional[_JoinTargetElement]:
5008 if stmt._setup_joins:
5009 return stmt._setup_joins[-1][0]
5010 else:
5011 return None
5012
5013 @classmethod
5014 def all_selected_columns(cls, statement: Select[Any]) -> _SelectIterable:
5015 return [c for c in _select_iterables(statement._raw_columns)]
5016
5017 def _setup_joins(
5018 self,
5019 args: Tuple[_SetupJoinsElement, ...],
5020 raw_columns: List[_ColumnsClauseElement],
5021 ) -> None:
5022 for right, onclause, left, flags in args:
5023 if TYPE_CHECKING:
5024 if onclause is not None:
5025 assert isinstance(onclause, ColumnElement)
5026
5027 isouter = flags["isouter"]
5028 full = flags["full"]
5029
5030 if left is None:
5031 (
5032 left,
5033 replace_from_obj_index,
5034 ) = self._join_determine_implicit_left_side(
5035 raw_columns, left, right, onclause
5036 )
5037 else:
5038 (replace_from_obj_index) = self._join_place_explicit_left_side(
5039 left
5040 )
5041
5042 # these assertions can be made here, as if the right/onclause
5043 # contained ORM elements, the select() statement would have been
5044 # upgraded to an ORM select, and this method would not be called;
5045 # orm.context.ORMSelectCompileState._join() would be
5046 # used instead.
5047 if TYPE_CHECKING:
5048 assert isinstance(right, FromClause)
5049 if onclause is not None:
5050 assert isinstance(onclause, ColumnElement)
5051
5052 if replace_from_obj_index is not None:
5053 # splice into an existing element in the
5054 # self._from_obj list
5055 left_clause = self.from_clauses[replace_from_obj_index]
5056
5057 self.from_clauses = (
5058 self.from_clauses[:replace_from_obj_index]
5059 + (
5060 Join(
5061 left_clause,
5062 right,
5063 onclause,
5064 isouter=isouter,
5065 full=full,
5066 ),
5067 )
5068 + self.from_clauses[replace_from_obj_index + 1 :]
5069 )
5070 else:
5071 assert left is not None
5072 self.from_clauses = self.from_clauses + (
5073 Join(left, right, onclause, isouter=isouter, full=full),
5074 )
5075
5076 @util.preload_module("sqlalchemy.sql.util")
5077 def _join_determine_implicit_left_side(
5078 self,
5079 raw_columns: List[_ColumnsClauseElement],
5080 left: Optional[FromClause],
5081 right: _JoinTargetElement,
5082 onclause: Optional[ColumnElement[Any]],
5083 ) -> Tuple[Optional[FromClause], Optional[int]]:
5084 """When join conditions don't express the left side explicitly,
5085 determine if an existing FROM or entity in this query
5086 can serve as the left hand side.
5087
5088 """
5089
5090 sql_util = util.preloaded.sql_util
5091
5092 replace_from_obj_index: Optional[int] = None
5093
5094 from_clauses = self.from_clauses
5095
5096 if from_clauses:
5097 indexes: List[int] = sql_util.find_left_clause_to_join_from(
5098 from_clauses, right, onclause
5099 )
5100
5101 if len(indexes) == 1:
5102 replace_from_obj_index = indexes[0]
5103 left = from_clauses[replace_from_obj_index]
5104 else:
5105 potential = {}
5106 statement = self.statement
5107
5108 for from_clause in itertools.chain(
5109 itertools.chain.from_iterable(
5110 [element._from_objects for element in raw_columns]
5111 ),
5112 itertools.chain.from_iterable(
5113 [
5114 element._from_objects
5115 for element in statement._where_criteria
5116 ]
5117 ),
5118 ):
5119 potential[from_clause] = ()
5120
5121 all_clauses = list(potential.keys())
5122 indexes = sql_util.find_left_clause_to_join_from(
5123 all_clauses, right, onclause
5124 )
5125
5126 if len(indexes) == 1:
5127 left = all_clauses[indexes[0]]
5128
5129 if len(indexes) > 1:
5130 raise exc.InvalidRequestError(
5131 "Can't determine which FROM clause to join "
5132 "from, there are multiple FROMS which can "
5133 "join to this entity. Please use the .select_from() "
5134 "method to establish an explicit left side, as well as "
5135 "providing an explicit ON clause if not present already to "
5136 "help resolve the ambiguity."
5137 )
5138 elif not indexes:
5139 raise exc.InvalidRequestError(
5140 "Don't know how to join to %r. "
5141 "Please use the .select_from() "
5142 "method to establish an explicit left side, as well as "
5143 "providing an explicit ON clause if not present already to "
5144 "help resolve the ambiguity." % (right,)
5145 )
5146 return left, replace_from_obj_index
5147
5148 @util.preload_module("sqlalchemy.sql.util")
5149 def _join_place_explicit_left_side(
5150 self, left: FromClause
5151 ) -> Optional[int]:
5152 replace_from_obj_index: Optional[int] = None
5153
5154 sql_util = util.preloaded.sql_util
5155
5156 from_clauses = list(self.statement._iterate_from_elements())
5157
5158 if from_clauses:
5159 indexes: List[int] = sql_util.find_left_clause_that_matches_given(
5160 self.from_clauses, left
5161 )
5162 else:
5163 indexes = []
5164
5165 if len(indexes) > 1:
5166 raise exc.InvalidRequestError(
5167 "Can't identify which entity in which to assign the "
5168 "left side of this join. Please use a more specific "
5169 "ON clause."
5170 )
5171
5172 # have an index, means the left side is already present in
5173 # an existing FROM in the self._from_obj tuple
5174 if indexes:
5175 replace_from_obj_index = indexes[0]
5176
5177 # no index, means we need to add a new element to the
5178 # self._from_obj tuple
5179
5180 return replace_from_obj_index
5181
5182
5183class _SelectFromElements:
5184 __slots__ = ()
5185
5186 _raw_columns: List[_ColumnsClauseElement]
5187 _where_criteria: Tuple[ColumnElement[Any], ...]
5188 _from_obj: Tuple[FromClause, ...]
5189
5190 def _iterate_from_elements(self) -> Iterator[FromClause]:
5191 # note this does not include elements
5192 # in _setup_joins
5193
5194 seen = set()
5195 for element in self._raw_columns:
5196 for fr in element._from_objects:
5197 if fr in seen:
5198 continue
5199 seen.add(fr)
5200 yield fr
5201 for element in self._where_criteria:
5202 for fr in element._from_objects:
5203 if fr in seen:
5204 continue
5205 seen.add(fr)
5206 yield fr
5207 for element in self._from_obj:
5208 if element in seen:
5209 continue
5210 seen.add(element)
5211 yield element
5212
5213
5214class _MemoizedSelectEntities(
5215 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible
5216):
5217 """represents partial state from a Select object, for the case
5218 where Select.columns() has redefined the set of columns/entities the
5219 statement will be SELECTing from. This object represents
5220 the entities from the SELECT before that transformation was applied,
5221 so that transformations that were made in terms of the SELECT at that
5222 time, such as join() as well as options(), can access the correct context.
5223
5224 In previous SQLAlchemy versions, this wasn't needed because these
5225 constructs calculated everything up front, like when you called join()
5226 or options(), it did everything to figure out how that would translate
5227 into specific SQL constructs that would be ready to send directly to the
5228 SQL compiler when needed. But as of
5229 1.4, all of that stuff is done in the compilation phase, during the
5230 "compile state" portion of the process, so that the work can all be
5231 cached. So it needs to be able to resolve joins/options2 based on what
5232 the list of entities was when those methods were called.
5233
5234
5235 """
5236
5237 __visit_name__ = "memoized_select_entities"
5238
5239 _traverse_internals: _TraverseInternalsType = [
5240 ("_raw_columns", InternalTraversal.dp_clauseelement_list),
5241 ("_setup_joins", InternalTraversal.dp_setup_join_tuple),
5242 ("_with_options", InternalTraversal.dp_executable_options),
5243 ]
5244
5245 _is_clone_of: Optional[ClauseElement]
5246 _raw_columns: List[_ColumnsClauseElement]
5247 _setup_joins: Tuple[_SetupJoinsElement, ...]
5248 _with_options: Tuple[ExecutableOption, ...]
5249
5250 _annotations = util.EMPTY_DICT
5251
5252 def _clone(self, **kw: Any) -> Self:
5253 c = self.__class__.__new__(self.__class__)
5254 c.__dict__ = {k: v for k, v in self.__dict__.items()}
5255
5256 c._is_clone_of = self.__dict__.get("_is_clone_of", self)
5257 return c
5258
5259 @classmethod
5260 def _generate_for_statement(cls, select_stmt: Select[Any]) -> None:
5261 if select_stmt._setup_joins or select_stmt._with_options:
5262 self = _MemoizedSelectEntities()
5263 self._raw_columns = select_stmt._raw_columns
5264 self._setup_joins = select_stmt._setup_joins
5265 self._with_options = select_stmt._with_options
5266
5267 select_stmt._memoized_select_entities += (self,)
5268 select_stmt._raw_columns = []
5269 select_stmt._setup_joins = select_stmt._with_options = ()
5270
5271
5272class Select(
5273 HasPrefixes,
5274 HasSuffixes,
5275 HasHints,
5276 HasCompileState,
5277 _SelectFromElements,
5278 GenerativeSelect,
5279 TypedReturnsRows[_TP],
5280):
5281 """Represents a ``SELECT`` statement.
5282
5283 The :class:`_sql.Select` object is normally constructed using the
5284 :func:`_sql.select` function. See that function for details.
5285
5286 .. seealso::
5287
5288 :func:`_sql.select`
5289
5290 :ref:`tutorial_selecting_data` - in the 2.0 tutorial
5291
5292 """
5293
5294 __visit_name__ = "select"
5295
5296 _setup_joins: Tuple[_SetupJoinsElement, ...] = ()
5297 _memoized_select_entities: Tuple[TODO_Any, ...] = ()
5298
5299 _raw_columns: List[_ColumnsClauseElement]
5300
5301 _distinct: bool = False
5302 _distinct_on: Tuple[ColumnElement[Any], ...] = ()
5303 _correlate: Tuple[FromClause, ...] = ()
5304 _correlate_except: Optional[Tuple[FromClause, ...]] = None
5305 _where_criteria: Tuple[ColumnElement[Any], ...] = ()
5306 _having_criteria: Tuple[ColumnElement[Any], ...] = ()
5307 _from_obj: Tuple[FromClause, ...] = ()
5308 _auto_correlate = True
5309 _is_select_statement = True
5310 _compile_options: CacheableOptions = (
5311 SelectState.default_select_compile_options
5312 )
5313
5314 _traverse_internals: _TraverseInternalsType = (
5315 [
5316 ("_raw_columns", InternalTraversal.dp_clauseelement_list),
5317 (
5318 "_memoized_select_entities",
5319 InternalTraversal.dp_memoized_select_entities,
5320 ),
5321 ("_from_obj", InternalTraversal.dp_clauseelement_list),
5322 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple),
5323 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple),
5324 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple),
5325 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple),
5326 ("_setup_joins", InternalTraversal.dp_setup_join_tuple),
5327 ("_correlate", InternalTraversal.dp_clauseelement_tuple),
5328 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple),
5329 ("_limit_clause", InternalTraversal.dp_clauseelement),
5330 ("_offset_clause", InternalTraversal.dp_clauseelement),
5331 ("_fetch_clause", InternalTraversal.dp_clauseelement),
5332 ("_fetch_clause_options", InternalTraversal.dp_plain_dict),
5333 ("_for_update_arg", InternalTraversal.dp_clauseelement),
5334 ("_distinct", InternalTraversal.dp_boolean),
5335 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple),
5336 ("_label_style", InternalTraversal.dp_plain_obj),
5337 ]
5338 + HasCTE._has_ctes_traverse_internals
5339 + HasPrefixes._has_prefixes_traverse_internals
5340 + HasSuffixes._has_suffixes_traverse_internals
5341 + HasHints._has_hints_traverse_internals
5342 + SupportsCloneAnnotations._clone_annotations_traverse_internals
5343 + Executable._executable_traverse_internals
5344 + DialectKWArgs._dialect_kwargs_traverse_internals
5345 )
5346
5347 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [
5348 ("_compile_options", InternalTraversal.dp_has_cache_key)
5349 ]
5350
5351 _compile_state_factory: Type[SelectState]
5352
5353 @classmethod
5354 def _create_raw_select(cls, **kw: Any) -> Select[Any]:
5355 """Create a :class:`.Select` using raw ``__new__`` with no coercions.
5356
5357 Used internally to build up :class:`.Select` constructs with
5358 pre-established state.
5359
5360 """
5361
5362 stmt = Select.__new__(Select)
5363 stmt.__dict__.update(kw)
5364 return stmt
5365
5366 def __init__(
5367 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any
5368 ):
5369 r"""Construct a new :class:`_expression.Select`.
5370
5371 The public constructor for :class:`_expression.Select` is the
5372 :func:`_sql.select` function.
5373
5374 """
5375 self._raw_columns = [
5376 coercions.expect(
5377 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self
5378 )
5379 for ent in entities
5380 ]
5381 GenerativeSelect.__init__(self)
5382
5383 def _scalar_type(self) -> TypeEngine[Any]:
5384 if not self._raw_columns:
5385 return NULLTYPE
5386 elem = self._raw_columns[0]
5387 cols = list(elem._select_iterable)
5388 return cols[0].type
5389
5390 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self:
5391 """A synonym for the :meth:`_sql.Select.where` method."""
5392
5393 return self.where(*criteria)
5394
5395 def _filter_by_zero(
5396 self,
5397 ) -> Union[
5398 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause
5399 ]:
5400 if self._setup_joins:
5401 meth = SelectState.get_plugin_class(
5402 self
5403 ).determine_last_joined_entity
5404 _last_joined_entity = meth(self)
5405 if _last_joined_entity is not None:
5406 return _last_joined_entity
5407
5408 if self._from_obj:
5409 return self._from_obj[0]
5410
5411 return self._raw_columns[0]
5412
5413 if TYPE_CHECKING:
5414
5415 @overload
5416 def scalar_subquery(
5417 self: Select[Tuple[_MAYBE_ENTITY]],
5418 ) -> ScalarSelect[Any]: ...
5419
5420 @overload
5421 def scalar_subquery(
5422 self: Select[Tuple[_NOT_ENTITY]],
5423 ) -> ScalarSelect[_NOT_ENTITY]: ...
5424
5425 @overload
5426 def scalar_subquery(self) -> ScalarSelect[Any]: ...
5427
5428 def scalar_subquery(self) -> ScalarSelect[Any]: ...
5429
5430 def filter_by(self, **kwargs: Any) -> Self:
5431 r"""apply the given filtering criterion as a WHERE clause
5432 to this select.
5433
5434 """
5435 from_entity = self._filter_by_zero()
5436
5437 clauses = [
5438 _entity_namespace_key(from_entity, key) == value
5439 for key, value in kwargs.items()
5440 ]
5441 return self.filter(*clauses)
5442
5443 @property
5444 def column_descriptions(self) -> Any:
5445 """Return a :term:`plugin-enabled` 'column descriptions' structure
5446 referring to the columns which are SELECTed by this statement.
5447
5448 This attribute is generally useful when using the ORM, as an
5449 extended structure which includes information about mapped
5450 entities is returned. The section :ref:`queryguide_inspection`
5451 contains more background.
5452
5453 For a Core-only statement, the structure returned by this accessor
5454 is derived from the same objects that are returned by the
5455 :attr:`.Select.selected_columns` accessor, formatted as a list of
5456 dictionaries which contain the keys ``name``, ``type`` and ``expr``,
5457 which indicate the column expressions to be selected::
5458
5459 >>> stmt = select(user_table)
5460 >>> stmt.column_descriptions
5461 [
5462 {
5463 'name': 'id',
5464 'type': Integer(),
5465 'expr': Column('id', Integer(), ...)},
5466 {
5467 'name': 'name',
5468 'type': String(length=30),
5469 'expr': Column('name', String(length=30), ...)}
5470 ]
5471
5472 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions`
5473 attribute returns a structure for a Core-only set of entities,
5474 not just ORM-only entities.
5475
5476 .. seealso::
5477
5478 :attr:`.UpdateBase.entity_description` - entity information for
5479 an :func:`.insert`, :func:`.update`, or :func:`.delete`
5480
5481 :ref:`queryguide_inspection` - ORM background
5482
5483 """
5484 meth = SelectState.get_plugin_class(self).get_column_descriptions
5485 return meth(self)
5486
5487 def from_statement(
5488 self, statement: roles.ReturnsRowsRole
5489 ) -> ExecutableReturnsRows:
5490 """Apply the columns which this :class:`.Select` would select
5491 onto another statement.
5492
5493 This operation is :term:`plugin-specific` and will raise a not
5494 supported exception if this :class:`_sql.Select` does not select from
5495 plugin-enabled entities.
5496
5497
5498 The statement is typically either a :func:`_expression.text` or
5499 :func:`_expression.select` construct, and should return the set of
5500 columns appropriate to the entities represented by this
5501 :class:`.Select`.
5502
5503 .. seealso::
5504
5505 :ref:`orm_queryguide_selecting_text` - usage examples in the
5506 ORM Querying Guide
5507
5508 """
5509 meth = SelectState.get_plugin_class(self).from_statement
5510 return meth(self, statement)
5511
5512 @_generative
5513 def join(
5514 self,
5515 target: _JoinTargetArgument,
5516 onclause: Optional[_OnClauseArgument] = None,
5517 *,
5518 isouter: bool = False,
5519 full: bool = False,
5520 ) -> Self:
5521 r"""Create a SQL JOIN against this :class:`_expression.Select`
5522 object's criterion
5523 and apply generatively, returning the newly resulting
5524 :class:`_expression.Select`.
5525
5526 E.g.::
5527
5528 stmt = select(user_table).join(
5529 address_table, user_table.c.id == address_table.c.user_id
5530 )
5531
5532 The above statement generates SQL similar to:
5533
5534 .. sourcecode:: sql
5535
5536 SELECT user.id, user.name
5537 FROM user
5538 JOIN address ON user.id = address.user_id
5539
5540 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates
5541 a :class:`_sql.Join` object between a :class:`_sql.FromClause`
5542 source that is within the FROM clause of the existing SELECT,
5543 and a given target :class:`_sql.FromClause`, and then adds
5544 this :class:`_sql.Join` to the FROM clause of the newly generated
5545 SELECT statement. This is completely reworked from the behavior
5546 in 1.3, which would instead create a subquery of the entire
5547 :class:`_expression.Select` and then join that subquery to the
5548 target.
5549
5550 This is a **backwards incompatible change** as the previous behavior
5551 was mostly useless, producing an unnamed subquery rejected by
5552 most databases in any case. The new behavior is modeled after
5553 that of the very successful :meth:`_orm.Query.join` method in the
5554 ORM, in order to support the functionality of :class:`_orm.Query`
5555 being available by using a :class:`_sql.Select` object with an
5556 :class:`_orm.Session`.
5557
5558 See the notes for this change at :ref:`change_select_join`.
5559
5560
5561 :param target: target table to join towards
5562
5563 :param onclause: ON clause of the join. If omitted, an ON clause
5564 is generated automatically based on the :class:`_schema.ForeignKey`
5565 linkages between the two tables, if one can be unambiguously
5566 determined, otherwise an error is raised.
5567
5568 :param isouter: if True, generate LEFT OUTER join. Same as
5569 :meth:`_expression.Select.outerjoin`.
5570
5571 :param full: if True, generate FULL OUTER join.
5572
5573 .. seealso::
5574
5575 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
5576
5577 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
5578
5579 :meth:`_expression.Select.join_from`
5580
5581 :meth:`_expression.Select.outerjoin`
5582
5583 """ # noqa: E501
5584 join_target = coercions.expect(
5585 roles.JoinTargetRole, target, apply_propagate_attrs=self
5586 )
5587 if onclause is not None:
5588 onclause_element = coercions.expect(roles.OnClauseRole, onclause)
5589 else:
5590 onclause_element = None
5591
5592 self._setup_joins += (
5593 (
5594 join_target,
5595 onclause_element,
5596 None,
5597 {"isouter": isouter, "full": full},
5598 ),
5599 )
5600 return self
5601
5602 def outerjoin_from(
5603 self,
5604 from_: _FromClauseArgument,
5605 target: _JoinTargetArgument,
5606 onclause: Optional[_OnClauseArgument] = None,
5607 *,
5608 full: bool = False,
5609 ) -> Self:
5610 r"""Create a SQL LEFT OUTER JOIN against this
5611 :class:`_expression.Select` object's criterion and apply generatively,
5612 returning the newly resulting :class:`_expression.Select`.
5613
5614 Usage is the same as that of :meth:`_selectable.Select.join_from`.
5615
5616 """
5617 return self.join_from(
5618 from_, target, onclause=onclause, isouter=True, full=full
5619 )
5620
5621 @_generative
5622 def join_from(
5623 self,
5624 from_: _FromClauseArgument,
5625 target: _JoinTargetArgument,
5626 onclause: Optional[_OnClauseArgument] = None,
5627 *,
5628 isouter: bool = False,
5629 full: bool = False,
5630 ) -> Self:
5631 r"""Create a SQL JOIN against this :class:`_expression.Select`
5632 object's criterion
5633 and apply generatively, returning the newly resulting
5634 :class:`_expression.Select`.
5635
5636 E.g.::
5637
5638 stmt = select(user_table, address_table).join_from(
5639 user_table, address_table, user_table.c.id == address_table.c.user_id
5640 )
5641
5642 The above statement generates SQL similar to:
5643
5644 .. sourcecode:: sql
5645
5646 SELECT user.id, user.name, address.id, address.email, address.user_id
5647 FROM user JOIN address ON user.id = address.user_id
5648
5649 .. versionadded:: 1.4
5650
5651 :param from\_: the left side of the join, will be rendered in the
5652 FROM clause and is roughly equivalent to using the
5653 :meth:`.Select.select_from` method.
5654
5655 :param target: target table to join towards
5656
5657 :param onclause: ON clause of the join.
5658
5659 :param isouter: if True, generate LEFT OUTER join. Same as
5660 :meth:`_expression.Select.outerjoin`.
5661
5662 :param full: if True, generate FULL OUTER join.
5663
5664 .. seealso::
5665
5666 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
5667
5668 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
5669
5670 :meth:`_expression.Select.join`
5671
5672 """ # noqa: E501
5673
5674 # note the order of parsing from vs. target is important here, as we
5675 # are also deriving the source of the plugin (i.e. the subject mapper
5676 # in an ORM query) which should favor the "from_" over the "target"
5677
5678 from_ = coercions.expect(
5679 roles.FromClauseRole, from_, apply_propagate_attrs=self
5680 )
5681 join_target = coercions.expect(
5682 roles.JoinTargetRole, target, apply_propagate_attrs=self
5683 )
5684 if onclause is not None:
5685 onclause_element = coercions.expect(roles.OnClauseRole, onclause)
5686 else:
5687 onclause_element = None
5688
5689 self._setup_joins += (
5690 (
5691 join_target,
5692 onclause_element,
5693 from_,
5694 {"isouter": isouter, "full": full},
5695 ),
5696 )
5697 return self
5698
5699 def outerjoin(
5700 self,
5701 target: _JoinTargetArgument,
5702 onclause: Optional[_OnClauseArgument] = None,
5703 *,
5704 full: bool = False,
5705 ) -> Self:
5706 """Create a left outer join.
5707
5708 Parameters are the same as that of :meth:`_expression.Select.join`.
5709
5710 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now
5711 creates a :class:`_sql.Join` object between a
5712 :class:`_sql.FromClause` source that is within the FROM clause of
5713 the existing SELECT, and a given target :class:`_sql.FromClause`,
5714 and then adds this :class:`_sql.Join` to the FROM clause of the
5715 newly generated SELECT statement. This is completely reworked
5716 from the behavior in 1.3, which would instead create a subquery of
5717 the entire
5718 :class:`_expression.Select` and then join that subquery to the
5719 target.
5720
5721 This is a **backwards incompatible change** as the previous behavior
5722 was mostly useless, producing an unnamed subquery rejected by
5723 most databases in any case. The new behavior is modeled after
5724 that of the very successful :meth:`_orm.Query.join` method in the
5725 ORM, in order to support the functionality of :class:`_orm.Query`
5726 being available by using a :class:`_sql.Select` object with an
5727 :class:`_orm.Session`.
5728
5729 See the notes for this change at :ref:`change_select_join`.
5730
5731 .. seealso::
5732
5733 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
5734
5735 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
5736
5737 :meth:`_expression.Select.join`
5738
5739 """
5740 return self.join(target, onclause=onclause, isouter=True, full=full)
5741
5742 def get_final_froms(self) -> Sequence[FromClause]:
5743 """Compute the final displayed list of :class:`_expression.FromClause`
5744 elements.
5745
5746 This method will run through the full computation required to
5747 determine what FROM elements will be displayed in the resulting
5748 SELECT statement, including shadowing individual tables with
5749 JOIN objects, as well as full computation for ORM use cases including
5750 eager loading clauses.
5751
5752 For ORM use, this accessor returns the **post compilation**
5753 list of FROM objects; this collection will include elements such as
5754 eagerly loaded tables and joins. The objects will **not** be
5755 ORM enabled and not work as a replacement for the
5756 :meth:`_sql.Select.select_froms` collection; additionally, the
5757 method is not well performing for an ORM enabled statement as it
5758 will incur the full ORM construction process.
5759
5760 To retrieve the FROM list that's implied by the "columns" collection
5761 passed to the :class:`_sql.Select` originally, use the
5762 :attr:`_sql.Select.columns_clause_froms` accessor.
5763
5764 To select from an alternative set of columns while maintaining the
5765 FROM list, use the :meth:`_sql.Select.with_only_columns` method and
5766 pass the
5767 :paramref:`_sql.Select.with_only_columns.maintain_column_froms`
5768 parameter.
5769
5770 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms`
5771 method replaces the previous :attr:`_sql.Select.froms` accessor,
5772 which is deprecated.
5773
5774 .. seealso::
5775
5776 :attr:`_sql.Select.columns_clause_froms`
5777
5778 """
5779 compiler = self._default_compiler()
5780
5781 return self._compile_state_factory(self, compiler)._get_display_froms()
5782
5783 @property
5784 @util.deprecated(
5785 "1.4.23",
5786 "The :attr:`_expression.Select.froms` attribute is moved to "
5787 "the :meth:`_expression.Select.get_final_froms` method.",
5788 )
5789 def froms(self) -> Sequence[FromClause]:
5790 """Return the displayed list of :class:`_expression.FromClause`
5791 elements.
5792
5793
5794 """
5795 return self.get_final_froms()
5796
5797 @property
5798 def columns_clause_froms(self) -> List[FromClause]:
5799 """Return the set of :class:`_expression.FromClause` objects implied
5800 by the columns clause of this SELECT statement.
5801
5802 .. versionadded:: 1.4.23
5803
5804 .. seealso::
5805
5806 :attr:`_sql.Select.froms` - "final" FROM list taking the full
5807 statement into account
5808
5809 :meth:`_sql.Select.with_only_columns` - makes use of this
5810 collection to set up a new FROM list
5811
5812 """
5813
5814 return SelectState.get_plugin_class(self).get_columns_clause_froms(
5815 self
5816 )
5817
5818 @property
5819 def inner_columns(self) -> _SelectIterable:
5820 """An iterator of all :class:`_expression.ColumnElement`
5821 expressions which would
5822 be rendered into the columns clause of the resulting SELECT statement.
5823
5824 This method is legacy as of 1.4 and is superseded by the
5825 :attr:`_expression.Select.exported_columns` collection.
5826
5827 """
5828
5829 return iter(self._all_selected_columns)
5830
5831 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
5832 if fromclause is not None and self in fromclause._cloned_set:
5833 return True
5834
5835 for f in self._iterate_from_elements():
5836 if f.is_derived_from(fromclause):
5837 return True
5838 return False
5839
5840 def _copy_internals(
5841 self, clone: _CloneCallableType = _clone, **kw: Any
5842 ) -> None:
5843 # Select() object has been cloned and probably adapted by the
5844 # given clone function. Apply the cloning function to internal
5845 # objects
5846
5847 # 1. keep a dictionary of the froms we've cloned, and what
5848 # they've become. This allows us to ensure the same cloned from
5849 # is used when other items such as columns are "cloned"
5850
5851 all_the_froms = set(
5852 itertools.chain(
5853 _from_objects(*self._raw_columns),
5854 _from_objects(*self._where_criteria),
5855 _from_objects(*[elem[0] for elem in self._setup_joins]),
5856 )
5857 )
5858
5859 # do a clone for the froms we've gathered. what is important here
5860 # is if any of the things we are selecting from, like tables,
5861 # were converted into Join objects. if so, these need to be
5862 # added to _from_obj explicitly, because otherwise they won't be
5863 # part of the new state, as they don't associate themselves with
5864 # their columns.
5865 new_froms = {f: clone(f, **kw) for f in all_the_froms}
5866
5867 # 2. copy FROM collections, adding in joins that we've created.
5868 existing_from_obj = [clone(f, **kw) for f in self._from_obj]
5869 add_froms = (
5870 {f for f in new_froms.values() if isinstance(f, Join)}
5871 .difference(all_the_froms)
5872 .difference(existing_from_obj)
5873 )
5874
5875 self._from_obj = tuple(existing_from_obj) + tuple(add_froms)
5876
5877 # 3. clone everything else, making sure we use columns
5878 # corresponding to the froms we just made.
5879 def replace(
5880 obj: Union[BinaryExpression[Any], ColumnClause[Any]],
5881 **kw: Any,
5882 ) -> Optional[KeyedColumnElement[Any]]:
5883 if isinstance(obj, ColumnClause) and obj.table in new_froms:
5884 newelem = new_froms[obj.table].corresponding_column(obj)
5885 return newelem
5886 return None
5887
5888 kw["replace"] = replace
5889
5890 # copy everything else. for table-ish things like correlate,
5891 # correlate_except, setup_joins, these clone normally. For
5892 # column-expression oriented things like raw_columns, where_criteria,
5893 # order by, we get this from the new froms.
5894 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw)
5895
5896 self._reset_memoizations()
5897
5898 def get_children(self, **kw: Any) -> Iterable[ClauseElement]:
5899 return itertools.chain(
5900 super().get_children(
5901 omit_attrs=("_from_obj", "_correlate", "_correlate_except"),
5902 **kw,
5903 ),
5904 self._iterate_from_elements(),
5905 )
5906
5907 @_generative
5908 def add_columns(
5909 self, *entities: _ColumnsClauseArgument[Any]
5910 ) -> Select[Any]:
5911 r"""Return a new :func:`_expression.select` construct with
5912 the given entities appended to its columns clause.
5913
5914 E.g.::
5915
5916 my_select = my_select.add_columns(table.c.new_column)
5917
5918 The original expressions in the columns clause remain in place.
5919 To replace the original expressions with new ones, see the method
5920 :meth:`_expression.Select.with_only_columns`.
5921
5922 :param \*entities: column, table, or other entity expressions to be
5923 added to the columns clause
5924
5925 .. seealso::
5926
5927 :meth:`_expression.Select.with_only_columns` - replaces existing
5928 expressions rather than appending.
5929
5930 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric
5931 example
5932
5933 """
5934 self._reset_memoizations()
5935
5936 self._raw_columns = self._raw_columns + [
5937 coercions.expect(
5938 roles.ColumnsClauseRole, column, apply_propagate_attrs=self
5939 )
5940 for column in entities
5941 ]
5942 return self
5943
5944 def _set_entities(
5945 self, entities: Iterable[_ColumnsClauseArgument[Any]]
5946 ) -> None:
5947 self._raw_columns = [
5948 coercions.expect(
5949 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self
5950 )
5951 for ent in util.to_list(entities)
5952 ]
5953
5954 @util.deprecated(
5955 "1.4",
5956 "The :meth:`_expression.Select.column` method is deprecated and will "
5957 "be removed in a future release. Please use "
5958 ":meth:`_expression.Select.add_columns`",
5959 )
5960 def column(self, column: _ColumnsClauseArgument[Any]) -> Select[Any]:
5961 """Return a new :func:`_expression.select` construct with
5962 the given column expression added to its columns clause.
5963
5964 E.g.::
5965
5966 my_select = my_select.column(table.c.new_column)
5967
5968 See the documentation for
5969 :meth:`_expression.Select.with_only_columns`
5970 for guidelines on adding /replacing the columns of a
5971 :class:`_expression.Select` object.
5972
5973 """
5974 return self.add_columns(column)
5975
5976 @util.preload_module("sqlalchemy.sql.util")
5977 def reduce_columns(self, only_synonyms: bool = True) -> Select[Any]:
5978 """Return a new :func:`_expression.select` construct with redundantly
5979 named, equivalently-valued columns removed from the columns clause.
5980
5981 "Redundant" here means two columns where one refers to the
5982 other either based on foreign key, or via a simple equality
5983 comparison in the WHERE clause of the statement. The primary purpose
5984 of this method is to automatically construct a select statement
5985 with all uniquely-named columns, without the need to use
5986 table-qualified labels as
5987 :meth:`_expression.Select.set_label_style`
5988 does.
5989
5990 When columns are omitted based on foreign key, the referred-to
5991 column is the one that's kept. When columns are omitted based on
5992 WHERE equivalence, the first column in the columns clause is the
5993 one that's kept.
5994
5995 :param only_synonyms: when True, limit the removal of columns
5996 to those which have the same name as the equivalent. Otherwise,
5997 all columns that are equivalent to another are removed.
5998
5999 """
6000 woc: Select[Any]
6001 woc = self.with_only_columns(
6002 *util.preloaded.sql_util.reduce_columns(
6003 self._all_selected_columns,
6004 only_synonyms=only_synonyms,
6005 *(self._where_criteria + self._from_obj),
6006 )
6007 )
6008 return woc
6009
6010 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501
6011
6012 # code within this block is **programmatically,
6013 # statically generated** by tools/generate_tuple_map_overloads.py
6014
6015 @overload
6016 def with_only_columns(
6017 self, __ent0: _TCCA[_T0], *, maintain_column_froms: bool = ...
6018 ) -> Select[Tuple[_T0]]: ...
6019
6020 @overload
6021 def with_only_columns(
6022 self,
6023 __ent0: _TCCA[_T0],
6024 __ent1: _TCCA[_T1],
6025 *,
6026 maintain_column_froms: bool = ...,
6027 ) -> Select[Tuple[_T0, _T1]]: ...
6028
6029 @overload
6030 def with_only_columns(
6031 self,
6032 __ent0: _TCCA[_T0],
6033 __ent1: _TCCA[_T1],
6034 __ent2: _TCCA[_T2],
6035 *,
6036 maintain_column_froms: bool = ...,
6037 ) -> Select[Tuple[_T0, _T1, _T2]]: ...
6038
6039 @overload
6040 def with_only_columns(
6041 self,
6042 __ent0: _TCCA[_T0],
6043 __ent1: _TCCA[_T1],
6044 __ent2: _TCCA[_T2],
6045 __ent3: _TCCA[_T3],
6046 *,
6047 maintain_column_froms: bool = ...,
6048 ) -> Select[Tuple[_T0, _T1, _T2, _T3]]: ...
6049
6050 @overload
6051 def with_only_columns(
6052 self,
6053 __ent0: _TCCA[_T0],
6054 __ent1: _TCCA[_T1],
6055 __ent2: _TCCA[_T2],
6056 __ent3: _TCCA[_T3],
6057 __ent4: _TCCA[_T4],
6058 *,
6059 maintain_column_froms: bool = ...,
6060 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
6061
6062 @overload
6063 def with_only_columns(
6064 self,
6065 __ent0: _TCCA[_T0],
6066 __ent1: _TCCA[_T1],
6067 __ent2: _TCCA[_T2],
6068 __ent3: _TCCA[_T3],
6069 __ent4: _TCCA[_T4],
6070 __ent5: _TCCA[_T5],
6071 *,
6072 maintain_column_froms: bool = ...,
6073 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
6074
6075 @overload
6076 def with_only_columns(
6077 self,
6078 __ent0: _TCCA[_T0],
6079 __ent1: _TCCA[_T1],
6080 __ent2: _TCCA[_T2],
6081 __ent3: _TCCA[_T3],
6082 __ent4: _TCCA[_T4],
6083 __ent5: _TCCA[_T5],
6084 __ent6: _TCCA[_T6],
6085 *,
6086 maintain_column_froms: bool = ...,
6087 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
6088
6089 @overload
6090 def with_only_columns(
6091 self,
6092 __ent0: _TCCA[_T0],
6093 __ent1: _TCCA[_T1],
6094 __ent2: _TCCA[_T2],
6095 __ent3: _TCCA[_T3],
6096 __ent4: _TCCA[_T4],
6097 __ent5: _TCCA[_T5],
6098 __ent6: _TCCA[_T6],
6099 __ent7: _TCCA[_T7],
6100 *,
6101 maintain_column_froms: bool = ...,
6102 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ...
6103
6104 # END OVERLOADED FUNCTIONS self.with_only_columns
6105
6106 @overload
6107 def with_only_columns(
6108 self,
6109 *entities: _ColumnsClauseArgument[Any],
6110 maintain_column_froms: bool = False,
6111 **__kw: Any,
6112 ) -> Select[Any]: ...
6113
6114 @_generative
6115 def with_only_columns(
6116 self,
6117 *entities: _ColumnsClauseArgument[Any],
6118 maintain_column_froms: bool = False,
6119 **__kw: Any,
6120 ) -> Select[Any]:
6121 r"""Return a new :func:`_expression.select` construct with its columns
6122 clause replaced with the given entities.
6123
6124 By default, this method is exactly equivalent to as if the original
6125 :func:`_expression.select` had been called with the given entities.
6126 E.g. a statement::
6127
6128 s = select(table1.c.a, table1.c.b)
6129 s = s.with_only_columns(table1.c.b)
6130
6131 should be exactly equivalent to::
6132
6133 s = select(table1.c.b)
6134
6135 In this mode of operation, :meth:`_sql.Select.with_only_columns`
6136 will also dynamically alter the FROM clause of the
6137 statement if it is not explicitly stated.
6138 To maintain the existing set of FROMs including those implied by the
6139 current columns clause, add the
6140 :paramref:`_sql.Select.with_only_columns.maintain_column_froms`
6141 parameter::
6142
6143 s = select(table1.c.a, table2.c.b)
6144 s = s.with_only_columns(table1.c.a, maintain_column_froms=True)
6145
6146 The above parameter performs a transfer of the effective FROMs
6147 in the columns collection to the :meth:`_sql.Select.select_from`
6148 method, as though the following were invoked::
6149
6150 s = select(table1.c.a, table2.c.b)
6151 s = s.select_from(table1, table2).with_only_columns(table1.c.a)
6152
6153 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms`
6154 parameter makes use of the :attr:`_sql.Select.columns_clause_froms`
6155 collection and performs an operation equivalent to the following::
6156
6157 s = select(table1.c.a, table2.c.b)
6158 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a)
6159
6160 :param \*entities: column expressions to be used.
6161
6162 :param maintain_column_froms: boolean parameter that will ensure the
6163 FROM list implied from the current columns clause will be transferred
6164 to the :meth:`_sql.Select.select_from` method first.
6165
6166 .. versionadded:: 1.4.23
6167
6168 """ # noqa: E501
6169
6170 if __kw:
6171 raise _no_kw()
6172
6173 # memoizations should be cleared here as of
6174 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this
6175 # is the case for now.
6176 self._assert_no_memoizations()
6177
6178 if maintain_column_froms:
6179 self.select_from.non_generative( # type: ignore
6180 self, *self.columns_clause_froms
6181 )
6182
6183 # then memoize the FROMs etc.
6184 _MemoizedSelectEntities._generate_for_statement(self)
6185
6186 self._raw_columns = [
6187 coercions.expect(roles.ColumnsClauseRole, c)
6188 for c in coercions._expression_collection_was_a_list(
6189 "entities", "Select.with_only_columns", entities
6190 )
6191 ]
6192 return self
6193
6194 @property
6195 def whereclause(self) -> Optional[ColumnElement[Any]]:
6196 """Return the completed WHERE clause for this
6197 :class:`_expression.Select` statement.
6198
6199 This assembles the current collection of WHERE criteria
6200 into a single :class:`_expression.BooleanClauseList` construct.
6201
6202
6203 .. versionadded:: 1.4
6204
6205 """
6206
6207 return BooleanClauseList._construct_for_whereclause(
6208 self._where_criteria
6209 )
6210
6211 _whereclause = whereclause
6212
6213 @_generative
6214 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self:
6215 """Return a new :func:`_expression.select` construct with
6216 the given expression added to
6217 its WHERE clause, joined to the existing clause via AND, if any.
6218
6219 """
6220
6221 assert isinstance(self._where_criteria, tuple)
6222
6223 for criterion in whereclause:
6224 where_criteria: ColumnElement[Any] = coercions.expect(
6225 roles.WhereHavingRole, criterion, apply_propagate_attrs=self
6226 )
6227 self._where_criteria += (where_criteria,)
6228 return self
6229
6230 @_generative
6231 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self:
6232 """Return a new :func:`_expression.select` construct with
6233 the given expression added to
6234 its HAVING clause, joined to the existing clause via AND, if any.
6235
6236 """
6237
6238 for criterion in having:
6239 having_criteria = coercions.expect(
6240 roles.WhereHavingRole, criterion, apply_propagate_attrs=self
6241 )
6242 self._having_criteria += (having_criteria,)
6243 return self
6244
6245 @_generative
6246 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self:
6247 r"""Return a new :func:`_expression.select` construct which
6248 will apply DISTINCT to the SELECT statement overall.
6249
6250 E.g.::
6251
6252 from sqlalchemy import select
6253
6254 stmt = select(users_table.c.id, users_table.c.name).distinct()
6255
6256 The above would produce an statement resembling:
6257
6258 .. sourcecode:: sql
6259
6260 SELECT DISTINCT user.id, user.name FROM user
6261
6262 The method also accepts an ``*expr`` parameter which produces the
6263 PostgreSQL dialect-specific ``DISTINCT ON`` expression. Using this
6264 parameter on other backends which don't support this syntax will
6265 raise an error.
6266
6267 :param \*expr: optional column expressions. When present,
6268 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)``
6269 construct. A deprecation warning and/or :class:`_exc.CompileError`
6270 will be raised on other backends.
6271
6272 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated
6273 and will raise :class:`_exc.CompileError` in a future version.
6274
6275 """
6276 if expr:
6277 self._distinct = True
6278 self._distinct_on = self._distinct_on + tuple(
6279 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self)
6280 for e in expr
6281 )
6282 else:
6283 self._distinct = True
6284 return self
6285
6286 @_generative
6287 def select_from(self, *froms: _FromClauseArgument) -> Self:
6288 r"""Return a new :func:`_expression.select` construct with the
6289 given FROM expression(s)
6290 merged into its list of FROM objects.
6291
6292 E.g.::
6293
6294 table1 = table("t1", column("a"))
6295 table2 = table("t2", column("b"))
6296 s = select(table1.c.a).select_from(
6297 table1.join(table2, table1.c.a == table2.c.b)
6298 )
6299
6300 The "from" list is a unique set on the identity of each element,
6301 so adding an already present :class:`_schema.Table`
6302 or other selectable
6303 will have no effect. Passing a :class:`_expression.Join` that refers
6304 to an already present :class:`_schema.Table`
6305 or other selectable will have
6306 the effect of concealing the presence of that selectable as
6307 an individual element in the rendered FROM list, instead
6308 rendering it into a JOIN clause.
6309
6310 While the typical purpose of :meth:`_expression.Select.select_from`
6311 is to
6312 replace the default, derived FROM clause with a join, it can
6313 also be called with individual table elements, multiple times
6314 if desired, in the case that the FROM clause cannot be fully
6315 derived from the columns clause::
6316
6317 select(func.count("*")).select_from(table1)
6318
6319 """
6320
6321 self._from_obj += tuple(
6322 coercions.expect(
6323 roles.FromClauseRole, fromclause, apply_propagate_attrs=self
6324 )
6325 for fromclause in froms
6326 )
6327 return self
6328
6329 @_generative
6330 def correlate(
6331 self,
6332 *fromclauses: Union[Literal[None, False], _FromClauseArgument],
6333 ) -> Self:
6334 r"""Return a new :class:`_expression.Select`
6335 which will correlate the given FROM
6336 clauses to that of an enclosing :class:`_expression.Select`.
6337
6338 Calling this method turns off the :class:`_expression.Select` object's
6339 default behavior of "auto-correlation". Normally, FROM elements
6340 which appear in a :class:`_expression.Select`
6341 that encloses this one via
6342 its :term:`WHERE clause`, ORDER BY, HAVING or
6343 :term:`columns clause` will be omitted from this
6344 :class:`_expression.Select`
6345 object's :term:`FROM clause`.
6346 Setting an explicit correlation collection using the
6347 :meth:`_expression.Select.correlate`
6348 method provides a fixed list of FROM objects
6349 that can potentially take place in this process.
6350
6351 When :meth:`_expression.Select.correlate`
6352 is used to apply specific FROM clauses
6353 for correlation, the FROM elements become candidates for
6354 correlation regardless of how deeply nested this
6355 :class:`_expression.Select`
6356 object is, relative to an enclosing :class:`_expression.Select`
6357 which refers to
6358 the same FROM object. This is in contrast to the behavior of
6359 "auto-correlation" which only correlates to an immediate enclosing
6360 :class:`_expression.Select`.
6361 Multi-level correlation ensures that the link
6362 between enclosed and enclosing :class:`_expression.Select`
6363 is always via
6364 at least one WHERE/ORDER BY/HAVING/columns clause in order for
6365 correlation to take place.
6366
6367 If ``None`` is passed, the :class:`_expression.Select`
6368 object will correlate
6369 none of its FROM entries, and all will render unconditionally
6370 in the local FROM clause.
6371
6372 :param \*fromclauses: one or more :class:`.FromClause` or other
6373 FROM-compatible construct such as an ORM mapped entity to become part
6374 of the correlate collection; alternatively pass a single value
6375 ``None`` to remove all existing correlations.
6376
6377 .. seealso::
6378
6379 :meth:`_expression.Select.correlate_except`
6380
6381 :ref:`tutorial_scalar_subquery`
6382
6383 """
6384
6385 # tests failing when we try to change how these
6386 # arguments are passed
6387
6388 self._auto_correlate = False
6389 if not fromclauses or fromclauses[0] in {None, False}:
6390 if len(fromclauses) > 1:
6391 raise exc.ArgumentError(
6392 "additional FROM objects not accepted when "
6393 "passing None/False to correlate()"
6394 )
6395 self._correlate = ()
6396 else:
6397 self._correlate = self._correlate + tuple(
6398 coercions.expect(roles.FromClauseRole, f) for f in fromclauses
6399 )
6400 return self
6401
6402 @_generative
6403 def correlate_except(
6404 self,
6405 *fromclauses: Union[Literal[None, False], _FromClauseArgument],
6406 ) -> Self:
6407 r"""Return a new :class:`_expression.Select`
6408 which will omit the given FROM
6409 clauses from the auto-correlation process.
6410
6411 Calling :meth:`_expression.Select.correlate_except` turns off the
6412 :class:`_expression.Select` object's default behavior of
6413 "auto-correlation" for the given FROM elements. An element
6414 specified here will unconditionally appear in the FROM list, while
6415 all other FROM elements remain subject to normal auto-correlation
6416 behaviors.
6417
6418 If ``None`` is passed, or no arguments are passed,
6419 the :class:`_expression.Select` object will correlate all of its
6420 FROM entries.
6421
6422 :param \*fromclauses: a list of one or more
6423 :class:`_expression.FromClause`
6424 constructs, or other compatible constructs (i.e. ORM-mapped
6425 classes) to become part of the correlate-exception collection.
6426
6427 .. seealso::
6428
6429 :meth:`_expression.Select.correlate`
6430
6431 :ref:`tutorial_scalar_subquery`
6432
6433 """
6434
6435 self._auto_correlate = False
6436 if not fromclauses or fromclauses[0] in {None, False}:
6437 if len(fromclauses) > 1:
6438 raise exc.ArgumentError(
6439 "additional FROM objects not accepted when "
6440 "passing None/False to correlate_except()"
6441 )
6442 self._correlate_except = ()
6443 else:
6444 self._correlate_except = (self._correlate_except or ()) + tuple(
6445 coercions.expect(roles.FromClauseRole, f) for f in fromclauses
6446 )
6447
6448 return self
6449
6450 @HasMemoized_ro_memoized_attribute
6451 def selected_columns(
6452 self,
6453 ) -> ColumnCollection[str, ColumnElement[Any]]:
6454 """A :class:`_expression.ColumnCollection`
6455 representing the columns that
6456 this SELECT statement or similar construct returns in its result set,
6457 not including :class:`_sql.TextClause` constructs.
6458
6459 This collection differs from the :attr:`_expression.FromClause.columns`
6460 collection of a :class:`_expression.FromClause` in that the columns
6461 within this collection cannot be directly nested inside another SELECT
6462 statement; a subquery must be applied first which provides for the
6463 necessary parenthesization required by SQL.
6464
6465 For a :func:`_expression.select` construct, the collection here is
6466 exactly what would be rendered inside the "SELECT" statement, and the
6467 :class:`_expression.ColumnElement` objects are directly present as they
6468 were given, e.g.::
6469
6470 col1 = column("q", Integer)
6471 col2 = column("p", Integer)
6472 stmt = select(col1, col2)
6473
6474 Above, ``stmt.selected_columns`` would be a collection that contains
6475 the ``col1`` and ``col2`` objects directly. For a statement that is
6476 against a :class:`_schema.Table` or other
6477 :class:`_expression.FromClause`, the collection will use the
6478 :class:`_expression.ColumnElement` objects that are in the
6479 :attr:`_expression.FromClause.c` collection of the from element.
6480
6481 A use case for the :attr:`_sql.Select.selected_columns` collection is
6482 to allow the existing columns to be referenced when adding additional
6483 criteria, e.g.::
6484
6485 def filter_on_id(my_select, id):
6486 return my_select.where(my_select.selected_columns["id"] == id)
6487
6488
6489 stmt = select(MyModel)
6490
6491 # adds "WHERE id=:param" to the statement
6492 stmt = filter_on_id(stmt, 42)
6493
6494 .. note::
6495
6496 The :attr:`_sql.Select.selected_columns` collection does not
6497 include expressions established in the columns clause using the
6498 :func:`_sql.text` construct; these are silently omitted from the
6499 collection. To use plain textual column expressions inside of a
6500 :class:`_sql.Select` construct, use the :func:`_sql.literal_column`
6501 construct.
6502
6503
6504 .. versionadded:: 1.4
6505
6506 """
6507
6508 # compare to SelectState._generate_columns_plus_names, which
6509 # generates the actual names used in the SELECT string. that
6510 # method is more complex because it also renders columns that are
6511 # fully ambiguous, e.g. same column more than once.
6512 conv = cast(
6513 "Callable[[Any], str]",
6514 SelectState._column_naming_convention(self._label_style),
6515 )
6516
6517 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection(
6518 [
6519 (conv(c), c)
6520 for c in self._all_selected_columns
6521 if is_column_element(c)
6522 ]
6523 )
6524 return cc.as_readonly()
6525
6526 @HasMemoized_ro_memoized_attribute
6527 def _all_selected_columns(self) -> _SelectIterable:
6528 meth = SelectState.get_plugin_class(self).all_selected_columns
6529 return list(meth(self))
6530
6531 def _ensure_disambiguated_names(self) -> Select[Any]:
6532 if self._label_style is LABEL_STYLE_NONE:
6533 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
6534 return self
6535
6536 def _generate_fromclause_column_proxies(
6537 self,
6538 subquery: FromClause,
6539 columns: ColumnCollection[str, KeyedColumnElement[Any]],
6540 primary_key: ColumnSet,
6541 foreign_keys: Set[KeyedColumnElement[Any]],
6542 *,
6543 proxy_compound_columns: Optional[
6544 Iterable[Sequence[ColumnElement[Any]]]
6545 ] = None,
6546 ) -> None:
6547 """Generate column proxies to place in the exported ``.c``
6548 collection of a subquery."""
6549
6550 if proxy_compound_columns:
6551 extra_col_iterator = proxy_compound_columns
6552 prox = [
6553 c._make_proxy(
6554 subquery,
6555 key=proxy_key,
6556 name=required_label_name,
6557 name_is_truncatable=True,
6558 compound_select_cols=extra_cols,
6559 primary_key=primary_key,
6560 foreign_keys=foreign_keys,
6561 )
6562 for (
6563 (
6564 required_label_name,
6565 proxy_key,
6566 fallback_label_name,
6567 c,
6568 repeated,
6569 ),
6570 extra_cols,
6571 ) in (
6572 zip(
6573 self._generate_columns_plus_names(False),
6574 extra_col_iterator,
6575 )
6576 )
6577 if is_column_element(c)
6578 ]
6579 else:
6580 prox = [
6581 c._make_proxy(
6582 subquery,
6583 key=proxy_key,
6584 name=required_label_name,
6585 name_is_truncatable=True,
6586 primary_key=primary_key,
6587 foreign_keys=foreign_keys,
6588 )
6589 for (
6590 required_label_name,
6591 proxy_key,
6592 fallback_label_name,
6593 c,
6594 repeated,
6595 ) in (self._generate_columns_plus_names(False))
6596 if is_column_element(c)
6597 ]
6598
6599 columns._populate_separate_keys(prox)
6600
6601 def _needs_parens_for_grouping(self) -> bool:
6602 return self._has_row_limiting_clause or bool(
6603 self._order_by_clause.clauses
6604 )
6605
6606 def self_group(
6607 self, against: Optional[OperatorType] = None
6608 ) -> Union[SelectStatementGrouping[Self], Self]:
6609 """Return a 'grouping' construct as per the
6610 :class:`_expression.ClauseElement` specification.
6611
6612 This produces an element that can be embedded in an expression. Note
6613 that this method is called automatically as needed when constructing
6614 expressions and should not require explicit use.
6615
6616 """
6617 if (
6618 isinstance(against, CompoundSelect)
6619 and not self._needs_parens_for_grouping()
6620 ):
6621 return self
6622 else:
6623 return SelectStatementGrouping(self)
6624
6625 def union(
6626 self, *other: _SelectStatementForCompoundArgument[_TP]
6627 ) -> CompoundSelect[_TP]:
6628 r"""Return a SQL ``UNION`` of this select() construct against
6629 the given selectables provided as positional arguments.
6630
6631 :param \*other: one or more elements with which to create a
6632 UNION.
6633
6634 .. versionchanged:: 1.4.28
6635
6636 multiple elements are now accepted.
6637
6638 :param \**kwargs: keyword arguments are forwarded to the constructor
6639 for the newly created :class:`_sql.CompoundSelect` object.
6640
6641 """
6642 return CompoundSelect._create_union(self, *other)
6643
6644 def union_all(
6645 self, *other: _SelectStatementForCompoundArgument[_TP]
6646 ) -> CompoundSelect[_TP]:
6647 r"""Return a SQL ``UNION ALL`` of this select() construct against
6648 the given selectables provided as positional arguments.
6649
6650 :param \*other: one or more elements with which to create a
6651 UNION.
6652
6653 .. versionchanged:: 1.4.28
6654
6655 multiple elements are now accepted.
6656
6657 :param \**kwargs: keyword arguments are forwarded to the constructor
6658 for the newly created :class:`_sql.CompoundSelect` object.
6659
6660 """
6661 return CompoundSelect._create_union_all(self, *other)
6662
6663 def except_(
6664 self, *other: _SelectStatementForCompoundArgument[_TP]
6665 ) -> CompoundSelect[_TP]:
6666 r"""Return a SQL ``EXCEPT`` of this select() construct against
6667 the given selectable provided as positional arguments.
6668
6669 :param \*other: one or more elements with which to create a
6670 UNION.
6671
6672 .. versionchanged:: 1.4.28
6673
6674 multiple elements are now accepted.
6675
6676 """
6677 return CompoundSelect._create_except(self, *other)
6678
6679 def except_all(
6680 self, *other: _SelectStatementForCompoundArgument[_TP]
6681 ) -> CompoundSelect[_TP]:
6682 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against
6683 the given selectables provided as positional arguments.
6684
6685 :param \*other: one or more elements with which to create a
6686 UNION.
6687
6688 .. versionchanged:: 1.4.28
6689
6690 multiple elements are now accepted.
6691
6692 """
6693 return CompoundSelect._create_except_all(self, *other)
6694
6695 def intersect(
6696 self, *other: _SelectStatementForCompoundArgument[_TP]
6697 ) -> CompoundSelect[_TP]:
6698 r"""Return a SQL ``INTERSECT`` of this select() construct against
6699 the given selectables provided as positional arguments.
6700
6701 :param \*other: one or more elements with which to create a
6702 UNION.
6703
6704 .. versionchanged:: 1.4.28
6705
6706 multiple elements are now accepted.
6707
6708 :param \**kwargs: keyword arguments are forwarded to the constructor
6709 for the newly created :class:`_sql.CompoundSelect` object.
6710
6711 """
6712 return CompoundSelect._create_intersect(self, *other)
6713
6714 def intersect_all(
6715 self, *other: _SelectStatementForCompoundArgument[_TP]
6716 ) -> CompoundSelect[_TP]:
6717 r"""Return a SQL ``INTERSECT ALL`` of this select() construct
6718 against the given selectables provided as positional arguments.
6719
6720 :param \*other: one or more elements with which to create a
6721 UNION.
6722
6723 .. versionchanged:: 1.4.28
6724
6725 multiple elements are now accepted.
6726
6727 :param \**kwargs: keyword arguments are forwarded to the constructor
6728 for the newly created :class:`_sql.CompoundSelect` object.
6729
6730 """
6731 return CompoundSelect._create_intersect_all(self, *other)
6732
6733
6734class ScalarSelect(
6735 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T]
6736):
6737 """Represent a scalar subquery.
6738
6739
6740 A :class:`_sql.ScalarSelect` is created by invoking the
6741 :meth:`_sql.SelectBase.scalar_subquery` method. The object
6742 then participates in other SQL expressions as a SQL column expression
6743 within the :class:`_sql.ColumnElement` hierarchy.
6744
6745 .. seealso::
6746
6747 :meth:`_sql.SelectBase.scalar_subquery`
6748
6749 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
6750
6751 """
6752
6753 _traverse_internals: _TraverseInternalsType = [
6754 ("element", InternalTraversal.dp_clauseelement),
6755 ("type", InternalTraversal.dp_type),
6756 ]
6757
6758 _from_objects: List[FromClause] = []
6759 _is_from_container = True
6760 if not TYPE_CHECKING:
6761 _is_implicitly_boolean = False
6762 inherit_cache = True
6763
6764 element: SelectBase
6765
6766 def __init__(self, element: SelectBase) -> None:
6767 self.element = element
6768 self.type = element._scalar_type()
6769 self._propagate_attrs = element._propagate_attrs
6770
6771 def __getattr__(self, attr: str) -> Any:
6772 return getattr(self.element, attr)
6773
6774 def __getstate__(self) -> Dict[str, Any]:
6775 return {"element": self.element, "type": self.type}
6776
6777 def __setstate__(self, state: Dict[str, Any]) -> None:
6778 self.element = state["element"]
6779 self.type = state["type"]
6780
6781 @property
6782 def columns(self) -> NoReturn:
6783 raise exc.InvalidRequestError(
6784 "Scalar Select expression has no "
6785 "columns; use this object directly "
6786 "within a column-level expression."
6787 )
6788
6789 c = columns
6790
6791 @_generative
6792 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self:
6793 """Apply a WHERE clause to the SELECT statement referred to
6794 by this :class:`_expression.ScalarSelect`.
6795
6796 """
6797 self.element = cast("Select[Any]", self.element).where(crit)
6798 return self
6799
6800 def self_group(self, against: Optional[OperatorType] = None) -> Self:
6801 return self
6802
6803 def _ungroup(self) -> Self:
6804 return self
6805
6806 @_generative
6807 def correlate(
6808 self,
6809 *fromclauses: Union[Literal[None, False], _FromClauseArgument],
6810 ) -> Self:
6811 r"""Return a new :class:`_expression.ScalarSelect`
6812 which will correlate the given FROM
6813 clauses to that of an enclosing :class:`_expression.Select`.
6814
6815 This method is mirrored from the :meth:`_sql.Select.correlate` method
6816 of the underlying :class:`_sql.Select`. The method applies the
6817 :meth:_sql.Select.correlate` method, then returns a new
6818 :class:`_sql.ScalarSelect` against that statement.
6819
6820 .. versionadded:: 1.4 Previously, the
6821 :meth:`_sql.ScalarSelect.correlate`
6822 method was only available from :class:`_sql.Select`.
6823
6824 :param \*fromclauses: a list of one or more
6825 :class:`_expression.FromClause`
6826 constructs, or other compatible constructs (i.e. ORM-mapped
6827 classes) to become part of the correlate collection.
6828
6829 .. seealso::
6830
6831 :meth:`_expression.ScalarSelect.correlate_except`
6832
6833 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
6834
6835
6836 """
6837 self.element = cast("Select[Any]", self.element).correlate(
6838 *fromclauses
6839 )
6840 return self
6841
6842 @_generative
6843 def correlate_except(
6844 self,
6845 *fromclauses: Union[Literal[None, False], _FromClauseArgument],
6846 ) -> Self:
6847 r"""Return a new :class:`_expression.ScalarSelect`
6848 which will omit the given FROM
6849 clauses from the auto-correlation process.
6850
6851 This method is mirrored from the
6852 :meth:`_sql.Select.correlate_except` method of the underlying
6853 :class:`_sql.Select`. The method applies the
6854 :meth:_sql.Select.correlate_except` method, then returns a new
6855 :class:`_sql.ScalarSelect` against that statement.
6856
6857 .. versionadded:: 1.4 Previously, the
6858 :meth:`_sql.ScalarSelect.correlate_except`
6859 method was only available from :class:`_sql.Select`.
6860
6861 :param \*fromclauses: a list of one or more
6862 :class:`_expression.FromClause`
6863 constructs, or other compatible constructs (i.e. ORM-mapped
6864 classes) to become part of the correlate-exception collection.
6865
6866 .. seealso::
6867
6868 :meth:`_expression.ScalarSelect.correlate`
6869
6870 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
6871
6872
6873 """
6874
6875 self.element = cast("Select[Any]", self.element).correlate_except(
6876 *fromclauses
6877 )
6878 return self
6879
6880
6881class Exists(UnaryExpression[bool]):
6882 """Represent an ``EXISTS`` clause.
6883
6884 See :func:`_sql.exists` for a description of usage.
6885
6886 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select`
6887 instance by calling :meth:`_sql.SelectBase.exists`.
6888
6889 """
6890
6891 inherit_cache = True
6892
6893 def __init__(
6894 self,
6895 __argument: Optional[
6896 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]]
6897 ] = None,
6898 ):
6899 s: ScalarSelect[Any]
6900
6901 # TODO: this seems like we should be using coercions for this
6902 if __argument is None:
6903 s = Select(literal_column("*")).scalar_subquery()
6904 elif isinstance(__argument, SelectBase):
6905 s = __argument.scalar_subquery()
6906 s._propagate_attrs = __argument._propagate_attrs
6907 elif isinstance(__argument, ScalarSelect):
6908 s = __argument
6909 else:
6910 s = Select(__argument).scalar_subquery()
6911
6912 UnaryExpression.__init__(
6913 self,
6914 s,
6915 operator=operators.exists,
6916 type_=type_api.BOOLEANTYPE,
6917 )
6918
6919 @util.ro_non_memoized_property
6920 def _from_objects(self) -> List[FromClause]:
6921 return []
6922
6923 def _regroup(
6924 self,
6925 fn: Callable[[Select[Any]], Select[Any]],
6926 ) -> ScalarSelect[Any]:
6927
6928 assert isinstance(self.element, ScalarSelect)
6929 element = self.element.element
6930 if not isinstance(element, Select):
6931 raise exc.InvalidRequestError(
6932 "Can only apply this operation to a plain SELECT construct"
6933 )
6934 new_element = fn(element)
6935
6936 return_value = new_element.scalar_subquery()
6937 return return_value
6938
6939 def select(self) -> Select[Tuple[bool]]:
6940 r"""Return a SELECT of this :class:`_expression.Exists`.
6941
6942 e.g.::
6943
6944 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select()
6945
6946 This will produce a statement resembling:
6947
6948 .. sourcecode:: sql
6949
6950 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1
6951
6952 .. seealso::
6953
6954 :func:`_expression.select` - general purpose
6955 method which allows for arbitrary column lists.
6956
6957 """ # noqa
6958
6959 return Select(self)
6960
6961 def correlate(
6962 self,
6963 *fromclauses: Union[Literal[None, False], _FromClauseArgument],
6964 ) -> Self:
6965 """Apply correlation to the subquery noted by this
6966 :class:`_sql.Exists`.
6967
6968 .. seealso::
6969
6970 :meth:`_sql.ScalarSelect.correlate`
6971
6972 """
6973 e = self._clone()
6974 e.element = self._regroup(
6975 lambda element: element.correlate(*fromclauses)
6976 )
6977 return e
6978
6979 def correlate_except(
6980 self,
6981 *fromclauses: Union[Literal[None, False], _FromClauseArgument],
6982 ) -> Self:
6983 """Apply correlation to the subquery noted by this
6984 :class:`_sql.Exists`.
6985
6986 .. seealso::
6987
6988 :meth:`_sql.ScalarSelect.correlate_except`
6989
6990 """
6991 e = self._clone()
6992 e.element = self._regroup(
6993 lambda element: element.correlate_except(*fromclauses)
6994 )
6995 return e
6996
6997 def select_from(self, *froms: _FromClauseArgument) -> Self:
6998 """Return a new :class:`_expression.Exists` construct,
6999 applying the given
7000 expression to the :meth:`_expression.Select.select_from`
7001 method of the select
7002 statement contained.
7003
7004 .. note:: it is typically preferable to build a :class:`_sql.Select`
7005 statement first, including the desired WHERE clause, then use the
7006 :meth:`_sql.SelectBase.exists` method to produce an
7007 :class:`_sql.Exists` object at once.
7008
7009 """
7010 e = self._clone()
7011 e.element = self._regroup(lambda element: element.select_from(*froms))
7012 return e
7013
7014 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self:
7015 """Return a new :func:`_expression.exists` construct with the
7016 given expression added to
7017 its WHERE clause, joined to the existing clause via AND, if any.
7018
7019
7020 .. note:: it is typically preferable to build a :class:`_sql.Select`
7021 statement first, including the desired WHERE clause, then use the
7022 :meth:`_sql.SelectBase.exists` method to produce an
7023 :class:`_sql.Exists` object at once.
7024
7025 """
7026 e = self._clone()
7027 e.element = self._regroup(lambda element: element.where(*clause))
7028 return e
7029
7030
7031class TextualSelect(SelectBase, ExecutableReturnsRows, Generative):
7032 """Wrap a :class:`_expression.TextClause` construct within a
7033 :class:`_expression.SelectBase`
7034 interface.
7035
7036 This allows the :class:`_expression.TextClause` object to gain a
7037 ``.c`` collection
7038 and other FROM-like capabilities such as
7039 :meth:`_expression.FromClause.alias`,
7040 :meth:`_expression.SelectBase.cte`, etc.
7041
7042 The :class:`_expression.TextualSelect` construct is produced via the
7043 :meth:`_expression.TextClause.columns`
7044 method - see that method for details.
7045
7046 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect`
7047 class was renamed
7048 from ``TextAsFrom``, to more correctly suit its role as a
7049 SELECT-oriented object and not a FROM clause.
7050
7051 .. seealso::
7052
7053 :func:`_expression.text`
7054
7055 :meth:`_expression.TextClause.columns` - primary creation interface.
7056
7057 """
7058
7059 __visit_name__ = "textual_select"
7060
7061 _label_style = LABEL_STYLE_NONE
7062
7063 _traverse_internals: _TraverseInternalsType = (
7064 [
7065 ("element", InternalTraversal.dp_clauseelement),
7066 ("column_args", InternalTraversal.dp_clauseelement_list),
7067 ]
7068 + SupportsCloneAnnotations._clone_annotations_traverse_internals
7069 + HasCTE._has_ctes_traverse_internals
7070 )
7071
7072 _is_textual = True
7073
7074 is_text = True
7075 is_select = True
7076
7077 def __init__(
7078 self,
7079 text: TextClause,
7080 columns: List[_ColumnExpressionArgument[Any]],
7081 positional: bool = False,
7082 ) -> None:
7083 self._init(
7084 text,
7085 # convert for ORM attributes->columns, etc
7086 [
7087 coercions.expect(roles.LabeledColumnExprRole, c)
7088 for c in columns
7089 ],
7090 positional,
7091 )
7092
7093 def _init(
7094 self,
7095 text: TextClause,
7096 columns: List[NamedColumn[Any]],
7097 positional: bool = False,
7098 ) -> None:
7099 self.element = text
7100 self.column_args = columns
7101 self.positional = positional
7102
7103 @HasMemoized_ro_memoized_attribute
7104 def selected_columns(
7105 self,
7106 ) -> ColumnCollection[str, KeyedColumnElement[Any]]:
7107 """A :class:`_expression.ColumnCollection`
7108 representing the columns that
7109 this SELECT statement or similar construct returns in its result set,
7110 not including :class:`_sql.TextClause` constructs.
7111
7112 This collection differs from the :attr:`_expression.FromClause.columns`
7113 collection of a :class:`_expression.FromClause` in that the columns
7114 within this collection cannot be directly nested inside another SELECT
7115 statement; a subquery must be applied first which provides for the
7116 necessary parenthesization required by SQL.
7117
7118 For a :class:`_expression.TextualSelect` construct, the collection
7119 contains the :class:`_expression.ColumnElement` objects that were
7120 passed to the constructor, typically via the
7121 :meth:`_expression.TextClause.columns` method.
7122
7123
7124 .. versionadded:: 1.4
7125
7126 """
7127 return ColumnCollection(
7128 (c.key, c) for c in self.column_args
7129 ).as_readonly()
7130
7131 @util.ro_non_memoized_property
7132 def _all_selected_columns(self) -> _SelectIterable:
7133 return self.column_args
7134
7135 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect:
7136 return self
7137
7138 def _ensure_disambiguated_names(self) -> TextualSelect:
7139 return self
7140
7141 @_generative
7142 def bindparams(
7143 self,
7144 *binds: BindParameter[Any],
7145 **bind_as_values: Any,
7146 ) -> Self:
7147 self.element = self.element.bindparams(*binds, **bind_as_values)
7148 return self
7149
7150 def _generate_fromclause_column_proxies(
7151 self,
7152 fromclause: FromClause,
7153 columns: ColumnCollection[str, KeyedColumnElement[Any]],
7154 primary_key: ColumnSet,
7155 foreign_keys: Set[KeyedColumnElement[Any]],
7156 *,
7157 proxy_compound_columns: Optional[
7158 Iterable[Sequence[ColumnElement[Any]]]
7159 ] = None,
7160 ) -> None:
7161 if TYPE_CHECKING:
7162 assert isinstance(fromclause, Subquery)
7163
7164 if proxy_compound_columns:
7165 columns._populate_separate_keys(
7166 c._make_proxy(
7167 fromclause,
7168 compound_select_cols=extra_cols,
7169 primary_key=primary_key,
7170 foreign_keys=foreign_keys,
7171 )
7172 for c, extra_cols in zip(
7173 self.column_args, proxy_compound_columns
7174 )
7175 )
7176 else:
7177 columns._populate_separate_keys(
7178 c._make_proxy(
7179 fromclause,
7180 primary_key=primary_key,
7181 foreign_keys=foreign_keys,
7182 )
7183 for c in self.column_args
7184 )
7185
7186 def _scalar_type(self) -> Union[TypeEngine[Any], Any]:
7187 return self.column_args[0].type
7188
7189
7190TextAsFrom = TextualSelect
7191"""Backwards compatibility with the previous name"""
7192
7193
7194class AnnotatedFromClause(Annotated):
7195 def _copy_internals(self, **kw: Any) -> None:
7196 super()._copy_internals(**kw)
7197 if kw.get("ind_cols_on_fromclause", False):
7198 ee = self._Annotated__element # type: ignore
7199
7200 self.c = ee.__class__.c.fget(self) # type: ignore
7201
7202 @util.ro_memoized_property
7203 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
7204 """proxy the .c collection of the underlying FromClause.
7205
7206 Originally implemented in 2008 as a simple load of the .c collection
7207 when the annotated construct was created (see d3621ae961a), in modern
7208 SQLAlchemy versions this can be expensive for statements constructed
7209 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy
7210 it, which works just as well.
7211
7212 Two different use cases seem to require the collection either copied
7213 from the underlying one, or unique to this AnnotatedFromClause.
7214
7215 See test_selectable->test_annotated_corresponding_column
7216
7217 """
7218 ee = self._Annotated__element # type: ignore
7219 return ee.c # type: ignore