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