Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/selectable.py: 46%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1795 statements  

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 Literal 

30from typing import NamedTuple 

31from typing import NoReturn 

32from typing import Optional 

33from typing import overload 

34from typing import Protocol 

35from typing import Sequence 

36from typing import Set 

37from typing import Tuple 

38from typing import Type 

39from typing import TYPE_CHECKING 

40from typing import TypeVar 

41from typing import Union 

42 

43from . import cache_key 

44from . import coercions 

45from . import operators 

46from . import roles 

47from . import traversals 

48from . import type_api 

49from . import visitors 

50from ._typing import _ColumnsClauseArgument 

51from ._typing import _no_kw 

52from ._typing import _T 

53from ._typing import _Ts 

54from ._typing import is_column_element 

55from ._typing import is_select_statement 

56from ._typing import is_subquery 

57from ._typing import is_table 

58from ._typing import is_text_clause 

59from .annotation import Annotated 

60from .annotation import SupportsCloneAnnotations 

61from .base import _clone 

62from .base import _cloned_difference 

63from .base import _cloned_intersection 

64from .base import _entity_namespace_key 

65from .base import _EntityNamespace 

66from .base import _expand_cloned 

67from .base import _from_objects 

68from .base import _generative 

69from .base import _never_select_column 

70from .base import _NoArg 

71from .base import _select_iterables 

72from .base import CacheableOptions 

73from .base import ColumnCollection 

74from .base import ColumnSet 

75from .base import CompileState 

76from .base import DedupeColumnCollection 

77from .base import DialectKWArgs 

78from .base import Executable 

79from .base import ExecutableStatement 

80from .base import Generative 

81from .base import HasCompileState 

82from .base import HasMemoized 

83from .base import HasSyntaxExtensions 

84from .base import Immutable 

85from .base import SyntaxExtension 

86from .coercions import _document_text_coercion 

87from .elements import _anonymous_label 

88from .elements import BindParameter 

89from .elements import BooleanClauseList 

90from .elements import ClauseElement 

91from .elements import ClauseList 

92from .elements import ColumnClause 

93from .elements import ColumnElement 

94from .elements import DQLDMLClauseElement 

95from .elements import GroupedElement 

96from .elements import literal_column 

97from .elements import TableValuedColumn 

98from .elements import UnaryExpression 

99from .operators import OperatorType 

100from .sqltypes import NULLTYPE 

101from .visitors import _TraverseInternalsType 

102from .visitors import InternalTraversal 

103from .visitors import prefix_anon_map 

104from .. import exc 

105from .. import util 

106from ..util import HasMemoized_ro_memoized_attribute 

107from ..util import warn_deprecated 

108from ..util.typing import Self 

109from ..util.typing import TupleAny 

110from ..util.typing import Unpack 

111 

112 

113and_ = BooleanClauseList.and_ 

114 

115 

116if TYPE_CHECKING: 

117 from ._typing import _ColumnExpressionArgument 

118 from ._typing import _ColumnExpressionOrStrLabelArgument 

119 from ._typing import _FromClauseArgument 

120 from ._typing import _JoinTargetArgument 

121 from ._typing import _LimitOffsetType 

122 from ._typing import _MAYBE_ENTITY 

123 from ._typing import _NOT_ENTITY 

124 from ._typing import _OnClauseArgument 

125 from ._typing import _SelectStatementForCompoundArgument 

126 from ._typing import _T0 

127 from ._typing import _T1 

128 from ._typing import _T2 

129 from ._typing import _T3 

130 from ._typing import _T4 

131 from ._typing import _T5 

132 from ._typing import _T6 

133 from ._typing import _T7 

134 from ._typing import _TextCoercedExpressionArgument 

135 from ._typing import _TypedColumnClauseArgument as _TCCA 

136 from ._typing import _TypeEngineArgument 

137 from .base import _AmbiguousTableNameMap 

138 from .base import ExecutableOption 

139 from .base import ReadOnlyColumnCollection 

140 from .cache_key import _CacheKeyTraversalType 

141 from .compiler import SQLCompiler 

142 from .ddl import CreateTableAs 

143 from .dml import Delete 

144 from .dml import Update 

145 from .elements import BinaryExpression 

146 from .elements import KeyedColumnElement 

147 from .elements import Label 

148 from .elements import NamedColumn 

149 from .elements import TextClause 

150 from .functions import Function 

151 from .schema import ForeignKey 

152 from .schema import ForeignKeyConstraint 

153 from .schema import MetaData 

154 from .sqltypes import TableValueType 

155 from .type_api import TypeEngine 

156 from .visitors import _CloneCallableType 

157 

158 

159_ColumnsClauseElement = Union["FromClause", ColumnElement[Any], "TextClause"] 

160_LabelConventionCallable = Callable[ 

161 [Union["ColumnElement[Any]", "TextClause"]], Optional[str] 

162] 

163 

164 

165class _JoinTargetProtocol(Protocol): 

166 @util.ro_non_memoized_property 

167 def _from_objects(self) -> List[FromClause]: ... 

168 

169 @util.ro_non_memoized_property 

170 def entity_namespace(self) -> _EntityNamespace: ... 

171 

172 

173_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

174_OnClauseElement = Union["ColumnElement[bool]", _JoinTargetProtocol] 

175 

176_ForUpdateOfArgument = Union[ 

177 # single column, Table, ORM entity 

178 Union[ 

179 "_ColumnExpressionArgument[Any]", 

180 "_FromClauseArgument", 

181 ], 

182 # or sequence of column, Table, ORM entity 

183 Sequence[ 

184 Union[ 

185 "_ColumnExpressionArgument[Any]", 

186 "_FromClauseArgument", 

187 ] 

188 ], 

189] 

190 

191 

192_SetupJoinsElement = Tuple[ 

193 _JoinTargetElement, 

194 Optional[_OnClauseElement], 

195 Optional["FromClause"], 

196 Dict[str, Any], 

197] 

198 

199 

200_SelectIterable = Iterable[Union["ColumnElement[Any]", "TextClause"]] 

201 

202 

203class _OffsetLimitParam(BindParameter[int]): 

204 inherit_cache = True 

205 

206 @property 

207 def _limit_offset_value(self) -> Optional[int]: 

208 return self.effective_value 

209 

210 

211class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

212 """The base-most class for Core constructs that have some concept of 

213 columns that can represent rows. 

214 

215 While the SELECT statement and TABLE are the primary things we think 

216 of in this category, DML like INSERT, UPDATE and DELETE can also specify 

217 RETURNING which means they can be used in CTEs and other forms, and 

218 PostgreSQL has functions that return rows also. 

219 

220 .. versionadded:: 1.4 

221 

222 """ 

223 

224 _is_returns_rows = True 

225 

226 # sub-elements of returns_rows 

227 _is_from_clause = False 

228 _is_select_base = False 

229 _is_select_statement = False 

230 _is_lateral = False 

231 

232 @property 

233 def selectable(self) -> ReturnsRows: 

234 return self 

235 

236 @util.ro_non_memoized_property 

237 def _all_selected_columns(self) -> _SelectIterable: 

238 """A sequence of column expression objects that represents the 

239 "selected" columns of this :class:`_expression.ReturnsRows`. 

240 

241 This is typically equivalent to .exported_columns except it is 

242 delivered in the form of a straight sequence and not keyed 

243 :class:`_expression.ColumnCollection`. 

244 

245 """ 

246 raise NotImplementedError() 

247 

248 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

249 """Return ``True`` if this :class:`.ReturnsRows` is 

250 'derived' from the given :class:`.FromClause`. 

251 

252 An example would be an Alias of a Table is derived from that Table. 

253 

254 """ 

255 raise NotImplementedError() 

256 

257 def _generate_fromclause_column_proxies( 

258 self, 

259 fromclause: FromClause, 

260 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

261 primary_key: ColumnSet, 

262 foreign_keys: Set[KeyedColumnElement[Any]], 

263 ) -> None: 

264 """Populate columns into an :class:`.AliasedReturnsRows` object.""" 

265 

266 raise NotImplementedError() 

267 

268 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

269 """reset internal collections for an incoming column being added.""" 

270 raise NotImplementedError() 

271 

272 @property 

273 def exported_columns(self) -> ReadOnlyColumnCollection[Any, Any]: 

274 """A :class:`_expression.ColumnCollection` 

275 that represents the "exported" 

276 columns of this :class:`_expression.ReturnsRows`. 

277 

278 The "exported" columns represent the collection of 

279 :class:`_expression.ColumnElement` 

280 expressions that are rendered by this SQL 

281 construct. There are primary varieties which are the 

282 "FROM clause columns" of a FROM clause, such as a table, join, 

283 or subquery, the "SELECTed columns", which are the columns in 

284 the "columns clause" of a SELECT statement, and the RETURNING 

285 columns in a DML statement.. 

286 

287 .. versionadded:: 1.4 

288 

289 .. seealso:: 

290 

291 :attr:`_expression.FromClause.exported_columns` 

292 

293 :attr:`_expression.SelectBase.exported_columns` 

294 """ 

295 

296 raise NotImplementedError() 

297 

298 

299class ExecutableReturnsRows(ExecutableStatement, ReturnsRows): 

300 """base for executable statements that return rows.""" 

301 

302 

303class TypedReturnsRows(ExecutableReturnsRows, Generic[Unpack[_Ts]]): 

304 """base for a typed executable statements that return rows.""" 

305 

306 

307class Selectable(ReturnsRows): 

308 """Mark a class as being selectable.""" 

309 

310 __visit_name__ = "selectable" 

311 

312 is_selectable = True 

313 

314 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

315 raise NotImplementedError() 

316 

317 def lateral(self, name: Optional[str] = None) -> LateralFromClause: 

318 """Return a LATERAL alias of this :class:`_expression.Selectable`. 

319 

320 The return value is the :class:`_expression.Lateral` construct also 

321 provided by the top-level :func:`_expression.lateral` function. 

322 

323 .. seealso:: 

324 

325 :ref:`tutorial_lateral_correlation` - overview of usage. 

326 

327 """ 

328 return Lateral._construct(self, name=name) 

329 

330 @util.deprecated( 

331 "1.4", 

332 message="The :meth:`.Selectable.replace_selectable` method is " 

333 "deprecated, and will be removed in a future release. Similar " 

334 "functionality is available via the sqlalchemy.sql.visitors module.", 

335 ) 

336 @util.preload_module("sqlalchemy.sql.util") 

337 def replace_selectable(self, old: FromClause, alias: Alias) -> Self: 

338 """Replace all occurrences of :class:`_expression.FromClause` 

339 'old' with the given :class:`_expression.Alias` 

340 object, returning a copy of this :class:`_expression.FromClause`. 

341 

342 """ 

343 return util.preloaded.sql_util.ClauseAdapter(alias).traverse(self) 

344 

345 def corresponding_column( 

346 self, column: KeyedColumnElement[Any], require_embedded: bool = False 

347 ) -> Optional[KeyedColumnElement[Any]]: 

348 """Given a :class:`_expression.ColumnElement`, return the exported 

349 :class:`_expression.ColumnElement` object from the 

350 :attr:`_expression.Selectable.exported_columns` 

351 collection of this :class:`_expression.Selectable` 

352 which corresponds to that 

353 original :class:`_expression.ColumnElement` via a common ancestor 

354 column. 

355 

356 :param column: the target :class:`_expression.ColumnElement` 

357 to be matched. 

358 

359 :param require_embedded: only return corresponding columns for 

360 the given :class:`_expression.ColumnElement`, if the given 

361 :class:`_expression.ColumnElement` 

362 is actually present within a sub-element 

363 of this :class:`_expression.Selectable`. 

364 Normally the column will match if 

365 it merely shares a common ancestor with one of the exported 

366 columns of this :class:`_expression.Selectable`. 

367 

368 .. seealso:: 

369 

370 :attr:`_expression.Selectable.exported_columns` - the 

371 :class:`_expression.ColumnCollection` 

372 that is used for the operation. 

373 

374 :meth:`_expression.ColumnCollection.corresponding_column` 

375 - implementation 

376 method. 

377 

378 """ 

379 

380 return self.exported_columns.corresponding_column( 

381 column, require_embedded 

382 ) 

383 

384 

385class HasPrefixes: 

386 _prefixes: Tuple[Tuple[DQLDMLClauseElement, str], ...] = () 

387 

388 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

389 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

390 ] 

391 

392 @_generative 

393 @_document_text_coercion( 

394 "prefixes", 

395 ":meth:`_expression.HasPrefixes.prefix_with`", 

396 ":paramref:`.HasPrefixes.prefix_with.*prefixes`", 

397 ) 

398 def prefix_with( 

399 self, 

400 *prefixes: _TextCoercedExpressionArgument[Any], 

401 dialect: str = "*", 

402 ) -> Self: 

403 r"""Add one or more expressions following the statement keyword, i.e. 

404 SELECT, INSERT, UPDATE, or DELETE. Generative. 

405 

406 This is used to support backend-specific prefix keywords such as those 

407 provided by MySQL. 

408 

409 E.g.:: 

410 

411 stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql") 

412 

413 # MySQL 5.7 optimizer hints 

414 stmt = select(table).prefix_with("/*+ BKA(t1) */", dialect="mysql") 

415 

416 Multiple prefixes can be specified by multiple calls 

417 to :meth:`_expression.HasPrefixes.prefix_with`. 

418 

419 :param \*prefixes: textual or :class:`_expression.ClauseElement` 

420 construct which 

421 will be rendered following the INSERT, UPDATE, or DELETE 

422 keyword. 

423 :param dialect: optional string dialect name which will 

424 limit rendering of this prefix to only that dialect. 

425 

426 """ 

427 self._prefixes = self._prefixes + tuple( 

428 [ 

429 (coercions.expect(roles.StatementOptionRole, p), dialect) 

430 for p in prefixes 

431 ] 

432 ) 

433 return self 

434 

435 

436class HasSuffixes: 

437 _suffixes: Tuple[Tuple[DQLDMLClauseElement, str], ...] = () 

438 

439 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

440 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

441 ] 

442 

443 @_generative 

444 @_document_text_coercion( 

445 "suffixes", 

446 ":meth:`_expression.HasSuffixes.suffix_with`", 

447 ":paramref:`.HasSuffixes.suffix_with.*suffixes`", 

448 ) 

449 def suffix_with( 

450 self, 

451 *suffixes: _TextCoercedExpressionArgument[Any], 

452 dialect: str = "*", 

453 ) -> Self: 

454 r"""Add one or more expressions following the statement as a whole. 

455 

456 This is used to support backend-specific suffix keywords on 

457 certain constructs. 

458 

459 E.g.:: 

460 

461 stmt = ( 

462 select(col1, col2) 

463 .cte() 

464 .suffix_with( 

465 "cycle empno set y_cycle to 1 default 0", dialect="oracle" 

466 ) 

467 ) 

468 

469 Multiple suffixes can be specified by multiple calls 

470 to :meth:`_expression.HasSuffixes.suffix_with`. 

471 

472 :param \*suffixes: textual or :class:`_expression.ClauseElement` 

473 construct which 

474 will be rendered following the target clause. 

475 :param dialect: Optional string dialect name which will 

476 limit rendering of this suffix to only that dialect. 

477 

478 """ 

479 self._suffixes = self._suffixes + tuple( 

480 [ 

481 (coercions.expect(roles.StatementOptionRole, p), dialect) 

482 for p in suffixes 

483 ] 

484 ) 

485 return self 

486 

487 

488class HasHints: 

489 _hints: util.immutabledict[Tuple[FromClause, str], str] = ( 

490 util.immutabledict() 

491 ) 

492 _statement_hints: Tuple[Tuple[str, str], ...] = () 

493 

494 _has_hints_traverse_internals: _TraverseInternalsType = [ 

495 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

496 ("_hints", InternalTraversal.dp_table_hint_list), 

497 ] 

498 

499 @_generative 

500 def with_statement_hint(self, text: str, dialect_name: str = "*") -> Self: 

501 """Add a statement hint to this :class:`_expression.Select` or 

502 other selectable object. 

503 

504 .. tip:: 

505 

506 :meth:`_expression.Select.with_statement_hint` generally adds hints 

507 **at the trailing end** of a SELECT statement. To place 

508 dialect-specific hints such as optimizer hints at the **front** of 

509 the SELECT statement after the SELECT keyword, use the 

510 :meth:`_expression.Select.prefix_with` method for an open-ended 

511 space, or for table-specific hints the 

512 :meth:`_expression.Select.with_hint` may be used, which places 

513 hints in a dialect-specific location. 

514 

515 This method is similar to :meth:`_expression.Select.with_hint` except 

516 that it does not require an individual table, and instead applies to 

517 the statement as a whole. 

518 

519 Hints here are specific to the backend database and may include 

520 directives such as isolation levels, file directives, fetch directives, 

521 etc. 

522 

523 .. seealso:: 

524 

525 :meth:`_expression.Select.with_hint` 

526 

527 :meth:`_expression.Select.prefix_with` - generic SELECT prefixing 

528 which also can suit some database-specific HINT syntaxes such as 

529 MySQL or Oracle Database optimizer hints 

530 

531 """ 

532 return self._with_hint(None, text, dialect_name) 

533 

534 @_generative 

535 def with_hint( 

536 self, 

537 selectable: _FromClauseArgument, 

538 text: str, 

539 dialect_name: str = "*", 

540 ) -> Self: 

541 r"""Add an indexing or other executional context hint for the given 

542 selectable to this :class:`_expression.Select` or other selectable 

543 object. 

544 

545 .. tip:: 

546 

547 The :meth:`_expression.Select.with_hint` method adds hints that are 

548 **specific to a single table** to a statement, in a location that 

549 is **dialect-specific**. To add generic optimizer hints to the 

550 **beginning** of a statement ahead of the SELECT keyword such as 

551 for MySQL or Oracle Database, use the 

552 :meth:`_expression.Select.prefix_with` method. To add optimizer 

553 hints to the **end** of a statement such as for PostgreSQL, use the 

554 :meth:`_expression.Select.with_statement_hint` method. 

555 

556 The text of the hint is rendered in the appropriate 

557 location for the database backend in use, relative 

558 to the given :class:`_schema.Table` or :class:`_expression.Alias` 

559 passed as the 

560 ``selectable`` argument. The dialect implementation 

561 typically uses Python string substitution syntax 

562 with the token ``%(name)s`` to render the name of 

563 the table or alias. E.g. when using Oracle Database, the 

564 following:: 

565 

566 select(mytable).with_hint(mytable, "index(%(name)s ix_mytable)") 

567 

568 Would render SQL as: 

569 

570 .. sourcecode:: sql 

571 

572 select /*+ index(mytable ix_mytable) */ ... from mytable 

573 

574 The ``dialect_name`` option will limit the rendering of a particular 

575 hint to a particular backend. Such as, to add hints for both Oracle 

576 Database and MSSql simultaneously:: 

577 

578 select(mytable).with_hint( 

579 mytable, "index(%(name)s ix_mytable)", "oracle" 

580 ).with_hint(mytable, "WITH INDEX ix_mytable", "mssql") 

581 

582 .. seealso:: 

583 

584 :meth:`_expression.Select.with_statement_hint` 

585 

586 :meth:`_expression.Select.prefix_with` - generic SELECT prefixing 

587 which also can suit some database-specific HINT syntaxes such as 

588 MySQL or Oracle Database optimizer hints 

589 

590 """ 

591 

592 return self._with_hint(selectable, text, dialect_name) 

593 

594 def _with_hint( 

595 self, 

596 selectable: Optional[_FromClauseArgument], 

597 text: str, 

598 dialect_name: str, 

599 ) -> Self: 

600 if selectable is None: 

601 self._statement_hints += ((dialect_name, text),) 

602 else: 

603 self._hints = self._hints.union( 

604 { 

605 ( 

606 coercions.expect(roles.FromClauseRole, selectable), 

607 dialect_name, 

608 ): text 

609 } 

610 ) 

611 return self 

612 

613 

614class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

615 """Represent an element that can be used within the ``FROM`` 

616 clause of a ``SELECT`` statement. 

617 

618 The most common forms of :class:`_expression.FromClause` are the 

619 :class:`_schema.Table` and the :func:`_expression.select` constructs. Key 

620 features common to all :class:`_expression.FromClause` objects include: 

621 

622 * a :attr:`.c` collection, which provides per-name access to a collection 

623 of :class:`_expression.ColumnElement` objects. 

624 * a :attr:`.primary_key` attribute, which is a collection of all those 

625 :class:`_expression.ColumnElement` 

626 objects that indicate the ``primary_key`` flag. 

627 * Methods to generate various derivations of a "from" clause, including 

628 :meth:`_expression.FromClause.alias`, 

629 :meth:`_expression.FromClause.join`, 

630 :meth:`_expression.FromClause.select`. 

631 

632 

633 """ 

634 

635 __visit_name__ = "fromclause" 

636 named_with_column = False 

637 

638 @util.ro_non_memoized_property 

639 def _hide_froms(self) -> Iterable[FromClause]: 

640 return () 

641 

642 _is_clone_of: Optional[FromClause] 

643 

644 _columns: ColumnCollection[Any, Any] 

645 

646 schema: Optional[str] = None 

647 """Define the 'schema' attribute for this :class:`_expression.FromClause`. 

648 

649 This is typically ``None`` for most objects except that of 

650 :class:`_schema.Table`, where it is taken as the value of the 

651 :paramref:`_schema.Table.schema` argument. 

652 

653 """ 

654 

655 is_selectable = True 

656 _is_from_clause = True 

657 _is_join = False 

658 

659 _use_schema_map = False 

660 

661 def select(self) -> Select[Unpack[TupleAny]]: 

662 r"""Return a SELECT of this :class:`_expression.FromClause`. 

663 

664 

665 e.g.:: 

666 

667 stmt = some_table.select().where(some_table.c.id == 5) 

668 

669 .. seealso:: 

670 

671 :func:`_expression.select` - general purpose 

672 method which allows for arbitrary column lists. 

673 

674 """ 

675 return Select(self) 

676 

677 def join( 

678 self, 

679 right: _FromClauseArgument, 

680 onclause: Optional[_ColumnExpressionArgument[bool]] = None, 

681 isouter: bool = False, 

682 full: bool = False, 

683 ) -> Join: 

684 """Return a :class:`_expression.Join` from this 

685 :class:`_expression.FromClause` 

686 to another :class:`FromClause`. 

687 

688 E.g.:: 

689 

690 from sqlalchemy import join 

691 

692 j = user_table.join( 

693 address_table, user_table.c.id == address_table.c.user_id 

694 ) 

695 stmt = select(user_table).select_from(j) 

696 

697 would emit SQL along the lines of: 

698 

699 .. sourcecode:: sql 

700 

701 SELECT user.id, user.name FROM user 

702 JOIN address ON user.id = address.user_id 

703 

704 :param right: the right side of the join; this is any 

705 :class:`_expression.FromClause` object such as a 

706 :class:`_schema.Table` object, and 

707 may also be a selectable-compatible object such as an ORM-mapped 

708 class. 

709 

710 :param onclause: a SQL expression representing the ON clause of the 

711 join. If left at ``None``, :meth:`_expression.FromClause.join` 

712 will attempt to 

713 join the two tables based on a foreign key relationship. 

714 

715 :param isouter: if True, render a LEFT OUTER JOIN, instead of JOIN. 

716 

717 :param full: if True, render a FULL OUTER JOIN, instead of LEFT OUTER 

718 JOIN. Implies :paramref:`.FromClause.join.isouter`. 

719 

720 .. seealso:: 

721 

722 :func:`_expression.join` - standalone function 

723 

724 :class:`_expression.Join` - the type of object produced 

725 

726 """ 

727 

728 return Join(self, right, onclause, isouter, full) 

729 

730 def outerjoin( 

731 self, 

732 right: _FromClauseArgument, 

733 onclause: Optional[_ColumnExpressionArgument[bool]] = None, 

734 full: bool = False, 

735 ) -> Join: 

736 """Return a :class:`_expression.Join` from this 

737 :class:`_expression.FromClause` 

738 to another :class:`FromClause`, with the "isouter" flag set to 

739 True. 

740 

741 E.g.:: 

742 

743 from sqlalchemy import outerjoin 

744 

745 j = user_table.outerjoin( 

746 address_table, user_table.c.id == address_table.c.user_id 

747 ) 

748 

749 The above is equivalent to:: 

750 

751 j = user_table.join( 

752 address_table, user_table.c.id == address_table.c.user_id, isouter=True 

753 ) 

754 

755 :param right: the right side of the join; this is any 

756 :class:`_expression.FromClause` object such as a 

757 :class:`_schema.Table` object, and 

758 may also be a selectable-compatible object such as an ORM-mapped 

759 class. 

760 

761 :param onclause: a SQL expression representing the ON clause of the 

762 join. If left at ``None``, :meth:`_expression.FromClause.join` 

763 will attempt to 

764 join the two tables based on a foreign key relationship. 

765 

766 :param full: if True, render a FULL OUTER JOIN, instead of 

767 LEFT OUTER JOIN. 

768 

769 .. seealso:: 

770 

771 :meth:`_expression.FromClause.join` 

772 

773 :class:`_expression.Join` 

774 

775 """ # noqa: E501 

776 

777 return Join(self, right, onclause, True, full) 

778 

779 def alias( 

780 self, name: Optional[str] = None, flat: bool = False 

781 ) -> NamedFromClause: 

782 """Return an alias of this :class:`_expression.FromClause`. 

783 

784 E.g.:: 

785 

786 a2 = some_table.alias("a2") 

787 

788 The above code creates an :class:`_expression.Alias` 

789 object which can be used 

790 as a FROM clause in any SELECT statement. 

791 

792 .. seealso:: 

793 

794 :ref:`tutorial_using_aliases` 

795 

796 :func:`_expression.alias` 

797 

798 """ 

799 

800 return Alias._construct(self, name=name) 

801 

802 def tablesample( 

803 self, 

804 sampling: Union[float, Function[Any]], 

805 name: Optional[str] = None, 

806 seed: Optional[roles.ExpressionElementRole[Any]] = None, 

807 ) -> TableSample: 

808 """Return a TABLESAMPLE alias of this :class:`_expression.FromClause`. 

809 

810 The return value is the :class:`_expression.TableSample` 

811 construct also 

812 provided by the top-level :func:`_expression.tablesample` function. 

813 

814 .. seealso:: 

815 

816 :func:`_expression.tablesample` - usage guidelines and parameters 

817 

818 """ 

819 return TableSample._construct( 

820 self, sampling=sampling, name=name, seed=seed 

821 ) 

822 

823 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

824 """Return ``True`` if this :class:`_expression.FromClause` is 

825 'derived' from the given ``FromClause``. 

826 

827 An example would be an Alias of a Table is derived from that Table. 

828 

829 """ 

830 # this is essentially an "identity" check in the base class. 

831 # Other constructs override this to traverse through 

832 # contained elements. 

833 return fromclause in self._cloned_set 

834 

835 def _is_lexical_equivalent(self, other: FromClause) -> bool: 

836 """Return ``True`` if this :class:`_expression.FromClause` and 

837 the other represent the same lexical identity. 

838 

839 This tests if either one is a copy of the other, or 

840 if they are the same via annotation identity. 

841 

842 """ 

843 return bool(self._cloned_set.intersection(other._cloned_set)) 

844 

845 @util.ro_non_memoized_property 

846 def description(self) -> str: 

847 """A brief description of this :class:`_expression.FromClause`. 

848 

849 Used primarily for error message formatting. 

850 

851 """ 

852 return getattr(self, "name", self.__class__.__name__ + " object") 

853 

854 def _generate_fromclause_column_proxies( 

855 self, 

856 fromclause: FromClause, 

857 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

858 primary_key: ColumnSet, 

859 foreign_keys: Set[KeyedColumnElement[Any]], 

860 ) -> None: 

861 columns._populate_separate_keys( 

862 col._make_proxy( 

863 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

864 ) 

865 for col in self.c 

866 ) 

867 

868 @util.ro_non_memoized_property 

869 def exported_columns( 

870 self, 

871 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

872 """A :class:`_expression.ColumnCollection` 

873 that represents the "exported" 

874 columns of this :class:`_expression.FromClause`. 

875 

876 The "exported" columns for a :class:`_expression.FromClause` 

877 object are synonymous 

878 with the :attr:`_expression.FromClause.columns` collection. 

879 

880 .. versionadded:: 1.4 

881 

882 .. seealso:: 

883 

884 :attr:`_expression.Selectable.exported_columns` 

885 

886 :attr:`_expression.SelectBase.exported_columns` 

887 

888 

889 """ 

890 return self.c 

891 

892 @util.ro_non_memoized_property 

893 def columns( 

894 self, 

895 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

896 """A named-based collection of :class:`_expression.ColumnElement` 

897 objects maintained by this :class:`_expression.FromClause`. 

898 

899 The :attr:`.columns`, or :attr:`.c` collection, is the gateway 

900 to the construction of SQL expressions using table-bound or 

901 other selectable-bound columns:: 

902 

903 select(mytable).where(mytable.c.somecolumn == 5) 

904 

905 :return: a :class:`.ColumnCollection` object. 

906 

907 """ 

908 return self.c 

909 

910 @util.ro_memoized_property 

911 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

912 """ 

913 A synonym for :attr:`.FromClause.columns` 

914 

915 :return: a :class:`.ColumnCollection` 

916 

917 """ 

918 if "_columns" not in self.__dict__: 

919 self._setup_collections() 

920 return self._columns.as_readonly() 

921 

922 def _setup_collections(self) -> None: 

923 with util.mini_gil: 

924 # detect another thread that raced ahead 

925 if "_columns" in self.__dict__: 

926 assert "primary_key" in self.__dict__ 

927 assert "foreign_keys" in self.__dict__ 

928 return 

929 

930 _columns: ColumnCollection[Any, Any] = ColumnCollection() 

931 primary_key = ColumnSet() 

932 foreign_keys: Set[KeyedColumnElement[Any]] = set() 

933 

934 self._populate_column_collection( 

935 columns=_columns, 

936 primary_key=primary_key, 

937 foreign_keys=foreign_keys, 

938 ) 

939 

940 # assigning these three collections separately is not itself 

941 # atomic, but greatly reduces the surface for problems 

942 self._columns = _columns 

943 self.primary_key = primary_key # type: ignore 

944 self.foreign_keys = foreign_keys # type: ignore 

945 

946 @util.ro_non_memoized_property 

947 def entity_namespace(self) -> _EntityNamespace: 

948 """Return a namespace used for name-based access in SQL expressions. 

949 

950 This is the namespace that is used to resolve "filter_by()" type 

951 expressions, such as:: 

952 

953 stmt.filter_by(address="some address") 

954 

955 It defaults to the ``.c`` collection, however internally it can 

956 be overridden using the "entity_namespace" annotation to deliver 

957 alternative results. 

958 

959 """ 

960 return self.c 

961 

962 @util.ro_memoized_property 

963 def primary_key(self) -> Iterable[NamedColumn[Any]]: 

964 """Return the iterable collection of :class:`_schema.Column` objects 

965 which comprise the primary key of this :class:`_selectable.FromClause`. 

966 

967 For a :class:`_schema.Table` object, this collection is represented 

968 by the :class:`_schema.PrimaryKeyConstraint` which itself is an 

969 iterable collection of :class:`_schema.Column` objects. 

970 

971 """ 

972 self._setup_collections() 

973 return self.primary_key 

974 

975 @util.ro_memoized_property 

976 def foreign_keys(self) -> Iterable[ForeignKey]: 

977 """Return the collection of :class:`_schema.ForeignKey` marker objects 

978 which this FromClause references. 

979 

980 Each :class:`_schema.ForeignKey` is a member of a 

981 :class:`_schema.Table`-wide 

982 :class:`_schema.ForeignKeyConstraint`. 

983 

984 .. seealso:: 

985 

986 :attr:`_schema.Table.foreign_key_constraints` 

987 

988 """ 

989 self._setup_collections() 

990 return self.foreign_keys 

991 

992 def _reset_column_collection(self) -> None: 

993 """Reset the attributes linked to the ``FromClause.c`` attribute. 

994 

995 This collection is separate from all the other memoized things 

996 as it has shown to be sensitive to being cleared out in situations 

997 where enclosing code, typically in a replacement traversal scenario, 

998 has already established strong relationships 

999 with the exported columns. 

1000 

1001 The collection is cleared for the case where a table is having a 

1002 column added to it as well as within a Join during copy internals. 

1003 

1004 """ 

1005 

1006 for key in ["_columns", "columns", "c", "primary_key", "foreign_keys"]: 

1007 self.__dict__.pop(key, None) 

1008 

1009 @util.ro_non_memoized_property 

1010 def _select_iterable(self) -> _SelectIterable: 

1011 return (c for c in self.c if not _never_select_column(c)) 

1012 

1013 @property 

1014 def _cols_populated(self) -> bool: 

1015 return "_columns" in self.__dict__ 

1016 

1017 def _populate_column_collection( 

1018 self, 

1019 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

1020 primary_key: ColumnSet, 

1021 foreign_keys: Set[KeyedColumnElement[Any]], 

1022 ) -> None: 

1023 """Called on subclasses to establish the .c collection. 

1024 

1025 Each implementation has a different way of establishing 

1026 this collection. 

1027 

1028 """ 

1029 

1030 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

1031 """Given a column added to the .c collection of an underlying 

1032 selectable, produce the local version of that column, assuming this 

1033 selectable ultimately should proxy this column. 

1034 

1035 this is used to "ping" a derived selectable to add a new column 

1036 to its .c. collection when a Column has been added to one of the 

1037 Table objects it ultimately derives from. 

1038 

1039 If the given selectable hasn't populated its .c. collection yet, 

1040 it should at least pass on the message to the contained selectables, 

1041 but it will return None. 

1042 

1043 This method is currently used by Declarative to allow Table 

1044 columns to be added to a partially constructed inheritance 

1045 mapping that may have already produced joins. The method 

1046 isn't public right now, as the full span of implications 

1047 and/or caveats aren't yet clear. 

1048 

1049 It's also possible that this functionality could be invoked by 

1050 default via an event, which would require that 

1051 selectables maintain a weak referencing collection of all 

1052 derivations. 

1053 

1054 """ 

1055 self._reset_column_collection() 

1056 

1057 def _anonymous_fromclause( 

1058 self, *, name: Optional[str] = None, flat: bool = False 

1059 ) -> FromClause: 

1060 return self.alias(name=name) 

1061 

1062 if TYPE_CHECKING: 

1063 

1064 def self_group( 

1065 self, against: Optional[OperatorType] = None 

1066 ) -> Union[FromGrouping, Self]: ... 

1067 

1068 

1069class NamedFromClause(FromClause): 

1070 """A :class:`.FromClause` that has a name. 

1071 

1072 Examples include tables, subqueries, CTEs, aliased tables. 

1073 

1074 .. versionadded:: 2.0 

1075 

1076 """ 

1077 

1078 named_with_column = True 

1079 

1080 name: str 

1081 

1082 @util.preload_module("sqlalchemy.sql.sqltypes") 

1083 def table_valued(self) -> TableValuedColumn[Any]: 

1084 """Return a :class:`_sql.TableValuedColumn` object for this 

1085 :class:`_expression.FromClause`. 

1086 

1087 A :class:`_sql.TableValuedColumn` is a :class:`_sql.ColumnElement` that 

1088 represents a complete row in a table. Support for this construct is 

1089 backend dependent, and is supported in various forms by backends 

1090 such as PostgreSQL, Oracle Database and SQL Server. 

1091 

1092 E.g.: 

1093 

1094 .. sourcecode:: pycon+sql 

1095 

1096 >>> from sqlalchemy import select, column, func, table 

1097 >>> a = table("a", column("id"), column("x"), column("y")) 

1098 >>> stmt = select(func.row_to_json(a.table_valued())) 

1099 >>> print(stmt) 

1100 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1101 FROM a 

1102 

1103 .. versionadded:: 1.4.0b2 

1104 

1105 .. seealso:: 

1106 

1107 :ref:`tutorial_functions` - in the :ref:`unified_tutorial` 

1108 

1109 """ 

1110 return TableValuedColumn(self, type_api.TABLEVALUE) 

1111 

1112 

1113class SelectLabelStyle(Enum): 

1114 """Label style constants that may be passed to 

1115 :meth:`_sql.Select.set_label_style`.""" 

1116 

1117 LABEL_STYLE_NONE = 0 

1118 """Label style indicating no automatic labeling should be applied to the 

1119 columns clause of a SELECT statement. 

1120 

1121 Below, the columns named ``columna`` are both rendered as is, meaning that 

1122 the name ``columna`` can only refer to the first occurrence of this name 

1123 within a result set, as well as if the statement were used as a subquery: 

1124 

1125 .. sourcecode:: pycon+sql 

1126 

1127 >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_NONE 

1128 >>> table1 = table("table1", column("columna"), column("columnb")) 

1129 >>> table2 = table("table2", column("columna"), column("columnc")) 

1130 >>> print( 

1131 ... select(table1, table2) 

1132 ... .join(table2, true()) 

1133 ... .set_label_style(LABEL_STYLE_NONE) 

1134 ... ) 

1135 {printsql}SELECT table1.columna, table1.columnb, table2.columna, table2.columnc 

1136 FROM table1 JOIN table2 ON true 

1137 

1138 Used with the :meth:`_sql.Select.set_label_style` method. 

1139 

1140 .. versionadded:: 1.4 

1141 

1142 """ # noqa: E501 

1143 

1144 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

1145 """Label style indicating all columns should be labeled as 

1146 ``<tablename>_<columnname>`` when generating the columns clause of a SELECT 

1147 statement, to disambiguate same-named columns referenced from different 

1148 tables, aliases, or subqueries. 

1149 

1150 Below, all column names are given a label so that the two same-named 

1151 columns ``columna`` are disambiguated as ``table1_columna`` and 

1152 ``table2_columna``: 

1153 

1154 .. sourcecode:: pycon+sql 

1155 

1156 >>> from sqlalchemy import ( 

1157 ... table, 

1158 ... column, 

1159 ... select, 

1160 ... true, 

1161 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1162 ... ) 

1163 >>> table1 = table("table1", column("columna"), column("columnb")) 

1164 >>> table2 = table("table2", column("columna"), column("columnc")) 

1165 >>> print( 

1166 ... select(table1, table2) 

1167 ... .join(table2, true()) 

1168 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1169 ... ) 

1170 {printsql}SELECT table1.columna AS table1_columna, table1.columnb AS table1_columnb, table2.columna AS table2_columna, table2.columnc AS table2_columnc 

1171 FROM table1 JOIN table2 ON true 

1172 

1173 Used with the :meth:`_sql.GenerativeSelect.set_label_style` method. 

1174 Equivalent to the legacy method ``Select.apply_labels()``; 

1175 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` is SQLAlchemy's legacy 

1176 auto-labeling style. :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` provides a 

1177 less intrusive approach to disambiguation of same-named column expressions. 

1178 

1179 

1180 .. versionadded:: 1.4 

1181 

1182 """ # noqa: E501 

1183 

1184 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

1185 """Label style indicating that columns with a name that conflicts with 

1186 an existing name should be labeled with a semi-anonymizing label 

1187 when generating the columns clause of a SELECT statement. 

1188 

1189 Below, most column names are left unaffected, except for the second 

1190 occurrence of the name ``columna``, which is labeled using the 

1191 label ``columna_1`` to disambiguate it from that of ``tablea.columna``: 

1192 

1193 .. sourcecode:: pycon+sql 

1194 

1195 >>> from sqlalchemy import ( 

1196 ... table, 

1197 ... column, 

1198 ... select, 

1199 ... true, 

1200 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1201 ... ) 

1202 >>> table1 = table("table1", column("columna"), column("columnb")) 

1203 >>> table2 = table("table2", column("columna"), column("columnc")) 

1204 >>> print( 

1205 ... select(table1, table2) 

1206 ... .join(table2, true()) 

1207 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1208 ... ) 

1209 {printsql}SELECT table1.columna, table1.columnb, table2.columna AS columna_1, table2.columnc 

1210 FROM table1 JOIN table2 ON true 

1211 

1212 Used with the :meth:`_sql.GenerativeSelect.set_label_style` method, 

1213 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` is the default labeling style 

1214 for all SELECT statements outside of :term:`1.x style` ORM queries. 

1215 

1216 .. versionadded:: 1.4 

1217 

1218 """ # noqa: E501 

1219 

1220 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1221 """The default label style, refers to 

1222 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1223 

1224 .. versionadded:: 1.4 

1225 

1226 """ 

1227 

1228 LABEL_STYLE_LEGACY_ORM = 3 

1229 

1230 

1231( 

1232 LABEL_STYLE_NONE, 

1233 LABEL_STYLE_TABLENAME_PLUS_COL, 

1234 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1235 _, 

1236) = list(SelectLabelStyle) 

1237 

1238LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1239 

1240 

1241class Join(roles.DMLTableRole, FromClause): 

1242 """Represent a ``JOIN`` construct between two 

1243 :class:`_expression.FromClause` 

1244 elements. 

1245 

1246 The public constructor function for :class:`_expression.Join` 

1247 is the module-level 

1248 :func:`_expression.join()` function, as well as the 

1249 :meth:`_expression.FromClause.join` method 

1250 of any :class:`_expression.FromClause` (e.g. such as 

1251 :class:`_schema.Table`). 

1252 

1253 .. seealso:: 

1254 

1255 :func:`_expression.join` 

1256 

1257 :meth:`_expression.FromClause.join` 

1258 

1259 """ 

1260 

1261 __visit_name__ = "join" 

1262 

1263 _traverse_internals: _TraverseInternalsType = [ 

1264 ("left", InternalTraversal.dp_clauseelement), 

1265 ("right", InternalTraversal.dp_clauseelement), 

1266 ("onclause", InternalTraversal.dp_clauseelement), 

1267 ("isouter", InternalTraversal.dp_boolean), 

1268 ("full", InternalTraversal.dp_boolean), 

1269 ] 

1270 

1271 _is_join = True 

1272 

1273 left: FromClause 

1274 right: FromClause 

1275 onclause: Optional[ColumnElement[bool]] 

1276 isouter: bool 

1277 full: bool 

1278 

1279 def __init__( 

1280 self, 

1281 left: _FromClauseArgument, 

1282 right: _FromClauseArgument, 

1283 onclause: Optional[_OnClauseArgument] = None, 

1284 isouter: bool = False, 

1285 full: bool = False, 

1286 ): 

1287 """Construct a new :class:`_expression.Join`. 

1288 

1289 The usual entrypoint here is the :func:`_expression.join` 

1290 function or the :meth:`_expression.FromClause.join` method of any 

1291 :class:`_expression.FromClause` object. 

1292 

1293 """ 

1294 

1295 # when deannotate was removed here, callcounts went up for ORM 

1296 # compilation of eager joins, since there were more comparisons of 

1297 # annotated objects. test_orm.py -> test_fetch_results 

1298 # was therefore changed to show a more real-world use case, where the 

1299 # compilation is cached; there's no change in post-cache callcounts. 

1300 # callcounts for a single compilation in that particular test 

1301 # that includes about eight joins about 1100 extra fn calls, from 

1302 # 29200 -> 30373 

1303 

1304 self.left = coercions.expect( 

1305 roles.FromClauseRole, 

1306 left, 

1307 ) 

1308 self.right = coercions.expect( 

1309 roles.FromClauseRole, 

1310 right, 

1311 ).self_group() 

1312 

1313 if onclause is None: 

1314 self.onclause = self._match_primaries(self.left, self.right) 

1315 else: 

1316 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1317 # not merged yet 

1318 self.onclause = coercions.expect( 

1319 roles.OnClauseRole, onclause 

1320 ).self_group(against=operators._asbool) 

1321 

1322 self.isouter = isouter 

1323 self.full = full 

1324 

1325 @util.ro_non_memoized_property 

1326 def description(self) -> str: 

1327 return "Join object on %s(%d) and %s(%d)" % ( 

1328 self.left.description, 

1329 id(self.left), 

1330 self.right.description, 

1331 id(self.right), 

1332 ) 

1333 

1334 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

1335 return ( 

1336 # use hash() to ensure direct comparison to annotated works 

1337 # as well 

1338 hash(fromclause) == hash(self) 

1339 or self.left.is_derived_from(fromclause) 

1340 or self.right.is_derived_from(fromclause) 

1341 ) 

1342 

1343 def self_group( 

1344 self, against: Optional[OperatorType] = None 

1345 ) -> FromGrouping: 

1346 return FromGrouping(self) 

1347 

1348 @util.preload_module("sqlalchemy.sql.util") 

1349 def _populate_column_collection( 

1350 self, 

1351 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

1352 primary_key: ColumnSet, 

1353 foreign_keys: Set[KeyedColumnElement[Any]], 

1354 ) -> None: 

1355 sqlutil = util.preloaded.sql_util 

1356 _columns: List[KeyedColumnElement[Any]] = [c for c in self.left.c] + [ 

1357 c for c in self.right.c 

1358 ] 

1359 

1360 primary_key.extend( 

1361 sqlutil.reduce_columns( 

1362 (c for c in _columns if c.primary_key), self.onclause 

1363 ) 

1364 ) 

1365 columns._populate_separate_keys( 

1366 (col._tq_key_label, col) for col in _columns # type: ignore 

1367 ) 

1368 foreign_keys.update( 

1369 itertools.chain(*[col.foreign_keys for col in _columns]) # type: ignore # noqa: E501 

1370 ) 

1371 

1372 def _copy_internals( 

1373 self, clone: _CloneCallableType = _clone, **kw: Any 

1374 ) -> None: 

1375 # see Select._copy_internals() for similar concept 

1376 

1377 # here we pre-clone "left" and "right" so that we can 

1378 # determine the new FROM clauses 

1379 all_the_froms = set( 

1380 itertools.chain( 

1381 _from_objects(self.left), 

1382 _from_objects(self.right), 

1383 ) 

1384 ) 

1385 

1386 # run the clone on those. these will be placed in the 

1387 # cache used by the clone function 

1388 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

1389 

1390 # set up a special replace function that will replace for 

1391 # ColumnClause with parent table referring to those 

1392 # replaced FromClause objects 

1393 def replace( 

1394 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

1395 **kw: Any, 

1396 ) -> Optional[KeyedColumnElement[Any]]: 

1397 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

1398 newelem = new_froms[obj.table].corresponding_column(obj) 

1399 return newelem 

1400 return None 

1401 

1402 kw["replace"] = replace 

1403 

1404 # run normal _copy_internals. the clones for 

1405 # left and right will come from the clone function's 

1406 # cache 

1407 super()._copy_internals(clone=clone, **kw) 

1408 

1409 self._reset_memoizations() 

1410 

1411 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

1412 super()._refresh_for_new_column(column) 

1413 self.left._refresh_for_new_column(column) 

1414 self.right._refresh_for_new_column(column) 

1415 

1416 def _match_primaries( 

1417 self, 

1418 left: FromClause, 

1419 right: FromClause, 

1420 ) -> ColumnElement[bool]: 

1421 if isinstance(left, Join): 

1422 left_right = left.right 

1423 else: 

1424 left_right = None 

1425 return self._join_condition(left, right, a_subset=left_right) 

1426 

1427 @classmethod 

1428 def _join_condition( 

1429 cls, 

1430 a: FromClause, 

1431 b: FromClause, 

1432 *, 

1433 a_subset: Optional[FromClause] = None, 

1434 consider_as_foreign_keys: Optional[ 

1435 AbstractSet[ColumnClause[Any]] 

1436 ] = None, 

1437 ) -> ColumnElement[bool]: 

1438 """Create a join condition between two tables or selectables. 

1439 

1440 See sqlalchemy.sql.util.join_condition() for full docs. 

1441 

1442 """ 

1443 constraints = cls._joincond_scan_left_right( 

1444 a, a_subset, b, consider_as_foreign_keys 

1445 ) 

1446 

1447 if len(constraints) > 1: 

1448 cls._joincond_trim_constraints( 

1449 a, b, constraints, consider_as_foreign_keys 

1450 ) 

1451 

1452 if len(constraints) == 0: 

1453 if isinstance(b, FromGrouping): 

1454 hint = ( 

1455 " Perhaps you meant to convert the right side to a " 

1456 "subquery using alias()?" 

1457 ) 

1458 else: 

1459 hint = "" 

1460 raise exc.NoForeignKeysError( 

1461 "Can't find any foreign key relationships " 

1462 "between '%s' and '%s'.%s" 

1463 % (a.description, b.description, hint) 

1464 ) 

1465 

1466 crit = [(x == y) for x, y in list(constraints.values())[0]] 

1467 if len(crit) == 1: 

1468 return crit[0] 

1469 else: 

1470 return and_(*crit) 

1471 

1472 @classmethod 

1473 def _can_join( 

1474 cls, 

1475 left: FromClause, 

1476 right: FromClause, 

1477 *, 

1478 consider_as_foreign_keys: Optional[ 

1479 AbstractSet[ColumnClause[Any]] 

1480 ] = None, 

1481 ) -> bool: 

1482 if isinstance(left, Join): 

1483 left_right = left.right 

1484 else: 

1485 left_right = None 

1486 

1487 constraints = cls._joincond_scan_left_right( 

1488 a=left, 

1489 b=right, 

1490 a_subset=left_right, 

1491 consider_as_foreign_keys=consider_as_foreign_keys, 

1492 ) 

1493 

1494 return bool(constraints) 

1495 

1496 @classmethod 

1497 @util.preload_module("sqlalchemy.sql.util") 

1498 def _joincond_scan_left_right( 

1499 cls, 

1500 a: FromClause, 

1501 a_subset: Optional[FromClause], 

1502 b: FromClause, 

1503 consider_as_foreign_keys: Optional[AbstractSet[ColumnClause[Any]]], 

1504 ) -> collections.defaultdict[ 

1505 Optional[ForeignKeyConstraint], 

1506 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1507 ]: 

1508 sql_util = util.preloaded.sql_util 

1509 

1510 a = coercions.expect(roles.FromClauseRole, a) 

1511 b = coercions.expect(roles.FromClauseRole, b) 

1512 

1513 constraints: collections.defaultdict[ 

1514 Optional[ForeignKeyConstraint], 

1515 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1516 ] = collections.defaultdict(list) 

1517 

1518 for left in (a_subset, a): 

1519 if left is None: 

1520 continue 

1521 for fk in sorted( 

1522 b.foreign_keys, 

1523 key=lambda fk: fk.parent._creation_order, 

1524 ): 

1525 if ( 

1526 consider_as_foreign_keys is not None 

1527 and fk.parent not in consider_as_foreign_keys 

1528 ): 

1529 continue 

1530 try: 

1531 col = fk.get_referent(left) 

1532 except exc.NoReferenceError as nrte: 

1533 table_names = {t.name for t in sql_util.find_tables(left)} 

1534 if nrte.table_name in table_names: 

1535 raise 

1536 else: 

1537 continue 

1538 

1539 if col is not None: 

1540 constraints[fk.constraint].append((col, fk.parent)) 

1541 if left is not b: 

1542 for fk in sorted( 

1543 left.foreign_keys, 

1544 key=lambda fk: fk.parent._creation_order, 

1545 ): 

1546 if ( 

1547 consider_as_foreign_keys is not None 

1548 and fk.parent not in consider_as_foreign_keys 

1549 ): 

1550 continue 

1551 try: 

1552 col = fk.get_referent(b) 

1553 except exc.NoReferenceError as nrte: 

1554 table_names = {t.name for t in sql_util.find_tables(b)} 

1555 if nrte.table_name in table_names: 

1556 raise 

1557 else: 

1558 continue 

1559 

1560 if col is not None: 

1561 constraints[fk.constraint].append((col, fk.parent)) 

1562 if constraints: 

1563 break 

1564 return constraints 

1565 

1566 @classmethod 

1567 def _joincond_trim_constraints( 

1568 cls, 

1569 a: FromClause, 

1570 b: FromClause, 

1571 constraints: Dict[Any, Any], 

1572 consider_as_foreign_keys: Optional[Any], 

1573 ) -> None: 

1574 # more than one constraint matched. narrow down the list 

1575 # to include just those FKCs that match exactly to 

1576 # "consider_as_foreign_keys". 

1577 if consider_as_foreign_keys: 

1578 for const in list(constraints): 

1579 if {f.parent for f in const.elements} != set( 

1580 consider_as_foreign_keys 

1581 ): 

1582 del constraints[const] 

1583 

1584 # if still multiple constraints, but 

1585 # they all refer to the exact same end result, use it. 

1586 if len(constraints) > 1: 

1587 dedupe = {tuple(crit) for crit in constraints.values()} 

1588 if len(dedupe) == 1: 

1589 key = list(constraints)[0] 

1590 constraints = {key: constraints[key]} 

1591 

1592 if len(constraints) != 1: 

1593 raise exc.AmbiguousForeignKeysError( 

1594 "Can't determine join between '%s' and '%s'; " 

1595 "tables have more than one foreign key " 

1596 "constraint relationship between them. " 

1597 "Please specify the 'onclause' of this " 

1598 "join explicitly." % (a.description, b.description) 

1599 ) 

1600 

1601 def select(self) -> Select[Unpack[TupleAny]]: 

1602 r"""Create a :class:`_expression.Select` from this 

1603 :class:`_expression.Join`. 

1604 

1605 E.g.:: 

1606 

1607 stmt = table_a.join(table_b, table_a.c.id == table_b.c.a_id) 

1608 

1609 stmt = stmt.select() 

1610 

1611 The above will produce a SQL string resembling: 

1612 

1613 .. sourcecode:: sql 

1614 

1615 SELECT table_a.id, table_a.col, table_b.id, table_b.a_id 

1616 FROM table_a JOIN table_b ON table_a.id = table_b.a_id 

1617 

1618 """ 

1619 return Select(self.left, self.right).select_from(self) 

1620 

1621 @util.preload_module("sqlalchemy.sql.util") 

1622 def _anonymous_fromclause( 

1623 self, name: Optional[str] = None, flat: bool = False 

1624 ) -> TODO_Any: 

1625 sqlutil = util.preloaded.sql_util 

1626 if flat: 

1627 if isinstance(self.left, (FromGrouping, Join)): 

1628 left_name = name # will recurse 

1629 else: 

1630 if name and isinstance(self.left, NamedFromClause): 

1631 left_name = f"{name}_{self.left.name}" 

1632 else: 

1633 left_name = name 

1634 if isinstance(self.right, (FromGrouping, Join)): 

1635 right_name = name # will recurse 

1636 else: 

1637 if name and isinstance(self.right, NamedFromClause): 

1638 right_name = f"{name}_{self.right.name}" 

1639 else: 

1640 right_name = name 

1641 left_a, right_a = ( 

1642 self.left._anonymous_fromclause(name=left_name, flat=flat), 

1643 self.right._anonymous_fromclause(name=right_name, flat=flat), 

1644 ) 

1645 adapter = sqlutil.ClauseAdapter(left_a).chain( 

1646 sqlutil.ClauseAdapter(right_a) 

1647 ) 

1648 

1649 return left_a.join( 

1650 right_a, 

1651 adapter.traverse(self.onclause), 

1652 isouter=self.isouter, 

1653 full=self.full, 

1654 ) 

1655 else: 

1656 return ( 

1657 self.select() 

1658 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1659 .correlate(None) 

1660 .alias(name) 

1661 ) 

1662 

1663 @util.ro_non_memoized_property 

1664 def _hide_froms(self) -> Iterable[FromClause]: 

1665 return itertools.chain( 

1666 *[_from_objects(x.left, x.right) for x in self._cloned_set] 

1667 ) 

1668 

1669 @util.ro_non_memoized_property 

1670 def _from_objects(self) -> List[FromClause]: 

1671 self_list: List[FromClause] = [self] 

1672 return self_list + self.left._from_objects + self.right._from_objects 

1673 

1674 

1675class NoInit: 

1676 def __init__(self, *arg: Any, **kw: Any): 

1677 raise NotImplementedError( 

1678 "The %s class is not intended to be constructed " 

1679 "directly. Please use the %s() standalone " 

1680 "function or the %s() method available from appropriate " 

1681 "selectable objects." 

1682 % ( 

1683 self.__class__.__name__, 

1684 self.__class__.__name__.lower(), 

1685 self.__class__.__name__.lower(), 

1686 ) 

1687 ) 

1688 

1689 

1690class LateralFromClause(NamedFromClause): 

1691 """mark a FROM clause as being able to render directly as LATERAL""" 

1692 

1693 

1694# FromClause -> 

1695# AliasedReturnsRows 

1696# -> Alias only for FromClause 

1697# -> Subquery only for SelectBase 

1698# -> CTE only for HasCTE -> SelectBase, DML 

1699# -> Lateral -> FromClause, but we accept SelectBase 

1700# w/ non-deprecated coercion 

1701# -> TableSample -> only for FromClause 

1702 

1703 

1704class AliasedReturnsRows(NoInit, NamedFromClause): 

1705 """Base class of aliases against tables, subqueries, and other 

1706 selectables.""" 

1707 

1708 _is_from_container = True 

1709 

1710 _supports_derived_columns = False 

1711 

1712 element: ReturnsRows 

1713 

1714 _traverse_internals: _TraverseInternalsType = [ 

1715 ("element", InternalTraversal.dp_clauseelement), 

1716 ("name", InternalTraversal.dp_anon_name), 

1717 ] 

1718 

1719 @classmethod 

1720 def _construct( 

1721 cls, 

1722 selectable: Any, 

1723 *, 

1724 name: Optional[str] = None, 

1725 **kw: Any, 

1726 ) -> Self: 

1727 obj = cls.__new__(cls) 

1728 obj._init(selectable, name=name, **kw) 

1729 return obj 

1730 

1731 def _init(self, selectable: Any, *, name: Optional[str] = None) -> None: 

1732 self.element = coercions.expect( 

1733 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1734 ) 

1735 self.element = selectable 

1736 self._orig_name = name 

1737 if name is None: 

1738 if ( 

1739 isinstance(selectable, FromClause) 

1740 and selectable.named_with_column 

1741 ): 

1742 name = getattr(selectable, "name", None) 

1743 if isinstance(name, _anonymous_label): 

1744 name = None 

1745 name = _anonymous_label.safe_construct(id(self), name or "anon") 

1746 self.name = name 

1747 

1748 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

1749 super()._refresh_for_new_column(column) 

1750 self.element._refresh_for_new_column(column) 

1751 

1752 def _populate_column_collection( 

1753 self, 

1754 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

1755 primary_key: ColumnSet, 

1756 foreign_keys: Set[KeyedColumnElement[Any]], 

1757 ) -> None: 

1758 self.element._generate_fromclause_column_proxies( 

1759 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1760 ) 

1761 

1762 @util.ro_non_memoized_property 

1763 def description(self) -> str: 

1764 name = self.name 

1765 if isinstance(name, _anonymous_label): 

1766 return "anon_1" 

1767 

1768 return name 

1769 

1770 @util.ro_non_memoized_property 

1771 def implicit_returning(self) -> bool: 

1772 return self.element.implicit_returning # type: ignore 

1773 

1774 @property 

1775 def original(self) -> ReturnsRows: 

1776 """Legacy for dialects that are referring to Alias.original.""" 

1777 return self.element 

1778 

1779 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

1780 if fromclause in self._cloned_set: 

1781 return True 

1782 return self.element.is_derived_from(fromclause) 

1783 

1784 def _copy_internals( 

1785 self, clone: _CloneCallableType = _clone, **kw: Any 

1786 ) -> None: 

1787 existing_element = self.element 

1788 

1789 super()._copy_internals(clone=clone, **kw) 

1790 

1791 # the element clone is usually against a Table that returns the 

1792 # same object. don't reset exported .c. collections and other 

1793 # memoized details if it was not changed. this saves a lot on 

1794 # performance. 

1795 if existing_element is not self.element: 

1796 self._reset_column_collection() 

1797 

1798 @property 

1799 def _from_objects(self) -> List[FromClause]: 

1800 return [self] 

1801 

1802 

1803class FromClauseAlias(AliasedReturnsRows): 

1804 element: FromClause 

1805 

1806 @util.ro_non_memoized_property 

1807 def description(self) -> str: 

1808 name = self.name 

1809 if isinstance(name, _anonymous_label): 

1810 return f"Anonymous alias of {self.element.description}" 

1811 

1812 return name 

1813 

1814 

1815class Alias(roles.DMLTableRole, FromClauseAlias): 

1816 """Represents an table or selectable alias (AS). 

1817 

1818 Represents an alias, as typically applied to any table or 

1819 sub-select within a SQL statement using the ``AS`` keyword (or 

1820 without the keyword on certain databases such as Oracle Database). 

1821 

1822 This object is constructed from the :func:`_expression.alias` module 

1823 level function as well as the :meth:`_expression.FromClause.alias` 

1824 method available 

1825 on all :class:`_expression.FromClause` subclasses. 

1826 

1827 .. seealso:: 

1828 

1829 :meth:`_expression.FromClause.alias` 

1830 

1831 """ 

1832 

1833 __visit_name__ = "alias" 

1834 

1835 inherit_cache = True 

1836 

1837 element: FromClause 

1838 

1839 @classmethod 

1840 def _factory( 

1841 cls, 

1842 selectable: FromClause, 

1843 name: Optional[str] = None, 

1844 flat: bool = False, 

1845 ) -> NamedFromClause: 

1846 return coercions.expect(roles.FromClauseRole, selectable).alias( 

1847 name=name, flat=flat 

1848 ) 

1849 

1850 

1851class TableValuedAlias(LateralFromClause, Alias): 

1852 """An alias against a "table valued" SQL function. 

1853 

1854 This construct provides for a SQL function that returns columns 

1855 to be used in the FROM clause of a SELECT statement. The 

1856 object is generated using the :meth:`_functions.FunctionElement.table_valued` 

1857 method, e.g.: 

1858 

1859 .. sourcecode:: pycon+sql 

1860 

1861 >>> from sqlalchemy import select, func 

1862 >>> fn = func.json_array_elements_text('["one", "two", "three"]').table_valued( 

1863 ... "value" 

1864 ... ) 

1865 >>> print(select(fn.c.value)) 

1866 {printsql}SELECT anon_1.value 

1867 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1868 

1869 .. versionadded:: 1.4.0b2 

1870 

1871 .. seealso:: 

1872 

1873 :ref:`tutorial_functions_table_valued` - in the :ref:`unified_tutorial` 

1874 

1875 """ # noqa: E501 

1876 

1877 __visit_name__ = "table_valued_alias" 

1878 

1879 _supports_derived_columns = True 

1880 _render_derived = False 

1881 _render_derived_w_types = False 

1882 joins_implicitly = False 

1883 

1884 _traverse_internals: _TraverseInternalsType = [ 

1885 ("element", InternalTraversal.dp_clauseelement), 

1886 ("name", InternalTraversal.dp_anon_name), 

1887 ("_tableval_type", InternalTraversal.dp_type), 

1888 ("_render_derived", InternalTraversal.dp_boolean), 

1889 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1890 ] 

1891 

1892 def _init( 

1893 self, 

1894 selectable: Any, 

1895 *, 

1896 name: Optional[str] = None, 

1897 table_value_type: Optional[TableValueType] = None, 

1898 joins_implicitly: bool = False, 

1899 ) -> None: 

1900 super()._init(selectable, name=name) 

1901 

1902 self.joins_implicitly = joins_implicitly 

1903 self._tableval_type = ( 

1904 type_api.TABLEVALUE 

1905 if table_value_type is None 

1906 else table_value_type 

1907 ) 

1908 

1909 @HasMemoized.memoized_attribute 

1910 def column(self) -> TableValuedColumn[Any]: 

1911 """Return a column expression representing this 

1912 :class:`_sql.TableValuedAlias`. 

1913 

1914 This accessor is used to implement the 

1915 :meth:`_functions.FunctionElement.column_valued` method. See that 

1916 method for further details. 

1917 

1918 E.g.: 

1919 

1920 .. sourcecode:: pycon+sql 

1921 

1922 >>> print(select(func.some_func().table_valued("value").column)) 

1923 {printsql}SELECT anon_1 FROM some_func() AS anon_1 

1924 

1925 .. seealso:: 

1926 

1927 :meth:`_functions.FunctionElement.column_valued` 

1928 

1929 """ 

1930 

1931 return TableValuedColumn(self, self._tableval_type) 

1932 

1933 def alias( 

1934 self, name: Optional[str] = None, flat: bool = False 

1935 ) -> TableValuedAlias: 

1936 """Return a new alias of this :class:`_sql.TableValuedAlias`. 

1937 

1938 This creates a distinct FROM object that will be distinguished 

1939 from the original one when used in a SQL statement. 

1940 

1941 """ 

1942 

1943 tva: TableValuedAlias = TableValuedAlias._construct( 

1944 self, 

1945 name=name, 

1946 table_value_type=self._tableval_type, 

1947 joins_implicitly=self.joins_implicitly, 

1948 ) 

1949 

1950 if self._render_derived: 

1951 tva._render_derived = True 

1952 tva._render_derived_w_types = self._render_derived_w_types 

1953 

1954 return tva 

1955 

1956 def lateral(self, name: Optional[str] = None) -> LateralFromClause: 

1957 """Return a new :class:`_sql.TableValuedAlias` with the lateral flag 

1958 set, so that it renders as LATERAL. 

1959 

1960 .. seealso:: 

1961 

1962 :func:`_expression.lateral` 

1963 

1964 """ 

1965 tva = self.alias(name=name) 

1966 tva._is_lateral = True 

1967 return tva 

1968 

1969 def render_derived( 

1970 self, 

1971 name: Optional[str] = None, 

1972 with_types: bool = False, 

1973 ) -> TableValuedAlias: 

1974 """Apply "render derived" to this :class:`_sql.TableValuedAlias`. 

1975 

1976 This has the effect of the individual column names listed out 

1977 after the alias name in the "AS" sequence, e.g.: 

1978 

1979 .. sourcecode:: pycon+sql 

1980 

1981 >>> print( 

1982 ... select( 

1983 ... func.unnest(array(["one", "two", "three"])) 

1984 ... .table_valued("x", with_ordinality="o") 

1985 ... .render_derived() 

1986 ... ) 

1987 ... ) 

1988 {printsql}SELECT anon_1.x, anon_1.o 

1989 FROM unnest(ARRAY[%(param_1)s, %(param_2)s, %(param_3)s]) WITH ORDINALITY AS anon_1(x, o) 

1990 

1991 The ``with_types`` keyword will render column types inline within 

1992 the alias expression (this syntax currently applies to the 

1993 PostgreSQL database): 

1994 

1995 .. sourcecode:: pycon+sql 

1996 

1997 >>> print( 

1998 ... select( 

1999 ... func.json_to_recordset('[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]') 

2000 ... .table_valued(column("a", Integer), column("b", String)) 

2001 ... .render_derived(with_types=True) 

2002 ... ) 

2003 ... ) 

2004 {printsql}SELECT anon_1.a, anon_1.b FROM json_to_recordset(:json_to_recordset_1) 

2005 AS anon_1(a INTEGER, b VARCHAR) 

2006 

2007 :param name: optional string name that will be applied to the alias 

2008 generated. If left as None, a unique anonymizing name will be used. 

2009 

2010 :param with_types: if True, the derived columns will include the 

2011 datatype specification with each column. This is a special syntax 

2012 currently known to be required by PostgreSQL for some SQL functions. 

2013 

2014 """ # noqa: E501 

2015 

2016 # note: don't use the @_generative system here, keep a reference 

2017 # to the original object. otherwise you can have re-use of the 

2018 # python id() of the original which can cause name conflicts if 

2019 # a new anon-name grabs the same identifier as the local anon-name 

2020 # (just saw it happen on CI) 

2021 

2022 # construct against original to prevent memory growth 

2023 # for repeated generations 

2024 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2025 self.element, 

2026 name=name, 

2027 table_value_type=self._tableval_type, 

2028 joins_implicitly=self.joins_implicitly, 

2029 ) 

2030 new_alias._render_derived = True 

2031 new_alias._render_derived_w_types = with_types 

2032 return new_alias 

2033 

2034 

2035class Lateral(FromClauseAlias, LateralFromClause): 

2036 """Represent a LATERAL subquery. 

2037 

2038 This object is constructed from the :func:`_expression.lateral` module 

2039 level function as well as the :meth:`_expression.FromClause.lateral` 

2040 method available 

2041 on all :class:`_expression.FromClause` subclasses. 

2042 

2043 While LATERAL is part of the SQL standard, currently only more recent 

2044 PostgreSQL versions provide support for this keyword. 

2045 

2046 .. seealso:: 

2047 

2048 :ref:`tutorial_lateral_correlation` - overview of usage. 

2049 

2050 """ 

2051 

2052 __visit_name__ = "lateral" 

2053 _is_lateral = True 

2054 

2055 inherit_cache = True 

2056 

2057 @classmethod 

2058 def _factory( 

2059 cls, 

2060 selectable: Union[SelectBase, _FromClauseArgument], 

2061 name: Optional[str] = None, 

2062 ) -> LateralFromClause: 

2063 return coercions.expect( 

2064 roles.FromClauseRole, selectable, explicit_subquery=True 

2065 ).lateral(name=name) 

2066 

2067 

2068class TableSample(FromClauseAlias): 

2069 """Represent a TABLESAMPLE clause. 

2070 

2071 This object is constructed from the :func:`_expression.tablesample` module 

2072 level function as well as the :meth:`_expression.FromClause.tablesample` 

2073 method 

2074 available on all :class:`_expression.FromClause` subclasses. 

2075 

2076 .. seealso:: 

2077 

2078 :func:`_expression.tablesample` 

2079 

2080 """ 

2081 

2082 __visit_name__ = "tablesample" 

2083 

2084 _traverse_internals: _TraverseInternalsType = ( 

2085 AliasedReturnsRows._traverse_internals 

2086 + [ 

2087 ("sampling", InternalTraversal.dp_clauseelement), 

2088 ("seed", InternalTraversal.dp_clauseelement), 

2089 ] 

2090 ) 

2091 

2092 @classmethod 

2093 def _factory( 

2094 cls, 

2095 selectable: _FromClauseArgument, 

2096 sampling: Union[float, Function[Any]], 

2097 name: Optional[str] = None, 

2098 seed: Optional[roles.ExpressionElementRole[Any]] = None, 

2099 ) -> TableSample: 

2100 return coercions.expect(roles.FromClauseRole, selectable).tablesample( 

2101 sampling, name=name, seed=seed 

2102 ) 

2103 

2104 @util.preload_module("sqlalchemy.sql.functions") 

2105 def _init( # type: ignore[override] 

2106 self, 

2107 selectable: Any, 

2108 *, 

2109 name: Optional[str] = None, 

2110 sampling: Union[float, Function[Any]], 

2111 seed: Optional[roles.ExpressionElementRole[Any]] = None, 

2112 ) -> None: 

2113 assert sampling is not None 

2114 functions = util.preloaded.sql_functions 

2115 if not isinstance(sampling, functions.Function): 

2116 sampling = functions.func.system(sampling) 

2117 

2118 self.sampling: Function[Any] = sampling 

2119 self.seed = seed 

2120 super()._init(selectable, name=name) 

2121 

2122 def _get_method(self) -> Function[Any]: 

2123 return self.sampling 

2124 

2125 

2126class CTE( 

2127 roles.DMLTableRole, 

2128 roles.IsCTERole, 

2129 Generative, 

2130 HasPrefixes, 

2131 HasSuffixes, 

2132 AliasedReturnsRows, 

2133): 

2134 """Represent a Common Table Expression. 

2135 

2136 The :class:`_expression.CTE` object is obtained using the 

2137 :meth:`_sql.SelectBase.cte` method from any SELECT statement. A less often 

2138 available syntax also allows use of the :meth:`_sql.HasCTE.cte` method 

2139 present on :term:`DML` constructs such as :class:`_sql.Insert`, 

2140 :class:`_sql.Update` and 

2141 :class:`_sql.Delete`. See the :meth:`_sql.HasCTE.cte` method for 

2142 usage details on CTEs. 

2143 

2144 .. seealso:: 

2145 

2146 :ref:`tutorial_subqueries_ctes` - in the 2.0 tutorial 

2147 

2148 :meth:`_sql.HasCTE.cte` - examples of calling styles 

2149 

2150 """ 

2151 

2152 __visit_name__ = "cte" 

2153 

2154 _traverse_internals: _TraverseInternalsType = ( 

2155 AliasedReturnsRows._traverse_internals 

2156 + [ 

2157 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2158 ("_restates", InternalTraversal.dp_clauseelement), 

2159 ("recursive", InternalTraversal.dp_boolean), 

2160 ("nesting", InternalTraversal.dp_boolean), 

2161 ] 

2162 + HasPrefixes._has_prefixes_traverse_internals 

2163 + HasSuffixes._has_suffixes_traverse_internals 

2164 ) 

2165 

2166 element: HasCTE 

2167 

2168 @classmethod 

2169 def _factory( 

2170 cls, 

2171 selectable: HasCTE, 

2172 name: Optional[str] = None, 

2173 recursive: bool = False, 

2174 ) -> CTE: 

2175 r"""Return a new :class:`_expression.CTE`, 

2176 or Common Table Expression instance. 

2177 

2178 Please see :meth:`_expression.HasCTE.cte` for detail on CTE usage. 

2179 

2180 """ 

2181 return coercions.expect(roles.HasCTERole, selectable).cte( 

2182 name=name, recursive=recursive 

2183 ) 

2184 

2185 def _init( 

2186 self, 

2187 selectable: HasCTE, 

2188 *, 

2189 name: Optional[str] = None, 

2190 recursive: bool = False, 

2191 nesting: bool = False, 

2192 _cte_alias: Optional[CTE] = None, 

2193 _restates: Optional[CTE] = None, 

2194 _prefixes: Optional[Tuple[()]] = None, 

2195 _suffixes: Optional[Tuple[()]] = None, 

2196 ) -> None: 

2197 self.recursive = recursive 

2198 self.nesting = nesting 

2199 self._cte_alias = _cte_alias 

2200 # Keep recursivity reference with union/union_all 

2201 self._restates = _restates 

2202 if _prefixes: 

2203 self._prefixes = _prefixes 

2204 if _suffixes: 

2205 self._suffixes = _suffixes 

2206 super()._init(selectable, name=name) 

2207 

2208 def _populate_column_collection( 

2209 self, 

2210 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

2211 primary_key: ColumnSet, 

2212 foreign_keys: Set[KeyedColumnElement[Any]], 

2213 ) -> None: 

2214 if self._cte_alias is not None: 

2215 self._cte_alias._generate_fromclause_column_proxies( 

2216 self, 

2217 columns, 

2218 primary_key=primary_key, 

2219 foreign_keys=foreign_keys, 

2220 ) 

2221 else: 

2222 self.element._generate_fromclause_column_proxies( 

2223 self, 

2224 columns, 

2225 primary_key=primary_key, 

2226 foreign_keys=foreign_keys, 

2227 ) 

2228 

2229 def alias(self, name: Optional[str] = None, flat: bool = False) -> CTE: 

2230 """Return an :class:`_expression.Alias` of this 

2231 :class:`_expression.CTE`. 

2232 

2233 This method is a CTE-specific specialization of the 

2234 :meth:`_expression.FromClause.alias` method. 

2235 

2236 .. seealso:: 

2237 

2238 :ref:`tutorial_using_aliases` 

2239 

2240 :func:`_expression.alias` 

2241 

2242 """ 

2243 return CTE._construct( 

2244 self.element, 

2245 name=name, 

2246 recursive=self.recursive, 

2247 nesting=self.nesting, 

2248 _cte_alias=self, 

2249 _prefixes=self._prefixes, 

2250 _suffixes=self._suffixes, 

2251 ) 

2252 

2253 def union(self, *other: _SelectStatementForCompoundArgument[Any]) -> CTE: 

2254 r"""Return a new :class:`_expression.CTE` with a SQL ``UNION`` 

2255 of the original CTE against the given selectables provided 

2256 as positional arguments. 

2257 

2258 :param \*other: one or more elements with which to create a 

2259 UNION. 

2260 

2261 .. versionchanged:: 1.4.28 multiple elements are now accepted. 

2262 

2263 .. seealso:: 

2264 

2265 :meth:`_sql.HasCTE.cte` - examples of calling styles 

2266 

2267 """ 

2268 assert is_select_statement( 

2269 self.element 

2270 ), f"CTE element f{self.element} does not support union()" 

2271 

2272 return CTE._construct( 

2273 self.element.union(*other), 

2274 name=self.name, 

2275 recursive=self.recursive, 

2276 nesting=self.nesting, 

2277 _restates=self, 

2278 _prefixes=self._prefixes, 

2279 _suffixes=self._suffixes, 

2280 ) 

2281 

2282 def union_all( 

2283 self, *other: _SelectStatementForCompoundArgument[Any] 

2284 ) -> CTE: 

2285 r"""Return a new :class:`_expression.CTE` with a SQL ``UNION ALL`` 

2286 of the original CTE against the given selectables provided 

2287 as positional arguments. 

2288 

2289 :param \*other: one or more elements with which to create a 

2290 UNION. 

2291 

2292 .. versionchanged:: 1.4.28 multiple elements are now accepted. 

2293 

2294 .. seealso:: 

2295 

2296 :meth:`_sql.HasCTE.cte` - examples of calling styles 

2297 

2298 """ 

2299 

2300 assert is_select_statement( 

2301 self.element 

2302 ), f"CTE element f{self.element} does not support union_all()" 

2303 

2304 return CTE._construct( 

2305 self.element.union_all(*other), 

2306 name=self.name, 

2307 recursive=self.recursive, 

2308 nesting=self.nesting, 

2309 _restates=self, 

2310 _prefixes=self._prefixes, 

2311 _suffixes=self._suffixes, 

2312 ) 

2313 

2314 def _get_reference_cte(self) -> CTE: 

2315 """ 

2316 A recursive CTE is updated to attach the recursive part. 

2317 Updated CTEs should still refer to the original CTE. 

2318 This function returns this reference identifier. 

2319 """ 

2320 return self._restates if self._restates is not None else self 

2321 

2322 

2323class _CTEOpts(NamedTuple): 

2324 nesting: bool 

2325 

2326 

2327class _ColumnsPlusNames(NamedTuple): 

2328 required_label_name: Optional[str] 

2329 """ 

2330 string label name, if non-None, must be rendered as a 

2331 label, i.e. "AS <name>" 

2332 """ 

2333 

2334 proxy_key: Optional[str] 

2335 """ 

2336 proxy_key that is to be part of the result map for this 

2337 col. this is also the key in a fromclause.c or 

2338 select.selected_columns collection 

2339 """ 

2340 

2341 fallback_label_name: Optional[str] 

2342 """ 

2343 name that can be used to render an "AS <name>" when 

2344 we have to render a label even though 

2345 required_label_name was not given 

2346 """ 

2347 

2348 column: Union[ColumnElement[Any], TextClause] 

2349 """ 

2350 the ColumnElement itself 

2351 """ 

2352 

2353 repeated: bool 

2354 """ 

2355 True if this is a duplicate of a previous column 

2356 in the list of columns 

2357 """ 

2358 

2359 

2360class SelectsRows(ReturnsRows): 

2361 """Sub-base of ReturnsRows for elements that deliver rows 

2362 directly, namely SELECT and INSERT/UPDATE/DELETE..RETURNING""" 

2363 

2364 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2365 

2366 def _generate_columns_plus_names( 

2367 self, 

2368 anon_for_dupe_key: bool, 

2369 cols: Optional[_SelectIterable] = None, 

2370 ) -> List[_ColumnsPlusNames]: 

2371 """Generate column names as rendered in a SELECT statement by 

2372 the compiler, as well as tokens used to populate the .c. collection 

2373 on a :class:`.FromClause`. 

2374 

2375 This is distinct from the _column_naming_convention generator that's 

2376 intended for population of the Select.selected_columns collection, 

2377 different rules. the collection returned here calls upon the 

2378 _column_naming_convention as well. 

2379 

2380 """ 

2381 

2382 if cols is None: 

2383 cols = self._all_selected_columns 

2384 

2385 key_naming_convention = SelectState._column_naming_convention( 

2386 self._label_style 

2387 ) 

2388 

2389 names = {} 

2390 

2391 result: List[_ColumnsPlusNames] = [] 

2392 result_append = result.append 

2393 

2394 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2395 label_style_none = self._label_style is LABEL_STYLE_NONE 

2396 

2397 # a counter used for "dedupe" labels, which have double underscores 

2398 # in them and are never referred by name; they only act 

2399 # as positional placeholders. they need only be unique within 

2400 # the single columns clause they're rendered within (required by 

2401 # some dbs such as mysql). So their anon identity is tracked against 

2402 # a fixed counter rather than hash() identity. 

2403 dedupe_hash = 1 

2404 

2405 for c in cols: 

2406 repeated = False 

2407 

2408 if not c._render_label_in_columns_clause: 

2409 effective_name = required_label_name = fallback_label_name = ( 

2410 None 

2411 ) 

2412 elif label_style_none: 

2413 if TYPE_CHECKING: 

2414 assert is_column_element(c) 

2415 

2416 effective_name = required_label_name = None 

2417 fallback_label_name = c._non_anon_label or c._anon_name_label 

2418 else: 

2419 if TYPE_CHECKING: 

2420 assert is_column_element(c) 

2421 

2422 if table_qualified: 

2423 required_label_name = effective_name = ( 

2424 fallback_label_name 

2425 ) = c._tq_label 

2426 else: 

2427 effective_name = fallback_label_name = c._non_anon_label 

2428 required_label_name = None 

2429 

2430 if effective_name is None: 

2431 # it seems like this could be _proxy_key and we would 

2432 # not need _expression_label but it isn't 

2433 # giving us a clue when to use anon_label instead 

2434 expr_label = c._expression_label 

2435 if expr_label is None: 

2436 repeated = c._anon_name_label in names 

2437 names[c._anon_name_label] = c 

2438 effective_name = required_label_name = None 

2439 

2440 if repeated: 

2441 # here, "required_label_name" is sent as 

2442 # "None" and "fallback_label_name" is sent. 

2443 if table_qualified: 

2444 fallback_label_name = ( 

2445 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2446 ) 

2447 dedupe_hash += 1 

2448 else: 

2449 fallback_label_name = c._dedupe_anon_label_idx( 

2450 dedupe_hash 

2451 ) 

2452 dedupe_hash += 1 

2453 else: 

2454 fallback_label_name = c._anon_name_label 

2455 else: 

2456 required_label_name = effective_name = ( 

2457 fallback_label_name 

2458 ) = expr_label 

2459 

2460 if effective_name is not None: 

2461 if TYPE_CHECKING: 

2462 assert is_column_element(c) 

2463 

2464 if effective_name in names: 

2465 # when looking to see if names[name] is the same column as 

2466 # c, use hash(), so that an annotated version of the column 

2467 # is seen as the same as the non-annotated 

2468 if hash(names[effective_name]) != hash(c): 

2469 # different column under the same name. apply 

2470 # disambiguating label 

2471 if table_qualified: 

2472 required_label_name = fallback_label_name = ( 

2473 c._anon_tq_label 

2474 ) 

2475 else: 

2476 required_label_name = fallback_label_name = ( 

2477 c._anon_name_label 

2478 ) 

2479 

2480 if anon_for_dupe_key and required_label_name in names: 

2481 # here, c._anon_tq_label is definitely unique to 

2482 # that column identity (or annotated version), so 

2483 # this should always be true. 

2484 # this is also an infrequent codepath because 

2485 # you need two levels of duplication to be here 

2486 assert hash(names[required_label_name]) == hash(c) 

2487 

2488 # the column under the disambiguating label is 

2489 # already present. apply the "dedupe" label to 

2490 # subsequent occurrences of the column so that the 

2491 # original stays non-ambiguous 

2492 if table_qualified: 

2493 required_label_name = fallback_label_name = ( 

2494 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2495 ) 

2496 dedupe_hash += 1 

2497 else: 

2498 required_label_name = fallback_label_name = ( 

2499 c._dedupe_anon_label_idx(dedupe_hash) 

2500 ) 

2501 dedupe_hash += 1 

2502 repeated = True 

2503 else: 

2504 names[required_label_name] = c 

2505 elif anon_for_dupe_key: 

2506 # same column under the same name. apply the "dedupe" 

2507 # label so that the original stays non-ambiguous 

2508 if table_qualified: 

2509 required_label_name = fallback_label_name = ( 

2510 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2511 ) 

2512 dedupe_hash += 1 

2513 else: 

2514 required_label_name = fallback_label_name = ( 

2515 c._dedupe_anon_label_idx(dedupe_hash) 

2516 ) 

2517 dedupe_hash += 1 

2518 repeated = True 

2519 else: 

2520 names[effective_name] = c 

2521 

2522 result_append( 

2523 _ColumnsPlusNames( 

2524 required_label_name, 

2525 key_naming_convention(c), 

2526 fallback_label_name, 

2527 c, 

2528 repeated, 

2529 ) 

2530 ) 

2531 

2532 return result 

2533 

2534 

2535class HasCTE(roles.HasCTERole, SelectsRows): 

2536 """Mixin that declares a class to include CTE support.""" 

2537 

2538 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2539 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2540 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2541 ] 

2542 

2543 _independent_ctes: Tuple[CTE, ...] = () 

2544 _independent_ctes_opts: Tuple[_CTEOpts, ...] = () 

2545 

2546 name_cte_columns: bool = False 

2547 """indicates if this HasCTE as contained within a CTE should compel the CTE 

2548 to render the column names of this object in the WITH clause. 

2549 

2550 .. versionadded:: 2.0.42 

2551 

2552 """ 

2553 

2554 @_generative 

2555 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self: 

2556 r"""Add one or more :class:`_sql.CTE` constructs to this statement. 

2557 

2558 This method will associate the given :class:`_sql.CTE` constructs with 

2559 the parent statement such that they will each be unconditionally 

2560 rendered in the WITH clause of the final statement, even if not 

2561 referenced elsewhere within the statement or any sub-selects. 

2562 

2563 The optional :paramref:`.HasCTE.add_cte.nest_here` parameter when set 

2564 to True will have the effect that each given :class:`_sql.CTE` will 

2565 render in a WITH clause rendered directly along with this statement, 

2566 rather than being moved to the top of the ultimate rendered statement, 

2567 even if this statement is rendered as a subquery within a larger 

2568 statement. 

2569 

2570 This method has two general uses. One is to embed CTE statements that 

2571 serve some purpose without being referenced explicitly, such as the use 

2572 case of embedding a DML statement such as an INSERT or UPDATE as a CTE 

2573 inline with a primary statement that may draw from its results 

2574 indirectly. The other is to provide control over the exact placement 

2575 of a particular series of CTE constructs that should remain rendered 

2576 directly in terms of a particular statement that may be nested in a 

2577 larger statement. 

2578 

2579 E.g.:: 

2580 

2581 from sqlalchemy import table, column, select 

2582 

2583 t = table("t", column("c1"), column("c2")) 

2584 

2585 ins = t.insert().values({"c1": "x", "c2": "y"}).cte() 

2586 

2587 stmt = select(t).add_cte(ins) 

2588 

2589 Would render: 

2590 

2591 .. sourcecode:: sql 

2592 

2593 WITH anon_1 AS ( 

2594 INSERT INTO t (c1, c2) VALUES (:param_1, :param_2) 

2595 ) 

2596 SELECT t.c1, t.c2 

2597 FROM t 

2598 

2599 Above, the "anon_1" CTE is not referenced in the SELECT 

2600 statement, however still accomplishes the task of running an INSERT 

2601 statement. 

2602 

2603 Similarly in a DML-related context, using the PostgreSQL 

2604 :class:`_postgresql.Insert` construct to generate an "upsert":: 

2605 

2606 from sqlalchemy import table, column 

2607 from sqlalchemy.dialects.postgresql import insert 

2608 

2609 t = table("t", column("c1"), column("c2")) 

2610 

2611 delete_statement_cte = t.delete().where(t.c.c1 < 1).cte("deletions") 

2612 

2613 insert_stmt = insert(t).values({"c1": 1, "c2": 2}) 

2614 update_statement = insert_stmt.on_conflict_do_update( 

2615 index_elements=[t.c.c1], 

2616 set_={ 

2617 "c1": insert_stmt.excluded.c1, 

2618 "c2": insert_stmt.excluded.c2, 

2619 }, 

2620 ).add_cte(delete_statement_cte) 

2621 

2622 print(update_statement) 

2623 

2624 The above statement renders as: 

2625 

2626 .. sourcecode:: sql 

2627 

2628 WITH deletions AS ( 

2629 DELETE FROM t WHERE t.c1 < %(c1_1)s 

2630 ) 

2631 INSERT INTO t (c1, c2) VALUES (%(c1)s, %(c2)s) 

2632 ON CONFLICT (c1) DO UPDATE SET c1 = excluded.c1, c2 = excluded.c2 

2633 

2634 .. versionadded:: 1.4.21 

2635 

2636 :param \*ctes: zero or more :class:`.CTE` constructs. 

2637 

2638 .. versionchanged:: 2.0 Multiple CTE instances are accepted 

2639 

2640 :param nest_here: if True, the given CTE or CTEs will be rendered 

2641 as though they specified the :paramref:`.HasCTE.cte.nesting` flag 

2642 to ``True`` when they were added to this :class:`.HasCTE`. 

2643 Assuming the given CTEs are not referenced in an outer-enclosing 

2644 statement as well, the CTEs given should render at the level of 

2645 this statement when this flag is given. 

2646 

2647 .. versionadded:: 2.0 

2648 

2649 .. seealso:: 

2650 

2651 :paramref:`.HasCTE.cte.nesting` 

2652 

2653 

2654 """ # noqa: E501 

2655 opt = _CTEOpts(nest_here) 

2656 for cte in ctes: 

2657 cte = coercions.expect(roles.IsCTERole, cte) 

2658 self._independent_ctes += (cte,) 

2659 self._independent_ctes_opts += (opt,) 

2660 return self 

2661 

2662 def cte( 

2663 self, 

2664 name: Optional[str] = None, 

2665 recursive: bool = False, 

2666 nesting: bool = False, 

2667 ) -> CTE: 

2668 r"""Return a new :class:`_expression.CTE`, 

2669 or Common Table Expression instance. 

2670 

2671 Common table expressions are a SQL standard whereby SELECT 

2672 statements can draw upon secondary statements specified along 

2673 with the primary statement, using a clause called "WITH". 

2674 Special semantics regarding UNION can also be employed to 

2675 allow "recursive" queries, where a SELECT statement can draw 

2676 upon the set of rows that have previously been selected. 

2677 

2678 CTEs can also be applied to DML constructs UPDATE, INSERT 

2679 and DELETE on some databases, both as a source of CTE rows 

2680 when combined with RETURNING, as well as a consumer of 

2681 CTE rows. 

2682 

2683 SQLAlchemy detects :class:`_expression.CTE` objects, which are treated 

2684 similarly to :class:`_expression.Alias` objects, as special elements 

2685 to be delivered to the FROM clause of the statement as well 

2686 as to a WITH clause at the top of the statement. 

2687 

2688 For special prefixes such as PostgreSQL "MATERIALIZED" and 

2689 "NOT MATERIALIZED", the :meth:`_expression.CTE.prefix_with` 

2690 method may be 

2691 used to establish these. 

2692 

2693 :param name: name given to the common table expression. Like 

2694 :meth:`_expression.FromClause.alias`, the name can be left as 

2695 ``None`` in which case an anonymous symbol will be used at query 

2696 compile time. 

2697 :param recursive: if ``True``, will render ``WITH RECURSIVE``. 

2698 A recursive common table expression is intended to be used in 

2699 conjunction with UNION ALL in order to derive rows 

2700 from those already selected. 

2701 :param nesting: if ``True``, will render the CTE locally to the 

2702 statement in which it is referenced. For more complex scenarios, 

2703 the :meth:`.HasCTE.add_cte` method using the 

2704 :paramref:`.HasCTE.add_cte.nest_here` 

2705 parameter may also be used to more carefully 

2706 control the exact placement of a particular CTE. 

2707 

2708 .. versionadded:: 1.4.24 

2709 

2710 .. seealso:: 

2711 

2712 :meth:`.HasCTE.add_cte` 

2713 

2714 The following examples include two from PostgreSQL's documentation at 

2715 https://www.postgresql.org/docs/current/static/queries-with.html, 

2716 as well as additional examples. 

2717 

2718 Example 1, non recursive:: 

2719 

2720 from sqlalchemy import ( 

2721 Table, 

2722 Column, 

2723 String, 

2724 Integer, 

2725 MetaData, 

2726 select, 

2727 func, 

2728 ) 

2729 

2730 metadata = MetaData() 

2731 

2732 orders = Table( 

2733 "orders", 

2734 metadata, 

2735 Column("region", String), 

2736 Column("amount", Integer), 

2737 Column("product", String), 

2738 Column("quantity", Integer), 

2739 ) 

2740 

2741 regional_sales = ( 

2742 select(orders.c.region, func.sum(orders.c.amount).label("total_sales")) 

2743 .group_by(orders.c.region) 

2744 .cte("regional_sales") 

2745 ) 

2746 

2747 

2748 top_regions = ( 

2749 select(regional_sales.c.region) 

2750 .where( 

2751 regional_sales.c.total_sales 

2752 > select(func.sum(regional_sales.c.total_sales) / 10) 

2753 ) 

2754 .cte("top_regions") 

2755 ) 

2756 

2757 statement = ( 

2758 select( 

2759 orders.c.region, 

2760 orders.c.product, 

2761 func.sum(orders.c.quantity).label("product_units"), 

2762 func.sum(orders.c.amount).label("product_sales"), 

2763 ) 

2764 .where(orders.c.region.in_(select(top_regions.c.region))) 

2765 .group_by(orders.c.region, orders.c.product) 

2766 ) 

2767 

2768 result = conn.execute(statement).fetchall() 

2769 

2770 Example 2, WITH RECURSIVE:: 

2771 

2772 from sqlalchemy import ( 

2773 Table, 

2774 Column, 

2775 String, 

2776 Integer, 

2777 MetaData, 

2778 select, 

2779 func, 

2780 ) 

2781 

2782 metadata = MetaData() 

2783 

2784 parts = Table( 

2785 "parts", 

2786 metadata, 

2787 Column("part", String), 

2788 Column("sub_part", String), 

2789 Column("quantity", Integer), 

2790 ) 

2791 

2792 included_parts = ( 

2793 select(parts.c.sub_part, parts.c.part, parts.c.quantity) 

2794 .where(parts.c.part == "our part") 

2795 .cte(recursive=True) 

2796 ) 

2797 

2798 

2799 incl_alias = included_parts.alias() 

2800 parts_alias = parts.alias() 

2801 included_parts = included_parts.union_all( 

2802 select( 

2803 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

2804 ).where(parts_alias.c.part == incl_alias.c.sub_part) 

2805 ) 

2806 

2807 statement = select( 

2808 included_parts.c.sub_part, 

2809 func.sum(included_parts.c.quantity).label("total_quantity"), 

2810 ).group_by(included_parts.c.sub_part) 

2811 

2812 result = conn.execute(statement).fetchall() 

2813 

2814 Example 3, an upsert using UPDATE and INSERT with CTEs:: 

2815 

2816 from datetime import date 

2817 from sqlalchemy import ( 

2818 MetaData, 

2819 Table, 

2820 Column, 

2821 Integer, 

2822 Date, 

2823 select, 

2824 literal, 

2825 and_, 

2826 exists, 

2827 ) 

2828 

2829 metadata = MetaData() 

2830 

2831 visitors = Table( 

2832 "visitors", 

2833 metadata, 

2834 Column("product_id", Integer, primary_key=True), 

2835 Column("date", Date, primary_key=True), 

2836 Column("count", Integer), 

2837 ) 

2838 

2839 # add 5 visitors for the product_id == 1 

2840 product_id = 1 

2841 day = date.today() 

2842 count = 5 

2843 

2844 update_cte = ( 

2845 visitors.update() 

2846 .where( 

2847 and_(visitors.c.product_id == product_id, visitors.c.date == day) 

2848 ) 

2849 .values(count=visitors.c.count + count) 

2850 .returning(literal(1)) 

2851 .cte("update_cte") 

2852 ) 

2853 

2854 upsert = visitors.insert().from_select( 

2855 [visitors.c.product_id, visitors.c.date, visitors.c.count], 

2856 select(literal(product_id), literal(day), literal(count)).where( 

2857 ~exists(update_cte.select()) 

2858 ), 

2859 ) 

2860 

2861 connection.execute(upsert) 

2862 

2863 Example 4, Nesting CTE (SQLAlchemy 1.4.24 and above):: 

2864 

2865 value_a = select(literal("root").label("n")).cte("value_a") 

2866 

2867 # A nested CTE with the same name as the root one 

2868 value_a_nested = select(literal("nesting").label("n")).cte( 

2869 "value_a", nesting=True 

2870 ) 

2871 

2872 # Nesting CTEs takes ascendency locally 

2873 # over the CTEs at a higher level 

2874 value_b = select(value_a_nested.c.n).cte("value_b") 

2875 

2876 value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b")) 

2877 

2878 The above query will render the second CTE nested inside the first, 

2879 shown with inline parameters below as: 

2880 

2881 .. sourcecode:: sql 

2882 

2883 WITH 

2884 value_a AS 

2885 (SELECT 'root' AS n), 

2886 value_b AS 

2887 (WITH value_a AS 

2888 (SELECT 'nesting' AS n) 

2889 SELECT value_a.n AS n FROM value_a) 

2890 SELECT value_a.n AS a, value_b.n AS b 

2891 FROM value_a, value_b 

2892 

2893 The same CTE can be set up using the :meth:`.HasCTE.add_cte` method 

2894 as follows (SQLAlchemy 2.0 and above):: 

2895 

2896 value_a = select(literal("root").label("n")).cte("value_a") 

2897 

2898 # A nested CTE with the same name as the root one 

2899 value_a_nested = select(literal("nesting").label("n")).cte("value_a") 

2900 

2901 # Nesting CTEs takes ascendency locally 

2902 # over the CTEs at a higher level 

2903 value_b = ( 

2904 select(value_a_nested.c.n) 

2905 .add_cte(value_a_nested, nest_here=True) 

2906 .cte("value_b") 

2907 ) 

2908 

2909 value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b")) 

2910 

2911 Example 5, Non-Linear CTE (SQLAlchemy 1.4.28 and above):: 

2912 

2913 edge = Table( 

2914 "edge", 

2915 metadata, 

2916 Column("id", Integer, primary_key=True), 

2917 Column("left", Integer), 

2918 Column("right", Integer), 

2919 ) 

2920 

2921 root_node = select(literal(1).label("node")).cte("nodes", recursive=True) 

2922 

2923 left_edge = select(edge.c.left).join( 

2924 root_node, edge.c.right == root_node.c.node 

2925 ) 

2926 right_edge = select(edge.c.right).join( 

2927 root_node, edge.c.left == root_node.c.node 

2928 ) 

2929 

2930 subgraph_cte = root_node.union(left_edge, right_edge) 

2931 

2932 subgraph = select(subgraph_cte) 

2933 

2934 The above query will render 2 UNIONs inside the recursive CTE: 

2935 

2936 .. sourcecode:: sql 

2937 

2938 WITH RECURSIVE nodes(node) AS ( 

2939 SELECT 1 AS node 

2940 UNION 

2941 SELECT edge."left" AS "left" 

2942 FROM edge JOIN nodes ON edge."right" = nodes.node 

2943 UNION 

2944 SELECT edge."right" AS "right" 

2945 FROM edge JOIN nodes ON edge."left" = nodes.node 

2946 ) 

2947 SELECT nodes.node FROM nodes 

2948 

2949 .. seealso:: 

2950 

2951 :meth:`_orm.Query.cte` - ORM version of 

2952 :meth:`_expression.HasCTE.cte`. 

2953 

2954 """ # noqa: E501 

2955 return CTE._construct( 

2956 self, name=name, recursive=recursive, nesting=nesting 

2957 ) 

2958 

2959 

2960class Subquery(AliasedReturnsRows): 

2961 """Represent a subquery of a SELECT. 

2962 

2963 A :class:`.Subquery` is created by invoking the 

2964 :meth:`_expression.SelectBase.subquery` method, or for convenience the 

2965 :meth:`_expression.SelectBase.alias` method, on any 

2966 :class:`_expression.SelectBase` subclass 

2967 which includes :class:`_expression.Select`, 

2968 :class:`_expression.CompoundSelect`, and 

2969 :class:`_expression.TextualSelect`. As rendered in a FROM clause, 

2970 it represents the 

2971 body of the SELECT statement inside of parenthesis, followed by the usual 

2972 "AS <somename>" that defines all "alias" objects. 

2973 

2974 The :class:`.Subquery` object is very similar to the 

2975 :class:`_expression.Alias` 

2976 object and can be used in an equivalent way. The difference between 

2977 :class:`_expression.Alias` and :class:`.Subquery` is that 

2978 :class:`_expression.Alias` always 

2979 contains a :class:`_expression.FromClause` object whereas 

2980 :class:`.Subquery` 

2981 always contains a :class:`_expression.SelectBase` object. 

2982 

2983 .. versionadded:: 1.4 The :class:`.Subquery` class was added which now 

2984 serves the purpose of providing an aliased version of a SELECT 

2985 statement. 

2986 

2987 """ 

2988 

2989 __visit_name__ = "subquery" 

2990 

2991 _is_subquery = True 

2992 

2993 inherit_cache = True 

2994 

2995 element: SelectBase 

2996 

2997 @classmethod 

2998 def _factory( 

2999 cls, selectable: SelectBase, name: Optional[str] = None 

3000 ) -> Subquery: 

3001 """Return a :class:`.Subquery` object.""" 

3002 

3003 return coercions.expect( 

3004 roles.SelectStatementRole, selectable 

3005 ).subquery(name=name) 

3006 

3007 @util.deprecated( 

3008 "1.4", 

3009 "The :meth:`.Subquery.as_scalar` method, which was previously " 

3010 "``Alias.as_scalar()`` prior to version 1.4, is deprecated and " 

3011 "will be removed in a future release; Please use the " 

3012 ":meth:`_expression.Select.scalar_subquery` method of the " 

3013 ":func:`_expression.select` " 

3014 "construct before constructing a subquery object, or with the ORM " 

3015 "use the :meth:`_query.Query.scalar_subquery` method.", 

3016 ) 

3017 def as_scalar(self) -> ScalarSelect[Any]: 

3018 return self.element.set_label_style(LABEL_STYLE_NONE).scalar_subquery() 

3019 

3020 

3021class FromGrouping(GroupedElement, FromClause): 

3022 """Represent a grouping of a FROM clause""" 

3023 

3024 _traverse_internals: _TraverseInternalsType = [ 

3025 ("element", InternalTraversal.dp_clauseelement) 

3026 ] 

3027 

3028 element: FromClause 

3029 

3030 def __init__(self, element: FromClause): 

3031 self.element = coercions.expect(roles.FromClauseRole, element) 

3032 

3033 @util.ro_non_memoized_property 

3034 def columns( 

3035 self, 

3036 ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

3037 return self.element.columns 

3038 

3039 @util.ro_non_memoized_property 

3040 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

3041 return self.element.columns 

3042 

3043 @property 

3044 def primary_key(self) -> Iterable[NamedColumn[Any]]: 

3045 return self.element.primary_key 

3046 

3047 @property 

3048 def foreign_keys(self) -> Iterable[ForeignKey]: 

3049 return self.element.foreign_keys 

3050 

3051 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

3052 return self.element.is_derived_from(fromclause) 

3053 

3054 def alias( 

3055 self, name: Optional[str] = None, flat: bool = False 

3056 ) -> NamedFromGrouping: 

3057 return NamedFromGrouping(self.element.alias(name=name, flat=flat)) 

3058 

3059 def _anonymous_fromclause(self, **kw: Any) -> FromGrouping: 

3060 return FromGrouping(self.element._anonymous_fromclause(**kw)) 

3061 

3062 @util.ro_non_memoized_property 

3063 def _hide_froms(self) -> Iterable[FromClause]: 

3064 return self.element._hide_froms 

3065 

3066 @util.ro_non_memoized_property 

3067 def _from_objects(self) -> List[FromClause]: 

3068 return self.element._from_objects 

3069 

3070 def __getstate__(self) -> Dict[str, FromClause]: 

3071 return {"element": self.element} 

3072 

3073 def __setstate__(self, state: Dict[str, FromClause]) -> None: 

3074 self.element = state["element"] 

3075 

3076 if TYPE_CHECKING: 

3077 

3078 def self_group( 

3079 self, against: Optional[OperatorType] = None 

3080 ) -> Self: ... 

3081 

3082 

3083class NamedFromGrouping(FromGrouping, NamedFromClause): 

3084 """represent a grouping of a named FROM clause 

3085 

3086 .. versionadded:: 2.0 

3087 

3088 """ 

3089 

3090 inherit_cache = True 

3091 

3092 if TYPE_CHECKING: 

3093 

3094 def self_group( 

3095 self, against: Optional[OperatorType] = None 

3096 ) -> Self: ... 

3097 

3098 

3099class TableClause(roles.DMLTableRole, Immutable, NamedFromClause): 

3100 """Represents a minimal "table" construct. 

3101 

3102 This is a lightweight table object that has only a name, a 

3103 collection of columns, which are typically produced 

3104 by the :func:`_expression.column` function, and a schema:: 

3105 

3106 from sqlalchemy import table, column 

3107 

3108 user = table( 

3109 "user", 

3110 column("id"), 

3111 column("name"), 

3112 column("description"), 

3113 ) 

3114 

3115 The :class:`_expression.TableClause` construct serves as the base for 

3116 the more commonly used :class:`_schema.Table` object, providing 

3117 the usual set of :class:`_expression.FromClause` services including 

3118 the ``.c.`` collection and statement generation methods. 

3119 

3120 It does **not** provide all the additional schema-level services 

3121 of :class:`_schema.Table`, including constraints, references to other 

3122 tables, or support for :class:`_schema.MetaData`-level services. 

3123 It's useful 

3124 on its own as an ad-hoc construct used to generate quick SQL 

3125 statements when a more fully fledged :class:`_schema.Table` 

3126 is not on hand. 

3127 

3128 """ 

3129 

3130 __visit_name__ = "table" 

3131 

3132 _traverse_internals: _TraverseInternalsType = [ 

3133 ( 

3134 "columns", 

3135 InternalTraversal.dp_fromclause_canonical_column_collection, 

3136 ), 

3137 ("name", InternalTraversal.dp_string), 

3138 ("schema", InternalTraversal.dp_string), 

3139 ] 

3140 

3141 _is_table = True 

3142 

3143 fullname: str 

3144 

3145 implicit_returning = False 

3146 """:class:`_expression.TableClause` 

3147 doesn't support having a primary key or column 

3148 -level defaults, so implicit returning doesn't apply.""" 

3149 

3150 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3151 

3152 @util.ro_memoized_property 

3153 def _autoincrement_column(self) -> Optional[ColumnClause[Any]]: 

3154 """No PK or default support so no autoincrement column.""" 

3155 return None 

3156 

3157 def __init__(self, name: str, *columns: ColumnClause[Any], **kw: Any): 

3158 super().__init__() 

3159 self.name = name 

3160 self._columns = DedupeColumnCollection() # type: ignore[unused-ignore] 

3161 self.primary_key = ColumnSet() # type: ignore 

3162 self.foreign_keys = set() # type: ignore 

3163 for c in columns: 

3164 self.append_column(c) 

3165 

3166 schema = kw.pop("schema", None) 

3167 if schema is not None: 

3168 self.schema = schema 

3169 if self.schema is not None: 

3170 self.fullname = "%s.%s" % (self.schema, self.name) 

3171 else: 

3172 self.fullname = self.name 

3173 if kw: 

3174 raise exc.ArgumentError("Unsupported argument(s): %s" % list(kw)) 

3175 

3176 if TYPE_CHECKING: 

3177 

3178 @util.ro_non_memoized_property 

3179 def columns( 

3180 self, 

3181 ) -> ReadOnlyColumnCollection[str, ColumnClause[Any]]: ... 

3182 

3183 @util.ro_non_memoized_property 

3184 def c(self) -> ReadOnlyColumnCollection[str, ColumnClause[Any]]: ... 

3185 

3186 def __str__(self) -> str: 

3187 if self.schema is not None: 

3188 return self.schema + "." + self.name 

3189 else: 

3190 return self.name 

3191 

3192 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

3193 pass 

3194 

3195 @util.ro_memoized_property 

3196 def description(self) -> str: 

3197 return self.name 

3198 

3199 def _insert_col_impl( 

3200 self, 

3201 c: ColumnClause[Any], 

3202 *, 

3203 index: Optional[int] = None, 

3204 ) -> None: 

3205 existing = c.table 

3206 if existing is not None and existing is not self: 

3207 raise exc.ArgumentError( 

3208 "column object '%s' already assigned to table '%s'" 

3209 % (c.key, existing) 

3210 ) 

3211 self._columns.add(c, index=index) 

3212 c.table = self 

3213 

3214 def append_column(self, c: ColumnClause[Any]) -> None: 

3215 self._insert_col_impl(c) 

3216 

3217 def insert_column(self, c: ColumnClause[Any], index: int) -> None: 

3218 self._insert_col_impl(c, index=index) 

3219 

3220 @util.preload_module("sqlalchemy.sql.dml") 

3221 def insert(self) -> util.preloaded.sql_dml.Insert: 

3222 """Generate an :class:`_sql.Insert` construct against this 

3223 :class:`_expression.TableClause`. 

3224 

3225 E.g.:: 

3226 

3227 table.insert().values(name="foo") 

3228 

3229 See :func:`_expression.insert` for argument and usage information. 

3230 

3231 """ 

3232 

3233 return util.preloaded.sql_dml.Insert(self) 

3234 

3235 @util.preload_module("sqlalchemy.sql.dml") 

3236 def update(self) -> Update: 

3237 """Generate an :func:`_expression.update` construct against this 

3238 :class:`_expression.TableClause`. 

3239 

3240 E.g.:: 

3241 

3242 table.update().where(table.c.id == 7).values(name="foo") 

3243 

3244 See :func:`_expression.update` for argument and usage information. 

3245 

3246 """ 

3247 return util.preloaded.sql_dml.Update( 

3248 self, 

3249 ) 

3250 

3251 @util.preload_module("sqlalchemy.sql.dml") 

3252 def delete(self) -> Delete: 

3253 """Generate a :func:`_expression.delete` construct against this 

3254 :class:`_expression.TableClause`. 

3255 

3256 E.g.:: 

3257 

3258 table.delete().where(table.c.id == 7) 

3259 

3260 See :func:`_expression.delete` for argument and usage information. 

3261 

3262 """ 

3263 return util.preloaded.sql_dml.Delete(self) 

3264 

3265 @util.ro_non_memoized_property 

3266 def _from_objects(self) -> List[FromClause]: 

3267 return [self] 

3268 

3269 

3270ForUpdateParameter = Union["ForUpdateArg", None, bool, Dict[str, Any]] 

3271 

3272 

3273class ForUpdateArg(ClauseElement): 

3274 _traverse_internals: _TraverseInternalsType = [ 

3275 ("of", InternalTraversal.dp_clauseelement_list), 

3276 ("nowait", InternalTraversal.dp_boolean), 

3277 ("read", InternalTraversal.dp_boolean), 

3278 ("skip_locked", InternalTraversal.dp_boolean), 

3279 ("key_share", InternalTraversal.dp_boolean), 

3280 ] 

3281 

3282 of: Optional[Sequence[ClauseElement]] 

3283 nowait: bool 

3284 read: bool 

3285 skip_locked: bool 

3286 

3287 @classmethod 

3288 def _from_argument( 

3289 cls, with_for_update: ForUpdateParameter 

3290 ) -> Optional[ForUpdateArg]: 

3291 if isinstance(with_for_update, ForUpdateArg): 

3292 return with_for_update 

3293 elif with_for_update in (None, False): 

3294 return None 

3295 elif with_for_update is True: 

3296 return ForUpdateArg() 

3297 else: 

3298 return ForUpdateArg(**cast("Dict[str, Any]", with_for_update)) 

3299 

3300 def __eq__(self, other: Any) -> bool: 

3301 return ( 

3302 isinstance(other, ForUpdateArg) 

3303 and other.nowait == self.nowait 

3304 and other.read == self.read 

3305 and other.skip_locked == self.skip_locked 

3306 and other.key_share == self.key_share 

3307 and other.of is self.of 

3308 ) 

3309 

3310 def __ne__(self, other: Any) -> bool: 

3311 return not self.__eq__(other) 

3312 

3313 def __hash__(self) -> int: 

3314 return id(self) 

3315 

3316 def __init__( 

3317 self, 

3318 *, 

3319 nowait: bool = False, 

3320 read: bool = False, 

3321 of: Optional[_ForUpdateOfArgument] = None, 

3322 skip_locked: bool = False, 

3323 key_share: bool = False, 

3324 ): 

3325 """Represents arguments specified to 

3326 :meth:`_expression.Select.for_update`. 

3327 

3328 """ 

3329 

3330 self.nowait = nowait 

3331 self.read = read 

3332 self.skip_locked = skip_locked 

3333 self.key_share = key_share 

3334 if of is not None: 

3335 self.of = [ 

3336 coercions.expect(roles.ColumnsClauseRole, elem) 

3337 for elem in util.to_list(of) 

3338 ] 

3339 else: 

3340 self.of = None 

3341 

3342 

3343class Values(roles.InElementRole, HasCTE, Generative, LateralFromClause): 

3344 """Represent a ``VALUES`` construct that can be used as a FROM element 

3345 in a statement. 

3346 

3347 The :class:`_expression.Values` object is created from the 

3348 :func:`_expression.values` function. 

3349 

3350 .. versionadded:: 1.4 

3351 

3352 """ 

3353 

3354 __visit_name__ = "values" 

3355 

3356 _data: Tuple[Sequence[Tuple[Any, ...]], ...] = () 

3357 

3358 _unnamed: bool 

3359 _traverse_internals: _TraverseInternalsType = [ 

3360 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3361 ("_data", InternalTraversal.dp_dml_multi_values), 

3362 ("name", InternalTraversal.dp_string), 

3363 ("literal_binds", InternalTraversal.dp_boolean), 

3364 ] + HasCTE._has_ctes_traverse_internals 

3365 

3366 name_cte_columns = True 

3367 

3368 def __init__( 

3369 self, 

3370 *columns: ColumnClause[Any], 

3371 name: Optional[str] = None, 

3372 literal_binds: bool = False, 

3373 ): 

3374 super().__init__() 

3375 self._column_args = columns 

3376 

3377 if name is None: 

3378 self._unnamed = True 

3379 self.name = _anonymous_label.safe_construct(id(self), "anon") 

3380 else: 

3381 self._unnamed = False 

3382 self.name = name 

3383 self.literal_binds = literal_binds 

3384 self.named_with_column = not self._unnamed 

3385 

3386 @property 

3387 def _column_types(self) -> List[TypeEngine[Any]]: 

3388 return [col.type for col in self._column_args] 

3389 

3390 @util.ro_non_memoized_property 

3391 def _all_selected_columns(self) -> _SelectIterable: 

3392 return self._column_args 

3393 

3394 @_generative 

3395 def alias(self, name: Optional[str] = None, flat: bool = False) -> Self: 

3396 """Return a new :class:`_expression.Values` 

3397 construct that is a copy of this 

3398 one with the given name. 

3399 

3400 This method is a VALUES-specific specialization of the 

3401 :meth:`_expression.FromClause.alias` method. 

3402 

3403 .. seealso:: 

3404 

3405 :ref:`tutorial_using_aliases` 

3406 

3407 :func:`_expression.alias` 

3408 

3409 """ 

3410 non_none_name: str 

3411 

3412 if name is None: 

3413 non_none_name = _anonymous_label.safe_construct(id(self), "anon") 

3414 else: 

3415 non_none_name = name 

3416 

3417 self.name = non_none_name 

3418 self.named_with_column = True 

3419 self._unnamed = False 

3420 return self 

3421 

3422 @_generative 

3423 def lateral(self, name: Optional[str] = None) -> Self: 

3424 """Return a new :class:`_expression.Values` with the lateral flag set, 

3425 so that 

3426 it renders as LATERAL. 

3427 

3428 .. seealso:: 

3429 

3430 :func:`_expression.lateral` 

3431 

3432 """ 

3433 non_none_name: str 

3434 

3435 if name is None: 

3436 non_none_name = self.name 

3437 else: 

3438 non_none_name = name 

3439 

3440 self._is_lateral = True 

3441 self.name = non_none_name 

3442 self._unnamed = False 

3443 return self 

3444 

3445 @_generative 

3446 def data(self, values: Sequence[Tuple[Any, ...]]) -> Self: 

3447 """Return a new :class:`_expression.Values` construct, 

3448 adding the given data to the data list. 

3449 

3450 E.g.:: 

3451 

3452 my_values = my_values.data([(1, "value 1"), (2, "value2")]) 

3453 

3454 :param values: a sequence (i.e. list) of tuples that map to the 

3455 column expressions given in the :class:`_expression.Values` 

3456 constructor. 

3457 

3458 """ 

3459 

3460 self._data += (values,) 

3461 return self 

3462 

3463 def scalar_values(self) -> ScalarValues: 

3464 """Returns a scalar ``VALUES`` construct that can be used as a 

3465 COLUMN element in a statement. 

3466 

3467 .. versionadded:: 2.0.0b4 

3468 

3469 """ 

3470 return ScalarValues(self._column_args, self._data, self.literal_binds) 

3471 

3472 def _populate_column_collection( 

3473 self, 

3474 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

3475 primary_key: ColumnSet, 

3476 foreign_keys: Set[KeyedColumnElement[Any]], 

3477 ) -> None: 

3478 for c in self._column_args: 

3479 if c.table is not None and c.table is not self: 

3480 _, c = c._make_proxy( 

3481 self, primary_key=primary_key, foreign_keys=foreign_keys 

3482 ) 

3483 else: 

3484 # if the column was used in other contexts, ensure 

3485 # no memoizations of other FROM clauses. 

3486 # see test_values.py -> test_auto_proxy_select_direct_col 

3487 c._reset_memoizations() 

3488 columns.add(c) 

3489 c.table = self 

3490 

3491 @util.ro_non_memoized_property 

3492 def _from_objects(self) -> List[FromClause]: 

3493 return [self] 

3494 

3495 

3496class ScalarValues(roles.InElementRole, GroupedElement, ColumnElement[Any]): 

3497 """Represent a scalar ``VALUES`` construct that can be used as a 

3498 COLUMN element in a statement. 

3499 

3500 The :class:`_expression.ScalarValues` object is created from the 

3501 :meth:`_expression.Values.scalar_values` method. It's also 

3502 automatically generated when a :class:`_expression.Values` is used in 

3503 an ``IN`` or ``NOT IN`` condition. 

3504 

3505 .. versionadded:: 2.0.0b4 

3506 

3507 """ 

3508 

3509 __visit_name__ = "scalar_values" 

3510 

3511 _traverse_internals: _TraverseInternalsType = [ 

3512 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3513 ("_data", InternalTraversal.dp_dml_multi_values), 

3514 ("literal_binds", InternalTraversal.dp_boolean), 

3515 ] 

3516 

3517 def __init__( 

3518 self, 

3519 columns: Sequence[ColumnClause[Any]], 

3520 data: Tuple[Sequence[Tuple[Any, ...]], ...], 

3521 literal_binds: bool, 

3522 ): 

3523 super().__init__() 

3524 self._column_args = columns 

3525 self._data = data 

3526 self.literal_binds = literal_binds 

3527 

3528 @property 

3529 def _column_types(self) -> List[TypeEngine[Any]]: 

3530 return [col.type for col in self._column_args] 

3531 

3532 def __clause_element__(self) -> ScalarValues: 

3533 return self 

3534 

3535 if TYPE_CHECKING: 

3536 

3537 def self_group( 

3538 self, against: Optional[OperatorType] = None 

3539 ) -> Self: ... 

3540 

3541 def _ungroup(self) -> ColumnElement[Any]: ... 

3542 

3543 

3544class SelectBase( 

3545 roles.SelectStatementRole, 

3546 roles.DMLSelectRole, 

3547 roles.CompoundElementRole, 

3548 roles.InElementRole, 

3549 HasCTE, 

3550 SupportsCloneAnnotations, 

3551 Selectable, 

3552): 

3553 """Base class for SELECT statements. 

3554 

3555 

3556 This includes :class:`_expression.Select`, 

3557 :class:`_expression.CompoundSelect` and 

3558 :class:`_expression.TextualSelect`. 

3559 

3560 

3561 """ 

3562 

3563 _is_select_base = True 

3564 is_select = True 

3565 

3566 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3567 

3568 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

3569 self._reset_memoizations() 

3570 

3571 @util.ro_non_memoized_property 

3572 def selected_columns( 

3573 self, 

3574 ) -> ColumnCollection[str, ColumnElement[Any]]: 

3575 """A :class:`_expression.ColumnCollection` 

3576 representing the columns that 

3577 this SELECT statement or similar construct returns in its result set. 

3578 

3579 This collection differs from the :attr:`_expression.FromClause.columns` 

3580 collection of a :class:`_expression.FromClause` in that the columns 

3581 within this collection cannot be directly nested inside another SELECT 

3582 statement; a subquery must be applied first which provides for the 

3583 necessary parenthesization required by SQL. 

3584 

3585 .. note:: 

3586 

3587 The :attr:`_sql.SelectBase.selected_columns` collection does not 

3588 include expressions established in the columns clause using the 

3589 :func:`_sql.text` construct; these are silently omitted from the 

3590 collection. To use plain textual column expressions inside of a 

3591 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

3592 construct. 

3593 

3594 .. seealso:: 

3595 

3596 :attr:`_sql.Select.selected_columns` 

3597 

3598 .. versionadded:: 1.4 

3599 

3600 """ 

3601 raise NotImplementedError() 

3602 

3603 def _generate_fromclause_column_proxies( 

3604 self, 

3605 subquery: FromClause, 

3606 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

3607 primary_key: ColumnSet, 

3608 foreign_keys: Set[KeyedColumnElement[Any]], 

3609 *, 

3610 proxy_compound_columns: Optional[ 

3611 Iterable[Sequence[ColumnElement[Any]]] 

3612 ] = None, 

3613 ) -> None: 

3614 raise NotImplementedError() 

3615 

3616 @util.ro_non_memoized_property 

3617 def _all_selected_columns(self) -> _SelectIterable: 

3618 """A sequence of expressions that correspond to what is rendered 

3619 in the columns clause, including :class:`_sql.TextClause` 

3620 constructs. 

3621 

3622 .. versionadded:: 1.4.12 

3623 

3624 .. seealso:: 

3625 

3626 :attr:`_sql.SelectBase.exported_columns` 

3627 

3628 """ 

3629 raise NotImplementedError() 

3630 

3631 @property 

3632 def exported_columns( 

3633 self, 

3634 ) -> ReadOnlyColumnCollection[str, ColumnElement[Any]]: 

3635 """A :class:`_expression.ColumnCollection` 

3636 that represents the "exported" 

3637 columns of this :class:`_expression.Selectable`, not including 

3638 :class:`_sql.TextClause` constructs. 

3639 

3640 The "exported" columns for a :class:`_expression.SelectBase` 

3641 object are synonymous 

3642 with the :attr:`_expression.SelectBase.selected_columns` collection. 

3643 

3644 .. versionadded:: 1.4 

3645 

3646 .. seealso:: 

3647 

3648 :attr:`_expression.Select.exported_columns` 

3649 

3650 :attr:`_expression.Selectable.exported_columns` 

3651 

3652 :attr:`_expression.FromClause.exported_columns` 

3653 

3654 

3655 """ 

3656 return self.selected_columns.as_readonly() 

3657 

3658 def get_label_style(self) -> SelectLabelStyle: 

3659 """ 

3660 Retrieve the current label style. 

3661 

3662 Implemented by subclasses. 

3663 

3664 """ 

3665 raise NotImplementedError() 

3666 

3667 def set_label_style(self, style: SelectLabelStyle) -> Self: 

3668 """Return a new selectable with the specified label style. 

3669 

3670 Implemented by subclasses. 

3671 

3672 """ 

3673 

3674 raise NotImplementedError() 

3675 

3676 def _scalar_type(self) -> TypeEngine[Any]: 

3677 raise NotImplementedError() 

3678 

3679 @util.deprecated( 

3680 "1.4", 

3681 "The :meth:`_expression.SelectBase.as_scalar` " 

3682 "method is deprecated and will be " 

3683 "removed in a future release. Please refer to " 

3684 ":meth:`_expression.SelectBase.scalar_subquery`.", 

3685 ) 

3686 def as_scalar(self) -> ScalarSelect[Any]: 

3687 return self.scalar_subquery() 

3688 

3689 def exists(self) -> Exists: 

3690 """Return an :class:`_sql.Exists` representation of this selectable, 

3691 which can be used as a column expression. 

3692 

3693 The returned object is an instance of :class:`_sql.Exists`. 

3694 

3695 .. seealso:: 

3696 

3697 :func:`_sql.exists` 

3698 

3699 :ref:`tutorial_exists` - in the :term:`2.0 style` tutorial. 

3700 

3701 .. versionadded:: 1.4 

3702 

3703 """ 

3704 return Exists(self) 

3705 

3706 def scalar_subquery(self) -> ScalarSelect[Any]: 

3707 """Return a 'scalar' representation of this selectable, which can be 

3708 used as a column expression. 

3709 

3710 The returned object is an instance of :class:`_sql.ScalarSelect`. 

3711 

3712 Typically, a select statement which has only one column in its columns 

3713 clause is eligible to be used as a scalar expression. The scalar 

3714 subquery can then be used in the WHERE clause or columns clause of 

3715 an enclosing SELECT. 

3716 

3717 Note that the scalar subquery differentiates from the FROM-level 

3718 subquery that can be produced using the 

3719 :meth:`_expression.SelectBase.subquery` 

3720 method. 

3721 

3722 .. versionchanged:: 1.4 - the ``.as_scalar()`` method was renamed to 

3723 :meth:`_expression.SelectBase.scalar_subquery`. 

3724 

3725 .. seealso:: 

3726 

3727 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

3728 

3729 """ 

3730 if self._label_style is not LABEL_STYLE_NONE: 

3731 self = self.set_label_style(LABEL_STYLE_NONE) 

3732 

3733 return ScalarSelect(self) 

3734 

3735 def label(self, name: Optional[str]) -> Label[Any]: 

3736 """Return a 'scalar' representation of this selectable, embedded as a 

3737 subquery with a label. 

3738 

3739 .. seealso:: 

3740 

3741 :meth:`_expression.SelectBase.scalar_subquery`. 

3742 

3743 """ 

3744 return self.scalar_subquery().label(name) 

3745 

3746 def lateral(self, name: Optional[str] = None) -> LateralFromClause: 

3747 """Return a LATERAL alias of this :class:`_expression.Selectable`. 

3748 

3749 The return value is the :class:`_expression.Lateral` construct also 

3750 provided by the top-level :func:`_expression.lateral` function. 

3751 

3752 .. seealso:: 

3753 

3754 :ref:`tutorial_lateral_correlation` - overview of usage. 

3755 

3756 """ 

3757 return Lateral._factory(self, name) 

3758 

3759 def subquery(self, name: Optional[str] = None) -> Subquery: 

3760 """Return a subquery of this :class:`_expression.SelectBase`. 

3761 

3762 A subquery is from a SQL perspective a parenthesized, named 

3763 construct that can be placed in the FROM clause of another 

3764 SELECT statement. 

3765 

3766 Given a SELECT statement such as:: 

3767 

3768 stmt = select(table.c.id, table.c.name) 

3769 

3770 The above statement might look like: 

3771 

3772 .. sourcecode:: sql 

3773 

3774 SELECT table.id, table.name FROM table 

3775 

3776 The subquery form by itself renders the same way, however when 

3777 embedded into the FROM clause of another SELECT statement, it becomes 

3778 a named sub-element:: 

3779 

3780 subq = stmt.subquery() 

3781 new_stmt = select(subq) 

3782 

3783 The above renders as: 

3784 

3785 .. sourcecode:: sql 

3786 

3787 SELECT anon_1.id, anon_1.name 

3788 FROM (SELECT table.id, table.name FROM table) AS anon_1 

3789 

3790 Historically, :meth:`_expression.SelectBase.subquery` 

3791 is equivalent to calling 

3792 the :meth:`_expression.FromClause.alias` 

3793 method on a FROM object; however, 

3794 as a :class:`_expression.SelectBase` 

3795 object is not directly FROM object, 

3796 the :meth:`_expression.SelectBase.subquery` 

3797 method provides clearer semantics. 

3798 

3799 .. versionadded:: 1.4 

3800 

3801 """ 

3802 

3803 return Subquery._construct( 

3804 self._ensure_disambiguated_names(), name=name 

3805 ) 

3806 

3807 @util.preload_module("sqlalchemy.sql.ddl") 

3808 def into( 

3809 self, 

3810 target: str, 

3811 *, 

3812 metadata: Optional["MetaData"] = None, 

3813 schema: Optional[str] = None, 

3814 temporary: bool = False, 

3815 if_not_exists: bool = False, 

3816 ) -> CreateTableAs: 

3817 """Create a :class:`_schema.CreateTableAs` construct from this SELECT. 

3818 

3819 This method provides a convenient way to create a ``CREATE TABLE ... 

3820 AS`` statement from a SELECT, as well as compound SELECTs like UNION. 

3821 The new table will be created with columns matching the SELECT list. 

3822 

3823 Supported on all included backends, the construct emits 

3824 ``CREATE TABLE...AS`` for all backends except SQL Server, which instead 

3825 emits a ``SELECT..INTO`` statement. 

3826 

3827 e.g.:: 

3828 

3829 from sqlalchemy import select 

3830 

3831 # Create a new table from a SELECT 

3832 stmt = ( 

3833 select(users.c.id, users.c.name) 

3834 .where(users.c.status == "active") 

3835 .into("active_users") 

3836 ) 

3837 

3838 with engine.begin() as conn: 

3839 conn.execute(stmt) 

3840 

3841 # With optional flags 

3842 stmt = ( 

3843 select(users.c.id) 

3844 .where(users.c.status == "inactive") 

3845 .into("inactive_users", schema="analytics", if_not_exists=True) 

3846 ) 

3847 

3848 .. versionadded:: 2.1 

3849 

3850 :param target: Name of the table to create as a string. Must be 

3851 unqualified; use the ``schema`` parameter for qualification. 

3852 

3853 :param metadata: :class:`_schema.MetaData`, optional 

3854 If provided, the :class:`_schema.Table` object available via the 

3855 :attr:`.CreateTableAs.table` attribute will be associated with this 

3856 :class:`.MetaData`. Otherwise, a new, empty :class:`.MetaData` 

3857 is created. 

3858 

3859 :param schema: Optional schema name for the new table. 

3860 

3861 :param temporary: If True, create a temporary table where supported 

3862 

3863 :param if_not_exists: If True, add IF NOT EXISTS clause where supported 

3864 

3865 :return: A :class:`_schema.CreateTableAs` construct. 

3866 

3867 .. seealso:: 

3868 

3869 :ref:`metadata_create_table_as` - in :ref:`metadata_toplevel` 

3870 

3871 :class:`_schema.CreateTableAs` 

3872 

3873 """ 

3874 sql_ddl = util.preloaded.sql_ddl 

3875 

3876 return sql_ddl.CreateTableAs( 

3877 self, 

3878 target, 

3879 metadata=metadata, 

3880 schema=schema, 

3881 temporary=temporary, 

3882 if_not_exists=if_not_exists, 

3883 ) 

3884 

3885 def _ensure_disambiguated_names(self) -> Self: 

3886 """Ensure that the names generated by this selectbase will be 

3887 disambiguated in some way, if possible. 

3888 

3889 """ 

3890 

3891 raise NotImplementedError() 

3892 

3893 def alias( 

3894 self, name: Optional[str] = None, flat: bool = False 

3895 ) -> Subquery: 

3896 """Return a named subquery against this 

3897 :class:`_expression.SelectBase`. 

3898 

3899 For a :class:`_expression.SelectBase` (as opposed to a 

3900 :class:`_expression.FromClause`), 

3901 this returns a :class:`.Subquery` object which behaves mostly the 

3902 same as the :class:`_expression.Alias` object that is used with a 

3903 :class:`_expression.FromClause`. 

3904 

3905 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3906 method is now 

3907 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3908 

3909 """ 

3910 return self.subquery(name=name) 

3911 

3912 

3913_SB = TypeVar("_SB", bound=SelectBase) 

3914 

3915 

3916class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3917 """Represent a grouping of a :class:`_expression.SelectBase`. 

3918 

3919 This differs from :class:`.Subquery` in that we are still 

3920 an "inner" SELECT statement, this is strictly for grouping inside of 

3921 compound selects. 

3922 

3923 """ 

3924 

3925 __visit_name__ = "select_statement_grouping" 

3926 _traverse_internals: _TraverseInternalsType = [ 

3927 ("element", InternalTraversal.dp_clauseelement) 

3928 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3929 

3930 _is_select_container = True 

3931 

3932 element: _SB 

3933 

3934 def __init__(self, element: _SB) -> None: 

3935 self.element = cast( 

3936 _SB, coercions.expect(roles.SelectStatementRole, element) 

3937 ) 

3938 

3939 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3940 new_element = self.element._ensure_disambiguated_names() 

3941 if new_element is not self.element: 

3942 return SelectStatementGrouping(new_element) 

3943 else: 

3944 return self 

3945 

3946 def get_label_style(self) -> SelectLabelStyle: 

3947 return self.element.get_label_style() 

3948 

3949 def set_label_style( 

3950 self, label_style: SelectLabelStyle 

3951 ) -> SelectStatementGrouping[_SB]: 

3952 return SelectStatementGrouping( 

3953 self.element.set_label_style(label_style) 

3954 ) 

3955 

3956 @property 

3957 def select_statement(self) -> _SB: 

3958 return self.element 

3959 

3960 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3961 return self 

3962 

3963 if TYPE_CHECKING: 

3964 

3965 def _ungroup(self) -> _SB: ... 

3966 

3967 # def _generate_columns_plus_names( 

3968 # self, anon_for_dupe_key: bool 

3969 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3970 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3971 

3972 def _generate_fromclause_column_proxies( 

3973 self, 

3974 subquery: FromClause, 

3975 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

3976 primary_key: ColumnSet, 

3977 foreign_keys: Set[KeyedColumnElement[Any]], 

3978 *, 

3979 proxy_compound_columns: Optional[ 

3980 Iterable[Sequence[ColumnElement[Any]]] 

3981 ] = None, 

3982 ) -> None: 

3983 self.element._generate_fromclause_column_proxies( 

3984 subquery, 

3985 columns, 

3986 proxy_compound_columns=proxy_compound_columns, 

3987 primary_key=primary_key, 

3988 foreign_keys=foreign_keys, 

3989 ) 

3990 

3991 @util.ro_non_memoized_property 

3992 def _all_selected_columns(self) -> _SelectIterable: 

3993 return self.element._all_selected_columns 

3994 

3995 @util.ro_non_memoized_property 

3996 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

3997 """A :class:`_expression.ColumnCollection` 

3998 representing the columns that 

3999 the embedded SELECT statement returns in its result set, not including 

4000 :class:`_sql.TextClause` constructs. 

4001 

4002 .. versionadded:: 1.4 

4003 

4004 .. seealso:: 

4005 

4006 :attr:`_sql.Select.selected_columns` 

4007 

4008 """ 

4009 return self.element.selected_columns 

4010 

4011 @util.ro_non_memoized_property 

4012 def _from_objects(self) -> List[FromClause]: 

4013 return self.element._from_objects 

4014 

4015 def _scalar_type(self) -> TypeEngine[Any]: 

4016 return self.element._scalar_type() 

4017 

4018 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self: 

4019 # SelectStatementGrouping not generative: has no attribute '_generate' 

4020 raise NotImplementedError 

4021 

4022 

4023class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

4024 """Base class for SELECT statements where additional elements can be 

4025 added. 

4026 

4027 This serves as the base for :class:`_expression.Select` and 

4028 :class:`_expression.CompoundSelect` 

4029 where elements such as ORDER BY, GROUP BY can be added and column 

4030 rendering can be controlled. Compare to 

4031 :class:`_expression.TextualSelect`, which, 

4032 while it subclasses :class:`_expression.SelectBase` 

4033 and is also a SELECT construct, 

4034 represents a fixed textual string which cannot be altered at this level, 

4035 only wrapped as a subquery. 

4036 

4037 """ 

4038 

4039 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

4040 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

4041 _limit_clause: Optional[ColumnElement[Any]] = None 

4042 _offset_clause: Optional[ColumnElement[Any]] = None 

4043 _fetch_clause: Optional[ColumnElement[Any]] = None 

4044 _fetch_clause_options: Optional[Dict[str, bool]] = None 

4045 _for_update_arg: Optional[ForUpdateArg] = None 

4046 

4047 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

4048 self._label_style = _label_style 

4049 

4050 @_generative 

4051 def with_for_update( 

4052 self, 

4053 *, 

4054 nowait: bool = False, 

4055 read: bool = False, 

4056 of: Optional[_ForUpdateOfArgument] = None, 

4057 skip_locked: bool = False, 

4058 key_share: bool = False, 

4059 ) -> Self: 

4060 """Specify a ``FOR UPDATE`` clause for this 

4061 :class:`_expression.GenerativeSelect`. 

4062 

4063 E.g.:: 

4064 

4065 stmt = select(table).with_for_update(nowait=True) 

4066 

4067 On a database like PostgreSQL or Oracle Database, the above would 

4068 render a statement like: 

4069 

4070 .. sourcecode:: sql 

4071 

4072 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

4073 

4074 on other backends, the ``nowait`` option is ignored and instead 

4075 would produce: 

4076 

4077 .. sourcecode:: sql 

4078 

4079 SELECT table.a, table.b FROM table FOR UPDATE 

4080 

4081 When called with no arguments, the statement will render with 

4082 the suffix ``FOR UPDATE``. Additional arguments can then be 

4083 provided which allow for common database-specific 

4084 variants. 

4085 

4086 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

4087 Database and PostgreSQL dialects. 

4088 

4089 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

4090 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

4091 ``nowait``, will render ``FOR SHARE NOWAIT``. 

4092 

4093 :param of: SQL expression or list of SQL expression elements, 

4094 (typically :class:`_schema.Column` objects or a compatible expression, 

4095 for some backends may also be a table expression) which will render 

4096 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4097 Database, some MySQL versions and possibly others. May render as a 

4098 table or as a column depending on backend. 

4099 

4100 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4101 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4102 if ``read=True`` is also specified. 

4103 

4104 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4105 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4106 on the PostgreSQL dialect. 

4107 

4108 """ 

4109 self._for_update_arg = ForUpdateArg( 

4110 nowait=nowait, 

4111 read=read, 

4112 of=of, 

4113 skip_locked=skip_locked, 

4114 key_share=key_share, 

4115 ) 

4116 return self 

4117 

4118 def get_label_style(self) -> SelectLabelStyle: 

4119 """ 

4120 Retrieve the current label style. 

4121 

4122 .. versionadded:: 1.4 

4123 

4124 """ 

4125 return self._label_style 

4126 

4127 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4128 """Return a new selectable with the specified label style. 

4129 

4130 There are three "label styles" available, 

4131 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4132 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4133 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4134 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4135 

4136 In modern SQLAlchemy, there is not generally a need to change the 

4137 labeling style, as per-expression labels are more effectively used by 

4138 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4139 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4140 disambiguate same-named columns from different tables, aliases, or 

4141 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4142 applies labels only to names that conflict with an existing name so 

4143 that the impact of this labeling is minimal. 

4144 

4145 The rationale for disambiguation is mostly so that all column 

4146 expressions are available from a given :attr:`_sql.FromClause.c` 

4147 collection when a subquery is created. 

4148 

4149 .. versionadded:: 1.4 - the 

4150 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4151 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4152 ``use_labels=True`` methods and/or parameters. 

4153 

4154 .. seealso:: 

4155 

4156 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4157 

4158 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL` 

4159 

4160 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE` 

4161 

4162 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DEFAULT` 

4163 

4164 """ 

4165 if self._label_style is not style: 

4166 self = self._generate() 

4167 self._label_style = style 

4168 return self 

4169 

4170 @property 

4171 def _group_by_clause(self) -> ClauseList: 

4172 """ClauseList access to group_by_clauses for legacy dialects""" 

4173 return ClauseList._construct_raw( 

4174 operators.comma_op, self._group_by_clauses 

4175 ) 

4176 

4177 @property 

4178 def _order_by_clause(self) -> ClauseList: 

4179 """ClauseList access to order_by_clauses for legacy dialects""" 

4180 return ClauseList._construct_raw( 

4181 operators.comma_op, self._order_by_clauses 

4182 ) 

4183 

4184 def _offset_or_limit_clause( 

4185 self, 

4186 element: _LimitOffsetType, 

4187 name: Optional[str] = None, 

4188 type_: Optional[_TypeEngineArgument[int]] = None, 

4189 ) -> ColumnElement[Any]: 

4190 """Convert the given value to an "offset or limit" clause. 

4191 

4192 This handles incoming integers and converts to an expression; if 

4193 an expression is already given, it is passed through. 

4194 

4195 """ 

4196 return coercions.expect( 

4197 roles.LimitOffsetRole, element, name=name, type_=type_ 

4198 ) 

4199 

4200 @overload 

4201 def _offset_or_limit_clause_asint( 

4202 self, clause: ColumnElement[Any], attrname: str 

4203 ) -> NoReturn: ... 

4204 

4205 @overload 

4206 def _offset_or_limit_clause_asint( 

4207 self, clause: Optional[_OffsetLimitParam], attrname: str 

4208 ) -> Optional[int]: ... 

4209 

4210 def _offset_or_limit_clause_asint( 

4211 self, clause: Optional[ColumnElement[Any]], attrname: str 

4212 ) -> Union[NoReturn, Optional[int]]: 

4213 """Convert the "offset or limit" clause of a select construct to an 

4214 integer. 

4215 

4216 This is only possible if the value is stored as a simple bound 

4217 parameter. Otherwise, a compilation error is raised. 

4218 

4219 """ 

4220 if clause is None: 

4221 return None 

4222 try: 

4223 value = clause._limit_offset_value 

4224 except AttributeError as err: 

4225 raise exc.CompileError( 

4226 "This SELECT structure does not use a simple " 

4227 "integer value for %s" % attrname 

4228 ) from err 

4229 else: 

4230 return util.asint(value) 

4231 

4232 @property 

4233 def _limit(self) -> Optional[int]: 

4234 """Get an integer value for the limit. This should only be used 

4235 by code that cannot support a limit as a BindParameter or 

4236 other custom clause as it will throw an exception if the limit 

4237 isn't currently set to an integer. 

4238 

4239 """ 

4240 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4241 

4242 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4243 """True if the clause is a simple integer, False 

4244 if it is not present or is a SQL expression. 

4245 """ 

4246 return isinstance(clause, _OffsetLimitParam) 

4247 

4248 @property 

4249 def _offset(self) -> Optional[int]: 

4250 """Get an integer value for the offset. This should only be used 

4251 by code that cannot support an offset as a BindParameter or 

4252 other custom clause as it will throw an exception if the 

4253 offset isn't currently set to an integer. 

4254 

4255 """ 

4256 return self._offset_or_limit_clause_asint( 

4257 self._offset_clause, "offset" 

4258 ) 

4259 

4260 @property 

4261 def _has_row_limiting_clause(self) -> bool: 

4262 return ( 

4263 self._limit_clause is not None 

4264 or self._offset_clause is not None 

4265 or self._fetch_clause is not None 

4266 ) 

4267 

4268 @_generative 

4269 def limit(self, limit: _LimitOffsetType) -> Self: 

4270 """Return a new selectable with the given LIMIT criterion 

4271 applied. 

4272 

4273 This is a numerical value which usually renders as a ``LIMIT`` 

4274 expression in the resulting select. Backends that don't 

4275 support ``LIMIT`` will attempt to provide similar 

4276 functionality. 

4277 

4278 .. note:: 

4279 

4280 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4281 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4282 

4283 :param limit: an integer LIMIT parameter, or a SQL expression 

4284 that provides an integer result. Pass ``None`` to reset it. 

4285 

4286 .. seealso:: 

4287 

4288 :meth:`_sql.GenerativeSelect.fetch` 

4289 

4290 :meth:`_sql.GenerativeSelect.offset` 

4291 

4292 """ 

4293 

4294 self._fetch_clause = self._fetch_clause_options = None 

4295 self._limit_clause = self._offset_or_limit_clause(limit) 

4296 return self 

4297 

4298 @_generative 

4299 def fetch( 

4300 self, 

4301 count: _LimitOffsetType, 

4302 with_ties: bool = False, 

4303 percent: bool = False, 

4304 **dialect_kw: Any, 

4305 ) -> Self: 

4306 r"""Return a new selectable with the given FETCH FIRST criterion 

4307 applied. 

4308 

4309 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4310 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4311 select. This functionality is is currently implemented for Oracle 

4312 Database, PostgreSQL, MSSQL. 

4313 

4314 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4315 

4316 .. note:: 

4317 

4318 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4319 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4320 

4321 .. versionadded:: 1.4 

4322 

4323 :param count: an integer COUNT parameter, or a SQL expression 

4324 that provides an integer result. When ``percent=True`` this will 

4325 represent the percentage of rows to return, not the absolute value. 

4326 Pass ``None`` to reset it. 

4327 

4328 :param with_ties: When ``True``, the WITH TIES option is used 

4329 to return any additional rows that tie for the last place in the 

4330 result set according to the ``ORDER BY`` clause. The 

4331 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4332 

4333 :param percent: When ``True``, ``count`` represents the percentage 

4334 of the total number of selected rows to return. Defaults to ``False`` 

4335 

4336 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4337 may be accepted by dialects. 

4338 

4339 .. versionadded:: 2.0.41 

4340 

4341 .. seealso:: 

4342 

4343 :meth:`_sql.GenerativeSelect.limit` 

4344 

4345 :meth:`_sql.GenerativeSelect.offset` 

4346 

4347 """ 

4348 self._validate_dialect_kwargs(dialect_kw) 

4349 self._limit_clause = None 

4350 if count is None: 

4351 self._fetch_clause = self._fetch_clause_options = None 

4352 else: 

4353 self._fetch_clause = self._offset_or_limit_clause(count) 

4354 self._fetch_clause_options = { 

4355 "with_ties": with_ties, 

4356 "percent": percent, 

4357 } 

4358 return self 

4359 

4360 @_generative 

4361 def offset(self, offset: _LimitOffsetType) -> Self: 

4362 """Return a new selectable with the given OFFSET criterion 

4363 applied. 

4364 

4365 

4366 This is a numeric value which usually renders as an ``OFFSET`` 

4367 expression in the resulting select. Backends that don't 

4368 support ``OFFSET`` will attempt to provide similar 

4369 functionality. 

4370 

4371 :param offset: an integer OFFSET parameter, or a SQL expression 

4372 that provides an integer result. Pass ``None`` to reset it. 

4373 

4374 .. seealso:: 

4375 

4376 :meth:`_sql.GenerativeSelect.limit` 

4377 

4378 :meth:`_sql.GenerativeSelect.fetch` 

4379 

4380 """ 

4381 

4382 self._offset_clause = self._offset_or_limit_clause(offset) 

4383 return self 

4384 

4385 @_generative 

4386 @util.preload_module("sqlalchemy.sql.util") 

4387 def slice( 

4388 self, 

4389 start: int, 

4390 stop: int, 

4391 ) -> Self: 

4392 """Apply LIMIT / OFFSET to this statement based on a slice. 

4393 

4394 The start and stop indices behave like the argument to Python's 

4395 built-in :func:`range` function. This method provides an 

4396 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4397 query. 

4398 

4399 For example, :: 

4400 

4401 stmt = select(User).order_by(User.id).slice(1, 3) 

4402 

4403 renders as 

4404 

4405 .. sourcecode:: sql 

4406 

4407 SELECT users.id AS users_id, 

4408 users.name AS users_name 

4409 FROM users ORDER BY users.id 

4410 LIMIT ? OFFSET ? 

4411 (2, 1) 

4412 

4413 .. note:: 

4414 

4415 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4416 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4417 

4418 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4419 method generalized from the ORM. 

4420 

4421 .. seealso:: 

4422 

4423 :meth:`_sql.GenerativeSelect.limit` 

4424 

4425 :meth:`_sql.GenerativeSelect.offset` 

4426 

4427 :meth:`_sql.GenerativeSelect.fetch` 

4428 

4429 """ 

4430 sql_util = util.preloaded.sql_util 

4431 self._fetch_clause = self._fetch_clause_options = None 

4432 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4433 self._limit_clause, self._offset_clause, start, stop 

4434 ) 

4435 return self 

4436 

4437 @_generative 

4438 def order_by( 

4439 self, 

4440 __first: Union[ 

4441 Literal[None, _NoArg.NO_ARG], 

4442 _ColumnExpressionOrStrLabelArgument[Any], 

4443 ] = _NoArg.NO_ARG, 

4444 /, 

4445 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4446 ) -> Self: 

4447 r"""Return a new selectable with the given list of ORDER BY 

4448 criteria applied. 

4449 

4450 e.g.:: 

4451 

4452 stmt = select(table).order_by(table.c.id, table.c.name) 

4453 

4454 Calling this method multiple times is equivalent to calling it once 

4455 with all the clauses concatenated. All existing ORDER BY criteria may 

4456 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4457 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4458 

4459 # will erase all ORDER BY and ORDER BY new_col alone 

4460 stmt = stmt.order_by(None).order_by(new_col) 

4461 

4462 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4463 constructs which will be used to generate an ORDER BY clause. 

4464 

4465 Alternatively, an individual entry may also be the string name of a 

4466 label located elsewhere in the columns clause of the statement which 

4467 will be matched and rendered in a backend-specific way based on 

4468 context; see :ref:`tutorial_order_by_label` for background on string 

4469 label matching in ORDER BY and GROUP BY expressions. 

4470 

4471 .. seealso:: 

4472 

4473 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4474 

4475 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4476 

4477 """ 

4478 

4479 if not clauses and __first is None: 

4480 self._order_by_clauses = () 

4481 elif __first is not _NoArg.NO_ARG: 

4482 self._order_by_clauses += tuple( 

4483 coercions.expect( 

4484 roles.OrderByRole, clause, apply_propagate_attrs=self 

4485 ) 

4486 for clause in (__first,) + clauses 

4487 ) 

4488 return self 

4489 

4490 @_generative 

4491 def group_by( 

4492 self, 

4493 __first: Union[ 

4494 Literal[None, _NoArg.NO_ARG], 

4495 _ColumnExpressionOrStrLabelArgument[Any], 

4496 ] = _NoArg.NO_ARG, 

4497 /, 

4498 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4499 ) -> Self: 

4500 r"""Return a new selectable with the given list of GROUP BY 

4501 criterion applied. 

4502 

4503 All existing GROUP BY settings can be suppressed by passing ``None``. 

4504 

4505 e.g.:: 

4506 

4507 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4508 

4509 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4510 constructs which will be used to generate an GROUP BY clause. 

4511 

4512 Alternatively, an individual entry may also be the string name of a 

4513 label located elsewhere in the columns clause of the statement which 

4514 will be matched and rendered in a backend-specific way based on 

4515 context; see :ref:`tutorial_order_by_label` for background on string 

4516 label matching in ORDER BY and GROUP BY expressions. 

4517 

4518 .. seealso:: 

4519 

4520 :ref:`tutorial_group_by_w_aggregates` - in the 

4521 :ref:`unified_tutorial` 

4522 

4523 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4524 

4525 """ # noqa: E501 

4526 

4527 if not clauses and __first is None: 

4528 self._group_by_clauses = () 

4529 elif __first is not _NoArg.NO_ARG: 

4530 self._group_by_clauses += tuple( 

4531 coercions.expect( 

4532 roles.GroupByRole, clause, apply_propagate_attrs=self 

4533 ) 

4534 for clause in (__first,) + clauses 

4535 ) 

4536 return self 

4537 

4538 

4539@CompileState.plugin_for("default", "compound_select") 

4540class CompoundSelectState(CompileState): 

4541 @util.memoized_property 

4542 def _label_resolve_dict( 

4543 self, 

4544 ) -> Tuple[ 

4545 Dict[str, ColumnElement[Any]], 

4546 Dict[str, ColumnElement[Any]], 

4547 Dict[str, ColumnElement[Any]], 

4548 ]: 

4549 # TODO: this is hacky and slow 

4550 hacky_subquery = self.statement.subquery() 

4551 hacky_subquery.named_with_column = False 

4552 d = {c.key: c for c in hacky_subquery.c} 

4553 return d, d, d 

4554 

4555 

4556class _CompoundSelectKeyword(Enum): 

4557 UNION = "UNION" 

4558 UNION_ALL = "UNION ALL" 

4559 EXCEPT = "EXCEPT" 

4560 EXCEPT_ALL = "EXCEPT ALL" 

4561 INTERSECT = "INTERSECT" 

4562 INTERSECT_ALL = "INTERSECT ALL" 

4563 

4564 

4565class CompoundSelect( 

4566 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4567): 

4568 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4569 SELECT-based set operations. 

4570 

4571 

4572 .. seealso:: 

4573 

4574 :func:`_expression.union` 

4575 

4576 :func:`_expression.union_all` 

4577 

4578 :func:`_expression.intersect` 

4579 

4580 :func:`_expression.intersect_all` 

4581 

4582 :func:`_expression.except` 

4583 

4584 :func:`_expression.except_all` 

4585 

4586 """ 

4587 

4588 __visit_name__ = "compound_select" 

4589 

4590 _traverse_internals: _TraverseInternalsType = ( 

4591 [ 

4592 ("selects", InternalTraversal.dp_clauseelement_list), 

4593 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4594 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4595 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4596 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4597 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4598 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4599 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4600 ("keyword", InternalTraversal.dp_string), 

4601 ] 

4602 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4603 + HasCTE._has_ctes_traverse_internals 

4604 + DialectKWArgs._dialect_kwargs_traverse_internals 

4605 + ExecutableStatement._executable_traverse_internals 

4606 ) 

4607 

4608 selects: List[SelectBase] 

4609 

4610 _is_from_container = True 

4611 _auto_correlate = False 

4612 

4613 def __init__( 

4614 self, 

4615 keyword: _CompoundSelectKeyword, 

4616 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4617 ): 

4618 self.keyword = keyword 

4619 self.selects = [ 

4620 coercions.expect( 

4621 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4622 ).self_group(against=self) 

4623 for s in selects 

4624 ] 

4625 

4626 GenerativeSelect.__init__(self) 

4627 

4628 @classmethod 

4629 def _create_union( 

4630 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4631 ) -> CompoundSelect[Unpack[_Ts]]: 

4632 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4633 

4634 @classmethod 

4635 def _create_union_all( 

4636 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4637 ) -> CompoundSelect[Unpack[_Ts]]: 

4638 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4639 

4640 @classmethod 

4641 def _create_except( 

4642 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4643 ) -> CompoundSelect[Unpack[_Ts]]: 

4644 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4645 

4646 @classmethod 

4647 def _create_except_all( 

4648 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4649 ) -> CompoundSelect[Unpack[_Ts]]: 

4650 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4651 

4652 @classmethod 

4653 def _create_intersect( 

4654 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4655 ) -> CompoundSelect[Unpack[_Ts]]: 

4656 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4657 

4658 @classmethod 

4659 def _create_intersect_all( 

4660 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4661 ) -> CompoundSelect[Unpack[_Ts]]: 

4662 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4663 

4664 def _scalar_type(self) -> TypeEngine[Any]: 

4665 return self.selects[0]._scalar_type() 

4666 

4667 def self_group( 

4668 self, against: Optional[OperatorType] = None 

4669 ) -> GroupedElement: 

4670 return SelectStatementGrouping(self) 

4671 

4672 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

4673 for s in self.selects: 

4674 if s.is_derived_from(fromclause): 

4675 return True 

4676 return False 

4677 

4678 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4679 if self._label_style is not style: 

4680 self = self._generate() 

4681 select_0 = self.selects[0].set_label_style(style) 

4682 self.selects = [select_0] + self.selects[1:] 

4683 

4684 return self 

4685 

4686 def _ensure_disambiguated_names(self) -> Self: 

4687 new_select = self.selects[0]._ensure_disambiguated_names() 

4688 if new_select is not self.selects[0]: 

4689 self = self._generate() 

4690 self.selects = [new_select] + self.selects[1:] 

4691 

4692 return self 

4693 

4694 def _generate_fromclause_column_proxies( 

4695 self, 

4696 subquery: FromClause, 

4697 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

4698 primary_key: ColumnSet, 

4699 foreign_keys: Set[KeyedColumnElement[Any]], 

4700 *, 

4701 proxy_compound_columns: Optional[ 

4702 Iterable[Sequence[ColumnElement[Any]]] 

4703 ] = None, 

4704 ) -> None: 

4705 # this is a slightly hacky thing - the union exports a 

4706 # column that resembles just that of the *first* selectable. 

4707 # to get at a "composite" column, particularly foreign keys, 

4708 # you have to dig through the proxies collection which we 

4709 # generate below. 

4710 select_0 = self.selects[0] 

4711 

4712 if self._label_style is not LABEL_STYLE_DEFAULT: 

4713 select_0 = select_0.set_label_style(self._label_style) 

4714 

4715 # hand-construct the "_proxies" collection to include all 

4716 # derived columns place a 'weight' annotation corresponding 

4717 # to how low in the list of select()s the column occurs, so 

4718 # that the corresponding_column() operation can resolve 

4719 # conflicts 

4720 extra_col_iterator = zip( 

4721 *[ 

4722 [ 

4723 c._annotate(dd) 

4724 for c in stmt._all_selected_columns 

4725 if is_column_element(c) 

4726 ] 

4727 for dd, stmt in [ 

4728 ({"weight": i + 1}, stmt) 

4729 for i, stmt in enumerate(self.selects) 

4730 ] 

4731 ] 

4732 ) 

4733 

4734 # the incoming proxy_compound_columns can be present also if this is 

4735 # a compound embedded in a compound. it's probably more appropriate 

4736 # that we generate new weights local to this nested compound, though 

4737 # i haven't tried to think what it means for compound nested in 

4738 # compound 

4739 select_0._generate_fromclause_column_proxies( 

4740 subquery, 

4741 columns, 

4742 proxy_compound_columns=extra_col_iterator, 

4743 primary_key=primary_key, 

4744 foreign_keys=foreign_keys, 

4745 ) 

4746 

4747 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

4748 super()._refresh_for_new_column(column) 

4749 for select in self.selects: 

4750 select._refresh_for_new_column(column) 

4751 

4752 @util.ro_non_memoized_property 

4753 def _all_selected_columns(self) -> _SelectIterable: 

4754 return self.selects[0]._all_selected_columns 

4755 

4756 @util.ro_non_memoized_property 

4757 def selected_columns( 

4758 self, 

4759 ) -> ColumnCollection[str, ColumnElement[Any]]: 

4760 """A :class:`_expression.ColumnCollection` 

4761 representing the columns that 

4762 this SELECT statement or similar construct returns in its result set, 

4763 not including :class:`_sql.TextClause` constructs. 

4764 

4765 For a :class:`_expression.CompoundSelect`, the 

4766 :attr:`_expression.CompoundSelect.selected_columns` 

4767 attribute returns the selected 

4768 columns of the first SELECT statement contained within the series of 

4769 statements within the set operation. 

4770 

4771 .. seealso:: 

4772 

4773 :attr:`_sql.Select.selected_columns` 

4774 

4775 .. versionadded:: 1.4 

4776 

4777 """ 

4778 return self.selects[0].selected_columns 

4779 

4780 

4781# backwards compat 

4782for elem in _CompoundSelectKeyword: 

4783 setattr(CompoundSelect, elem.name, elem) 

4784 

4785 

4786@CompileState.plugin_for("default", "select") 

4787class SelectState(util.MemoizedSlots, CompileState): 

4788 __slots__ = ( 

4789 "from_clauses", 

4790 "froms", 

4791 "columns_plus_names", 

4792 "_label_resolve_dict", 

4793 ) 

4794 

4795 if TYPE_CHECKING: 

4796 default_select_compile_options: CacheableOptions 

4797 else: 

4798 

4799 class default_select_compile_options(CacheableOptions): 

4800 _cache_key_traversal = [] 

4801 

4802 if TYPE_CHECKING: 

4803 

4804 @classmethod 

4805 def get_plugin_class( 

4806 cls, statement: Executable 

4807 ) -> Type[SelectState]: ... 

4808 

4809 def __init__( 

4810 self, 

4811 statement: Select[Unpack[TupleAny]], 

4812 compiler: SQLCompiler, 

4813 **kw: Any, 

4814 ): 

4815 self.statement = statement 

4816 self.from_clauses = statement._from_obj 

4817 

4818 for memoized_entities in statement._memoized_select_entities: 

4819 self._setup_joins( 

4820 memoized_entities._setup_joins, memoized_entities._raw_columns 

4821 ) 

4822 

4823 if statement._setup_joins: 

4824 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4825 

4826 self.froms = self._get_froms(statement) 

4827 

4828 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4829 

4830 @classmethod 

4831 def _plugin_not_implemented(cls) -> NoReturn: 

4832 raise NotImplementedError( 

4833 "The default SELECT construct without plugins does not " 

4834 "implement this method." 

4835 ) 

4836 

4837 @classmethod 

4838 def get_column_descriptions( 

4839 cls, statement: Select[Unpack[TupleAny]] 

4840 ) -> List[Dict[str, Any]]: 

4841 return [ 

4842 { 

4843 "name": name, 

4844 "type": element.type, 

4845 "expr": element, 

4846 } 

4847 for _, name, _, element, _ in ( 

4848 statement._generate_columns_plus_names(False) 

4849 ) 

4850 ] 

4851 

4852 @classmethod 

4853 def from_statement( 

4854 cls, 

4855 statement: Select[Unpack[TupleAny]], 

4856 from_statement: roles.ReturnsRowsRole, 

4857 ) -> ExecutableReturnsRows: 

4858 cls._plugin_not_implemented() 

4859 

4860 @classmethod 

4861 def get_columns_clause_froms( 

4862 cls, statement: Select[Unpack[TupleAny]] 

4863 ) -> List[FromClause]: 

4864 return cls._normalize_froms( 

4865 itertools.chain.from_iterable( 

4866 element._from_objects for element in statement._raw_columns 

4867 ) 

4868 ) 

4869 

4870 @classmethod 

4871 def _column_naming_convention( 

4872 cls, label_style: SelectLabelStyle 

4873 ) -> _LabelConventionCallable: 

4874 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4875 

4876 dedupe = label_style is not LABEL_STYLE_NONE 

4877 

4878 pa = prefix_anon_map() 

4879 names = set() 

4880 

4881 def go( 

4882 c: Union[ColumnElement[Any], TextClause], 

4883 col_name: Optional[str] = None, 

4884 ) -> Optional[str]: 

4885 if is_text_clause(c): 

4886 return None 

4887 elif TYPE_CHECKING: 

4888 assert is_column_element(c) 

4889 

4890 if not dedupe: 

4891 name = c._proxy_key 

4892 if name is None: 

4893 name = "_no_label" 

4894 return name 

4895 

4896 name = c._tq_key_label if table_qualified else c._proxy_key 

4897 

4898 if name is None: 

4899 name = "_no_label" 

4900 if name in names: 

4901 return c._anon_label(name) % pa 

4902 else: 

4903 names.add(name) 

4904 return name 

4905 

4906 elif name in names: 

4907 return ( 

4908 c._anon_tq_key_label % pa 

4909 if table_qualified 

4910 else c._anon_key_label % pa 

4911 ) 

4912 else: 

4913 names.add(name) 

4914 return name 

4915 

4916 return go 

4917 

4918 def _get_froms( 

4919 self, statement: Select[Unpack[TupleAny]] 

4920 ) -> List[FromClause]: 

4921 ambiguous_table_name_map: _AmbiguousTableNameMap 

4922 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4923 

4924 return self._normalize_froms( 

4925 itertools.chain( 

4926 self.from_clauses, 

4927 itertools.chain.from_iterable( 

4928 [ 

4929 element._from_objects 

4930 for element in statement._raw_columns 

4931 ] 

4932 ), 

4933 itertools.chain.from_iterable( 

4934 [ 

4935 element._from_objects 

4936 for element in statement._where_criteria 

4937 ] 

4938 ), 

4939 ), 

4940 check_statement=statement, 

4941 ambiguous_table_name_map=ambiguous_table_name_map, 

4942 ) 

4943 

4944 @classmethod 

4945 def _normalize_froms( 

4946 cls, 

4947 iterable_of_froms: Iterable[FromClause], 

4948 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4949 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4950 ) -> List[FromClause]: 

4951 """given an iterable of things to select FROM, reduce them to what 

4952 would actually render in the FROM clause of a SELECT. 

4953 

4954 This does the job of checking for JOINs, tables, etc. that are in fact 

4955 overlapping due to cloning, adaption, present in overlapping joins, 

4956 etc. 

4957 

4958 """ 

4959 seen: Set[FromClause] = set() 

4960 froms: List[FromClause] = [] 

4961 

4962 for item in iterable_of_froms: 

4963 if is_subquery(item) and item.element is check_statement: 

4964 raise exc.InvalidRequestError( 

4965 "select() construct refers to itself as a FROM" 

4966 ) 

4967 

4968 if not seen.intersection(item._cloned_set): 

4969 froms.append(item) 

4970 seen.update(item._cloned_set) 

4971 

4972 if froms: 

4973 toremove = set( 

4974 itertools.chain.from_iterable( 

4975 [_expand_cloned(f._hide_froms) for f in froms] 

4976 ) 

4977 ) 

4978 if toremove: 

4979 # filter out to FROM clauses not in the list, 

4980 # using a list to maintain ordering 

4981 froms = [f for f in froms if f not in toremove] 

4982 

4983 if ambiguous_table_name_map is not None: 

4984 ambiguous_table_name_map.update( 

4985 ( 

4986 fr.name, 

4987 _anonymous_label.safe_construct( 

4988 hash(fr.name), fr.name 

4989 ), 

4990 ) 

4991 for item in froms 

4992 for fr in item._from_objects 

4993 if is_table(fr) 

4994 and fr.schema 

4995 and fr.name not in ambiguous_table_name_map 

4996 ) 

4997 

4998 return froms 

4999 

5000 def _get_display_froms( 

5001 self, 

5002 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

5003 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

5004 ) -> List[FromClause]: 

5005 """Return the full list of 'from' clauses to be displayed. 

5006 

5007 Takes into account a set of existing froms which may be 

5008 rendered in the FROM clause of enclosing selects; this Select 

5009 may want to leave those absent if it is automatically 

5010 correlating. 

5011 

5012 """ 

5013 

5014 froms = self.froms 

5015 

5016 if self.statement._correlate: 

5017 to_correlate = self.statement._correlate 

5018 if to_correlate: 

5019 froms = [ 

5020 f 

5021 for f in froms 

5022 if f 

5023 not in _cloned_intersection( 

5024 _cloned_intersection( 

5025 froms, explicit_correlate_froms or () 

5026 ), 

5027 to_correlate, 

5028 ) 

5029 ] 

5030 

5031 if self.statement._correlate_except is not None: 

5032 froms = [ 

5033 f 

5034 for f in froms 

5035 if f 

5036 not in _cloned_difference( 

5037 _cloned_intersection( 

5038 froms, explicit_correlate_froms or () 

5039 ), 

5040 self.statement._correlate_except, 

5041 ) 

5042 ] 

5043 

5044 if ( 

5045 self.statement._auto_correlate 

5046 and implicit_correlate_froms 

5047 and len(froms) > 1 

5048 ): 

5049 froms = [ 

5050 f 

5051 for f in froms 

5052 if f 

5053 not in _cloned_intersection(froms, implicit_correlate_froms) 

5054 ] 

5055 

5056 if not len(froms): 

5057 raise exc.InvalidRequestError( 

5058 "Select statement '%r" 

5059 "' returned no FROM clauses " 

5060 "due to auto-correlation; " 

5061 "specify correlate(<tables>) " 

5062 "to control correlation " 

5063 "manually." % self.statement 

5064 ) 

5065 

5066 return froms 

5067 

5068 def _memoized_attr__label_resolve_dict( 

5069 self, 

5070 ) -> Tuple[ 

5071 Dict[str, ColumnElement[Any]], 

5072 Dict[str, ColumnElement[Any]], 

5073 Dict[str, ColumnElement[Any]], 

5074 ]: 

5075 with_cols: Dict[str, ColumnElement[Any]] = { 

5076 c._tq_label or c.key: c 

5077 for c in self.statement._all_selected_columns 

5078 if c._allow_label_resolve 

5079 } 

5080 only_froms: Dict[str, ColumnElement[Any]] = { 

5081 c.key: c # type: ignore 

5082 for c in _select_iterables(self.froms) 

5083 if c._allow_label_resolve 

5084 } 

5085 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

5086 for key, value in only_froms.items(): 

5087 with_cols.setdefault(key, value) 

5088 

5089 return with_cols, only_froms, only_cols 

5090 

5091 @classmethod 

5092 def determine_last_joined_entity( 

5093 cls, stmt: Select[Unpack[TupleAny]] 

5094 ) -> Optional[_JoinTargetElement]: 

5095 if stmt._setup_joins: 

5096 return stmt._setup_joins[-1][0] 

5097 else: 

5098 return None 

5099 

5100 @classmethod 

5101 def all_selected_columns( 

5102 cls, statement: Select[Unpack[TupleAny]] 

5103 ) -> _SelectIterable: 

5104 return [c for c in _select_iterables(statement._raw_columns)] 

5105 

5106 def _setup_joins( 

5107 self, 

5108 args: Tuple[_SetupJoinsElement, ...], 

5109 raw_columns: List[_ColumnsClauseElement], 

5110 ) -> None: 

5111 for right, onclause, left, flags in args: 

5112 if TYPE_CHECKING: 

5113 if onclause is not None: 

5114 assert isinstance(onclause, ColumnElement) 

5115 

5116 explicit_left = left 

5117 isouter = flags["isouter"] 

5118 full = flags["full"] 

5119 

5120 if left is None: 

5121 ( 

5122 left, 

5123 replace_from_obj_index, 

5124 ) = self._join_determine_implicit_left_side( 

5125 raw_columns, left, right, onclause 

5126 ) 

5127 else: 

5128 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5129 left 

5130 ) 

5131 

5132 # these assertions can be made here, as if the right/onclause 

5133 # contained ORM elements, the select() statement would have been 

5134 # upgraded to an ORM select, and this method would not be called; 

5135 # orm.context.ORMSelectCompileState._join() would be 

5136 # used instead. 

5137 if TYPE_CHECKING: 

5138 assert isinstance(right, FromClause) 

5139 if onclause is not None: 

5140 assert isinstance(onclause, ColumnElement) 

5141 

5142 if replace_from_obj_index is not None: 

5143 # splice into an existing element in the 

5144 # self._from_obj list 

5145 left_clause = self.from_clauses[replace_from_obj_index] 

5146 

5147 if explicit_left is not None and onclause is None: 

5148 onclause = Join._join_condition(explicit_left, right) 

5149 

5150 self.from_clauses = ( 

5151 self.from_clauses[:replace_from_obj_index] 

5152 + ( 

5153 Join( 

5154 left_clause, 

5155 right, 

5156 onclause, 

5157 isouter=isouter, 

5158 full=full, 

5159 ), 

5160 ) 

5161 + self.from_clauses[replace_from_obj_index + 1 :] 

5162 ) 

5163 else: 

5164 assert left is not None 

5165 self.from_clauses = self.from_clauses + ( 

5166 Join(left, right, onclause, isouter=isouter, full=full), 

5167 ) 

5168 

5169 @util.preload_module("sqlalchemy.sql.util") 

5170 def _join_determine_implicit_left_side( 

5171 self, 

5172 raw_columns: List[_ColumnsClauseElement], 

5173 left: Optional[FromClause], 

5174 right: _JoinTargetElement, 

5175 onclause: Optional[ColumnElement[Any]], 

5176 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5177 """When join conditions don't express the left side explicitly, 

5178 determine if an existing FROM or entity in this query 

5179 can serve as the left hand side. 

5180 

5181 """ 

5182 

5183 sql_util = util.preloaded.sql_util 

5184 

5185 replace_from_obj_index: Optional[int] = None 

5186 

5187 from_clauses = self.from_clauses 

5188 

5189 if from_clauses: 

5190 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5191 from_clauses, right, onclause 

5192 ) 

5193 

5194 if len(indexes) == 1: 

5195 replace_from_obj_index = indexes[0] 

5196 left = from_clauses[replace_from_obj_index] 

5197 else: 

5198 potential = {} 

5199 statement = self.statement 

5200 

5201 for from_clause in itertools.chain( 

5202 itertools.chain.from_iterable( 

5203 [element._from_objects for element in raw_columns] 

5204 ), 

5205 itertools.chain.from_iterable( 

5206 [ 

5207 element._from_objects 

5208 for element in statement._where_criteria 

5209 ] 

5210 ), 

5211 ): 

5212 potential[from_clause] = () 

5213 

5214 all_clauses = list(potential.keys()) 

5215 indexes = sql_util.find_left_clause_to_join_from( 

5216 all_clauses, right, onclause 

5217 ) 

5218 

5219 if len(indexes) == 1: 

5220 left = all_clauses[indexes[0]] 

5221 

5222 if len(indexes) > 1: 

5223 raise exc.InvalidRequestError( 

5224 "Can't determine which FROM clause to join " 

5225 "from, there are multiple FROMS which can " 

5226 "join to this entity. Please use the .select_from() " 

5227 "method to establish an explicit left side, as well as " 

5228 "providing an explicit ON clause if not present already to " 

5229 "help resolve the ambiguity." 

5230 ) 

5231 elif not indexes: 

5232 raise exc.InvalidRequestError( 

5233 "Don't know how to join to %r. " 

5234 "Please use the .select_from() " 

5235 "method to establish an explicit left side, as well as " 

5236 "providing an explicit ON clause if not present already to " 

5237 "help resolve the ambiguity." % (right,) 

5238 ) 

5239 return left, replace_from_obj_index 

5240 

5241 @util.preload_module("sqlalchemy.sql.util") 

5242 def _join_place_explicit_left_side( 

5243 self, left: FromClause 

5244 ) -> Optional[int]: 

5245 replace_from_obj_index: Optional[int] = None 

5246 

5247 sql_util = util.preloaded.sql_util 

5248 

5249 from_clauses = list(self.statement._iterate_from_elements()) 

5250 

5251 if from_clauses: 

5252 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5253 self.from_clauses, left 

5254 ) 

5255 else: 

5256 indexes = [] 

5257 

5258 if len(indexes) > 1: 

5259 raise exc.InvalidRequestError( 

5260 "Can't identify which entity in which to assign the " 

5261 "left side of this join. Please use a more specific " 

5262 "ON clause." 

5263 ) 

5264 

5265 # have an index, means the left side is already present in 

5266 # an existing FROM in the self._from_obj tuple 

5267 if indexes: 

5268 replace_from_obj_index = indexes[0] 

5269 

5270 # no index, means we need to add a new element to the 

5271 # self._from_obj tuple 

5272 

5273 return replace_from_obj_index 

5274 

5275 

5276class _SelectFromElements: 

5277 __slots__ = () 

5278 

5279 _raw_columns: List[_ColumnsClauseElement] 

5280 _where_criteria: Tuple[ColumnElement[Any], ...] 

5281 _from_obj: Tuple[FromClause, ...] 

5282 

5283 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5284 # note this does not include elements 

5285 # in _setup_joins 

5286 

5287 seen = set() 

5288 for element in self._raw_columns: 

5289 for fr in element._from_objects: 

5290 if fr in seen: 

5291 continue 

5292 seen.add(fr) 

5293 yield fr 

5294 for element in self._where_criteria: 

5295 for fr in element._from_objects: 

5296 if fr in seen: 

5297 continue 

5298 seen.add(fr) 

5299 yield fr 

5300 for element in self._from_obj: 

5301 if element in seen: 

5302 continue 

5303 seen.add(element) 

5304 yield element 

5305 

5306 

5307class _MemoizedSelectEntities( 

5308 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5309): 

5310 """represents partial state from a Select object, for the case 

5311 where Select.columns() has redefined the set of columns/entities the 

5312 statement will be SELECTing from. This object represents 

5313 the entities from the SELECT before that transformation was applied, 

5314 so that transformations that were made in terms of the SELECT at that 

5315 time, such as join() as well as options(), can access the correct context. 

5316 

5317 In previous SQLAlchemy versions, this wasn't needed because these 

5318 constructs calculated everything up front, like when you called join() 

5319 or options(), it did everything to figure out how that would translate 

5320 into specific SQL constructs that would be ready to send directly to the 

5321 SQL compiler when needed. But as of 

5322 1.4, all of that stuff is done in the compilation phase, during the 

5323 "compile state" portion of the process, so that the work can all be 

5324 cached. So it needs to be able to resolve joins/options2 based on what 

5325 the list of entities was when those methods were called. 

5326 

5327 

5328 """ 

5329 

5330 __visit_name__ = "memoized_select_entities" 

5331 

5332 _traverse_internals: _TraverseInternalsType = [ 

5333 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5334 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5335 ("_with_options", InternalTraversal.dp_executable_options), 

5336 ] 

5337 

5338 _is_clone_of: Optional[ClauseElement] 

5339 _raw_columns: List[_ColumnsClauseElement] 

5340 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5341 _with_options: Tuple[ExecutableOption, ...] 

5342 

5343 _annotations = util.EMPTY_DICT 

5344 

5345 def _clone(self, **kw: Any) -> Self: 

5346 c = self.__class__.__new__(self.__class__) 

5347 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5348 

5349 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5350 return c 

5351 

5352 @classmethod 

5353 def _generate_for_statement( 

5354 cls, select_stmt: Select[Unpack[TupleAny]] 

5355 ) -> None: 

5356 if select_stmt._setup_joins or select_stmt._with_options: 

5357 self = _MemoizedSelectEntities() 

5358 self._raw_columns = select_stmt._raw_columns 

5359 self._setup_joins = select_stmt._setup_joins 

5360 self._with_options = select_stmt._with_options 

5361 

5362 select_stmt._memoized_select_entities += (self,) 

5363 select_stmt._raw_columns = [] 

5364 select_stmt._setup_joins = select_stmt._with_options = () 

5365 

5366 

5367class Select( 

5368 HasPrefixes, 

5369 HasSuffixes, 

5370 HasHints, 

5371 HasCompileState, 

5372 HasSyntaxExtensions[ 

5373 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5374 ], 

5375 _SelectFromElements, 

5376 GenerativeSelect, 

5377 TypedReturnsRows[Unpack[_Ts]], 

5378): 

5379 """Represents a ``SELECT`` statement. 

5380 

5381 The :class:`_sql.Select` object is normally constructed using the 

5382 :func:`_sql.select` function. See that function for details. 

5383 

5384 Available extension points: 

5385 

5386 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5387 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5388 keyword (if any) and the list of columns. 

5389 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5390 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5391 

5392 .. seealso:: 

5393 

5394 :func:`_sql.select` 

5395 

5396 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5397 

5398 """ 

5399 

5400 __visit_name__ = "select" 

5401 

5402 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5403 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5404 

5405 _raw_columns: List[_ColumnsClauseElement] 

5406 

5407 _distinct: bool = False 

5408 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5409 _correlate: Tuple[FromClause, ...] = () 

5410 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5411 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5412 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5413 _from_obj: Tuple[FromClause, ...] = () 

5414 

5415 _position_map = util.immutabledict( 

5416 { 

5417 "post_select": "_post_select_clause", 

5418 "pre_columns": "_pre_columns_clause", 

5419 "post_criteria": "_post_criteria_clause", 

5420 "post_body": "_post_body_clause", 

5421 } 

5422 ) 

5423 

5424 _post_select_clause: Optional[ClauseElement] = None 

5425 """extension point for a ClauseElement that will be compiled directly 

5426 after the SELECT keyword. 

5427 

5428 .. versionadded:: 2.1 

5429 

5430 """ 

5431 

5432 _pre_columns_clause: Optional[ClauseElement] = None 

5433 """extension point for a ClauseElement that will be compiled directly 

5434 before the "columns" clause; after DISTINCT (if present). 

5435 

5436 .. versionadded:: 2.1 

5437 

5438 """ 

5439 

5440 _post_criteria_clause: Optional[ClauseElement] = None 

5441 """extension point for a ClauseElement that will be compiled directly 

5442 after "criteria", following the HAVING clause but before ORDER BY. 

5443 

5444 .. versionadded:: 2.1 

5445 

5446 """ 

5447 

5448 _post_body_clause: Optional[ClauseElement] = None 

5449 """extension point for a ClauseElement that will be compiled directly 

5450 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5451 of the SELECT. 

5452 

5453 .. versionadded:: 2.1 

5454 

5455 """ 

5456 

5457 _auto_correlate = True 

5458 _is_select_statement = True 

5459 _compile_options: CacheableOptions = ( 

5460 SelectState.default_select_compile_options 

5461 ) 

5462 

5463 _traverse_internals: _TraverseInternalsType = ( 

5464 [ 

5465 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5466 ( 

5467 "_memoized_select_entities", 

5468 InternalTraversal.dp_memoized_select_entities, 

5469 ), 

5470 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5471 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5472 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5473 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5474 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5475 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5476 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5477 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5478 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5479 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5480 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5481 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5482 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5483 ("_distinct", InternalTraversal.dp_boolean), 

5484 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5485 ("_label_style", InternalTraversal.dp_plain_obj), 

5486 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5487 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5488 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5489 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5490 ] 

5491 + HasCTE._has_ctes_traverse_internals 

5492 + HasPrefixes._has_prefixes_traverse_internals 

5493 + HasSuffixes._has_suffixes_traverse_internals 

5494 + HasHints._has_hints_traverse_internals 

5495 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5496 + ExecutableStatement._executable_traverse_internals 

5497 + DialectKWArgs._dialect_kwargs_traverse_internals 

5498 ) 

5499 

5500 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5501 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5502 ] 

5503 

5504 _compile_state_factory: Type[SelectState] 

5505 

5506 @classmethod 

5507 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5508 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5509 

5510 Used internally to build up :class:`.Select` constructs with 

5511 pre-established state. 

5512 

5513 """ 

5514 

5515 stmt = Select.__new__(Select) 

5516 stmt.__dict__.update(kw) 

5517 return stmt 

5518 

5519 def __init__( 

5520 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5521 ): 

5522 r"""Construct a new :class:`_expression.Select`. 

5523 

5524 The public constructor for :class:`_expression.Select` is the 

5525 :func:`_sql.select` function. 

5526 

5527 """ 

5528 self._raw_columns = [ 

5529 coercions.expect( 

5530 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5531 ) 

5532 for ent in entities 

5533 ] 

5534 GenerativeSelect.__init__(self) 

5535 

5536 def _apply_syntax_extension_to_self( 

5537 self, extension: SyntaxExtension 

5538 ) -> None: 

5539 extension.apply_to_select(self) 

5540 

5541 def _scalar_type(self) -> TypeEngine[Any]: 

5542 if not self._raw_columns: 

5543 return NULLTYPE 

5544 elem = self._raw_columns[0] 

5545 cols = list(elem._select_iterable) 

5546 return cols[0].type 

5547 

5548 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5549 """A synonym for the :meth:`_sql.Select.where` method.""" 

5550 

5551 return self.where(*criteria) 

5552 

5553 def _filter_by_zero( 

5554 self, 

5555 ) -> Union[ 

5556 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5557 ]: 

5558 if self._setup_joins: 

5559 meth = SelectState.get_plugin_class( 

5560 self 

5561 ).determine_last_joined_entity 

5562 _last_joined_entity = meth(self) 

5563 if _last_joined_entity is not None: 

5564 return _last_joined_entity 

5565 

5566 if self._from_obj: 

5567 return self._from_obj[0] 

5568 

5569 return self._raw_columns[0] 

5570 

5571 if TYPE_CHECKING: 

5572 

5573 @overload 

5574 def scalar_subquery( 

5575 self: Select[_MAYBE_ENTITY], 

5576 ) -> ScalarSelect[Any]: ... 

5577 

5578 @overload 

5579 def scalar_subquery( 

5580 self: Select[_NOT_ENTITY], 

5581 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5582 

5583 @overload 

5584 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5585 

5586 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5587 

5588 def filter_by(self, **kwargs: Any) -> Self: 

5589 r"""apply the given filtering criterion as a WHERE clause 

5590 to this select. 

5591 

5592 """ 

5593 from_entity = self._filter_by_zero() 

5594 

5595 clauses = [ 

5596 _entity_namespace_key(from_entity, key) == value 

5597 for key, value in kwargs.items() 

5598 ] 

5599 return self.filter(*clauses) 

5600 

5601 @property 

5602 def column_descriptions(self) -> Any: 

5603 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5604 referring to the columns which are SELECTed by this statement. 

5605 

5606 This attribute is generally useful when using the ORM, as an 

5607 extended structure which includes information about mapped 

5608 entities is returned. The section :ref:`queryguide_inspection` 

5609 contains more background. 

5610 

5611 For a Core-only statement, the structure returned by this accessor 

5612 is derived from the same objects that are returned by the 

5613 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5614 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5615 which indicate the column expressions to be selected:: 

5616 

5617 >>> stmt = select(user_table) 

5618 >>> stmt.column_descriptions 

5619 [ 

5620 { 

5621 'name': 'id', 

5622 'type': Integer(), 

5623 'expr': Column('id', Integer(), ...)}, 

5624 { 

5625 'name': 'name', 

5626 'type': String(length=30), 

5627 'expr': Column('name', String(length=30), ...)} 

5628 ] 

5629 

5630 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5631 attribute returns a structure for a Core-only set of entities, 

5632 not just ORM-only entities. 

5633 

5634 .. seealso:: 

5635 

5636 :attr:`.UpdateBase.entity_description` - entity information for 

5637 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5638 

5639 :ref:`queryguide_inspection` - ORM background 

5640 

5641 """ 

5642 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5643 return meth(self) 

5644 

5645 def from_statement( 

5646 self, statement: roles.ReturnsRowsRole 

5647 ) -> ExecutableReturnsRows: 

5648 """Apply the columns which this :class:`.Select` would select 

5649 onto another statement. 

5650 

5651 This operation is :term:`plugin-specific` and will raise a not 

5652 supported exception if this :class:`_sql.Select` does not select from 

5653 plugin-enabled entities. 

5654 

5655 

5656 The statement is typically either a :func:`_expression.text` or 

5657 :func:`_expression.select` construct, and should return the set of 

5658 columns appropriate to the entities represented by this 

5659 :class:`.Select`. 

5660 

5661 .. seealso:: 

5662 

5663 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5664 ORM Querying Guide 

5665 

5666 """ 

5667 meth = SelectState.get_plugin_class(self).from_statement 

5668 return meth(self, statement) 

5669 

5670 @_generative 

5671 def join( 

5672 self, 

5673 target: _JoinTargetArgument, 

5674 onclause: Optional[_OnClauseArgument] = None, 

5675 *, 

5676 isouter: bool = False, 

5677 full: bool = False, 

5678 ) -> Self: 

5679 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5680 object's criterion 

5681 and apply generatively, returning the newly resulting 

5682 :class:`_expression.Select`. 

5683 

5684 E.g.:: 

5685 

5686 stmt = select(user_table).join( 

5687 address_table, user_table.c.id == address_table.c.user_id 

5688 ) 

5689 

5690 The above statement generates SQL similar to: 

5691 

5692 .. sourcecode:: sql 

5693 

5694 SELECT user.id, user.name 

5695 FROM user 

5696 JOIN address ON user.id = address.user_id 

5697 

5698 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5699 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5700 source that is within the FROM clause of the existing SELECT, 

5701 and a given target :class:`_sql.FromClause`, and then adds 

5702 this :class:`_sql.Join` to the FROM clause of the newly generated 

5703 SELECT statement. This is completely reworked from the behavior 

5704 in 1.3, which would instead create a subquery of the entire 

5705 :class:`_expression.Select` and then join that subquery to the 

5706 target. 

5707 

5708 This is a **backwards incompatible change** as the previous behavior 

5709 was mostly useless, producing an unnamed subquery rejected by 

5710 most databases in any case. The new behavior is modeled after 

5711 that of the very successful :meth:`_orm.Query.join` method in the 

5712 ORM, in order to support the functionality of :class:`_orm.Query` 

5713 being available by using a :class:`_sql.Select` object with an 

5714 :class:`_orm.Session`. 

5715 

5716 See the notes for this change at :ref:`change_select_join`. 

5717 

5718 

5719 :param target: target table to join towards 

5720 

5721 :param onclause: ON clause of the join. If omitted, an ON clause 

5722 is generated automatically based on the :class:`_schema.ForeignKey` 

5723 linkages between the two tables, if one can be unambiguously 

5724 determined, otherwise an error is raised. 

5725 

5726 :param isouter: if True, generate LEFT OUTER join. Same as 

5727 :meth:`_expression.Select.outerjoin`. 

5728 

5729 :param full: if True, generate FULL OUTER join. 

5730 

5731 .. seealso:: 

5732 

5733 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5734 

5735 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5736 

5737 :meth:`_expression.Select.join_from` 

5738 

5739 :meth:`_expression.Select.outerjoin` 

5740 

5741 """ # noqa: E501 

5742 join_target = coercions.expect( 

5743 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5744 ) 

5745 if onclause is not None: 

5746 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5747 else: 

5748 onclause_element = None 

5749 

5750 self._setup_joins += ( 

5751 ( 

5752 join_target, 

5753 onclause_element, 

5754 None, 

5755 {"isouter": isouter, "full": full}, 

5756 ), 

5757 ) 

5758 return self 

5759 

5760 def outerjoin_from( 

5761 self, 

5762 from_: _FromClauseArgument, 

5763 target: _JoinTargetArgument, 

5764 onclause: Optional[_OnClauseArgument] = None, 

5765 *, 

5766 full: bool = False, 

5767 ) -> Self: 

5768 r"""Create a SQL LEFT OUTER JOIN against this 

5769 :class:`_expression.Select` object's criterion and apply generatively, 

5770 returning the newly resulting :class:`_expression.Select`. 

5771 

5772 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5773 

5774 """ 

5775 return self.join_from( 

5776 from_, target, onclause=onclause, isouter=True, full=full 

5777 ) 

5778 

5779 @_generative 

5780 def join_from( 

5781 self, 

5782 from_: _FromClauseArgument, 

5783 target: _JoinTargetArgument, 

5784 onclause: Optional[_OnClauseArgument] = None, 

5785 *, 

5786 isouter: bool = False, 

5787 full: bool = False, 

5788 ) -> Self: 

5789 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5790 object's criterion 

5791 and apply generatively, returning the newly resulting 

5792 :class:`_expression.Select`. 

5793 

5794 E.g.:: 

5795 

5796 stmt = select(user_table, address_table).join_from( 

5797 user_table, address_table, user_table.c.id == address_table.c.user_id 

5798 ) 

5799 

5800 The above statement generates SQL similar to: 

5801 

5802 .. sourcecode:: sql 

5803 

5804 SELECT user.id, user.name, address.id, address.email, address.user_id 

5805 FROM user JOIN address ON user.id = address.user_id 

5806 

5807 .. versionadded:: 1.4 

5808 

5809 :param from\_: the left side of the join, will be rendered in the 

5810 FROM clause and is roughly equivalent to using the 

5811 :meth:`.Select.select_from` method. 

5812 

5813 :param target: target table to join towards 

5814 

5815 :param onclause: ON clause of the join. 

5816 

5817 :param isouter: if True, generate LEFT OUTER join. Same as 

5818 :meth:`_expression.Select.outerjoin`. 

5819 

5820 :param full: if True, generate FULL OUTER join. 

5821 

5822 .. seealso:: 

5823 

5824 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5825 

5826 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5827 

5828 :meth:`_expression.Select.join` 

5829 

5830 """ # noqa: E501 

5831 

5832 # note the order of parsing from vs. target is important here, as we 

5833 # are also deriving the source of the plugin (i.e. the subject mapper 

5834 # in an ORM query) which should favor the "from_" over the "target" 

5835 

5836 from_ = coercions.expect( 

5837 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5838 ) 

5839 join_target = coercions.expect( 

5840 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5841 ) 

5842 if onclause is not None: 

5843 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5844 else: 

5845 onclause_element = None 

5846 

5847 self._setup_joins += ( 

5848 ( 

5849 join_target, 

5850 onclause_element, 

5851 from_, 

5852 {"isouter": isouter, "full": full}, 

5853 ), 

5854 ) 

5855 return self 

5856 

5857 def outerjoin( 

5858 self, 

5859 target: _JoinTargetArgument, 

5860 onclause: Optional[_OnClauseArgument] = None, 

5861 *, 

5862 full: bool = False, 

5863 ) -> Self: 

5864 """Create a left outer join. 

5865 

5866 Parameters are the same as that of :meth:`_expression.Select.join`. 

5867 

5868 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5869 creates a :class:`_sql.Join` object between a 

5870 :class:`_sql.FromClause` source that is within the FROM clause of 

5871 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5872 and then adds this :class:`_sql.Join` to the FROM clause of the 

5873 newly generated SELECT statement. This is completely reworked 

5874 from the behavior in 1.3, which would instead create a subquery of 

5875 the entire 

5876 :class:`_expression.Select` and then join that subquery to the 

5877 target. 

5878 

5879 This is a **backwards incompatible change** as the previous behavior 

5880 was mostly useless, producing an unnamed subquery rejected by 

5881 most databases in any case. The new behavior is modeled after 

5882 that of the very successful :meth:`_orm.Query.join` method in the 

5883 ORM, in order to support the functionality of :class:`_orm.Query` 

5884 being available by using a :class:`_sql.Select` object with an 

5885 :class:`_orm.Session`. 

5886 

5887 See the notes for this change at :ref:`change_select_join`. 

5888 

5889 .. seealso:: 

5890 

5891 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5892 

5893 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5894 

5895 :meth:`_expression.Select.join` 

5896 

5897 """ 

5898 return self.join(target, onclause=onclause, isouter=True, full=full) 

5899 

5900 def get_final_froms(self) -> Sequence[FromClause]: 

5901 """Compute the final displayed list of :class:`_expression.FromClause` 

5902 elements. 

5903 

5904 This method will run through the full computation required to 

5905 determine what FROM elements will be displayed in the resulting 

5906 SELECT statement, including shadowing individual tables with 

5907 JOIN objects, as well as full computation for ORM use cases including 

5908 eager loading clauses. 

5909 

5910 For ORM use, this accessor returns the **post compilation** 

5911 list of FROM objects; this collection will include elements such as 

5912 eagerly loaded tables and joins. The objects will **not** be 

5913 ORM enabled and not work as a replacement for the 

5914 :meth:`_sql.Select.select_froms` collection; additionally, the 

5915 method is not well performing for an ORM enabled statement as it 

5916 will incur the full ORM construction process. 

5917 

5918 To retrieve the FROM list that's implied by the "columns" collection 

5919 passed to the :class:`_sql.Select` originally, use the 

5920 :attr:`_sql.Select.columns_clause_froms` accessor. 

5921 

5922 To select from an alternative set of columns while maintaining the 

5923 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5924 pass the 

5925 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5926 parameter. 

5927 

5928 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5929 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5930 which is deprecated. 

5931 

5932 .. seealso:: 

5933 

5934 :attr:`_sql.Select.columns_clause_froms` 

5935 

5936 """ 

5937 compiler = self._default_compiler() 

5938 

5939 return self._compile_state_factory(self, compiler)._get_display_froms() 

5940 

5941 @property 

5942 @util.deprecated( 

5943 "1.4.23", 

5944 "The :attr:`_expression.Select.froms` attribute is moved to " 

5945 "the :meth:`_expression.Select.get_final_froms` method.", 

5946 ) 

5947 def froms(self) -> Sequence[FromClause]: 

5948 """Return the displayed list of :class:`_expression.FromClause` 

5949 elements. 

5950 

5951 

5952 """ 

5953 return self.get_final_froms() 

5954 

5955 @property 

5956 def columns_clause_froms(self) -> List[FromClause]: 

5957 """Return the set of :class:`_expression.FromClause` objects implied 

5958 by the columns clause of this SELECT statement. 

5959 

5960 .. versionadded:: 1.4.23 

5961 

5962 .. seealso:: 

5963 

5964 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5965 statement into account 

5966 

5967 :meth:`_sql.Select.with_only_columns` - makes use of this 

5968 collection to set up a new FROM list 

5969 

5970 """ 

5971 

5972 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5973 self 

5974 ) 

5975 

5976 @property 

5977 def inner_columns(self) -> _SelectIterable: 

5978 """An iterator of all :class:`_expression.ColumnElement` 

5979 expressions which would 

5980 be rendered into the columns clause of the resulting SELECT statement. 

5981 

5982 This method is legacy as of 1.4 and is superseded by the 

5983 :attr:`_expression.Select.exported_columns` collection. 

5984 

5985 """ 

5986 

5987 return iter(self._all_selected_columns) 

5988 

5989 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5990 if fromclause is not None and self in fromclause._cloned_set: 

5991 return True 

5992 

5993 for f in self._iterate_from_elements(): 

5994 if f.is_derived_from(fromclause): 

5995 return True 

5996 return False 

5997 

5998 def _copy_internals( 

5999 self, clone: _CloneCallableType = _clone, **kw: Any 

6000 ) -> None: 

6001 # Select() object has been cloned and probably adapted by the 

6002 # given clone function. Apply the cloning function to internal 

6003 # objects 

6004 

6005 # 1. keep a dictionary of the froms we've cloned, and what 

6006 # they've become. This allows us to ensure the same cloned from 

6007 # is used when other items such as columns are "cloned" 

6008 

6009 all_the_froms = set( 

6010 itertools.chain( 

6011 _from_objects(*self._raw_columns), 

6012 _from_objects(*self._where_criteria), 

6013 _from_objects(*[elem[0] for elem in self._setup_joins]), 

6014 ) 

6015 ) 

6016 

6017 # do a clone for the froms we've gathered. what is important here 

6018 # is if any of the things we are selecting from, like tables, 

6019 # were converted into Join objects. if so, these need to be 

6020 # added to _from_obj explicitly, because otherwise they won't be 

6021 # part of the new state, as they don't associate themselves with 

6022 # their columns. 

6023 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

6024 

6025 # 2. copy FROM collections, adding in joins that we've created. 

6026 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

6027 add_froms = ( 

6028 {f for f in new_froms.values() if isinstance(f, Join)} 

6029 .difference(all_the_froms) 

6030 .difference(existing_from_obj) 

6031 ) 

6032 

6033 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

6034 

6035 # 3. clone everything else, making sure we use columns 

6036 # corresponding to the froms we just made. 

6037 def replace( 

6038 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

6039 **kw: Any, 

6040 ) -> Optional[KeyedColumnElement[Any]]: 

6041 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

6042 newelem = new_froms[obj.table].corresponding_column(obj) 

6043 return newelem 

6044 return None 

6045 

6046 kw["replace"] = replace 

6047 

6048 # copy everything else. for table-ish things like correlate, 

6049 # correlate_except, setup_joins, these clone normally. For 

6050 # column-expression oriented things like raw_columns, where_criteria, 

6051 # order by, we get this from the new froms. 

6052 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

6053 

6054 self._reset_memoizations() 

6055 

6056 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

6057 return itertools.chain( 

6058 super().get_children( 

6059 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

6060 **kw, 

6061 ), 

6062 self._iterate_from_elements(), 

6063 ) 

6064 

6065 @_generative 

6066 def add_columns( 

6067 self, *entities: _ColumnsClauseArgument[Any] 

6068 ) -> Select[Unpack[TupleAny]]: 

6069 r"""Return a new :func:`_expression.select` construct with 

6070 the given entities appended to its columns clause. 

6071 

6072 E.g.:: 

6073 

6074 my_select = my_select.add_columns(table.c.new_column) 

6075 

6076 The original expressions in the columns clause remain in place. 

6077 To replace the original expressions with new ones, see the method 

6078 :meth:`_expression.Select.with_only_columns`. 

6079 

6080 :param \*entities: column, table, or other entity expressions to be 

6081 added to the columns clause 

6082 

6083 .. seealso:: 

6084 

6085 :meth:`_expression.Select.with_only_columns` - replaces existing 

6086 expressions rather than appending. 

6087 

6088 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

6089 example 

6090 

6091 """ 

6092 self._reset_memoizations() 

6093 

6094 self._raw_columns = self._raw_columns + [ 

6095 coercions.expect( 

6096 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

6097 ) 

6098 for column in entities 

6099 ] 

6100 return self 

6101 

6102 def _set_entities( 

6103 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

6104 ) -> None: 

6105 self._raw_columns = [ 

6106 coercions.expect( 

6107 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6108 ) 

6109 for ent in util.to_list(entities) 

6110 ] 

6111 

6112 @util.deprecated( 

6113 "1.4", 

6114 "The :meth:`_expression.Select.column` method is deprecated and will " 

6115 "be removed in a future release. Please use " 

6116 ":meth:`_expression.Select.add_columns`", 

6117 ) 

6118 def column( 

6119 self, column: _ColumnsClauseArgument[Any] 

6120 ) -> Select[Unpack[TupleAny]]: 

6121 """Return a new :func:`_expression.select` construct with 

6122 the given column expression added to its columns clause. 

6123 

6124 E.g.:: 

6125 

6126 my_select = my_select.column(table.c.new_column) 

6127 

6128 See the documentation for 

6129 :meth:`_expression.Select.with_only_columns` 

6130 for guidelines on adding /replacing the columns of a 

6131 :class:`_expression.Select` object. 

6132 

6133 """ 

6134 return self.add_columns(column) 

6135 

6136 @util.preload_module("sqlalchemy.sql.util") 

6137 def reduce_columns( 

6138 self, only_synonyms: bool = True 

6139 ) -> Select[Unpack[TupleAny]]: 

6140 """Return a new :func:`_expression.select` construct with redundantly 

6141 named, equivalently-valued columns removed from the columns clause. 

6142 

6143 "Redundant" here means two columns where one refers to the 

6144 other either based on foreign key, or via a simple equality 

6145 comparison in the WHERE clause of the statement. The primary purpose 

6146 of this method is to automatically construct a select statement 

6147 with all uniquely-named columns, without the need to use 

6148 table-qualified labels as 

6149 :meth:`_expression.Select.set_label_style` 

6150 does. 

6151 

6152 When columns are omitted based on foreign key, the referred-to 

6153 column is the one that's kept. When columns are omitted based on 

6154 WHERE equivalence, the first column in the columns clause is the 

6155 one that's kept. 

6156 

6157 :param only_synonyms: when True, limit the removal of columns 

6158 to those which have the same name as the equivalent. Otherwise, 

6159 all columns that are equivalent to another are removed. 

6160 

6161 """ 

6162 woc: Select[Unpack[TupleAny]] 

6163 woc = self.with_only_columns( 

6164 *util.preloaded.sql_util.reduce_columns( 

6165 self._all_selected_columns, 

6166 only_synonyms=only_synonyms, 

6167 *(self._where_criteria + self._from_obj), 

6168 ) 

6169 ) 

6170 return woc 

6171 

6172 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6173 

6174 # code within this block is **programmatically, 

6175 # statically generated** by tools/generate_tuple_map_overloads.py 

6176 

6177 @overload 

6178 def with_only_columns( 

6179 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6180 ) -> Select[_T0]: ... 

6181 

6182 @overload 

6183 def with_only_columns( 

6184 self, 

6185 __ent0: _TCCA[_T0], 

6186 __ent1: _TCCA[_T1], 

6187 /, 

6188 *, 

6189 maintain_column_froms: bool = ..., 

6190 ) -> Select[_T0, _T1]: ... 

6191 

6192 @overload 

6193 def with_only_columns( 

6194 self, 

6195 __ent0: _TCCA[_T0], 

6196 __ent1: _TCCA[_T1], 

6197 __ent2: _TCCA[_T2], 

6198 /, 

6199 *, 

6200 maintain_column_froms: bool = ..., 

6201 ) -> Select[_T0, _T1, _T2]: ... 

6202 

6203 @overload 

6204 def with_only_columns( 

6205 self, 

6206 __ent0: _TCCA[_T0], 

6207 __ent1: _TCCA[_T1], 

6208 __ent2: _TCCA[_T2], 

6209 __ent3: _TCCA[_T3], 

6210 /, 

6211 *, 

6212 maintain_column_froms: bool = ..., 

6213 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6214 

6215 @overload 

6216 def with_only_columns( 

6217 self, 

6218 __ent0: _TCCA[_T0], 

6219 __ent1: _TCCA[_T1], 

6220 __ent2: _TCCA[_T2], 

6221 __ent3: _TCCA[_T3], 

6222 __ent4: _TCCA[_T4], 

6223 /, 

6224 *, 

6225 maintain_column_froms: bool = ..., 

6226 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6227 

6228 @overload 

6229 def with_only_columns( 

6230 self, 

6231 __ent0: _TCCA[_T0], 

6232 __ent1: _TCCA[_T1], 

6233 __ent2: _TCCA[_T2], 

6234 __ent3: _TCCA[_T3], 

6235 __ent4: _TCCA[_T4], 

6236 __ent5: _TCCA[_T5], 

6237 /, 

6238 *, 

6239 maintain_column_froms: bool = ..., 

6240 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6241 

6242 @overload 

6243 def with_only_columns( 

6244 self, 

6245 __ent0: _TCCA[_T0], 

6246 __ent1: _TCCA[_T1], 

6247 __ent2: _TCCA[_T2], 

6248 __ent3: _TCCA[_T3], 

6249 __ent4: _TCCA[_T4], 

6250 __ent5: _TCCA[_T5], 

6251 __ent6: _TCCA[_T6], 

6252 /, 

6253 *, 

6254 maintain_column_froms: bool = ..., 

6255 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6256 

6257 @overload 

6258 def with_only_columns( 

6259 self, 

6260 __ent0: _TCCA[_T0], 

6261 __ent1: _TCCA[_T1], 

6262 __ent2: _TCCA[_T2], 

6263 __ent3: _TCCA[_T3], 

6264 __ent4: _TCCA[_T4], 

6265 __ent5: _TCCA[_T5], 

6266 __ent6: _TCCA[_T6], 

6267 __ent7: _TCCA[_T7], 

6268 /, 

6269 *entities: _ColumnsClauseArgument[Any], 

6270 maintain_column_froms: bool = ..., 

6271 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6272 

6273 # END OVERLOADED FUNCTIONS self.with_only_columns 

6274 

6275 @overload 

6276 def with_only_columns( 

6277 self, 

6278 *entities: _ColumnsClauseArgument[Any], 

6279 maintain_column_froms: bool = False, 

6280 **__kw: Any, 

6281 ) -> Select[Unpack[TupleAny]]: ... 

6282 

6283 @_generative 

6284 def with_only_columns( 

6285 self, 

6286 *entities: _ColumnsClauseArgument[Any], 

6287 maintain_column_froms: bool = False, 

6288 **__kw: Any, 

6289 ) -> Select[Unpack[TupleAny]]: 

6290 r"""Return a new :func:`_expression.select` construct with its columns 

6291 clause replaced with the given entities. 

6292 

6293 By default, this method is exactly equivalent to as if the original 

6294 :func:`_expression.select` had been called with the given entities. 

6295 E.g. a statement:: 

6296 

6297 s = select(table1.c.a, table1.c.b) 

6298 s = s.with_only_columns(table1.c.b) 

6299 

6300 should be exactly equivalent to:: 

6301 

6302 s = select(table1.c.b) 

6303 

6304 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6305 will also dynamically alter the FROM clause of the 

6306 statement if it is not explicitly stated. 

6307 To maintain the existing set of FROMs including those implied by the 

6308 current columns clause, add the 

6309 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6310 parameter:: 

6311 

6312 s = select(table1.c.a, table2.c.b) 

6313 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6314 

6315 The above parameter performs a transfer of the effective FROMs 

6316 in the columns collection to the :meth:`_sql.Select.select_from` 

6317 method, as though the following were invoked:: 

6318 

6319 s = select(table1.c.a, table2.c.b) 

6320 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6321 

6322 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6323 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6324 collection and performs an operation equivalent to the following:: 

6325 

6326 s = select(table1.c.a, table2.c.b) 

6327 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6328 

6329 :param \*entities: column expressions to be used. 

6330 

6331 :param maintain_column_froms: boolean parameter that will ensure the 

6332 FROM list implied from the current columns clause will be transferred 

6333 to the :meth:`_sql.Select.select_from` method first. 

6334 

6335 .. versionadded:: 1.4.23 

6336 

6337 """ # noqa: E501 

6338 

6339 if __kw: 

6340 raise _no_kw() 

6341 

6342 # memoizations should be cleared here as of 

6343 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6344 # is the case for now. 

6345 self._assert_no_memoizations() 

6346 

6347 if maintain_column_froms: 

6348 self.select_from.non_generative( # type: ignore 

6349 self, *self.columns_clause_froms 

6350 ) 

6351 

6352 # then memoize the FROMs etc. 

6353 _MemoizedSelectEntities._generate_for_statement(self) 

6354 

6355 self._raw_columns = [ 

6356 coercions.expect(roles.ColumnsClauseRole, c) 

6357 for c in coercions._expression_collection_was_a_list( 

6358 "entities", "Select.with_only_columns", entities 

6359 ) 

6360 ] 

6361 return self 

6362 

6363 @property 

6364 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6365 """Return the completed WHERE clause for this 

6366 :class:`_expression.Select` statement. 

6367 

6368 This assembles the current collection of WHERE criteria 

6369 into a single :class:`_expression.BooleanClauseList` construct. 

6370 

6371 

6372 .. versionadded:: 1.4 

6373 

6374 """ 

6375 

6376 return BooleanClauseList._construct_for_whereclause( 

6377 self._where_criteria 

6378 ) 

6379 

6380 _whereclause = whereclause 

6381 

6382 @_generative 

6383 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6384 """Return a new :func:`_expression.select` construct with 

6385 the given expression added to 

6386 its WHERE clause, joined to the existing clause via AND, if any. 

6387 

6388 """ 

6389 

6390 assert isinstance(self._where_criteria, tuple) 

6391 

6392 for criterion in whereclause: 

6393 where_criteria: ColumnElement[Any] = coercions.expect( 

6394 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6395 ) 

6396 self._where_criteria += (where_criteria,) 

6397 return self 

6398 

6399 @_generative 

6400 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6401 """Return a new :func:`_expression.select` construct with 

6402 the given expression added to 

6403 its HAVING clause, joined to the existing clause via AND, if any. 

6404 

6405 """ 

6406 

6407 for criterion in having: 

6408 having_criteria = coercions.expect( 

6409 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6410 ) 

6411 self._having_criteria += (having_criteria,) 

6412 return self 

6413 

6414 @_generative 

6415 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6416 r"""Return a new :func:`_expression.select` construct which 

6417 will apply DISTINCT to the SELECT statement overall. 

6418 

6419 E.g.:: 

6420 

6421 from sqlalchemy import select 

6422 

6423 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6424 

6425 The above would produce an statement resembling: 

6426 

6427 .. sourcecode:: sql 

6428 

6429 SELECT DISTINCT user.id, user.name FROM user 

6430 

6431 The method also historically accepted an ``*expr`` parameter which 

6432 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6433 This is now replaced using the :func:`_postgresql.distinct_on` 

6434 extension:: 

6435 

6436 from sqlalchemy import select 

6437 from sqlalchemy.dialects.postgresql import distinct_on 

6438 

6439 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6440 

6441 Using this parameter on other backends which don't support this 

6442 syntax will raise an error. 

6443 

6444 :param \*expr: optional column expressions. When present, 

6445 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6446 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6447 will be raised on other backends. 

6448 

6449 .. deprecated:: 2.1 Passing expressions to 

6450 :meth:`_sql.Select.distinct` is deprecated, use 

6451 :func:`_postgresql.distinct_on` instead. 

6452 

6453 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6454 and will raise :class:`_exc.CompileError` in a future version. 

6455 

6456 .. seealso:: 

6457 

6458 :func:`_postgresql.distinct_on` 

6459 

6460 :meth:`_sql.HasSyntaxExtensions.ext` 

6461 """ 

6462 self._distinct = True 

6463 if expr: 

6464 warn_deprecated( 

6465 "Passing expression to ``distinct`` to generate a " 

6466 "DISTINCT ON clause is deprecated. Use instead the " 

6467 "``postgresql.distinct_on`` function as an extension.", 

6468 "2.1", 

6469 ) 

6470 self._distinct_on = self._distinct_on + tuple( 

6471 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6472 for e in expr 

6473 ) 

6474 return self 

6475 

6476 @_generative 

6477 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6478 r"""Return a new :func:`_expression.select` construct with the 

6479 given FROM expression(s) 

6480 merged into its list of FROM objects. 

6481 

6482 E.g.:: 

6483 

6484 table1 = table("t1", column("a")) 

6485 table2 = table("t2", column("b")) 

6486 s = select(table1.c.a).select_from( 

6487 table1.join(table2, table1.c.a == table2.c.b) 

6488 ) 

6489 

6490 The "from" list is a unique set on the identity of each element, 

6491 so adding an already present :class:`_schema.Table` 

6492 or other selectable 

6493 will have no effect. Passing a :class:`_expression.Join` that refers 

6494 to an already present :class:`_schema.Table` 

6495 or other selectable will have 

6496 the effect of concealing the presence of that selectable as 

6497 an individual element in the rendered FROM list, instead 

6498 rendering it into a JOIN clause. 

6499 

6500 While the typical purpose of :meth:`_expression.Select.select_from` 

6501 is to 

6502 replace the default, derived FROM clause with a join, it can 

6503 also be called with individual table elements, multiple times 

6504 if desired, in the case that the FROM clause cannot be fully 

6505 derived from the columns clause:: 

6506 

6507 select(func.count("*")).select_from(table1) 

6508 

6509 """ 

6510 

6511 self._from_obj += tuple( 

6512 coercions.expect( 

6513 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6514 ) 

6515 for fromclause in froms 

6516 ) 

6517 return self 

6518 

6519 @_generative 

6520 def correlate( 

6521 self, 

6522 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6523 ) -> Self: 

6524 r"""Return a new :class:`_expression.Select` 

6525 which will correlate the given FROM 

6526 clauses to that of an enclosing :class:`_expression.Select`. 

6527 

6528 Calling this method turns off the :class:`_expression.Select` object's 

6529 default behavior of "auto-correlation". Normally, FROM elements 

6530 which appear in a :class:`_expression.Select` 

6531 that encloses this one via 

6532 its :term:`WHERE clause`, ORDER BY, HAVING or 

6533 :term:`columns clause` will be omitted from this 

6534 :class:`_expression.Select` 

6535 object's :term:`FROM clause`. 

6536 Setting an explicit correlation collection using the 

6537 :meth:`_expression.Select.correlate` 

6538 method provides a fixed list of FROM objects 

6539 that can potentially take place in this process. 

6540 

6541 When :meth:`_expression.Select.correlate` 

6542 is used to apply specific FROM clauses 

6543 for correlation, the FROM elements become candidates for 

6544 correlation regardless of how deeply nested this 

6545 :class:`_expression.Select` 

6546 object is, relative to an enclosing :class:`_expression.Select` 

6547 which refers to 

6548 the same FROM object. This is in contrast to the behavior of 

6549 "auto-correlation" which only correlates to an immediate enclosing 

6550 :class:`_expression.Select`. 

6551 Multi-level correlation ensures that the link 

6552 between enclosed and enclosing :class:`_expression.Select` 

6553 is always via 

6554 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6555 correlation to take place. 

6556 

6557 If ``None`` is passed, the :class:`_expression.Select` 

6558 object will correlate 

6559 none of its FROM entries, and all will render unconditionally 

6560 in the local FROM clause. 

6561 

6562 :param \*fromclauses: one or more :class:`.FromClause` or other 

6563 FROM-compatible construct such as an ORM mapped entity to become part 

6564 of the correlate collection; alternatively pass a single value 

6565 ``None`` to remove all existing correlations. 

6566 

6567 .. seealso:: 

6568 

6569 :meth:`_expression.Select.correlate_except` 

6570 

6571 :ref:`tutorial_scalar_subquery` 

6572 

6573 """ 

6574 

6575 # tests failing when we try to change how these 

6576 # arguments are passed 

6577 

6578 self._auto_correlate = False 

6579 if not fromclauses or fromclauses[0] in {None, False}: 

6580 if len(fromclauses) > 1: 

6581 raise exc.ArgumentError( 

6582 "additional FROM objects not accepted when " 

6583 "passing None/False to correlate()" 

6584 ) 

6585 self._correlate = () 

6586 else: 

6587 self._correlate = self._correlate + tuple( 

6588 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6589 ) 

6590 return self 

6591 

6592 @_generative 

6593 def correlate_except( 

6594 self, 

6595 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6596 ) -> Self: 

6597 r"""Return a new :class:`_expression.Select` 

6598 which will omit the given FROM 

6599 clauses from the auto-correlation process. 

6600 

6601 Calling :meth:`_expression.Select.correlate_except` turns off the 

6602 :class:`_expression.Select` object's default behavior of 

6603 "auto-correlation" for the given FROM elements. An element 

6604 specified here will unconditionally appear in the FROM list, while 

6605 all other FROM elements remain subject to normal auto-correlation 

6606 behaviors. 

6607 

6608 If ``None`` is passed, or no arguments are passed, 

6609 the :class:`_expression.Select` object will correlate all of its 

6610 FROM entries. 

6611 

6612 :param \*fromclauses: a list of one or more 

6613 :class:`_expression.FromClause` 

6614 constructs, or other compatible constructs (i.e. ORM-mapped 

6615 classes) to become part of the correlate-exception collection. 

6616 

6617 .. seealso:: 

6618 

6619 :meth:`_expression.Select.correlate` 

6620 

6621 :ref:`tutorial_scalar_subquery` 

6622 

6623 """ 

6624 

6625 self._auto_correlate = False 

6626 if not fromclauses or fromclauses[0] in {None, False}: 

6627 if len(fromclauses) > 1: 

6628 raise exc.ArgumentError( 

6629 "additional FROM objects not accepted when " 

6630 "passing None/False to correlate_except()" 

6631 ) 

6632 self._correlate_except = () 

6633 else: 

6634 self._correlate_except = (self._correlate_except or ()) + tuple( 

6635 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6636 ) 

6637 

6638 return self 

6639 

6640 @HasMemoized_ro_memoized_attribute 

6641 def selected_columns( 

6642 self, 

6643 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6644 """A :class:`_expression.ColumnCollection` 

6645 representing the columns that 

6646 this SELECT statement or similar construct returns in its result set, 

6647 not including :class:`_sql.TextClause` constructs. 

6648 

6649 This collection differs from the :attr:`_expression.FromClause.columns` 

6650 collection of a :class:`_expression.FromClause` in that the columns 

6651 within this collection cannot be directly nested inside another SELECT 

6652 statement; a subquery must be applied first which provides for the 

6653 necessary parenthesization required by SQL. 

6654 

6655 For a :func:`_expression.select` construct, the collection here is 

6656 exactly what would be rendered inside the "SELECT" statement, and the 

6657 :class:`_expression.ColumnElement` objects are directly present as they 

6658 were given, e.g.:: 

6659 

6660 col1 = column("q", Integer) 

6661 col2 = column("p", Integer) 

6662 stmt = select(col1, col2) 

6663 

6664 Above, ``stmt.selected_columns`` would be a collection that contains 

6665 the ``col1`` and ``col2`` objects directly. For a statement that is 

6666 against a :class:`_schema.Table` or other 

6667 :class:`_expression.FromClause`, the collection will use the 

6668 :class:`_expression.ColumnElement` objects that are in the 

6669 :attr:`_expression.FromClause.c` collection of the from element. 

6670 

6671 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6672 to allow the existing columns to be referenced when adding additional 

6673 criteria, e.g.:: 

6674 

6675 def filter_on_id(my_select, id): 

6676 return my_select.where(my_select.selected_columns["id"] == id) 

6677 

6678 

6679 stmt = select(MyModel) 

6680 

6681 # adds "WHERE id=:param" to the statement 

6682 stmt = filter_on_id(stmt, 42) 

6683 

6684 .. note:: 

6685 

6686 The :attr:`_sql.Select.selected_columns` collection does not 

6687 include expressions established in the columns clause using the 

6688 :func:`_sql.text` construct; these are silently omitted from the 

6689 collection. To use plain textual column expressions inside of a 

6690 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6691 construct. 

6692 

6693 

6694 .. versionadded:: 1.4 

6695 

6696 """ 

6697 

6698 # compare to SelectState._generate_columns_plus_names, which 

6699 # generates the actual names used in the SELECT string. that 

6700 # method is more complex because it also renders columns that are 

6701 # fully ambiguous, e.g. same column more than once. 

6702 conv = cast( 

6703 "Callable[[Any], str]", 

6704 SelectState._column_naming_convention(self._label_style), 

6705 ) 

6706 

6707 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6708 [ 

6709 (conv(c), c) 

6710 for c in self._all_selected_columns 

6711 if is_column_element(c) 

6712 ] 

6713 ) 

6714 return cc.as_readonly() 

6715 

6716 @HasMemoized_ro_memoized_attribute 

6717 def _all_selected_columns(self) -> _SelectIterable: 

6718 meth = SelectState.get_plugin_class(self).all_selected_columns 

6719 return list(meth(self)) 

6720 

6721 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6722 if self._label_style is LABEL_STYLE_NONE: 

6723 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6724 return self 

6725 

6726 def _generate_fromclause_column_proxies( 

6727 self, 

6728 subquery: FromClause, 

6729 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

6730 primary_key: ColumnSet, 

6731 foreign_keys: Set[KeyedColumnElement[Any]], 

6732 *, 

6733 proxy_compound_columns: Optional[ 

6734 Iterable[Sequence[ColumnElement[Any]]] 

6735 ] = None, 

6736 ) -> None: 

6737 """Generate column proxies to place in the exported ``.c`` 

6738 collection of a subquery.""" 

6739 

6740 if proxy_compound_columns: 

6741 extra_col_iterator = proxy_compound_columns 

6742 prox = [ 

6743 c._make_proxy( 

6744 subquery, 

6745 key=proxy_key, 

6746 name=required_label_name, 

6747 name_is_truncatable=True, 

6748 compound_select_cols=extra_cols, 

6749 primary_key=primary_key, 

6750 foreign_keys=foreign_keys, 

6751 ) 

6752 for ( 

6753 ( 

6754 required_label_name, 

6755 proxy_key, 

6756 fallback_label_name, 

6757 c, 

6758 repeated, 

6759 ), 

6760 extra_cols, 

6761 ) in ( 

6762 zip( 

6763 self._generate_columns_plus_names(False), 

6764 extra_col_iterator, 

6765 ) 

6766 ) 

6767 if is_column_element(c) 

6768 ] 

6769 else: 

6770 prox = [ 

6771 c._make_proxy( 

6772 subquery, 

6773 key=proxy_key, 

6774 name=required_label_name, 

6775 name_is_truncatable=True, 

6776 primary_key=primary_key, 

6777 foreign_keys=foreign_keys, 

6778 ) 

6779 for ( 

6780 required_label_name, 

6781 proxy_key, 

6782 fallback_label_name, 

6783 c, 

6784 repeated, 

6785 ) in (self._generate_columns_plus_names(False)) 

6786 if is_column_element(c) 

6787 ] 

6788 

6789 columns._populate_separate_keys(prox) 

6790 

6791 def _needs_parens_for_grouping(self) -> bool: 

6792 return self._has_row_limiting_clause or bool( 

6793 self._order_by_clause.clauses 

6794 ) 

6795 

6796 def self_group( 

6797 self, against: Optional[OperatorType] = None 

6798 ) -> Union[SelectStatementGrouping[Self], Self]: 

6799 """Return a 'grouping' construct as per the 

6800 :class:`_expression.ClauseElement` specification. 

6801 

6802 This produces an element that can be embedded in an expression. Note 

6803 that this method is called automatically as needed when constructing 

6804 expressions and should not require explicit use. 

6805 

6806 """ 

6807 if ( 

6808 isinstance(against, CompoundSelect) 

6809 and not self._needs_parens_for_grouping() 

6810 ): 

6811 return self 

6812 else: 

6813 return SelectStatementGrouping(self) 

6814 

6815 def union( 

6816 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6817 ) -> CompoundSelect[Unpack[_Ts]]: 

6818 r"""Return a SQL ``UNION`` of this select() construct against 

6819 the given selectables provided as positional arguments. 

6820 

6821 :param \*other: one or more elements with which to create a 

6822 UNION. 

6823 

6824 .. versionchanged:: 1.4.28 

6825 

6826 multiple elements are now accepted. 

6827 

6828 :param \**kwargs: keyword arguments are forwarded to the constructor 

6829 for the newly created :class:`_sql.CompoundSelect` object. 

6830 

6831 """ 

6832 return CompoundSelect._create_union(self, *other) 

6833 

6834 def union_all( 

6835 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6836 ) -> CompoundSelect[Unpack[_Ts]]: 

6837 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6838 the given selectables provided as positional arguments. 

6839 

6840 :param \*other: one or more elements with which to create a 

6841 UNION. 

6842 

6843 .. versionchanged:: 1.4.28 

6844 

6845 multiple elements are now accepted. 

6846 

6847 :param \**kwargs: keyword arguments are forwarded to the constructor 

6848 for the newly created :class:`_sql.CompoundSelect` object. 

6849 

6850 """ 

6851 return CompoundSelect._create_union_all(self, *other) 

6852 

6853 def except_( 

6854 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6855 ) -> CompoundSelect[Unpack[_Ts]]: 

6856 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6857 the given selectable provided as positional arguments. 

6858 

6859 :param \*other: one or more elements with which to create a 

6860 UNION. 

6861 

6862 .. versionchanged:: 1.4.28 

6863 

6864 multiple elements are now accepted. 

6865 

6866 """ 

6867 return CompoundSelect._create_except(self, *other) 

6868 

6869 def except_all( 

6870 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6871 ) -> CompoundSelect[Unpack[_Ts]]: 

6872 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6873 the given selectables provided as positional arguments. 

6874 

6875 :param \*other: one or more elements with which to create a 

6876 UNION. 

6877 

6878 .. versionchanged:: 1.4.28 

6879 

6880 multiple elements are now accepted. 

6881 

6882 """ 

6883 return CompoundSelect._create_except_all(self, *other) 

6884 

6885 def intersect( 

6886 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6887 ) -> CompoundSelect[Unpack[_Ts]]: 

6888 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6889 the given selectables provided as positional arguments. 

6890 

6891 :param \*other: one or more elements with which to create a 

6892 UNION. 

6893 

6894 .. versionchanged:: 1.4.28 

6895 

6896 multiple elements are now accepted. 

6897 

6898 :param \**kwargs: keyword arguments are forwarded to the constructor 

6899 for the newly created :class:`_sql.CompoundSelect` object. 

6900 

6901 """ 

6902 return CompoundSelect._create_intersect(self, *other) 

6903 

6904 def intersect_all( 

6905 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6906 ) -> CompoundSelect[Unpack[_Ts]]: 

6907 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6908 against the given selectables provided as positional arguments. 

6909 

6910 :param \*other: one or more elements with which to create a 

6911 UNION. 

6912 

6913 .. versionchanged:: 1.4.28 

6914 

6915 multiple elements are now accepted. 

6916 

6917 :param \**kwargs: keyword arguments are forwarded to the constructor 

6918 for the newly created :class:`_sql.CompoundSelect` object. 

6919 

6920 """ 

6921 return CompoundSelect._create_intersect_all(self, *other) 

6922 

6923 

6924class ScalarSelect( 

6925 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6926): 

6927 """Represent a scalar subquery. 

6928 

6929 

6930 A :class:`_sql.ScalarSelect` is created by invoking the 

6931 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6932 then participates in other SQL expressions as a SQL column expression 

6933 within the :class:`_sql.ColumnElement` hierarchy. 

6934 

6935 .. seealso:: 

6936 

6937 :meth:`_sql.SelectBase.scalar_subquery` 

6938 

6939 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6940 

6941 """ 

6942 

6943 _traverse_internals: _TraverseInternalsType = [ 

6944 ("element", InternalTraversal.dp_clauseelement), 

6945 ("type", InternalTraversal.dp_type), 

6946 ] 

6947 

6948 _from_objects: List[FromClause] = [] 

6949 _is_from_container = True 

6950 if not TYPE_CHECKING: 

6951 _is_implicitly_boolean = False 

6952 inherit_cache = True 

6953 

6954 element: SelectBase 

6955 

6956 def __init__(self, element: SelectBase) -> None: 

6957 self.element = element 

6958 self.type = element._scalar_type() 

6959 self._propagate_attrs = element._propagate_attrs 

6960 

6961 def __getattr__(self, attr: str) -> Any: 

6962 return getattr(self.element, attr) 

6963 

6964 def __getstate__(self) -> Dict[str, Any]: 

6965 return {"element": self.element, "type": self.type} 

6966 

6967 def __setstate__(self, state: Dict[str, Any]) -> None: 

6968 self.element = state["element"] 

6969 self.type = state["type"] 

6970 

6971 @property 

6972 def columns(self) -> NoReturn: 

6973 raise exc.InvalidRequestError( 

6974 "Scalar Select expression has no " 

6975 "columns; use this object directly " 

6976 "within a column-level expression." 

6977 ) 

6978 

6979 c = columns 

6980 

6981 @_generative 

6982 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6983 """Apply a WHERE clause to the SELECT statement referred to 

6984 by this :class:`_expression.ScalarSelect`. 

6985 

6986 """ 

6987 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6988 crit 

6989 ) 

6990 return self 

6991 

6992 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6993 return self 

6994 

6995 def _ungroup(self) -> Self: 

6996 return self 

6997 

6998 @_generative 

6999 def correlate( 

7000 self, 

7001 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7002 ) -> Self: 

7003 r"""Return a new :class:`_expression.ScalarSelect` 

7004 which will correlate the given FROM 

7005 clauses to that of an enclosing :class:`_expression.Select`. 

7006 

7007 This method is mirrored from the :meth:`_sql.Select.correlate` method 

7008 of the underlying :class:`_sql.Select`. The method applies the 

7009 :meth:_sql.Select.correlate` method, then returns a new 

7010 :class:`_sql.ScalarSelect` against that statement. 

7011 

7012 .. versionadded:: 1.4 Previously, the 

7013 :meth:`_sql.ScalarSelect.correlate` 

7014 method was only available from :class:`_sql.Select`. 

7015 

7016 :param \*fromclauses: a list of one or more 

7017 :class:`_expression.FromClause` 

7018 constructs, or other compatible constructs (i.e. ORM-mapped 

7019 classes) to become part of the correlate collection. 

7020 

7021 .. seealso:: 

7022 

7023 :meth:`_expression.ScalarSelect.correlate_except` 

7024 

7025 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7026 

7027 

7028 """ 

7029 self.element = cast( 

7030 "Select[Unpack[TupleAny]]", self.element 

7031 ).correlate(*fromclauses) 

7032 return self 

7033 

7034 @_generative 

7035 def correlate_except( 

7036 self, 

7037 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7038 ) -> Self: 

7039 r"""Return a new :class:`_expression.ScalarSelect` 

7040 which will omit the given FROM 

7041 clauses from the auto-correlation process. 

7042 

7043 This method is mirrored from the 

7044 :meth:`_sql.Select.correlate_except` method of the underlying 

7045 :class:`_sql.Select`. The method applies the 

7046 :meth:_sql.Select.correlate_except` method, then returns a new 

7047 :class:`_sql.ScalarSelect` against that statement. 

7048 

7049 .. versionadded:: 1.4 Previously, the 

7050 :meth:`_sql.ScalarSelect.correlate_except` 

7051 method was only available from :class:`_sql.Select`. 

7052 

7053 :param \*fromclauses: a list of one or more 

7054 :class:`_expression.FromClause` 

7055 constructs, or other compatible constructs (i.e. ORM-mapped 

7056 classes) to become part of the correlate-exception collection. 

7057 

7058 .. seealso:: 

7059 

7060 :meth:`_expression.ScalarSelect.correlate` 

7061 

7062 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7063 

7064 

7065 """ 

7066 

7067 self.element = cast( 

7068 "Select[Unpack[TupleAny]]", self.element 

7069 ).correlate_except(*fromclauses) 

7070 return self 

7071 

7072 

7073class Exists(UnaryExpression[bool]): 

7074 """Represent an ``EXISTS`` clause. 

7075 

7076 See :func:`_sql.exists` for a description of usage. 

7077 

7078 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

7079 instance by calling :meth:`_sql.SelectBase.exists`. 

7080 

7081 """ 

7082 

7083 inherit_cache = True 

7084 

7085 def __init__( 

7086 self, 

7087 __argument: Optional[ 

7088 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

7089 ] = None, 

7090 /, 

7091 ): 

7092 s: ScalarSelect[Any] 

7093 

7094 # TODO: this seems like we should be using coercions for this 

7095 if __argument is None: 

7096 s = Select(literal_column("*")).scalar_subquery() 

7097 elif isinstance(__argument, SelectBase): 

7098 s = __argument.scalar_subquery() 

7099 s._propagate_attrs = __argument._propagate_attrs 

7100 elif isinstance(__argument, ScalarSelect): 

7101 s = __argument 

7102 else: 

7103 s = Select(__argument).scalar_subquery() 

7104 

7105 UnaryExpression.__init__( 

7106 self, 

7107 s, 

7108 operator=operators.exists, 

7109 type_=type_api.BOOLEANTYPE, 

7110 ) 

7111 

7112 @util.ro_non_memoized_property 

7113 def _from_objects(self) -> List[FromClause]: 

7114 return [] 

7115 

7116 def _regroup( 

7117 self, 

7118 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7119 ) -> ScalarSelect[Any]: 

7120 

7121 assert isinstance(self.element, ScalarSelect) 

7122 element = self.element.element 

7123 if not isinstance(element, Select): 

7124 raise exc.InvalidRequestError( 

7125 "Can only apply this operation to a plain SELECT construct" 

7126 ) 

7127 new_element = fn(element) 

7128 

7129 return_value = new_element.scalar_subquery() 

7130 return return_value 

7131 

7132 def select(self) -> Select[bool]: 

7133 r"""Return a SELECT of this :class:`_expression.Exists`. 

7134 

7135 e.g.:: 

7136 

7137 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7138 

7139 This will produce a statement resembling: 

7140 

7141 .. sourcecode:: sql 

7142 

7143 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7144 

7145 .. seealso:: 

7146 

7147 :func:`_expression.select` - general purpose 

7148 method which allows for arbitrary column lists. 

7149 

7150 """ # noqa 

7151 

7152 return Select(self) 

7153 

7154 def correlate( 

7155 self, 

7156 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7157 ) -> Self: 

7158 """Apply correlation to the subquery noted by this 

7159 :class:`_sql.Exists`. 

7160 

7161 .. seealso:: 

7162 

7163 :meth:`_sql.ScalarSelect.correlate` 

7164 

7165 """ 

7166 e = self._clone() 

7167 e.element = self._regroup( 

7168 lambda element: element.correlate(*fromclauses) 

7169 ) 

7170 return e 

7171 

7172 def correlate_except( 

7173 self, 

7174 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7175 ) -> Self: 

7176 """Apply correlation to the subquery noted by this 

7177 :class:`_sql.Exists`. 

7178 

7179 .. seealso:: 

7180 

7181 :meth:`_sql.ScalarSelect.correlate_except` 

7182 

7183 """ 

7184 e = self._clone() 

7185 e.element = self._regroup( 

7186 lambda element: element.correlate_except(*fromclauses) 

7187 ) 

7188 return e 

7189 

7190 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7191 """Return a new :class:`_expression.Exists` construct, 

7192 applying the given 

7193 expression to the :meth:`_expression.Select.select_from` 

7194 method of the select 

7195 statement contained. 

7196 

7197 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7198 statement first, including the desired WHERE clause, then use the 

7199 :meth:`_sql.SelectBase.exists` method to produce an 

7200 :class:`_sql.Exists` object at once. 

7201 

7202 """ 

7203 e = self._clone() 

7204 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7205 return e 

7206 

7207 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7208 """Return a new :func:`_expression.exists` construct with the 

7209 given expression added to 

7210 its WHERE clause, joined to the existing clause via AND, if any. 

7211 

7212 

7213 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7214 statement first, including the desired WHERE clause, then use the 

7215 :meth:`_sql.SelectBase.exists` method to produce an 

7216 :class:`_sql.Exists` object at once. 

7217 

7218 """ 

7219 e = self._clone() 

7220 e.element = self._regroup(lambda element: element.where(*clause)) 

7221 return e 

7222 

7223 

7224class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7225 """Wrap a :class:`_expression.TextClause` construct within a 

7226 :class:`_expression.SelectBase` 

7227 interface. 

7228 

7229 This allows the :class:`_expression.TextClause` object to gain a 

7230 ``.c`` collection 

7231 and other FROM-like capabilities such as 

7232 :meth:`_expression.FromClause.alias`, 

7233 :meth:`_expression.SelectBase.cte`, etc. 

7234 

7235 The :class:`_expression.TextualSelect` construct is produced via the 

7236 :meth:`_expression.TextClause.columns` 

7237 method - see that method for details. 

7238 

7239 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7240 class was renamed 

7241 from ``TextAsFrom``, to more correctly suit its role as a 

7242 SELECT-oriented object and not a FROM clause. 

7243 

7244 .. seealso:: 

7245 

7246 :func:`_expression.text` 

7247 

7248 :meth:`_expression.TextClause.columns` - primary creation interface. 

7249 

7250 """ 

7251 

7252 __visit_name__ = "textual_select" 

7253 

7254 _label_style = LABEL_STYLE_NONE 

7255 

7256 _traverse_internals: _TraverseInternalsType = ( 

7257 [ 

7258 ("element", InternalTraversal.dp_clauseelement), 

7259 ("column_args", InternalTraversal.dp_clauseelement_list), 

7260 ] 

7261 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7262 + HasCTE._has_ctes_traverse_internals 

7263 + ExecutableStatement._executable_traverse_internals 

7264 ) 

7265 

7266 _is_textual = True 

7267 

7268 is_text = True 

7269 is_select = True 

7270 

7271 def __init__( 

7272 self, 

7273 text: TextClause, 

7274 columns: List[_ColumnExpressionArgument[Any]], 

7275 positional: bool = False, 

7276 ) -> None: 

7277 self._init( 

7278 text, 

7279 # convert for ORM attributes->columns, etc 

7280 [ 

7281 coercions.expect(roles.LabeledColumnExprRole, c) 

7282 for c in columns 

7283 ], 

7284 positional, 

7285 ) 

7286 

7287 def _init( 

7288 self, 

7289 text: TextClause, 

7290 columns: List[NamedColumn[Any]], 

7291 positional: bool = False, 

7292 ) -> None: 

7293 self.element = text 

7294 self.column_args = columns 

7295 self.positional = positional 

7296 

7297 @HasMemoized_ro_memoized_attribute 

7298 def selected_columns( 

7299 self, 

7300 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7301 """A :class:`_expression.ColumnCollection` 

7302 representing the columns that 

7303 this SELECT statement or similar construct returns in its result set, 

7304 not including :class:`_sql.TextClause` constructs. 

7305 

7306 This collection differs from the :attr:`_expression.FromClause.columns` 

7307 collection of a :class:`_expression.FromClause` in that the columns 

7308 within this collection cannot be directly nested inside another SELECT 

7309 statement; a subquery must be applied first which provides for the 

7310 necessary parenthesization required by SQL. 

7311 

7312 For a :class:`_expression.TextualSelect` construct, the collection 

7313 contains the :class:`_expression.ColumnElement` objects that were 

7314 passed to the constructor, typically via the 

7315 :meth:`_expression.TextClause.columns` method. 

7316 

7317 

7318 .. versionadded:: 1.4 

7319 

7320 """ 

7321 return ColumnCollection( 

7322 (c.key, c) for c in self.column_args 

7323 ).as_readonly() 

7324 

7325 @util.ro_non_memoized_property 

7326 def _all_selected_columns(self) -> _SelectIterable: 

7327 return self.column_args 

7328 

7329 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7330 return self 

7331 

7332 def _ensure_disambiguated_names(self) -> TextualSelect: 

7333 return self 

7334 

7335 @_generative 

7336 def bindparams( 

7337 self, 

7338 *binds: BindParameter[Any], 

7339 **bind_as_values: Any, 

7340 ) -> Self: 

7341 self.element = self.element.bindparams(*binds, **bind_as_values) 

7342 return self 

7343 

7344 def _generate_fromclause_column_proxies( 

7345 self, 

7346 fromclause: FromClause, 

7347 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

7348 primary_key: ColumnSet, 

7349 foreign_keys: Set[KeyedColumnElement[Any]], 

7350 *, 

7351 proxy_compound_columns: Optional[ 

7352 Iterable[Sequence[ColumnElement[Any]]] 

7353 ] = None, 

7354 ) -> None: 

7355 if TYPE_CHECKING: 

7356 assert isinstance(fromclause, Subquery) 

7357 

7358 if proxy_compound_columns: 

7359 columns._populate_separate_keys( 

7360 c._make_proxy( 

7361 fromclause, 

7362 compound_select_cols=extra_cols, 

7363 primary_key=primary_key, 

7364 foreign_keys=foreign_keys, 

7365 ) 

7366 for c, extra_cols in zip( 

7367 self.column_args, proxy_compound_columns 

7368 ) 

7369 ) 

7370 else: 

7371 columns._populate_separate_keys( 

7372 c._make_proxy( 

7373 fromclause, 

7374 primary_key=primary_key, 

7375 foreign_keys=foreign_keys, 

7376 ) 

7377 for c in self.column_args 

7378 ) 

7379 

7380 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7381 return self.column_args[0].type 

7382 

7383 

7384TextAsFrom = TextualSelect 

7385"""Backwards compatibility with the previous name""" 

7386 

7387 

7388class AnnotatedFromClause(Annotated): 

7389 def _copy_internals( 

7390 self, 

7391 _annotations_traversal: bool = False, 

7392 ind_cols_on_fromclause: bool = False, 

7393 **kw: Any, 

7394 ) -> None: 

7395 super()._copy_internals(**kw) 

7396 

7397 # passed from annotations._shallow_annotate(), _deep_annotate(), etc. 

7398 # the traversals used by annotations for these cases are not currently 

7399 # designed around expecting that inner elements inside of 

7400 # AnnotatedFromClause's element are also deep copied, so skip for these 

7401 # cases. in other cases such as plain visitors.cloned_traverse(), we 

7402 # expect this to happen. see issue #12915 

7403 if not _annotations_traversal: 

7404 ee = self._Annotated__element # type: ignore 

7405 ee._copy_internals(**kw) 

7406 

7407 if ind_cols_on_fromclause: 

7408 # passed from annotations._deep_annotate(). See that function 

7409 # for notes 

7410 ee = self._Annotated__element # type: ignore 

7411 self.c = ee.__class__.c.fget(self) # type: ignore 

7412 

7413 @util.ro_memoized_property 

7414 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7415 """proxy the .c collection of the underlying FromClause. 

7416 

7417 Originally implemented in 2008 as a simple load of the .c collection 

7418 when the annotated construct was created (see d3621ae961a), in modern 

7419 SQLAlchemy versions this can be expensive for statements constructed 

7420 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7421 it, which works just as well. 

7422 

7423 Two different use cases seem to require the collection either copied 

7424 from the underlying one, or unique to this AnnotatedFromClause. 

7425 

7426 See test_selectable->test_annotated_corresponding_column 

7427 

7428 """ 

7429 ee = self._Annotated__element # type: ignore 

7430 return ee.c # type: ignore