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

1796 statements  

1# sql/selectable.py 

2# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

7 

8"""The :class:`_expression.FromClause` class of SQL expression elements, 

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19import os 

20from typing import AbstractSet 

21from typing import Any as TODO_Any 

22from typing import Any 

23from typing import Callable 

24from typing import cast 

25from typing import Collection 

26from typing import Dict 

27from typing import Generic 

28from typing import Iterable 

29from typing import Iterator 

30from typing import List 

31from typing import Literal 

32from typing import NamedTuple 

33from typing import NoReturn 

34from typing import Optional 

35from typing import overload 

36from typing import Protocol 

37from typing import Sequence 

38from typing import Set 

39from typing import Tuple 

40from typing import Type 

41from typing import TYPE_CHECKING 

42from typing import TypeVar 

43from typing import Union 

44 

45from . import cache_key 

46from . import coercions 

47from . import operators 

48from . import roles 

49from . import traversals 

50from . import type_api 

51from . import visitors 

52from ._typing import _ColumnsClauseArgument 

53from ._typing import _no_kw 

54from ._typing import _T 

55from ._typing import _Ts 

56from ._typing import is_column_element 

57from ._typing import is_select_statement 

58from ._typing import is_subquery 

59from ._typing import is_table 

60from ._typing import is_text_clause 

61from .annotation import Annotated 

62from .annotation import SupportsCloneAnnotations 

63from .base import _clone 

64from .base import _cloned_difference 

65from .base import _cloned_intersection 

66from .base import _entity_namespace_key_search_all 

67from .base import _EntityNamespace 

68from .base import _expand_cloned 

69from .base import _from_objects 

70from .base import _generative 

71from .base import _never_select_column 

72from .base import _NoArg 

73from .base import _select_iterables 

74from .base import CacheableOptions 

75from .base import ColumnCollection 

76from .base import ColumnSet 

77from .base import CompileState 

78from .base import DedupeColumnCollection 

79from .base import DialectKWArgs 

80from .base import Executable 

81from .base import ExecutableStatement 

82from .base import Generative 

83from .base import HasCompileState 

84from .base import HasMemoized 

85from .base import HasSyntaxExtensions 

86from .base import Immutable 

87from .base import SyntaxExtension 

88from .base import WriteableColumnCollection 

89from .coercions import _document_text_coercion 

90from .elements import _anonymous_label 

91from .elements import BindParameter 

92from .elements import BooleanClauseList 

93from .elements import ClauseElement 

94from .elements import ClauseList 

95from .elements import ColumnClause 

96from .elements import ColumnElement 

97from .elements import DQLDMLClauseElement 

98from .elements import GroupedElement 

99from .elements import literal_column 

100from .elements import TableValuedColumn 

101from .elements import TextClause 

102from .elements import UnaryExpression 

103from .operators import OperatorType 

104from .sqltypes import NULLTYPE 

105from .visitors import _TraverseInternalsType 

106from .visitors import InternalTraversal 

107from .visitors import prefix_anon_map 

108from .. import exc 

109from .. import util 

110from ..util import HasMemoized_ro_memoized_attribute 

111from ..util import warn_deprecated 

112from ..util.typing import Self 

113from ..util.typing import TupleAny 

114from ..util.typing import Unpack 

115 

116and_ = BooleanClauseList.and_ 

117 

118 

119if TYPE_CHECKING: 

120 from ._typing import _ColumnExpressionArgument 

121 from ._typing import _ColumnExpressionOrStrLabelArgument 

122 from ._typing import _FromClauseArgument 

123 from ._typing import _JoinTargetArgument 

124 from ._typing import _LimitOffsetType 

125 from ._typing import _MAYBE_ENTITY 

126 from ._typing import _NOT_ENTITY 

127 from ._typing import _OnClauseArgument 

128 from ._typing import _OnlyColumnArgument 

129 from ._typing import _SelectStatementForCompoundArgument 

130 from ._typing import _T0 

131 from ._typing import _T1 

132 from ._typing import _T2 

133 from ._typing import _T3 

134 from ._typing import _T4 

135 from ._typing import _T5 

136 from ._typing import _T6 

137 from ._typing import _T7 

138 from ._typing import _TextCoercedExpressionArgument 

139 from ._typing import _TypedColumnClauseArgument as _TCCA 

140 from ._typing import _TypeEngineArgument 

141 from .base import _AmbiguousTableNameMap 

142 from .base import ExecutableOption 

143 from .base import ReadOnlyColumnCollection 

144 from .cache_key import _CacheKeyTraversalType 

145 from .compiler import SQLCompiler 

146 from .ddl import CreateTableAs 

147 from .dml import Delete 

148 from .dml import Update 

149 from .elements import AbstractTextClause 

150 from .elements import BinaryExpression 

151 from .elements import KeyedColumnElement 

152 from .elements import Label 

153 from .elements import NamedColumn 

154 from .functions import Function 

155 from .schema import ForeignKey 

156 from .schema import ForeignKeyConstraint 

157 from .schema import MetaData 

158 from .sqltypes import TableValueType 

159 from .type_api import TypeEngine 

160 from .visitors import _CloneCallableType 

161 

162 

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

164_LabelConventionCallable = Callable[ 

165 [Union["ColumnElement[Any]", "AbstractTextClause"]], Optional[str] 

166] 

167 

168 

169class _JoinTargetProtocol(Protocol): 

170 @util.ro_non_memoized_property 

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

172 

173 @util.ro_non_memoized_property 

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

175 

176 

177_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

179 

180_ForUpdateOfArgument = Union[ 

181 # single column, Table, ORM entity 

182 Union[ 

183 "_ColumnExpressionArgument[Any]", 

184 "_FromClauseArgument", 

185 ], 

186 # or sequence of column, Table, ORM entity 

187 Sequence[ 

188 Union[ 

189 "_ColumnExpressionArgument[Any]", 

190 "_FromClauseArgument", 

191 ] 

192 ], 

193] 

194 

195 

196_SetupJoinsElement = Tuple[ 

197 _JoinTargetElement, 

198 Optional[_OnClauseElement], 

199 Optional["FromClause"], 

200 Dict[str, Any], 

201] 

202 

203 

204_SelectIterable = Iterable[Union["ColumnElement[Any]", "AbstractTextClause"]] 

205 

206 

207class _OffsetLimitParam(BindParameter[int]): 

208 inherit_cache = True 

209 

210 @property 

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

212 return self.effective_value 

213 

214 

215class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

217 columns that can represent rows. 

218 

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

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

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

222 PostgreSQL has functions that return rows also. 

223 

224 .. versionadded:: 1.4 

225 

226 """ 

227 

228 _is_returns_rows = True 

229 

230 # sub-elements of returns_rows 

231 _is_from_clause = False 

232 _is_select_base = False 

233 _is_select_statement = False 

234 _is_lateral = False 

235 

236 @property 

237 def selectable(self) -> ReturnsRows: 

238 return self 

239 

240 @util.ro_non_memoized_property 

241 def _all_selected_columns(self) -> _SelectIterable: 

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

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

244 

245 This is typically equivalent to .exported_columns except it is 

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

247 :class:`_expression.ColumnCollection`. 

248 

249 """ 

250 raise NotImplementedError() 

251 

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

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

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

255 

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

257 

258 """ 

259 raise NotImplementedError() 

260 

261 def _generate_fromclause_column_proxies( 

262 self, 

263 fromclause: FromClause, 

264 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

265 primary_key: ColumnSet, 

266 foreign_keys: Set[KeyedColumnElement[Any]], 

267 ) -> None: 

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

269 

270 raise NotImplementedError() 

271 

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

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

274 raise NotImplementedError() 

275 

276 @property 

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

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

279 that represents the "exported" 

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

281 

282 The "exported" columns represent the collection of 

283 :class:`_expression.ColumnElement` 

284 expressions that are rendered by this SQL 

285 construct. There are primary varieties which are the 

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

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

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

289 columns in a DML statement.. 

290 

291 .. versionadded:: 1.4 

292 

293 .. seealso:: 

294 

295 :attr:`_expression.FromClause.exported_columns` 

296 

297 :attr:`_expression.SelectBase.exported_columns` 

298 """ 

299 

300 raise NotImplementedError() 

301 

302 

303class ExecutableReturnsRows(ExecutableStatement, ReturnsRows): 

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

305 

306 

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

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

309 

310 

311class Selectable(ReturnsRows): 

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

313 

314 __visit_name__ = "selectable" 

315 

316 is_selectable = True 

317 

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

319 raise NotImplementedError() 

320 

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

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

323 

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

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

326 

327 .. seealso:: 

328 

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

330 

331 """ 

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

333 

334 @util.deprecated( 

335 "1.4", 

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

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

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

339 ) 

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

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

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

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

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

345 

346 """ 

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

348 

349 def corresponding_column( 

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

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

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

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

354 :attr:`_expression.Selectable.exported_columns` 

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

356 which corresponds to that 

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

358 column. 

359 

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

361 to be matched. 

362 

363 :param require_embedded: only return corresponding columns for 

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

365 :class:`_expression.ColumnElement` 

366 is actually present within a sub-element 

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

368 Normally the column will match if 

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

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

371 

372 .. seealso:: 

373 

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

375 :class:`_expression.ColumnCollection` 

376 that is used for the operation. 

377 

378 :meth:`_expression.ColumnCollection.corresponding_column` 

379 - implementation 

380 method. 

381 

382 """ 

383 

384 return self.exported_columns.corresponding_column( 

385 column, require_embedded 

386 ) 

387 

388 

389class HasPrefixes: 

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

391 

392 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

393 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

394 ] 

395 

396 @_generative 

397 @_document_text_coercion( 

398 "prefixes", 

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

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

401 ) 

402 def prefix_with( 

403 self, 

404 *prefixes: _TextCoercedExpressionArgument[Any], 

405 dialect: str = "*", 

406 ) -> Self: 

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

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

409 

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

411 provided by MySQL. 

412 

413 E.g.:: 

414 

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

416 

417 # MySQL 5.7 optimizer hints 

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

419 

420 Multiple prefixes can be specified by multiple calls 

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

422 

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

424 construct which 

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

426 keyword. 

427 :param dialect: optional string dialect name which will 

428 limit rendering of this prefix to only that dialect. 

429 

430 """ 

431 self._prefixes = self._prefixes + tuple( 

432 [ 

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

434 for p in prefixes 

435 ] 

436 ) 

437 return self 

438 

439 

440class HasSuffixes: 

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

442 

443 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

444 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

445 ] 

446 

447 @_generative 

448 @_document_text_coercion( 

449 "suffixes", 

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

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

452 ) 

453 def suffix_with( 

454 self, 

455 *suffixes: _TextCoercedExpressionArgument[Any], 

456 dialect: str = "*", 

457 ) -> Self: 

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

459 

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

461 certain constructs. 

462 

463 E.g.:: 

464 

465 stmt = ( 

466 select(col1, col2) 

467 .cte() 

468 .suffix_with( 

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

470 ) 

471 ) 

472 

473 Multiple suffixes can be specified by multiple calls 

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

475 

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

477 construct which 

478 will be rendered following the target clause. 

479 :param dialect: Optional string dialect name which will 

480 limit rendering of this suffix to only that dialect. 

481 

482 """ 

483 self._suffixes = self._suffixes + tuple( 

484 [ 

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

486 for p in suffixes 

487 ] 

488 ) 

489 return self 

490 

491 

492class HasHints: 

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

494 util.immutabledict() 

495 ) 

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

497 

498 _has_hints_traverse_internals: _TraverseInternalsType = [ 

499 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

500 ("_hints", InternalTraversal.dp_table_hint_list), 

501 ] 

502 

503 @_generative 

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

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

506 other selectable object. 

507 

508 .. tip:: 

509 

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

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

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

513 the SELECT statement after the SELECT keyword, use the 

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

515 space, or for table-specific hints the 

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

517 hints in a dialect-specific location. 

518 

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

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

521 the statement as a whole. 

522 

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

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

525 etc. 

526 

527 .. seealso:: 

528 

529 :meth:`_expression.Select.with_hint` 

530 

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

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

533 MySQL or Oracle Database optimizer hints 

534 

535 """ 

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

537 

538 @_generative 

539 def with_hint( 

540 self, 

541 selectable: _FromClauseArgument, 

542 text: str, 

543 dialect_name: str = "*", 

544 ) -> Self: 

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

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

547 object. 

548 

549 .. tip:: 

550 

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

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

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

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

555 for MySQL or Oracle Database, use the 

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

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

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

559 

560 The text of the hint is rendered in the appropriate 

561 location for the database backend in use, relative 

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

563 passed as the 

564 ``selectable`` argument. The dialect implementation 

565 typically uses Python string substitution syntax 

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

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

568 following:: 

569 

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

571 

572 Would render SQL as: 

573 

574 .. sourcecode:: sql 

575 

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

577 

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

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

580 Database and MSSql simultaneously:: 

581 

582 select(mytable).with_hint( 

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

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

585 

586 .. seealso:: 

587 

588 :meth:`_expression.Select.with_statement_hint` 

589 

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

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

592 MySQL or Oracle Database optimizer hints 

593 

594 """ 

595 

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

597 

598 def _with_hint( 

599 self, 

600 selectable: Optional[_FromClauseArgument], 

601 text: str, 

602 dialect_name: str, 

603 ) -> Self: 

604 if selectable is None: 

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

606 else: 

607 self._hints = self._hints.union( 

608 { 

609 ( 

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

611 dialect_name, 

612 ): text 

613 } 

614 ) 

615 return self 

616 

617 

618class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

620 clause of a ``SELECT`` statement. 

621 

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

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

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

625 

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

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

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

629 :class:`_expression.ColumnElement` 

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

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

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

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

634 :meth:`_expression.FromClause.select`. 

635 

636 

637 """ 

638 

639 __visit_name__ = "fromclause" 

640 named_with_column = False 

641 

642 @util.ro_non_memoized_property 

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

644 return () 

645 

646 _is_clone_of: Optional[FromClause] 

647 

648 _columns: WriteableColumnCollection[Any, Any] 

649 

650 schema: Optional[str] = None 

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

652 

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

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

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

656 

657 """ 

658 

659 is_selectable = True 

660 _is_from_clause = True 

661 _is_join = False 

662 

663 _use_schema_map = False 

664 

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

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

667 

668 

669 e.g.:: 

670 

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

672 

673 .. seealso:: 

674 

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

676 method which allows for arbitrary column lists. 

677 

678 """ 

679 return Select(self) 

680 

681 def join( 

682 self, 

683 right: _FromClauseArgument, 

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

685 isouter: bool = False, 

686 full: bool = False, 

687 ) -> Join: 

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

689 :class:`_expression.FromClause` 

690 to another :class:`FromClause`. 

691 

692 E.g.:: 

693 

694 from sqlalchemy import join 

695 

696 j = user_table.join( 

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

698 ) 

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

700 

701 would emit SQL along the lines of: 

702 

703 .. sourcecode:: sql 

704 

705 SELECT user.id, user.name FROM user 

706 JOIN address ON user.id = address.user_id 

707 

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

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

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

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

712 class. 

713 

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

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

716 will attempt to 

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

718 

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

720 

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

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

723 

724 .. seealso:: 

725 

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

727 

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

729 

730 """ 

731 

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

733 

734 def outerjoin( 

735 self, 

736 right: _FromClauseArgument, 

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

738 full: bool = False, 

739 ) -> Join: 

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

741 :class:`_expression.FromClause` 

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

743 True. 

744 

745 E.g.:: 

746 

747 from sqlalchemy import outerjoin 

748 

749 j = user_table.outerjoin( 

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

751 ) 

752 

753 The above is equivalent to:: 

754 

755 j = user_table.join( 

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

757 ) 

758 

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

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

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

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

763 class. 

764 

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

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

767 will attempt to 

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

769 

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

771 LEFT OUTER JOIN. 

772 

773 .. seealso:: 

774 

775 :meth:`_expression.FromClause.join` 

776 

777 :class:`_expression.Join` 

778 

779 """ # noqa: E501 

780 

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

782 

783 def alias( 

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

785 ) -> NamedFromClause: 

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

787 

788 E.g.:: 

789 

790 a2 = some_table.alias("a2") 

791 

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

793 object which can be used 

794 as a FROM clause in any SELECT statement. 

795 

796 .. seealso:: 

797 

798 :ref:`tutorial_using_aliases` 

799 

800 :func:`_expression.alias` 

801 

802 """ 

803 

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

805 

806 def tablesample( 

807 self, 

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

809 name: Optional[str] = None, 

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

811 ) -> TableSample: 

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

813 

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

815 construct also 

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

817 

818 .. seealso:: 

819 

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

821 

822 """ 

823 return TableSample._construct( 

824 self, sampling=sampling, name=name, seed=seed 

825 ) 

826 

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

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

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

830 

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

832 

833 """ 

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

835 # Other constructs override this to traverse through 

836 # contained elements. 

837 return fromclause in self._cloned_set 

838 

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

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

841 the other represent the same lexical identity. 

842 

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

844 if they are the same via annotation identity. 

845 

846 """ 

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

848 

849 @util.ro_non_memoized_property 

850 def description(self) -> str: 

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

852 

853 Used primarily for error message formatting. 

854 

855 """ 

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

857 

858 def _generate_fromclause_column_proxies( 

859 self, 

860 fromclause: FromClause, 

861 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

862 primary_key: ColumnSet, 

863 foreign_keys: Set[KeyedColumnElement[Any]], 

864 ) -> None: 

865 columns._populate_separate_keys( 

866 col._make_proxy( 

867 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

868 ) 

869 for col in self.c 

870 ) 

871 

872 @util.ro_non_memoized_property 

873 def exported_columns( 

874 self, 

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

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

877 that represents the "exported" 

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

879 

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

881 object are synonymous 

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

883 

884 .. versionadded:: 1.4 

885 

886 .. seealso:: 

887 

888 :attr:`_expression.Selectable.exported_columns` 

889 

890 :attr:`_expression.SelectBase.exported_columns` 

891 

892 

893 """ 

894 return self.c 

895 

896 @util.ro_non_memoized_property 

897 def columns( 

898 self, 

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

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

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

902 

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

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

905 other selectable-bound columns:: 

906 

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

908 

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

910 

911 """ 

912 return self.c 

913 

914 @util.ro_memoized_property 

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

916 """ 

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

918 

919 :return: a :class:`.ColumnCollection` 

920 

921 """ 

922 if "_columns" not in self.__dict__: 

923 self._setup_collections() 

924 return self._columns.as_readonly() 

925 

926 def _setup_collections(self) -> None: 

927 with util.mini_gil: 

928 # detect another thread that raced ahead 

929 if "_columns" in self.__dict__: 

930 assert "primary_key" in self.__dict__ 

931 assert "foreign_keys" in self.__dict__ 

932 return 

933 

934 _columns: WriteableColumnCollection[Any, Any] = ( 

935 WriteableColumnCollection() 

936 ) 

937 primary_key = ColumnSet() 

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

939 

940 self._populate_column_collection( 

941 columns=_columns, 

942 primary_key=primary_key, 

943 foreign_keys=foreign_keys, 

944 ) 

945 

946 # assigning these three collections separately is not itself 

947 # atomic, but greatly reduces the surface for problems 

948 self._columns = _columns 

949 self.primary_key = primary_key # type: ignore 

950 self.foreign_keys = foreign_keys # type: ignore 

951 

952 @util.ro_non_memoized_property 

953 def entity_namespace(self) -> _EntityNamespace: 

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

955 

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

957 expressions, such as:: 

958 

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

960 

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

962 be overridden using the "entity_namespace" annotation to deliver 

963 alternative results. 

964 

965 """ 

966 return self.c 

967 

968 @util.ro_memoized_property 

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

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

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

972 

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

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

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

976 

977 """ 

978 self._setup_collections() 

979 return self.primary_key 

980 

981 @util.ro_memoized_property 

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

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

984 which this FromClause references. 

985 

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

987 :class:`_schema.Table`-wide 

988 :class:`_schema.ForeignKeyConstraint`. 

989 

990 .. seealso:: 

991 

992 :attr:`_schema.Table.foreign_key_constraints` 

993 

994 """ 

995 self._setup_collections() 

996 return self.foreign_keys 

997 

998 def _reset_column_collection(self) -> None: 

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

1000 

1001 This collection is separate from all the other memoized things 

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

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

1004 has already established strong relationships 

1005 with the exported columns. 

1006 

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

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

1009 

1010 """ 

1011 

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

1013 self.__dict__.pop(key, None) 

1014 

1015 @util.ro_non_memoized_property 

1016 def _select_iterable(self) -> _SelectIterable: 

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

1018 

1019 @property 

1020 def _cols_populated(self) -> bool: 

1021 return "_columns" in self.__dict__ 

1022 

1023 def _populate_column_collection( 

1024 self, 

1025 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

1026 primary_key: ColumnSet, 

1027 foreign_keys: Set[KeyedColumnElement[Any]], 

1028 ) -> None: 

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

1030 

1031 Each implementation has a different way of establishing 

1032 this collection. 

1033 

1034 """ 

1035 

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

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

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

1039 selectable ultimately should proxy this column. 

1040 

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

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

1043 Table objects it ultimately derives from. 

1044 

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

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

1047 but it will return None. 

1048 

1049 This method is currently used by Declarative to allow Table 

1050 columns to be added to a partially constructed inheritance 

1051 mapping that may have already produced joins. The method 

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

1053 and/or caveats aren't yet clear. 

1054 

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

1056 default via an event, which would require that 

1057 selectables maintain a weak referencing collection of all 

1058 derivations. 

1059 

1060 """ 

1061 self._reset_column_collection() 

1062 

1063 def _anonymous_fromclause( 

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

1065 ) -> FromClause: 

1066 return self.alias(name=name) 

1067 

1068 if TYPE_CHECKING: 

1069 

1070 def self_group( 

1071 self, against: Optional[OperatorType] = None 

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

1073 

1074 

1075class NamedFromClause(FromClause): 

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

1077 

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

1079 

1080 .. versionadded:: 2.0 

1081 

1082 """ 

1083 

1084 named_with_column = True 

1085 

1086 name: str 

1087 

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

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

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

1091 :class:`_expression.FromClause`. 

1092 

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

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

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

1096 such as PostgreSQL, Oracle Database and SQL Server. 

1097 

1098 E.g.: 

1099 

1100 .. sourcecode:: pycon+sql 

1101 

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

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

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

1105 >>> print(stmt) 

1106 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1107 FROM a 

1108 

1109 .. versionadded:: 1.4.0b2 

1110 

1111 .. seealso:: 

1112 

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

1114 

1115 """ 

1116 return TableValuedColumn(self, type_api.TABLEVALUE) 

1117 

1118 

1119class SelectLabelStyle(Enum): 

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

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

1122 

1123 LABEL_STYLE_NONE = 0 

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

1125 columns clause of a SELECT statement. 

1126 

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

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

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

1130 

1131 .. sourcecode:: pycon+sql 

1132 

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

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

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

1136 >>> print( 

1137 ... select(table1, table2) 

1138 ... .join(table2, true()) 

1139 ... .set_label_style(LABEL_STYLE_NONE) 

1140 ... ) 

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

1142 FROM table1 JOIN table2 ON true 

1143 

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

1145 

1146 .. versionadded:: 1.4 

1147 

1148 """ # noqa: E501 

1149 

1150 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1154 tables, aliases, or subqueries. 

1155 

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

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

1158 ``table2_columna``: 

1159 

1160 .. sourcecode:: pycon+sql 

1161 

1162 >>> from sqlalchemy import ( 

1163 ... table, 

1164 ... column, 

1165 ... select, 

1166 ... true, 

1167 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1168 ... ) 

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

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

1171 >>> print( 

1172 ... select(table1, table2) 

1173 ... .join(table2, true()) 

1174 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1175 ... ) 

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

1177 FROM table1 JOIN table2 ON true 

1178 

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

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

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

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

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

1184 

1185 

1186 .. versionadded:: 1.4 

1187 

1188 """ # noqa: E501 

1189 

1190 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1193 when generating the columns clause of a SELECT statement. 

1194 

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

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

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

1198 

1199 .. sourcecode:: pycon+sql 

1200 

1201 >>> from sqlalchemy import ( 

1202 ... table, 

1203 ... column, 

1204 ... select, 

1205 ... true, 

1206 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1207 ... ) 

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

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

1210 >>> print( 

1211 ... select(table1, table2) 

1212 ... .join(table2, true()) 

1213 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1214 ... ) 

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

1216 FROM table1 JOIN table2 ON true 

1217 

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

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

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

1221 

1222 .. versionadded:: 1.4 

1223 

1224 """ # noqa: E501 

1225 

1226 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1227 """The default label style, refers to 

1228 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1229 

1230 .. versionadded:: 1.4 

1231 

1232 """ 

1233 

1234 LABEL_STYLE_LEGACY_ORM = 3 

1235 

1236 

1237( 

1238 LABEL_STYLE_NONE, 

1239 LABEL_STYLE_TABLENAME_PLUS_COL, 

1240 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1241 _, 

1242) = list(SelectLabelStyle) 

1243 

1244LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1245 

1246 

1247class Join(roles.DMLTableRole, FromClause): 

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

1249 :class:`_expression.FromClause` 

1250 elements. 

1251 

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

1253 is the module-level 

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

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

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

1257 :class:`_schema.Table`). 

1258 

1259 .. seealso:: 

1260 

1261 :func:`_expression.join` 

1262 

1263 :meth:`_expression.FromClause.join` 

1264 

1265 """ 

1266 

1267 __visit_name__ = "join" 

1268 

1269 _traverse_internals: _TraverseInternalsType = [ 

1270 ("left", InternalTraversal.dp_clauseelement), 

1271 ("right", InternalTraversal.dp_clauseelement), 

1272 ("onclause", InternalTraversal.dp_clauseelement), 

1273 ("isouter", InternalTraversal.dp_boolean), 

1274 ("full", InternalTraversal.dp_boolean), 

1275 ] 

1276 

1277 _is_join = True 

1278 

1279 left: FromClause 

1280 right: FromClause 

1281 onclause: Optional[ColumnElement[bool]] 

1282 isouter: bool 

1283 full: bool 

1284 

1285 def __init__( 

1286 self, 

1287 left: _FromClauseArgument, 

1288 right: _FromClauseArgument, 

1289 onclause: Optional[_OnClauseArgument] = None, 

1290 isouter: bool = False, 

1291 full: bool = False, 

1292 ): 

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

1294 

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

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

1297 :class:`_expression.FromClause` object. 

1298 

1299 """ 

1300 

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

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

1303 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1306 # callcounts for a single compilation in that particular test 

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

1308 # 29200 -> 30373 

1309 

1310 self.left = coercions.expect( 

1311 roles.FromClauseRole, 

1312 left, 

1313 ) 

1314 self.right = coercions.expect( 

1315 roles.FromClauseRole, 

1316 right, 

1317 ).self_group() 

1318 

1319 if onclause is None: 

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

1321 else: 

1322 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1323 # not merged yet 

1324 self.onclause = coercions.expect( 

1325 roles.OnClauseRole, onclause 

1326 ).self_group(against=operators._asbool) 

1327 

1328 self.isouter = isouter 

1329 self.full = full 

1330 

1331 @util.ro_non_memoized_property 

1332 def description(self) -> str: 

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

1334 self.left.description, 

1335 id(self.left), 

1336 self.right.description, 

1337 id(self.right), 

1338 ) 

1339 

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

1341 return ( 

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

1343 # as well 

1344 hash(fromclause) == hash(self) 

1345 or self.left.is_derived_from(fromclause) 

1346 or self.right.is_derived_from(fromclause) 

1347 ) 

1348 

1349 def self_group( 

1350 self, against: Optional[OperatorType] = None 

1351 ) -> FromGrouping: 

1352 return FromGrouping(self) 

1353 

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

1355 def _populate_column_collection( 

1356 self, 

1357 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

1358 primary_key: ColumnSet, 

1359 foreign_keys: Set[KeyedColumnElement[Any]], 

1360 ) -> None: 

1361 sqlutil = util.preloaded.sql_util 

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

1363 c for c in self.right.c 

1364 ] 

1365 

1366 primary_key.extend( 

1367 sqlutil.reduce_columns( 

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

1369 ) 

1370 ) 

1371 columns._populate_separate_keys( 

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

1373 ) 

1374 foreign_keys.update( 

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

1376 ) 

1377 

1378 def _copy_internals( 

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

1380 ) -> None: 

1381 # see Select._copy_internals() for similar concept 

1382 

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

1384 # determine the new FROM clauses 

1385 all_the_froms = set( 

1386 itertools.chain( 

1387 _from_objects(self.left), 

1388 _from_objects(self.right), 

1389 ) 

1390 ) 

1391 

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

1393 # cache used by the clone function 

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

1395 

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

1397 # ColumnClause with parent table referring to those 

1398 # replaced FromClause objects 

1399 def replace( 

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

1401 **kw: Any, 

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

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

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

1405 return newelem 

1406 return None 

1407 

1408 kw["replace"] = replace 

1409 

1410 # run normal _copy_internals. the clones for 

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

1412 # cache 

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

1414 

1415 self._reset_memoizations() 

1416 

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

1418 super()._refresh_for_new_column(column) 

1419 self.left._refresh_for_new_column(column) 

1420 self.right._refresh_for_new_column(column) 

1421 

1422 def _match_primaries( 

1423 self, 

1424 left: FromClause, 

1425 right: FromClause, 

1426 ) -> ColumnElement[bool]: 

1427 if isinstance(left, Join): 

1428 left_right = left.right 

1429 else: 

1430 left_right = None 

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

1432 

1433 @classmethod 

1434 def _join_condition( 

1435 cls, 

1436 a: FromClause, 

1437 b: FromClause, 

1438 *, 

1439 a_subset: Optional[FromClause] = None, 

1440 consider_as_foreign_keys: Optional[ 

1441 AbstractSet[ColumnClause[Any]] 

1442 ] = None, 

1443 ) -> ColumnElement[bool]: 

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

1445 

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

1447 

1448 """ 

1449 constraints = cls._joincond_scan_left_right( 

1450 a, a_subset, b, consider_as_foreign_keys 

1451 ) 

1452 

1453 if len(constraints) > 1: 

1454 cls._joincond_trim_constraints( 

1455 a, b, constraints, consider_as_foreign_keys 

1456 ) 

1457 

1458 if len(constraints) == 0: 

1459 if isinstance(b, FromGrouping): 

1460 hint = ( 

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

1462 "subquery using alias()?" 

1463 ) 

1464 else: 

1465 hint = "" 

1466 raise exc.NoForeignKeysError( 

1467 "Can't find any foreign key relationships " 

1468 "between '%s' and '%s'.%s" 

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

1470 ) 

1471 

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

1473 if len(crit) == 1: 

1474 return crit[0] 

1475 else: 

1476 return and_(*crit) 

1477 

1478 @classmethod 

1479 def _can_join( 

1480 cls, 

1481 left: FromClause, 

1482 right: FromClause, 

1483 *, 

1484 consider_as_foreign_keys: Optional[ 

1485 AbstractSet[ColumnClause[Any]] 

1486 ] = None, 

1487 ) -> bool: 

1488 if isinstance(left, Join): 

1489 left_right = left.right 

1490 else: 

1491 left_right = None 

1492 

1493 constraints = cls._joincond_scan_left_right( 

1494 a=left, 

1495 b=right, 

1496 a_subset=left_right, 

1497 consider_as_foreign_keys=consider_as_foreign_keys, 

1498 ) 

1499 

1500 return bool(constraints) 

1501 

1502 @classmethod 

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

1504 def _joincond_scan_left_right( 

1505 cls, 

1506 a: FromClause, 

1507 a_subset: Optional[FromClause], 

1508 b: FromClause, 

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

1510 ) -> collections.defaultdict[ 

1511 Optional[ForeignKeyConstraint], 

1512 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1513 ]: 

1514 sql_util = util.preloaded.sql_util 

1515 

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

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

1518 

1519 constraints: collections.defaultdict[ 

1520 Optional[ForeignKeyConstraint], 

1521 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1522 ] = collections.defaultdict(list) 

1523 

1524 for left in (a_subset, a): 

1525 if left is None: 

1526 continue 

1527 for fk in sorted( 

1528 b.foreign_keys, 

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

1530 ): 

1531 if ( 

1532 consider_as_foreign_keys is not None 

1533 and fk.parent not in consider_as_foreign_keys 

1534 ): 

1535 continue 

1536 try: 

1537 col = fk.get_referent(left) 

1538 except exc.NoReferenceError as nrte: 

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

1540 if nrte.table_name in table_names: 

1541 raise 

1542 else: 

1543 continue 

1544 

1545 if col is not None: 

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

1547 if left is not b: 

1548 for fk in sorted( 

1549 left.foreign_keys, 

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

1551 ): 

1552 if ( 

1553 consider_as_foreign_keys is not None 

1554 and fk.parent not in consider_as_foreign_keys 

1555 ): 

1556 continue 

1557 try: 

1558 col = fk.get_referent(b) 

1559 except exc.NoReferenceError as nrte: 

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

1561 if nrte.table_name in table_names: 

1562 raise 

1563 else: 

1564 continue 

1565 

1566 if col is not None: 

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

1568 if constraints: 

1569 break 

1570 return constraints 

1571 

1572 @classmethod 

1573 def _joincond_trim_constraints( 

1574 cls, 

1575 a: FromClause, 

1576 b: FromClause, 

1577 constraints: Dict[Any, Any], 

1578 consider_as_foreign_keys: Optional[Any], 

1579 ) -> None: 

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

1581 # to include just those FKCs that match exactly to 

1582 # "consider_as_foreign_keys". 

1583 if consider_as_foreign_keys: 

1584 for const in list(constraints): 

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

1586 consider_as_foreign_keys 

1587 ): 

1588 del constraints[const] 

1589 

1590 # if still multiple constraints, but 

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

1592 if len(constraints) > 1: 

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

1594 if len(dedupe) == 1: 

1595 key = list(constraints)[0] 

1596 constraints = {key: constraints[key]} 

1597 

1598 if len(constraints) != 1: 

1599 raise exc.AmbiguousForeignKeysError( 

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

1601 "tables have more than one foreign key " 

1602 "constraint relationship between them. " 

1603 "Please specify the 'onclause' of this " 

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

1605 ) 

1606 

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

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

1609 :class:`_expression.Join`. 

1610 

1611 E.g.:: 

1612 

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

1614 

1615 stmt = stmt.select() 

1616 

1617 The above will produce a SQL string resembling: 

1618 

1619 .. sourcecode:: sql 

1620 

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

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

1623 

1624 """ 

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

1626 

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

1628 def _anonymous_fromclause( 

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

1630 ) -> TODO_Any: 

1631 sqlutil = util.preloaded.sql_util 

1632 if flat: 

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

1634 left_name = name # will recurse 

1635 else: 

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

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

1638 else: 

1639 left_name = name 

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

1641 right_name = name # will recurse 

1642 else: 

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

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

1645 else: 

1646 right_name = name 

1647 left_a, right_a = ( 

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

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

1650 ) 

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

1652 sqlutil.ClauseAdapter(right_a) 

1653 ) 

1654 

1655 return left_a.join( 

1656 right_a, 

1657 adapter.traverse(self.onclause), 

1658 isouter=self.isouter, 

1659 full=self.full, 

1660 ) 

1661 else: 

1662 return ( 

1663 self.select() 

1664 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1665 .correlate(None) 

1666 .alias(name) 

1667 ) 

1668 

1669 @util.ro_non_memoized_property 

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

1671 return itertools.chain( 

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

1673 ) 

1674 

1675 @util.ro_non_memoized_property 

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

1677 self_list: List[FromClause] = [self] 

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

1679 

1680 

1681class NoInit: 

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

1683 raise NotImplementedError( 

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

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

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

1687 "selectable objects." 

1688 % ( 

1689 self.__class__.__name__, 

1690 self.__class__.__name__.lower(), 

1691 self.__class__.__name__.lower(), 

1692 ) 

1693 ) 

1694 

1695 

1696class LateralFromClause(NamedFromClause): 

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

1698 

1699 

1700# FromClause -> 

1701# AliasedReturnsRows 

1702# -> Alias only for FromClause 

1703# -> Subquery only for SelectBase 

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

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

1706# w/ non-deprecated coercion 

1707# -> TableSample -> only for FromClause 

1708 

1709 

1710class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1712 selectables.""" 

1713 

1714 _is_from_container = True 

1715 

1716 _supports_derived_columns = False 

1717 

1718 element: ReturnsRows 

1719 

1720 _traverse_internals: _TraverseInternalsType = [ 

1721 ("element", InternalTraversal.dp_clauseelement), 

1722 ("name", InternalTraversal.dp_anon_name), 

1723 ] 

1724 

1725 @classmethod 

1726 def _construct( 

1727 cls, 

1728 selectable: Any, 

1729 *, 

1730 name: Optional[str] = None, 

1731 **kw: Any, 

1732 ) -> Self: 

1733 obj = cls.__new__(cls) 

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

1735 return obj 

1736 

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

1738 self.element = coercions.expect( 

1739 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1740 ) 

1741 self.element = selectable 

1742 self._orig_name = name 

1743 if name is None: 

1744 if ( 

1745 isinstance(selectable, FromClause) 

1746 and selectable.named_with_column 

1747 ): 

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

1749 if isinstance(name, _anonymous_label): 

1750 name = None 

1751 name = _anonymous_label.safe_construct( 

1752 os.urandom(10).hex(), name or "anon" 

1753 ) 

1754 self.name = name 

1755 

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

1757 super()._refresh_for_new_column(column) 

1758 self.element._refresh_for_new_column(column) 

1759 

1760 def _populate_column_collection( 

1761 self, 

1762 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

1763 primary_key: ColumnSet, 

1764 foreign_keys: Set[KeyedColumnElement[Any]], 

1765 ) -> None: 

1766 self.element._generate_fromclause_column_proxies( 

1767 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1768 ) 

1769 

1770 @util.ro_non_memoized_property 

1771 def description(self) -> str: 

1772 name = self.name 

1773 if isinstance(name, _anonymous_label): 

1774 return "anon_1" 

1775 

1776 return name 

1777 

1778 @util.ro_non_memoized_property 

1779 def implicit_returning(self) -> bool: 

1780 return self.element.implicit_returning # type: ignore 

1781 

1782 @property 

1783 def original(self) -> ReturnsRows: 

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

1785 return self.element 

1786 

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

1788 if fromclause in self._cloned_set: 

1789 return True 

1790 return self.element.is_derived_from(fromclause) 

1791 

1792 def _copy_internals( 

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

1794 ) -> None: 

1795 existing_element = self.element 

1796 

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

1798 

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

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

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

1802 # performance. 

1803 if existing_element is not self.element: 

1804 self._reset_column_collection() 

1805 

1806 @property 

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

1808 return [self] 

1809 

1810 

1811class FromClauseAlias(AliasedReturnsRows): 

1812 element: FromClause 

1813 

1814 @util.ro_non_memoized_property 

1815 def description(self) -> str: 

1816 name = self.name 

1817 if isinstance(name, _anonymous_label): 

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

1819 

1820 return name 

1821 

1822 

1823class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1825 

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

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

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

1829 

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

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

1832 method available 

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

1834 

1835 .. seealso:: 

1836 

1837 :meth:`_expression.FromClause.alias` 

1838 

1839 """ 

1840 

1841 __visit_name__ = "alias" 

1842 

1843 inherit_cache = True 

1844 

1845 element: FromClause 

1846 

1847 @classmethod 

1848 def _factory( 

1849 cls, 

1850 selectable: FromClause, 

1851 name: Optional[str] = None, 

1852 flat: bool = False, 

1853 ) -> NamedFromClause: 

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

1855 name=name, flat=flat 

1856 ) 

1857 

1858 

1859class TableValuedAlias(LateralFromClause, Alias): 

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

1861 

1862 This construct provides for a SQL function that returns columns 

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

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

1865 method, e.g.: 

1866 

1867 .. sourcecode:: pycon+sql 

1868 

1869 >>> from sqlalchemy import select, func 

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

1871 ... "value" 

1872 ... ) 

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

1874 {printsql}SELECT anon_1.value 

1875 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1876 

1877 .. versionadded:: 1.4.0b2 

1878 

1879 .. seealso:: 

1880 

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

1882 

1883 """ # noqa: E501 

1884 

1885 __visit_name__ = "table_valued_alias" 

1886 

1887 _supports_derived_columns = True 

1888 _render_derived = False 

1889 _render_derived_w_types = False 

1890 joins_implicitly = False 

1891 

1892 _traverse_internals: _TraverseInternalsType = [ 

1893 ("element", InternalTraversal.dp_clauseelement), 

1894 ("name", InternalTraversal.dp_anon_name), 

1895 ("_tableval_type", InternalTraversal.dp_type), 

1896 ("_render_derived", InternalTraversal.dp_boolean), 

1897 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1898 ] 

1899 

1900 def _init( 

1901 self, 

1902 selectable: Any, 

1903 *, 

1904 name: Optional[str] = None, 

1905 table_value_type: Optional[TableValueType] = None, 

1906 joins_implicitly: bool = False, 

1907 ) -> None: 

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

1909 

1910 self.joins_implicitly = joins_implicitly 

1911 self._tableval_type = ( 

1912 type_api.TABLEVALUE 

1913 if table_value_type is None 

1914 else table_value_type 

1915 ) 

1916 

1917 @HasMemoized.memoized_attribute 

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

1919 """Return a column expression representing this 

1920 :class:`_sql.TableValuedAlias`. 

1921 

1922 This accessor is used to implement the 

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

1924 method for further details. 

1925 

1926 E.g.: 

1927 

1928 .. sourcecode:: pycon+sql 

1929 

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

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

1932 

1933 .. seealso:: 

1934 

1935 :meth:`_functions.FunctionElement.column_valued` 

1936 

1937 """ 

1938 

1939 return TableValuedColumn(self, self._tableval_type) 

1940 

1941 def alias( 

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

1943 ) -> TableValuedAlias: 

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

1945 

1946 This creates a distinct FROM object that will be distinguished 

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

1948 

1949 """ 

1950 

1951 tva: TableValuedAlias = TableValuedAlias._construct( 

1952 self, 

1953 name=name, 

1954 table_value_type=self._tableval_type, 

1955 joins_implicitly=self.joins_implicitly, 

1956 ) 

1957 

1958 if self._render_derived: 

1959 tva._render_derived = True 

1960 tva._render_derived_w_types = self._render_derived_w_types 

1961 

1962 return tva 

1963 

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

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

1966 set, so that it renders as LATERAL. 

1967 

1968 .. seealso:: 

1969 

1970 :func:`_expression.lateral` 

1971 

1972 """ 

1973 tva = self.alias(name=name) 

1974 tva._is_lateral = True 

1975 return tva 

1976 

1977 def render_derived( 

1978 self, 

1979 name: Optional[str] = None, 

1980 with_types: bool = False, 

1981 ) -> TableValuedAlias: 

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

1983 

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

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

1986 

1987 .. sourcecode:: pycon+sql 

1988 

1989 >>> print( 

1990 ... select( 

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

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

1993 ... .render_derived() 

1994 ... ) 

1995 ... ) 

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

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

1998 

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

2000 the alias expression (this syntax currently applies to the 

2001 PostgreSQL database): 

2002 

2003 .. sourcecode:: pycon+sql 

2004 

2005 >>> print( 

2006 ... select( 

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

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

2009 ... .render_derived(with_types=True) 

2010 ... ) 

2011 ... ) 

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

2013 AS anon_1(a INTEGER, b VARCHAR) 

2014 

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

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

2017 

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

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

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

2021 

2022 """ # noqa: E501 

2023 

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

2025 # to the original object. otherwise you can have reuse of the 

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

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

2028 # (just saw it happen on CI) 

2029 

2030 # construct against original to prevent memory growth 

2031 # for repeated generations 

2032 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2033 self.element, 

2034 name=name, 

2035 table_value_type=self._tableval_type, 

2036 joins_implicitly=self.joins_implicitly, 

2037 ) 

2038 new_alias._render_derived = True 

2039 new_alias._render_derived_w_types = with_types 

2040 return new_alias 

2041 

2042 

2043class Lateral(FromClauseAlias, LateralFromClause): 

2044 """Represent a LATERAL subquery. 

2045 

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

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

2048 method available 

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

2050 

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

2052 PostgreSQL versions provide support for this keyword. 

2053 

2054 .. seealso:: 

2055 

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

2057 

2058 """ 

2059 

2060 __visit_name__ = "lateral" 

2061 _is_lateral = True 

2062 

2063 inherit_cache = True 

2064 

2065 @classmethod 

2066 def _factory( 

2067 cls, 

2068 selectable: Union[SelectBase, _FromClauseArgument], 

2069 name: Optional[str] = None, 

2070 ) -> LateralFromClause: 

2071 return coercions.expect( 

2072 roles.FromClauseRole, selectable, explicit_subquery=True 

2073 ).lateral(name=name) 

2074 

2075 

2076class TableSample(FromClauseAlias): 

2077 """Represent a TABLESAMPLE clause. 

2078 

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

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

2081 method 

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

2083 

2084 .. seealso:: 

2085 

2086 :func:`_expression.tablesample` 

2087 

2088 """ 

2089 

2090 __visit_name__ = "tablesample" 

2091 

2092 _traverse_internals: _TraverseInternalsType = ( 

2093 AliasedReturnsRows._traverse_internals 

2094 + [ 

2095 ("sampling", InternalTraversal.dp_clauseelement), 

2096 ("seed", InternalTraversal.dp_clauseelement), 

2097 ] 

2098 ) 

2099 

2100 @classmethod 

2101 def _factory( 

2102 cls, 

2103 selectable: _FromClauseArgument, 

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

2105 name: Optional[str] = None, 

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

2107 ) -> TableSample: 

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

2109 sampling, name=name, seed=seed 

2110 ) 

2111 

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

2113 def _init( # type: ignore[override] 

2114 self, 

2115 selectable: Any, 

2116 *, 

2117 name: Optional[str] = None, 

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

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

2120 ) -> None: 

2121 assert sampling is not None 

2122 functions = util.preloaded.sql_functions 

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

2124 sampling = functions.func.system(sampling) 

2125 

2126 self.sampling: Function[Any] = sampling 

2127 self.seed = seed 

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

2129 

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

2131 return self.sampling 

2132 

2133 

2134class CTE( 

2135 roles.DMLTableRole, 

2136 roles.IsCTERole, 

2137 Generative, 

2138 HasPrefixes, 

2139 HasSuffixes, 

2140 AliasedReturnsRows, 

2141): 

2142 """Represent a Common Table Expression. 

2143 

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

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

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

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

2148 :class:`_sql.Update` and 

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

2150 usage details on CTEs. 

2151 

2152 .. seealso:: 

2153 

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

2155 

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

2157 

2158 """ 

2159 

2160 __visit_name__ = "cte" 

2161 

2162 _traverse_internals: _TraverseInternalsType = ( 

2163 AliasedReturnsRows._traverse_internals 

2164 + [ 

2165 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2166 ("_restates", InternalTraversal.dp_clauseelement), 

2167 ("recursive", InternalTraversal.dp_boolean), 

2168 ("nesting", InternalTraversal.dp_boolean), 

2169 ] 

2170 + HasPrefixes._has_prefixes_traverse_internals 

2171 + HasSuffixes._has_suffixes_traverse_internals 

2172 ) 

2173 

2174 element: HasCTE 

2175 

2176 @classmethod 

2177 def _factory( 

2178 cls, 

2179 selectable: HasCTE, 

2180 name: Optional[str] = None, 

2181 recursive: bool = False, 

2182 ) -> CTE: 

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

2184 or Common Table Expression instance. 

2185 

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

2187 

2188 """ 

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

2190 name=name, recursive=recursive 

2191 ) 

2192 

2193 def _init( 

2194 self, 

2195 selectable: HasCTE, 

2196 *, 

2197 name: Optional[str] = None, 

2198 recursive: bool = False, 

2199 nesting: bool = False, 

2200 _cte_alias: Optional[CTE] = None, 

2201 _restates: Optional[CTE] = None, 

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

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

2204 ) -> None: 

2205 self.recursive = recursive 

2206 self.nesting = nesting 

2207 self._cte_alias = _cte_alias 

2208 # Keep recursivity reference with union/union_all 

2209 self._restates = _restates 

2210 if _prefixes: 

2211 self._prefixes = _prefixes 

2212 if _suffixes: 

2213 self._suffixes = _suffixes 

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

2215 

2216 def _populate_column_collection( 

2217 self, 

2218 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

2219 primary_key: ColumnSet, 

2220 foreign_keys: Set[KeyedColumnElement[Any]], 

2221 ) -> None: 

2222 if self._cte_alias is not None: 

2223 self._cte_alias._generate_fromclause_column_proxies( 

2224 self, 

2225 columns, 

2226 primary_key=primary_key, 

2227 foreign_keys=foreign_keys, 

2228 ) 

2229 else: 

2230 self.element._generate_fromclause_column_proxies( 

2231 self, 

2232 columns, 

2233 primary_key=primary_key, 

2234 foreign_keys=foreign_keys, 

2235 ) 

2236 

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

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

2239 :class:`_expression.CTE`. 

2240 

2241 This method is a CTE-specific specialization of the 

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

2243 

2244 .. seealso:: 

2245 

2246 :ref:`tutorial_using_aliases` 

2247 

2248 :func:`_expression.alias` 

2249 

2250 """ 

2251 return CTE._construct( 

2252 self.element, 

2253 name=name, 

2254 recursive=self.recursive, 

2255 nesting=self.nesting, 

2256 _cte_alias=self, 

2257 _prefixes=self._prefixes, 

2258 _suffixes=self._suffixes, 

2259 ) 

2260 

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

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

2263 of the original CTE against the given selectables provided 

2264 as positional arguments. 

2265 

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

2267 UNION. 

2268 

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

2270 

2271 .. seealso:: 

2272 

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

2274 

2275 """ 

2276 assert is_select_statement( 

2277 self.element 

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

2279 

2280 return CTE._construct( 

2281 self.element.union(*other), 

2282 name=self.name, 

2283 recursive=self.recursive, 

2284 nesting=self.nesting, 

2285 _restates=self, 

2286 _prefixes=self._prefixes, 

2287 _suffixes=self._suffixes, 

2288 ) 

2289 

2290 def union_all( 

2291 self, *other: _SelectStatementForCompoundArgument[Any] 

2292 ) -> CTE: 

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

2294 of the original CTE against the given selectables provided 

2295 as positional arguments. 

2296 

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

2298 UNION. 

2299 

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

2301 

2302 .. seealso:: 

2303 

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

2305 

2306 """ 

2307 

2308 assert is_select_statement( 

2309 self.element 

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

2311 

2312 return CTE._construct( 

2313 self.element.union_all(*other), 

2314 name=self.name, 

2315 recursive=self.recursive, 

2316 nesting=self.nesting, 

2317 _restates=self, 

2318 _prefixes=self._prefixes, 

2319 _suffixes=self._suffixes, 

2320 ) 

2321 

2322 def _get_reference_cte(self) -> CTE: 

2323 """ 

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

2325 Updated CTEs should still refer to the original CTE. 

2326 This function returns this reference identifier. 

2327 """ 

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

2329 

2330 

2331class _CTEOpts(NamedTuple): 

2332 nesting: bool 

2333 

2334 

2335class _ColumnsPlusNames(NamedTuple): 

2336 required_label_name: Optional[str] 

2337 """ 

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

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

2340 """ 

2341 

2342 proxy_key: Optional[str] 

2343 """ 

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

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

2346 select.selected_columns collection 

2347 """ 

2348 

2349 fallback_label_name: Optional[str] 

2350 """ 

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

2352 we have to render a label even though 

2353 required_label_name was not given 

2354 """ 

2355 

2356 column: Union[ColumnElement[Any], AbstractTextClause] 

2357 """ 

2358 the ColumnElement itself 

2359 """ 

2360 

2361 repeated: bool 

2362 """ 

2363 True if this is a duplicate of a previous column 

2364 in the list of columns 

2365 """ 

2366 

2367 

2368class SelectsRows(ReturnsRows): 

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

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

2371 

2372 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2373 

2374 def _generate_columns_plus_names( 

2375 self, 

2376 anon_for_dupe_key: bool, 

2377 cols: Optional[_SelectIterable] = None, 

2378 ) -> List[_ColumnsPlusNames]: 

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

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

2381 on a :class:`.FromClause`. 

2382 

2383 This is distinct from the _column_naming_convention generator that's 

2384 intended for population of the Select.selected_columns collection, 

2385 different rules. the collection returned here calls upon the 

2386 _column_naming_convention as well. 

2387 

2388 """ 

2389 

2390 if cols is None: 

2391 cols = self._all_selected_columns 

2392 

2393 key_naming_convention = SelectState._column_naming_convention( 

2394 self._label_style 

2395 ) 

2396 

2397 names = {} 

2398 

2399 result: List[_ColumnsPlusNames] = [] 

2400 result_append = result.append 

2401 

2402 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2403 label_style_none = self._label_style is LABEL_STYLE_NONE 

2404 

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

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

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

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

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

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

2411 dedupe_hash = 1 

2412 

2413 for c in cols: 

2414 repeated = False 

2415 

2416 if not c._render_label_in_columns_clause: 

2417 effective_name = required_label_name = fallback_label_name = ( 

2418 None 

2419 ) 

2420 elif label_style_none: 

2421 if TYPE_CHECKING: 

2422 assert is_column_element(c) 

2423 

2424 effective_name = required_label_name = None 

2425 fallback_label_name = c._non_anon_label or c._anon_name_label 

2426 else: 

2427 if TYPE_CHECKING: 

2428 assert is_column_element(c) 

2429 

2430 if table_qualified: 

2431 required_label_name = effective_name = ( 

2432 fallback_label_name 

2433 ) = c._tq_label 

2434 else: 

2435 effective_name = fallback_label_name = c._non_anon_label 

2436 required_label_name = None 

2437 

2438 if effective_name is None: 

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

2440 # not need _expression_label but it isn't 

2441 # giving us a clue when to use anon_label instead 

2442 expr_label = c._expression_label 

2443 if expr_label is None: 

2444 repeated = c._anon_name_label in names 

2445 names[c._anon_name_label] = c 

2446 effective_name = required_label_name = None 

2447 

2448 if repeated: 

2449 # here, "required_label_name" is sent as 

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

2451 if table_qualified: 

2452 fallback_label_name = ( 

2453 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2454 ) 

2455 dedupe_hash += 1 

2456 else: 

2457 fallback_label_name = c._dedupe_anon_label_idx( 

2458 dedupe_hash 

2459 ) 

2460 dedupe_hash += 1 

2461 else: 

2462 fallback_label_name = c._anon_name_label 

2463 else: 

2464 required_label_name = effective_name = ( 

2465 fallback_label_name 

2466 ) = expr_label 

2467 

2468 if effective_name is not None: 

2469 if TYPE_CHECKING: 

2470 assert is_column_element(c) 

2471 

2472 if effective_name in names: 

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

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

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

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

2477 # different column under the same name. apply 

2478 # disambiguating label 

2479 if table_qualified: 

2480 required_label_name = fallback_label_name = ( 

2481 c._anon_tq_label 

2482 ) 

2483 else: 

2484 required_label_name = fallback_label_name = ( 

2485 c._anon_name_label 

2486 ) 

2487 

2488 if anon_for_dupe_key and required_label_name in names: 

2489 # here, c._anon_tq_label is definitely unique to 

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

2491 # this should always be true. 

2492 # this is also an infrequent codepath because 

2493 # you need two levels of duplication to be here 

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

2495 

2496 # the column under the disambiguating label is 

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

2498 # subsequent occurrences of the column so that the 

2499 # original stays non-ambiguous 

2500 if table_qualified: 

2501 required_label_name = fallback_label_name = ( 

2502 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2503 ) 

2504 dedupe_hash += 1 

2505 else: 

2506 required_label_name = fallback_label_name = ( 

2507 c._dedupe_anon_label_idx(dedupe_hash) 

2508 ) 

2509 dedupe_hash += 1 

2510 repeated = True 

2511 else: 

2512 names[required_label_name] = c 

2513 elif anon_for_dupe_key: 

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

2515 # label so that the original stays non-ambiguous 

2516 if table_qualified: 

2517 required_label_name = fallback_label_name = ( 

2518 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2519 ) 

2520 dedupe_hash += 1 

2521 else: 

2522 required_label_name = fallback_label_name = ( 

2523 c._dedupe_anon_label_idx(dedupe_hash) 

2524 ) 

2525 dedupe_hash += 1 

2526 repeated = True 

2527 else: 

2528 names[effective_name] = c 

2529 

2530 result_append( 

2531 _ColumnsPlusNames( 

2532 required_label_name, 

2533 key_naming_convention(c), 

2534 fallback_label_name, 

2535 c, 

2536 repeated, 

2537 ) 

2538 ) 

2539 

2540 return result 

2541 

2542 

2543class HasCTE(roles.HasCTERole, SelectsRows): 

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

2545 

2546 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2547 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2548 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2549 ] 

2550 

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

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

2553 

2554 name_cte_columns: bool = False 

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

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

2557 

2558 .. versionadded:: 2.0.42 

2559 

2560 """ 

2561 

2562 @_generative 

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

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

2565 

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

2567 the parent statement such that they will each be unconditionally 

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

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

2570 

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

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

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

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

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

2576 statement. 

2577 

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

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

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

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

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

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

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

2585 larger statement. 

2586 

2587 E.g.:: 

2588 

2589 from sqlalchemy import table, column, select 

2590 

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

2592 

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

2594 

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

2596 

2597 Would render: 

2598 

2599 .. sourcecode:: sql 

2600 

2601 WITH anon_1 AS ( 

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

2603 ) 

2604 SELECT t.c1, t.c2 

2605 FROM t 

2606 

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

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

2609 statement. 

2610 

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

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

2613 

2614 from sqlalchemy import table, column 

2615 from sqlalchemy.dialects.postgresql import insert 

2616 

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

2618 

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

2620 

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

2622 update_statement = insert_stmt.on_conflict_do_update( 

2623 index_elements=[t.c.c1], 

2624 set_={ 

2625 "c1": insert_stmt.excluded.c1, 

2626 "c2": insert_stmt.excluded.c2, 

2627 }, 

2628 ).add_cte(delete_statement_cte) 

2629 

2630 print(update_statement) 

2631 

2632 The above statement renders as: 

2633 

2634 .. sourcecode:: sql 

2635 

2636 WITH deletions AS ( 

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

2638 ) 

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

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

2641 

2642 .. versionadded:: 1.4.21 

2643 

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

2645 

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

2647 

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

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

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

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

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

2653 this statement when this flag is given. 

2654 

2655 .. versionadded:: 2.0 

2656 

2657 .. seealso:: 

2658 

2659 :paramref:`.HasCTE.cte.nesting` 

2660 

2661 

2662 """ # noqa: E501 

2663 opt = _CTEOpts(nest_here) 

2664 for cte in ctes: 

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

2666 self._independent_ctes += (cte,) 

2667 self._independent_ctes_opts += (opt,) 

2668 return self 

2669 

2670 def cte( 

2671 self, 

2672 name: Optional[str] = None, 

2673 recursive: bool = False, 

2674 nesting: bool = False, 

2675 ) -> CTE: 

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

2677 or Common Table Expression instance. 

2678 

2679 Common table expressions are a SQL standard whereby SELECT 

2680 statements can draw upon secondary statements specified along 

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

2682 Special semantics regarding UNION can also be employed to 

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

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

2685 

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

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

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

2689 CTE rows. 

2690 

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

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

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

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

2695 

2696 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2698 method may be 

2699 used to establish these. 

2700 

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

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

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

2704 compile time. 

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

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

2707 conjunction with UNION ALL in order to derive rows 

2708 from those already selected. 

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

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

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

2712 :paramref:`.HasCTE.add_cte.nest_here` 

2713 parameter may also be used to more carefully 

2714 control the exact placement of a particular CTE. 

2715 

2716 .. versionadded:: 1.4.24 

2717 

2718 .. seealso:: 

2719 

2720 :meth:`.HasCTE.add_cte` 

2721 

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

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

2724 as well as additional examples. 

2725 

2726 Example 1, non recursive:: 

2727 

2728 from sqlalchemy import ( 

2729 Table, 

2730 Column, 

2731 String, 

2732 Integer, 

2733 MetaData, 

2734 select, 

2735 func, 

2736 ) 

2737 

2738 metadata = MetaData() 

2739 

2740 orders = Table( 

2741 "orders", 

2742 metadata, 

2743 Column("region", String), 

2744 Column("amount", Integer), 

2745 Column("product", String), 

2746 Column("quantity", Integer), 

2747 ) 

2748 

2749 regional_sales = ( 

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

2751 .group_by(orders.c.region) 

2752 .cte("regional_sales") 

2753 ) 

2754 

2755 

2756 top_regions = ( 

2757 select(regional_sales.c.region) 

2758 .where( 

2759 regional_sales.c.total_sales 

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

2761 ) 

2762 .cte("top_regions") 

2763 ) 

2764 

2765 statement = ( 

2766 select( 

2767 orders.c.region, 

2768 orders.c.product, 

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

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

2771 ) 

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

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

2774 ) 

2775 

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

2777 

2778 Example 2, WITH RECURSIVE:: 

2779 

2780 from sqlalchemy import ( 

2781 Table, 

2782 Column, 

2783 String, 

2784 Integer, 

2785 MetaData, 

2786 select, 

2787 func, 

2788 ) 

2789 

2790 metadata = MetaData() 

2791 

2792 parts = Table( 

2793 "parts", 

2794 metadata, 

2795 Column("part", String), 

2796 Column("sub_part", String), 

2797 Column("quantity", Integer), 

2798 ) 

2799 

2800 included_parts = ( 

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

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

2803 .cte(recursive=True) 

2804 ) 

2805 

2806 

2807 incl_alias = included_parts.alias() 

2808 parts_alias = parts.alias() 

2809 included_parts = included_parts.union_all( 

2810 select( 

2811 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2813 ) 

2814 

2815 statement = select( 

2816 included_parts.c.sub_part, 

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

2818 ).group_by(included_parts.c.sub_part) 

2819 

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

2821 

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

2823 

2824 from datetime import date 

2825 from sqlalchemy import ( 

2826 MetaData, 

2827 Table, 

2828 Column, 

2829 Integer, 

2830 Date, 

2831 select, 

2832 literal, 

2833 and_, 

2834 exists, 

2835 ) 

2836 

2837 metadata = MetaData() 

2838 

2839 visitors = Table( 

2840 "visitors", 

2841 metadata, 

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

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

2844 Column("count", Integer), 

2845 ) 

2846 

2847 # add 5 visitors for the product_id == 1 

2848 product_id = 1 

2849 day = date.today() 

2850 count = 5 

2851 

2852 update_cte = ( 

2853 visitors.update() 

2854 .where( 

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

2856 ) 

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

2858 .returning(literal(1)) 

2859 .cte("update_cte") 

2860 ) 

2861 

2862 upsert = visitors.insert().from_select( 

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

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

2865 ~exists(update_cte.select()) 

2866 ), 

2867 ) 

2868 

2869 connection.execute(upsert) 

2870 

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

2872 

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

2874 

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

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

2877 "value_a", nesting=True 

2878 ) 

2879 

2880 # Nesting CTEs takes ascendency locally 

2881 # over the CTEs at a higher level 

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

2883 

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

2885 

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

2887 shown with inline parameters below as: 

2888 

2889 .. sourcecode:: sql 

2890 

2891 WITH 

2892 value_a AS 

2893 (SELECT 'root' AS n), 

2894 value_b AS 

2895 (WITH value_a AS 

2896 (SELECT 'nesting' AS n) 

2897 SELECT value_a.n AS n FROM value_a) 

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

2899 FROM value_a, value_b 

2900 

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

2902 as follows (SQLAlchemy 2.0 and above):: 

2903 

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

2905 

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

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

2908 

2909 # Nesting CTEs takes ascendency locally 

2910 # over the CTEs at a higher level 

2911 value_b = ( 

2912 select(value_a_nested.c.n) 

2913 .add_cte(value_a_nested, nest_here=True) 

2914 .cte("value_b") 

2915 ) 

2916 

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

2918 

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

2920 

2921 edge = Table( 

2922 "edge", 

2923 metadata, 

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

2925 Column("left", Integer), 

2926 Column("right", Integer), 

2927 ) 

2928 

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

2930 

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

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

2933 ) 

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

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

2936 ) 

2937 

2938 subgraph_cte = root_node.union(left_edge, right_edge) 

2939 

2940 subgraph = select(subgraph_cte) 

2941 

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

2943 

2944 .. sourcecode:: sql 

2945 

2946 WITH RECURSIVE nodes(node) AS ( 

2947 SELECT 1 AS node 

2948 UNION 

2949 SELECT edge."left" AS "left" 

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

2951 UNION 

2952 SELECT edge."right" AS "right" 

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

2954 ) 

2955 SELECT nodes.node FROM nodes 

2956 

2957 .. seealso:: 

2958 

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

2960 :meth:`_expression.HasCTE.cte`. 

2961 

2962 """ # noqa: E501 

2963 return CTE._construct( 

2964 self, name=name, recursive=recursive, nesting=nesting 

2965 ) 

2966 

2967 

2968class Subquery(AliasedReturnsRows): 

2969 """Represent a subquery of a SELECT. 

2970 

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

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

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

2974 :class:`_expression.SelectBase` subclass 

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

2976 :class:`_expression.CompoundSelect`, and 

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

2978 it represents the 

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

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

2981 

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

2983 :class:`_expression.Alias` 

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

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

2986 :class:`_expression.Alias` always 

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

2988 :class:`.Subquery` 

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

2990 

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

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

2993 statement. 

2994 

2995 """ 

2996 

2997 __visit_name__ = "subquery" 

2998 

2999 _is_subquery = True 

3000 

3001 inherit_cache = True 

3002 

3003 element: SelectBase 

3004 

3005 @classmethod 

3006 def _factory( 

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

3008 ) -> Subquery: 

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

3010 

3011 return coercions.expect( 

3012 roles.SelectStatementRole, selectable 

3013 ).subquery(name=name) 

3014 

3015 @util.deprecated( 

3016 "1.4", 

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

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

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

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

3021 ":func:`_expression.select` " 

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

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

3024 ) 

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

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

3027 

3028 

3029class FromGrouping(GroupedElement, FromClause): 

3030 """Represent a grouping of a FROM clause""" 

3031 

3032 _traverse_internals: _TraverseInternalsType = [ 

3033 ("element", InternalTraversal.dp_clauseelement) 

3034 ] 

3035 

3036 element: FromClause 

3037 

3038 def __init__(self, element: FromClause): 

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

3040 

3041 @util.ro_non_memoized_property 

3042 def columns( 

3043 self, 

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

3045 return self.element.columns 

3046 

3047 @util.ro_non_memoized_property 

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

3049 return self.element.columns 

3050 

3051 @property 

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

3053 return self.element.primary_key 

3054 

3055 @property 

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

3057 return self.element.foreign_keys 

3058 

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

3060 return self.element.is_derived_from(fromclause) 

3061 

3062 def alias( 

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

3064 ) -> NamedFromGrouping: 

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

3066 

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

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

3069 

3070 @util.ro_non_memoized_property 

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

3072 return self.element._hide_froms 

3073 

3074 @util.ro_non_memoized_property 

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

3076 return self.element._from_objects 

3077 

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

3079 return {"element": self.element} 

3080 

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

3082 self.element = state["element"] 

3083 

3084 if TYPE_CHECKING: 

3085 

3086 def self_group( 

3087 self, against: Optional[OperatorType] = None 

3088 ) -> Self: ... 

3089 

3090 

3091class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3093 

3094 .. versionadded:: 2.0 

3095 

3096 """ 

3097 

3098 inherit_cache = True 

3099 

3100 if TYPE_CHECKING: 

3101 

3102 def self_group( 

3103 self, against: Optional[OperatorType] = None 

3104 ) -> Self: ... 

3105 

3106 

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

3108 """Represents a minimal "table" construct. 

3109 

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

3111 collection of columns, which are typically produced 

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

3113 

3114 from sqlalchemy import table, column 

3115 

3116 user = table( 

3117 "user", 

3118 column("id"), 

3119 column("name"), 

3120 column("description"), 

3121 ) 

3122 

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

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

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

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

3127 

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

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

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

3131 It's useful 

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

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

3134 is not on hand. 

3135 

3136 """ 

3137 

3138 __visit_name__ = "table" 

3139 

3140 _traverse_internals: _TraverseInternalsType = [ 

3141 ( 

3142 "columns", 

3143 InternalTraversal.dp_fromclause_canonical_column_collection, 

3144 ), 

3145 ("name", InternalTraversal.dp_string), 

3146 ("schema", InternalTraversal.dp_string), 

3147 ] 

3148 

3149 _is_table = True 

3150 

3151 fullname: str 

3152 

3153 implicit_returning = False 

3154 """:class:`_expression.TableClause` 

3155 doesn't support having a primary key or column 

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

3157 

3158 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3159 

3160 @util.ro_memoized_property 

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

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

3163 return None 

3164 

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

3166 super().__init__() 

3167 self.name = name 

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

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

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

3171 for c in columns: 

3172 self.append_column(c) 

3173 

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

3175 if schema is not None: 

3176 self.schema = schema 

3177 if self.schema is not None: 

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

3179 else: 

3180 self.fullname = self.name 

3181 if kw: 

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

3183 

3184 if TYPE_CHECKING: 

3185 

3186 @util.ro_non_memoized_property 

3187 def columns( 

3188 self, 

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

3190 

3191 @util.ro_non_memoized_property 

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

3193 

3194 def __str__(self) -> str: 

3195 if self.schema is not None: 

3196 return self.schema + "." + self.name 

3197 else: 

3198 return self.name 

3199 

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

3201 pass 

3202 

3203 @util.ro_memoized_property 

3204 def description(self) -> str: 

3205 return self.name 

3206 

3207 def _insert_col_impl( 

3208 self, 

3209 c: ColumnClause[Any], 

3210 *, 

3211 index: Optional[int] = None, 

3212 ) -> None: 

3213 existing = c.table 

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

3215 raise exc.ArgumentError( 

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

3217 % (c.key, existing) 

3218 ) 

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

3220 c.table = self 

3221 

3222 def append_column(self, column: ColumnClause[Any]) -> None: 

3223 """Append a :class:`.ColumnClause` to this :class:`.TableClause`.""" 

3224 self._insert_col_impl(column) 

3225 

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

3227 """Insert a :class:`.ColumnClause` to this :class:`.TableClause` at 

3228 a specific position. 

3229 

3230 .. versionadded:: 2.1 

3231 

3232 """ 

3233 self._insert_col_impl(column, index=index) 

3234 

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

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

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

3238 :class:`_expression.TableClause`. 

3239 

3240 E.g.:: 

3241 

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

3243 

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

3245 

3246 """ 

3247 

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

3249 

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

3251 def update(self) -> Update: 

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

3253 :class:`_expression.TableClause`. 

3254 

3255 E.g.:: 

3256 

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

3258 

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

3260 

3261 """ 

3262 return util.preloaded.sql_dml.Update( 

3263 self, 

3264 ) 

3265 

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

3267 def delete(self) -> Delete: 

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

3269 :class:`_expression.TableClause`. 

3270 

3271 E.g.:: 

3272 

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

3274 

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

3276 

3277 """ 

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

3279 

3280 @util.ro_non_memoized_property 

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

3282 return [self] 

3283 

3284 

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

3286 

3287 

3288class ForUpdateArg(ClauseElement): 

3289 _traverse_internals: _TraverseInternalsType = [ 

3290 ("of", InternalTraversal.dp_clauseelement_list), 

3291 ("nowait", InternalTraversal.dp_boolean), 

3292 ("read", InternalTraversal.dp_boolean), 

3293 ("skip_locked", InternalTraversal.dp_boolean), 

3294 ("key_share", InternalTraversal.dp_boolean), 

3295 ] 

3296 

3297 of: Optional[Sequence[ClauseElement]] 

3298 nowait: bool 

3299 read: bool 

3300 skip_locked: bool 

3301 

3302 @classmethod 

3303 def _from_argument( 

3304 cls, with_for_update: ForUpdateParameter 

3305 ) -> Optional[ForUpdateArg]: 

3306 if isinstance(with_for_update, ForUpdateArg): 

3307 return with_for_update 

3308 elif with_for_update in (None, False): 

3309 return None 

3310 elif with_for_update is True: 

3311 return ForUpdateArg() 

3312 else: 

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

3314 

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

3316 return ( 

3317 isinstance(other, ForUpdateArg) 

3318 and other.nowait == self.nowait 

3319 and other.read == self.read 

3320 and other.skip_locked == self.skip_locked 

3321 and other.key_share == self.key_share 

3322 and other.of is self.of 

3323 ) 

3324 

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

3326 return not self.__eq__(other) 

3327 

3328 def __hash__(self) -> int: 

3329 return id(self) 

3330 

3331 def __init__( 

3332 self, 

3333 *, 

3334 nowait: bool = False, 

3335 read: bool = False, 

3336 of: Optional[_ForUpdateOfArgument] = None, 

3337 skip_locked: bool = False, 

3338 key_share: bool = False, 

3339 ): 

3340 """Represents arguments specified to 

3341 :meth:`_expression.Select.for_update`. 

3342 

3343 """ 

3344 

3345 self.nowait = nowait 

3346 self.read = read 

3347 self.skip_locked = skip_locked 

3348 self.key_share = key_share 

3349 if of is not None: 

3350 self.of = [ 

3351 coercions.expect(roles.ColumnsClauseRole, elem) 

3352 for elem in util.to_list(of) 

3353 ] 

3354 else: 

3355 self.of = None 

3356 

3357 

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

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

3360 in a statement. 

3361 

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

3363 :func:`_expression.values` function. 

3364 

3365 .. versionadded:: 1.4 

3366 

3367 """ 

3368 

3369 __visit_name__ = "values" 

3370 

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

3372 _column_args: Tuple[NamedColumn[Any], ...] 

3373 

3374 _unnamed: bool 

3375 _traverse_internals: _TraverseInternalsType = [ 

3376 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3377 ("_data", InternalTraversal.dp_dml_multi_values), 

3378 ("name", InternalTraversal.dp_string), 

3379 ("literal_binds", InternalTraversal.dp_boolean), 

3380 ] + HasCTE._has_ctes_traverse_internals 

3381 

3382 name_cte_columns = True 

3383 

3384 def __init__( 

3385 self, 

3386 *columns: _OnlyColumnArgument[Any], 

3387 name: Optional[str] = None, 

3388 literal_binds: bool = False, 

3389 ): 

3390 super().__init__() 

3391 self._column_args = tuple( 

3392 coercions.expect(roles.LabeledColumnExprRole, col) 

3393 for col in columns 

3394 ) 

3395 

3396 if name is None: 

3397 self._unnamed = True 

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

3399 else: 

3400 self._unnamed = False 

3401 self.name = name 

3402 self.literal_binds = literal_binds 

3403 self.named_with_column = not self._unnamed 

3404 

3405 @property 

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

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

3408 

3409 @util.ro_non_memoized_property 

3410 def _all_selected_columns(self) -> _SelectIterable: 

3411 return self._column_args 

3412 

3413 @_generative 

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

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

3416 construct that is a copy of this 

3417 one with the given name. 

3418 

3419 This method is a VALUES-specific specialization of the 

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

3421 

3422 .. seealso:: 

3423 

3424 :ref:`tutorial_using_aliases` 

3425 

3426 :func:`_expression.alias` 

3427 

3428 """ 

3429 non_none_name: str 

3430 

3431 if name is None: 

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

3433 else: 

3434 non_none_name = name 

3435 

3436 self.name = non_none_name 

3437 self.named_with_column = True 

3438 self._unnamed = False 

3439 return self 

3440 

3441 @_generative 

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

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

3444 so that 

3445 it renders as LATERAL. 

3446 

3447 .. seealso:: 

3448 

3449 :func:`_expression.lateral` 

3450 

3451 """ 

3452 non_none_name: str 

3453 

3454 if name is None: 

3455 non_none_name = self.name 

3456 else: 

3457 non_none_name = name 

3458 

3459 self._is_lateral = True 

3460 self.name = non_none_name 

3461 self._unnamed = False 

3462 return self 

3463 

3464 @_generative 

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

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

3467 adding the given data to the data list. 

3468 

3469 E.g.:: 

3470 

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

3472 

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

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

3475 constructor. 

3476 

3477 """ 

3478 

3479 self._data += (values,) 

3480 return self 

3481 

3482 def scalar_values(self) -> ScalarValues: 

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

3484 COLUMN element in a statement. 

3485 

3486 .. versionadded:: 2.0.0b4 

3487 

3488 """ 

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

3490 

3491 def _populate_column_collection( 

3492 self, 

3493 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

3494 primary_key: ColumnSet, 

3495 foreign_keys: Set[KeyedColumnElement[Any]], 

3496 ) -> None: 

3497 for c in self._column_args: 

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

3499 _, c = c._make_proxy( 

3500 self, primary_key=primary_key, foreign_keys=foreign_keys 

3501 ) 

3502 else: 

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

3504 # no memoizations of other FROM clauses. 

3505 # see test_values.py -> test_auto_proxy_select_direct_col 

3506 c._reset_memoizations() 

3507 columns.add(c) 

3508 c.table = self 

3509 

3510 @util.ro_non_memoized_property 

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

3512 return [self] 

3513 

3514 

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

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

3517 COLUMN element in a statement. 

3518 

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

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

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

3522 an ``IN`` or ``NOT IN`` condition. 

3523 

3524 .. versionadded:: 2.0.0b4 

3525 

3526 """ 

3527 

3528 __visit_name__ = "scalar_values" 

3529 

3530 _traverse_internals: _TraverseInternalsType = [ 

3531 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3532 ("_data", InternalTraversal.dp_dml_multi_values), 

3533 ("literal_binds", InternalTraversal.dp_boolean), 

3534 ] 

3535 

3536 def __init__( 

3537 self, 

3538 columns: Sequence[NamedColumn[Any]], 

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

3540 literal_binds: bool, 

3541 ): 

3542 super().__init__() 

3543 self._column_args = columns 

3544 self._data = data 

3545 self.literal_binds = literal_binds 

3546 

3547 @property 

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

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

3550 

3551 def __clause_element__(self) -> ScalarValues: 

3552 return self 

3553 

3554 if TYPE_CHECKING: 

3555 

3556 def self_group( 

3557 self, against: Optional[OperatorType] = None 

3558 ) -> Self: ... 

3559 

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

3561 

3562 

3563class SelectBase( 

3564 roles.SelectStatementRole, 

3565 roles.DMLSelectRole, 

3566 roles.CompoundElementRole, 

3567 roles.InElementRole, 

3568 HasCTE, 

3569 SupportsCloneAnnotations, 

3570 Selectable, 

3571): 

3572 """Base class for SELECT statements. 

3573 

3574 

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

3576 :class:`_expression.CompoundSelect` and 

3577 :class:`_expression.TextualSelect`. 

3578 

3579 

3580 """ 

3581 

3582 _is_select_base = True 

3583 is_select = True 

3584 

3585 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3586 

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

3588 self._reset_memoizations() 

3589 

3590 @util.ro_non_memoized_property 

3591 def selected_columns( 

3592 self, 

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

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

3595 representing the columns that 

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

3597 

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

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

3600 within this collection cannot be directly nested inside another SELECT 

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

3602 necessary parenthesization required by SQL. 

3603 

3604 .. note:: 

3605 

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

3607 include expressions established in the columns clause using the 

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

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

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

3611 construct. 

3612 

3613 .. seealso:: 

3614 

3615 :attr:`_sql.Select.selected_columns` 

3616 

3617 .. versionadded:: 1.4 

3618 

3619 """ 

3620 raise NotImplementedError() 

3621 

3622 def _generate_fromclause_column_proxies( 

3623 self, 

3624 subquery: FromClause, 

3625 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

3626 primary_key: ColumnSet, 

3627 foreign_keys: Set[KeyedColumnElement[Any]], 

3628 *, 

3629 proxy_compound_columns: Optional[ 

3630 Iterable[Sequence[ColumnElement[Any]]] 

3631 ] = None, 

3632 ) -> None: 

3633 raise NotImplementedError() 

3634 

3635 @util.ro_non_memoized_property 

3636 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3639 constructs. 

3640 

3641 .. versionadded:: 1.4.12 

3642 

3643 .. seealso:: 

3644 

3645 :attr:`_sql.SelectBase.exported_columns` 

3646 

3647 """ 

3648 raise NotImplementedError() 

3649 

3650 @property 

3651 def exported_columns( 

3652 self, 

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

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

3655 that represents the "exported" 

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

3657 :class:`_sql.TextClause` constructs. 

3658 

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

3660 object are synonymous 

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

3662 

3663 .. versionadded:: 1.4 

3664 

3665 .. seealso:: 

3666 

3667 :attr:`_expression.Select.exported_columns` 

3668 

3669 :attr:`_expression.Selectable.exported_columns` 

3670 

3671 :attr:`_expression.FromClause.exported_columns` 

3672 

3673 

3674 """ 

3675 return self.selected_columns._as_readonly() 

3676 

3677 def get_label_style(self) -> SelectLabelStyle: 

3678 """ 

3679 Retrieve the current label style. 

3680 

3681 Implemented by subclasses. 

3682 

3683 """ 

3684 raise NotImplementedError() 

3685 

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

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

3688 

3689 Implemented by subclasses. 

3690 

3691 """ 

3692 

3693 raise NotImplementedError() 

3694 

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

3696 raise NotImplementedError() 

3697 

3698 @util.deprecated( 

3699 "1.4", 

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

3701 "method is deprecated and will be " 

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

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

3704 ) 

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

3706 return self.scalar_subquery() 

3707 

3708 def exists(self) -> Exists: 

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

3710 which can be used as a column expression. 

3711 

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

3713 

3714 .. seealso:: 

3715 

3716 :func:`_sql.exists` 

3717 

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

3719 

3720 .. versionadded:: 1.4 

3721 

3722 """ 

3723 return Exists(self) 

3724 

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

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

3727 used as a column expression. 

3728 

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

3730 

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

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

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

3734 an enclosing SELECT. 

3735 

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

3737 subquery that can be produced using the 

3738 :meth:`_expression.SelectBase.subquery` 

3739 method. 

3740 

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

3742 :meth:`_expression.SelectBase.scalar_subquery`. 

3743 

3744 .. seealso:: 

3745 

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

3747 

3748 """ 

3749 if self._label_style is not LABEL_STYLE_NONE: 

3750 self = self.set_label_style(LABEL_STYLE_NONE) 

3751 

3752 return ScalarSelect(self) 

3753 

3754 def label(self, name: Optional[str]) -> Label[Any]: 

3755 """Return a 'scalar' representation of this selectable, embedded as a 

3756 subquery with a label. 

3757 

3758 .. seealso:: 

3759 

3760 :meth:`_expression.SelectBase.scalar_subquery`. 

3761 

3762 """ 

3763 return self.scalar_subquery().label(name) 

3764 

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

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

3767 

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

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

3770 

3771 .. seealso:: 

3772 

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

3774 

3775 """ 

3776 return Lateral._factory(self, name) 

3777 

3778 def subquery(self, name: Optional[str] = None) -> Subquery: 

3779 """Return a subquery of this :class:`_expression.SelectBase`. 

3780 

3781 A subquery is from a SQL perspective a parenthesized, named 

3782 construct that can be placed in the FROM clause of another 

3783 SELECT statement. 

3784 

3785 Given a SELECT statement such as:: 

3786 

3787 stmt = select(table.c.id, table.c.name) 

3788 

3789 The above statement might look like: 

3790 

3791 .. sourcecode:: sql 

3792 

3793 SELECT table.id, table.name FROM table 

3794 

3795 The subquery form by itself renders the same way, however when 

3796 embedded into the FROM clause of another SELECT statement, it becomes 

3797 a named sub-element:: 

3798 

3799 subq = stmt.subquery() 

3800 new_stmt = select(subq) 

3801 

3802 The above renders as: 

3803 

3804 .. sourcecode:: sql 

3805 

3806 SELECT anon_1.id, anon_1.name 

3807 FROM (SELECT table.id, table.name FROM table) AS anon_1 

3808 

3809 Historically, :meth:`_expression.SelectBase.subquery` 

3810 is equivalent to calling 

3811 the :meth:`_expression.FromClause.alias` 

3812 method on a FROM object; however, 

3813 as a :class:`_expression.SelectBase` 

3814 object is not directly FROM object, 

3815 the :meth:`_expression.SelectBase.subquery` 

3816 method provides clearer semantics. 

3817 

3818 .. versionadded:: 1.4 

3819 

3820 """ 

3821 

3822 return Subquery._construct( 

3823 self._ensure_disambiguated_names(), name=name 

3824 ) 

3825 

3826 @util.preload_module("sqlalchemy.sql.ddl") 

3827 def into( 

3828 self, 

3829 target: str, 

3830 *, 

3831 metadata: Optional["MetaData"] = None, 

3832 schema: Optional[str] = None, 

3833 temporary: bool = False, 

3834 if_not_exists: bool = False, 

3835 ) -> CreateTableAs: 

3836 """Create a :class:`_schema.CreateTableAs` construct from this SELECT. 

3837 

3838 This method provides a convenient way to create a ``CREATE TABLE ... 

3839 AS`` statement from a SELECT, as well as compound SELECTs like UNION. 

3840 The new table will be created with columns matching the SELECT list. 

3841 

3842 Supported on all included backends, the construct emits 

3843 ``CREATE TABLE...AS`` for all backends except SQL Server, which instead 

3844 emits a ``SELECT..INTO`` statement. 

3845 

3846 e.g.:: 

3847 

3848 from sqlalchemy import select 

3849 

3850 # Create a new table from a SELECT 

3851 stmt = ( 

3852 select(users.c.id, users.c.name) 

3853 .where(users.c.status == "active") 

3854 .into("active_users") 

3855 ) 

3856 

3857 with engine.begin() as conn: 

3858 conn.execute(stmt) 

3859 

3860 # With optional flags 

3861 stmt = ( 

3862 select(users.c.id) 

3863 .where(users.c.status == "inactive") 

3864 .into("inactive_users", schema="analytics", if_not_exists=True) 

3865 ) 

3866 

3867 .. versionadded:: 2.1 

3868 

3869 :param target: Name of the table to create as a string. Must be 

3870 unqualified; use the ``schema`` parameter for qualification. 

3871 

3872 :param metadata: :class:`_schema.MetaData`, optional 

3873 If provided, the :class:`_schema.Table` object available via the 

3874 :attr:`.CreateTableAs.table` attribute will be associated with this 

3875 :class:`.MetaData`. Otherwise, a new, empty :class:`.MetaData` 

3876 is created. 

3877 

3878 :param schema: Optional schema name for the new table. 

3879 

3880 :param temporary: If True, create a temporary table where supported 

3881 

3882 :param if_not_exists: If True, add IF NOT EXISTS clause where supported 

3883 

3884 :return: A :class:`_schema.CreateTableAs` construct. 

3885 

3886 .. seealso:: 

3887 

3888 :ref:`metadata_create_table_as` - in :ref:`metadata_toplevel` 

3889 

3890 :class:`_schema.CreateTableAs` 

3891 

3892 """ 

3893 sql_ddl = util.preloaded.sql_ddl 

3894 

3895 return sql_ddl.CreateTableAs( 

3896 self, 

3897 target, 

3898 metadata=metadata, 

3899 schema=schema, 

3900 temporary=temporary, 

3901 if_not_exists=if_not_exists, 

3902 ) 

3903 

3904 def _ensure_disambiguated_names(self) -> Self: 

3905 """Ensure that the names generated by this selectbase will be 

3906 disambiguated in some way, if possible. 

3907 

3908 """ 

3909 

3910 raise NotImplementedError() 

3911 

3912 def alias( 

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

3914 ) -> Subquery: 

3915 """Return a named subquery against this 

3916 :class:`_expression.SelectBase`. 

3917 

3918 For a :class:`_expression.SelectBase` (as opposed to a 

3919 :class:`_expression.FromClause`), 

3920 this returns a :class:`.Subquery` object which behaves mostly the 

3921 same as the :class:`_expression.Alias` object that is used with a 

3922 :class:`_expression.FromClause`. 

3923 

3924 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3925 method is now 

3926 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3927 

3928 """ 

3929 return self.subquery(name=name) 

3930 

3931 

3932_SB = TypeVar("_SB", bound=SelectBase) 

3933 

3934 

3935class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3936 """Represent a grouping of a :class:`_expression.SelectBase`. 

3937 

3938 This differs from :class:`.Subquery` in that we are still 

3939 an "inner" SELECT statement, this is strictly for grouping inside of 

3940 compound selects. 

3941 

3942 """ 

3943 

3944 __visit_name__ = "select_statement_grouping" 

3945 _traverse_internals: _TraverseInternalsType = [ 

3946 ("element", InternalTraversal.dp_clauseelement) 

3947 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3948 

3949 _is_select_container = True 

3950 

3951 element: _SB 

3952 

3953 def __init__(self, element: _SB) -> None: 

3954 self.element = cast( 

3955 _SB, coercions.expect(roles.SelectStatementRole, element) 

3956 ) 

3957 

3958 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3959 new_element = self.element._ensure_disambiguated_names() 

3960 if new_element is not self.element: 

3961 return SelectStatementGrouping(new_element) 

3962 else: 

3963 return self 

3964 

3965 def get_label_style(self) -> SelectLabelStyle: 

3966 return self.element.get_label_style() 

3967 

3968 def set_label_style( 

3969 self, label_style: SelectLabelStyle 

3970 ) -> SelectStatementGrouping[_SB]: 

3971 return SelectStatementGrouping( 

3972 self.element.set_label_style(label_style) 

3973 ) 

3974 

3975 @property 

3976 def select_statement(self) -> _SB: 

3977 return self.element 

3978 

3979 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3980 return self 

3981 

3982 if TYPE_CHECKING: 

3983 

3984 def _ungroup(self) -> _SB: ... 

3985 

3986 # def _generate_columns_plus_names( 

3987 # self, anon_for_dupe_key: bool 

3988 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3989 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3990 

3991 def _generate_fromclause_column_proxies( 

3992 self, 

3993 subquery: FromClause, 

3994 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

3995 primary_key: ColumnSet, 

3996 foreign_keys: Set[KeyedColumnElement[Any]], 

3997 *, 

3998 proxy_compound_columns: Optional[ 

3999 Iterable[Sequence[ColumnElement[Any]]] 

4000 ] = None, 

4001 ) -> None: 

4002 self.element._generate_fromclause_column_proxies( 

4003 subquery, 

4004 columns, 

4005 proxy_compound_columns=proxy_compound_columns, 

4006 primary_key=primary_key, 

4007 foreign_keys=foreign_keys, 

4008 ) 

4009 

4010 @util.ro_non_memoized_property 

4011 def _all_selected_columns(self) -> _SelectIterable: 

4012 return self.element._all_selected_columns 

4013 

4014 @util.ro_non_memoized_property 

4015 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

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

4017 representing the columns that 

4018 the embedded SELECT statement returns in its result set, not including 

4019 :class:`_sql.TextClause` constructs. 

4020 

4021 .. versionadded:: 1.4 

4022 

4023 .. seealso:: 

4024 

4025 :attr:`_sql.Select.selected_columns` 

4026 

4027 """ 

4028 return self.element.selected_columns 

4029 

4030 @util.ro_non_memoized_property 

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

4032 return self.element._from_objects 

4033 

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

4035 return self.element._scalar_type() 

4036 

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

4038 # SelectStatementGrouping not generative: has no attribute '_generate' 

4039 raise NotImplementedError 

4040 

4041 

4042class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

4043 """Base class for SELECT statements where additional elements can be 

4044 added. 

4045 

4046 This serves as the base for :class:`_expression.Select` and 

4047 :class:`_expression.CompoundSelect` 

4048 where elements such as ORDER BY, GROUP BY can be added and column 

4049 rendering can be controlled. Compare to 

4050 :class:`_expression.TextualSelect`, which, 

4051 while it subclasses :class:`_expression.SelectBase` 

4052 and is also a SELECT construct, 

4053 represents a fixed textual string which cannot be altered at this level, 

4054 only wrapped as a subquery. 

4055 

4056 """ 

4057 

4058 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

4059 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

4060 _limit_clause: Optional[ColumnElement[Any]] = None 

4061 _offset_clause: Optional[ColumnElement[Any]] = None 

4062 _fetch_clause: Optional[ColumnElement[Any]] = None 

4063 _fetch_clause_options: Optional[Dict[str, bool]] = None 

4064 _for_update_arg: Optional[ForUpdateArg] = None 

4065 

4066 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

4067 self._label_style = _label_style 

4068 

4069 @_generative 

4070 def with_for_update( 

4071 self, 

4072 *, 

4073 nowait: bool = False, 

4074 read: bool = False, 

4075 of: Optional[_ForUpdateOfArgument] = None, 

4076 skip_locked: bool = False, 

4077 key_share: bool = False, 

4078 ) -> Self: 

4079 """Specify a ``FOR UPDATE`` clause for this 

4080 :class:`_expression.GenerativeSelect`. 

4081 

4082 E.g.:: 

4083 

4084 stmt = select(table).with_for_update(nowait=True) 

4085 

4086 On a database like PostgreSQL or Oracle Database, the above would 

4087 render a statement like: 

4088 

4089 .. sourcecode:: sql 

4090 

4091 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

4092 

4093 on other backends, the ``nowait`` option is ignored and instead 

4094 would produce: 

4095 

4096 .. sourcecode:: sql 

4097 

4098 SELECT table.a, table.b FROM table FOR UPDATE 

4099 

4100 When called with no arguments, the statement will render with 

4101 the suffix ``FOR UPDATE``. Additional arguments can then be 

4102 provided which allow for common database-specific 

4103 variants. 

4104 

4105 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

4106 Database and PostgreSQL dialects. 

4107 

4108 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

4109 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

4110 ``nowait``, will render ``FOR SHARE NOWAIT``. 

4111 

4112 :param of: SQL expression or list of SQL expression elements, 

4113 (typically :class:`_schema.Column` objects or a compatible expression, 

4114 for some backends may also be a table expression) which will render 

4115 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4116 Database, some MySQL versions and possibly others. May render as a 

4117 table or as a column depending on backend. 

4118 

4119 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4120 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4121 if ``read=True`` is also specified. 

4122 

4123 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4124 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4125 on the PostgreSQL dialect. 

4126 

4127 """ 

4128 self._for_update_arg = ForUpdateArg( 

4129 nowait=nowait, 

4130 read=read, 

4131 of=of, 

4132 skip_locked=skip_locked, 

4133 key_share=key_share, 

4134 ) 

4135 return self 

4136 

4137 def get_label_style(self) -> SelectLabelStyle: 

4138 """ 

4139 Retrieve the current label style. 

4140 

4141 .. versionadded:: 1.4 

4142 

4143 """ 

4144 return self._label_style 

4145 

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

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

4148 

4149 There are three "label styles" available, 

4150 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4151 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4152 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4153 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4154 

4155 In modern SQLAlchemy, there is not generally a need to change the 

4156 labeling style, as per-expression labels are more effectively used by 

4157 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4158 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4159 disambiguate same-named columns from different tables, aliases, or 

4160 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4161 applies labels only to names that conflict with an existing name so 

4162 that the impact of this labeling is minimal. 

4163 

4164 The rationale for disambiguation is mostly so that all column 

4165 expressions are available from a given :attr:`_sql.FromClause.c` 

4166 collection when a subquery is created. 

4167 

4168 .. versionadded:: 1.4 - the 

4169 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4170 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4171 ``use_labels=True`` methods and/or parameters. 

4172 

4173 .. seealso:: 

4174 

4175 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4176 

4177 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL` 

4178 

4179 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE` 

4180 

4181 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DEFAULT` 

4182 

4183 """ 

4184 if self._label_style is not style: 

4185 self = self._generate() 

4186 self._label_style = style 

4187 return self 

4188 

4189 @property 

4190 def _group_by_clause(self) -> ClauseList: 

4191 """ClauseList access to group_by_clauses for legacy dialects""" 

4192 return ClauseList._construct_raw( 

4193 operators.comma_op, self._group_by_clauses 

4194 ) 

4195 

4196 @property 

4197 def _order_by_clause(self) -> ClauseList: 

4198 """ClauseList access to order_by_clauses for legacy dialects""" 

4199 return ClauseList._construct_raw( 

4200 operators.comma_op, self._order_by_clauses 

4201 ) 

4202 

4203 def _offset_or_limit_clause( 

4204 self, 

4205 element: _LimitOffsetType, 

4206 name: Optional[str] = None, 

4207 type_: Optional[_TypeEngineArgument[int]] = None, 

4208 ) -> ColumnElement[Any]: 

4209 """Convert the given value to an "offset or limit" clause. 

4210 

4211 This handles incoming integers and converts to an expression; if 

4212 an expression is already given, it is passed through. 

4213 

4214 """ 

4215 return coercions.expect( 

4216 roles.LimitOffsetRole, element, name=name, type_=type_ 

4217 ) 

4218 

4219 @overload 

4220 def _offset_or_limit_clause_asint( 

4221 self, clause: ColumnElement[Any], attrname: str 

4222 ) -> NoReturn: ... 

4223 

4224 @overload 

4225 def _offset_or_limit_clause_asint( 

4226 self, clause: Optional[_OffsetLimitParam], attrname: str 

4227 ) -> Optional[int]: ... 

4228 

4229 def _offset_or_limit_clause_asint( 

4230 self, clause: Optional[ColumnElement[Any]], attrname: str 

4231 ) -> Union[NoReturn, Optional[int]]: 

4232 """Convert the "offset or limit" clause of a select construct to an 

4233 integer. 

4234 

4235 This is only possible if the value is stored as a simple bound 

4236 parameter. Otherwise, a compilation error is raised. 

4237 

4238 """ 

4239 if clause is None: 

4240 return None 

4241 try: 

4242 value = clause._limit_offset_value 

4243 except AttributeError as err: 

4244 raise exc.CompileError( 

4245 "This SELECT structure does not use a simple " 

4246 "integer value for %s" % attrname 

4247 ) from err 

4248 else: 

4249 return util.asint(value) 

4250 

4251 @property 

4252 def _limit(self) -> Optional[int]: 

4253 """Get an integer value for the limit. This should only be used 

4254 by code that cannot support a limit as a BindParameter or 

4255 other custom clause as it will throw an exception if the limit 

4256 isn't currently set to an integer. 

4257 

4258 """ 

4259 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4260 

4261 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4262 """True if the clause is a simple integer, False 

4263 if it is not present or is a SQL expression. 

4264 """ 

4265 return isinstance(clause, _OffsetLimitParam) 

4266 

4267 @property 

4268 def _offset(self) -> Optional[int]: 

4269 """Get an integer value for the offset. This should only be used 

4270 by code that cannot support an offset as a BindParameter or 

4271 other custom clause as it will throw an exception if the 

4272 offset isn't currently set to an integer. 

4273 

4274 """ 

4275 return self._offset_or_limit_clause_asint( 

4276 self._offset_clause, "offset" 

4277 ) 

4278 

4279 @property 

4280 def _has_row_limiting_clause(self) -> bool: 

4281 return ( 

4282 self._limit_clause is not None 

4283 or self._offset_clause is not None 

4284 or self._fetch_clause is not None 

4285 ) 

4286 

4287 @_generative 

4288 def limit(self, limit: _LimitOffsetType) -> Self: 

4289 """Return a new selectable with the given LIMIT criterion 

4290 applied. 

4291 

4292 This is a numerical value which usually renders as a ``LIMIT`` 

4293 expression in the resulting select. Backends that don't 

4294 support ``LIMIT`` will attempt to provide similar 

4295 functionality. 

4296 

4297 .. note:: 

4298 

4299 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4300 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4301 

4302 :param limit: an integer LIMIT parameter, or a SQL expression 

4303 that provides an integer result. Pass ``None`` to reset it. 

4304 

4305 .. seealso:: 

4306 

4307 :meth:`_sql.GenerativeSelect.fetch` 

4308 

4309 :meth:`_sql.GenerativeSelect.offset` 

4310 

4311 """ 

4312 

4313 self._fetch_clause = self._fetch_clause_options = None 

4314 self._limit_clause = self._offset_or_limit_clause(limit) 

4315 return self 

4316 

4317 @_generative 

4318 def fetch( 

4319 self, 

4320 count: _LimitOffsetType, 

4321 with_ties: bool = False, 

4322 percent: bool = False, 

4323 **dialect_kw: Any, 

4324 ) -> Self: 

4325 r"""Return a new selectable with the given FETCH FIRST criterion 

4326 applied. 

4327 

4328 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4329 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4330 select. This functionality is is currently implemented for Oracle 

4331 Database, PostgreSQL, MSSQL. 

4332 

4333 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4334 

4335 .. note:: 

4336 

4337 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4338 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4339 

4340 .. versionadded:: 1.4 

4341 

4342 :param count: an integer COUNT parameter, or a SQL expression 

4343 that provides an integer result. When ``percent=True`` this will 

4344 represent the percentage of rows to return, not the absolute value. 

4345 Pass ``None`` to reset it. 

4346 

4347 :param with_ties: When ``True``, the WITH TIES option is used 

4348 to return any additional rows that tie for the last place in the 

4349 result set according to the ``ORDER BY`` clause. The 

4350 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4351 

4352 :param percent: When ``True``, ``count`` represents the percentage 

4353 of the total number of selected rows to return. Defaults to ``False`` 

4354 

4355 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4356 may be accepted by dialects. 

4357 

4358 .. versionadded:: 2.0.41 

4359 

4360 .. seealso:: 

4361 

4362 :meth:`_sql.GenerativeSelect.limit` 

4363 

4364 :meth:`_sql.GenerativeSelect.offset` 

4365 

4366 """ 

4367 self._validate_dialect_kwargs(dialect_kw) 

4368 self._limit_clause = None 

4369 if count is None: 

4370 self._fetch_clause = self._fetch_clause_options = None 

4371 else: 

4372 self._fetch_clause = self._offset_or_limit_clause(count) 

4373 self._fetch_clause_options = { 

4374 "with_ties": with_ties, 

4375 "percent": percent, 

4376 } 

4377 return self 

4378 

4379 @_generative 

4380 def offset(self, offset: _LimitOffsetType) -> Self: 

4381 """Return a new selectable with the given OFFSET criterion 

4382 applied. 

4383 

4384 

4385 This is a numeric value which usually renders as an ``OFFSET`` 

4386 expression in the resulting select. Backends that don't 

4387 support ``OFFSET`` will attempt to provide similar 

4388 functionality. 

4389 

4390 :param offset: an integer OFFSET parameter, or a SQL expression 

4391 that provides an integer result. Pass ``None`` to reset it. 

4392 

4393 .. seealso:: 

4394 

4395 :meth:`_sql.GenerativeSelect.limit` 

4396 

4397 :meth:`_sql.GenerativeSelect.fetch` 

4398 

4399 """ 

4400 

4401 self._offset_clause = self._offset_or_limit_clause(offset) 

4402 return self 

4403 

4404 @_generative 

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

4406 def slice( 

4407 self, 

4408 start: int, 

4409 stop: int, 

4410 ) -> Self: 

4411 """Apply LIMIT / OFFSET to this statement based on a slice. 

4412 

4413 The start and stop indices behave like the argument to Python's 

4414 built-in :func:`range` function. This method provides an 

4415 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4416 query. 

4417 

4418 For example, :: 

4419 

4420 stmt = select(User).order_by(User.id).slice(1, 3) 

4421 

4422 renders as 

4423 

4424 .. sourcecode:: sql 

4425 

4426 SELECT users.id AS users_id, 

4427 users.name AS users_name 

4428 FROM users ORDER BY users.id 

4429 LIMIT ? OFFSET ? 

4430 (2, 1) 

4431 

4432 .. note:: 

4433 

4434 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4435 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4436 

4437 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4438 method generalized from the ORM. 

4439 

4440 .. seealso:: 

4441 

4442 :meth:`_sql.GenerativeSelect.limit` 

4443 

4444 :meth:`_sql.GenerativeSelect.offset` 

4445 

4446 :meth:`_sql.GenerativeSelect.fetch` 

4447 

4448 """ 

4449 sql_util = util.preloaded.sql_util 

4450 self._fetch_clause = self._fetch_clause_options = None 

4451 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4452 self._limit_clause, self._offset_clause, start, stop 

4453 ) 

4454 return self 

4455 

4456 @_generative 

4457 def order_by( 

4458 self, 

4459 __first: Union[ 

4460 Literal[None, _NoArg.NO_ARG], 

4461 _ColumnExpressionOrStrLabelArgument[Any], 

4462 ] = _NoArg.NO_ARG, 

4463 /, 

4464 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4465 ) -> Self: 

4466 r"""Return a new selectable with the given list of ORDER BY 

4467 criteria applied. 

4468 

4469 e.g.:: 

4470 

4471 stmt = select(table).order_by(table.c.id, table.c.name) 

4472 

4473 Calling this method multiple times is equivalent to calling it once 

4474 with all the clauses concatenated. All existing ORDER BY criteria may 

4475 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4476 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4477 

4478 # will erase all ORDER BY and ORDER BY new_col alone 

4479 stmt = stmt.order_by(None).order_by(new_col) 

4480 

4481 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4482 constructs which will be used to generate an ORDER BY clause. 

4483 

4484 Alternatively, an individual entry may also be the string name of a 

4485 label located elsewhere in the columns clause of the statement which 

4486 will be matched and rendered in a backend-specific way based on 

4487 context; see :ref:`tutorial_order_by_label` for background on string 

4488 label matching in ORDER BY and GROUP BY expressions. 

4489 

4490 .. seealso:: 

4491 

4492 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4493 

4494 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4495 

4496 """ 

4497 

4498 if not clauses and __first is None: 

4499 self._order_by_clauses = () 

4500 elif __first is not _NoArg.NO_ARG: 

4501 self._order_by_clauses += tuple( 

4502 coercions.expect( 

4503 roles.OrderByRole, clause, apply_propagate_attrs=self 

4504 ) 

4505 for clause in (__first,) + clauses 

4506 ) 

4507 return self 

4508 

4509 @_generative 

4510 def group_by( 

4511 self, 

4512 __first: Union[ 

4513 Literal[None, _NoArg.NO_ARG], 

4514 _ColumnExpressionOrStrLabelArgument[Any], 

4515 ] = _NoArg.NO_ARG, 

4516 /, 

4517 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4518 ) -> Self: 

4519 r"""Return a new selectable with the given list of GROUP BY 

4520 criterion applied. 

4521 

4522 All existing GROUP BY settings can be suppressed by passing ``None``. 

4523 

4524 e.g.:: 

4525 

4526 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4527 

4528 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4529 constructs which will be used to generate an GROUP BY clause. 

4530 

4531 Alternatively, an individual entry may also be the string name of a 

4532 label located elsewhere in the columns clause of the statement which 

4533 will be matched and rendered in a backend-specific way based on 

4534 context; see :ref:`tutorial_order_by_label` for background on string 

4535 label matching in ORDER BY and GROUP BY expressions. 

4536 

4537 .. seealso:: 

4538 

4539 :ref:`tutorial_group_by_w_aggregates` - in the 

4540 :ref:`unified_tutorial` 

4541 

4542 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4543 

4544 """ # noqa: E501 

4545 

4546 if not clauses and __first is None: 

4547 self._group_by_clauses = () 

4548 elif __first is not _NoArg.NO_ARG: 

4549 self._group_by_clauses += tuple( 

4550 coercions.expect( 

4551 roles.GroupByRole, clause, apply_propagate_attrs=self 

4552 ) 

4553 for clause in (__first,) + clauses 

4554 ) 

4555 return self 

4556 

4557 

4558@CompileState.plugin_for("default", "compound_select") 

4559class CompoundSelectState(CompileState): 

4560 @util.memoized_property 

4561 def _label_resolve_dict( 

4562 self, 

4563 ) -> Tuple[ 

4564 Dict[str, ColumnElement[Any]], 

4565 Dict[str, ColumnElement[Any]], 

4566 Dict[str, ColumnElement[Any]], 

4567 ]: 

4568 # TODO: this is hacky and slow 

4569 hacky_subquery = self.statement.subquery() 

4570 hacky_subquery.named_with_column = False 

4571 d = {c.key: c for c in hacky_subquery.c} 

4572 return d, d, d 

4573 

4574 

4575class _CompoundSelectKeyword(Enum): 

4576 UNION = "UNION" 

4577 UNION_ALL = "UNION ALL" 

4578 EXCEPT = "EXCEPT" 

4579 EXCEPT_ALL = "EXCEPT ALL" 

4580 INTERSECT = "INTERSECT" 

4581 INTERSECT_ALL = "INTERSECT ALL" 

4582 

4583 

4584class CompoundSelect( 

4585 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4586): 

4587 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4588 SELECT-based set operations. 

4589 

4590 

4591 .. seealso:: 

4592 

4593 :func:`_expression.union` 

4594 

4595 :func:`_expression.union_all` 

4596 

4597 :func:`_expression.intersect` 

4598 

4599 :func:`_expression.intersect_all` 

4600 

4601 :func:`_expression.except` 

4602 

4603 :func:`_expression.except_all` 

4604 

4605 """ 

4606 

4607 __visit_name__ = "compound_select" 

4608 

4609 _traverse_internals: _TraverseInternalsType = ( 

4610 [ 

4611 ("selects", InternalTraversal.dp_clauseelement_list), 

4612 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4613 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4614 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4615 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4616 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4617 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4618 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4619 ("keyword", InternalTraversal.dp_string), 

4620 ] 

4621 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4622 + HasCTE._has_ctes_traverse_internals 

4623 + DialectKWArgs._dialect_kwargs_traverse_internals 

4624 + ExecutableStatement._executable_traverse_internals 

4625 ) 

4626 

4627 selects: List[SelectBase] 

4628 

4629 _is_from_container = True 

4630 _auto_correlate = False 

4631 

4632 def __init__( 

4633 self, 

4634 keyword: _CompoundSelectKeyword, 

4635 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4636 ): 

4637 self.keyword = keyword 

4638 self.selects = [ 

4639 coercions.expect( 

4640 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4641 ).self_group(against=self) 

4642 for s in selects 

4643 ] 

4644 

4645 GenerativeSelect.__init__(self) 

4646 

4647 @classmethod 

4648 def _create_union( 

4649 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4650 ) -> CompoundSelect[Unpack[_Ts]]: 

4651 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4652 

4653 @classmethod 

4654 def _create_union_all( 

4655 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4656 ) -> CompoundSelect[Unpack[_Ts]]: 

4657 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4658 

4659 @classmethod 

4660 def _create_except( 

4661 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4662 ) -> CompoundSelect[Unpack[_Ts]]: 

4663 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4664 

4665 @classmethod 

4666 def _create_except_all( 

4667 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4668 ) -> CompoundSelect[Unpack[_Ts]]: 

4669 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4670 

4671 @classmethod 

4672 def _create_intersect( 

4673 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4674 ) -> CompoundSelect[Unpack[_Ts]]: 

4675 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4676 

4677 @classmethod 

4678 def _create_intersect_all( 

4679 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4680 ) -> CompoundSelect[Unpack[_Ts]]: 

4681 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4682 

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

4684 return self.selects[0]._scalar_type() 

4685 

4686 def self_group( 

4687 self, against: Optional[OperatorType] = None 

4688 ) -> GroupedElement: 

4689 return SelectStatementGrouping(self) 

4690 

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

4692 for s in self.selects: 

4693 if s.is_derived_from(fromclause): 

4694 return True 

4695 return False 

4696 

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

4698 if self._label_style is not style: 

4699 self = self._generate() 

4700 select_0 = self.selects[0].set_label_style(style) 

4701 self.selects = [select_0] + self.selects[1:] 

4702 

4703 return self 

4704 

4705 def _ensure_disambiguated_names(self) -> Self: 

4706 new_select = self.selects[0]._ensure_disambiguated_names() 

4707 if new_select is not self.selects[0]: 

4708 self = self._generate() 

4709 self.selects = [new_select] + self.selects[1:] 

4710 

4711 return self 

4712 

4713 def _generate_fromclause_column_proxies( 

4714 self, 

4715 subquery: FromClause, 

4716 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

4717 primary_key: ColumnSet, 

4718 foreign_keys: Set[KeyedColumnElement[Any]], 

4719 *, 

4720 proxy_compound_columns: Optional[ 

4721 Iterable[Sequence[ColumnElement[Any]]] 

4722 ] = None, 

4723 ) -> None: 

4724 # this is a slightly hacky thing - the union exports a 

4725 # column that resembles just that of the *first* selectable. 

4726 # to get at a "composite" column, particularly foreign keys, 

4727 # you have to dig through the proxies collection which we 

4728 # generate below. 

4729 select_0 = self.selects[0] 

4730 

4731 if self._label_style is not LABEL_STYLE_DEFAULT: 

4732 select_0 = select_0.set_label_style(self._label_style) 

4733 

4734 # hand-construct the "_proxies" collection to include all 

4735 # derived columns place a 'weight' annotation corresponding 

4736 # to how low in the list of select()s the column occurs, so 

4737 # that the corresponding_column() operation can resolve 

4738 # conflicts 

4739 extra_col_iterator = zip( 

4740 *[ 

4741 [ 

4742 c._annotate(dd) 

4743 for c in stmt._all_selected_columns 

4744 if is_column_element(c) 

4745 ] 

4746 for dd, stmt in [ 

4747 ({"weight": i + 1}, stmt) 

4748 for i, stmt in enumerate(self.selects) 

4749 ] 

4750 ] 

4751 ) 

4752 

4753 # the incoming proxy_compound_columns can be present also if this is 

4754 # a compound embedded in a compound. it's probably more appropriate 

4755 # that we generate new weights local to this nested compound, though 

4756 # i haven't tried to think what it means for compound nested in 

4757 # compound 

4758 select_0._generate_fromclause_column_proxies( 

4759 subquery, 

4760 columns, 

4761 proxy_compound_columns=extra_col_iterator, 

4762 primary_key=primary_key, 

4763 foreign_keys=foreign_keys, 

4764 ) 

4765 

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

4767 super()._refresh_for_new_column(column) 

4768 for select in self.selects: 

4769 select._refresh_for_new_column(column) 

4770 

4771 @util.ro_non_memoized_property 

4772 def _all_selected_columns(self) -> _SelectIterable: 

4773 return self.selects[0]._all_selected_columns 

4774 

4775 @util.ro_non_memoized_property 

4776 def selected_columns( 

4777 self, 

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

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

4780 representing the columns that 

4781 this SELECT statement or similar construct returns in its result set, 

4782 not including :class:`_sql.TextClause` constructs. 

4783 

4784 For a :class:`_expression.CompoundSelect`, the 

4785 :attr:`_expression.CompoundSelect.selected_columns` 

4786 attribute returns the selected 

4787 columns of the first SELECT statement contained within the series of 

4788 statements within the set operation. 

4789 

4790 .. seealso:: 

4791 

4792 :attr:`_sql.Select.selected_columns` 

4793 

4794 .. versionadded:: 1.4 

4795 

4796 """ 

4797 return self.selects[0].selected_columns 

4798 

4799 

4800# backwards compat 

4801for elem in _CompoundSelectKeyword: 

4802 setattr(CompoundSelect, elem.name, elem) 

4803 

4804 

4805@CompileState.plugin_for("default", "select") 

4806class SelectState(util.MemoizedSlots, CompileState): 

4807 __slots__ = ( 

4808 "from_clauses", 

4809 "froms", 

4810 "columns_plus_names", 

4811 "_label_resolve_dict", 

4812 ) 

4813 

4814 if TYPE_CHECKING: 

4815 default_select_compile_options: CacheableOptions 

4816 else: 

4817 

4818 class default_select_compile_options(CacheableOptions): 

4819 _cache_key_traversal = [] 

4820 

4821 if TYPE_CHECKING: 

4822 

4823 @classmethod 

4824 def get_plugin_class( 

4825 cls, statement: Executable 

4826 ) -> Type[SelectState]: ... 

4827 

4828 def __init__( 

4829 self, 

4830 statement: Select[Unpack[TupleAny]], 

4831 compiler: SQLCompiler, 

4832 **kw: Any, 

4833 ): 

4834 self.statement = statement 

4835 self.from_clauses = statement._from_obj 

4836 

4837 for memoized_entities in statement._memoized_select_entities: 

4838 self._setup_joins( 

4839 memoized_entities._setup_joins, memoized_entities._raw_columns 

4840 ) 

4841 

4842 if statement._setup_joins: 

4843 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4844 

4845 self.froms = self._get_froms(statement) 

4846 

4847 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4848 

4849 @classmethod 

4850 def _plugin_not_implemented(cls) -> NoReturn: 

4851 raise NotImplementedError( 

4852 "The default SELECT construct without plugins does not " 

4853 "implement this method." 

4854 ) 

4855 

4856 @classmethod 

4857 def get_column_descriptions( 

4858 cls, statement: Select[Unpack[TupleAny]] 

4859 ) -> List[Dict[str, Any]]: 

4860 return [ 

4861 { 

4862 "name": name, 

4863 "type": element.type, 

4864 "expr": element, 

4865 } 

4866 for _, name, _, element, _ in ( 

4867 statement._generate_columns_plus_names(False) 

4868 ) 

4869 ] 

4870 

4871 @classmethod 

4872 def from_statement( 

4873 cls, 

4874 statement: Select[Unpack[TupleAny]], 

4875 from_statement: roles.ReturnsRowsRole, 

4876 ) -> ExecutableReturnsRows: 

4877 cls._plugin_not_implemented() 

4878 

4879 @classmethod 

4880 def get_columns_clause_froms( 

4881 cls, statement: Select[Unpack[TupleAny]] 

4882 ) -> List[FromClause]: 

4883 return cls._normalize_froms( 

4884 itertools.chain.from_iterable( 

4885 element._from_objects for element in statement._raw_columns 

4886 ) 

4887 ) 

4888 

4889 @classmethod 

4890 def _column_naming_convention( 

4891 cls, label_style: SelectLabelStyle 

4892 ) -> _LabelConventionCallable: 

4893 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4894 

4895 dedupe = label_style is not LABEL_STYLE_NONE 

4896 

4897 pa = prefix_anon_map() 

4898 names = set() 

4899 

4900 def go( 

4901 c: Union[ColumnElement[Any], AbstractTextClause], 

4902 col_name: Optional[str] = None, 

4903 ) -> Optional[str]: 

4904 if is_text_clause(c): 

4905 return None 

4906 elif TYPE_CHECKING: 

4907 assert is_column_element(c) 

4908 

4909 if not dedupe: 

4910 name = c._proxy_key 

4911 if name is None: 

4912 name = "_no_label" 

4913 return name 

4914 

4915 name = c._tq_key_label if table_qualified else c._proxy_key 

4916 

4917 if name is None: 

4918 name = "_no_label" 

4919 if name in names: 

4920 return c._anon_label(name) % pa 

4921 else: 

4922 names.add(name) 

4923 return name 

4924 

4925 elif name in names: 

4926 return ( 

4927 c._anon_tq_key_label % pa 

4928 if table_qualified 

4929 else c._anon_key_label % pa 

4930 ) 

4931 else: 

4932 names.add(name) 

4933 return name 

4934 

4935 return go 

4936 

4937 def _get_froms( 

4938 self, statement: Select[Unpack[TupleAny]] 

4939 ) -> List[FromClause]: 

4940 ambiguous_table_name_map: _AmbiguousTableNameMap 

4941 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4942 

4943 return self._normalize_froms( 

4944 itertools.chain( 

4945 self.from_clauses, 

4946 itertools.chain.from_iterable( 

4947 [ 

4948 element._from_objects 

4949 for element in statement._raw_columns 

4950 ] 

4951 ), 

4952 itertools.chain.from_iterable( 

4953 [ 

4954 element._from_objects 

4955 for element in statement._where_criteria 

4956 ] 

4957 ), 

4958 ), 

4959 check_statement=statement, 

4960 ambiguous_table_name_map=ambiguous_table_name_map, 

4961 ) 

4962 

4963 @classmethod 

4964 def _normalize_froms( 

4965 cls, 

4966 iterable_of_froms: Iterable[FromClause], 

4967 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4968 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4969 ) -> List[FromClause]: 

4970 """given an iterable of things to select FROM, reduce them to what 

4971 would actually render in the FROM clause of a SELECT. 

4972 

4973 This does the job of checking for JOINs, tables, etc. that are in fact 

4974 overlapping due to cloning, adaption, present in overlapping joins, 

4975 etc. 

4976 

4977 """ 

4978 seen: Set[FromClause] = set() 

4979 froms: List[FromClause] = [] 

4980 

4981 for item in iterable_of_froms: 

4982 if is_subquery(item) and item.element is check_statement: 

4983 raise exc.InvalidRequestError( 

4984 "select() construct refers to itself as a FROM" 

4985 ) 

4986 

4987 if not seen.intersection(item._cloned_set): 

4988 froms.append(item) 

4989 seen.update(item._cloned_set) 

4990 

4991 if froms: 

4992 toremove = set( 

4993 itertools.chain.from_iterable( 

4994 [_expand_cloned(f._hide_froms) for f in froms] 

4995 ) 

4996 ) 

4997 if toremove: 

4998 # filter out to FROM clauses not in the list, 

4999 # using a list to maintain ordering 

5000 froms = [f for f in froms if f not in toremove] 

5001 

5002 if ambiguous_table_name_map is not None: 

5003 ambiguous_table_name_map.update( 

5004 ( 

5005 fr.name, 

5006 _anonymous_label.safe_construct( 

5007 hash(fr.name), fr.name 

5008 ), 

5009 ) 

5010 for item in froms 

5011 for fr in item._from_objects 

5012 if is_table(fr) 

5013 and fr.schema 

5014 and fr.name not in ambiguous_table_name_map 

5015 ) 

5016 

5017 return froms 

5018 

5019 def _get_display_froms( 

5020 self, 

5021 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

5022 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

5023 ) -> List[FromClause]: 

5024 """Return the full list of 'from' clauses to be displayed. 

5025 

5026 Takes into account a set of existing froms which may be 

5027 rendered in the FROM clause of enclosing selects; this Select 

5028 may want to leave those absent if it is automatically 

5029 correlating. 

5030 

5031 """ 

5032 

5033 froms = self.froms 

5034 

5035 if self.statement._correlate: 

5036 to_correlate = self.statement._correlate 

5037 if to_correlate: 

5038 froms = [ 

5039 f 

5040 for f in froms 

5041 if f 

5042 not in _cloned_intersection( 

5043 _cloned_intersection( 

5044 froms, explicit_correlate_froms or () 

5045 ), 

5046 to_correlate, 

5047 ) 

5048 ] 

5049 

5050 if self.statement._correlate_except is not None: 

5051 froms = [ 

5052 f 

5053 for f in froms 

5054 if f 

5055 not in _cloned_difference( 

5056 _cloned_intersection( 

5057 froms, explicit_correlate_froms or () 

5058 ), 

5059 self.statement._correlate_except, 

5060 ) 

5061 ] 

5062 

5063 if ( 

5064 self.statement._auto_correlate 

5065 and implicit_correlate_froms 

5066 and len(froms) > 1 

5067 ): 

5068 froms = [ 

5069 f 

5070 for f in froms 

5071 if f 

5072 not in _cloned_intersection(froms, implicit_correlate_froms) 

5073 ] 

5074 

5075 if not len(froms): 

5076 raise exc.InvalidRequestError( 

5077 "Select statement '%r" 

5078 "' returned no FROM clauses " 

5079 "due to auto-correlation; " 

5080 "specify correlate(<tables>) " 

5081 "to control correlation " 

5082 "manually." % self.statement 

5083 ) 

5084 

5085 return froms 

5086 

5087 def _memoized_attr__label_resolve_dict( 

5088 self, 

5089 ) -> Tuple[ 

5090 Dict[str, ColumnElement[Any]], 

5091 Dict[str, ColumnElement[Any]], 

5092 Dict[str, ColumnElement[Any]], 

5093 ]: 

5094 with_cols: Dict[str, ColumnElement[Any]] = { 

5095 c._tq_label or c.key: c 

5096 for c in self.statement._all_selected_columns 

5097 if c._allow_label_resolve 

5098 } 

5099 only_froms: Dict[str, ColumnElement[Any]] = { 

5100 c.key: c # type: ignore 

5101 for c in _select_iterables(self.froms) 

5102 if c._allow_label_resolve 

5103 } 

5104 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

5105 for key, value in only_froms.items(): 

5106 with_cols.setdefault(key, value) 

5107 

5108 return with_cols, only_froms, only_cols 

5109 

5110 @classmethod 

5111 def _get_filter_by_entities( 

5112 cls, statement: Select[Unpack[TupleAny]] 

5113 ) -> Collection[ 

5114 Union[FromClause, _JoinTargetProtocol, ColumnElement[Any]] 

5115 ]: 

5116 """Return all entities to search for filter_by() attributes. 

5117 

5118 This includes: 

5119 

5120 * All joined entities from _setup_joins 

5121 * Memoized entities from previous operations (e.g., 

5122 before with_only_columns) 

5123 * Explicit FROM objects from _from_obj 

5124 * Entities inferred from _raw_columns 

5125 

5126 .. versionadded:: 2.1 

5127 

5128 """ 

5129 entities: set[ 

5130 Union[FromClause, _JoinTargetProtocol, ColumnElement[Any]] 

5131 ] 

5132 

5133 entities = set( 

5134 join_element[0] for join_element in statement._setup_joins 

5135 ) 

5136 

5137 for memoized in statement._memoized_select_entities: 

5138 entities.update( 

5139 join_element[0] for join_element in memoized._setup_joins 

5140 ) 

5141 

5142 entities.update(statement._from_obj) 

5143 

5144 for col in statement._raw_columns: 

5145 entities.update(col._from_objects) 

5146 

5147 return entities 

5148 

5149 @classmethod 

5150 def all_selected_columns( 

5151 cls, statement: Select[Unpack[TupleAny]] 

5152 ) -> _SelectIterable: 

5153 return [c for c in _select_iterables(statement._raw_columns)] 

5154 

5155 def _setup_joins( 

5156 self, 

5157 args: Tuple[_SetupJoinsElement, ...], 

5158 raw_columns: List[_ColumnsClauseElement], 

5159 ) -> None: 

5160 for right, onclause, left, flags in args: 

5161 if TYPE_CHECKING: 

5162 if onclause is not None: 

5163 assert isinstance(onclause, ColumnElement) 

5164 

5165 explicit_left = left 

5166 isouter = flags["isouter"] 

5167 full = flags["full"] 

5168 

5169 if left is None: 

5170 ( 

5171 left, 

5172 replace_from_obj_index, 

5173 ) = self._join_determine_implicit_left_side( 

5174 raw_columns, left, right, onclause 

5175 ) 

5176 else: 

5177 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5178 left 

5179 ) 

5180 

5181 # these assertions can be made here, as if the right/onclause 

5182 # contained ORM elements, the select() statement would have been 

5183 # upgraded to an ORM select, and this method would not be called; 

5184 # orm.context.ORMSelectCompileState._join() would be 

5185 # used instead. 

5186 if TYPE_CHECKING: 

5187 assert isinstance(right, FromClause) 

5188 if onclause is not None: 

5189 assert isinstance(onclause, ColumnElement) 

5190 

5191 if replace_from_obj_index is not None: 

5192 # splice into an existing element in the 

5193 # self._from_obj list 

5194 left_clause = self.from_clauses[replace_from_obj_index] 

5195 

5196 if explicit_left is not None and onclause is None: 

5197 onclause = Join._join_condition(explicit_left, right) 

5198 

5199 self.from_clauses = ( 

5200 self.from_clauses[:replace_from_obj_index] 

5201 + ( 

5202 Join( 

5203 left_clause, 

5204 right, 

5205 onclause, 

5206 isouter=isouter, 

5207 full=full, 

5208 ), 

5209 ) 

5210 + self.from_clauses[replace_from_obj_index + 1 :] 

5211 ) 

5212 else: 

5213 assert left is not None 

5214 self.from_clauses = self.from_clauses + ( 

5215 Join(left, right, onclause, isouter=isouter, full=full), 

5216 ) 

5217 

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

5219 def _join_determine_implicit_left_side( 

5220 self, 

5221 raw_columns: List[_ColumnsClauseElement], 

5222 left: Optional[FromClause], 

5223 right: _JoinTargetElement, 

5224 onclause: Optional[ColumnElement[Any]], 

5225 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5226 """When join conditions don't express the left side explicitly, 

5227 determine if an existing FROM or entity in this query 

5228 can serve as the left hand side. 

5229 

5230 """ 

5231 

5232 sql_util = util.preloaded.sql_util 

5233 

5234 replace_from_obj_index: Optional[int] = None 

5235 

5236 from_clauses = self.from_clauses 

5237 

5238 if from_clauses: 

5239 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5240 from_clauses, right, onclause 

5241 ) 

5242 

5243 if len(indexes) == 1: 

5244 replace_from_obj_index = indexes[0] 

5245 left = from_clauses[replace_from_obj_index] 

5246 else: 

5247 potential = {} 

5248 statement = self.statement 

5249 

5250 for from_clause in itertools.chain( 

5251 itertools.chain.from_iterable( 

5252 [element._from_objects for element in raw_columns] 

5253 ), 

5254 itertools.chain.from_iterable( 

5255 [ 

5256 element._from_objects 

5257 for element in statement._where_criteria 

5258 ] 

5259 ), 

5260 ): 

5261 potential[from_clause] = () 

5262 

5263 all_clauses = list(potential.keys()) 

5264 indexes = sql_util.find_left_clause_to_join_from( 

5265 all_clauses, right, onclause 

5266 ) 

5267 

5268 if len(indexes) == 1: 

5269 left = all_clauses[indexes[0]] 

5270 

5271 if len(indexes) > 1: 

5272 raise exc.InvalidRequestError( 

5273 "Can't determine which FROM clause to join " 

5274 "from, there are multiple FROMS which can " 

5275 "join to this entity. Please use the .select_from() " 

5276 "method to establish an explicit left side, as well as " 

5277 "providing an explicit ON clause if not present already to " 

5278 "help resolve the ambiguity." 

5279 ) 

5280 elif not indexes: 

5281 raise exc.InvalidRequestError( 

5282 "Don't know how to join to %r. " 

5283 "Please use the .select_from() " 

5284 "method to establish an explicit left side, as well as " 

5285 "providing an explicit ON clause if not present already to " 

5286 "help resolve the ambiguity." % (right,) 

5287 ) 

5288 return left, replace_from_obj_index 

5289 

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

5291 def _join_place_explicit_left_side( 

5292 self, left: FromClause 

5293 ) -> Optional[int]: 

5294 replace_from_obj_index: Optional[int] = None 

5295 

5296 sql_util = util.preloaded.sql_util 

5297 

5298 from_clauses = list(self.statement._iterate_from_elements()) 

5299 

5300 if from_clauses: 

5301 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5302 self.from_clauses, left 

5303 ) 

5304 else: 

5305 indexes = [] 

5306 

5307 if len(indexes) > 1: 

5308 raise exc.InvalidRequestError( 

5309 "Can't identify which entity in which to assign the " 

5310 "left side of this join. Please use a more specific " 

5311 "ON clause." 

5312 ) 

5313 

5314 # have an index, means the left side is already present in 

5315 # an existing FROM in the self._from_obj tuple 

5316 if indexes: 

5317 replace_from_obj_index = indexes[0] 

5318 

5319 # no index, means we need to add a new element to the 

5320 # self._from_obj tuple 

5321 

5322 return replace_from_obj_index 

5323 

5324 

5325class _SelectFromElements: 

5326 __slots__ = () 

5327 

5328 _raw_columns: List[_ColumnsClauseElement] 

5329 _where_criteria: Tuple[ColumnElement[Any], ...] 

5330 _from_obj: Tuple[FromClause, ...] 

5331 

5332 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5333 # note this does not include elements 

5334 # in _setup_joins 

5335 

5336 seen = set() 

5337 for element in self._raw_columns: 

5338 for fr in element._from_objects: 

5339 if fr in seen: 

5340 continue 

5341 seen.add(fr) 

5342 yield fr 

5343 for element in self._where_criteria: 

5344 for fr in element._from_objects: 

5345 if fr in seen: 

5346 continue 

5347 seen.add(fr) 

5348 yield fr 

5349 for element in self._from_obj: 

5350 if element in seen: 

5351 continue 

5352 seen.add(element) 

5353 yield element 

5354 

5355 

5356class _MemoizedSelectEntities( 

5357 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5358): 

5359 """represents partial state from a Select object, for the case 

5360 where Select.columns() has redefined the set of columns/entities the 

5361 statement will be SELECTing from. This object represents 

5362 the entities from the SELECT before that transformation was applied, 

5363 so that transformations that were made in terms of the SELECT at that 

5364 time, such as join() as well as options(), can access the correct context. 

5365 

5366 In previous SQLAlchemy versions, this wasn't needed because these 

5367 constructs calculated everything up front, like when you called join() 

5368 or options(), it did everything to figure out how that would translate 

5369 into specific SQL constructs that would be ready to send directly to the 

5370 SQL compiler when needed. But as of 

5371 1.4, all of that stuff is done in the compilation phase, during the 

5372 "compile state" portion of the process, so that the work can all be 

5373 cached. So it needs to be able to resolve joins/options2 based on what 

5374 the list of entities was when those methods were called. 

5375 

5376 

5377 """ 

5378 

5379 __visit_name__ = "memoized_select_entities" 

5380 

5381 _traverse_internals: _TraverseInternalsType = [ 

5382 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5383 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5384 ("_with_options", InternalTraversal.dp_executable_options), 

5385 ] 

5386 

5387 _is_clone_of: Optional[ClauseElement] 

5388 _raw_columns: List[_ColumnsClauseElement] 

5389 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5390 _with_options: Tuple[ExecutableOption, ...] 

5391 

5392 _annotations = util.EMPTY_DICT 

5393 

5394 def _clone(self, **kw: Any) -> Self: 

5395 c = self.__class__.__new__(self.__class__) 

5396 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5397 

5398 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5399 return c 

5400 

5401 @classmethod 

5402 def _generate_for_statement( 

5403 cls, select_stmt: Select[Unpack[TupleAny]] 

5404 ) -> None: 

5405 if select_stmt._setup_joins or select_stmt._with_options: 

5406 self = _MemoizedSelectEntities() 

5407 self._raw_columns = select_stmt._raw_columns 

5408 self._setup_joins = select_stmt._setup_joins 

5409 self._with_options = select_stmt._with_options 

5410 

5411 select_stmt._memoized_select_entities += (self,) 

5412 select_stmt._raw_columns = [] 

5413 select_stmt._setup_joins = select_stmt._with_options = () 

5414 

5415 

5416class Select( 

5417 HasPrefixes, 

5418 HasSuffixes, 

5419 HasHints, 

5420 HasCompileState, 

5421 HasSyntaxExtensions[ 

5422 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5423 ], 

5424 _SelectFromElements, 

5425 GenerativeSelect, 

5426 TypedReturnsRows[Unpack[_Ts]], 

5427): 

5428 """Represents a ``SELECT`` statement. 

5429 

5430 The :class:`_sql.Select` object is normally constructed using the 

5431 :func:`_sql.select` function. See that function for details. 

5432 

5433 Available extension points: 

5434 

5435 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5436 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5437 keyword (if any) and the list of columns. 

5438 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5439 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5440 

5441 .. seealso:: 

5442 

5443 :func:`_sql.select` 

5444 

5445 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5446 

5447 """ 

5448 

5449 __visit_name__ = "select" 

5450 

5451 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5452 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5453 

5454 _raw_columns: List[_ColumnsClauseElement] 

5455 

5456 _distinct: bool = False 

5457 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5458 _correlate: Tuple[FromClause, ...] = () 

5459 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5460 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5461 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5462 _from_obj: Tuple[FromClause, ...] = () 

5463 

5464 _position_map = util.immutabledict( 

5465 { 

5466 "post_select": "_post_select_clause", 

5467 "pre_columns": "_pre_columns_clause", 

5468 "post_criteria": "_post_criteria_clause", 

5469 "post_body": "_post_body_clause", 

5470 } 

5471 ) 

5472 

5473 _post_select_clause: Optional[ClauseElement] = None 

5474 """extension point for a ClauseElement that will be compiled directly 

5475 after the SELECT keyword. 

5476 

5477 .. versionadded:: 2.1 

5478 

5479 """ 

5480 

5481 _pre_columns_clause: Optional[ClauseElement] = None 

5482 """extension point for a ClauseElement that will be compiled directly 

5483 before the "columns" clause; after DISTINCT (if present). 

5484 

5485 .. versionadded:: 2.1 

5486 

5487 """ 

5488 

5489 _post_criteria_clause: Optional[ClauseElement] = None 

5490 """extension point for a ClauseElement that will be compiled directly 

5491 after "criteria", following the HAVING clause but before ORDER BY. 

5492 

5493 .. versionadded:: 2.1 

5494 

5495 """ 

5496 

5497 _post_body_clause: Optional[ClauseElement] = None 

5498 """extension point for a ClauseElement that will be compiled directly 

5499 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5500 of the SELECT. 

5501 

5502 .. versionadded:: 2.1 

5503 

5504 """ 

5505 

5506 _auto_correlate = True 

5507 _is_select_statement = True 

5508 _compile_options: CacheableOptions = ( 

5509 SelectState.default_select_compile_options 

5510 ) 

5511 

5512 _traverse_internals: _TraverseInternalsType = ( 

5513 [ 

5514 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5515 ( 

5516 "_memoized_select_entities", 

5517 InternalTraversal.dp_memoized_select_entities, 

5518 ), 

5519 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5520 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5521 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5522 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5523 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5524 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5525 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5526 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5527 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5528 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5529 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5530 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5531 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5532 ("_distinct", InternalTraversal.dp_boolean), 

5533 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5534 ("_label_style", InternalTraversal.dp_plain_obj), 

5535 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5536 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5537 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5538 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5539 ] 

5540 + HasCTE._has_ctes_traverse_internals 

5541 + HasPrefixes._has_prefixes_traverse_internals 

5542 + HasSuffixes._has_suffixes_traverse_internals 

5543 + HasHints._has_hints_traverse_internals 

5544 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5545 + ExecutableStatement._executable_traverse_internals 

5546 + DialectKWArgs._dialect_kwargs_traverse_internals 

5547 ) 

5548 

5549 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5550 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5551 ] 

5552 

5553 _compile_state_factory: Type[SelectState] 

5554 

5555 @classmethod 

5556 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5557 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5558 

5559 Used internally to build up :class:`.Select` constructs with 

5560 pre-established state. 

5561 

5562 """ 

5563 

5564 stmt = Select.__new__(Select) 

5565 stmt.__dict__.update(kw) 

5566 return stmt 

5567 

5568 def __init__( 

5569 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5570 ): 

5571 r"""Construct a new :class:`_expression.Select`. 

5572 

5573 The public constructor for :class:`_expression.Select` is the 

5574 :func:`_sql.select` function. 

5575 

5576 """ 

5577 self._raw_columns = [ 

5578 coercions.expect( 

5579 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5580 ) 

5581 for ent in entities 

5582 ] 

5583 GenerativeSelect.__init__(self) 

5584 

5585 def _apply_syntax_extension_to_self( 

5586 self, extension: SyntaxExtension 

5587 ) -> None: 

5588 extension.apply_to_select(self) 

5589 

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

5591 if not self._raw_columns: 

5592 return NULLTYPE 

5593 elem = self._raw_columns[0] 

5594 cols = list(elem._select_iterable) 

5595 return cols[0].type 

5596 

5597 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5598 """A synonym for the :meth:`_sql.Select.where` method.""" 

5599 

5600 return self.where(*criteria) 

5601 

5602 if TYPE_CHECKING: 

5603 

5604 @overload 

5605 def scalar_subquery( 

5606 self: Select[_MAYBE_ENTITY], 

5607 ) -> ScalarSelect[Any]: ... 

5608 

5609 @overload 

5610 def scalar_subquery( 

5611 self: Select[_NOT_ENTITY], 

5612 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5613 

5614 @overload 

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

5616 

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

5618 

5619 def filter_by(self, **kwargs: Any) -> Self: 

5620 r"""Apply the given filtering criterion as a WHERE clause 

5621 to this select, using keyword expressions. 

5622 

5623 E.g.:: 

5624 

5625 stmt = select(User).filter_by(name="some name") 

5626 

5627 Multiple criteria may be specified as comma separated; the effect 

5628 is that they will be joined together using the :func:`.and_` 

5629 function:: 

5630 

5631 stmt = select(User).filter_by(name="some name", id=5) 

5632 

5633 The keyword expressions are extracted by searching across **all 

5634 entities present in the FROM clause** of the statement. If a 

5635 keyword name is present in more than one entity, 

5636 :class:`_exc.AmbiguousColumnError` is raised. In this case, use 

5637 :meth:`_sql.Select.filter` or :meth:`_sql.Select.where` with 

5638 explicit column references:: 

5639 

5640 # both User and Address have an 'id' attribute 

5641 stmt = select(User).join(Address).filter_by(id=5) 

5642 # raises AmbiguousColumnError 

5643 

5644 # use filter() with explicit qualification instead 

5645 stmt = select(User).join(Address).filter(Address.id == 5) 

5646 

5647 .. versionchanged:: 2.1 

5648 

5649 :meth:`_sql.Select.filter_by` now searches across all FROM clause 

5650 entities rather than only searching the last joined entity or first 

5651 FROM entity. This allows the method to locate attributes 

5652 unambiguously across multiple joined tables. The new 

5653 :class:`_exc.AmbiguousColumnError` is raised when an attribute name 

5654 is present in more than one entity. 

5655 

5656 See :ref:`change_8601` for migration notes. 

5657 

5658 .. seealso:: 

5659 

5660 :ref:`tutorial_selecting_data` - in the :ref:`unified_tutorial` 

5661 

5662 :meth:`_sql.Select.filter` - filter on SQL expressions. 

5663 

5664 :meth:`_sql.Select.where` - filter on SQL expressions. 

5665 

5666 """ 

5667 # Get all entities via plugin system 

5668 all_entities = SelectState.get_plugin_class( 

5669 self 

5670 )._get_filter_by_entities(self) 

5671 

5672 clauses = [ 

5673 _entity_namespace_key_search_all(all_entities, key) == value 

5674 for key, value in kwargs.items() 

5675 ] 

5676 return self.filter(*clauses) 

5677 

5678 @property 

5679 def column_descriptions(self) -> Any: 

5680 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5681 referring to the columns which are SELECTed by this statement. 

5682 

5683 This attribute is generally useful when using the ORM, as an 

5684 extended structure which includes information about mapped 

5685 entities is returned. The section :ref:`queryguide_inspection` 

5686 contains more background. 

5687 

5688 For a Core-only statement, the structure returned by this accessor 

5689 is derived from the same objects that are returned by the 

5690 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5691 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5692 which indicate the column expressions to be selected:: 

5693 

5694 >>> stmt = select(user_table) 

5695 >>> stmt.column_descriptions 

5696 [ 

5697 { 

5698 'name': 'id', 

5699 'type': Integer(), 

5700 'expr': Column('id', Integer(), ...)}, 

5701 { 

5702 'name': 'name', 

5703 'type': String(length=30), 

5704 'expr': Column('name', String(length=30), ...)} 

5705 ] 

5706 

5707 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5708 attribute returns a structure for a Core-only set of entities, 

5709 not just ORM-only entities. 

5710 

5711 .. seealso:: 

5712 

5713 :attr:`.UpdateBase.entity_description` - entity information for 

5714 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5715 

5716 :ref:`queryguide_inspection` - ORM background 

5717 

5718 """ 

5719 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5720 return meth(self) 

5721 

5722 def from_statement( 

5723 self, statement: roles.ReturnsRowsRole 

5724 ) -> ExecutableReturnsRows: 

5725 """Apply the columns which this :class:`.Select` would select 

5726 onto another statement. 

5727 

5728 This operation is :term:`plugin-specific` and will raise a not 

5729 supported exception if this :class:`_sql.Select` does not select from 

5730 plugin-enabled entities. 

5731 

5732 

5733 The statement is typically either a :func:`_expression.text` or 

5734 :func:`_expression.select` construct, and should return the set of 

5735 columns appropriate to the entities represented by this 

5736 :class:`.Select`. 

5737 

5738 .. seealso:: 

5739 

5740 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5741 ORM Querying Guide 

5742 

5743 """ 

5744 meth = SelectState.get_plugin_class(self).from_statement 

5745 return meth(self, statement) 

5746 

5747 @_generative 

5748 def join( 

5749 self, 

5750 target: _JoinTargetArgument, 

5751 onclause: Optional[_OnClauseArgument] = None, 

5752 *, 

5753 isouter: bool = False, 

5754 full: bool = False, 

5755 ) -> Self: 

5756 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5757 object's criterion 

5758 and apply generatively, returning the newly resulting 

5759 :class:`_expression.Select`. 

5760 

5761 E.g.:: 

5762 

5763 stmt = select(user_table).join( 

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

5765 ) 

5766 

5767 The above statement generates SQL similar to: 

5768 

5769 .. sourcecode:: sql 

5770 

5771 SELECT user.id, user.name 

5772 FROM user 

5773 JOIN address ON user.id = address.user_id 

5774 

5775 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5776 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5777 source that is within the FROM clause of the existing SELECT, 

5778 and a given target :class:`_sql.FromClause`, and then adds 

5779 this :class:`_sql.Join` to the FROM clause of the newly generated 

5780 SELECT statement. This is completely reworked from the behavior 

5781 in 1.3, which would instead create a subquery of the entire 

5782 :class:`_expression.Select` and then join that subquery to the 

5783 target. 

5784 

5785 This is a **backwards incompatible change** as the previous behavior 

5786 was mostly useless, producing an unnamed subquery rejected by 

5787 most databases in any case. The new behavior is modeled after 

5788 that of the very successful :meth:`_orm.Query.join` method in the 

5789 ORM, in order to support the functionality of :class:`_orm.Query` 

5790 being available by using a :class:`_sql.Select` object with an 

5791 :class:`_orm.Session`. 

5792 

5793 See the notes for this change at :ref:`change_select_join`. 

5794 

5795 

5796 :param target: target table to join towards 

5797 

5798 :param onclause: ON clause of the join. If omitted, an ON clause 

5799 is generated automatically based on the :class:`_schema.ForeignKey` 

5800 linkages between the two tables, if one can be unambiguously 

5801 determined, otherwise an error is raised. 

5802 

5803 :param isouter: if True, generate LEFT OUTER join. Same as 

5804 :meth:`_expression.Select.outerjoin`. 

5805 

5806 :param full: if True, generate FULL OUTER join. 

5807 

5808 .. seealso:: 

5809 

5810 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5811 

5812 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5813 

5814 :meth:`_expression.Select.join_from` 

5815 

5816 :meth:`_expression.Select.outerjoin` 

5817 

5818 """ # noqa: E501 

5819 join_target = coercions.expect( 

5820 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5821 ) 

5822 if onclause is not None: 

5823 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5824 else: 

5825 onclause_element = None 

5826 

5827 self._setup_joins += ( 

5828 ( 

5829 join_target, 

5830 onclause_element, 

5831 None, 

5832 {"isouter": isouter, "full": full}, 

5833 ), 

5834 ) 

5835 return self 

5836 

5837 def outerjoin_from( 

5838 self, 

5839 from_: _FromClauseArgument, 

5840 target: _JoinTargetArgument, 

5841 onclause: Optional[_OnClauseArgument] = None, 

5842 *, 

5843 full: bool = False, 

5844 ) -> Self: 

5845 r"""Create a SQL LEFT OUTER JOIN against this 

5846 :class:`_expression.Select` object's criterion and apply generatively, 

5847 returning the newly resulting :class:`_expression.Select`. 

5848 

5849 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5850 

5851 """ 

5852 return self.join_from( 

5853 from_, target, onclause=onclause, isouter=True, full=full 

5854 ) 

5855 

5856 @_generative 

5857 def join_from( 

5858 self, 

5859 from_: _FromClauseArgument, 

5860 target: _JoinTargetArgument, 

5861 onclause: Optional[_OnClauseArgument] = None, 

5862 *, 

5863 isouter: bool = False, 

5864 full: bool = False, 

5865 ) -> Self: 

5866 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5867 object's criterion 

5868 and apply generatively, returning the newly resulting 

5869 :class:`_expression.Select`. 

5870 

5871 E.g.:: 

5872 

5873 stmt = select(user_table, address_table).join_from( 

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

5875 ) 

5876 

5877 The above statement generates SQL similar to: 

5878 

5879 .. sourcecode:: sql 

5880 

5881 SELECT user.id, user.name, address.id, address.email, address.user_id 

5882 FROM user JOIN address ON user.id = address.user_id 

5883 

5884 .. versionadded:: 1.4 

5885 

5886 :param from\_: the left side of the join, will be rendered in the 

5887 FROM clause and is roughly equivalent to using the 

5888 :meth:`.Select.select_from` method. 

5889 

5890 :param target: target table to join towards 

5891 

5892 :param onclause: ON clause of the join. 

5893 

5894 :param isouter: if True, generate LEFT OUTER join. Same as 

5895 :meth:`_expression.Select.outerjoin`. 

5896 

5897 :param full: if True, generate FULL OUTER join. 

5898 

5899 .. seealso:: 

5900 

5901 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5902 

5903 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5904 

5905 :meth:`_expression.Select.join` 

5906 

5907 """ # noqa: E501 

5908 

5909 # note the order of parsing from vs. target is important here, as we 

5910 # are also deriving the source of the plugin (i.e. the subject mapper 

5911 # in an ORM query) which should favor the "from_" over the "target" 

5912 

5913 from_ = coercions.expect( 

5914 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5915 ) 

5916 join_target = coercions.expect( 

5917 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5918 ) 

5919 if onclause is not None: 

5920 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5921 else: 

5922 onclause_element = None 

5923 

5924 self._setup_joins += ( 

5925 ( 

5926 join_target, 

5927 onclause_element, 

5928 from_, 

5929 {"isouter": isouter, "full": full}, 

5930 ), 

5931 ) 

5932 return self 

5933 

5934 def outerjoin( 

5935 self, 

5936 target: _JoinTargetArgument, 

5937 onclause: Optional[_OnClauseArgument] = None, 

5938 *, 

5939 full: bool = False, 

5940 ) -> Self: 

5941 """Create a left outer join. 

5942 

5943 Parameters are the same as that of :meth:`_expression.Select.join`. 

5944 

5945 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5946 creates a :class:`_sql.Join` object between a 

5947 :class:`_sql.FromClause` source that is within the FROM clause of 

5948 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5949 and then adds this :class:`_sql.Join` to the FROM clause of the 

5950 newly generated SELECT statement. This is completely reworked 

5951 from the behavior in 1.3, which would instead create a subquery of 

5952 the entire 

5953 :class:`_expression.Select` and then join that subquery to the 

5954 target. 

5955 

5956 This is a **backwards incompatible change** as the previous behavior 

5957 was mostly useless, producing an unnamed subquery rejected by 

5958 most databases in any case. The new behavior is modeled after 

5959 that of the very successful :meth:`_orm.Query.join` method in the 

5960 ORM, in order to support the functionality of :class:`_orm.Query` 

5961 being available by using a :class:`_sql.Select` object with an 

5962 :class:`_orm.Session`. 

5963 

5964 See the notes for this change at :ref:`change_select_join`. 

5965 

5966 .. seealso:: 

5967 

5968 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5969 

5970 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5971 

5972 :meth:`_expression.Select.join` 

5973 

5974 """ 

5975 return self.join(target, onclause=onclause, isouter=True, full=full) 

5976 

5977 def get_final_froms(self) -> Sequence[FromClause]: 

5978 """Compute the final displayed list of :class:`_expression.FromClause` 

5979 elements. 

5980 

5981 This method will run through the full computation required to 

5982 determine what FROM elements will be displayed in the resulting 

5983 SELECT statement, including shadowing individual tables with 

5984 JOIN objects, as well as full computation for ORM use cases including 

5985 eager loading clauses. 

5986 

5987 For ORM use, this accessor returns the **post compilation** 

5988 list of FROM objects; this collection will include elements such as 

5989 eagerly loaded tables and joins. The objects will **not** be 

5990 ORM enabled and not work as a replacement for the 

5991 :meth:`_sql.Select.select_froms` collection; additionally, the 

5992 method is not well performing for an ORM enabled statement as it 

5993 will incur the full ORM construction process. 

5994 

5995 To retrieve the FROM list that's implied by the "columns" collection 

5996 passed to the :class:`_sql.Select` originally, use the 

5997 :attr:`_sql.Select.columns_clause_froms` accessor. 

5998 

5999 To select from an alternative set of columns while maintaining the 

6000 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

6001 pass the 

6002 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6003 parameter. 

6004 

6005 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

6006 method replaces the previous :attr:`_sql.Select.froms` accessor, 

6007 which is deprecated. 

6008 

6009 .. seealso:: 

6010 

6011 :attr:`_sql.Select.columns_clause_froms` 

6012 

6013 """ 

6014 compiler = self._default_compiler() 

6015 

6016 return self._compile_state_factory(self, compiler)._get_display_froms() 

6017 

6018 @property 

6019 @util.deprecated( 

6020 "1.4.23", 

6021 "The :attr:`_expression.Select.froms` attribute is moved to " 

6022 "the :meth:`_expression.Select.get_final_froms` method.", 

6023 ) 

6024 def froms(self) -> Sequence[FromClause]: 

6025 """Return the displayed list of :class:`_expression.FromClause` 

6026 elements. 

6027 

6028 

6029 """ 

6030 return self.get_final_froms() 

6031 

6032 @property 

6033 def columns_clause_froms(self) -> List[FromClause]: 

6034 """Return the set of :class:`_expression.FromClause` objects implied 

6035 by the columns clause of this SELECT statement. 

6036 

6037 .. versionadded:: 1.4.23 

6038 

6039 .. seealso:: 

6040 

6041 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

6042 statement into account 

6043 

6044 :meth:`_sql.Select.with_only_columns` - makes use of this 

6045 collection to set up a new FROM list 

6046 

6047 """ 

6048 

6049 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

6050 self 

6051 ) 

6052 

6053 @property 

6054 def inner_columns(self) -> _SelectIterable: 

6055 """An iterator of all :class:`_expression.ColumnElement` 

6056 expressions which would 

6057 be rendered into the columns clause of the resulting SELECT statement. 

6058 

6059 This method is legacy as of 1.4 and is superseded by the 

6060 :attr:`_expression.Select.exported_columns` collection. 

6061 

6062 """ 

6063 

6064 return iter(self._all_selected_columns) 

6065 

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

6067 if fromclause is not None and self in fromclause._cloned_set: 

6068 return True 

6069 

6070 for f in self._iterate_from_elements(): 

6071 if f.is_derived_from(fromclause): 

6072 return True 

6073 return False 

6074 

6075 def _copy_internals( 

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

6077 ) -> None: 

6078 # Select() object has been cloned and probably adapted by the 

6079 # given clone function. Apply the cloning function to internal 

6080 # objects 

6081 

6082 # 1. keep a dictionary of the froms we've cloned, and what 

6083 # they've become. This allows us to ensure the same cloned from 

6084 # is used when other items such as columns are "cloned" 

6085 

6086 all_the_froms = set( 

6087 itertools.chain( 

6088 _from_objects(*self._raw_columns), 

6089 _from_objects(*self._where_criteria), 

6090 _from_objects(*[elem[0] for elem in self._setup_joins]), 

6091 ) 

6092 ) 

6093 

6094 # do a clone for the froms we've gathered. what is important here 

6095 # is if any of the things we are selecting from, like tables, 

6096 # were converted into Join objects. if so, these need to be 

6097 # added to _from_obj explicitly, because otherwise they won't be 

6098 # part of the new state, as they don't associate themselves with 

6099 # their columns. 

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

6101 

6102 # 2. copy FROM collections, adding in joins that we've created. 

6103 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

6104 add_froms = ( 

6105 {f for f in new_froms.values() if isinstance(f, Join)} 

6106 .difference(all_the_froms) 

6107 .difference(existing_from_obj) 

6108 ) 

6109 

6110 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

6111 

6112 # 3. clone everything else, making sure we use columns 

6113 # corresponding to the froms we just made. 

6114 def replace( 

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

6116 **kw: Any, 

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

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

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

6120 return newelem 

6121 return None 

6122 

6123 kw["replace"] = replace 

6124 

6125 # copy everything else. for table-ish things like correlate, 

6126 # correlate_except, setup_joins, these clone normally. For 

6127 # column-expression oriented things like raw_columns, where_criteria, 

6128 # order by, we get this from the new froms. 

6129 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

6130 

6131 self._reset_memoizations() 

6132 

6133 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

6134 return itertools.chain( 

6135 super().get_children( 

6136 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

6137 **kw, 

6138 ), 

6139 self._iterate_from_elements(), 

6140 ) 

6141 

6142 @_generative 

6143 def add_columns( 

6144 self, *entities: _ColumnsClauseArgument[Any] 

6145 ) -> Select[Unpack[TupleAny]]: 

6146 r"""Return a new :func:`_expression.select` construct with 

6147 the given entities appended to its columns clause. 

6148 

6149 E.g.:: 

6150 

6151 my_select = my_select.add_columns(table.c.new_column) 

6152 

6153 The original expressions in the columns clause remain in place. 

6154 To replace the original expressions with new ones, see the method 

6155 :meth:`_expression.Select.with_only_columns`. 

6156 

6157 :param \*entities: column, table, or other entity expressions to be 

6158 added to the columns clause 

6159 

6160 .. seealso:: 

6161 

6162 :meth:`_expression.Select.with_only_columns` - replaces existing 

6163 expressions rather than appending. 

6164 

6165 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

6166 example 

6167 

6168 """ 

6169 self._reset_memoizations() 

6170 

6171 self._raw_columns = self._raw_columns + [ 

6172 coercions.expect( 

6173 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

6174 ) 

6175 for column in entities 

6176 ] 

6177 return self 

6178 

6179 def _set_entities( 

6180 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

6181 ) -> None: 

6182 self._raw_columns = [ 

6183 coercions.expect( 

6184 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6185 ) 

6186 for ent in util.to_list(entities) 

6187 ] 

6188 

6189 @util.deprecated( 

6190 "1.4", 

6191 "The :meth:`_expression.Select.column` method is deprecated and will " 

6192 "be removed in a future release. Please use " 

6193 ":meth:`_expression.Select.add_columns`", 

6194 ) 

6195 def column( 

6196 self, column: _ColumnsClauseArgument[Any] 

6197 ) -> Select[Unpack[TupleAny]]: 

6198 """Return a new :func:`_expression.select` construct with 

6199 the given column expression added to its columns clause. 

6200 

6201 E.g.:: 

6202 

6203 my_select = my_select.column(table.c.new_column) 

6204 

6205 See the documentation for 

6206 :meth:`_expression.Select.with_only_columns` 

6207 for guidelines on adding /replacing the columns of a 

6208 :class:`_expression.Select` object. 

6209 

6210 """ 

6211 return self.add_columns(column) 

6212 

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

6214 def reduce_columns( 

6215 self, only_synonyms: bool = True 

6216 ) -> Select[Unpack[TupleAny]]: 

6217 """Return a new :func:`_expression.select` construct with redundantly 

6218 named, equivalently-valued columns removed from the columns clause. 

6219 

6220 "Redundant" here means two columns where one refers to the 

6221 other either based on foreign key, or via a simple equality 

6222 comparison in the WHERE clause of the statement. The primary purpose 

6223 of this method is to automatically construct a select statement 

6224 with all uniquely-named columns, without the need to use 

6225 table-qualified labels as 

6226 :meth:`_expression.Select.set_label_style` 

6227 does. 

6228 

6229 When columns are omitted based on foreign key, the referred-to 

6230 column is the one that's kept. When columns are omitted based on 

6231 WHERE equivalence, the first column in the columns clause is the 

6232 one that's kept. 

6233 

6234 :param only_synonyms: when True, limit the removal of columns 

6235 to those which have the same name as the equivalent. Otherwise, 

6236 all columns that are equivalent to another are removed. 

6237 

6238 """ 

6239 woc: Select[Unpack[TupleAny]] 

6240 woc = self.with_only_columns( 

6241 *util.preloaded.sql_util.reduce_columns( 

6242 self._all_selected_columns, 

6243 only_synonyms=only_synonyms, 

6244 *(self._where_criteria + self._from_obj), 

6245 ) 

6246 ) 

6247 return woc 

6248 

6249 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6250 

6251 # code within this block is **programmatically, 

6252 # statically generated** by tools/generate_tuple_map_overloads.py 

6253 

6254 @overload 

6255 def with_only_columns( 

6256 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6257 ) -> Select[_T0]: ... 

6258 

6259 @overload 

6260 def with_only_columns( 

6261 self, 

6262 __ent0: _TCCA[_T0], 

6263 __ent1: _TCCA[_T1], 

6264 /, 

6265 *, 

6266 maintain_column_froms: bool = ..., 

6267 ) -> Select[_T0, _T1]: ... 

6268 

6269 @overload 

6270 def with_only_columns( 

6271 self, 

6272 __ent0: _TCCA[_T0], 

6273 __ent1: _TCCA[_T1], 

6274 __ent2: _TCCA[_T2], 

6275 /, 

6276 *, 

6277 maintain_column_froms: bool = ..., 

6278 ) -> Select[_T0, _T1, _T2]: ... 

6279 

6280 @overload 

6281 def with_only_columns( 

6282 self, 

6283 __ent0: _TCCA[_T0], 

6284 __ent1: _TCCA[_T1], 

6285 __ent2: _TCCA[_T2], 

6286 __ent3: _TCCA[_T3], 

6287 /, 

6288 *, 

6289 maintain_column_froms: bool = ..., 

6290 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6291 

6292 @overload 

6293 def with_only_columns( 

6294 self, 

6295 __ent0: _TCCA[_T0], 

6296 __ent1: _TCCA[_T1], 

6297 __ent2: _TCCA[_T2], 

6298 __ent3: _TCCA[_T3], 

6299 __ent4: _TCCA[_T4], 

6300 /, 

6301 *, 

6302 maintain_column_froms: bool = ..., 

6303 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6304 

6305 @overload 

6306 def with_only_columns( 

6307 self, 

6308 __ent0: _TCCA[_T0], 

6309 __ent1: _TCCA[_T1], 

6310 __ent2: _TCCA[_T2], 

6311 __ent3: _TCCA[_T3], 

6312 __ent4: _TCCA[_T4], 

6313 __ent5: _TCCA[_T5], 

6314 /, 

6315 *, 

6316 maintain_column_froms: bool = ..., 

6317 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6318 

6319 @overload 

6320 def with_only_columns( 

6321 self, 

6322 __ent0: _TCCA[_T0], 

6323 __ent1: _TCCA[_T1], 

6324 __ent2: _TCCA[_T2], 

6325 __ent3: _TCCA[_T3], 

6326 __ent4: _TCCA[_T4], 

6327 __ent5: _TCCA[_T5], 

6328 __ent6: _TCCA[_T6], 

6329 /, 

6330 *, 

6331 maintain_column_froms: bool = ..., 

6332 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6333 

6334 @overload 

6335 def with_only_columns( 

6336 self, 

6337 __ent0: _TCCA[_T0], 

6338 __ent1: _TCCA[_T1], 

6339 __ent2: _TCCA[_T2], 

6340 __ent3: _TCCA[_T3], 

6341 __ent4: _TCCA[_T4], 

6342 __ent5: _TCCA[_T5], 

6343 __ent6: _TCCA[_T6], 

6344 __ent7: _TCCA[_T7], 

6345 /, 

6346 *entities: _ColumnsClauseArgument[Any], 

6347 maintain_column_froms: bool = ..., 

6348 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6349 

6350 # END OVERLOADED FUNCTIONS self.with_only_columns 

6351 

6352 @overload 

6353 def with_only_columns( 

6354 self, 

6355 *entities: _ColumnsClauseArgument[Any], 

6356 maintain_column_froms: bool = False, 

6357 **__kw: Any, 

6358 ) -> Select[Unpack[TupleAny]]: ... 

6359 

6360 @_generative 

6361 def with_only_columns( 

6362 self, 

6363 *entities: _ColumnsClauseArgument[Any], 

6364 maintain_column_froms: bool = False, 

6365 **__kw: Any, 

6366 ) -> Select[Unpack[TupleAny]]: 

6367 r"""Return a new :func:`_expression.select` construct with its columns 

6368 clause replaced with the given entities. 

6369 

6370 By default, this method is exactly equivalent to as if the original 

6371 :func:`_expression.select` had been called with the given entities. 

6372 E.g. a statement:: 

6373 

6374 s = select(table1.c.a, table1.c.b) 

6375 s = s.with_only_columns(table1.c.b) 

6376 

6377 should be exactly equivalent to:: 

6378 

6379 s = select(table1.c.b) 

6380 

6381 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6382 will also dynamically alter the FROM clause of the 

6383 statement if it is not explicitly stated. 

6384 To maintain the existing set of FROMs including those implied by the 

6385 current columns clause, add the 

6386 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6387 parameter:: 

6388 

6389 s = select(table1.c.a, table2.c.b) 

6390 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6391 

6392 The above parameter performs a transfer of the effective FROMs 

6393 in the columns collection to the :meth:`_sql.Select.select_from` 

6394 method, as though the following were invoked:: 

6395 

6396 s = select(table1.c.a, table2.c.b) 

6397 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6398 

6399 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6400 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6401 collection and performs an operation equivalent to the following:: 

6402 

6403 s = select(table1.c.a, table2.c.b) 

6404 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6405 

6406 :param \*entities: column expressions to be used. 

6407 

6408 :param maintain_column_froms: boolean parameter that will ensure the 

6409 FROM list implied from the current columns clause will be transferred 

6410 to the :meth:`_sql.Select.select_from` method first. 

6411 

6412 .. versionadded:: 1.4.23 

6413 

6414 """ # noqa: E501 

6415 

6416 if __kw: 

6417 raise _no_kw() 

6418 

6419 # memoizations should be cleared here as of 

6420 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6421 # is the case for now. 

6422 self._assert_no_memoizations() 

6423 

6424 if maintain_column_froms: 

6425 self.select_from.non_generative( # type: ignore 

6426 self, *self.columns_clause_froms 

6427 ) 

6428 

6429 # then memoize the FROMs etc. 

6430 _MemoizedSelectEntities._generate_for_statement(self) 

6431 

6432 self._raw_columns = [ 

6433 coercions.expect(roles.ColumnsClauseRole, c) 

6434 for c in coercions._expression_collection_was_a_list( 

6435 "entities", "Select.with_only_columns", entities 

6436 ) 

6437 ] 

6438 return self 

6439 

6440 @property 

6441 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6442 """Return the completed WHERE clause for this 

6443 :class:`_expression.Select` statement. 

6444 

6445 This assembles the current collection of WHERE criteria 

6446 into a single :class:`_expression.BooleanClauseList` construct. 

6447 

6448 

6449 .. versionadded:: 1.4 

6450 

6451 """ 

6452 

6453 return BooleanClauseList._construct_for_whereclause( 

6454 self._where_criteria 

6455 ) 

6456 

6457 _whereclause = whereclause 

6458 

6459 @_generative 

6460 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6461 """Return a new :func:`_expression.select` construct with 

6462 the given expression added to 

6463 its WHERE clause, joined to the existing clause via AND, if any. 

6464 

6465 """ 

6466 

6467 assert isinstance(self._where_criteria, tuple) 

6468 

6469 for criterion in whereclause: 

6470 where_criteria: ColumnElement[Any] = coercions.expect( 

6471 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6472 ) 

6473 self._where_criteria += (where_criteria,) 

6474 return self 

6475 

6476 @_generative 

6477 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6478 """Return a new :func:`_expression.select` construct with 

6479 the given expression added to 

6480 its HAVING clause, joined to the existing clause via AND, if any. 

6481 

6482 """ 

6483 

6484 for criterion in having: 

6485 having_criteria = coercions.expect( 

6486 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6487 ) 

6488 self._having_criteria += (having_criteria,) 

6489 return self 

6490 

6491 @_generative 

6492 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6493 r"""Return a new :func:`_expression.select` construct which 

6494 will apply DISTINCT to the SELECT statement overall. 

6495 

6496 E.g.:: 

6497 

6498 from sqlalchemy import select 

6499 

6500 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6501 

6502 The above would produce an statement resembling: 

6503 

6504 .. sourcecode:: sql 

6505 

6506 SELECT DISTINCT user.id, user.name FROM user 

6507 

6508 The method also historically accepted an ``*expr`` parameter which 

6509 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6510 This is now replaced using the :func:`_postgresql.distinct_on` 

6511 extension:: 

6512 

6513 from sqlalchemy import select 

6514 from sqlalchemy.dialects.postgresql import distinct_on 

6515 

6516 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6517 

6518 Using this parameter on other backends which don't support this 

6519 syntax will raise an error. 

6520 

6521 :param \*expr: optional column expressions. When present, 

6522 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6523 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6524 will be raised on other backends. 

6525 

6526 .. deprecated:: 2.1 Passing expressions to 

6527 :meth:`_sql.Select.distinct` is deprecated, use 

6528 :func:`_postgresql.distinct_on` instead. 

6529 

6530 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6531 and will raise :class:`_exc.CompileError` in a future version. 

6532 

6533 .. seealso:: 

6534 

6535 :func:`_postgresql.distinct_on` 

6536 

6537 :meth:`.ext` 

6538 """ 

6539 self._distinct = True 

6540 if expr: 

6541 warn_deprecated( 

6542 "Passing expression to ``distinct`` to generate a " 

6543 "DISTINCT ON clause is deprecated. Use instead the " 

6544 "``postgresql.distinct_on`` function as an extension.", 

6545 "2.1", 

6546 ) 

6547 self._distinct_on = self._distinct_on + tuple( 

6548 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6549 for e in expr 

6550 ) 

6551 return self 

6552 

6553 @_generative 

6554 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6555 r"""Return a new :func:`_expression.select` construct with the 

6556 given FROM expression(s) 

6557 merged into its list of FROM objects. 

6558 

6559 E.g.:: 

6560 

6561 table1 = table("t1", column("a")) 

6562 table2 = table("t2", column("b")) 

6563 s = select(table1.c.a).select_from( 

6564 table1.join(table2, table1.c.a == table2.c.b) 

6565 ) 

6566 

6567 The "from" list is a unique set on the identity of each element, 

6568 so adding an already present :class:`_schema.Table` 

6569 or other selectable 

6570 will have no effect. Passing a :class:`_expression.Join` that refers 

6571 to an already present :class:`_schema.Table` 

6572 or other selectable will have 

6573 the effect of concealing the presence of that selectable as 

6574 an individual element in the rendered FROM list, instead 

6575 rendering it into a JOIN clause. 

6576 

6577 While the typical purpose of :meth:`_expression.Select.select_from` 

6578 is to 

6579 replace the default, derived FROM clause with a join, it can 

6580 also be called with individual table elements, multiple times 

6581 if desired, in the case that the FROM clause cannot be fully 

6582 derived from the columns clause:: 

6583 

6584 select(func.count("*")).select_from(table1) 

6585 

6586 """ 

6587 

6588 self._from_obj += tuple( 

6589 coercions.expect( 

6590 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6591 ) 

6592 for fromclause in froms 

6593 ) 

6594 return self 

6595 

6596 @_generative 

6597 def correlate( 

6598 self, 

6599 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6600 ) -> Self: 

6601 r"""Return a new :class:`_expression.Select` 

6602 which will correlate the given FROM 

6603 clauses to that of an enclosing :class:`_expression.Select`. 

6604 

6605 Calling this method turns off the :class:`_expression.Select` object's 

6606 default behavior of "auto-correlation". Normally, FROM elements 

6607 which appear in a :class:`_expression.Select` 

6608 that encloses this one via 

6609 its :term:`WHERE clause`, ORDER BY, HAVING or 

6610 :term:`columns clause` will be omitted from this 

6611 :class:`_expression.Select` 

6612 object's :term:`FROM clause`. 

6613 Setting an explicit correlation collection using the 

6614 :meth:`_expression.Select.correlate` 

6615 method provides a fixed list of FROM objects 

6616 that can potentially take place in this process. 

6617 

6618 When :meth:`_expression.Select.correlate` 

6619 is used to apply specific FROM clauses 

6620 for correlation, the FROM elements become candidates for 

6621 correlation regardless of how deeply nested this 

6622 :class:`_expression.Select` 

6623 object is, relative to an enclosing :class:`_expression.Select` 

6624 which refers to 

6625 the same FROM object. This is in contrast to the behavior of 

6626 "auto-correlation" which only correlates to an immediate enclosing 

6627 :class:`_expression.Select`. 

6628 Multi-level correlation ensures that the link 

6629 between enclosed and enclosing :class:`_expression.Select` 

6630 is always via 

6631 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6632 correlation to take place. 

6633 

6634 If ``None`` is passed, the :class:`_expression.Select` 

6635 object will correlate 

6636 none of its FROM entries, and all will render unconditionally 

6637 in the local FROM clause. 

6638 

6639 :param \*fromclauses: one or more :class:`.FromClause` or other 

6640 FROM-compatible construct such as an ORM mapped entity to become part 

6641 of the correlate collection; alternatively pass a single value 

6642 ``None`` to remove all existing correlations. 

6643 

6644 .. seealso:: 

6645 

6646 :meth:`_expression.Select.correlate_except` 

6647 

6648 :ref:`tutorial_scalar_subquery` 

6649 

6650 """ 

6651 

6652 # tests failing when we try to change how these 

6653 # arguments are passed 

6654 

6655 self._auto_correlate = False 

6656 if not fromclauses or fromclauses[0] in {None, False}: 

6657 if len(fromclauses) > 1: 

6658 raise exc.ArgumentError( 

6659 "additional FROM objects not accepted when " 

6660 "passing None/False to correlate()" 

6661 ) 

6662 self._correlate = () 

6663 else: 

6664 self._correlate = self._correlate + tuple( 

6665 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6666 ) 

6667 return self 

6668 

6669 @_generative 

6670 def correlate_except( 

6671 self, 

6672 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6673 ) -> Self: 

6674 r"""Return a new :class:`_expression.Select` 

6675 which will omit the given FROM 

6676 clauses from the auto-correlation process. 

6677 

6678 Calling :meth:`_expression.Select.correlate_except` turns off the 

6679 :class:`_expression.Select` object's default behavior of 

6680 "auto-correlation" for the given FROM elements. An element 

6681 specified here will unconditionally appear in the FROM list, while 

6682 all other FROM elements remain subject to normal auto-correlation 

6683 behaviors. 

6684 

6685 If ``None`` is passed, or no arguments are passed, 

6686 the :class:`_expression.Select` object will correlate all of its 

6687 FROM entries. 

6688 

6689 :param \*fromclauses: a list of one or more 

6690 :class:`_expression.FromClause` 

6691 constructs, or other compatible constructs (i.e. ORM-mapped 

6692 classes) to become part of the correlate-exception collection. 

6693 

6694 .. seealso:: 

6695 

6696 :meth:`_expression.Select.correlate` 

6697 

6698 :ref:`tutorial_scalar_subquery` 

6699 

6700 """ 

6701 

6702 self._auto_correlate = False 

6703 if not fromclauses or fromclauses[0] in {None, False}: 

6704 if len(fromclauses) > 1: 

6705 raise exc.ArgumentError( 

6706 "additional FROM objects not accepted when " 

6707 "passing None/False to correlate_except()" 

6708 ) 

6709 self._correlate_except = () 

6710 else: 

6711 self._correlate_except = (self._correlate_except or ()) + tuple( 

6712 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6713 ) 

6714 

6715 return self 

6716 

6717 @HasMemoized_ro_memoized_attribute 

6718 def selected_columns( 

6719 self, 

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

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

6722 representing the columns that 

6723 this SELECT statement or similar construct returns in its result set, 

6724 not including :class:`_sql.TextClause` constructs. 

6725 

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

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

6728 within this collection cannot be directly nested inside another SELECT 

6729 statement; a subquery must be applied first which provides for the 

6730 necessary parenthesization required by SQL. 

6731 

6732 For a :func:`_expression.select` construct, the collection here is 

6733 exactly what would be rendered inside the "SELECT" statement, and the 

6734 :class:`_expression.ColumnElement` objects are directly present as they 

6735 were given, e.g.:: 

6736 

6737 col1 = column("q", Integer) 

6738 col2 = column("p", Integer) 

6739 stmt = select(col1, col2) 

6740 

6741 Above, ``stmt.selected_columns`` would be a collection that contains 

6742 the ``col1`` and ``col2`` objects directly. For a statement that is 

6743 against a :class:`_schema.Table` or other 

6744 :class:`_expression.FromClause`, the collection will use the 

6745 :class:`_expression.ColumnElement` objects that are in the 

6746 :attr:`_expression.FromClause.c` collection of the from element. 

6747 

6748 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6749 to allow the existing columns to be referenced when adding additional 

6750 criteria, e.g.:: 

6751 

6752 def filter_on_id(my_select, id): 

6753 return my_select.where(my_select.selected_columns["id"] == id) 

6754 

6755 

6756 stmt = select(MyModel) 

6757 

6758 # adds "WHERE id=:param" to the statement 

6759 stmt = filter_on_id(stmt, 42) 

6760 

6761 .. note:: 

6762 

6763 The :attr:`_sql.Select.selected_columns` collection does not 

6764 include expressions established in the columns clause using the 

6765 :func:`_sql.text` construct; these are silently omitted from the 

6766 collection. To use plain textual column expressions inside of a 

6767 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6768 construct. 

6769 

6770 

6771 .. versionadded:: 1.4 

6772 

6773 """ 

6774 

6775 # compare to SelectState._generate_columns_plus_names, which 

6776 # generates the actual names used in the SELECT string. that 

6777 # method is more complex because it also renders columns that are 

6778 # fully ambiguous, e.g. same column more than once. 

6779 conv = cast( 

6780 "Callable[[Any], str]", 

6781 SelectState._column_naming_convention(self._label_style), 

6782 ) 

6783 

6784 cc: WriteableColumnCollection[str, ColumnElement[Any]] = ( 

6785 WriteableColumnCollection( 

6786 [ 

6787 (conv(c), c) 

6788 for c in self._all_selected_columns 

6789 if is_column_element(c) 

6790 ] 

6791 ) 

6792 ) 

6793 return cc.as_readonly() 

6794 

6795 @HasMemoized_ro_memoized_attribute 

6796 def _all_selected_columns(self) -> _SelectIterable: 

6797 meth = SelectState.get_plugin_class(self).all_selected_columns 

6798 return list(meth(self)) 

6799 

6800 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6801 if self._label_style is LABEL_STYLE_NONE: 

6802 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6803 return self 

6804 

6805 def _generate_fromclause_column_proxies( 

6806 self, 

6807 subquery: FromClause, 

6808 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

6809 primary_key: ColumnSet, 

6810 foreign_keys: Set[KeyedColumnElement[Any]], 

6811 *, 

6812 proxy_compound_columns: Optional[ 

6813 Iterable[Sequence[ColumnElement[Any]]] 

6814 ] = None, 

6815 ) -> None: 

6816 """Generate column proxies to place in the exported ``.c`` 

6817 collection of a subquery.""" 

6818 

6819 if proxy_compound_columns: 

6820 extra_col_iterator = proxy_compound_columns 

6821 prox = [ 

6822 c._make_proxy( 

6823 subquery, 

6824 key=proxy_key, 

6825 name=required_label_name, 

6826 name_is_truncatable=True, 

6827 compound_select_cols=extra_cols, 

6828 primary_key=primary_key, 

6829 foreign_keys=foreign_keys, 

6830 ) 

6831 for ( 

6832 ( 

6833 required_label_name, 

6834 proxy_key, 

6835 fallback_label_name, 

6836 c, 

6837 repeated, 

6838 ), 

6839 extra_cols, 

6840 ) in ( 

6841 zip( 

6842 self._generate_columns_plus_names(False), 

6843 extra_col_iterator, 

6844 ) 

6845 ) 

6846 if is_column_element(c) 

6847 ] 

6848 else: 

6849 prox = [ 

6850 c._make_proxy( 

6851 subquery, 

6852 key=proxy_key, 

6853 name=required_label_name, 

6854 name_is_truncatable=True, 

6855 primary_key=primary_key, 

6856 foreign_keys=foreign_keys, 

6857 ) 

6858 for ( 

6859 required_label_name, 

6860 proxy_key, 

6861 fallback_label_name, 

6862 c, 

6863 repeated, 

6864 ) in (self._generate_columns_plus_names(False)) 

6865 if is_column_element(c) 

6866 ] 

6867 

6868 columns._populate_separate_keys(prox) 

6869 

6870 def _needs_parens_for_grouping(self) -> bool: 

6871 return self._has_row_limiting_clause or bool( 

6872 self._order_by_clause.clauses 

6873 ) 

6874 

6875 def self_group( 

6876 self, against: Optional[OperatorType] = None 

6877 ) -> Union[SelectStatementGrouping[Self], Self]: 

6878 """Return a 'grouping' construct as per the 

6879 :class:`_expression.ClauseElement` specification. 

6880 

6881 This produces an element that can be embedded in an expression. Note 

6882 that this method is called automatically as needed when constructing 

6883 expressions and should not require explicit use. 

6884 

6885 """ 

6886 if ( 

6887 isinstance(against, CompoundSelect) 

6888 and not self._needs_parens_for_grouping() 

6889 ): 

6890 return self 

6891 else: 

6892 return SelectStatementGrouping(self) 

6893 

6894 def union( 

6895 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6896 ) -> CompoundSelect[Unpack[_Ts]]: 

6897 r"""Return a SQL ``UNION`` of this select() construct against 

6898 the given selectables provided as positional arguments. 

6899 

6900 :param \*other: one or more elements with which to create a 

6901 UNION. 

6902 

6903 .. versionchanged:: 1.4.28 

6904 

6905 multiple elements are now accepted. 

6906 

6907 :param \**kwargs: keyword arguments are forwarded to the constructor 

6908 for the newly created :class:`_sql.CompoundSelect` object. 

6909 

6910 """ 

6911 return CompoundSelect._create_union(self, *other) 

6912 

6913 def union_all( 

6914 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6915 ) -> CompoundSelect[Unpack[_Ts]]: 

6916 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6917 the given selectables provided as positional arguments. 

6918 

6919 :param \*other: one or more elements with which to create a 

6920 UNION. 

6921 

6922 .. versionchanged:: 1.4.28 

6923 

6924 multiple elements are now accepted. 

6925 

6926 :param \**kwargs: keyword arguments are forwarded to the constructor 

6927 for the newly created :class:`_sql.CompoundSelect` object. 

6928 

6929 """ 

6930 return CompoundSelect._create_union_all(self, *other) 

6931 

6932 def except_( 

6933 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6934 ) -> CompoundSelect[Unpack[_Ts]]: 

6935 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6936 the given selectable provided as positional arguments. 

6937 

6938 :param \*other: one or more elements with which to create a 

6939 UNION. 

6940 

6941 .. versionchanged:: 1.4.28 

6942 

6943 multiple elements are now accepted. 

6944 

6945 """ 

6946 return CompoundSelect._create_except(self, *other) 

6947 

6948 def except_all( 

6949 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6950 ) -> CompoundSelect[Unpack[_Ts]]: 

6951 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6952 the given selectables provided as positional arguments. 

6953 

6954 :param \*other: one or more elements with which to create a 

6955 UNION. 

6956 

6957 .. versionchanged:: 1.4.28 

6958 

6959 multiple elements are now accepted. 

6960 

6961 """ 

6962 return CompoundSelect._create_except_all(self, *other) 

6963 

6964 def intersect( 

6965 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6966 ) -> CompoundSelect[Unpack[_Ts]]: 

6967 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6968 the given selectables provided as positional arguments. 

6969 

6970 :param \*other: one or more elements with which to create a 

6971 UNION. 

6972 

6973 .. versionchanged:: 1.4.28 

6974 

6975 multiple elements are now accepted. 

6976 

6977 :param \**kwargs: keyword arguments are forwarded to the constructor 

6978 for the newly created :class:`_sql.CompoundSelect` object. 

6979 

6980 """ 

6981 return CompoundSelect._create_intersect(self, *other) 

6982 

6983 def intersect_all( 

6984 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6985 ) -> CompoundSelect[Unpack[_Ts]]: 

6986 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6987 against the given selectables provided as positional arguments. 

6988 

6989 :param \*other: one or more elements with which to create a 

6990 UNION. 

6991 

6992 .. versionchanged:: 1.4.28 

6993 

6994 multiple elements are now accepted. 

6995 

6996 :param \**kwargs: keyword arguments are forwarded to the constructor 

6997 for the newly created :class:`_sql.CompoundSelect` object. 

6998 

6999 """ 

7000 return CompoundSelect._create_intersect_all(self, *other) 

7001 

7002 

7003class ScalarSelect( 

7004 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

7005): 

7006 """Represent a scalar subquery. 

7007 

7008 

7009 A :class:`_sql.ScalarSelect` is created by invoking the 

7010 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

7011 then participates in other SQL expressions as a SQL column expression 

7012 within the :class:`_sql.ColumnElement` hierarchy. 

7013 

7014 .. seealso:: 

7015 

7016 :meth:`_sql.SelectBase.scalar_subquery` 

7017 

7018 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7019 

7020 """ 

7021 

7022 _traverse_internals: _TraverseInternalsType = [ 

7023 ("element", InternalTraversal.dp_clauseelement), 

7024 ("type", InternalTraversal.dp_type), 

7025 ] 

7026 

7027 _from_objects: List[FromClause] = [] 

7028 _is_from_container = True 

7029 if not TYPE_CHECKING: 

7030 _is_implicitly_boolean = False 

7031 inherit_cache = True 

7032 

7033 element: SelectBase 

7034 

7035 def __init__(self, element: SelectBase) -> None: 

7036 self.element = element 

7037 self.type = element._scalar_type() 

7038 self._propagate_attrs = element._propagate_attrs 

7039 

7040 def __getattr__(self, attr: str) -> Any: 

7041 return getattr(self.element, attr) 

7042 

7043 def __getstate__(self) -> Dict[str, Any]: 

7044 return {"element": self.element, "type": self.type} 

7045 

7046 def __setstate__(self, state: Dict[str, Any]) -> None: 

7047 self.element = state["element"] 

7048 self.type = state["type"] 

7049 

7050 @property 

7051 def columns(self) -> NoReturn: 

7052 raise exc.InvalidRequestError( 

7053 "Scalar Select expression has no " 

7054 "columns; use this object directly " 

7055 "within a column-level expression." 

7056 ) 

7057 

7058 c = columns 

7059 

7060 @_generative 

7061 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

7062 """Apply a WHERE clause to the SELECT statement referred to 

7063 by this :class:`_expression.ScalarSelect`. 

7064 

7065 """ 

7066 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

7067 crit 

7068 ) 

7069 return self 

7070 

7071 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

7072 return self 

7073 

7074 def _ungroup(self) -> Self: 

7075 return self 

7076 

7077 @_generative 

7078 def correlate( 

7079 self, 

7080 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7081 ) -> Self: 

7082 r"""Return a new :class:`_expression.ScalarSelect` 

7083 which will correlate the given FROM 

7084 clauses to that of an enclosing :class:`_expression.Select`. 

7085 

7086 This method is mirrored from the :meth:`_sql.Select.correlate` method 

7087 of the underlying :class:`_sql.Select`. The method applies the 

7088 :meth:_sql.Select.correlate` method, then returns a new 

7089 :class:`_sql.ScalarSelect` against that statement. 

7090 

7091 .. versionadded:: 1.4 Previously, the 

7092 :meth:`_sql.ScalarSelect.correlate` 

7093 method was only available from :class:`_sql.Select`. 

7094 

7095 :param \*fromclauses: a list of one or more 

7096 :class:`_expression.FromClause` 

7097 constructs, or other compatible constructs (i.e. ORM-mapped 

7098 classes) to become part of the correlate collection. 

7099 

7100 .. seealso:: 

7101 

7102 :meth:`_expression.ScalarSelect.correlate_except` 

7103 

7104 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7105 

7106 

7107 """ 

7108 self.element = cast( 

7109 "Select[Unpack[TupleAny]]", self.element 

7110 ).correlate(*fromclauses) 

7111 return self 

7112 

7113 @_generative 

7114 def correlate_except( 

7115 self, 

7116 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7117 ) -> Self: 

7118 r"""Return a new :class:`_expression.ScalarSelect` 

7119 which will omit the given FROM 

7120 clauses from the auto-correlation process. 

7121 

7122 This method is mirrored from the 

7123 :meth:`_sql.Select.correlate_except` method of the underlying 

7124 :class:`_sql.Select`. The method applies the 

7125 :meth:_sql.Select.correlate_except` method, then returns a new 

7126 :class:`_sql.ScalarSelect` against that statement. 

7127 

7128 .. versionadded:: 1.4 Previously, the 

7129 :meth:`_sql.ScalarSelect.correlate_except` 

7130 method was only available from :class:`_sql.Select`. 

7131 

7132 :param \*fromclauses: a list of one or more 

7133 :class:`_expression.FromClause` 

7134 constructs, or other compatible constructs (i.e. ORM-mapped 

7135 classes) to become part of the correlate-exception collection. 

7136 

7137 .. seealso:: 

7138 

7139 :meth:`_expression.ScalarSelect.correlate` 

7140 

7141 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7142 

7143 

7144 """ 

7145 

7146 self.element = cast( 

7147 "Select[Unpack[TupleAny]]", self.element 

7148 ).correlate_except(*fromclauses) 

7149 return self 

7150 

7151 

7152class Exists(UnaryExpression[bool]): 

7153 """Represent an ``EXISTS`` clause. 

7154 

7155 See :func:`_sql.exists` for a description of usage. 

7156 

7157 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

7158 instance by calling :meth:`_sql.SelectBase.exists`. 

7159 

7160 """ 

7161 

7162 inherit_cache = True 

7163 

7164 def __init__( 

7165 self, 

7166 __argument: Optional[ 

7167 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

7168 ] = None, 

7169 /, 

7170 ): 

7171 s: ScalarSelect[Any] 

7172 

7173 # TODO: this seems like we should be using coercions for this 

7174 if __argument is None: 

7175 s = Select(literal_column("*")).scalar_subquery() 

7176 elif isinstance(__argument, SelectBase): 

7177 s = __argument.scalar_subquery() 

7178 s._propagate_attrs = __argument._propagate_attrs 

7179 elif isinstance(__argument, ScalarSelect): 

7180 s = __argument 

7181 else: 

7182 s = Select(__argument).scalar_subquery() 

7183 

7184 UnaryExpression.__init__( 

7185 self, 

7186 s, 

7187 operator=operators.exists, 

7188 type_=type_api.BOOLEANTYPE, 

7189 ) 

7190 

7191 @util.ro_non_memoized_property 

7192 def _from_objects(self) -> List[FromClause]: 

7193 return [] 

7194 

7195 def _regroup( 

7196 self, 

7197 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7198 ) -> ScalarSelect[Any]: 

7199 

7200 assert isinstance(self.element, ScalarSelect) 

7201 element = self.element.element 

7202 if not isinstance(element, Select): 

7203 raise exc.InvalidRequestError( 

7204 "Can only apply this operation to a plain SELECT construct" 

7205 ) 

7206 new_element = fn(element) 

7207 

7208 return_value = new_element.scalar_subquery() 

7209 return return_value 

7210 

7211 def select(self) -> Select[bool]: 

7212 r"""Return a SELECT of this :class:`_expression.Exists`. 

7213 

7214 e.g.:: 

7215 

7216 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7217 

7218 This will produce a statement resembling: 

7219 

7220 .. sourcecode:: sql 

7221 

7222 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7223 

7224 .. seealso:: 

7225 

7226 :func:`_expression.select` - general purpose 

7227 method which allows for arbitrary column lists. 

7228 

7229 """ # noqa 

7230 

7231 return Select(self) 

7232 

7233 def correlate( 

7234 self, 

7235 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7236 ) -> Self: 

7237 """Apply correlation to the subquery noted by this 

7238 :class:`_sql.Exists`. 

7239 

7240 .. seealso:: 

7241 

7242 :meth:`_sql.ScalarSelect.correlate` 

7243 

7244 """ 

7245 e = self._clone() 

7246 e.element = self._regroup( 

7247 lambda element: element.correlate(*fromclauses) 

7248 ) 

7249 return e 

7250 

7251 def correlate_except( 

7252 self, 

7253 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7254 ) -> Self: 

7255 """Apply correlation to the subquery noted by this 

7256 :class:`_sql.Exists`. 

7257 

7258 .. seealso:: 

7259 

7260 :meth:`_sql.ScalarSelect.correlate_except` 

7261 

7262 """ 

7263 e = self._clone() 

7264 e.element = self._regroup( 

7265 lambda element: element.correlate_except(*fromclauses) 

7266 ) 

7267 return e 

7268 

7269 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7270 """Return a new :class:`_expression.Exists` construct, 

7271 applying the given 

7272 expression to the :meth:`_expression.Select.select_from` 

7273 method of the select 

7274 statement contained. 

7275 

7276 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7277 statement first, including the desired WHERE clause, then use the 

7278 :meth:`_sql.SelectBase.exists` method to produce an 

7279 :class:`_sql.Exists` object at once. 

7280 

7281 """ 

7282 e = self._clone() 

7283 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7284 return e 

7285 

7286 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7287 """Return a new :func:`_expression.exists` construct with the 

7288 given expression added to 

7289 its WHERE clause, joined to the existing clause via AND, if any. 

7290 

7291 

7292 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7293 statement first, including the desired WHERE clause, then use the 

7294 :meth:`_sql.SelectBase.exists` method to produce an 

7295 :class:`_sql.Exists` object at once. 

7296 

7297 """ 

7298 e = self._clone() 

7299 e.element = self._regroup(lambda element: element.where(*clause)) 

7300 return e 

7301 

7302 

7303class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7304 """Wrap a :class:`_expression.TextClause` construct within a 

7305 :class:`_expression.SelectBase` 

7306 interface. 

7307 

7308 This allows the :class:`_expression.TextClause` object to gain a 

7309 ``.c`` collection 

7310 and other FROM-like capabilities such as 

7311 :meth:`_expression.FromClause.alias`, 

7312 :meth:`_expression.SelectBase.cte`, etc. 

7313 

7314 The :class:`_expression.TextualSelect` construct is produced via the 

7315 :meth:`_expression.TextClause.columns` 

7316 method - see that method for details. 

7317 

7318 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7319 class was renamed 

7320 from ``TextAsFrom``, to more correctly suit its role as a 

7321 SELECT-oriented object and not a FROM clause. 

7322 

7323 .. seealso:: 

7324 

7325 :func:`_expression.text` 

7326 

7327 :meth:`_expression.TextClause.columns` - primary creation interface. 

7328 

7329 """ 

7330 

7331 __visit_name__ = "textual_select" 

7332 

7333 _label_style = LABEL_STYLE_NONE 

7334 

7335 _traverse_internals: _TraverseInternalsType = ( 

7336 [ 

7337 ("element", InternalTraversal.dp_clauseelement), 

7338 ("column_args", InternalTraversal.dp_clauseelement_list), 

7339 ] 

7340 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7341 + HasCTE._has_ctes_traverse_internals 

7342 + ExecutableStatement._executable_traverse_internals 

7343 ) 

7344 

7345 _is_textual = True 

7346 

7347 is_text = True 

7348 is_select = True 

7349 

7350 def __init__( 

7351 self, 

7352 text: TextClause, 

7353 columns: List[_ColumnExpressionArgument[Any]], 

7354 positional: bool = False, 

7355 ) -> None: 

7356 self._init( 

7357 text, 

7358 # convert for ORM attributes->columns, etc 

7359 [ 

7360 coercions.expect(roles.LabeledColumnExprRole, c) 

7361 for c in columns 

7362 ], 

7363 positional, 

7364 ) 

7365 

7366 def _init( 

7367 self, 

7368 text: AbstractTextClause, 

7369 columns: List[NamedColumn[Any]], 

7370 positional: bool = False, 

7371 ) -> None: 

7372 self.element = text 

7373 self.column_args = columns 

7374 self.positional = positional 

7375 

7376 @HasMemoized_ro_memoized_attribute 

7377 def selected_columns( 

7378 self, 

7379 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7380 """A :class:`_expression.ColumnCollection` 

7381 representing the columns that 

7382 this SELECT statement or similar construct returns in its result set, 

7383 not including :class:`_sql.TextClause` constructs. 

7384 

7385 This collection differs from the :attr:`_expression.FromClause.columns` 

7386 collection of a :class:`_expression.FromClause` in that the columns 

7387 within this collection cannot be directly nested inside another SELECT 

7388 statement; a subquery must be applied first which provides for the 

7389 necessary parenthesization required by SQL. 

7390 

7391 For a :class:`_expression.TextualSelect` construct, the collection 

7392 contains the :class:`_expression.ColumnElement` objects that were 

7393 passed to the constructor, typically via the 

7394 :meth:`_expression.TextClause.columns` method. 

7395 

7396 

7397 .. versionadded:: 1.4 

7398 

7399 """ 

7400 return WriteableColumnCollection( 

7401 (c.key, c) for c in self.column_args 

7402 ).as_readonly() 

7403 

7404 @util.ro_non_memoized_property 

7405 def _all_selected_columns(self) -> _SelectIterable: 

7406 return self.column_args 

7407 

7408 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7409 return self 

7410 

7411 def _ensure_disambiguated_names(self) -> TextualSelect: 

7412 return self 

7413 

7414 @_generative 

7415 def bindparams( 

7416 self, 

7417 *binds: BindParameter[Any], 

7418 **bind_as_values: Any, 

7419 ) -> Self: 

7420 self.element = self.element.bindparams(*binds, **bind_as_values) 

7421 return self 

7422 

7423 def _generate_fromclause_column_proxies( 

7424 self, 

7425 fromclause: FromClause, 

7426 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

7427 primary_key: ColumnSet, 

7428 foreign_keys: Set[KeyedColumnElement[Any]], 

7429 *, 

7430 proxy_compound_columns: Optional[ 

7431 Iterable[Sequence[ColumnElement[Any]]] 

7432 ] = None, 

7433 ) -> None: 

7434 if TYPE_CHECKING: 

7435 assert isinstance(fromclause, Subquery) 

7436 

7437 if proxy_compound_columns: 

7438 columns._populate_separate_keys( 

7439 c._make_proxy( 

7440 fromclause, 

7441 compound_select_cols=extra_cols, 

7442 primary_key=primary_key, 

7443 foreign_keys=foreign_keys, 

7444 ) 

7445 for c, extra_cols in zip( 

7446 self.column_args, proxy_compound_columns 

7447 ) 

7448 ) 

7449 else: 

7450 columns._populate_separate_keys( 

7451 c._make_proxy( 

7452 fromclause, 

7453 primary_key=primary_key, 

7454 foreign_keys=foreign_keys, 

7455 ) 

7456 for c in self.column_args 

7457 ) 

7458 

7459 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7460 return self.column_args[0].type 

7461 

7462 

7463TextAsFrom = TextualSelect 

7464"""Backwards compatibility with the previous name""" 

7465 

7466 

7467class AnnotatedFromClause(Annotated): 

7468 def _copy_internals( 

7469 self, 

7470 _annotations_traversal: bool = False, 

7471 ind_cols_on_fromclause: bool = False, 

7472 **kw: Any, 

7473 ) -> None: 

7474 super()._copy_internals(**kw) 

7475 

7476 # passed from annotations._shallow_annotate(), _deep_annotate(), etc. 

7477 # the traversals used by annotations for these cases are not currently 

7478 # designed around expecting that inner elements inside of 

7479 # AnnotatedFromClause's element are also deep copied, so skip for these 

7480 # cases. in other cases such as plain visitors.cloned_traverse(), we 

7481 # expect this to happen. see issue #12915 

7482 if not _annotations_traversal: 

7483 ee = self._Annotated__element # type: ignore 

7484 ee._copy_internals(**kw) 

7485 

7486 if ind_cols_on_fromclause: 

7487 # passed from annotations._deep_annotate(). See that function 

7488 # for notes 

7489 ee = self._Annotated__element # type: ignore 

7490 self.c = ee.__class__.c.fget(self) # type: ignore 

7491 

7492 @util.ro_memoized_property 

7493 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7494 """proxy the .c collection of the underlying FromClause. 

7495 

7496 Originally implemented in 2008 as a simple load of the .c collection 

7497 when the annotated construct was created (see d3621ae961a), in modern 

7498 SQLAlchemy versions this can be expensive for statements constructed 

7499 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7500 it, which works just as well. 

7501 

7502 Two different use cases seem to require the collection either copied 

7503 from the underlying one, or unique to this AnnotatedFromClause. 

7504 

7505 See test_selectable->test_annotated_corresponding_column 

7506 

7507 """ 

7508 ee = self._Annotated__element # type: ignore 

7509 return ee.c # type: ignore