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