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

1778 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import NamedTuple 

30from typing import NoReturn 

31from typing import Optional 

32from typing import overload 

33from typing import Protocol 

34from typing import Sequence 

35from typing import Set 

36from typing import Tuple 

37from typing import Type 

38from typing import TYPE_CHECKING 

39from typing import TypeVar 

40from typing import Union 

41 

42from . import cache_key 

43from . import coercions 

44from . import operators 

45from . import roles 

46from . import traversals 

47from . import type_api 

48from . import visitors 

49from ._typing import _ColumnsClauseArgument 

50from ._typing import _no_kw 

51from ._typing import _T 

52from ._typing import _Ts 

53from ._typing import is_column_element 

54from ._typing import is_select_statement 

55from ._typing import is_subquery 

56from ._typing import is_table 

57from ._typing import is_text_clause 

58from .annotation import Annotated 

59from .annotation import SupportsCloneAnnotations 

60from .base import _clone 

61from .base import _cloned_difference 

62from .base import _cloned_intersection 

63from .base import _entity_namespace_key 

64from .base import _EntityNamespace 

65from .base import _expand_cloned 

66from .base import _from_objects 

67from .base import _generative 

68from .base import _never_select_column 

69from .base import _NoArg 

70from .base import _select_iterables 

71from .base import CacheableOptions 

72from .base import ColumnCollection 

73from .base import ColumnSet 

74from .base import CompileState 

75from .base import DedupeColumnCollection 

76from .base import DialectKWArgs 

77from .base import Executable 

78from .base import Generative 

79from .base import HasCompileState 

80from .base import HasMemoized 

81from .base import HasSyntaxExtensions 

82from .base import Immutable 

83from .base import SyntaxExtension 

84from .coercions import _document_text_coercion 

85from .elements import _anonymous_label 

86from .elements import BindParameter 

87from .elements import BooleanClauseList 

88from .elements import ClauseElement 

89from .elements import ClauseList 

90from .elements import ColumnClause 

91from .elements import ColumnElement 

92from .elements import DQLDMLClauseElement 

93from .elements import GroupedElement 

94from .elements import literal_column 

95from .elements import TableValuedColumn 

96from .elements import UnaryExpression 

97from .operators import OperatorType 

98from .sqltypes import NULLTYPE 

99from .visitors import _TraverseInternalsType 

100from .visitors import InternalTraversal 

101from .visitors import prefix_anon_map 

102from .. import exc 

103from .. import util 

104from ..util import HasMemoized_ro_memoized_attribute 

105from ..util import warn_deprecated 

106from ..util.typing import Literal 

107from ..util.typing import Self 

108from ..util.typing import TupleAny 

109from ..util.typing import Unpack 

110 

111 

112and_ = BooleanClauseList.and_ 

113 

114 

115if TYPE_CHECKING: 

116 from ._typing import _ColumnExpressionArgument 

117 from ._typing import _ColumnExpressionOrStrLabelArgument 

118 from ._typing import _FromClauseArgument 

119 from ._typing import _JoinTargetArgument 

120 from ._typing import _LimitOffsetType 

121 from ._typing import _MAYBE_ENTITY 

122 from ._typing import _NOT_ENTITY 

123 from ._typing import _OnClauseArgument 

124 from ._typing import _SelectStatementForCompoundArgument 

125 from ._typing import _T0 

126 from ._typing import _T1 

127 from ._typing import _T2 

128 from ._typing import _T3 

129 from ._typing import _T4 

130 from ._typing import _T5 

131 from ._typing import _T6 

132 from ._typing import _T7 

133 from ._typing import _TextCoercedExpressionArgument 

134 from ._typing import _TypedColumnClauseArgument as _TCCA 

135 from ._typing import _TypeEngineArgument 

136 from .base import _AmbiguousTableNameMap 

137 from .base import ExecutableOption 

138 from .base import ReadOnlyColumnCollection 

139 from .cache_key import _CacheKeyTraversalType 

140 from .compiler import SQLCompiler 

141 from .dml import Delete 

142 from .dml import Update 

143 from .elements import BinaryExpression 

144 from .elements import KeyedColumnElement 

145 from .elements import Label 

146 from .elements import NamedColumn 

147 from .elements import TextClause 

148 from .functions import Function 

149 from .schema import ForeignKey 

150 from .schema import ForeignKeyConstraint 

151 from .sqltypes import TableValueType 

152 from .type_api import TypeEngine 

153 from .visitors import _CloneCallableType 

154 

155 

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

157_LabelConventionCallable = Callable[ 

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

159] 

160 

161 

162class _JoinTargetProtocol(Protocol): 

163 @util.ro_non_memoized_property 

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

165 

166 @util.ro_non_memoized_property 

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

168 

169 

170_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

172 

173_ForUpdateOfArgument = Union[ 

174 # single column, Table, ORM Entity 

175 Union[ 

176 "_ColumnExpressionArgument[Any]", 

177 "_FromClauseArgument", 

178 ], 

179 # or sequence of single column elements 

180 Sequence["_ColumnExpressionArgument[Any]"], 

181] 

182 

183 

184_SetupJoinsElement = Tuple[ 

185 _JoinTargetElement, 

186 Optional[_OnClauseElement], 

187 Optional["FromClause"], 

188 Dict[str, Any], 

189] 

190 

191 

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

193 

194 

195class _OffsetLimitParam(BindParameter[int]): 

196 inherit_cache = True 

197 

198 @property 

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

200 return self.effective_value 

201 

202 

203class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

205 columns that can represent rows. 

206 

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

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

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

210 PostgreSQL has functions that return rows also. 

211 

212 .. versionadded:: 1.4 

213 

214 """ 

215 

216 _is_returns_rows = True 

217 

218 # sub-elements of returns_rows 

219 _is_from_clause = False 

220 _is_select_base = False 

221 _is_select_statement = False 

222 _is_lateral = False 

223 

224 @property 

225 def selectable(self) -> ReturnsRows: 

226 return self 

227 

228 @util.ro_non_memoized_property 

229 def _all_selected_columns(self) -> _SelectIterable: 

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

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

232 

233 This is typically equivalent to .exported_columns except it is 

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

235 :class:`_expression.ColumnCollection`. 

236 

237 """ 

238 raise NotImplementedError() 

239 

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

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

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

243 

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

245 

246 """ 

247 raise NotImplementedError() 

248 

249 def _generate_fromclause_column_proxies( 

250 self, 

251 fromclause: FromClause, 

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

253 primary_key: ColumnSet, 

254 foreign_keys: Set[KeyedColumnElement[Any]], 

255 ) -> None: 

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

257 

258 raise NotImplementedError() 

259 

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

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

262 raise NotImplementedError() 

263 

264 @property 

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

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

267 that represents the "exported" 

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

269 

270 The "exported" columns represent the collection of 

271 :class:`_expression.ColumnElement` 

272 expressions that are rendered by this SQL 

273 construct. There are primary varieties which are the 

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

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

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

277 columns in a DML statement.. 

278 

279 .. versionadded:: 1.4 

280 

281 .. seealso:: 

282 

283 :attr:`_expression.FromClause.exported_columns` 

284 

285 :attr:`_expression.SelectBase.exported_columns` 

286 """ 

287 

288 raise NotImplementedError() 

289 

290 

291class ExecutableReturnsRows(Executable, ReturnsRows): 

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

293 

294 

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

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

297 

298 

299class Selectable(ReturnsRows): 

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

301 

302 __visit_name__ = "selectable" 

303 

304 is_selectable = True 

305 

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

307 raise NotImplementedError() 

308 

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

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

311 

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

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

314 

315 .. seealso:: 

316 

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

318 

319 """ 

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

321 

322 @util.deprecated( 

323 "1.4", 

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

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

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

327 ) 

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

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

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

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

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

333 

334 """ 

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

336 

337 def corresponding_column( 

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

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

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

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

342 :attr:`_expression.Selectable.exported_columns` 

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

344 which corresponds to that 

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

346 column. 

347 

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

349 to be matched. 

350 

351 :param require_embedded: only return corresponding columns for 

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

353 :class:`_expression.ColumnElement` 

354 is actually present within a sub-element 

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

356 Normally the column will match if 

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

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

359 

360 .. seealso:: 

361 

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

363 :class:`_expression.ColumnCollection` 

364 that is used for the operation. 

365 

366 :meth:`_expression.ColumnCollection.corresponding_column` 

367 - implementation 

368 method. 

369 

370 """ 

371 

372 return self.exported_columns.corresponding_column( 

373 column, require_embedded 

374 ) 

375 

376 

377class HasPrefixes: 

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

379 

380 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

381 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

382 ] 

383 

384 @_generative 

385 @_document_text_coercion( 

386 "prefixes", 

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

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

389 ) 

390 def prefix_with( 

391 self, 

392 *prefixes: _TextCoercedExpressionArgument[Any], 

393 dialect: str = "*", 

394 ) -> Self: 

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

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

397 

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

399 provided by MySQL. 

400 

401 E.g.:: 

402 

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

404 

405 # MySQL 5.7 optimizer hints 

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

407 

408 Multiple prefixes can be specified by multiple calls 

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

410 

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

412 construct which 

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

414 keyword. 

415 :param dialect: optional string dialect name which will 

416 limit rendering of this prefix to only that dialect. 

417 

418 """ 

419 self._prefixes = self._prefixes + tuple( 

420 [ 

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

422 for p in prefixes 

423 ] 

424 ) 

425 return self 

426 

427 

428class HasSuffixes: 

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

430 

431 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

432 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

433 ] 

434 

435 @_generative 

436 @_document_text_coercion( 

437 "suffixes", 

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

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

440 ) 

441 def suffix_with( 

442 self, 

443 *suffixes: _TextCoercedExpressionArgument[Any], 

444 dialect: str = "*", 

445 ) -> Self: 

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

447 

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

449 certain constructs. 

450 

451 E.g.:: 

452 

453 stmt = ( 

454 select(col1, col2) 

455 .cte() 

456 .suffix_with( 

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

458 ) 

459 ) 

460 

461 Multiple suffixes can be specified by multiple calls 

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

463 

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

465 construct which 

466 will be rendered following the target clause. 

467 :param dialect: Optional string dialect name which will 

468 limit rendering of this suffix to only that dialect. 

469 

470 """ 

471 self._suffixes = self._suffixes + tuple( 

472 [ 

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

474 for p in suffixes 

475 ] 

476 ) 

477 return self 

478 

479 

480class HasHints: 

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

482 util.immutabledict() 

483 ) 

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

485 

486 _has_hints_traverse_internals: _TraverseInternalsType = [ 

487 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

488 ("_hints", InternalTraversal.dp_table_hint_list), 

489 ] 

490 

491 @_generative 

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

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

494 other selectable object. 

495 

496 .. tip:: 

497 

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

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

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

501 the SELECT statement after the SELECT keyword, use the 

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

503 space, or for table-specific hints the 

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

505 hints in a dialect-specific location. 

506 

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

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

509 the statement as a whole. 

510 

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

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

513 etc. 

514 

515 .. seealso:: 

516 

517 :meth:`_expression.Select.with_hint` 

518 

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

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

521 MySQL or Oracle Database optimizer hints 

522 

523 """ 

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

525 

526 @_generative 

527 def with_hint( 

528 self, 

529 selectable: _FromClauseArgument, 

530 text: str, 

531 dialect_name: str = "*", 

532 ) -> Self: 

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

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

535 object. 

536 

537 .. tip:: 

538 

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

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

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

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

543 for MySQL or Oracle Database, use the 

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

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

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

547 

548 The text of the hint is rendered in the appropriate 

549 location for the database backend in use, relative 

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

551 passed as the 

552 ``selectable`` argument. The dialect implementation 

553 typically uses Python string substitution syntax 

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

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

556 following:: 

557 

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

559 

560 Would render SQL as: 

561 

562 .. sourcecode:: sql 

563 

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

565 

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

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

568 Database and MSSql simultaneously:: 

569 

570 select(mytable).with_hint( 

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

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

573 

574 .. seealso:: 

575 

576 :meth:`_expression.Select.with_statement_hint` 

577 

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

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

580 MySQL or Oracle Database optimizer hints 

581 

582 """ 

583 

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

585 

586 def _with_hint( 

587 self, 

588 selectable: Optional[_FromClauseArgument], 

589 text: str, 

590 dialect_name: str, 

591 ) -> Self: 

592 if selectable is None: 

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

594 else: 

595 self._hints = self._hints.union( 

596 { 

597 ( 

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

599 dialect_name, 

600 ): text 

601 } 

602 ) 

603 return self 

604 

605 

606class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

608 clause of a ``SELECT`` statement. 

609 

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

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

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

613 

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

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

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

617 :class:`_expression.ColumnElement` 

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

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

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

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

622 :meth:`_expression.FromClause.select`. 

623 

624 

625 """ 

626 

627 __visit_name__ = "fromclause" 

628 named_with_column = False 

629 

630 @util.ro_non_memoized_property 

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

632 return () 

633 

634 _is_clone_of: Optional[FromClause] 

635 

636 _columns: ColumnCollection[Any, Any] 

637 

638 schema: Optional[str] = None 

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

640 

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

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

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

644 

645 """ 

646 

647 is_selectable = True 

648 _is_from_clause = True 

649 _is_join = False 

650 

651 _use_schema_map = False 

652 

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

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

655 

656 

657 e.g.:: 

658 

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

660 

661 .. seealso:: 

662 

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

664 method which allows for arbitrary column lists. 

665 

666 """ 

667 return Select(self) 

668 

669 def join( 

670 self, 

671 right: _FromClauseArgument, 

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

673 isouter: bool = False, 

674 full: bool = False, 

675 ) -> Join: 

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

677 :class:`_expression.FromClause` 

678 to another :class:`FromClause`. 

679 

680 E.g.:: 

681 

682 from sqlalchemy import join 

683 

684 j = user_table.join( 

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

686 ) 

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

688 

689 would emit SQL along the lines of: 

690 

691 .. sourcecode:: sql 

692 

693 SELECT user.id, user.name FROM user 

694 JOIN address ON user.id = address.user_id 

695 

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

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

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

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

700 class. 

701 

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

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

704 will attempt to 

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

706 

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

708 

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

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

711 

712 .. seealso:: 

713 

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

715 

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

717 

718 """ 

719 

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

721 

722 def outerjoin( 

723 self, 

724 right: _FromClauseArgument, 

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

726 full: bool = False, 

727 ) -> Join: 

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

729 :class:`_expression.FromClause` 

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

731 True. 

732 

733 E.g.:: 

734 

735 from sqlalchemy import outerjoin 

736 

737 j = user_table.outerjoin( 

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

739 ) 

740 

741 The above is equivalent to:: 

742 

743 j = user_table.join( 

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

745 ) 

746 

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

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

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

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

751 class. 

752 

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

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

755 will attempt to 

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

757 

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

759 LEFT OUTER JOIN. 

760 

761 .. seealso:: 

762 

763 :meth:`_expression.FromClause.join` 

764 

765 :class:`_expression.Join` 

766 

767 """ # noqa: E501 

768 

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

770 

771 def alias( 

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

773 ) -> NamedFromClause: 

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

775 

776 E.g.:: 

777 

778 a2 = some_table.alias("a2") 

779 

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

781 object which can be used 

782 as a FROM clause in any SELECT statement. 

783 

784 .. seealso:: 

785 

786 :ref:`tutorial_using_aliases` 

787 

788 :func:`_expression.alias` 

789 

790 """ 

791 

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

793 

794 def tablesample( 

795 self, 

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

797 name: Optional[str] = None, 

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

799 ) -> TableSample: 

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

801 

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

803 construct also 

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

805 

806 .. seealso:: 

807 

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

809 

810 """ 

811 return TableSample._construct( 

812 self, sampling=sampling, name=name, seed=seed 

813 ) 

814 

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

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

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

818 

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

820 

821 """ 

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

823 # Other constructs override this to traverse through 

824 # contained elements. 

825 return fromclause in self._cloned_set 

826 

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

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

829 the other represent the same lexical identity. 

830 

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

832 if they are the same via annotation identity. 

833 

834 """ 

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

836 

837 @util.ro_non_memoized_property 

838 def description(self) -> str: 

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

840 

841 Used primarily for error message formatting. 

842 

843 """ 

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

845 

846 def _generate_fromclause_column_proxies( 

847 self, 

848 fromclause: FromClause, 

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

850 primary_key: ColumnSet, 

851 foreign_keys: Set[KeyedColumnElement[Any]], 

852 ) -> None: 

853 columns._populate_separate_keys( 

854 col._make_proxy( 

855 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

856 ) 

857 for col in self.c 

858 ) 

859 

860 @util.ro_non_memoized_property 

861 def exported_columns( 

862 self, 

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

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

865 that represents the "exported" 

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

867 

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

869 object are synonymous 

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

871 

872 .. versionadded:: 1.4 

873 

874 .. seealso:: 

875 

876 :attr:`_expression.Selectable.exported_columns` 

877 

878 :attr:`_expression.SelectBase.exported_columns` 

879 

880 

881 """ 

882 return self.c 

883 

884 @util.ro_non_memoized_property 

885 def columns( 

886 self, 

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

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

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

890 

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

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

893 other selectable-bound columns:: 

894 

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

896 

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

898 

899 """ 

900 return self.c 

901 

902 @util.ro_memoized_property 

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

904 """ 

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

906 

907 :return: a :class:`.ColumnCollection` 

908 

909 """ 

910 if "_columns" not in self.__dict__: 

911 self._setup_collections() 

912 return self._columns.as_readonly() 

913 

914 def _setup_collections(self) -> None: 

915 assert "_columns" not in self.__dict__ 

916 assert "primary_key" not in self.__dict__ 

917 assert "foreign_keys" not in self.__dict__ 

918 

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

920 primary_key = ColumnSet() 

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

922 

923 self._populate_column_collection( 

924 columns=_columns, 

925 primary_key=primary_key, 

926 foreign_keys=foreign_keys, 

927 ) 

928 

929 # assigning these three collections separately is not itself atomic, 

930 # but greatly reduces the surface for problems 

931 self._columns = _columns 

932 self.primary_key = primary_key # type: ignore 

933 self.foreign_keys = foreign_keys # type: ignore 

934 

935 @util.ro_non_memoized_property 

936 def entity_namespace(self) -> _EntityNamespace: 

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

938 

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

940 expressions, such as:: 

941 

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

943 

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

945 be overridden using the "entity_namespace" annotation to deliver 

946 alternative results. 

947 

948 """ 

949 return self.c 

950 

951 @util.ro_memoized_property 

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

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

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

955 

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

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

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

959 

960 """ 

961 self._setup_collections() 

962 return self.primary_key 

963 

964 @util.ro_memoized_property 

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

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

967 which this FromClause references. 

968 

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

970 :class:`_schema.Table`-wide 

971 :class:`_schema.ForeignKeyConstraint`. 

972 

973 .. seealso:: 

974 

975 :attr:`_schema.Table.foreign_key_constraints` 

976 

977 """ 

978 self._setup_collections() 

979 return self.foreign_keys 

980 

981 def _reset_column_collection(self) -> None: 

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

983 

984 This collection is separate from all the other memoized things 

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

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

987 has already established strong relationships 

988 with the exported columns. 

989 

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

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

992 

993 """ 

994 

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

996 self.__dict__.pop(key, None) 

997 

998 @util.ro_non_memoized_property 

999 def _select_iterable(self) -> _SelectIterable: 

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

1001 

1002 @property 

1003 def _cols_populated(self) -> bool: 

1004 return "_columns" in self.__dict__ 

1005 

1006 def _populate_column_collection( 

1007 self, 

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

1009 primary_key: ColumnSet, 

1010 foreign_keys: Set[KeyedColumnElement[Any]], 

1011 ) -> None: 

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

1013 

1014 Each implementation has a different way of establishing 

1015 this collection. 

1016 

1017 """ 

1018 

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

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

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

1022 selectable ultimately should proxy this column. 

1023 

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

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

1026 Table objects it ultimately derives from. 

1027 

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

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

1030 but it will return None. 

1031 

1032 This method is currently used by Declarative to allow Table 

1033 columns to be added to a partially constructed inheritance 

1034 mapping that may have already produced joins. The method 

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

1036 and/or caveats aren't yet clear. 

1037 

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

1039 default via an event, which would require that 

1040 selectables maintain a weak referencing collection of all 

1041 derivations. 

1042 

1043 """ 

1044 self._reset_column_collection() 

1045 

1046 def _anonymous_fromclause( 

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

1048 ) -> FromClause: 

1049 return self.alias(name=name) 

1050 

1051 if TYPE_CHECKING: 

1052 

1053 def self_group( 

1054 self, against: Optional[OperatorType] = None 

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

1056 

1057 

1058class NamedFromClause(FromClause): 

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

1060 

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

1062 

1063 .. versionadded:: 2.0 

1064 

1065 """ 

1066 

1067 named_with_column = True 

1068 

1069 name: str 

1070 

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

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

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

1074 :class:`_expression.FromClause`. 

1075 

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

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

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

1079 such as PostgreSQL, Oracle Database and SQL Server. 

1080 

1081 E.g.: 

1082 

1083 .. sourcecode:: pycon+sql 

1084 

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

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

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

1088 >>> print(stmt) 

1089 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1090 FROM a 

1091 

1092 .. versionadded:: 1.4.0b2 

1093 

1094 .. seealso:: 

1095 

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

1097 

1098 """ 

1099 return TableValuedColumn(self, type_api.TABLEVALUE) 

1100 

1101 

1102class SelectLabelStyle(Enum): 

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

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

1105 

1106 LABEL_STYLE_NONE = 0 

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

1108 columns clause of a SELECT statement. 

1109 

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

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

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

1113 

1114 .. sourcecode:: pycon+sql 

1115 

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

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

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

1119 >>> print( 

1120 ... select(table1, table2) 

1121 ... .join(table2, true()) 

1122 ... .set_label_style(LABEL_STYLE_NONE) 

1123 ... ) 

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

1125 FROM table1 JOIN table2 ON true 

1126 

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

1128 

1129 .. versionadded:: 1.4 

1130 

1131 """ # noqa: E501 

1132 

1133 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1137 tables, aliases, or subqueries. 

1138 

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

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

1141 ``table2_columna``: 

1142 

1143 .. sourcecode:: pycon+sql 

1144 

1145 >>> from sqlalchemy import ( 

1146 ... table, 

1147 ... column, 

1148 ... select, 

1149 ... true, 

1150 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1151 ... ) 

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

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

1154 >>> print( 

1155 ... select(table1, table2) 

1156 ... .join(table2, true()) 

1157 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1158 ... ) 

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

1160 FROM table1 JOIN table2 ON true 

1161 

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

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

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

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

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

1167 

1168 

1169 .. versionadded:: 1.4 

1170 

1171 """ # noqa: E501 

1172 

1173 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1176 when generating the columns clause of a SELECT statement. 

1177 

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

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

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

1181 

1182 .. sourcecode:: pycon+sql 

1183 

1184 >>> from sqlalchemy import ( 

1185 ... table, 

1186 ... column, 

1187 ... select, 

1188 ... true, 

1189 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1190 ... ) 

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

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

1193 >>> print( 

1194 ... select(table1, table2) 

1195 ... .join(table2, true()) 

1196 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1197 ... ) 

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

1199 FROM table1 JOIN table2 ON true 

1200 

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

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

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

1204 

1205 .. versionadded:: 1.4 

1206 

1207 """ # noqa: E501 

1208 

1209 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1210 """The default label style, refers to 

1211 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1212 

1213 .. versionadded:: 1.4 

1214 

1215 """ 

1216 

1217 LABEL_STYLE_LEGACY_ORM = 3 

1218 

1219 

1220( 

1221 LABEL_STYLE_NONE, 

1222 LABEL_STYLE_TABLENAME_PLUS_COL, 

1223 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1224 _, 

1225) = list(SelectLabelStyle) 

1226 

1227LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1228 

1229 

1230class Join(roles.DMLTableRole, FromClause): 

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

1232 :class:`_expression.FromClause` 

1233 elements. 

1234 

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

1236 is the module-level 

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

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

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

1240 :class:`_schema.Table`). 

1241 

1242 .. seealso:: 

1243 

1244 :func:`_expression.join` 

1245 

1246 :meth:`_expression.FromClause.join` 

1247 

1248 """ 

1249 

1250 __visit_name__ = "join" 

1251 

1252 _traverse_internals: _TraverseInternalsType = [ 

1253 ("left", InternalTraversal.dp_clauseelement), 

1254 ("right", InternalTraversal.dp_clauseelement), 

1255 ("onclause", InternalTraversal.dp_clauseelement), 

1256 ("isouter", InternalTraversal.dp_boolean), 

1257 ("full", InternalTraversal.dp_boolean), 

1258 ] 

1259 

1260 _is_join = True 

1261 

1262 left: FromClause 

1263 right: FromClause 

1264 onclause: Optional[ColumnElement[bool]] 

1265 isouter: bool 

1266 full: bool 

1267 

1268 def __init__( 

1269 self, 

1270 left: _FromClauseArgument, 

1271 right: _FromClauseArgument, 

1272 onclause: Optional[_OnClauseArgument] = None, 

1273 isouter: bool = False, 

1274 full: bool = False, 

1275 ): 

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

1277 

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

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

1280 :class:`_expression.FromClause` object. 

1281 

1282 """ 

1283 

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

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

1286 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1289 # callcounts for a single compilation in that particular test 

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

1291 # 29200 -> 30373 

1292 

1293 self.left = coercions.expect( 

1294 roles.FromClauseRole, 

1295 left, 

1296 ) 

1297 self.right = coercions.expect( 

1298 roles.FromClauseRole, 

1299 right, 

1300 ).self_group() 

1301 

1302 if onclause is None: 

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

1304 else: 

1305 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1306 # not merged yet 

1307 self.onclause = coercions.expect( 

1308 roles.OnClauseRole, onclause 

1309 ).self_group(against=operators._asbool) 

1310 

1311 self.isouter = isouter 

1312 self.full = full 

1313 

1314 @util.ro_non_memoized_property 

1315 def description(self) -> str: 

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

1317 self.left.description, 

1318 id(self.left), 

1319 self.right.description, 

1320 id(self.right), 

1321 ) 

1322 

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

1324 return ( 

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

1326 # as well 

1327 hash(fromclause) == hash(self) 

1328 or self.left.is_derived_from(fromclause) 

1329 or self.right.is_derived_from(fromclause) 

1330 ) 

1331 

1332 def self_group( 

1333 self, against: Optional[OperatorType] = None 

1334 ) -> FromGrouping: 

1335 return FromGrouping(self) 

1336 

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

1338 def _populate_column_collection( 

1339 self, 

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

1341 primary_key: ColumnSet, 

1342 foreign_keys: Set[KeyedColumnElement[Any]], 

1343 ) -> None: 

1344 sqlutil = util.preloaded.sql_util 

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

1346 c for c in self.right.c 

1347 ] 

1348 

1349 primary_key.extend( # type: ignore 

1350 sqlutil.reduce_columns( 

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

1352 ) 

1353 ) 

1354 columns._populate_separate_keys( 

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

1356 ) 

1357 foreign_keys.update( 

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

1359 ) 

1360 

1361 def _copy_internals( 

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

1363 ) -> None: 

1364 # see Select._copy_internals() for similar concept 

1365 

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

1367 # determine the new FROM clauses 

1368 all_the_froms = set( 

1369 itertools.chain( 

1370 _from_objects(self.left), 

1371 _from_objects(self.right), 

1372 ) 

1373 ) 

1374 

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

1376 # cache used by the clone function 

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

1378 

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

1380 # ColumnClause with parent table referring to those 

1381 # replaced FromClause objects 

1382 def replace( 

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

1384 **kw: Any, 

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

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

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

1388 return newelem 

1389 return None 

1390 

1391 kw["replace"] = replace 

1392 

1393 # run normal _copy_internals. the clones for 

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

1395 # cache 

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

1397 

1398 self._reset_memoizations() 

1399 

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

1401 super()._refresh_for_new_column(column) 

1402 self.left._refresh_for_new_column(column) 

1403 self.right._refresh_for_new_column(column) 

1404 

1405 def _match_primaries( 

1406 self, 

1407 left: FromClause, 

1408 right: FromClause, 

1409 ) -> ColumnElement[bool]: 

1410 if isinstance(left, Join): 

1411 left_right = left.right 

1412 else: 

1413 left_right = None 

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

1415 

1416 @classmethod 

1417 def _join_condition( 

1418 cls, 

1419 a: FromClause, 

1420 b: FromClause, 

1421 *, 

1422 a_subset: Optional[FromClause] = None, 

1423 consider_as_foreign_keys: Optional[ 

1424 AbstractSet[ColumnClause[Any]] 

1425 ] = None, 

1426 ) -> ColumnElement[bool]: 

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

1428 

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

1430 

1431 """ 

1432 constraints = cls._joincond_scan_left_right( 

1433 a, a_subset, b, consider_as_foreign_keys 

1434 ) 

1435 

1436 if len(constraints) > 1: 

1437 cls._joincond_trim_constraints( 

1438 a, b, constraints, consider_as_foreign_keys 

1439 ) 

1440 

1441 if len(constraints) == 0: 

1442 if isinstance(b, FromGrouping): 

1443 hint = ( 

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

1445 "subquery using alias()?" 

1446 ) 

1447 else: 

1448 hint = "" 

1449 raise exc.NoForeignKeysError( 

1450 "Can't find any foreign key relationships " 

1451 "between '%s' and '%s'.%s" 

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

1453 ) 

1454 

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

1456 if len(crit) == 1: 

1457 return crit[0] 

1458 else: 

1459 return and_(*crit) 

1460 

1461 @classmethod 

1462 def _can_join( 

1463 cls, 

1464 left: FromClause, 

1465 right: FromClause, 

1466 *, 

1467 consider_as_foreign_keys: Optional[ 

1468 AbstractSet[ColumnClause[Any]] 

1469 ] = None, 

1470 ) -> bool: 

1471 if isinstance(left, Join): 

1472 left_right = left.right 

1473 else: 

1474 left_right = None 

1475 

1476 constraints = cls._joincond_scan_left_right( 

1477 a=left, 

1478 b=right, 

1479 a_subset=left_right, 

1480 consider_as_foreign_keys=consider_as_foreign_keys, 

1481 ) 

1482 

1483 return bool(constraints) 

1484 

1485 @classmethod 

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

1487 def _joincond_scan_left_right( 

1488 cls, 

1489 a: FromClause, 

1490 a_subset: Optional[FromClause], 

1491 b: FromClause, 

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

1493 ) -> collections.defaultdict[ 

1494 Optional[ForeignKeyConstraint], 

1495 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1496 ]: 

1497 sql_util = util.preloaded.sql_util 

1498 

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

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

1501 

1502 constraints: collections.defaultdict[ 

1503 Optional[ForeignKeyConstraint], 

1504 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1505 ] = collections.defaultdict(list) 

1506 

1507 for left in (a_subset, a): 

1508 if left is None: 

1509 continue 

1510 for fk in sorted( 

1511 b.foreign_keys, 

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

1513 ): 

1514 if ( 

1515 consider_as_foreign_keys is not None 

1516 and fk.parent not in consider_as_foreign_keys 

1517 ): 

1518 continue 

1519 try: 

1520 col = fk.get_referent(left) 

1521 except exc.NoReferenceError as nrte: 

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

1523 if nrte.table_name in table_names: 

1524 raise 

1525 else: 

1526 continue 

1527 

1528 if col is not None: 

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

1530 if left is not b: 

1531 for fk in sorted( 

1532 left.foreign_keys, 

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

1534 ): 

1535 if ( 

1536 consider_as_foreign_keys is not None 

1537 and fk.parent not in consider_as_foreign_keys 

1538 ): 

1539 continue 

1540 try: 

1541 col = fk.get_referent(b) 

1542 except exc.NoReferenceError as nrte: 

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

1544 if nrte.table_name in table_names: 

1545 raise 

1546 else: 

1547 continue 

1548 

1549 if col is not None: 

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

1551 if constraints: 

1552 break 

1553 return constraints 

1554 

1555 @classmethod 

1556 def _joincond_trim_constraints( 

1557 cls, 

1558 a: FromClause, 

1559 b: FromClause, 

1560 constraints: Dict[Any, Any], 

1561 consider_as_foreign_keys: Optional[Any], 

1562 ) -> None: 

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

1564 # to include just those FKCs that match exactly to 

1565 # "consider_as_foreign_keys". 

1566 if consider_as_foreign_keys: 

1567 for const in list(constraints): 

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

1569 consider_as_foreign_keys 

1570 ): 

1571 del constraints[const] 

1572 

1573 # if still multiple constraints, but 

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

1575 if len(constraints) > 1: 

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

1577 if len(dedupe) == 1: 

1578 key = list(constraints)[0] 

1579 constraints = {key: constraints[key]} 

1580 

1581 if len(constraints) != 1: 

1582 raise exc.AmbiguousForeignKeysError( 

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

1584 "tables have more than one foreign key " 

1585 "constraint relationship between them. " 

1586 "Please specify the 'onclause' of this " 

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

1588 ) 

1589 

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

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

1592 :class:`_expression.Join`. 

1593 

1594 E.g.:: 

1595 

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

1597 

1598 stmt = stmt.select() 

1599 

1600 The above will produce a SQL string resembling: 

1601 

1602 .. sourcecode:: sql 

1603 

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

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

1606 

1607 """ 

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

1609 

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

1611 def _anonymous_fromclause( 

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

1613 ) -> TODO_Any: 

1614 sqlutil = util.preloaded.sql_util 

1615 if flat: 

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

1617 left_name = name # will recurse 

1618 else: 

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

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

1621 else: 

1622 left_name = name 

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

1624 right_name = name # will recurse 

1625 else: 

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

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

1628 else: 

1629 right_name = name 

1630 left_a, right_a = ( 

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

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

1633 ) 

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

1635 sqlutil.ClauseAdapter(right_a) 

1636 ) 

1637 

1638 return left_a.join( 

1639 right_a, 

1640 adapter.traverse(self.onclause), 

1641 isouter=self.isouter, 

1642 full=self.full, 

1643 ) 

1644 else: 

1645 return ( 

1646 self.select() 

1647 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1648 .correlate(None) 

1649 .alias(name) 

1650 ) 

1651 

1652 @util.ro_non_memoized_property 

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

1654 return itertools.chain( 

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

1656 ) 

1657 

1658 @util.ro_non_memoized_property 

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

1660 self_list: List[FromClause] = [self] 

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

1662 

1663 

1664class NoInit: 

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

1666 raise NotImplementedError( 

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

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

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

1670 "selectable objects." 

1671 % ( 

1672 self.__class__.__name__, 

1673 self.__class__.__name__.lower(), 

1674 self.__class__.__name__.lower(), 

1675 ) 

1676 ) 

1677 

1678 

1679class LateralFromClause(NamedFromClause): 

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

1681 

1682 

1683# FromClause -> 

1684# AliasedReturnsRows 

1685# -> Alias only for FromClause 

1686# -> Subquery only for SelectBase 

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

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

1689# w/ non-deprecated coercion 

1690# -> TableSample -> only for FromClause 

1691 

1692 

1693class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1695 selectables.""" 

1696 

1697 _is_from_container = True 

1698 

1699 _supports_derived_columns = False 

1700 

1701 element: ReturnsRows 

1702 

1703 _traverse_internals: _TraverseInternalsType = [ 

1704 ("element", InternalTraversal.dp_clauseelement), 

1705 ("name", InternalTraversal.dp_anon_name), 

1706 ] 

1707 

1708 @classmethod 

1709 def _construct( 

1710 cls, 

1711 selectable: Any, 

1712 *, 

1713 name: Optional[str] = None, 

1714 **kw: Any, 

1715 ) -> Self: 

1716 obj = cls.__new__(cls) 

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

1718 return obj 

1719 

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

1721 self.element = coercions.expect( 

1722 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1723 ) 

1724 self.element = selectable 

1725 self._orig_name = name 

1726 if name is None: 

1727 if ( 

1728 isinstance(selectable, FromClause) 

1729 and selectable.named_with_column 

1730 ): 

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

1732 if isinstance(name, _anonymous_label): 

1733 name = None 

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

1735 self.name = name 

1736 

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

1738 super()._refresh_for_new_column(column) 

1739 self.element._refresh_for_new_column(column) 

1740 

1741 def _populate_column_collection( 

1742 self, 

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

1744 primary_key: ColumnSet, 

1745 foreign_keys: Set[KeyedColumnElement[Any]], 

1746 ) -> None: 

1747 self.element._generate_fromclause_column_proxies( 

1748 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1749 ) 

1750 

1751 @util.ro_non_memoized_property 

1752 def description(self) -> str: 

1753 name = self.name 

1754 if isinstance(name, _anonymous_label): 

1755 return "anon_1" 

1756 

1757 return name 

1758 

1759 @util.ro_non_memoized_property 

1760 def implicit_returning(self) -> bool: 

1761 return self.element.implicit_returning # type: ignore 

1762 

1763 @property 

1764 def original(self) -> ReturnsRows: 

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

1766 return self.element 

1767 

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

1769 if fromclause in self._cloned_set: 

1770 return True 

1771 return self.element.is_derived_from(fromclause) 

1772 

1773 def _copy_internals( 

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

1775 ) -> None: 

1776 existing_element = self.element 

1777 

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

1779 

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

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

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

1783 # performance. 

1784 if existing_element is not self.element: 

1785 self._reset_column_collection() 

1786 

1787 @property 

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

1789 return [self] 

1790 

1791 

1792class FromClauseAlias(AliasedReturnsRows): 

1793 element: FromClause 

1794 

1795 @util.ro_non_memoized_property 

1796 def description(self) -> str: 

1797 name = self.name 

1798 if isinstance(name, _anonymous_label): 

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

1800 

1801 return name 

1802 

1803 

1804class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1806 

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

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

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

1810 

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

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

1813 method available 

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

1815 

1816 .. seealso:: 

1817 

1818 :meth:`_expression.FromClause.alias` 

1819 

1820 """ 

1821 

1822 __visit_name__ = "alias" 

1823 

1824 inherit_cache = True 

1825 

1826 element: FromClause 

1827 

1828 @classmethod 

1829 def _factory( 

1830 cls, 

1831 selectable: FromClause, 

1832 name: Optional[str] = None, 

1833 flat: bool = False, 

1834 ) -> NamedFromClause: 

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

1836 name=name, flat=flat 

1837 ) 

1838 

1839 

1840class TableValuedAlias(LateralFromClause, Alias): 

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

1842 

1843 This construct provides for a SQL function that returns columns 

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

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

1846 method, e.g.: 

1847 

1848 .. sourcecode:: pycon+sql 

1849 

1850 >>> from sqlalchemy import select, func 

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

1852 ... "value" 

1853 ... ) 

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

1855 {printsql}SELECT anon_1.value 

1856 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1857 

1858 .. versionadded:: 1.4.0b2 

1859 

1860 .. seealso:: 

1861 

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

1863 

1864 """ # noqa: E501 

1865 

1866 __visit_name__ = "table_valued_alias" 

1867 

1868 _supports_derived_columns = True 

1869 _render_derived = False 

1870 _render_derived_w_types = False 

1871 joins_implicitly = False 

1872 

1873 _traverse_internals: _TraverseInternalsType = [ 

1874 ("element", InternalTraversal.dp_clauseelement), 

1875 ("name", InternalTraversal.dp_anon_name), 

1876 ("_tableval_type", InternalTraversal.dp_type), 

1877 ("_render_derived", InternalTraversal.dp_boolean), 

1878 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1879 ] 

1880 

1881 def _init( 

1882 self, 

1883 selectable: Any, 

1884 *, 

1885 name: Optional[str] = None, 

1886 table_value_type: Optional[TableValueType] = None, 

1887 joins_implicitly: bool = False, 

1888 ) -> None: 

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

1890 

1891 self.joins_implicitly = joins_implicitly 

1892 self._tableval_type = ( 

1893 type_api.TABLEVALUE 

1894 if table_value_type is None 

1895 else table_value_type 

1896 ) 

1897 

1898 @HasMemoized.memoized_attribute 

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

1900 """Return a column expression representing this 

1901 :class:`_sql.TableValuedAlias`. 

1902 

1903 This accessor is used to implement the 

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

1905 method for further details. 

1906 

1907 E.g.: 

1908 

1909 .. sourcecode:: pycon+sql 

1910 

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

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

1913 

1914 .. seealso:: 

1915 

1916 :meth:`_functions.FunctionElement.column_valued` 

1917 

1918 """ 

1919 

1920 return TableValuedColumn(self, self._tableval_type) 

1921 

1922 def alias( 

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

1924 ) -> TableValuedAlias: 

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

1926 

1927 This creates a distinct FROM object that will be distinguished 

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

1929 

1930 """ 

1931 

1932 tva: TableValuedAlias = TableValuedAlias._construct( 

1933 self, 

1934 name=name, 

1935 table_value_type=self._tableval_type, 

1936 joins_implicitly=self.joins_implicitly, 

1937 ) 

1938 

1939 if self._render_derived: 

1940 tva._render_derived = True 

1941 tva._render_derived_w_types = self._render_derived_w_types 

1942 

1943 return tva 

1944 

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

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

1947 set, so that it renders as LATERAL. 

1948 

1949 .. seealso:: 

1950 

1951 :func:`_expression.lateral` 

1952 

1953 """ 

1954 tva = self.alias(name=name) 

1955 tva._is_lateral = True 

1956 return tva 

1957 

1958 def render_derived( 

1959 self, 

1960 name: Optional[str] = None, 

1961 with_types: bool = False, 

1962 ) -> TableValuedAlias: 

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

1964 

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

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

1967 

1968 .. sourcecode:: pycon+sql 

1969 

1970 >>> print( 

1971 ... select( 

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

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

1974 ... .render_derived() 

1975 ... ) 

1976 ... ) 

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

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

1979 

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

1981 the alias expression (this syntax currently applies to the 

1982 PostgreSQL database): 

1983 

1984 .. sourcecode:: pycon+sql 

1985 

1986 >>> print( 

1987 ... select( 

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

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

1990 ... .render_derived(with_types=True) 

1991 ... ) 

1992 ... ) 

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

1994 AS anon_1(a INTEGER, b VARCHAR) 

1995 

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

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

1998 

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

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

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

2002 

2003 """ # noqa: E501 

2004 

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

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

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

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

2009 # (just saw it happen on CI) 

2010 

2011 # construct against original to prevent memory growth 

2012 # for repeated generations 

2013 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2014 self.element, 

2015 name=name, 

2016 table_value_type=self._tableval_type, 

2017 joins_implicitly=self.joins_implicitly, 

2018 ) 

2019 new_alias._render_derived = True 

2020 new_alias._render_derived_w_types = with_types 

2021 return new_alias 

2022 

2023 

2024class Lateral(FromClauseAlias, LateralFromClause): 

2025 """Represent a LATERAL subquery. 

2026 

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

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

2029 method available 

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

2031 

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

2033 PostgreSQL versions provide support for this keyword. 

2034 

2035 .. seealso:: 

2036 

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

2038 

2039 """ 

2040 

2041 __visit_name__ = "lateral" 

2042 _is_lateral = True 

2043 

2044 inherit_cache = True 

2045 

2046 @classmethod 

2047 def _factory( 

2048 cls, 

2049 selectable: Union[SelectBase, _FromClauseArgument], 

2050 name: Optional[str] = None, 

2051 ) -> LateralFromClause: 

2052 return coercions.expect( 

2053 roles.FromClauseRole, selectable, explicit_subquery=True 

2054 ).lateral(name=name) 

2055 

2056 

2057class TableSample(FromClauseAlias): 

2058 """Represent a TABLESAMPLE clause. 

2059 

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

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

2062 method 

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

2064 

2065 .. seealso:: 

2066 

2067 :func:`_expression.tablesample` 

2068 

2069 """ 

2070 

2071 __visit_name__ = "tablesample" 

2072 

2073 _traverse_internals: _TraverseInternalsType = ( 

2074 AliasedReturnsRows._traverse_internals 

2075 + [ 

2076 ("sampling", InternalTraversal.dp_clauseelement), 

2077 ("seed", InternalTraversal.dp_clauseelement), 

2078 ] 

2079 ) 

2080 

2081 @classmethod 

2082 def _factory( 

2083 cls, 

2084 selectable: _FromClauseArgument, 

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

2086 name: Optional[str] = None, 

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

2088 ) -> TableSample: 

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

2090 sampling, name=name, seed=seed 

2091 ) 

2092 

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

2094 def _init( # type: ignore[override] 

2095 self, 

2096 selectable: Any, 

2097 *, 

2098 name: Optional[str] = None, 

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

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

2101 ) -> None: 

2102 assert sampling is not None 

2103 functions = util.preloaded.sql_functions 

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

2105 sampling = functions.func.system(sampling) 

2106 

2107 self.sampling: Function[Any] = sampling 

2108 self.seed = seed 

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

2110 

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

2112 return self.sampling 

2113 

2114 

2115class CTE( 

2116 roles.DMLTableRole, 

2117 roles.IsCTERole, 

2118 Generative, 

2119 HasPrefixes, 

2120 HasSuffixes, 

2121 AliasedReturnsRows, 

2122): 

2123 """Represent a Common Table Expression. 

2124 

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

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

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

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

2129 :class:`_sql.Update` and 

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

2131 usage details on CTEs. 

2132 

2133 .. seealso:: 

2134 

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

2136 

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

2138 

2139 """ 

2140 

2141 __visit_name__ = "cte" 

2142 

2143 _traverse_internals: _TraverseInternalsType = ( 

2144 AliasedReturnsRows._traverse_internals 

2145 + [ 

2146 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2147 ("_restates", InternalTraversal.dp_clauseelement), 

2148 ("recursive", InternalTraversal.dp_boolean), 

2149 ("nesting", InternalTraversal.dp_boolean), 

2150 ] 

2151 + HasPrefixes._has_prefixes_traverse_internals 

2152 + HasSuffixes._has_suffixes_traverse_internals 

2153 ) 

2154 

2155 element: HasCTE 

2156 

2157 @classmethod 

2158 def _factory( 

2159 cls, 

2160 selectable: HasCTE, 

2161 name: Optional[str] = None, 

2162 recursive: bool = False, 

2163 ) -> CTE: 

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

2165 or Common Table Expression instance. 

2166 

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

2168 

2169 """ 

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

2171 name=name, recursive=recursive 

2172 ) 

2173 

2174 def _init( 

2175 self, 

2176 selectable: HasCTE, 

2177 *, 

2178 name: Optional[str] = None, 

2179 recursive: bool = False, 

2180 nesting: bool = False, 

2181 _cte_alias: Optional[CTE] = None, 

2182 _restates: Optional[CTE] = None, 

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

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

2185 ) -> None: 

2186 self.recursive = recursive 

2187 self.nesting = nesting 

2188 self._cte_alias = _cte_alias 

2189 # Keep recursivity reference with union/union_all 

2190 self._restates = _restates 

2191 if _prefixes: 

2192 self._prefixes = _prefixes 

2193 if _suffixes: 

2194 self._suffixes = _suffixes 

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

2196 

2197 def _populate_column_collection( 

2198 self, 

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

2200 primary_key: ColumnSet, 

2201 foreign_keys: Set[KeyedColumnElement[Any]], 

2202 ) -> None: 

2203 if self._cte_alias is not None: 

2204 self._cte_alias._generate_fromclause_column_proxies( 

2205 self, 

2206 columns, 

2207 primary_key=primary_key, 

2208 foreign_keys=foreign_keys, 

2209 ) 

2210 else: 

2211 self.element._generate_fromclause_column_proxies( 

2212 self, 

2213 columns, 

2214 primary_key=primary_key, 

2215 foreign_keys=foreign_keys, 

2216 ) 

2217 

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

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

2220 :class:`_expression.CTE`. 

2221 

2222 This method is a CTE-specific specialization of the 

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

2224 

2225 .. seealso:: 

2226 

2227 :ref:`tutorial_using_aliases` 

2228 

2229 :func:`_expression.alias` 

2230 

2231 """ 

2232 return CTE._construct( 

2233 self.element, 

2234 name=name, 

2235 recursive=self.recursive, 

2236 nesting=self.nesting, 

2237 _cte_alias=self, 

2238 _prefixes=self._prefixes, 

2239 _suffixes=self._suffixes, 

2240 ) 

2241 

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

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

2244 of the original CTE against the given selectables provided 

2245 as positional arguments. 

2246 

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

2248 UNION. 

2249 

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

2251 

2252 .. seealso:: 

2253 

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

2255 

2256 """ 

2257 assert is_select_statement( 

2258 self.element 

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

2260 

2261 return CTE._construct( 

2262 self.element.union(*other), 

2263 name=self.name, 

2264 recursive=self.recursive, 

2265 nesting=self.nesting, 

2266 _restates=self, 

2267 _prefixes=self._prefixes, 

2268 _suffixes=self._suffixes, 

2269 ) 

2270 

2271 def union_all( 

2272 self, *other: _SelectStatementForCompoundArgument[Any] 

2273 ) -> CTE: 

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

2275 of the original CTE against the given selectables provided 

2276 as positional arguments. 

2277 

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

2279 UNION. 

2280 

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

2282 

2283 .. seealso:: 

2284 

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

2286 

2287 """ 

2288 

2289 assert is_select_statement( 

2290 self.element 

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

2292 

2293 return CTE._construct( 

2294 self.element.union_all(*other), 

2295 name=self.name, 

2296 recursive=self.recursive, 

2297 nesting=self.nesting, 

2298 _restates=self, 

2299 _prefixes=self._prefixes, 

2300 _suffixes=self._suffixes, 

2301 ) 

2302 

2303 def _get_reference_cte(self) -> CTE: 

2304 """ 

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

2306 Updated CTEs should still refer to the original CTE. 

2307 This function returns this reference identifier. 

2308 """ 

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

2310 

2311 

2312class _CTEOpts(NamedTuple): 

2313 nesting: bool 

2314 

2315 

2316class _ColumnsPlusNames(NamedTuple): 

2317 required_label_name: Optional[str] 

2318 """ 

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

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

2321 """ 

2322 

2323 proxy_key: Optional[str] 

2324 """ 

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

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

2327 select.selected_columns collection 

2328 """ 

2329 

2330 fallback_label_name: Optional[str] 

2331 """ 

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

2333 we have to render a label even though 

2334 required_label_name was not given 

2335 """ 

2336 

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

2338 """ 

2339 the ColumnElement itself 

2340 """ 

2341 

2342 repeated: bool 

2343 """ 

2344 True if this is a duplicate of a previous column 

2345 in the list of columns 

2346 """ 

2347 

2348 

2349class SelectsRows(ReturnsRows): 

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

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

2352 

2353 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2354 

2355 def _generate_columns_plus_names( 

2356 self, 

2357 anon_for_dupe_key: bool, 

2358 cols: Optional[_SelectIterable] = None, 

2359 ) -> List[_ColumnsPlusNames]: 

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

2361 the compiler. 

2362 

2363 This is distinct from the _column_naming_convention generator that's 

2364 intended for population of .c collections and similar, which has 

2365 different rules. the collection returned here calls upon the 

2366 _column_naming_convention as well. 

2367 

2368 """ 

2369 

2370 if cols is None: 

2371 cols = self._all_selected_columns 

2372 

2373 key_naming_convention = SelectState._column_naming_convention( 

2374 self._label_style 

2375 ) 

2376 

2377 names = {} 

2378 

2379 result: List[_ColumnsPlusNames] = [] 

2380 result_append = result.append 

2381 

2382 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2383 label_style_none = self._label_style is LABEL_STYLE_NONE 

2384 

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

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

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

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

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

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

2391 dedupe_hash = 1 

2392 

2393 for c in cols: 

2394 repeated = False 

2395 

2396 if not c._render_label_in_columns_clause: 

2397 effective_name = required_label_name = fallback_label_name = ( 

2398 None 

2399 ) 

2400 elif label_style_none: 

2401 if TYPE_CHECKING: 

2402 assert is_column_element(c) 

2403 

2404 effective_name = required_label_name = None 

2405 fallback_label_name = c._non_anon_label or c._anon_name_label 

2406 else: 

2407 if TYPE_CHECKING: 

2408 assert is_column_element(c) 

2409 

2410 if table_qualified: 

2411 required_label_name = effective_name = ( 

2412 fallback_label_name 

2413 ) = c._tq_label 

2414 else: 

2415 effective_name = fallback_label_name = c._non_anon_label 

2416 required_label_name = None 

2417 

2418 if effective_name is None: 

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

2420 # not need _expression_label but it isn't 

2421 # giving us a clue when to use anon_label instead 

2422 expr_label = c._expression_label 

2423 if expr_label is None: 

2424 repeated = c._anon_name_label in names 

2425 names[c._anon_name_label] = c 

2426 effective_name = required_label_name = None 

2427 

2428 if repeated: 

2429 # here, "required_label_name" is sent as 

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

2431 if table_qualified: 

2432 fallback_label_name = ( 

2433 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2434 ) 

2435 dedupe_hash += 1 

2436 else: 

2437 fallback_label_name = c._dedupe_anon_label_idx( 

2438 dedupe_hash 

2439 ) 

2440 dedupe_hash += 1 

2441 else: 

2442 fallback_label_name = c._anon_name_label 

2443 else: 

2444 required_label_name = effective_name = ( 

2445 fallback_label_name 

2446 ) = expr_label 

2447 

2448 if effective_name is not None: 

2449 if TYPE_CHECKING: 

2450 assert is_column_element(c) 

2451 

2452 if effective_name in names: 

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

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

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

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

2457 # different column under the same name. apply 

2458 # disambiguating label 

2459 if table_qualified: 

2460 required_label_name = fallback_label_name = ( 

2461 c._anon_tq_label 

2462 ) 

2463 else: 

2464 required_label_name = fallback_label_name = ( 

2465 c._anon_name_label 

2466 ) 

2467 

2468 if anon_for_dupe_key and required_label_name in names: 

2469 # here, c._anon_tq_label is definitely unique to 

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

2471 # this should always be true. 

2472 # this is also an infrequent codepath because 

2473 # you need two levels of duplication to be here 

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

2475 

2476 # the column under the disambiguating label is 

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

2478 # subsequent occurrences of the column so that the 

2479 # original stays non-ambiguous 

2480 if table_qualified: 

2481 required_label_name = fallback_label_name = ( 

2482 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2483 ) 

2484 dedupe_hash += 1 

2485 else: 

2486 required_label_name = fallback_label_name = ( 

2487 c._dedupe_anon_label_idx(dedupe_hash) 

2488 ) 

2489 dedupe_hash += 1 

2490 repeated = True 

2491 else: 

2492 names[required_label_name] = c 

2493 elif anon_for_dupe_key: 

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

2495 # label so that the original stays non-ambiguous 

2496 if table_qualified: 

2497 required_label_name = fallback_label_name = ( 

2498 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2499 ) 

2500 dedupe_hash += 1 

2501 else: 

2502 required_label_name = fallback_label_name = ( 

2503 c._dedupe_anon_label_idx(dedupe_hash) 

2504 ) 

2505 dedupe_hash += 1 

2506 repeated = True 

2507 else: 

2508 names[effective_name] = c 

2509 

2510 result_append( 

2511 _ColumnsPlusNames( 

2512 required_label_name, 

2513 key_naming_convention(c), 

2514 fallback_label_name, 

2515 c, 

2516 repeated, 

2517 ) 

2518 ) 

2519 

2520 return result 

2521 

2522 

2523class HasCTE(roles.HasCTERole, SelectsRows): 

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

2525 

2526 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2527 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2528 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2529 ] 

2530 

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

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

2533 

2534 name_cte_columns: bool = False 

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

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

2537 

2538 .. versionadded:: 2.0.42 

2539 

2540 """ 

2541 

2542 @_generative 

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

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

2545 

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

2547 the parent statement such that they will each be unconditionally 

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

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

2550 

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

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

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

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

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

2556 statement. 

2557 

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

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

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

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

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

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

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

2565 larger statement. 

2566 

2567 E.g.:: 

2568 

2569 from sqlalchemy import table, column, select 

2570 

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

2572 

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

2574 

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

2576 

2577 Would render: 

2578 

2579 .. sourcecode:: sql 

2580 

2581 WITH anon_1 AS ( 

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

2583 ) 

2584 SELECT t.c1, t.c2 

2585 FROM t 

2586 

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

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

2589 statement. 

2590 

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

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

2593 

2594 from sqlalchemy import table, column 

2595 from sqlalchemy.dialects.postgresql import insert 

2596 

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

2598 

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

2600 

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

2602 update_statement = insert_stmt.on_conflict_do_update( 

2603 index_elements=[t.c.c1], 

2604 set_={ 

2605 "c1": insert_stmt.excluded.c1, 

2606 "c2": insert_stmt.excluded.c2, 

2607 }, 

2608 ).add_cte(delete_statement_cte) 

2609 

2610 print(update_statement) 

2611 

2612 The above statement renders as: 

2613 

2614 .. sourcecode:: sql 

2615 

2616 WITH deletions AS ( 

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

2618 ) 

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

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

2621 

2622 .. versionadded:: 1.4.21 

2623 

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

2625 

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

2627 

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

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

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

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

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

2633 this statement when this flag is given. 

2634 

2635 .. versionadded:: 2.0 

2636 

2637 .. seealso:: 

2638 

2639 :paramref:`.HasCTE.cte.nesting` 

2640 

2641 

2642 """ # noqa: E501 

2643 opt = _CTEOpts(nest_here) 

2644 for cte in ctes: 

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

2646 self._independent_ctes += (cte,) 

2647 self._independent_ctes_opts += (opt,) 

2648 return self 

2649 

2650 def cte( 

2651 self, 

2652 name: Optional[str] = None, 

2653 recursive: bool = False, 

2654 nesting: bool = False, 

2655 ) -> CTE: 

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

2657 or Common Table Expression instance. 

2658 

2659 Common table expressions are a SQL standard whereby SELECT 

2660 statements can draw upon secondary statements specified along 

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

2662 Special semantics regarding UNION can also be employed to 

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

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

2665 

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

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

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

2669 CTE rows. 

2670 

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

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

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

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

2675 

2676 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2678 method may be 

2679 used to establish these. 

2680 

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

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

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

2684 compile time. 

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

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

2687 conjunction with UNION ALL in order to derive rows 

2688 from those already selected. 

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

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

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

2692 :paramref:`.HasCTE.add_cte.nest_here` 

2693 parameter may also be used to more carefully 

2694 control the exact placement of a particular CTE. 

2695 

2696 .. versionadded:: 1.4.24 

2697 

2698 .. seealso:: 

2699 

2700 :meth:`.HasCTE.add_cte` 

2701 

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

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

2704 as well as additional examples. 

2705 

2706 Example 1, non recursive:: 

2707 

2708 from sqlalchemy import ( 

2709 Table, 

2710 Column, 

2711 String, 

2712 Integer, 

2713 MetaData, 

2714 select, 

2715 func, 

2716 ) 

2717 

2718 metadata = MetaData() 

2719 

2720 orders = Table( 

2721 "orders", 

2722 metadata, 

2723 Column("region", String), 

2724 Column("amount", Integer), 

2725 Column("product", String), 

2726 Column("quantity", Integer), 

2727 ) 

2728 

2729 regional_sales = ( 

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

2731 .group_by(orders.c.region) 

2732 .cte("regional_sales") 

2733 ) 

2734 

2735 

2736 top_regions = ( 

2737 select(regional_sales.c.region) 

2738 .where( 

2739 regional_sales.c.total_sales 

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

2741 ) 

2742 .cte("top_regions") 

2743 ) 

2744 

2745 statement = ( 

2746 select( 

2747 orders.c.region, 

2748 orders.c.product, 

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

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

2751 ) 

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

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

2754 ) 

2755 

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

2757 

2758 Example 2, WITH RECURSIVE:: 

2759 

2760 from sqlalchemy import ( 

2761 Table, 

2762 Column, 

2763 String, 

2764 Integer, 

2765 MetaData, 

2766 select, 

2767 func, 

2768 ) 

2769 

2770 metadata = MetaData() 

2771 

2772 parts = Table( 

2773 "parts", 

2774 metadata, 

2775 Column("part", String), 

2776 Column("sub_part", String), 

2777 Column("quantity", Integer), 

2778 ) 

2779 

2780 included_parts = ( 

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

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

2783 .cte(recursive=True) 

2784 ) 

2785 

2786 

2787 incl_alias = included_parts.alias() 

2788 parts_alias = parts.alias() 

2789 included_parts = included_parts.union_all( 

2790 select( 

2791 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2793 ) 

2794 

2795 statement = select( 

2796 included_parts.c.sub_part, 

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

2798 ).group_by(included_parts.c.sub_part) 

2799 

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

2801 

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

2803 

2804 from datetime import date 

2805 from sqlalchemy import ( 

2806 MetaData, 

2807 Table, 

2808 Column, 

2809 Integer, 

2810 Date, 

2811 select, 

2812 literal, 

2813 and_, 

2814 exists, 

2815 ) 

2816 

2817 metadata = MetaData() 

2818 

2819 visitors = Table( 

2820 "visitors", 

2821 metadata, 

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

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

2824 Column("count", Integer), 

2825 ) 

2826 

2827 # add 5 visitors for the product_id == 1 

2828 product_id = 1 

2829 day = date.today() 

2830 count = 5 

2831 

2832 update_cte = ( 

2833 visitors.update() 

2834 .where( 

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

2836 ) 

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

2838 .returning(literal(1)) 

2839 .cte("update_cte") 

2840 ) 

2841 

2842 upsert = visitors.insert().from_select( 

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

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

2845 ~exists(update_cte.select()) 

2846 ), 

2847 ) 

2848 

2849 connection.execute(upsert) 

2850 

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

2852 

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

2854 

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

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

2857 "value_a", nesting=True 

2858 ) 

2859 

2860 # Nesting CTEs takes ascendency locally 

2861 # over the CTEs at a higher level 

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

2863 

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

2865 

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

2867 shown with inline parameters below as: 

2868 

2869 .. sourcecode:: sql 

2870 

2871 WITH 

2872 value_a AS 

2873 (SELECT 'root' AS n), 

2874 value_b AS 

2875 (WITH value_a AS 

2876 (SELECT 'nesting' AS n) 

2877 SELECT value_a.n AS n FROM value_a) 

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

2879 FROM value_a, value_b 

2880 

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

2882 as follows (SQLAlchemy 2.0 and above):: 

2883 

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

2885 

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

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

2888 

2889 # Nesting CTEs takes ascendency locally 

2890 # over the CTEs at a higher level 

2891 value_b = ( 

2892 select(value_a_nested.c.n) 

2893 .add_cte(value_a_nested, nest_here=True) 

2894 .cte("value_b") 

2895 ) 

2896 

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

2898 

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

2900 

2901 edge = Table( 

2902 "edge", 

2903 metadata, 

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

2905 Column("left", Integer), 

2906 Column("right", Integer), 

2907 ) 

2908 

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

2910 

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

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

2913 ) 

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

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

2916 ) 

2917 

2918 subgraph_cte = root_node.union(left_edge, right_edge) 

2919 

2920 subgraph = select(subgraph_cte) 

2921 

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

2923 

2924 .. sourcecode:: sql 

2925 

2926 WITH RECURSIVE nodes(node) AS ( 

2927 SELECT 1 AS node 

2928 UNION 

2929 SELECT edge."left" AS "left" 

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

2931 UNION 

2932 SELECT edge."right" AS "right" 

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

2934 ) 

2935 SELECT nodes.node FROM nodes 

2936 

2937 .. seealso:: 

2938 

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

2940 :meth:`_expression.HasCTE.cte`. 

2941 

2942 """ # noqa: E501 

2943 return CTE._construct( 

2944 self, name=name, recursive=recursive, nesting=nesting 

2945 ) 

2946 

2947 

2948class Subquery(AliasedReturnsRows): 

2949 """Represent a subquery of a SELECT. 

2950 

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

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

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

2954 :class:`_expression.SelectBase` subclass 

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

2956 :class:`_expression.CompoundSelect`, and 

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

2958 it represents the 

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

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

2961 

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

2963 :class:`_expression.Alias` 

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

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

2966 :class:`_expression.Alias` always 

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

2968 :class:`.Subquery` 

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

2970 

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

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

2973 statement. 

2974 

2975 """ 

2976 

2977 __visit_name__ = "subquery" 

2978 

2979 _is_subquery = True 

2980 

2981 inherit_cache = True 

2982 

2983 element: SelectBase 

2984 

2985 @classmethod 

2986 def _factory( 

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

2988 ) -> Subquery: 

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

2990 

2991 return coercions.expect( 

2992 roles.SelectStatementRole, selectable 

2993 ).subquery(name=name) 

2994 

2995 @util.deprecated( 

2996 "1.4", 

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

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

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

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

3001 ":func:`_expression.select` " 

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

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

3004 ) 

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

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

3007 

3008 

3009class FromGrouping(GroupedElement, FromClause): 

3010 """Represent a grouping of a FROM clause""" 

3011 

3012 _traverse_internals: _TraverseInternalsType = [ 

3013 ("element", InternalTraversal.dp_clauseelement) 

3014 ] 

3015 

3016 element: FromClause 

3017 

3018 def __init__(self, element: FromClause): 

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

3020 

3021 @util.ro_non_memoized_property 

3022 def columns( 

3023 self, 

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

3025 return self.element.columns 

3026 

3027 @util.ro_non_memoized_property 

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

3029 return self.element.columns 

3030 

3031 @property 

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

3033 return self.element.primary_key 

3034 

3035 @property 

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

3037 return self.element.foreign_keys 

3038 

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

3040 return self.element.is_derived_from(fromclause) 

3041 

3042 def alias( 

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

3044 ) -> NamedFromGrouping: 

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

3046 

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

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

3049 

3050 @util.ro_non_memoized_property 

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

3052 return self.element._hide_froms 

3053 

3054 @util.ro_non_memoized_property 

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

3056 return self.element._from_objects 

3057 

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

3059 return {"element": self.element} 

3060 

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

3062 self.element = state["element"] 

3063 

3064 if TYPE_CHECKING: 

3065 

3066 def self_group( 

3067 self, against: Optional[OperatorType] = None 

3068 ) -> Self: ... 

3069 

3070 

3071class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3073 

3074 .. versionadded:: 2.0 

3075 

3076 """ 

3077 

3078 inherit_cache = True 

3079 

3080 if TYPE_CHECKING: 

3081 

3082 def self_group( 

3083 self, against: Optional[OperatorType] = None 

3084 ) -> Self: ... 

3085 

3086 

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

3088 """Represents a minimal "table" construct. 

3089 

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

3091 collection of columns, which are typically produced 

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

3093 

3094 from sqlalchemy import table, column 

3095 

3096 user = table( 

3097 "user", 

3098 column("id"), 

3099 column("name"), 

3100 column("description"), 

3101 ) 

3102 

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

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

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

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

3107 

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

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

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

3111 It's useful 

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

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

3114 is not on hand. 

3115 

3116 """ 

3117 

3118 __visit_name__ = "table" 

3119 

3120 _traverse_internals: _TraverseInternalsType = [ 

3121 ( 

3122 "columns", 

3123 InternalTraversal.dp_fromclause_canonical_column_collection, 

3124 ), 

3125 ("name", InternalTraversal.dp_string), 

3126 ("schema", InternalTraversal.dp_string), 

3127 ] 

3128 

3129 _is_table = True 

3130 

3131 fullname: str 

3132 

3133 implicit_returning = False 

3134 """:class:`_expression.TableClause` 

3135 doesn't support having a primary key or column 

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

3137 

3138 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3139 

3140 @util.ro_memoized_property 

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

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

3143 return None 

3144 

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

3146 super().__init__() 

3147 self.name = name 

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

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

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

3151 for c in columns: 

3152 self.append_column(c) 

3153 

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

3155 if schema is not None: 

3156 self.schema = schema 

3157 if self.schema is not None: 

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

3159 else: 

3160 self.fullname = self.name 

3161 if kw: 

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

3163 

3164 if TYPE_CHECKING: 

3165 

3166 @util.ro_non_memoized_property 

3167 def columns( 

3168 self, 

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

3170 

3171 @util.ro_non_memoized_property 

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

3173 

3174 def __str__(self) -> str: 

3175 if self.schema is not None: 

3176 return self.schema + "." + self.name 

3177 else: 

3178 return self.name 

3179 

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

3181 pass 

3182 

3183 @util.ro_memoized_property 

3184 def description(self) -> str: 

3185 return self.name 

3186 

3187 def _insert_col_impl( 

3188 self, 

3189 c: ColumnClause[Any], 

3190 *, 

3191 index: Optional[int] = None, 

3192 ) -> None: 

3193 existing = c.table 

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

3195 raise exc.ArgumentError( 

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

3197 % (c.key, existing) 

3198 ) 

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

3200 c.table = self 

3201 

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

3203 self._insert_col_impl(c) 

3204 

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

3206 self._insert_col_impl(c, index=index) 

3207 

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

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

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

3211 :class:`_expression.TableClause`. 

3212 

3213 E.g.:: 

3214 

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

3216 

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

3218 

3219 """ 

3220 

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

3222 

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

3224 def update(self) -> Update: 

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

3226 :class:`_expression.TableClause`. 

3227 

3228 E.g.:: 

3229 

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

3231 

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

3233 

3234 """ 

3235 return util.preloaded.sql_dml.Update( 

3236 self, 

3237 ) 

3238 

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

3240 def delete(self) -> Delete: 

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

3242 :class:`_expression.TableClause`. 

3243 

3244 E.g.:: 

3245 

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

3247 

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

3249 

3250 """ 

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

3252 

3253 @util.ro_non_memoized_property 

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

3255 return [self] 

3256 

3257 

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

3259 

3260 

3261class ForUpdateArg(ClauseElement): 

3262 _traverse_internals: _TraverseInternalsType = [ 

3263 ("of", InternalTraversal.dp_clauseelement_list), 

3264 ("nowait", InternalTraversal.dp_boolean), 

3265 ("read", InternalTraversal.dp_boolean), 

3266 ("skip_locked", InternalTraversal.dp_boolean), 

3267 ("key_share", InternalTraversal.dp_boolean), 

3268 ] 

3269 

3270 of: Optional[Sequence[ClauseElement]] 

3271 nowait: bool 

3272 read: bool 

3273 skip_locked: bool 

3274 

3275 @classmethod 

3276 def _from_argument( 

3277 cls, with_for_update: ForUpdateParameter 

3278 ) -> Optional[ForUpdateArg]: 

3279 if isinstance(with_for_update, ForUpdateArg): 

3280 return with_for_update 

3281 elif with_for_update in (None, False): 

3282 return None 

3283 elif with_for_update is True: 

3284 return ForUpdateArg() 

3285 else: 

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

3287 

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

3289 return ( 

3290 isinstance(other, ForUpdateArg) 

3291 and other.nowait == self.nowait 

3292 and other.read == self.read 

3293 and other.skip_locked == self.skip_locked 

3294 and other.key_share == self.key_share 

3295 and other.of is self.of 

3296 ) 

3297 

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

3299 return not self.__eq__(other) 

3300 

3301 def __hash__(self) -> int: 

3302 return id(self) 

3303 

3304 def __init__( 

3305 self, 

3306 *, 

3307 nowait: bool = False, 

3308 read: bool = False, 

3309 of: Optional[_ForUpdateOfArgument] = None, 

3310 skip_locked: bool = False, 

3311 key_share: bool = False, 

3312 ): 

3313 """Represents arguments specified to 

3314 :meth:`_expression.Select.for_update`. 

3315 

3316 """ 

3317 

3318 self.nowait = nowait 

3319 self.read = read 

3320 self.skip_locked = skip_locked 

3321 self.key_share = key_share 

3322 if of is not None: 

3323 self.of = [ 

3324 coercions.expect(roles.ColumnsClauseRole, elem) 

3325 for elem in util.to_list(of) 

3326 ] 

3327 else: 

3328 self.of = None 

3329 

3330 

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

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

3333 in a statement. 

3334 

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

3336 :func:`_expression.values` function. 

3337 

3338 .. versionadded:: 1.4 

3339 

3340 """ 

3341 

3342 __visit_name__ = "values" 

3343 

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

3345 

3346 _unnamed: bool 

3347 _traverse_internals: _TraverseInternalsType = [ 

3348 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3349 ("_data", InternalTraversal.dp_dml_multi_values), 

3350 ("name", InternalTraversal.dp_string), 

3351 ("literal_binds", InternalTraversal.dp_boolean), 

3352 ] + HasCTE._has_ctes_traverse_internals 

3353 

3354 name_cte_columns = True 

3355 

3356 def __init__( 

3357 self, 

3358 *columns: ColumnClause[Any], 

3359 name: Optional[str] = None, 

3360 literal_binds: bool = False, 

3361 ): 

3362 super().__init__() 

3363 self._column_args = columns 

3364 

3365 if name is None: 

3366 self._unnamed = True 

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

3368 else: 

3369 self._unnamed = False 

3370 self.name = name 

3371 self.literal_binds = literal_binds 

3372 self.named_with_column = not self._unnamed 

3373 

3374 @property 

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

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

3377 

3378 @util.ro_non_memoized_property 

3379 def _all_selected_columns(self) -> _SelectIterable: 

3380 return self._column_args 

3381 

3382 @_generative 

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

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

3385 construct that is a copy of this 

3386 one with the given name. 

3387 

3388 This method is a VALUES-specific specialization of the 

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

3390 

3391 .. seealso:: 

3392 

3393 :ref:`tutorial_using_aliases` 

3394 

3395 :func:`_expression.alias` 

3396 

3397 """ 

3398 non_none_name: str 

3399 

3400 if name is None: 

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

3402 else: 

3403 non_none_name = name 

3404 

3405 self.name = non_none_name 

3406 self.named_with_column = True 

3407 self._unnamed = False 

3408 return self 

3409 

3410 @_generative 

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

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

3413 so that 

3414 it renders as LATERAL. 

3415 

3416 .. seealso:: 

3417 

3418 :func:`_expression.lateral` 

3419 

3420 """ 

3421 non_none_name: str 

3422 

3423 if name is None: 

3424 non_none_name = self.name 

3425 else: 

3426 non_none_name = name 

3427 

3428 self._is_lateral = True 

3429 self.name = non_none_name 

3430 self._unnamed = False 

3431 return self 

3432 

3433 @_generative 

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

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

3436 adding the given data to the data list. 

3437 

3438 E.g.:: 

3439 

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

3441 

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

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

3444 constructor. 

3445 

3446 """ 

3447 

3448 self._data += (values,) 

3449 return self 

3450 

3451 def scalar_values(self) -> ScalarValues: 

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

3453 COLUMN element in a statement. 

3454 

3455 .. versionadded:: 2.0.0b4 

3456 

3457 """ 

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

3459 

3460 def _populate_column_collection( 

3461 self, 

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

3463 primary_key: ColumnSet, 

3464 foreign_keys: Set[KeyedColumnElement[Any]], 

3465 ) -> None: 

3466 for c in self._column_args: 

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

3468 _, c = c._make_proxy( 

3469 self, primary_key=primary_key, foreign_keys=foreign_keys 

3470 ) 

3471 else: 

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

3473 # no memoizations of other FROM clauses. 

3474 # see test_values.py -> test_auto_proxy_select_direct_col 

3475 c._reset_memoizations() 

3476 columns.add(c) 

3477 c.table = self 

3478 

3479 @util.ro_non_memoized_property 

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

3481 return [self] 

3482 

3483 

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

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

3486 COLUMN element in a statement. 

3487 

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

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

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

3491 an ``IN`` or ``NOT IN`` condition. 

3492 

3493 .. versionadded:: 2.0.0b4 

3494 

3495 """ 

3496 

3497 __visit_name__ = "scalar_values" 

3498 

3499 _traverse_internals: _TraverseInternalsType = [ 

3500 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3501 ("_data", InternalTraversal.dp_dml_multi_values), 

3502 ("literal_binds", InternalTraversal.dp_boolean), 

3503 ] 

3504 

3505 def __init__( 

3506 self, 

3507 columns: Sequence[ColumnClause[Any]], 

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

3509 literal_binds: bool, 

3510 ): 

3511 super().__init__() 

3512 self._column_args = columns 

3513 self._data = data 

3514 self.literal_binds = literal_binds 

3515 

3516 @property 

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

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

3519 

3520 def __clause_element__(self) -> ScalarValues: 

3521 return self 

3522 

3523 if TYPE_CHECKING: 

3524 

3525 def self_group( 

3526 self, against: Optional[OperatorType] = None 

3527 ) -> Self: ... 

3528 

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

3530 

3531 

3532class SelectBase( 

3533 roles.SelectStatementRole, 

3534 roles.DMLSelectRole, 

3535 roles.CompoundElementRole, 

3536 roles.InElementRole, 

3537 HasCTE, 

3538 SupportsCloneAnnotations, 

3539 Selectable, 

3540): 

3541 """Base class for SELECT statements. 

3542 

3543 

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

3545 :class:`_expression.CompoundSelect` and 

3546 :class:`_expression.TextualSelect`. 

3547 

3548 

3549 """ 

3550 

3551 _is_select_base = True 

3552 is_select = True 

3553 

3554 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3555 

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

3557 self._reset_memoizations() 

3558 

3559 @util.ro_non_memoized_property 

3560 def selected_columns( 

3561 self, 

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

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

3564 representing the columns that 

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

3566 

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

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

3569 within this collection cannot be directly nested inside another SELECT 

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

3571 necessary parenthesization required by SQL. 

3572 

3573 .. note:: 

3574 

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

3576 include expressions established in the columns clause using the 

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

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

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

3580 construct. 

3581 

3582 .. seealso:: 

3583 

3584 :attr:`_sql.Select.selected_columns` 

3585 

3586 .. versionadded:: 1.4 

3587 

3588 """ 

3589 raise NotImplementedError() 

3590 

3591 def _generate_fromclause_column_proxies( 

3592 self, 

3593 subquery: FromClause, 

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

3595 primary_key: ColumnSet, 

3596 foreign_keys: Set[KeyedColumnElement[Any]], 

3597 *, 

3598 proxy_compound_columns: Optional[ 

3599 Iterable[Sequence[ColumnElement[Any]]] 

3600 ] = None, 

3601 ) -> None: 

3602 raise NotImplementedError() 

3603 

3604 @util.ro_non_memoized_property 

3605 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3608 constructs. 

3609 

3610 .. versionadded:: 1.4.12 

3611 

3612 .. seealso:: 

3613 

3614 :attr:`_sql.SelectBase.exported_columns` 

3615 

3616 """ 

3617 raise NotImplementedError() 

3618 

3619 @property 

3620 def exported_columns( 

3621 self, 

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

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

3624 that represents the "exported" 

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

3626 :class:`_sql.TextClause` constructs. 

3627 

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

3629 object are synonymous 

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

3631 

3632 .. versionadded:: 1.4 

3633 

3634 .. seealso:: 

3635 

3636 :attr:`_expression.Select.exported_columns` 

3637 

3638 :attr:`_expression.Selectable.exported_columns` 

3639 

3640 :attr:`_expression.FromClause.exported_columns` 

3641 

3642 

3643 """ 

3644 return self.selected_columns.as_readonly() 

3645 

3646 def get_label_style(self) -> SelectLabelStyle: 

3647 """ 

3648 Retrieve the current label style. 

3649 

3650 Implemented by subclasses. 

3651 

3652 """ 

3653 raise NotImplementedError() 

3654 

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

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

3657 

3658 Implemented by subclasses. 

3659 

3660 """ 

3661 

3662 raise NotImplementedError() 

3663 

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

3665 raise NotImplementedError() 

3666 

3667 @util.deprecated( 

3668 "1.4", 

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

3670 "method is deprecated and will be " 

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

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

3673 ) 

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

3675 return self.scalar_subquery() 

3676 

3677 def exists(self) -> Exists: 

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

3679 which can be used as a column expression. 

3680 

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

3682 

3683 .. seealso:: 

3684 

3685 :func:`_sql.exists` 

3686 

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

3688 

3689 .. versionadded:: 1.4 

3690 

3691 """ 

3692 return Exists(self) 

3693 

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

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

3696 used as a column expression. 

3697 

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

3699 

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

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

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

3703 an enclosing SELECT. 

3704 

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

3706 subquery that can be produced using the 

3707 :meth:`_expression.SelectBase.subquery` 

3708 method. 

3709 

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

3711 :meth:`_expression.SelectBase.scalar_subquery`. 

3712 

3713 .. seealso:: 

3714 

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

3716 

3717 """ 

3718 if self._label_style is not LABEL_STYLE_NONE: 

3719 self = self.set_label_style(LABEL_STYLE_NONE) 

3720 

3721 return ScalarSelect(self) 

3722 

3723 def label(self, name: Optional[str]) -> Label[Any]: 

3724 """Return a 'scalar' representation of this selectable, embedded as a 

3725 subquery with a label. 

3726 

3727 .. seealso:: 

3728 

3729 :meth:`_expression.SelectBase.scalar_subquery`. 

3730 

3731 """ 

3732 return self.scalar_subquery().label(name) 

3733 

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

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

3736 

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

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

3739 

3740 .. seealso:: 

3741 

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

3743 

3744 """ 

3745 return Lateral._factory(self, name) 

3746 

3747 def subquery(self, name: Optional[str] = None) -> Subquery: 

3748 """Return a subquery of this :class:`_expression.SelectBase`. 

3749 

3750 A subquery is from a SQL perspective a parenthesized, named 

3751 construct that can be placed in the FROM clause of another 

3752 SELECT statement. 

3753 

3754 Given a SELECT statement such as:: 

3755 

3756 stmt = select(table.c.id, table.c.name) 

3757 

3758 The above statement might look like: 

3759 

3760 .. sourcecode:: sql 

3761 

3762 SELECT table.id, table.name FROM table 

3763 

3764 The subquery form by itself renders the same way, however when 

3765 embedded into the FROM clause of another SELECT statement, it becomes 

3766 a named sub-element:: 

3767 

3768 subq = stmt.subquery() 

3769 new_stmt = select(subq) 

3770 

3771 The above renders as: 

3772 

3773 .. sourcecode:: sql 

3774 

3775 SELECT anon_1.id, anon_1.name 

3776 FROM (SELECT table.id, table.name FROM table) AS anon_1 

3777 

3778 Historically, :meth:`_expression.SelectBase.subquery` 

3779 is equivalent to calling 

3780 the :meth:`_expression.FromClause.alias` 

3781 method on a FROM object; however, 

3782 as a :class:`_expression.SelectBase` 

3783 object is not directly FROM object, 

3784 the :meth:`_expression.SelectBase.subquery` 

3785 method provides clearer semantics. 

3786 

3787 .. versionadded:: 1.4 

3788 

3789 """ 

3790 

3791 return Subquery._construct( 

3792 self._ensure_disambiguated_names(), name=name 

3793 ) 

3794 

3795 def _ensure_disambiguated_names(self) -> Self: 

3796 """Ensure that the names generated by this selectbase will be 

3797 disambiguated in some way, if possible. 

3798 

3799 """ 

3800 

3801 raise NotImplementedError() 

3802 

3803 def alias( 

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

3805 ) -> Subquery: 

3806 """Return a named subquery against this 

3807 :class:`_expression.SelectBase`. 

3808 

3809 For a :class:`_expression.SelectBase` (as opposed to a 

3810 :class:`_expression.FromClause`), 

3811 this returns a :class:`.Subquery` object which behaves mostly the 

3812 same as the :class:`_expression.Alias` object that is used with a 

3813 :class:`_expression.FromClause`. 

3814 

3815 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3816 method is now 

3817 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3818 

3819 """ 

3820 return self.subquery(name=name) 

3821 

3822 

3823_SB = TypeVar("_SB", bound=SelectBase) 

3824 

3825 

3826class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3827 """Represent a grouping of a :class:`_expression.SelectBase`. 

3828 

3829 This differs from :class:`.Subquery` in that we are still 

3830 an "inner" SELECT statement, this is strictly for grouping inside of 

3831 compound selects. 

3832 

3833 """ 

3834 

3835 __visit_name__ = "select_statement_grouping" 

3836 _traverse_internals: _TraverseInternalsType = [ 

3837 ("element", InternalTraversal.dp_clauseelement) 

3838 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3839 

3840 _is_select_container = True 

3841 

3842 element: _SB 

3843 

3844 def __init__(self, element: _SB) -> None: 

3845 self.element = cast( 

3846 _SB, coercions.expect(roles.SelectStatementRole, element) 

3847 ) 

3848 

3849 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3850 new_element = self.element._ensure_disambiguated_names() 

3851 if new_element is not self.element: 

3852 return SelectStatementGrouping(new_element) 

3853 else: 

3854 return self 

3855 

3856 def get_label_style(self) -> SelectLabelStyle: 

3857 return self.element.get_label_style() 

3858 

3859 def set_label_style( 

3860 self, label_style: SelectLabelStyle 

3861 ) -> SelectStatementGrouping[_SB]: 

3862 return SelectStatementGrouping( 

3863 self.element.set_label_style(label_style) 

3864 ) 

3865 

3866 @property 

3867 def select_statement(self) -> _SB: 

3868 return self.element 

3869 

3870 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3871 return self 

3872 

3873 if TYPE_CHECKING: 

3874 

3875 def _ungroup(self) -> _SB: ... 

3876 

3877 # def _generate_columns_plus_names( 

3878 # self, anon_for_dupe_key: bool 

3879 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3880 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3881 

3882 def _generate_fromclause_column_proxies( 

3883 self, 

3884 subquery: FromClause, 

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

3886 primary_key: ColumnSet, 

3887 foreign_keys: Set[KeyedColumnElement[Any]], 

3888 *, 

3889 proxy_compound_columns: Optional[ 

3890 Iterable[Sequence[ColumnElement[Any]]] 

3891 ] = None, 

3892 ) -> None: 

3893 self.element._generate_fromclause_column_proxies( 

3894 subquery, 

3895 columns, 

3896 proxy_compound_columns=proxy_compound_columns, 

3897 primary_key=primary_key, 

3898 foreign_keys=foreign_keys, 

3899 ) 

3900 

3901 @util.ro_non_memoized_property 

3902 def _all_selected_columns(self) -> _SelectIterable: 

3903 return self.element._all_selected_columns 

3904 

3905 @util.ro_non_memoized_property 

3906 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

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

3908 representing the columns that 

3909 the embedded SELECT statement returns in its result set, not including 

3910 :class:`_sql.TextClause` constructs. 

3911 

3912 .. versionadded:: 1.4 

3913 

3914 .. seealso:: 

3915 

3916 :attr:`_sql.Select.selected_columns` 

3917 

3918 """ 

3919 return self.element.selected_columns 

3920 

3921 @util.ro_non_memoized_property 

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

3923 return self.element._from_objects 

3924 

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

3926 # SelectStatementGrouping not generative: has no attribute '_generate' 

3927 raise NotImplementedError 

3928 

3929 

3930class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

3931 """Base class for SELECT statements where additional elements can be 

3932 added. 

3933 

3934 This serves as the base for :class:`_expression.Select` and 

3935 :class:`_expression.CompoundSelect` 

3936 where elements such as ORDER BY, GROUP BY can be added and column 

3937 rendering can be controlled. Compare to 

3938 :class:`_expression.TextualSelect`, which, 

3939 while it subclasses :class:`_expression.SelectBase` 

3940 and is also a SELECT construct, 

3941 represents a fixed textual string which cannot be altered at this level, 

3942 only wrapped as a subquery. 

3943 

3944 """ 

3945 

3946 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3947 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3948 _limit_clause: Optional[ColumnElement[Any]] = None 

3949 _offset_clause: Optional[ColumnElement[Any]] = None 

3950 _fetch_clause: Optional[ColumnElement[Any]] = None 

3951 _fetch_clause_options: Optional[Dict[str, bool]] = None 

3952 _for_update_arg: Optional[ForUpdateArg] = None 

3953 

3954 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

3955 self._label_style = _label_style 

3956 

3957 @_generative 

3958 def with_for_update( 

3959 self, 

3960 *, 

3961 nowait: bool = False, 

3962 read: bool = False, 

3963 of: Optional[_ForUpdateOfArgument] = None, 

3964 skip_locked: bool = False, 

3965 key_share: bool = False, 

3966 ) -> Self: 

3967 """Specify a ``FOR UPDATE`` clause for this 

3968 :class:`_expression.GenerativeSelect`. 

3969 

3970 E.g.:: 

3971 

3972 stmt = select(table).with_for_update(nowait=True) 

3973 

3974 On a database like PostgreSQL or Oracle Database, the above would 

3975 render a statement like: 

3976 

3977 .. sourcecode:: sql 

3978 

3979 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

3980 

3981 on other backends, the ``nowait`` option is ignored and instead 

3982 would produce: 

3983 

3984 .. sourcecode:: sql 

3985 

3986 SELECT table.a, table.b FROM table FOR UPDATE 

3987 

3988 When called with no arguments, the statement will render with 

3989 the suffix ``FOR UPDATE``. Additional arguments can then be 

3990 provided which allow for common database-specific 

3991 variants. 

3992 

3993 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

3994 Database and PostgreSQL dialects. 

3995 

3996 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

3997 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

3998 ``nowait``, will render ``FOR SHARE NOWAIT``. 

3999 

4000 :param of: SQL expression or list of SQL expression elements, 

4001 (typically :class:`_schema.Column` objects or a compatible expression, 

4002 for some backends may also be a table expression) which will render 

4003 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4004 Database, some MySQL versions and possibly others. May render as a 

4005 table or as a column depending on backend. 

4006 

4007 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4008 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4009 if ``read=True`` is also specified. 

4010 

4011 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4012 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4013 on the PostgreSQL dialect. 

4014 

4015 """ 

4016 self._for_update_arg = ForUpdateArg( 

4017 nowait=nowait, 

4018 read=read, 

4019 of=of, 

4020 skip_locked=skip_locked, 

4021 key_share=key_share, 

4022 ) 

4023 return self 

4024 

4025 def get_label_style(self) -> SelectLabelStyle: 

4026 """ 

4027 Retrieve the current label style. 

4028 

4029 .. versionadded:: 1.4 

4030 

4031 """ 

4032 return self._label_style 

4033 

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

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

4036 

4037 There are three "label styles" available, 

4038 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4039 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4040 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4041 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4042 

4043 In modern SQLAlchemy, there is not generally a need to change the 

4044 labeling style, as per-expression labels are more effectively used by 

4045 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4046 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4047 disambiguate same-named columns from different tables, aliases, or 

4048 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4049 applies labels only to names that conflict with an existing name so 

4050 that the impact of this labeling is minimal. 

4051 

4052 The rationale for disambiguation is mostly so that all column 

4053 expressions are available from a given :attr:`_sql.FromClause.c` 

4054 collection when a subquery is created. 

4055 

4056 .. versionadded:: 1.4 - the 

4057 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4058 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4059 ``use_labels=True`` methods and/or parameters. 

4060 

4061 .. seealso:: 

4062 

4063 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4064 

4065 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` 

4066 

4067 :data:`_sql.LABEL_STYLE_NONE` 

4068 

4069 :data:`_sql.LABEL_STYLE_DEFAULT` 

4070 

4071 """ 

4072 if self._label_style is not style: 

4073 self = self._generate() 

4074 self._label_style = style 

4075 return self 

4076 

4077 @property 

4078 def _group_by_clause(self) -> ClauseList: 

4079 """ClauseList access to group_by_clauses for legacy dialects""" 

4080 return ClauseList._construct_raw( 

4081 operators.comma_op, self._group_by_clauses 

4082 ) 

4083 

4084 @property 

4085 def _order_by_clause(self) -> ClauseList: 

4086 """ClauseList access to order_by_clauses for legacy dialects""" 

4087 return ClauseList._construct_raw( 

4088 operators.comma_op, self._order_by_clauses 

4089 ) 

4090 

4091 def _offset_or_limit_clause( 

4092 self, 

4093 element: _LimitOffsetType, 

4094 name: Optional[str] = None, 

4095 type_: Optional[_TypeEngineArgument[int]] = None, 

4096 ) -> ColumnElement[Any]: 

4097 """Convert the given value to an "offset or limit" clause. 

4098 

4099 This handles incoming integers and converts to an expression; if 

4100 an expression is already given, it is passed through. 

4101 

4102 """ 

4103 return coercions.expect( 

4104 roles.LimitOffsetRole, element, name=name, type_=type_ 

4105 ) 

4106 

4107 @overload 

4108 def _offset_or_limit_clause_asint( 

4109 self, clause: ColumnElement[Any], attrname: str 

4110 ) -> NoReturn: ... 

4111 

4112 @overload 

4113 def _offset_or_limit_clause_asint( 

4114 self, clause: Optional[_OffsetLimitParam], attrname: str 

4115 ) -> Optional[int]: ... 

4116 

4117 def _offset_or_limit_clause_asint( 

4118 self, clause: Optional[ColumnElement[Any]], attrname: str 

4119 ) -> Union[NoReturn, Optional[int]]: 

4120 """Convert the "offset or limit" clause of a select construct to an 

4121 integer. 

4122 

4123 This is only possible if the value is stored as a simple bound 

4124 parameter. Otherwise, a compilation error is raised. 

4125 

4126 """ 

4127 if clause is None: 

4128 return None 

4129 try: 

4130 value = clause._limit_offset_value 

4131 except AttributeError as err: 

4132 raise exc.CompileError( 

4133 "This SELECT structure does not use a simple " 

4134 "integer value for %s" % attrname 

4135 ) from err 

4136 else: 

4137 return util.asint(value) 

4138 

4139 @property 

4140 def _limit(self) -> Optional[int]: 

4141 """Get an integer value for the limit. This should only be used 

4142 by code that cannot support a limit as a BindParameter or 

4143 other custom clause as it will throw an exception if the limit 

4144 isn't currently set to an integer. 

4145 

4146 """ 

4147 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4148 

4149 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4150 """True if the clause is a simple integer, False 

4151 if it is not present or is a SQL expression. 

4152 """ 

4153 return isinstance(clause, _OffsetLimitParam) 

4154 

4155 @property 

4156 def _offset(self) -> Optional[int]: 

4157 """Get an integer value for the offset. This should only be used 

4158 by code that cannot support an offset as a BindParameter or 

4159 other custom clause as it will throw an exception if the 

4160 offset isn't currently set to an integer. 

4161 

4162 """ 

4163 return self._offset_or_limit_clause_asint( 

4164 self._offset_clause, "offset" 

4165 ) 

4166 

4167 @property 

4168 def _has_row_limiting_clause(self) -> bool: 

4169 return ( 

4170 self._limit_clause is not None 

4171 or self._offset_clause is not None 

4172 or self._fetch_clause is not None 

4173 ) 

4174 

4175 @_generative 

4176 def limit(self, limit: _LimitOffsetType) -> Self: 

4177 """Return a new selectable with the given LIMIT criterion 

4178 applied. 

4179 

4180 This is a numerical value which usually renders as a ``LIMIT`` 

4181 expression in the resulting select. Backends that don't 

4182 support ``LIMIT`` will attempt to provide similar 

4183 functionality. 

4184 

4185 .. note:: 

4186 

4187 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4188 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4189 

4190 :param limit: an integer LIMIT parameter, or a SQL expression 

4191 that provides an integer result. Pass ``None`` to reset it. 

4192 

4193 .. seealso:: 

4194 

4195 :meth:`_sql.GenerativeSelect.fetch` 

4196 

4197 :meth:`_sql.GenerativeSelect.offset` 

4198 

4199 """ 

4200 

4201 self._fetch_clause = self._fetch_clause_options = None 

4202 self._limit_clause = self._offset_or_limit_clause(limit) 

4203 return self 

4204 

4205 @_generative 

4206 def fetch( 

4207 self, 

4208 count: _LimitOffsetType, 

4209 with_ties: bool = False, 

4210 percent: bool = False, 

4211 **dialect_kw: Any, 

4212 ) -> Self: 

4213 r"""Return a new selectable with the given FETCH FIRST criterion 

4214 applied. 

4215 

4216 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4217 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4218 select. This functionality is is currently implemented for Oracle 

4219 Database, PostgreSQL, MSSQL. 

4220 

4221 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4222 

4223 .. note:: 

4224 

4225 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4226 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4227 

4228 .. versionadded:: 1.4 

4229 

4230 :param count: an integer COUNT parameter, or a SQL expression 

4231 that provides an integer result. When ``percent=True`` this will 

4232 represent the percentage of rows to return, not the absolute value. 

4233 Pass ``None`` to reset it. 

4234 

4235 :param with_ties: When ``True``, the WITH TIES option is used 

4236 to return any additional rows that tie for the last place in the 

4237 result set according to the ``ORDER BY`` clause. The 

4238 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4239 

4240 :param percent: When ``True``, ``count`` represents the percentage 

4241 of the total number of selected rows to return. Defaults to ``False`` 

4242 

4243 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4244 may be accepted by dialects. 

4245 

4246 .. versionadded:: 2.0.41 

4247 

4248 .. seealso:: 

4249 

4250 :meth:`_sql.GenerativeSelect.limit` 

4251 

4252 :meth:`_sql.GenerativeSelect.offset` 

4253 

4254 """ 

4255 self._validate_dialect_kwargs(dialect_kw) 

4256 self._limit_clause = None 

4257 if count is None: 

4258 self._fetch_clause = self._fetch_clause_options = None 

4259 else: 

4260 self._fetch_clause = self._offset_or_limit_clause(count) 

4261 self._fetch_clause_options = { 

4262 "with_ties": with_ties, 

4263 "percent": percent, 

4264 } 

4265 return self 

4266 

4267 @_generative 

4268 def offset(self, offset: _LimitOffsetType) -> Self: 

4269 """Return a new selectable with the given OFFSET criterion 

4270 applied. 

4271 

4272 

4273 This is a numeric value which usually renders as an ``OFFSET`` 

4274 expression in the resulting select. Backends that don't 

4275 support ``OFFSET`` will attempt to provide similar 

4276 functionality. 

4277 

4278 :param offset: an integer OFFSET parameter, or a SQL expression 

4279 that provides an integer result. Pass ``None`` to reset it. 

4280 

4281 .. seealso:: 

4282 

4283 :meth:`_sql.GenerativeSelect.limit` 

4284 

4285 :meth:`_sql.GenerativeSelect.fetch` 

4286 

4287 """ 

4288 

4289 self._offset_clause = self._offset_or_limit_clause(offset) 

4290 return self 

4291 

4292 @_generative 

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

4294 def slice( 

4295 self, 

4296 start: int, 

4297 stop: int, 

4298 ) -> Self: 

4299 """Apply LIMIT / OFFSET to this statement based on a slice. 

4300 

4301 The start and stop indices behave like the argument to Python's 

4302 built-in :func:`range` function. This method provides an 

4303 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4304 query. 

4305 

4306 For example, :: 

4307 

4308 stmt = select(User).order_by(User.id).slice(1, 3) 

4309 

4310 renders as 

4311 

4312 .. sourcecode:: sql 

4313 

4314 SELECT users.id AS users_id, 

4315 users.name AS users_name 

4316 FROM users ORDER BY users.id 

4317 LIMIT ? OFFSET ? 

4318 (2, 1) 

4319 

4320 .. note:: 

4321 

4322 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4323 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4324 

4325 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4326 method generalized from the ORM. 

4327 

4328 .. seealso:: 

4329 

4330 :meth:`_sql.GenerativeSelect.limit` 

4331 

4332 :meth:`_sql.GenerativeSelect.offset` 

4333 

4334 :meth:`_sql.GenerativeSelect.fetch` 

4335 

4336 """ 

4337 sql_util = util.preloaded.sql_util 

4338 self._fetch_clause = self._fetch_clause_options = None 

4339 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4340 self._limit_clause, self._offset_clause, start, stop 

4341 ) 

4342 return self 

4343 

4344 @_generative 

4345 def order_by( 

4346 self, 

4347 __first: Union[ 

4348 Literal[None, _NoArg.NO_ARG], 

4349 _ColumnExpressionOrStrLabelArgument[Any], 

4350 ] = _NoArg.NO_ARG, 

4351 /, 

4352 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4353 ) -> Self: 

4354 r"""Return a new selectable with the given list of ORDER BY 

4355 criteria applied. 

4356 

4357 e.g.:: 

4358 

4359 stmt = select(table).order_by(table.c.id, table.c.name) 

4360 

4361 Calling this method multiple times is equivalent to calling it once 

4362 with all the clauses concatenated. All existing ORDER BY criteria may 

4363 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4364 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4365 

4366 # will erase all ORDER BY and ORDER BY new_col alone 

4367 stmt = stmt.order_by(None).order_by(new_col) 

4368 

4369 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4370 constructs 

4371 which will be used to generate an ORDER BY clause. 

4372 

4373 .. seealso:: 

4374 

4375 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4376 

4377 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4378 

4379 """ 

4380 

4381 if not clauses and __first is None: 

4382 self._order_by_clauses = () 

4383 elif __first is not _NoArg.NO_ARG: 

4384 self._order_by_clauses += tuple( 

4385 coercions.expect( 

4386 roles.OrderByRole, clause, apply_propagate_attrs=self 

4387 ) 

4388 for clause in (__first,) + clauses 

4389 ) 

4390 return self 

4391 

4392 @_generative 

4393 def group_by( 

4394 self, 

4395 __first: Union[ 

4396 Literal[None, _NoArg.NO_ARG], 

4397 _ColumnExpressionOrStrLabelArgument[Any], 

4398 ] = _NoArg.NO_ARG, 

4399 /, 

4400 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4401 ) -> Self: 

4402 r"""Return a new selectable with the given list of GROUP BY 

4403 criterion applied. 

4404 

4405 All existing GROUP BY settings can be suppressed by passing ``None``. 

4406 

4407 e.g.:: 

4408 

4409 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4410 

4411 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4412 constructs 

4413 which will be used to generate an GROUP BY clause. 

4414 

4415 .. seealso:: 

4416 

4417 :ref:`tutorial_group_by_w_aggregates` - in the 

4418 :ref:`unified_tutorial` 

4419 

4420 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4421 

4422 """ # noqa: E501 

4423 

4424 if not clauses and __first is None: 

4425 self._group_by_clauses = () 

4426 elif __first is not _NoArg.NO_ARG: 

4427 self._group_by_clauses += tuple( 

4428 coercions.expect( 

4429 roles.GroupByRole, clause, apply_propagate_attrs=self 

4430 ) 

4431 for clause in (__first,) + clauses 

4432 ) 

4433 return self 

4434 

4435 

4436@CompileState.plugin_for("default", "compound_select") 

4437class CompoundSelectState(CompileState): 

4438 @util.memoized_property 

4439 def _label_resolve_dict( 

4440 self, 

4441 ) -> Tuple[ 

4442 Dict[str, ColumnElement[Any]], 

4443 Dict[str, ColumnElement[Any]], 

4444 Dict[str, ColumnElement[Any]], 

4445 ]: 

4446 # TODO: this is hacky and slow 

4447 hacky_subquery = self.statement.subquery() 

4448 hacky_subquery.named_with_column = False 

4449 d = {c.key: c for c in hacky_subquery.c} 

4450 return d, d, d 

4451 

4452 

4453class _CompoundSelectKeyword(Enum): 

4454 UNION = "UNION" 

4455 UNION_ALL = "UNION ALL" 

4456 EXCEPT = "EXCEPT" 

4457 EXCEPT_ALL = "EXCEPT ALL" 

4458 INTERSECT = "INTERSECT" 

4459 INTERSECT_ALL = "INTERSECT ALL" 

4460 

4461 

4462class CompoundSelect( 

4463 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4464): 

4465 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4466 SELECT-based set operations. 

4467 

4468 

4469 .. seealso:: 

4470 

4471 :func:`_expression.union` 

4472 

4473 :func:`_expression.union_all` 

4474 

4475 :func:`_expression.intersect` 

4476 

4477 :func:`_expression.intersect_all` 

4478 

4479 :func:`_expression.except` 

4480 

4481 :func:`_expression.except_all` 

4482 

4483 """ 

4484 

4485 __visit_name__ = "compound_select" 

4486 

4487 _traverse_internals: _TraverseInternalsType = ( 

4488 [ 

4489 ("selects", InternalTraversal.dp_clauseelement_list), 

4490 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4491 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4492 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4493 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4494 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4495 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4496 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4497 ("keyword", InternalTraversal.dp_string), 

4498 ] 

4499 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4500 + HasCTE._has_ctes_traverse_internals 

4501 + DialectKWArgs._dialect_kwargs_traverse_internals 

4502 ) 

4503 

4504 selects: List[SelectBase] 

4505 

4506 _is_from_container = True 

4507 _auto_correlate = False 

4508 

4509 def __init__( 

4510 self, 

4511 keyword: _CompoundSelectKeyword, 

4512 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4513 ): 

4514 self.keyword = keyword 

4515 self.selects = [ 

4516 coercions.expect( 

4517 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4518 ).self_group(against=self) 

4519 for s in selects 

4520 ] 

4521 

4522 GenerativeSelect.__init__(self) 

4523 

4524 @classmethod 

4525 def _create_union( 

4526 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4527 ) -> CompoundSelect[Unpack[_Ts]]: 

4528 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4529 

4530 @classmethod 

4531 def _create_union_all( 

4532 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4533 ) -> CompoundSelect[Unpack[_Ts]]: 

4534 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4535 

4536 @classmethod 

4537 def _create_except( 

4538 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4539 ) -> CompoundSelect[Unpack[_Ts]]: 

4540 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4541 

4542 @classmethod 

4543 def _create_except_all( 

4544 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4545 ) -> CompoundSelect[Unpack[_Ts]]: 

4546 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4547 

4548 @classmethod 

4549 def _create_intersect( 

4550 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4551 ) -> CompoundSelect[Unpack[_Ts]]: 

4552 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4553 

4554 @classmethod 

4555 def _create_intersect_all( 

4556 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4557 ) -> CompoundSelect[Unpack[_Ts]]: 

4558 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4559 

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

4561 return self.selects[0]._scalar_type() 

4562 

4563 def self_group( 

4564 self, against: Optional[OperatorType] = None 

4565 ) -> GroupedElement: 

4566 return SelectStatementGrouping(self) 

4567 

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

4569 for s in self.selects: 

4570 if s.is_derived_from(fromclause): 

4571 return True 

4572 return False 

4573 

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

4575 if self._label_style is not style: 

4576 self = self._generate() 

4577 select_0 = self.selects[0].set_label_style(style) 

4578 self.selects = [select_0] + self.selects[1:] 

4579 

4580 return self 

4581 

4582 def _ensure_disambiguated_names(self) -> Self: 

4583 new_select = self.selects[0]._ensure_disambiguated_names() 

4584 if new_select is not self.selects[0]: 

4585 self = self._generate() 

4586 self.selects = [new_select] + self.selects[1:] 

4587 

4588 return self 

4589 

4590 def _generate_fromclause_column_proxies( 

4591 self, 

4592 subquery: FromClause, 

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

4594 primary_key: ColumnSet, 

4595 foreign_keys: Set[KeyedColumnElement[Any]], 

4596 *, 

4597 proxy_compound_columns: Optional[ 

4598 Iterable[Sequence[ColumnElement[Any]]] 

4599 ] = None, 

4600 ) -> None: 

4601 # this is a slightly hacky thing - the union exports a 

4602 # column that resembles just that of the *first* selectable. 

4603 # to get at a "composite" column, particularly foreign keys, 

4604 # you have to dig through the proxies collection which we 

4605 # generate below. 

4606 select_0 = self.selects[0] 

4607 

4608 if self._label_style is not LABEL_STYLE_DEFAULT: 

4609 select_0 = select_0.set_label_style(self._label_style) 

4610 

4611 # hand-construct the "_proxies" collection to include all 

4612 # derived columns place a 'weight' annotation corresponding 

4613 # to how low in the list of select()s the column occurs, so 

4614 # that the corresponding_column() operation can resolve 

4615 # conflicts 

4616 extra_col_iterator = zip( 

4617 *[ 

4618 [ 

4619 c._annotate(dd) 

4620 for c in stmt._all_selected_columns 

4621 if is_column_element(c) 

4622 ] 

4623 for dd, stmt in [ 

4624 ({"weight": i + 1}, stmt) 

4625 for i, stmt in enumerate(self.selects) 

4626 ] 

4627 ] 

4628 ) 

4629 

4630 # the incoming proxy_compound_columns can be present also if this is 

4631 # a compound embedded in a compound. it's probably more appropriate 

4632 # that we generate new weights local to this nested compound, though 

4633 # i haven't tried to think what it means for compound nested in 

4634 # compound 

4635 select_0._generate_fromclause_column_proxies( 

4636 subquery, 

4637 columns, 

4638 proxy_compound_columns=extra_col_iterator, 

4639 primary_key=primary_key, 

4640 foreign_keys=foreign_keys, 

4641 ) 

4642 

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

4644 super()._refresh_for_new_column(column) 

4645 for select in self.selects: 

4646 select._refresh_for_new_column(column) 

4647 

4648 @util.ro_non_memoized_property 

4649 def _all_selected_columns(self) -> _SelectIterable: 

4650 return self.selects[0]._all_selected_columns 

4651 

4652 @util.ro_non_memoized_property 

4653 def selected_columns( 

4654 self, 

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

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

4657 representing the columns that 

4658 this SELECT statement or similar construct returns in its result set, 

4659 not including :class:`_sql.TextClause` constructs. 

4660 

4661 For a :class:`_expression.CompoundSelect`, the 

4662 :attr:`_expression.CompoundSelect.selected_columns` 

4663 attribute returns the selected 

4664 columns of the first SELECT statement contained within the series of 

4665 statements within the set operation. 

4666 

4667 .. seealso:: 

4668 

4669 :attr:`_sql.Select.selected_columns` 

4670 

4671 .. versionadded:: 1.4 

4672 

4673 """ 

4674 return self.selects[0].selected_columns 

4675 

4676 

4677# backwards compat 

4678for elem in _CompoundSelectKeyword: 

4679 setattr(CompoundSelect, elem.name, elem) 

4680 

4681 

4682@CompileState.plugin_for("default", "select") 

4683class SelectState(util.MemoizedSlots, CompileState): 

4684 __slots__ = ( 

4685 "from_clauses", 

4686 "froms", 

4687 "columns_plus_names", 

4688 "_label_resolve_dict", 

4689 ) 

4690 

4691 if TYPE_CHECKING: 

4692 default_select_compile_options: CacheableOptions 

4693 else: 

4694 

4695 class default_select_compile_options(CacheableOptions): 

4696 _cache_key_traversal = [] 

4697 

4698 if TYPE_CHECKING: 

4699 

4700 @classmethod 

4701 def get_plugin_class( 

4702 cls, statement: Executable 

4703 ) -> Type[SelectState]: ... 

4704 

4705 def __init__( 

4706 self, 

4707 statement: Select[Unpack[TupleAny]], 

4708 compiler: SQLCompiler, 

4709 **kw: Any, 

4710 ): 

4711 self.statement = statement 

4712 self.from_clauses = statement._from_obj 

4713 

4714 for memoized_entities in statement._memoized_select_entities: 

4715 self._setup_joins( 

4716 memoized_entities._setup_joins, memoized_entities._raw_columns 

4717 ) 

4718 

4719 if statement._setup_joins: 

4720 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4721 

4722 self.froms = self._get_froms(statement) 

4723 

4724 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4725 

4726 @classmethod 

4727 def _plugin_not_implemented(cls) -> NoReturn: 

4728 raise NotImplementedError( 

4729 "The default SELECT construct without plugins does not " 

4730 "implement this method." 

4731 ) 

4732 

4733 @classmethod 

4734 def get_column_descriptions( 

4735 cls, statement: Select[Unpack[TupleAny]] 

4736 ) -> List[Dict[str, Any]]: 

4737 return [ 

4738 { 

4739 "name": name, 

4740 "type": element.type, 

4741 "expr": element, 

4742 } 

4743 for _, name, _, element, _ in ( 

4744 statement._generate_columns_plus_names(False) 

4745 ) 

4746 ] 

4747 

4748 @classmethod 

4749 def from_statement( 

4750 cls, 

4751 statement: Select[Unpack[TupleAny]], 

4752 from_statement: roles.ReturnsRowsRole, 

4753 ) -> ExecutableReturnsRows: 

4754 cls._plugin_not_implemented() 

4755 

4756 @classmethod 

4757 def get_columns_clause_froms( 

4758 cls, statement: Select[Unpack[TupleAny]] 

4759 ) -> List[FromClause]: 

4760 return cls._normalize_froms( 

4761 itertools.chain.from_iterable( 

4762 element._from_objects for element in statement._raw_columns 

4763 ) 

4764 ) 

4765 

4766 @classmethod 

4767 def _column_naming_convention( 

4768 cls, label_style: SelectLabelStyle 

4769 ) -> _LabelConventionCallable: 

4770 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4771 

4772 dedupe = label_style is not LABEL_STYLE_NONE 

4773 

4774 pa = prefix_anon_map() 

4775 names = set() 

4776 

4777 def go( 

4778 c: Union[ColumnElement[Any], TextClause], 

4779 col_name: Optional[str] = None, 

4780 ) -> Optional[str]: 

4781 if is_text_clause(c): 

4782 return None 

4783 elif TYPE_CHECKING: 

4784 assert is_column_element(c) 

4785 

4786 if not dedupe: 

4787 name = c._proxy_key 

4788 if name is None: 

4789 name = "_no_label" 

4790 return name 

4791 

4792 name = c._tq_key_label if table_qualified else c._proxy_key 

4793 

4794 if name is None: 

4795 name = "_no_label" 

4796 if name in names: 

4797 return c._anon_label(name) % pa 

4798 else: 

4799 names.add(name) 

4800 return name 

4801 

4802 elif name in names: 

4803 return ( 

4804 c._anon_tq_key_label % pa 

4805 if table_qualified 

4806 else c._anon_key_label % pa 

4807 ) 

4808 else: 

4809 names.add(name) 

4810 return name 

4811 

4812 return go 

4813 

4814 def _get_froms( 

4815 self, statement: Select[Unpack[TupleAny]] 

4816 ) -> List[FromClause]: 

4817 ambiguous_table_name_map: _AmbiguousTableNameMap 

4818 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4819 

4820 return self._normalize_froms( 

4821 itertools.chain( 

4822 self.from_clauses, 

4823 itertools.chain.from_iterable( 

4824 [ 

4825 element._from_objects 

4826 for element in statement._raw_columns 

4827 ] 

4828 ), 

4829 itertools.chain.from_iterable( 

4830 [ 

4831 element._from_objects 

4832 for element in statement._where_criteria 

4833 ] 

4834 ), 

4835 ), 

4836 check_statement=statement, 

4837 ambiguous_table_name_map=ambiguous_table_name_map, 

4838 ) 

4839 

4840 @classmethod 

4841 def _normalize_froms( 

4842 cls, 

4843 iterable_of_froms: Iterable[FromClause], 

4844 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4845 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4846 ) -> List[FromClause]: 

4847 """given an iterable of things to select FROM, reduce them to what 

4848 would actually render in the FROM clause of a SELECT. 

4849 

4850 This does the job of checking for JOINs, tables, etc. that are in fact 

4851 overlapping due to cloning, adaption, present in overlapping joins, 

4852 etc. 

4853 

4854 """ 

4855 seen: Set[FromClause] = set() 

4856 froms: List[FromClause] = [] 

4857 

4858 for item in iterable_of_froms: 

4859 if is_subquery(item) and item.element is check_statement: 

4860 raise exc.InvalidRequestError( 

4861 "select() construct refers to itself as a FROM" 

4862 ) 

4863 

4864 if not seen.intersection(item._cloned_set): 

4865 froms.append(item) 

4866 seen.update(item._cloned_set) 

4867 

4868 if froms: 

4869 toremove = set( 

4870 itertools.chain.from_iterable( 

4871 [_expand_cloned(f._hide_froms) for f in froms] 

4872 ) 

4873 ) 

4874 if toremove: 

4875 # filter out to FROM clauses not in the list, 

4876 # using a list to maintain ordering 

4877 froms = [f for f in froms if f not in toremove] 

4878 

4879 if ambiguous_table_name_map is not None: 

4880 ambiguous_table_name_map.update( 

4881 ( 

4882 fr.name, 

4883 _anonymous_label.safe_construct( 

4884 hash(fr.name), fr.name 

4885 ), 

4886 ) 

4887 for item in froms 

4888 for fr in item._from_objects 

4889 if is_table(fr) 

4890 and fr.schema 

4891 and fr.name not in ambiguous_table_name_map 

4892 ) 

4893 

4894 return froms 

4895 

4896 def _get_display_froms( 

4897 self, 

4898 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4899 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4900 ) -> List[FromClause]: 

4901 """Return the full list of 'from' clauses to be displayed. 

4902 

4903 Takes into account a set of existing froms which may be 

4904 rendered in the FROM clause of enclosing selects; this Select 

4905 may want to leave those absent if it is automatically 

4906 correlating. 

4907 

4908 """ 

4909 

4910 froms = self.froms 

4911 

4912 if self.statement._correlate: 

4913 to_correlate = self.statement._correlate 

4914 if to_correlate: 

4915 froms = [ 

4916 f 

4917 for f in froms 

4918 if f 

4919 not in _cloned_intersection( 

4920 _cloned_intersection( 

4921 froms, explicit_correlate_froms or () 

4922 ), 

4923 to_correlate, 

4924 ) 

4925 ] 

4926 

4927 if self.statement._correlate_except is not None: 

4928 froms = [ 

4929 f 

4930 for f in froms 

4931 if f 

4932 not in _cloned_difference( 

4933 _cloned_intersection( 

4934 froms, explicit_correlate_froms or () 

4935 ), 

4936 self.statement._correlate_except, 

4937 ) 

4938 ] 

4939 

4940 if ( 

4941 self.statement._auto_correlate 

4942 and implicit_correlate_froms 

4943 and len(froms) > 1 

4944 ): 

4945 froms = [ 

4946 f 

4947 for f in froms 

4948 if f 

4949 not in _cloned_intersection(froms, implicit_correlate_froms) 

4950 ] 

4951 

4952 if not len(froms): 

4953 raise exc.InvalidRequestError( 

4954 "Select statement '%r" 

4955 "' returned no FROM clauses " 

4956 "due to auto-correlation; " 

4957 "specify correlate(<tables>) " 

4958 "to control correlation " 

4959 "manually." % self.statement 

4960 ) 

4961 

4962 return froms 

4963 

4964 def _memoized_attr__label_resolve_dict( 

4965 self, 

4966 ) -> Tuple[ 

4967 Dict[str, ColumnElement[Any]], 

4968 Dict[str, ColumnElement[Any]], 

4969 Dict[str, ColumnElement[Any]], 

4970 ]: 

4971 with_cols: Dict[str, ColumnElement[Any]] = { 

4972 c._tq_label or c.key: c 

4973 for c in self.statement._all_selected_columns 

4974 if c._allow_label_resolve 

4975 } 

4976 only_froms: Dict[str, ColumnElement[Any]] = { 

4977 c.key: c # type: ignore 

4978 for c in _select_iterables(self.froms) 

4979 if c._allow_label_resolve 

4980 } 

4981 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

4982 for key, value in only_froms.items(): 

4983 with_cols.setdefault(key, value) 

4984 

4985 return with_cols, only_froms, only_cols 

4986 

4987 @classmethod 

4988 def determine_last_joined_entity( 

4989 cls, stmt: Select[Unpack[TupleAny]] 

4990 ) -> Optional[_JoinTargetElement]: 

4991 if stmt._setup_joins: 

4992 return stmt._setup_joins[-1][0] 

4993 else: 

4994 return None 

4995 

4996 @classmethod 

4997 def all_selected_columns( 

4998 cls, statement: Select[Unpack[TupleAny]] 

4999 ) -> _SelectIterable: 

5000 return [c for c in _select_iterables(statement._raw_columns)] 

5001 

5002 def _setup_joins( 

5003 self, 

5004 args: Tuple[_SetupJoinsElement, ...], 

5005 raw_columns: List[_ColumnsClauseElement], 

5006 ) -> None: 

5007 for right, onclause, left, flags in args: 

5008 if TYPE_CHECKING: 

5009 if onclause is not None: 

5010 assert isinstance(onclause, ColumnElement) 

5011 

5012 isouter = flags["isouter"] 

5013 full = flags["full"] 

5014 

5015 if left is None: 

5016 ( 

5017 left, 

5018 replace_from_obj_index, 

5019 ) = self._join_determine_implicit_left_side( 

5020 raw_columns, left, right, onclause 

5021 ) 

5022 else: 

5023 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5024 left 

5025 ) 

5026 

5027 # these assertions can be made here, as if the right/onclause 

5028 # contained ORM elements, the select() statement would have been 

5029 # upgraded to an ORM select, and this method would not be called; 

5030 # orm.context.ORMSelectCompileState._join() would be 

5031 # used instead. 

5032 if TYPE_CHECKING: 

5033 assert isinstance(right, FromClause) 

5034 if onclause is not None: 

5035 assert isinstance(onclause, ColumnElement) 

5036 

5037 if replace_from_obj_index is not None: 

5038 # splice into an existing element in the 

5039 # self._from_obj list 

5040 left_clause = self.from_clauses[replace_from_obj_index] 

5041 

5042 self.from_clauses = ( 

5043 self.from_clauses[:replace_from_obj_index] 

5044 + ( 

5045 Join( 

5046 left_clause, 

5047 right, 

5048 onclause, 

5049 isouter=isouter, 

5050 full=full, 

5051 ), 

5052 ) 

5053 + self.from_clauses[replace_from_obj_index + 1 :] 

5054 ) 

5055 else: 

5056 assert left is not None 

5057 self.from_clauses = self.from_clauses + ( 

5058 Join(left, right, onclause, isouter=isouter, full=full), 

5059 ) 

5060 

5061 @util.preload_module("sqlalchemy.sql.util") 

5062 def _join_determine_implicit_left_side( 

5063 self, 

5064 raw_columns: List[_ColumnsClauseElement], 

5065 left: Optional[FromClause], 

5066 right: _JoinTargetElement, 

5067 onclause: Optional[ColumnElement[Any]], 

5068 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5069 """When join conditions don't express the left side explicitly, 

5070 determine if an existing FROM or entity in this query 

5071 can serve as the left hand side. 

5072 

5073 """ 

5074 

5075 sql_util = util.preloaded.sql_util 

5076 

5077 replace_from_obj_index: Optional[int] = None 

5078 

5079 from_clauses = self.from_clauses 

5080 

5081 if from_clauses: 

5082 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5083 from_clauses, right, onclause 

5084 ) 

5085 

5086 if len(indexes) == 1: 

5087 replace_from_obj_index = indexes[0] 

5088 left = from_clauses[replace_from_obj_index] 

5089 else: 

5090 potential = {} 

5091 statement = self.statement 

5092 

5093 for from_clause in itertools.chain( 

5094 itertools.chain.from_iterable( 

5095 [element._from_objects for element in raw_columns] 

5096 ), 

5097 itertools.chain.from_iterable( 

5098 [ 

5099 element._from_objects 

5100 for element in statement._where_criteria 

5101 ] 

5102 ), 

5103 ): 

5104 potential[from_clause] = () 

5105 

5106 all_clauses = list(potential.keys()) 

5107 indexes = sql_util.find_left_clause_to_join_from( 

5108 all_clauses, right, onclause 

5109 ) 

5110 

5111 if len(indexes) == 1: 

5112 left = all_clauses[indexes[0]] 

5113 

5114 if len(indexes) > 1: 

5115 raise exc.InvalidRequestError( 

5116 "Can't determine which FROM clause to join " 

5117 "from, there are multiple FROMS which can " 

5118 "join to this entity. Please use the .select_from() " 

5119 "method to establish an explicit left side, as well as " 

5120 "providing an explicit ON clause if not present already to " 

5121 "help resolve the ambiguity." 

5122 ) 

5123 elif not indexes: 

5124 raise exc.InvalidRequestError( 

5125 "Don't know how to join to %r. " 

5126 "Please use the .select_from() " 

5127 "method to establish an explicit left side, as well as " 

5128 "providing an explicit ON clause if not present already to " 

5129 "help resolve the ambiguity." % (right,) 

5130 ) 

5131 return left, replace_from_obj_index 

5132 

5133 @util.preload_module("sqlalchemy.sql.util") 

5134 def _join_place_explicit_left_side( 

5135 self, left: FromClause 

5136 ) -> Optional[int]: 

5137 replace_from_obj_index: Optional[int] = None 

5138 

5139 sql_util = util.preloaded.sql_util 

5140 

5141 from_clauses = list(self.statement._iterate_from_elements()) 

5142 

5143 if from_clauses: 

5144 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5145 self.from_clauses, left 

5146 ) 

5147 else: 

5148 indexes = [] 

5149 

5150 if len(indexes) > 1: 

5151 raise exc.InvalidRequestError( 

5152 "Can't identify which entity in which to assign the " 

5153 "left side of this join. Please use a more specific " 

5154 "ON clause." 

5155 ) 

5156 

5157 # have an index, means the left side is already present in 

5158 # an existing FROM in the self._from_obj tuple 

5159 if indexes: 

5160 replace_from_obj_index = indexes[0] 

5161 

5162 # no index, means we need to add a new element to the 

5163 # self._from_obj tuple 

5164 

5165 return replace_from_obj_index 

5166 

5167 

5168class _SelectFromElements: 

5169 __slots__ = () 

5170 

5171 _raw_columns: List[_ColumnsClauseElement] 

5172 _where_criteria: Tuple[ColumnElement[Any], ...] 

5173 _from_obj: Tuple[FromClause, ...] 

5174 

5175 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5176 # note this does not include elements 

5177 # in _setup_joins 

5178 

5179 seen = set() 

5180 for element in self._raw_columns: 

5181 for fr in element._from_objects: 

5182 if fr in seen: 

5183 continue 

5184 seen.add(fr) 

5185 yield fr 

5186 for element in self._where_criteria: 

5187 for fr in element._from_objects: 

5188 if fr in seen: 

5189 continue 

5190 seen.add(fr) 

5191 yield fr 

5192 for element in self._from_obj: 

5193 if element in seen: 

5194 continue 

5195 seen.add(element) 

5196 yield element 

5197 

5198 

5199class _MemoizedSelectEntities( 

5200 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5201): 

5202 """represents partial state from a Select object, for the case 

5203 where Select.columns() has redefined the set of columns/entities the 

5204 statement will be SELECTing from. This object represents 

5205 the entities from the SELECT before that transformation was applied, 

5206 so that transformations that were made in terms of the SELECT at that 

5207 time, such as join() as well as options(), can access the correct context. 

5208 

5209 In previous SQLAlchemy versions, this wasn't needed because these 

5210 constructs calculated everything up front, like when you called join() 

5211 or options(), it did everything to figure out how that would translate 

5212 into specific SQL constructs that would be ready to send directly to the 

5213 SQL compiler when needed. But as of 

5214 1.4, all of that stuff is done in the compilation phase, during the 

5215 "compile state" portion of the process, so that the work can all be 

5216 cached. So it needs to be able to resolve joins/options2 based on what 

5217 the list of entities was when those methods were called. 

5218 

5219 

5220 """ 

5221 

5222 __visit_name__ = "memoized_select_entities" 

5223 

5224 _traverse_internals: _TraverseInternalsType = [ 

5225 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5226 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5227 ("_with_options", InternalTraversal.dp_executable_options), 

5228 ] 

5229 

5230 _is_clone_of: Optional[ClauseElement] 

5231 _raw_columns: List[_ColumnsClauseElement] 

5232 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5233 _with_options: Tuple[ExecutableOption, ...] 

5234 

5235 _annotations = util.EMPTY_DICT 

5236 

5237 def _clone(self, **kw: Any) -> Self: 

5238 c = self.__class__.__new__(self.__class__) 

5239 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5240 

5241 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5242 return c 

5243 

5244 @classmethod 

5245 def _generate_for_statement( 

5246 cls, select_stmt: Select[Unpack[TupleAny]] 

5247 ) -> None: 

5248 if select_stmt._setup_joins or select_stmt._with_options: 

5249 self = _MemoizedSelectEntities() 

5250 self._raw_columns = select_stmt._raw_columns 

5251 self._setup_joins = select_stmt._setup_joins 

5252 self._with_options = select_stmt._with_options 

5253 

5254 select_stmt._memoized_select_entities += (self,) 

5255 select_stmt._raw_columns = [] 

5256 select_stmt._setup_joins = select_stmt._with_options = () 

5257 

5258 

5259class Select( 

5260 HasPrefixes, 

5261 HasSuffixes, 

5262 HasHints, 

5263 HasCompileState, 

5264 HasSyntaxExtensions[ 

5265 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5266 ], 

5267 _SelectFromElements, 

5268 GenerativeSelect, 

5269 TypedReturnsRows[Unpack[_Ts]], 

5270): 

5271 """Represents a ``SELECT`` statement. 

5272 

5273 The :class:`_sql.Select` object is normally constructed using the 

5274 :func:`_sql.select` function. See that function for details. 

5275 

5276 Available extension points: 

5277 

5278 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5279 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5280 keyword (if any) and the list of columns. 

5281 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5282 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5283 

5284 .. seealso:: 

5285 

5286 :func:`_sql.select` 

5287 

5288 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5289 

5290 """ 

5291 

5292 __visit_name__ = "select" 

5293 

5294 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5295 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5296 

5297 _raw_columns: List[_ColumnsClauseElement] 

5298 

5299 _distinct: bool = False 

5300 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5301 _correlate: Tuple[FromClause, ...] = () 

5302 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5303 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5304 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5305 _from_obj: Tuple[FromClause, ...] = () 

5306 

5307 _position_map = util.immutabledict( 

5308 { 

5309 "post_select": "_post_select_clause", 

5310 "pre_columns": "_pre_columns_clause", 

5311 "post_criteria": "_post_criteria_clause", 

5312 "post_body": "_post_body_clause", 

5313 } 

5314 ) 

5315 

5316 _post_select_clause: Optional[ClauseElement] = None 

5317 """extension point for a ClauseElement that will be compiled directly 

5318 after the SELECT keyword. 

5319 

5320 .. versionadded:: 2.1 

5321 

5322 """ 

5323 

5324 _pre_columns_clause: Optional[ClauseElement] = None 

5325 """extension point for a ClauseElement that will be compiled directly 

5326 before the "columns" clause; after DISTINCT (if present). 

5327 

5328 .. versionadded:: 2.1 

5329 

5330 """ 

5331 

5332 _post_criteria_clause: Optional[ClauseElement] = None 

5333 """extension point for a ClauseElement that will be compiled directly 

5334 after "criteria", following the HAVING clause but before ORDER BY. 

5335 

5336 .. versionadded:: 2.1 

5337 

5338 """ 

5339 

5340 _post_body_clause: Optional[ClauseElement] = None 

5341 """extension point for a ClauseElement that will be compiled directly 

5342 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5343 of the SELECT. 

5344 

5345 .. versionadded:: 2.1 

5346 

5347 """ 

5348 

5349 _auto_correlate = True 

5350 _is_select_statement = True 

5351 _compile_options: CacheableOptions = ( 

5352 SelectState.default_select_compile_options 

5353 ) 

5354 

5355 _traverse_internals: _TraverseInternalsType = ( 

5356 [ 

5357 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5358 ( 

5359 "_memoized_select_entities", 

5360 InternalTraversal.dp_memoized_select_entities, 

5361 ), 

5362 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5363 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5364 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5365 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5366 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5367 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5368 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5369 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5370 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5371 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5372 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5373 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5374 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5375 ("_distinct", InternalTraversal.dp_boolean), 

5376 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5377 ("_label_style", InternalTraversal.dp_plain_obj), 

5378 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5379 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5380 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5381 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5382 ] 

5383 + HasCTE._has_ctes_traverse_internals 

5384 + HasPrefixes._has_prefixes_traverse_internals 

5385 + HasSuffixes._has_suffixes_traverse_internals 

5386 + HasHints._has_hints_traverse_internals 

5387 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5388 + Executable._executable_traverse_internals 

5389 + DialectKWArgs._dialect_kwargs_traverse_internals 

5390 ) 

5391 

5392 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5393 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5394 ] 

5395 

5396 _compile_state_factory: Type[SelectState] 

5397 

5398 @classmethod 

5399 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5400 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5401 

5402 Used internally to build up :class:`.Select` constructs with 

5403 pre-established state. 

5404 

5405 """ 

5406 

5407 stmt = Select.__new__(Select) 

5408 stmt.__dict__.update(kw) 

5409 return stmt 

5410 

5411 def __init__( 

5412 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5413 ): 

5414 r"""Construct a new :class:`_expression.Select`. 

5415 

5416 The public constructor for :class:`_expression.Select` is the 

5417 :func:`_sql.select` function. 

5418 

5419 """ 

5420 self._raw_columns = [ 

5421 coercions.expect( 

5422 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5423 ) 

5424 for ent in entities 

5425 ] 

5426 GenerativeSelect.__init__(self) 

5427 

5428 def _apply_syntax_extension_to_self( 

5429 self, extension: SyntaxExtension 

5430 ) -> None: 

5431 extension.apply_to_select(self) 

5432 

5433 def _scalar_type(self) -> TypeEngine[Any]: 

5434 if not self._raw_columns: 

5435 return NULLTYPE 

5436 elem = self._raw_columns[0] 

5437 cols = list(elem._select_iterable) 

5438 return cols[0].type 

5439 

5440 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5441 """A synonym for the :meth:`_sql.Select.where` method.""" 

5442 

5443 return self.where(*criteria) 

5444 

5445 def _filter_by_zero( 

5446 self, 

5447 ) -> Union[ 

5448 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5449 ]: 

5450 if self._setup_joins: 

5451 meth = SelectState.get_plugin_class( 

5452 self 

5453 ).determine_last_joined_entity 

5454 _last_joined_entity = meth(self) 

5455 if _last_joined_entity is not None: 

5456 return _last_joined_entity 

5457 

5458 if self._from_obj: 

5459 return self._from_obj[0] 

5460 

5461 return self._raw_columns[0] 

5462 

5463 if TYPE_CHECKING: 

5464 

5465 @overload 

5466 def scalar_subquery( 

5467 self: Select[_MAYBE_ENTITY], 

5468 ) -> ScalarSelect[Any]: ... 

5469 

5470 @overload 

5471 def scalar_subquery( 

5472 self: Select[_NOT_ENTITY], 

5473 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5474 

5475 @overload 

5476 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5477 

5478 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5479 

5480 def filter_by(self, **kwargs: Any) -> Self: 

5481 r"""apply the given filtering criterion as a WHERE clause 

5482 to this select. 

5483 

5484 """ 

5485 from_entity = self._filter_by_zero() 

5486 

5487 clauses = [ 

5488 _entity_namespace_key(from_entity, key) == value 

5489 for key, value in kwargs.items() 

5490 ] 

5491 return self.filter(*clauses) 

5492 

5493 @property 

5494 def column_descriptions(self) -> Any: 

5495 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5496 referring to the columns which are SELECTed by this statement. 

5497 

5498 This attribute is generally useful when using the ORM, as an 

5499 extended structure which includes information about mapped 

5500 entities is returned. The section :ref:`queryguide_inspection` 

5501 contains more background. 

5502 

5503 For a Core-only statement, the structure returned by this accessor 

5504 is derived from the same objects that are returned by the 

5505 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5506 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5507 which indicate the column expressions to be selected:: 

5508 

5509 >>> stmt = select(user_table) 

5510 >>> stmt.column_descriptions 

5511 [ 

5512 { 

5513 'name': 'id', 

5514 'type': Integer(), 

5515 'expr': Column('id', Integer(), ...)}, 

5516 { 

5517 'name': 'name', 

5518 'type': String(length=30), 

5519 'expr': Column('name', String(length=30), ...)} 

5520 ] 

5521 

5522 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5523 attribute returns a structure for a Core-only set of entities, 

5524 not just ORM-only entities. 

5525 

5526 .. seealso:: 

5527 

5528 :attr:`.UpdateBase.entity_description` - entity information for 

5529 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5530 

5531 :ref:`queryguide_inspection` - ORM background 

5532 

5533 """ 

5534 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5535 return meth(self) 

5536 

5537 def from_statement( 

5538 self, statement: roles.ReturnsRowsRole 

5539 ) -> ExecutableReturnsRows: 

5540 """Apply the columns which this :class:`.Select` would select 

5541 onto another statement. 

5542 

5543 This operation is :term:`plugin-specific` and will raise a not 

5544 supported exception if this :class:`_sql.Select` does not select from 

5545 plugin-enabled entities. 

5546 

5547 

5548 The statement is typically either a :func:`_expression.text` or 

5549 :func:`_expression.select` construct, and should return the set of 

5550 columns appropriate to the entities represented by this 

5551 :class:`.Select`. 

5552 

5553 .. seealso:: 

5554 

5555 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5556 ORM Querying Guide 

5557 

5558 """ 

5559 meth = SelectState.get_plugin_class(self).from_statement 

5560 return meth(self, statement) 

5561 

5562 @_generative 

5563 def join( 

5564 self, 

5565 target: _JoinTargetArgument, 

5566 onclause: Optional[_OnClauseArgument] = None, 

5567 *, 

5568 isouter: bool = False, 

5569 full: bool = False, 

5570 ) -> Self: 

5571 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5572 object's criterion 

5573 and apply generatively, returning the newly resulting 

5574 :class:`_expression.Select`. 

5575 

5576 E.g.:: 

5577 

5578 stmt = select(user_table).join( 

5579 address_table, user_table.c.id == address_table.c.user_id 

5580 ) 

5581 

5582 The above statement generates SQL similar to: 

5583 

5584 .. sourcecode:: sql 

5585 

5586 SELECT user.id, user.name 

5587 FROM user 

5588 JOIN address ON user.id = address.user_id 

5589 

5590 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5591 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5592 source that is within the FROM clause of the existing SELECT, 

5593 and a given target :class:`_sql.FromClause`, and then adds 

5594 this :class:`_sql.Join` to the FROM clause of the newly generated 

5595 SELECT statement. This is completely reworked from the behavior 

5596 in 1.3, which would instead create a subquery of the entire 

5597 :class:`_expression.Select` and then join that subquery to the 

5598 target. 

5599 

5600 This is a **backwards incompatible change** as the previous behavior 

5601 was mostly useless, producing an unnamed subquery rejected by 

5602 most databases in any case. The new behavior is modeled after 

5603 that of the very successful :meth:`_orm.Query.join` method in the 

5604 ORM, in order to support the functionality of :class:`_orm.Query` 

5605 being available by using a :class:`_sql.Select` object with an 

5606 :class:`_orm.Session`. 

5607 

5608 See the notes for this change at :ref:`change_select_join`. 

5609 

5610 

5611 :param target: target table to join towards 

5612 

5613 :param onclause: ON clause of the join. If omitted, an ON clause 

5614 is generated automatically based on the :class:`_schema.ForeignKey` 

5615 linkages between the two tables, if one can be unambiguously 

5616 determined, otherwise an error is raised. 

5617 

5618 :param isouter: if True, generate LEFT OUTER join. Same as 

5619 :meth:`_expression.Select.outerjoin`. 

5620 

5621 :param full: if True, generate FULL OUTER join. 

5622 

5623 .. seealso:: 

5624 

5625 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5626 

5627 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5628 

5629 :meth:`_expression.Select.join_from` 

5630 

5631 :meth:`_expression.Select.outerjoin` 

5632 

5633 """ # noqa: E501 

5634 join_target = coercions.expect( 

5635 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5636 ) 

5637 if onclause is not None: 

5638 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5639 else: 

5640 onclause_element = None 

5641 

5642 self._setup_joins += ( 

5643 ( 

5644 join_target, 

5645 onclause_element, 

5646 None, 

5647 {"isouter": isouter, "full": full}, 

5648 ), 

5649 ) 

5650 return self 

5651 

5652 def outerjoin_from( 

5653 self, 

5654 from_: _FromClauseArgument, 

5655 target: _JoinTargetArgument, 

5656 onclause: Optional[_OnClauseArgument] = None, 

5657 *, 

5658 full: bool = False, 

5659 ) -> Self: 

5660 r"""Create a SQL LEFT OUTER JOIN against this 

5661 :class:`_expression.Select` object's criterion and apply generatively, 

5662 returning the newly resulting :class:`_expression.Select`. 

5663 

5664 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5665 

5666 """ 

5667 return self.join_from( 

5668 from_, target, onclause=onclause, isouter=True, full=full 

5669 ) 

5670 

5671 @_generative 

5672 def join_from( 

5673 self, 

5674 from_: _FromClauseArgument, 

5675 target: _JoinTargetArgument, 

5676 onclause: Optional[_OnClauseArgument] = None, 

5677 *, 

5678 isouter: bool = False, 

5679 full: bool = False, 

5680 ) -> Self: 

5681 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5682 object's criterion 

5683 and apply generatively, returning the newly resulting 

5684 :class:`_expression.Select`. 

5685 

5686 E.g.:: 

5687 

5688 stmt = select(user_table, address_table).join_from( 

5689 user_table, address_table, user_table.c.id == address_table.c.user_id 

5690 ) 

5691 

5692 The above statement generates SQL similar to: 

5693 

5694 .. sourcecode:: sql 

5695 

5696 SELECT user.id, user.name, address.id, address.email, address.user_id 

5697 FROM user JOIN address ON user.id = address.user_id 

5698 

5699 .. versionadded:: 1.4 

5700 

5701 :param from\_: the left side of the join, will be rendered in the 

5702 FROM clause and is roughly equivalent to using the 

5703 :meth:`.Select.select_from` method. 

5704 

5705 :param target: target table to join towards 

5706 

5707 :param onclause: ON clause of the join. 

5708 

5709 :param isouter: if True, generate LEFT OUTER join. Same as 

5710 :meth:`_expression.Select.outerjoin`. 

5711 

5712 :param full: if True, generate FULL OUTER join. 

5713 

5714 .. seealso:: 

5715 

5716 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5717 

5718 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5719 

5720 :meth:`_expression.Select.join` 

5721 

5722 """ # noqa: E501 

5723 

5724 # note the order of parsing from vs. target is important here, as we 

5725 # are also deriving the source of the plugin (i.e. the subject mapper 

5726 # in an ORM query) which should favor the "from_" over the "target" 

5727 

5728 from_ = coercions.expect( 

5729 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5730 ) 

5731 join_target = coercions.expect( 

5732 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5733 ) 

5734 if onclause is not None: 

5735 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5736 else: 

5737 onclause_element = None 

5738 

5739 self._setup_joins += ( 

5740 ( 

5741 join_target, 

5742 onclause_element, 

5743 from_, 

5744 {"isouter": isouter, "full": full}, 

5745 ), 

5746 ) 

5747 return self 

5748 

5749 def outerjoin( 

5750 self, 

5751 target: _JoinTargetArgument, 

5752 onclause: Optional[_OnClauseArgument] = None, 

5753 *, 

5754 full: bool = False, 

5755 ) -> Self: 

5756 """Create a left outer join. 

5757 

5758 Parameters are the same as that of :meth:`_expression.Select.join`. 

5759 

5760 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5761 creates a :class:`_sql.Join` object between a 

5762 :class:`_sql.FromClause` source that is within the FROM clause of 

5763 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5764 and then adds this :class:`_sql.Join` to the FROM clause of the 

5765 newly generated SELECT statement. This is completely reworked 

5766 from the behavior in 1.3, which would instead create a subquery of 

5767 the entire 

5768 :class:`_expression.Select` and then join that subquery to the 

5769 target. 

5770 

5771 This is a **backwards incompatible change** as the previous behavior 

5772 was mostly useless, producing an unnamed subquery rejected by 

5773 most databases in any case. The new behavior is modeled after 

5774 that of the very successful :meth:`_orm.Query.join` method in the 

5775 ORM, in order to support the functionality of :class:`_orm.Query` 

5776 being available by using a :class:`_sql.Select` object with an 

5777 :class:`_orm.Session`. 

5778 

5779 See the notes for this change at :ref:`change_select_join`. 

5780 

5781 .. seealso:: 

5782 

5783 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5784 

5785 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5786 

5787 :meth:`_expression.Select.join` 

5788 

5789 """ 

5790 return self.join(target, onclause=onclause, isouter=True, full=full) 

5791 

5792 def get_final_froms(self) -> Sequence[FromClause]: 

5793 """Compute the final displayed list of :class:`_expression.FromClause` 

5794 elements. 

5795 

5796 This method will run through the full computation required to 

5797 determine what FROM elements will be displayed in the resulting 

5798 SELECT statement, including shadowing individual tables with 

5799 JOIN objects, as well as full computation for ORM use cases including 

5800 eager loading clauses. 

5801 

5802 For ORM use, this accessor returns the **post compilation** 

5803 list of FROM objects; this collection will include elements such as 

5804 eagerly loaded tables and joins. The objects will **not** be 

5805 ORM enabled and not work as a replacement for the 

5806 :meth:`_sql.Select.select_froms` collection; additionally, the 

5807 method is not well performing for an ORM enabled statement as it 

5808 will incur the full ORM construction process. 

5809 

5810 To retrieve the FROM list that's implied by the "columns" collection 

5811 passed to the :class:`_sql.Select` originally, use the 

5812 :attr:`_sql.Select.columns_clause_froms` accessor. 

5813 

5814 To select from an alternative set of columns while maintaining the 

5815 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5816 pass the 

5817 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5818 parameter. 

5819 

5820 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5821 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5822 which is deprecated. 

5823 

5824 .. seealso:: 

5825 

5826 :attr:`_sql.Select.columns_clause_froms` 

5827 

5828 """ 

5829 compiler = self._default_compiler() 

5830 

5831 return self._compile_state_factory(self, compiler)._get_display_froms() 

5832 

5833 @property 

5834 @util.deprecated( 

5835 "1.4.23", 

5836 "The :attr:`_expression.Select.froms` attribute is moved to " 

5837 "the :meth:`_expression.Select.get_final_froms` method.", 

5838 ) 

5839 def froms(self) -> Sequence[FromClause]: 

5840 """Return the displayed list of :class:`_expression.FromClause` 

5841 elements. 

5842 

5843 

5844 """ 

5845 return self.get_final_froms() 

5846 

5847 @property 

5848 def columns_clause_froms(self) -> List[FromClause]: 

5849 """Return the set of :class:`_expression.FromClause` objects implied 

5850 by the columns clause of this SELECT statement. 

5851 

5852 .. versionadded:: 1.4.23 

5853 

5854 .. seealso:: 

5855 

5856 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5857 statement into account 

5858 

5859 :meth:`_sql.Select.with_only_columns` - makes use of this 

5860 collection to set up a new FROM list 

5861 

5862 """ 

5863 

5864 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5865 self 

5866 ) 

5867 

5868 @property 

5869 def inner_columns(self) -> _SelectIterable: 

5870 """An iterator of all :class:`_expression.ColumnElement` 

5871 expressions which would 

5872 be rendered into the columns clause of the resulting SELECT statement. 

5873 

5874 This method is legacy as of 1.4 and is superseded by the 

5875 :attr:`_expression.Select.exported_columns` collection. 

5876 

5877 """ 

5878 

5879 return iter(self._all_selected_columns) 

5880 

5881 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5882 if fromclause is not None and self in fromclause._cloned_set: 

5883 return True 

5884 

5885 for f in self._iterate_from_elements(): 

5886 if f.is_derived_from(fromclause): 

5887 return True 

5888 return False 

5889 

5890 def _copy_internals( 

5891 self, clone: _CloneCallableType = _clone, **kw: Any 

5892 ) -> None: 

5893 # Select() object has been cloned and probably adapted by the 

5894 # given clone function. Apply the cloning function to internal 

5895 # objects 

5896 

5897 # 1. keep a dictionary of the froms we've cloned, and what 

5898 # they've become. This allows us to ensure the same cloned from 

5899 # is used when other items such as columns are "cloned" 

5900 

5901 all_the_froms = set( 

5902 itertools.chain( 

5903 _from_objects(*self._raw_columns), 

5904 _from_objects(*self._where_criteria), 

5905 _from_objects(*[elem[0] for elem in self._setup_joins]), 

5906 ) 

5907 ) 

5908 

5909 # do a clone for the froms we've gathered. what is important here 

5910 # is if any of the things we are selecting from, like tables, 

5911 # were converted into Join objects. if so, these need to be 

5912 # added to _from_obj explicitly, because otherwise they won't be 

5913 # part of the new state, as they don't associate themselves with 

5914 # their columns. 

5915 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

5916 

5917 # 2. copy FROM collections, adding in joins that we've created. 

5918 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

5919 add_froms = ( 

5920 {f for f in new_froms.values() if isinstance(f, Join)} 

5921 .difference(all_the_froms) 

5922 .difference(existing_from_obj) 

5923 ) 

5924 

5925 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

5926 

5927 # 3. clone everything else, making sure we use columns 

5928 # corresponding to the froms we just made. 

5929 def replace( 

5930 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

5931 **kw: Any, 

5932 ) -> Optional[KeyedColumnElement[Any]]: 

5933 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

5934 newelem = new_froms[obj.table].corresponding_column(obj) 

5935 return newelem 

5936 return None 

5937 

5938 kw["replace"] = replace 

5939 

5940 # copy everything else. for table-ish things like correlate, 

5941 # correlate_except, setup_joins, these clone normally. For 

5942 # column-expression oriented things like raw_columns, where_criteria, 

5943 # order by, we get this from the new froms. 

5944 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

5945 

5946 self._reset_memoizations() 

5947 

5948 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

5949 return itertools.chain( 

5950 super().get_children( 

5951 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

5952 **kw, 

5953 ), 

5954 self._iterate_from_elements(), 

5955 ) 

5956 

5957 @_generative 

5958 def add_columns( 

5959 self, *entities: _ColumnsClauseArgument[Any] 

5960 ) -> Select[Unpack[TupleAny]]: 

5961 r"""Return a new :func:`_expression.select` construct with 

5962 the given entities appended to its columns clause. 

5963 

5964 E.g.:: 

5965 

5966 my_select = my_select.add_columns(table.c.new_column) 

5967 

5968 The original expressions in the columns clause remain in place. 

5969 To replace the original expressions with new ones, see the method 

5970 :meth:`_expression.Select.with_only_columns`. 

5971 

5972 :param \*entities: column, table, or other entity expressions to be 

5973 added to the columns clause 

5974 

5975 .. seealso:: 

5976 

5977 :meth:`_expression.Select.with_only_columns` - replaces existing 

5978 expressions rather than appending. 

5979 

5980 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

5981 example 

5982 

5983 """ 

5984 self._reset_memoizations() 

5985 

5986 self._raw_columns = self._raw_columns + [ 

5987 coercions.expect( 

5988 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

5989 ) 

5990 for column in entities 

5991 ] 

5992 return self 

5993 

5994 def _set_entities( 

5995 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

5996 ) -> None: 

5997 self._raw_columns = [ 

5998 coercions.expect( 

5999 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6000 ) 

6001 for ent in util.to_list(entities) 

6002 ] 

6003 

6004 @util.deprecated( 

6005 "1.4", 

6006 "The :meth:`_expression.Select.column` method is deprecated and will " 

6007 "be removed in a future release. Please use " 

6008 ":meth:`_expression.Select.add_columns`", 

6009 ) 

6010 def column( 

6011 self, column: _ColumnsClauseArgument[Any] 

6012 ) -> Select[Unpack[TupleAny]]: 

6013 """Return a new :func:`_expression.select` construct with 

6014 the given column expression added to its columns clause. 

6015 

6016 E.g.:: 

6017 

6018 my_select = my_select.column(table.c.new_column) 

6019 

6020 See the documentation for 

6021 :meth:`_expression.Select.with_only_columns` 

6022 for guidelines on adding /replacing the columns of a 

6023 :class:`_expression.Select` object. 

6024 

6025 """ 

6026 return self.add_columns(column) 

6027 

6028 @util.preload_module("sqlalchemy.sql.util") 

6029 def reduce_columns( 

6030 self, only_synonyms: bool = True 

6031 ) -> Select[Unpack[TupleAny]]: 

6032 """Return a new :func:`_expression.select` construct with redundantly 

6033 named, equivalently-valued columns removed from the columns clause. 

6034 

6035 "Redundant" here means two columns where one refers to the 

6036 other either based on foreign key, or via a simple equality 

6037 comparison in the WHERE clause of the statement. The primary purpose 

6038 of this method is to automatically construct a select statement 

6039 with all uniquely-named columns, without the need to use 

6040 table-qualified labels as 

6041 :meth:`_expression.Select.set_label_style` 

6042 does. 

6043 

6044 When columns are omitted based on foreign key, the referred-to 

6045 column is the one that's kept. When columns are omitted based on 

6046 WHERE equivalence, the first column in the columns clause is the 

6047 one that's kept. 

6048 

6049 :param only_synonyms: when True, limit the removal of columns 

6050 to those which have the same name as the equivalent. Otherwise, 

6051 all columns that are equivalent to another are removed. 

6052 

6053 """ 

6054 woc: Select[Unpack[TupleAny]] 

6055 woc = self.with_only_columns( 

6056 *util.preloaded.sql_util.reduce_columns( 

6057 self._all_selected_columns, 

6058 only_synonyms=only_synonyms, 

6059 *(self._where_criteria + self._from_obj), 

6060 ) 

6061 ) 

6062 return woc 

6063 

6064 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6065 

6066 # code within this block is **programmatically, 

6067 # statically generated** by tools/generate_tuple_map_overloads.py 

6068 

6069 @overload 

6070 def with_only_columns( 

6071 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6072 ) -> Select[_T0]: ... 

6073 

6074 @overload 

6075 def with_only_columns( 

6076 self, 

6077 __ent0: _TCCA[_T0], 

6078 __ent1: _TCCA[_T1], 

6079 /, 

6080 *, 

6081 maintain_column_froms: bool = ..., 

6082 ) -> Select[_T0, _T1]: ... 

6083 

6084 @overload 

6085 def with_only_columns( 

6086 self, 

6087 __ent0: _TCCA[_T0], 

6088 __ent1: _TCCA[_T1], 

6089 __ent2: _TCCA[_T2], 

6090 /, 

6091 *, 

6092 maintain_column_froms: bool = ..., 

6093 ) -> Select[_T0, _T1, _T2]: ... 

6094 

6095 @overload 

6096 def with_only_columns( 

6097 self, 

6098 __ent0: _TCCA[_T0], 

6099 __ent1: _TCCA[_T1], 

6100 __ent2: _TCCA[_T2], 

6101 __ent3: _TCCA[_T3], 

6102 /, 

6103 *, 

6104 maintain_column_froms: bool = ..., 

6105 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6106 

6107 @overload 

6108 def with_only_columns( 

6109 self, 

6110 __ent0: _TCCA[_T0], 

6111 __ent1: _TCCA[_T1], 

6112 __ent2: _TCCA[_T2], 

6113 __ent3: _TCCA[_T3], 

6114 __ent4: _TCCA[_T4], 

6115 /, 

6116 *, 

6117 maintain_column_froms: bool = ..., 

6118 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6119 

6120 @overload 

6121 def with_only_columns( 

6122 self, 

6123 __ent0: _TCCA[_T0], 

6124 __ent1: _TCCA[_T1], 

6125 __ent2: _TCCA[_T2], 

6126 __ent3: _TCCA[_T3], 

6127 __ent4: _TCCA[_T4], 

6128 __ent5: _TCCA[_T5], 

6129 /, 

6130 *, 

6131 maintain_column_froms: bool = ..., 

6132 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6133 

6134 @overload 

6135 def with_only_columns( 

6136 self, 

6137 __ent0: _TCCA[_T0], 

6138 __ent1: _TCCA[_T1], 

6139 __ent2: _TCCA[_T2], 

6140 __ent3: _TCCA[_T3], 

6141 __ent4: _TCCA[_T4], 

6142 __ent5: _TCCA[_T5], 

6143 __ent6: _TCCA[_T6], 

6144 /, 

6145 *, 

6146 maintain_column_froms: bool = ..., 

6147 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6148 

6149 @overload 

6150 def with_only_columns( 

6151 self, 

6152 __ent0: _TCCA[_T0], 

6153 __ent1: _TCCA[_T1], 

6154 __ent2: _TCCA[_T2], 

6155 __ent3: _TCCA[_T3], 

6156 __ent4: _TCCA[_T4], 

6157 __ent5: _TCCA[_T5], 

6158 __ent6: _TCCA[_T6], 

6159 __ent7: _TCCA[_T7], 

6160 /, 

6161 *entities: _ColumnsClauseArgument[Any], 

6162 maintain_column_froms: bool = ..., 

6163 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6164 

6165 # END OVERLOADED FUNCTIONS self.with_only_columns 

6166 

6167 @overload 

6168 def with_only_columns( 

6169 self, 

6170 *entities: _ColumnsClauseArgument[Any], 

6171 maintain_column_froms: bool = False, 

6172 **__kw: Any, 

6173 ) -> Select[Unpack[TupleAny]]: ... 

6174 

6175 @_generative 

6176 def with_only_columns( 

6177 self, 

6178 *entities: _ColumnsClauseArgument[Any], 

6179 maintain_column_froms: bool = False, 

6180 **__kw: Any, 

6181 ) -> Select[Unpack[TupleAny]]: 

6182 r"""Return a new :func:`_expression.select` construct with its columns 

6183 clause replaced with the given entities. 

6184 

6185 By default, this method is exactly equivalent to as if the original 

6186 :func:`_expression.select` had been called with the given entities. 

6187 E.g. a statement:: 

6188 

6189 s = select(table1.c.a, table1.c.b) 

6190 s = s.with_only_columns(table1.c.b) 

6191 

6192 should be exactly equivalent to:: 

6193 

6194 s = select(table1.c.b) 

6195 

6196 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6197 will also dynamically alter the FROM clause of the 

6198 statement if it is not explicitly stated. 

6199 To maintain the existing set of FROMs including those implied by the 

6200 current columns clause, add the 

6201 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6202 parameter:: 

6203 

6204 s = select(table1.c.a, table2.c.b) 

6205 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6206 

6207 The above parameter performs a transfer of the effective FROMs 

6208 in the columns collection to the :meth:`_sql.Select.select_from` 

6209 method, as though the following were invoked:: 

6210 

6211 s = select(table1.c.a, table2.c.b) 

6212 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6213 

6214 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6215 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6216 collection and performs an operation equivalent to the following:: 

6217 

6218 s = select(table1.c.a, table2.c.b) 

6219 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6220 

6221 :param \*entities: column expressions to be used. 

6222 

6223 :param maintain_column_froms: boolean parameter that will ensure the 

6224 FROM list implied from the current columns clause will be transferred 

6225 to the :meth:`_sql.Select.select_from` method first. 

6226 

6227 .. versionadded:: 1.4.23 

6228 

6229 """ # noqa: E501 

6230 

6231 if __kw: 

6232 raise _no_kw() 

6233 

6234 # memoizations should be cleared here as of 

6235 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6236 # is the case for now. 

6237 self._assert_no_memoizations() 

6238 

6239 if maintain_column_froms: 

6240 self.select_from.non_generative( # type: ignore 

6241 self, *self.columns_clause_froms 

6242 ) 

6243 

6244 # then memoize the FROMs etc. 

6245 _MemoizedSelectEntities._generate_for_statement(self) 

6246 

6247 self._raw_columns = [ 

6248 coercions.expect(roles.ColumnsClauseRole, c) 

6249 for c in coercions._expression_collection_was_a_list( 

6250 "entities", "Select.with_only_columns", entities 

6251 ) 

6252 ] 

6253 return self 

6254 

6255 @property 

6256 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6257 """Return the completed WHERE clause for this 

6258 :class:`_expression.Select` statement. 

6259 

6260 This assembles the current collection of WHERE criteria 

6261 into a single :class:`_expression.BooleanClauseList` construct. 

6262 

6263 

6264 .. versionadded:: 1.4 

6265 

6266 """ 

6267 

6268 return BooleanClauseList._construct_for_whereclause( 

6269 self._where_criteria 

6270 ) 

6271 

6272 _whereclause = whereclause 

6273 

6274 @_generative 

6275 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6276 """Return a new :func:`_expression.select` construct with 

6277 the given expression added to 

6278 its WHERE clause, joined to the existing clause via AND, if any. 

6279 

6280 """ 

6281 

6282 assert isinstance(self._where_criteria, tuple) 

6283 

6284 for criterion in whereclause: 

6285 where_criteria: ColumnElement[Any] = coercions.expect( 

6286 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6287 ) 

6288 self._where_criteria += (where_criteria,) 

6289 return self 

6290 

6291 @_generative 

6292 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6293 """Return a new :func:`_expression.select` construct with 

6294 the given expression added to 

6295 its HAVING clause, joined to the existing clause via AND, if any. 

6296 

6297 """ 

6298 

6299 for criterion in having: 

6300 having_criteria = coercions.expect( 

6301 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6302 ) 

6303 self._having_criteria += (having_criteria,) 

6304 return self 

6305 

6306 @_generative 

6307 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6308 r"""Return a new :func:`_expression.select` construct which 

6309 will apply DISTINCT to the SELECT statement overall. 

6310 

6311 E.g.:: 

6312 

6313 from sqlalchemy import select 

6314 

6315 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6316 

6317 The above would produce an statement resembling: 

6318 

6319 .. sourcecode:: sql 

6320 

6321 SELECT DISTINCT user.id, user.name FROM user 

6322 

6323 The method also historically accepted an ``*expr`` parameter which 

6324 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6325 This is now replaced using the :func:`_postgresql.distinct_on` 

6326 extension:: 

6327 

6328 from sqlalchemy import select 

6329 from sqlalchemy.dialects.postgresql import distinct_on 

6330 

6331 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6332 

6333 Using this parameter on other backends which don't support this 

6334 syntax will raise an error. 

6335 

6336 :param \*expr: optional column expressions. When present, 

6337 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6338 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6339 will be raised on other backends. 

6340 

6341 .. deprecated:: 2.1 Passing expressions to 

6342 :meth:`_sql.Select.distinct` is deprecated, use 

6343 :func:`_postgresql.distinct_on` instead. 

6344 

6345 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6346 and will raise :class:`_exc.CompileError` in a future version. 

6347 

6348 .. seealso:: 

6349 

6350 :func:`_postgresql.distinct_on` 

6351 

6352 :meth:`_sql.HasSyntaxExtensions.ext` 

6353 """ 

6354 self._distinct = True 

6355 if expr: 

6356 warn_deprecated( 

6357 "Passing expression to ``distinct`` to generate a " 

6358 "DISTINCT ON clause is deprecated. Use instead the " 

6359 "``postgresql.distinct_on`` function as an extension.", 

6360 "2.1", 

6361 ) 

6362 self._distinct_on = self._distinct_on + tuple( 

6363 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6364 for e in expr 

6365 ) 

6366 return self 

6367 

6368 @_generative 

6369 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6370 r"""Return a new :func:`_expression.select` construct with the 

6371 given FROM expression(s) 

6372 merged into its list of FROM objects. 

6373 

6374 E.g.:: 

6375 

6376 table1 = table("t1", column("a")) 

6377 table2 = table("t2", column("b")) 

6378 s = select(table1.c.a).select_from( 

6379 table1.join(table2, table1.c.a == table2.c.b) 

6380 ) 

6381 

6382 The "from" list is a unique set on the identity of each element, 

6383 so adding an already present :class:`_schema.Table` 

6384 or other selectable 

6385 will have no effect. Passing a :class:`_expression.Join` that refers 

6386 to an already present :class:`_schema.Table` 

6387 or other selectable will have 

6388 the effect of concealing the presence of that selectable as 

6389 an individual element in the rendered FROM list, instead 

6390 rendering it into a JOIN clause. 

6391 

6392 While the typical purpose of :meth:`_expression.Select.select_from` 

6393 is to 

6394 replace the default, derived FROM clause with a join, it can 

6395 also be called with individual table elements, multiple times 

6396 if desired, in the case that the FROM clause cannot be fully 

6397 derived from the columns clause:: 

6398 

6399 select(func.count("*")).select_from(table1) 

6400 

6401 """ 

6402 

6403 self._from_obj += tuple( 

6404 coercions.expect( 

6405 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6406 ) 

6407 for fromclause in froms 

6408 ) 

6409 return self 

6410 

6411 @_generative 

6412 def correlate( 

6413 self, 

6414 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6415 ) -> Self: 

6416 r"""Return a new :class:`_expression.Select` 

6417 which will correlate the given FROM 

6418 clauses to that of an enclosing :class:`_expression.Select`. 

6419 

6420 Calling this method turns off the :class:`_expression.Select` object's 

6421 default behavior of "auto-correlation". Normally, FROM elements 

6422 which appear in a :class:`_expression.Select` 

6423 that encloses this one via 

6424 its :term:`WHERE clause`, ORDER BY, HAVING or 

6425 :term:`columns clause` will be omitted from this 

6426 :class:`_expression.Select` 

6427 object's :term:`FROM clause`. 

6428 Setting an explicit correlation collection using the 

6429 :meth:`_expression.Select.correlate` 

6430 method provides a fixed list of FROM objects 

6431 that can potentially take place in this process. 

6432 

6433 When :meth:`_expression.Select.correlate` 

6434 is used to apply specific FROM clauses 

6435 for correlation, the FROM elements become candidates for 

6436 correlation regardless of how deeply nested this 

6437 :class:`_expression.Select` 

6438 object is, relative to an enclosing :class:`_expression.Select` 

6439 which refers to 

6440 the same FROM object. This is in contrast to the behavior of 

6441 "auto-correlation" which only correlates to an immediate enclosing 

6442 :class:`_expression.Select`. 

6443 Multi-level correlation ensures that the link 

6444 between enclosed and enclosing :class:`_expression.Select` 

6445 is always via 

6446 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6447 correlation to take place. 

6448 

6449 If ``None`` is passed, the :class:`_expression.Select` 

6450 object will correlate 

6451 none of its FROM entries, and all will render unconditionally 

6452 in the local FROM clause. 

6453 

6454 :param \*fromclauses: one or more :class:`.FromClause` or other 

6455 FROM-compatible construct such as an ORM mapped entity to become part 

6456 of the correlate collection; alternatively pass a single value 

6457 ``None`` to remove all existing correlations. 

6458 

6459 .. seealso:: 

6460 

6461 :meth:`_expression.Select.correlate_except` 

6462 

6463 :ref:`tutorial_scalar_subquery` 

6464 

6465 """ 

6466 

6467 # tests failing when we try to change how these 

6468 # arguments are passed 

6469 

6470 self._auto_correlate = False 

6471 if not fromclauses or fromclauses[0] in {None, False}: 

6472 if len(fromclauses) > 1: 

6473 raise exc.ArgumentError( 

6474 "additional FROM objects not accepted when " 

6475 "passing None/False to correlate()" 

6476 ) 

6477 self._correlate = () 

6478 else: 

6479 self._correlate = self._correlate + tuple( 

6480 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6481 ) 

6482 return self 

6483 

6484 @_generative 

6485 def correlate_except( 

6486 self, 

6487 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6488 ) -> Self: 

6489 r"""Return a new :class:`_expression.Select` 

6490 which will omit the given FROM 

6491 clauses from the auto-correlation process. 

6492 

6493 Calling :meth:`_expression.Select.correlate_except` turns off the 

6494 :class:`_expression.Select` object's default behavior of 

6495 "auto-correlation" for the given FROM elements. An element 

6496 specified here will unconditionally appear in the FROM list, while 

6497 all other FROM elements remain subject to normal auto-correlation 

6498 behaviors. 

6499 

6500 If ``None`` is passed, or no arguments are passed, 

6501 the :class:`_expression.Select` object will correlate all of its 

6502 FROM entries. 

6503 

6504 :param \*fromclauses: a list of one or more 

6505 :class:`_expression.FromClause` 

6506 constructs, or other compatible constructs (i.e. ORM-mapped 

6507 classes) to become part of the correlate-exception collection. 

6508 

6509 .. seealso:: 

6510 

6511 :meth:`_expression.Select.correlate` 

6512 

6513 :ref:`tutorial_scalar_subquery` 

6514 

6515 """ 

6516 

6517 self._auto_correlate = False 

6518 if not fromclauses or fromclauses[0] in {None, False}: 

6519 if len(fromclauses) > 1: 

6520 raise exc.ArgumentError( 

6521 "additional FROM objects not accepted when " 

6522 "passing None/False to correlate_except()" 

6523 ) 

6524 self._correlate_except = () 

6525 else: 

6526 self._correlate_except = (self._correlate_except or ()) + tuple( 

6527 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6528 ) 

6529 

6530 return self 

6531 

6532 @HasMemoized_ro_memoized_attribute 

6533 def selected_columns( 

6534 self, 

6535 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6536 """A :class:`_expression.ColumnCollection` 

6537 representing the columns that 

6538 this SELECT statement or similar construct returns in its result set, 

6539 not including :class:`_sql.TextClause` constructs. 

6540 

6541 This collection differs from the :attr:`_expression.FromClause.columns` 

6542 collection of a :class:`_expression.FromClause` in that the columns 

6543 within this collection cannot be directly nested inside another SELECT 

6544 statement; a subquery must be applied first which provides for the 

6545 necessary parenthesization required by SQL. 

6546 

6547 For a :func:`_expression.select` construct, the collection here is 

6548 exactly what would be rendered inside the "SELECT" statement, and the 

6549 :class:`_expression.ColumnElement` objects are directly present as they 

6550 were given, e.g.:: 

6551 

6552 col1 = column("q", Integer) 

6553 col2 = column("p", Integer) 

6554 stmt = select(col1, col2) 

6555 

6556 Above, ``stmt.selected_columns`` would be a collection that contains 

6557 the ``col1`` and ``col2`` objects directly. For a statement that is 

6558 against a :class:`_schema.Table` or other 

6559 :class:`_expression.FromClause`, the collection will use the 

6560 :class:`_expression.ColumnElement` objects that are in the 

6561 :attr:`_expression.FromClause.c` collection of the from element. 

6562 

6563 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6564 to allow the existing columns to be referenced when adding additional 

6565 criteria, e.g.:: 

6566 

6567 def filter_on_id(my_select, id): 

6568 return my_select.where(my_select.selected_columns["id"] == id) 

6569 

6570 

6571 stmt = select(MyModel) 

6572 

6573 # adds "WHERE id=:param" to the statement 

6574 stmt = filter_on_id(stmt, 42) 

6575 

6576 .. note:: 

6577 

6578 The :attr:`_sql.Select.selected_columns` collection does not 

6579 include expressions established in the columns clause using the 

6580 :func:`_sql.text` construct; these are silently omitted from the 

6581 collection. To use plain textual column expressions inside of a 

6582 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6583 construct. 

6584 

6585 

6586 .. versionadded:: 1.4 

6587 

6588 """ 

6589 

6590 # compare to SelectState._generate_columns_plus_names, which 

6591 # generates the actual names used in the SELECT string. that 

6592 # method is more complex because it also renders columns that are 

6593 # fully ambiguous, e.g. same column more than once. 

6594 conv = cast( 

6595 "Callable[[Any], str]", 

6596 SelectState._column_naming_convention(self._label_style), 

6597 ) 

6598 

6599 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6600 [ 

6601 (conv(c), c) 

6602 for c in self._all_selected_columns 

6603 if is_column_element(c) 

6604 ] 

6605 ) 

6606 return cc.as_readonly() 

6607 

6608 @HasMemoized_ro_memoized_attribute 

6609 def _all_selected_columns(self) -> _SelectIterable: 

6610 meth = SelectState.get_plugin_class(self).all_selected_columns 

6611 return list(meth(self)) 

6612 

6613 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6614 if self._label_style is LABEL_STYLE_NONE: 

6615 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6616 return self 

6617 

6618 def _generate_fromclause_column_proxies( 

6619 self, 

6620 subquery: FromClause, 

6621 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

6622 primary_key: ColumnSet, 

6623 foreign_keys: Set[KeyedColumnElement[Any]], 

6624 *, 

6625 proxy_compound_columns: Optional[ 

6626 Iterable[Sequence[ColumnElement[Any]]] 

6627 ] = None, 

6628 ) -> None: 

6629 """Generate column proxies to place in the exported ``.c`` 

6630 collection of a subquery.""" 

6631 

6632 if proxy_compound_columns: 

6633 extra_col_iterator = proxy_compound_columns 

6634 prox = [ 

6635 c._make_proxy( 

6636 subquery, 

6637 key=proxy_key, 

6638 name=required_label_name, 

6639 name_is_truncatable=True, 

6640 compound_select_cols=extra_cols, 

6641 primary_key=primary_key, 

6642 foreign_keys=foreign_keys, 

6643 ) 

6644 for ( 

6645 ( 

6646 required_label_name, 

6647 proxy_key, 

6648 fallback_label_name, 

6649 c, 

6650 repeated, 

6651 ), 

6652 extra_cols, 

6653 ) in ( 

6654 zip( 

6655 self._generate_columns_plus_names(False), 

6656 extra_col_iterator, 

6657 ) 

6658 ) 

6659 if is_column_element(c) 

6660 ] 

6661 else: 

6662 prox = [ 

6663 c._make_proxy( 

6664 subquery, 

6665 key=proxy_key, 

6666 name=required_label_name, 

6667 name_is_truncatable=True, 

6668 primary_key=primary_key, 

6669 foreign_keys=foreign_keys, 

6670 ) 

6671 for ( 

6672 required_label_name, 

6673 proxy_key, 

6674 fallback_label_name, 

6675 c, 

6676 repeated, 

6677 ) in (self._generate_columns_plus_names(False)) 

6678 if is_column_element(c) 

6679 ] 

6680 

6681 columns._populate_separate_keys(prox) 

6682 

6683 def _needs_parens_for_grouping(self) -> bool: 

6684 return self._has_row_limiting_clause or bool( 

6685 self._order_by_clause.clauses 

6686 ) 

6687 

6688 def self_group( 

6689 self, against: Optional[OperatorType] = None 

6690 ) -> Union[SelectStatementGrouping[Self], Self]: 

6691 """Return a 'grouping' construct as per the 

6692 :class:`_expression.ClauseElement` specification. 

6693 

6694 This produces an element that can be embedded in an expression. Note 

6695 that this method is called automatically as needed when constructing 

6696 expressions and should not require explicit use. 

6697 

6698 """ 

6699 if ( 

6700 isinstance(against, CompoundSelect) 

6701 and not self._needs_parens_for_grouping() 

6702 ): 

6703 return self 

6704 else: 

6705 return SelectStatementGrouping(self) 

6706 

6707 def union( 

6708 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6709 ) -> CompoundSelect[Unpack[_Ts]]: 

6710 r"""Return a SQL ``UNION`` of this select() construct against 

6711 the given selectables provided as positional arguments. 

6712 

6713 :param \*other: one or more elements with which to create a 

6714 UNION. 

6715 

6716 .. versionchanged:: 1.4.28 

6717 

6718 multiple elements are now accepted. 

6719 

6720 :param \**kwargs: keyword arguments are forwarded to the constructor 

6721 for the newly created :class:`_sql.CompoundSelect` object. 

6722 

6723 """ 

6724 return CompoundSelect._create_union(self, *other) 

6725 

6726 def union_all( 

6727 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6728 ) -> CompoundSelect[Unpack[_Ts]]: 

6729 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6730 the given selectables provided as positional arguments. 

6731 

6732 :param \*other: one or more elements with which to create a 

6733 UNION. 

6734 

6735 .. versionchanged:: 1.4.28 

6736 

6737 multiple elements are now accepted. 

6738 

6739 :param \**kwargs: keyword arguments are forwarded to the constructor 

6740 for the newly created :class:`_sql.CompoundSelect` object. 

6741 

6742 """ 

6743 return CompoundSelect._create_union_all(self, *other) 

6744 

6745 def except_( 

6746 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6747 ) -> CompoundSelect[Unpack[_Ts]]: 

6748 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6749 the given selectable provided as positional arguments. 

6750 

6751 :param \*other: one or more elements with which to create a 

6752 UNION. 

6753 

6754 .. versionchanged:: 1.4.28 

6755 

6756 multiple elements are now accepted. 

6757 

6758 """ 

6759 return CompoundSelect._create_except(self, *other) 

6760 

6761 def except_all( 

6762 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6763 ) -> CompoundSelect[Unpack[_Ts]]: 

6764 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6765 the given selectables provided as positional arguments. 

6766 

6767 :param \*other: one or more elements with which to create a 

6768 UNION. 

6769 

6770 .. versionchanged:: 1.4.28 

6771 

6772 multiple elements are now accepted. 

6773 

6774 """ 

6775 return CompoundSelect._create_except_all(self, *other) 

6776 

6777 def intersect( 

6778 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6779 ) -> CompoundSelect[Unpack[_Ts]]: 

6780 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6781 the given selectables provided as positional arguments. 

6782 

6783 :param \*other: one or more elements with which to create a 

6784 UNION. 

6785 

6786 .. versionchanged:: 1.4.28 

6787 

6788 multiple elements are now accepted. 

6789 

6790 :param \**kwargs: keyword arguments are forwarded to the constructor 

6791 for the newly created :class:`_sql.CompoundSelect` object. 

6792 

6793 """ 

6794 return CompoundSelect._create_intersect(self, *other) 

6795 

6796 def intersect_all( 

6797 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6798 ) -> CompoundSelect[Unpack[_Ts]]: 

6799 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6800 against the given selectables provided as positional arguments. 

6801 

6802 :param \*other: one or more elements with which to create a 

6803 UNION. 

6804 

6805 .. versionchanged:: 1.4.28 

6806 

6807 multiple elements are now accepted. 

6808 

6809 :param \**kwargs: keyword arguments are forwarded to the constructor 

6810 for the newly created :class:`_sql.CompoundSelect` object. 

6811 

6812 """ 

6813 return CompoundSelect._create_intersect_all(self, *other) 

6814 

6815 

6816class ScalarSelect( 

6817 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6818): 

6819 """Represent a scalar subquery. 

6820 

6821 

6822 A :class:`_sql.ScalarSelect` is created by invoking the 

6823 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6824 then participates in other SQL expressions as a SQL column expression 

6825 within the :class:`_sql.ColumnElement` hierarchy. 

6826 

6827 .. seealso:: 

6828 

6829 :meth:`_sql.SelectBase.scalar_subquery` 

6830 

6831 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6832 

6833 """ 

6834 

6835 _traverse_internals: _TraverseInternalsType = [ 

6836 ("element", InternalTraversal.dp_clauseelement), 

6837 ("type", InternalTraversal.dp_type), 

6838 ] 

6839 

6840 _from_objects: List[FromClause] = [] 

6841 _is_from_container = True 

6842 if not TYPE_CHECKING: 

6843 _is_implicitly_boolean = False 

6844 inherit_cache = True 

6845 

6846 element: SelectBase 

6847 

6848 def __init__(self, element: SelectBase) -> None: 

6849 self.element = element 

6850 self.type = element._scalar_type() 

6851 self._propagate_attrs = element._propagate_attrs 

6852 

6853 def __getattr__(self, attr: str) -> Any: 

6854 return getattr(self.element, attr) 

6855 

6856 def __getstate__(self) -> Dict[str, Any]: 

6857 return {"element": self.element, "type": self.type} 

6858 

6859 def __setstate__(self, state: Dict[str, Any]) -> None: 

6860 self.element = state["element"] 

6861 self.type = state["type"] 

6862 

6863 @property 

6864 def columns(self) -> NoReturn: 

6865 raise exc.InvalidRequestError( 

6866 "Scalar Select expression has no " 

6867 "columns; use this object directly " 

6868 "within a column-level expression." 

6869 ) 

6870 

6871 c = columns 

6872 

6873 @_generative 

6874 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6875 """Apply a WHERE clause to the SELECT statement referred to 

6876 by this :class:`_expression.ScalarSelect`. 

6877 

6878 """ 

6879 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6880 crit 

6881 ) 

6882 return self 

6883 

6884 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6885 return self 

6886 

6887 def _ungroup(self) -> Self: 

6888 return self 

6889 

6890 @_generative 

6891 def correlate( 

6892 self, 

6893 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6894 ) -> Self: 

6895 r"""Return a new :class:`_expression.ScalarSelect` 

6896 which will correlate the given FROM 

6897 clauses to that of an enclosing :class:`_expression.Select`. 

6898 

6899 This method is mirrored from the :meth:`_sql.Select.correlate` method 

6900 of the underlying :class:`_sql.Select`. The method applies the 

6901 :meth:_sql.Select.correlate` method, then returns a new 

6902 :class:`_sql.ScalarSelect` against that statement. 

6903 

6904 .. versionadded:: 1.4 Previously, the 

6905 :meth:`_sql.ScalarSelect.correlate` 

6906 method was only available from :class:`_sql.Select`. 

6907 

6908 :param \*fromclauses: a list of one or more 

6909 :class:`_expression.FromClause` 

6910 constructs, or other compatible constructs (i.e. ORM-mapped 

6911 classes) to become part of the correlate collection. 

6912 

6913 .. seealso:: 

6914 

6915 :meth:`_expression.ScalarSelect.correlate_except` 

6916 

6917 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6918 

6919 

6920 """ 

6921 self.element = cast( 

6922 "Select[Unpack[TupleAny]]", self.element 

6923 ).correlate(*fromclauses) 

6924 return self 

6925 

6926 @_generative 

6927 def correlate_except( 

6928 self, 

6929 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6930 ) -> Self: 

6931 r"""Return a new :class:`_expression.ScalarSelect` 

6932 which will omit the given FROM 

6933 clauses from the auto-correlation process. 

6934 

6935 This method is mirrored from the 

6936 :meth:`_sql.Select.correlate_except` method of the underlying 

6937 :class:`_sql.Select`. The method applies the 

6938 :meth:_sql.Select.correlate_except` method, then returns a new 

6939 :class:`_sql.ScalarSelect` against that statement. 

6940 

6941 .. versionadded:: 1.4 Previously, the 

6942 :meth:`_sql.ScalarSelect.correlate_except` 

6943 method was only available from :class:`_sql.Select`. 

6944 

6945 :param \*fromclauses: a list of one or more 

6946 :class:`_expression.FromClause` 

6947 constructs, or other compatible constructs (i.e. ORM-mapped 

6948 classes) to become part of the correlate-exception collection. 

6949 

6950 .. seealso:: 

6951 

6952 :meth:`_expression.ScalarSelect.correlate` 

6953 

6954 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6955 

6956 

6957 """ 

6958 

6959 self.element = cast( 

6960 "Select[Unpack[TupleAny]]", self.element 

6961 ).correlate_except(*fromclauses) 

6962 return self 

6963 

6964 

6965class Exists(UnaryExpression[bool]): 

6966 """Represent an ``EXISTS`` clause. 

6967 

6968 See :func:`_sql.exists` for a description of usage. 

6969 

6970 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

6971 instance by calling :meth:`_sql.SelectBase.exists`. 

6972 

6973 """ 

6974 

6975 inherit_cache = True 

6976 

6977 def __init__( 

6978 self, 

6979 __argument: Optional[ 

6980 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

6981 ] = None, 

6982 /, 

6983 ): 

6984 s: ScalarSelect[Any] 

6985 

6986 # TODO: this seems like we should be using coercions for this 

6987 if __argument is None: 

6988 s = Select(literal_column("*")).scalar_subquery() 

6989 elif isinstance(__argument, SelectBase): 

6990 s = __argument.scalar_subquery() 

6991 s._propagate_attrs = __argument._propagate_attrs 

6992 elif isinstance(__argument, ScalarSelect): 

6993 s = __argument 

6994 else: 

6995 s = Select(__argument).scalar_subquery() 

6996 

6997 UnaryExpression.__init__( 

6998 self, 

6999 s, 

7000 operator=operators.exists, 

7001 type_=type_api.BOOLEANTYPE, 

7002 ) 

7003 

7004 @util.ro_non_memoized_property 

7005 def _from_objects(self) -> List[FromClause]: 

7006 return [] 

7007 

7008 def _regroup( 

7009 self, 

7010 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7011 ) -> ScalarSelect[Any]: 

7012 

7013 assert isinstance(self.element, ScalarSelect) 

7014 element = self.element.element 

7015 if not isinstance(element, Select): 

7016 raise exc.InvalidRequestError( 

7017 "Can only apply this operation to a plain SELECT construct" 

7018 ) 

7019 new_element = fn(element) 

7020 

7021 return_value = new_element.scalar_subquery() 

7022 return return_value 

7023 

7024 def select(self) -> Select[bool]: 

7025 r"""Return a SELECT of this :class:`_expression.Exists`. 

7026 

7027 e.g.:: 

7028 

7029 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7030 

7031 This will produce a statement resembling: 

7032 

7033 .. sourcecode:: sql 

7034 

7035 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7036 

7037 .. seealso:: 

7038 

7039 :func:`_expression.select` - general purpose 

7040 method which allows for arbitrary column lists. 

7041 

7042 """ # noqa 

7043 

7044 return Select(self) 

7045 

7046 def correlate( 

7047 self, 

7048 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7049 ) -> Self: 

7050 """Apply correlation to the subquery noted by this 

7051 :class:`_sql.Exists`. 

7052 

7053 .. seealso:: 

7054 

7055 :meth:`_sql.ScalarSelect.correlate` 

7056 

7057 """ 

7058 e = self._clone() 

7059 e.element = self._regroup( 

7060 lambda element: element.correlate(*fromclauses) 

7061 ) 

7062 return e 

7063 

7064 def correlate_except( 

7065 self, 

7066 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7067 ) -> Self: 

7068 """Apply correlation to the subquery noted by this 

7069 :class:`_sql.Exists`. 

7070 

7071 .. seealso:: 

7072 

7073 :meth:`_sql.ScalarSelect.correlate_except` 

7074 

7075 """ 

7076 e = self._clone() 

7077 e.element = self._regroup( 

7078 lambda element: element.correlate_except(*fromclauses) 

7079 ) 

7080 return e 

7081 

7082 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7083 """Return a new :class:`_expression.Exists` construct, 

7084 applying the given 

7085 expression to the :meth:`_expression.Select.select_from` 

7086 method of the select 

7087 statement contained. 

7088 

7089 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7090 statement first, including the desired WHERE clause, then use the 

7091 :meth:`_sql.SelectBase.exists` method to produce an 

7092 :class:`_sql.Exists` object at once. 

7093 

7094 """ 

7095 e = self._clone() 

7096 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7097 return e 

7098 

7099 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7100 """Return a new :func:`_expression.exists` construct with the 

7101 given expression added to 

7102 its WHERE clause, joined to the existing clause via AND, if any. 

7103 

7104 

7105 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7106 statement first, including the desired WHERE clause, then use the 

7107 :meth:`_sql.SelectBase.exists` method to produce an 

7108 :class:`_sql.Exists` object at once. 

7109 

7110 """ 

7111 e = self._clone() 

7112 e.element = self._regroup(lambda element: element.where(*clause)) 

7113 return e 

7114 

7115 

7116class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7117 """Wrap a :class:`_expression.TextClause` construct within a 

7118 :class:`_expression.SelectBase` 

7119 interface. 

7120 

7121 This allows the :class:`_expression.TextClause` object to gain a 

7122 ``.c`` collection 

7123 and other FROM-like capabilities such as 

7124 :meth:`_expression.FromClause.alias`, 

7125 :meth:`_expression.SelectBase.cte`, etc. 

7126 

7127 The :class:`_expression.TextualSelect` construct is produced via the 

7128 :meth:`_expression.TextClause.columns` 

7129 method - see that method for details. 

7130 

7131 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7132 class was renamed 

7133 from ``TextAsFrom``, to more correctly suit its role as a 

7134 SELECT-oriented object and not a FROM clause. 

7135 

7136 .. seealso:: 

7137 

7138 :func:`_expression.text` 

7139 

7140 :meth:`_expression.TextClause.columns` - primary creation interface. 

7141 

7142 """ 

7143 

7144 __visit_name__ = "textual_select" 

7145 

7146 _label_style = LABEL_STYLE_NONE 

7147 

7148 _traverse_internals: _TraverseInternalsType = ( 

7149 [ 

7150 ("element", InternalTraversal.dp_clauseelement), 

7151 ("column_args", InternalTraversal.dp_clauseelement_list), 

7152 ] 

7153 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7154 + HasCTE._has_ctes_traverse_internals 

7155 ) 

7156 

7157 _is_textual = True 

7158 

7159 is_text = True 

7160 is_select = True 

7161 

7162 def __init__( 

7163 self, 

7164 text: TextClause, 

7165 columns: List[_ColumnExpressionArgument[Any]], 

7166 positional: bool = False, 

7167 ) -> None: 

7168 self._init( 

7169 text, 

7170 # convert for ORM attributes->columns, etc 

7171 [ 

7172 coercions.expect(roles.LabeledColumnExprRole, c) 

7173 for c in columns 

7174 ], 

7175 positional, 

7176 ) 

7177 

7178 def _init( 

7179 self, 

7180 text: TextClause, 

7181 columns: List[NamedColumn[Any]], 

7182 positional: bool = False, 

7183 ) -> None: 

7184 self.element = text 

7185 self.column_args = columns 

7186 self.positional = positional 

7187 

7188 @HasMemoized_ro_memoized_attribute 

7189 def selected_columns( 

7190 self, 

7191 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7192 """A :class:`_expression.ColumnCollection` 

7193 representing the columns that 

7194 this SELECT statement or similar construct returns in its result set, 

7195 not including :class:`_sql.TextClause` constructs. 

7196 

7197 This collection differs from the :attr:`_expression.FromClause.columns` 

7198 collection of a :class:`_expression.FromClause` in that the columns 

7199 within this collection cannot be directly nested inside another SELECT 

7200 statement; a subquery must be applied first which provides for the 

7201 necessary parenthesization required by SQL. 

7202 

7203 For a :class:`_expression.TextualSelect` construct, the collection 

7204 contains the :class:`_expression.ColumnElement` objects that were 

7205 passed to the constructor, typically via the 

7206 :meth:`_expression.TextClause.columns` method. 

7207 

7208 

7209 .. versionadded:: 1.4 

7210 

7211 """ 

7212 return ColumnCollection( 

7213 (c.key, c) for c in self.column_args 

7214 ).as_readonly() 

7215 

7216 @util.ro_non_memoized_property 

7217 def _all_selected_columns(self) -> _SelectIterable: 

7218 return self.column_args 

7219 

7220 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7221 return self 

7222 

7223 def _ensure_disambiguated_names(self) -> TextualSelect: 

7224 return self 

7225 

7226 @_generative 

7227 def bindparams( 

7228 self, 

7229 *binds: BindParameter[Any], 

7230 **bind_as_values: Any, 

7231 ) -> Self: 

7232 self.element = self.element.bindparams(*binds, **bind_as_values) 

7233 return self 

7234 

7235 def _generate_fromclause_column_proxies( 

7236 self, 

7237 fromclause: FromClause, 

7238 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

7239 primary_key: ColumnSet, 

7240 foreign_keys: Set[KeyedColumnElement[Any]], 

7241 *, 

7242 proxy_compound_columns: Optional[ 

7243 Iterable[Sequence[ColumnElement[Any]]] 

7244 ] = None, 

7245 ) -> None: 

7246 if TYPE_CHECKING: 

7247 assert isinstance(fromclause, Subquery) 

7248 

7249 if proxy_compound_columns: 

7250 columns._populate_separate_keys( 

7251 c._make_proxy( 

7252 fromclause, 

7253 compound_select_cols=extra_cols, 

7254 primary_key=primary_key, 

7255 foreign_keys=foreign_keys, 

7256 ) 

7257 for c, extra_cols in zip( 

7258 self.column_args, proxy_compound_columns 

7259 ) 

7260 ) 

7261 else: 

7262 columns._populate_separate_keys( 

7263 c._make_proxy( 

7264 fromclause, 

7265 primary_key=primary_key, 

7266 foreign_keys=foreign_keys, 

7267 ) 

7268 for c in self.column_args 

7269 ) 

7270 

7271 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7272 return self.column_args[0].type 

7273 

7274 

7275TextAsFrom = TextualSelect 

7276"""Backwards compatibility with the previous name""" 

7277 

7278 

7279class AnnotatedFromClause(Annotated): 

7280 def _copy_internals(self, **kw: Any) -> None: 

7281 super()._copy_internals(**kw) 

7282 if kw.get("ind_cols_on_fromclause", False): 

7283 ee = self._Annotated__element # type: ignore 

7284 

7285 self.c = ee.__class__.c.fget(self) # type: ignore 

7286 

7287 @util.ro_memoized_property 

7288 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7289 """proxy the .c collection of the underlying FromClause. 

7290 

7291 Originally implemented in 2008 as a simple load of the .c collection 

7292 when the annotated construct was created (see d3621ae961a), in modern 

7293 SQLAlchemy versions this can be expensive for statements constructed 

7294 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7295 it, which works just as well. 

7296 

7297 Two different use cases seem to require the collection either copied 

7298 from the underlying one, or unique to this AnnotatedFromClause. 

7299 

7300 See test_selectable->test_annotated_corresponding_column 

7301 

7302 """ 

7303 ee = self._Annotated__element # type: ignore 

7304 return ee.c # type: ignore