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

1780 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import Literal 

30from typing import NamedTuple 

31from typing import NoReturn 

32from typing import Optional 

33from typing import overload 

34from typing import Protocol 

35from typing import Sequence 

36from typing import Set 

37from typing import Tuple 

38from typing import Type 

39from typing import TYPE_CHECKING 

40from typing import TypeVar 

41from typing import Union 

42 

43from . import cache_key 

44from . import coercions 

45from . import operators 

46from . import roles 

47from . import traversals 

48from . import type_api 

49from . import visitors 

50from ._typing import _ColumnsClauseArgument 

51from ._typing import _no_kw 

52from ._typing import _T 

53from ._typing import _Ts 

54from ._typing import is_column_element 

55from ._typing import is_select_statement 

56from ._typing import is_subquery 

57from ._typing import is_table 

58from ._typing import is_text_clause 

59from .annotation import Annotated 

60from .annotation import SupportsCloneAnnotations 

61from .base import _clone 

62from .base import _cloned_difference 

63from .base import _cloned_intersection 

64from .base import _entity_namespace_key 

65from .base import _EntityNamespace 

66from .base import _expand_cloned 

67from .base import _from_objects 

68from .base import _generative 

69from .base import _never_select_column 

70from .base import _NoArg 

71from .base import _select_iterables 

72from .base import CacheableOptions 

73from .base import ColumnCollection 

74from .base import ColumnSet 

75from .base import CompileState 

76from .base import DedupeColumnCollection 

77from .base import DialectKWArgs 

78from .base import Executable 

79from .base import Generative 

80from .base import HasCompileState 

81from .base import HasMemoized 

82from .base import HasSyntaxExtensions 

83from .base import Immutable 

84from .base import SyntaxExtension 

85from .coercions import _document_text_coercion 

86from .elements import _anonymous_label 

87from .elements import BindParameter 

88from .elements import BooleanClauseList 

89from .elements import ClauseElement 

90from .elements import ClauseList 

91from .elements import ColumnClause 

92from .elements import ColumnElement 

93from .elements import DQLDMLClauseElement 

94from .elements import GroupedElement 

95from .elements import literal_column 

96from .elements import TableValuedColumn 

97from .elements import UnaryExpression 

98from .operators import OperatorType 

99from .sqltypes import NULLTYPE 

100from .visitors import _TraverseInternalsType 

101from .visitors import InternalTraversal 

102from .visitors import prefix_anon_map 

103from .. import exc 

104from .. import util 

105from ..util import HasMemoized_ro_memoized_attribute 

106from ..util import warn_deprecated 

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 with util.mini_gil: 

916 # detect another thread that raced ahead 

917 if "_columns" in self.__dict__: 

918 assert "primary_key" in self.__dict__ 

919 assert "foreign_keys" in self.__dict__ 

920 return 

921 

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

923 primary_key = ColumnSet() 

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

925 

926 self._populate_column_collection( 

927 columns=_columns, 

928 primary_key=primary_key, 

929 foreign_keys=foreign_keys, 

930 ) 

931 

932 # assigning these three collections separately is not itself 

933 # atomic, but greatly reduces the surface for problems 

934 self._columns = _columns 

935 self.primary_key = primary_key # type: ignore 

936 self.foreign_keys = foreign_keys # type: ignore 

937 

938 @util.ro_non_memoized_property 

939 def entity_namespace(self) -> _EntityNamespace: 

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

941 

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

943 expressions, such as:: 

944 

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

946 

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

948 be overridden using the "entity_namespace" annotation to deliver 

949 alternative results. 

950 

951 """ 

952 return self.c 

953 

954 @util.ro_memoized_property 

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

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

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

958 

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

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

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

962 

963 """ 

964 self._setup_collections() 

965 return self.primary_key 

966 

967 @util.ro_memoized_property 

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

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

970 which this FromClause references. 

971 

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

973 :class:`_schema.Table`-wide 

974 :class:`_schema.ForeignKeyConstraint`. 

975 

976 .. seealso:: 

977 

978 :attr:`_schema.Table.foreign_key_constraints` 

979 

980 """ 

981 self._setup_collections() 

982 return self.foreign_keys 

983 

984 def _reset_column_collection(self) -> None: 

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

986 

987 This collection is separate from all the other memoized things 

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

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

990 has already established strong relationships 

991 with the exported columns. 

992 

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

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

995 

996 """ 

997 

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

999 self.__dict__.pop(key, None) 

1000 

1001 @util.ro_non_memoized_property 

1002 def _select_iterable(self) -> _SelectIterable: 

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

1004 

1005 @property 

1006 def _cols_populated(self) -> bool: 

1007 return "_columns" in self.__dict__ 

1008 

1009 def _populate_column_collection( 

1010 self, 

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

1012 primary_key: ColumnSet, 

1013 foreign_keys: Set[KeyedColumnElement[Any]], 

1014 ) -> None: 

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

1016 

1017 Each implementation has a different way of establishing 

1018 this collection. 

1019 

1020 """ 

1021 

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

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

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

1025 selectable ultimately should proxy this column. 

1026 

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

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

1029 Table objects it ultimately derives from. 

1030 

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

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

1033 but it will return None. 

1034 

1035 This method is currently used by Declarative to allow Table 

1036 columns to be added to a partially constructed inheritance 

1037 mapping that may have already produced joins. The method 

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

1039 and/or caveats aren't yet clear. 

1040 

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

1042 default via an event, which would require that 

1043 selectables maintain a weak referencing collection of all 

1044 derivations. 

1045 

1046 """ 

1047 self._reset_column_collection() 

1048 

1049 def _anonymous_fromclause( 

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

1051 ) -> FromClause: 

1052 return self.alias(name=name) 

1053 

1054 if TYPE_CHECKING: 

1055 

1056 def self_group( 

1057 self, against: Optional[OperatorType] = None 

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

1059 

1060 

1061class NamedFromClause(FromClause): 

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

1063 

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

1065 

1066 .. versionadded:: 2.0 

1067 

1068 """ 

1069 

1070 named_with_column = True 

1071 

1072 name: str 

1073 

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

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

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

1077 :class:`_expression.FromClause`. 

1078 

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

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

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

1082 such as PostgreSQL, Oracle Database and SQL Server. 

1083 

1084 E.g.: 

1085 

1086 .. sourcecode:: pycon+sql 

1087 

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

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

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

1091 >>> print(stmt) 

1092 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1093 FROM a 

1094 

1095 .. versionadded:: 1.4.0b2 

1096 

1097 .. seealso:: 

1098 

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

1100 

1101 """ 

1102 return TableValuedColumn(self, type_api.TABLEVALUE) 

1103 

1104 

1105class SelectLabelStyle(Enum): 

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

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

1108 

1109 LABEL_STYLE_NONE = 0 

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

1111 columns clause of a SELECT statement. 

1112 

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

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

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

1116 

1117 .. sourcecode:: pycon+sql 

1118 

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

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

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

1122 >>> print( 

1123 ... select(table1, table2) 

1124 ... .join(table2, true()) 

1125 ... .set_label_style(LABEL_STYLE_NONE) 

1126 ... ) 

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

1128 FROM table1 JOIN table2 ON true 

1129 

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

1131 

1132 .. versionadded:: 1.4 

1133 

1134 """ # noqa: E501 

1135 

1136 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1140 tables, aliases, or subqueries. 

1141 

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

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

1144 ``table2_columna``: 

1145 

1146 .. sourcecode:: pycon+sql 

1147 

1148 >>> from sqlalchemy import ( 

1149 ... table, 

1150 ... column, 

1151 ... select, 

1152 ... true, 

1153 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1154 ... ) 

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

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

1157 >>> print( 

1158 ... select(table1, table2) 

1159 ... .join(table2, true()) 

1160 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1161 ... ) 

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

1163 FROM table1 JOIN table2 ON true 

1164 

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

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

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

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

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

1170 

1171 

1172 .. versionadded:: 1.4 

1173 

1174 """ # noqa: E501 

1175 

1176 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1179 when generating the columns clause of a SELECT statement. 

1180 

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

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

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

1184 

1185 .. sourcecode:: pycon+sql 

1186 

1187 >>> from sqlalchemy import ( 

1188 ... table, 

1189 ... column, 

1190 ... select, 

1191 ... true, 

1192 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1193 ... ) 

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

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

1196 >>> print( 

1197 ... select(table1, table2) 

1198 ... .join(table2, true()) 

1199 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1200 ... ) 

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

1202 FROM table1 JOIN table2 ON true 

1203 

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

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

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

1207 

1208 .. versionadded:: 1.4 

1209 

1210 """ # noqa: E501 

1211 

1212 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1213 """The default label style, refers to 

1214 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1215 

1216 .. versionadded:: 1.4 

1217 

1218 """ 

1219 

1220 LABEL_STYLE_LEGACY_ORM = 3 

1221 

1222 

1223( 

1224 LABEL_STYLE_NONE, 

1225 LABEL_STYLE_TABLENAME_PLUS_COL, 

1226 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1227 _, 

1228) = list(SelectLabelStyle) 

1229 

1230LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1231 

1232 

1233class Join(roles.DMLTableRole, FromClause): 

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

1235 :class:`_expression.FromClause` 

1236 elements. 

1237 

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

1239 is the module-level 

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

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

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

1243 :class:`_schema.Table`). 

1244 

1245 .. seealso:: 

1246 

1247 :func:`_expression.join` 

1248 

1249 :meth:`_expression.FromClause.join` 

1250 

1251 """ 

1252 

1253 __visit_name__ = "join" 

1254 

1255 _traverse_internals: _TraverseInternalsType = [ 

1256 ("left", InternalTraversal.dp_clauseelement), 

1257 ("right", InternalTraversal.dp_clauseelement), 

1258 ("onclause", InternalTraversal.dp_clauseelement), 

1259 ("isouter", InternalTraversal.dp_boolean), 

1260 ("full", InternalTraversal.dp_boolean), 

1261 ] 

1262 

1263 _is_join = True 

1264 

1265 left: FromClause 

1266 right: FromClause 

1267 onclause: Optional[ColumnElement[bool]] 

1268 isouter: bool 

1269 full: bool 

1270 

1271 def __init__( 

1272 self, 

1273 left: _FromClauseArgument, 

1274 right: _FromClauseArgument, 

1275 onclause: Optional[_OnClauseArgument] = None, 

1276 isouter: bool = False, 

1277 full: bool = False, 

1278 ): 

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

1280 

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

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

1283 :class:`_expression.FromClause` object. 

1284 

1285 """ 

1286 

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

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

1289 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1292 # callcounts for a single compilation in that particular test 

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

1294 # 29200 -> 30373 

1295 

1296 self.left = coercions.expect( 

1297 roles.FromClauseRole, 

1298 left, 

1299 ) 

1300 self.right = coercions.expect( 

1301 roles.FromClauseRole, 

1302 right, 

1303 ).self_group() 

1304 

1305 if onclause is None: 

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

1307 else: 

1308 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1309 # not merged yet 

1310 self.onclause = coercions.expect( 

1311 roles.OnClauseRole, onclause 

1312 ).self_group(against=operators._asbool) 

1313 

1314 self.isouter = isouter 

1315 self.full = full 

1316 

1317 @util.ro_non_memoized_property 

1318 def description(self) -> str: 

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

1320 self.left.description, 

1321 id(self.left), 

1322 self.right.description, 

1323 id(self.right), 

1324 ) 

1325 

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

1327 return ( 

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

1329 # as well 

1330 hash(fromclause) == hash(self) 

1331 or self.left.is_derived_from(fromclause) 

1332 or self.right.is_derived_from(fromclause) 

1333 ) 

1334 

1335 def self_group( 

1336 self, against: Optional[OperatorType] = None 

1337 ) -> FromGrouping: 

1338 return FromGrouping(self) 

1339 

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

1341 def _populate_column_collection( 

1342 self, 

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

1344 primary_key: ColumnSet, 

1345 foreign_keys: Set[KeyedColumnElement[Any]], 

1346 ) -> None: 

1347 sqlutil = util.preloaded.sql_util 

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

1349 c for c in self.right.c 

1350 ] 

1351 

1352 primary_key.extend( 

1353 sqlutil.reduce_columns( 

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

1355 ) 

1356 ) 

1357 columns._populate_separate_keys( 

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

1359 ) 

1360 foreign_keys.update( 

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

1362 ) 

1363 

1364 def _copy_internals( 

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

1366 ) -> None: 

1367 # see Select._copy_internals() for similar concept 

1368 

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

1370 # determine the new FROM clauses 

1371 all_the_froms = set( 

1372 itertools.chain( 

1373 _from_objects(self.left), 

1374 _from_objects(self.right), 

1375 ) 

1376 ) 

1377 

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

1379 # cache used by the clone function 

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

1381 

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

1383 # ColumnClause with parent table referring to those 

1384 # replaced FromClause objects 

1385 def replace( 

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

1387 **kw: Any, 

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

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

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

1391 return newelem 

1392 return None 

1393 

1394 kw["replace"] = replace 

1395 

1396 # run normal _copy_internals. the clones for 

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

1398 # cache 

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

1400 

1401 self._reset_memoizations() 

1402 

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

1404 super()._refresh_for_new_column(column) 

1405 self.left._refresh_for_new_column(column) 

1406 self.right._refresh_for_new_column(column) 

1407 

1408 def _match_primaries( 

1409 self, 

1410 left: FromClause, 

1411 right: FromClause, 

1412 ) -> ColumnElement[bool]: 

1413 if isinstance(left, Join): 

1414 left_right = left.right 

1415 else: 

1416 left_right = None 

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

1418 

1419 @classmethod 

1420 def _join_condition( 

1421 cls, 

1422 a: FromClause, 

1423 b: FromClause, 

1424 *, 

1425 a_subset: Optional[FromClause] = None, 

1426 consider_as_foreign_keys: Optional[ 

1427 AbstractSet[ColumnClause[Any]] 

1428 ] = None, 

1429 ) -> ColumnElement[bool]: 

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

1431 

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

1433 

1434 """ 

1435 constraints = cls._joincond_scan_left_right( 

1436 a, a_subset, b, consider_as_foreign_keys 

1437 ) 

1438 

1439 if len(constraints) > 1: 

1440 cls._joincond_trim_constraints( 

1441 a, b, constraints, consider_as_foreign_keys 

1442 ) 

1443 

1444 if len(constraints) == 0: 

1445 if isinstance(b, FromGrouping): 

1446 hint = ( 

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

1448 "subquery using alias()?" 

1449 ) 

1450 else: 

1451 hint = "" 

1452 raise exc.NoForeignKeysError( 

1453 "Can't find any foreign key relationships " 

1454 "between '%s' and '%s'.%s" 

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

1456 ) 

1457 

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

1459 if len(crit) == 1: 

1460 return crit[0] 

1461 else: 

1462 return and_(*crit) 

1463 

1464 @classmethod 

1465 def _can_join( 

1466 cls, 

1467 left: FromClause, 

1468 right: FromClause, 

1469 *, 

1470 consider_as_foreign_keys: Optional[ 

1471 AbstractSet[ColumnClause[Any]] 

1472 ] = None, 

1473 ) -> bool: 

1474 if isinstance(left, Join): 

1475 left_right = left.right 

1476 else: 

1477 left_right = None 

1478 

1479 constraints = cls._joincond_scan_left_right( 

1480 a=left, 

1481 b=right, 

1482 a_subset=left_right, 

1483 consider_as_foreign_keys=consider_as_foreign_keys, 

1484 ) 

1485 

1486 return bool(constraints) 

1487 

1488 @classmethod 

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

1490 def _joincond_scan_left_right( 

1491 cls, 

1492 a: FromClause, 

1493 a_subset: Optional[FromClause], 

1494 b: FromClause, 

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

1496 ) -> collections.defaultdict[ 

1497 Optional[ForeignKeyConstraint], 

1498 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1499 ]: 

1500 sql_util = util.preloaded.sql_util 

1501 

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

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

1504 

1505 constraints: collections.defaultdict[ 

1506 Optional[ForeignKeyConstraint], 

1507 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1508 ] = collections.defaultdict(list) 

1509 

1510 for left in (a_subset, a): 

1511 if left is None: 

1512 continue 

1513 for fk in sorted( 

1514 b.foreign_keys, 

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

1516 ): 

1517 if ( 

1518 consider_as_foreign_keys is not None 

1519 and fk.parent not in consider_as_foreign_keys 

1520 ): 

1521 continue 

1522 try: 

1523 col = fk.get_referent(left) 

1524 except exc.NoReferenceError as nrte: 

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

1526 if nrte.table_name in table_names: 

1527 raise 

1528 else: 

1529 continue 

1530 

1531 if col is not None: 

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

1533 if left is not b: 

1534 for fk in sorted( 

1535 left.foreign_keys, 

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

1537 ): 

1538 if ( 

1539 consider_as_foreign_keys is not None 

1540 and fk.parent not in consider_as_foreign_keys 

1541 ): 

1542 continue 

1543 try: 

1544 col = fk.get_referent(b) 

1545 except exc.NoReferenceError as nrte: 

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

1547 if nrte.table_name in table_names: 

1548 raise 

1549 else: 

1550 continue 

1551 

1552 if col is not None: 

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

1554 if constraints: 

1555 break 

1556 return constraints 

1557 

1558 @classmethod 

1559 def _joincond_trim_constraints( 

1560 cls, 

1561 a: FromClause, 

1562 b: FromClause, 

1563 constraints: Dict[Any, Any], 

1564 consider_as_foreign_keys: Optional[Any], 

1565 ) -> None: 

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

1567 # to include just those FKCs that match exactly to 

1568 # "consider_as_foreign_keys". 

1569 if consider_as_foreign_keys: 

1570 for const in list(constraints): 

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

1572 consider_as_foreign_keys 

1573 ): 

1574 del constraints[const] 

1575 

1576 # if still multiple constraints, but 

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

1578 if len(constraints) > 1: 

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

1580 if len(dedupe) == 1: 

1581 key = list(constraints)[0] 

1582 constraints = {key: constraints[key]} 

1583 

1584 if len(constraints) != 1: 

1585 raise exc.AmbiguousForeignKeysError( 

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

1587 "tables have more than one foreign key " 

1588 "constraint relationship between them. " 

1589 "Please specify the 'onclause' of this " 

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

1591 ) 

1592 

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

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

1595 :class:`_expression.Join`. 

1596 

1597 E.g.:: 

1598 

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

1600 

1601 stmt = stmt.select() 

1602 

1603 The above will produce a SQL string resembling: 

1604 

1605 .. sourcecode:: sql 

1606 

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

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

1609 

1610 """ 

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

1612 

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

1614 def _anonymous_fromclause( 

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

1616 ) -> TODO_Any: 

1617 sqlutil = util.preloaded.sql_util 

1618 if flat: 

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

1620 left_name = name # will recurse 

1621 else: 

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

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

1624 else: 

1625 left_name = name 

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

1627 right_name = name # will recurse 

1628 else: 

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

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

1631 else: 

1632 right_name = name 

1633 left_a, right_a = ( 

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

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

1636 ) 

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

1638 sqlutil.ClauseAdapter(right_a) 

1639 ) 

1640 

1641 return left_a.join( 

1642 right_a, 

1643 adapter.traverse(self.onclause), 

1644 isouter=self.isouter, 

1645 full=self.full, 

1646 ) 

1647 else: 

1648 return ( 

1649 self.select() 

1650 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1651 .correlate(None) 

1652 .alias(name) 

1653 ) 

1654 

1655 @util.ro_non_memoized_property 

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

1657 return itertools.chain( 

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

1659 ) 

1660 

1661 @util.ro_non_memoized_property 

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

1663 self_list: List[FromClause] = [self] 

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

1665 

1666 

1667class NoInit: 

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

1669 raise NotImplementedError( 

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

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

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

1673 "selectable objects." 

1674 % ( 

1675 self.__class__.__name__, 

1676 self.__class__.__name__.lower(), 

1677 self.__class__.__name__.lower(), 

1678 ) 

1679 ) 

1680 

1681 

1682class LateralFromClause(NamedFromClause): 

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

1684 

1685 

1686# FromClause -> 

1687# AliasedReturnsRows 

1688# -> Alias only for FromClause 

1689# -> Subquery only for SelectBase 

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

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

1692# w/ non-deprecated coercion 

1693# -> TableSample -> only for FromClause 

1694 

1695 

1696class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1698 selectables.""" 

1699 

1700 _is_from_container = True 

1701 

1702 _supports_derived_columns = False 

1703 

1704 element: ReturnsRows 

1705 

1706 _traverse_internals: _TraverseInternalsType = [ 

1707 ("element", InternalTraversal.dp_clauseelement), 

1708 ("name", InternalTraversal.dp_anon_name), 

1709 ] 

1710 

1711 @classmethod 

1712 def _construct( 

1713 cls, 

1714 selectable: Any, 

1715 *, 

1716 name: Optional[str] = None, 

1717 **kw: Any, 

1718 ) -> Self: 

1719 obj = cls.__new__(cls) 

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

1721 return obj 

1722 

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

1724 self.element = coercions.expect( 

1725 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1726 ) 

1727 self.element = selectable 

1728 self._orig_name = name 

1729 if name is None: 

1730 if ( 

1731 isinstance(selectable, FromClause) 

1732 and selectable.named_with_column 

1733 ): 

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

1735 if isinstance(name, _anonymous_label): 

1736 name = None 

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

1738 self.name = name 

1739 

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

1741 super()._refresh_for_new_column(column) 

1742 self.element._refresh_for_new_column(column) 

1743 

1744 def _populate_column_collection( 

1745 self, 

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

1747 primary_key: ColumnSet, 

1748 foreign_keys: Set[KeyedColumnElement[Any]], 

1749 ) -> None: 

1750 self.element._generate_fromclause_column_proxies( 

1751 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1752 ) 

1753 

1754 @util.ro_non_memoized_property 

1755 def description(self) -> str: 

1756 name = self.name 

1757 if isinstance(name, _anonymous_label): 

1758 return "anon_1" 

1759 

1760 return name 

1761 

1762 @util.ro_non_memoized_property 

1763 def implicit_returning(self) -> bool: 

1764 return self.element.implicit_returning # type: ignore 

1765 

1766 @property 

1767 def original(self) -> ReturnsRows: 

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

1769 return self.element 

1770 

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

1772 if fromclause in self._cloned_set: 

1773 return True 

1774 return self.element.is_derived_from(fromclause) 

1775 

1776 def _copy_internals( 

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

1778 ) -> None: 

1779 existing_element = self.element 

1780 

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

1782 

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

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

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

1786 # performance. 

1787 if existing_element is not self.element: 

1788 self._reset_column_collection() 

1789 

1790 @property 

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

1792 return [self] 

1793 

1794 

1795class FromClauseAlias(AliasedReturnsRows): 

1796 element: FromClause 

1797 

1798 @util.ro_non_memoized_property 

1799 def description(self) -> str: 

1800 name = self.name 

1801 if isinstance(name, _anonymous_label): 

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

1803 

1804 return name 

1805 

1806 

1807class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1809 

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

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

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

1813 

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

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

1816 method available 

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

1818 

1819 .. seealso:: 

1820 

1821 :meth:`_expression.FromClause.alias` 

1822 

1823 """ 

1824 

1825 __visit_name__ = "alias" 

1826 

1827 inherit_cache = True 

1828 

1829 element: FromClause 

1830 

1831 @classmethod 

1832 def _factory( 

1833 cls, 

1834 selectable: FromClause, 

1835 name: Optional[str] = None, 

1836 flat: bool = False, 

1837 ) -> NamedFromClause: 

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

1839 name=name, flat=flat 

1840 ) 

1841 

1842 

1843class TableValuedAlias(LateralFromClause, Alias): 

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

1845 

1846 This construct provides for a SQL function that returns columns 

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

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

1849 method, e.g.: 

1850 

1851 .. sourcecode:: pycon+sql 

1852 

1853 >>> from sqlalchemy import select, func 

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

1855 ... "value" 

1856 ... ) 

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

1858 {printsql}SELECT anon_1.value 

1859 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1860 

1861 .. versionadded:: 1.4.0b2 

1862 

1863 .. seealso:: 

1864 

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

1866 

1867 """ # noqa: E501 

1868 

1869 __visit_name__ = "table_valued_alias" 

1870 

1871 _supports_derived_columns = True 

1872 _render_derived = False 

1873 _render_derived_w_types = False 

1874 joins_implicitly = False 

1875 

1876 _traverse_internals: _TraverseInternalsType = [ 

1877 ("element", InternalTraversal.dp_clauseelement), 

1878 ("name", InternalTraversal.dp_anon_name), 

1879 ("_tableval_type", InternalTraversal.dp_type), 

1880 ("_render_derived", InternalTraversal.dp_boolean), 

1881 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1882 ] 

1883 

1884 def _init( 

1885 self, 

1886 selectable: Any, 

1887 *, 

1888 name: Optional[str] = None, 

1889 table_value_type: Optional[TableValueType] = None, 

1890 joins_implicitly: bool = False, 

1891 ) -> None: 

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

1893 

1894 self.joins_implicitly = joins_implicitly 

1895 self._tableval_type = ( 

1896 type_api.TABLEVALUE 

1897 if table_value_type is None 

1898 else table_value_type 

1899 ) 

1900 

1901 @HasMemoized.memoized_attribute 

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

1903 """Return a column expression representing this 

1904 :class:`_sql.TableValuedAlias`. 

1905 

1906 This accessor is used to implement the 

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

1908 method for further details. 

1909 

1910 E.g.: 

1911 

1912 .. sourcecode:: pycon+sql 

1913 

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

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

1916 

1917 .. seealso:: 

1918 

1919 :meth:`_functions.FunctionElement.column_valued` 

1920 

1921 """ 

1922 

1923 return TableValuedColumn(self, self._tableval_type) 

1924 

1925 def alias( 

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

1927 ) -> TableValuedAlias: 

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

1929 

1930 This creates a distinct FROM object that will be distinguished 

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

1932 

1933 """ 

1934 

1935 tva: TableValuedAlias = TableValuedAlias._construct( 

1936 self, 

1937 name=name, 

1938 table_value_type=self._tableval_type, 

1939 joins_implicitly=self.joins_implicitly, 

1940 ) 

1941 

1942 if self._render_derived: 

1943 tva._render_derived = True 

1944 tva._render_derived_w_types = self._render_derived_w_types 

1945 

1946 return tva 

1947 

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

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

1950 set, so that it renders as LATERAL. 

1951 

1952 .. seealso:: 

1953 

1954 :func:`_expression.lateral` 

1955 

1956 """ 

1957 tva = self.alias(name=name) 

1958 tva._is_lateral = True 

1959 return tva 

1960 

1961 def render_derived( 

1962 self, 

1963 name: Optional[str] = None, 

1964 with_types: bool = False, 

1965 ) -> TableValuedAlias: 

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

1967 

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

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

1970 

1971 .. sourcecode:: pycon+sql 

1972 

1973 >>> print( 

1974 ... select( 

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

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

1977 ... .render_derived() 

1978 ... ) 

1979 ... ) 

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

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

1982 

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

1984 the alias expression (this syntax currently applies to the 

1985 PostgreSQL database): 

1986 

1987 .. sourcecode:: pycon+sql 

1988 

1989 >>> print( 

1990 ... select( 

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

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

1993 ... .render_derived(with_types=True) 

1994 ... ) 

1995 ... ) 

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

1997 AS anon_1(a INTEGER, b VARCHAR) 

1998 

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

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

2001 

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

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

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

2005 

2006 """ # noqa: E501 

2007 

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

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

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

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

2012 # (just saw it happen on CI) 

2013 

2014 # construct against original to prevent memory growth 

2015 # for repeated generations 

2016 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2017 self.element, 

2018 name=name, 

2019 table_value_type=self._tableval_type, 

2020 joins_implicitly=self.joins_implicitly, 

2021 ) 

2022 new_alias._render_derived = True 

2023 new_alias._render_derived_w_types = with_types 

2024 return new_alias 

2025 

2026 

2027class Lateral(FromClauseAlias, LateralFromClause): 

2028 """Represent a LATERAL subquery. 

2029 

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

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

2032 method available 

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

2034 

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

2036 PostgreSQL versions provide support for this keyword. 

2037 

2038 .. seealso:: 

2039 

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

2041 

2042 """ 

2043 

2044 __visit_name__ = "lateral" 

2045 _is_lateral = True 

2046 

2047 inherit_cache = True 

2048 

2049 @classmethod 

2050 def _factory( 

2051 cls, 

2052 selectable: Union[SelectBase, _FromClauseArgument], 

2053 name: Optional[str] = None, 

2054 ) -> LateralFromClause: 

2055 return coercions.expect( 

2056 roles.FromClauseRole, selectable, explicit_subquery=True 

2057 ).lateral(name=name) 

2058 

2059 

2060class TableSample(FromClauseAlias): 

2061 """Represent a TABLESAMPLE clause. 

2062 

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

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

2065 method 

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

2067 

2068 .. seealso:: 

2069 

2070 :func:`_expression.tablesample` 

2071 

2072 """ 

2073 

2074 __visit_name__ = "tablesample" 

2075 

2076 _traverse_internals: _TraverseInternalsType = ( 

2077 AliasedReturnsRows._traverse_internals 

2078 + [ 

2079 ("sampling", InternalTraversal.dp_clauseelement), 

2080 ("seed", InternalTraversal.dp_clauseelement), 

2081 ] 

2082 ) 

2083 

2084 @classmethod 

2085 def _factory( 

2086 cls, 

2087 selectable: _FromClauseArgument, 

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

2089 name: Optional[str] = None, 

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

2091 ) -> TableSample: 

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

2093 sampling, name=name, seed=seed 

2094 ) 

2095 

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

2097 def _init( # type: ignore[override] 

2098 self, 

2099 selectable: Any, 

2100 *, 

2101 name: Optional[str] = None, 

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

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

2104 ) -> None: 

2105 assert sampling is not None 

2106 functions = util.preloaded.sql_functions 

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

2108 sampling = functions.func.system(sampling) 

2109 

2110 self.sampling: Function[Any] = sampling 

2111 self.seed = seed 

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

2113 

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

2115 return self.sampling 

2116 

2117 

2118class CTE( 

2119 roles.DMLTableRole, 

2120 roles.IsCTERole, 

2121 Generative, 

2122 HasPrefixes, 

2123 HasSuffixes, 

2124 AliasedReturnsRows, 

2125): 

2126 """Represent a Common Table Expression. 

2127 

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

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

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

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

2132 :class:`_sql.Update` and 

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

2134 usage details on CTEs. 

2135 

2136 .. seealso:: 

2137 

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

2139 

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

2141 

2142 """ 

2143 

2144 __visit_name__ = "cte" 

2145 

2146 _traverse_internals: _TraverseInternalsType = ( 

2147 AliasedReturnsRows._traverse_internals 

2148 + [ 

2149 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2150 ("_restates", InternalTraversal.dp_clauseelement), 

2151 ("recursive", InternalTraversal.dp_boolean), 

2152 ("nesting", InternalTraversal.dp_boolean), 

2153 ] 

2154 + HasPrefixes._has_prefixes_traverse_internals 

2155 + HasSuffixes._has_suffixes_traverse_internals 

2156 ) 

2157 

2158 element: HasCTE 

2159 

2160 @classmethod 

2161 def _factory( 

2162 cls, 

2163 selectable: HasCTE, 

2164 name: Optional[str] = None, 

2165 recursive: bool = False, 

2166 ) -> CTE: 

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

2168 or Common Table Expression instance. 

2169 

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

2171 

2172 """ 

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

2174 name=name, recursive=recursive 

2175 ) 

2176 

2177 def _init( 

2178 self, 

2179 selectable: HasCTE, 

2180 *, 

2181 name: Optional[str] = None, 

2182 recursive: bool = False, 

2183 nesting: bool = False, 

2184 _cte_alias: Optional[CTE] = None, 

2185 _restates: Optional[CTE] = None, 

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

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

2188 ) -> None: 

2189 self.recursive = recursive 

2190 self.nesting = nesting 

2191 self._cte_alias = _cte_alias 

2192 # Keep recursivity reference with union/union_all 

2193 self._restates = _restates 

2194 if _prefixes: 

2195 self._prefixes = _prefixes 

2196 if _suffixes: 

2197 self._suffixes = _suffixes 

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

2199 

2200 def _populate_column_collection( 

2201 self, 

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

2203 primary_key: ColumnSet, 

2204 foreign_keys: Set[KeyedColumnElement[Any]], 

2205 ) -> None: 

2206 if self._cte_alias is not None: 

2207 self._cte_alias._generate_fromclause_column_proxies( 

2208 self, 

2209 columns, 

2210 primary_key=primary_key, 

2211 foreign_keys=foreign_keys, 

2212 ) 

2213 else: 

2214 self.element._generate_fromclause_column_proxies( 

2215 self, 

2216 columns, 

2217 primary_key=primary_key, 

2218 foreign_keys=foreign_keys, 

2219 ) 

2220 

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

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

2223 :class:`_expression.CTE`. 

2224 

2225 This method is a CTE-specific specialization of the 

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

2227 

2228 .. seealso:: 

2229 

2230 :ref:`tutorial_using_aliases` 

2231 

2232 :func:`_expression.alias` 

2233 

2234 """ 

2235 return CTE._construct( 

2236 self.element, 

2237 name=name, 

2238 recursive=self.recursive, 

2239 nesting=self.nesting, 

2240 _cte_alias=self, 

2241 _prefixes=self._prefixes, 

2242 _suffixes=self._suffixes, 

2243 ) 

2244 

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

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

2247 of the original CTE against the given selectables provided 

2248 as positional arguments. 

2249 

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

2251 UNION. 

2252 

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

2254 

2255 .. seealso:: 

2256 

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

2258 

2259 """ 

2260 assert is_select_statement( 

2261 self.element 

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

2263 

2264 return CTE._construct( 

2265 self.element.union(*other), 

2266 name=self.name, 

2267 recursive=self.recursive, 

2268 nesting=self.nesting, 

2269 _restates=self, 

2270 _prefixes=self._prefixes, 

2271 _suffixes=self._suffixes, 

2272 ) 

2273 

2274 def union_all( 

2275 self, *other: _SelectStatementForCompoundArgument[Any] 

2276 ) -> CTE: 

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

2278 of the original CTE against the given selectables provided 

2279 as positional arguments. 

2280 

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

2282 UNION. 

2283 

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

2285 

2286 .. seealso:: 

2287 

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

2289 

2290 """ 

2291 

2292 assert is_select_statement( 

2293 self.element 

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

2295 

2296 return CTE._construct( 

2297 self.element.union_all(*other), 

2298 name=self.name, 

2299 recursive=self.recursive, 

2300 nesting=self.nesting, 

2301 _restates=self, 

2302 _prefixes=self._prefixes, 

2303 _suffixes=self._suffixes, 

2304 ) 

2305 

2306 def _get_reference_cte(self) -> CTE: 

2307 """ 

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

2309 Updated CTEs should still refer to the original CTE. 

2310 This function returns this reference identifier. 

2311 """ 

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

2313 

2314 

2315class _CTEOpts(NamedTuple): 

2316 nesting: bool 

2317 

2318 

2319class _ColumnsPlusNames(NamedTuple): 

2320 required_label_name: Optional[str] 

2321 """ 

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

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

2324 """ 

2325 

2326 proxy_key: Optional[str] 

2327 """ 

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

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

2330 select.selected_columns collection 

2331 """ 

2332 

2333 fallback_label_name: Optional[str] 

2334 """ 

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

2336 we have to render a label even though 

2337 required_label_name was not given 

2338 """ 

2339 

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

2341 """ 

2342 the ColumnElement itself 

2343 """ 

2344 

2345 repeated: bool 

2346 """ 

2347 True if this is a duplicate of a previous column 

2348 in the list of columns 

2349 """ 

2350 

2351 

2352class SelectsRows(ReturnsRows): 

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

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

2355 

2356 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2357 

2358 def _generate_columns_plus_names( 

2359 self, 

2360 anon_for_dupe_key: bool, 

2361 cols: Optional[_SelectIterable] = None, 

2362 ) -> List[_ColumnsPlusNames]: 

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

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

2365 on a :class:`.FromClause`. 

2366 

2367 This is distinct from the _column_naming_convention generator that's 

2368 intended for population of the Select.selected_columns collection, 

2369 different rules. the collection returned here calls upon the 

2370 _column_naming_convention as well. 

2371 

2372 """ 

2373 

2374 if cols is None: 

2375 cols = self._all_selected_columns 

2376 

2377 key_naming_convention = SelectState._column_naming_convention( 

2378 self._label_style 

2379 ) 

2380 

2381 names = {} 

2382 

2383 result: List[_ColumnsPlusNames] = [] 

2384 result_append = result.append 

2385 

2386 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2387 label_style_none = self._label_style is LABEL_STYLE_NONE 

2388 

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

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

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

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

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

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

2395 dedupe_hash = 1 

2396 

2397 for c in cols: 

2398 repeated = False 

2399 

2400 if not c._render_label_in_columns_clause: 

2401 effective_name = required_label_name = fallback_label_name = ( 

2402 None 

2403 ) 

2404 elif label_style_none: 

2405 if TYPE_CHECKING: 

2406 assert is_column_element(c) 

2407 

2408 effective_name = required_label_name = None 

2409 fallback_label_name = c._non_anon_label or c._anon_name_label 

2410 else: 

2411 if TYPE_CHECKING: 

2412 assert is_column_element(c) 

2413 

2414 if table_qualified: 

2415 required_label_name = effective_name = ( 

2416 fallback_label_name 

2417 ) = c._tq_label 

2418 else: 

2419 effective_name = fallback_label_name = c._non_anon_label 

2420 required_label_name = None 

2421 

2422 if effective_name is None: 

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

2424 # not need _expression_label but it isn't 

2425 # giving us a clue when to use anon_label instead 

2426 expr_label = c._expression_label 

2427 if expr_label is None: 

2428 repeated = c._anon_name_label in names 

2429 names[c._anon_name_label] = c 

2430 effective_name = required_label_name = None 

2431 

2432 if repeated: 

2433 # here, "required_label_name" is sent as 

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

2435 if table_qualified: 

2436 fallback_label_name = ( 

2437 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2438 ) 

2439 dedupe_hash += 1 

2440 else: 

2441 fallback_label_name = c._dedupe_anon_label_idx( 

2442 dedupe_hash 

2443 ) 

2444 dedupe_hash += 1 

2445 else: 

2446 fallback_label_name = c._anon_name_label 

2447 else: 

2448 required_label_name = effective_name = ( 

2449 fallback_label_name 

2450 ) = expr_label 

2451 

2452 if effective_name is not None: 

2453 if TYPE_CHECKING: 

2454 assert is_column_element(c) 

2455 

2456 if effective_name in names: 

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

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

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

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

2461 # different column under the same name. apply 

2462 # disambiguating label 

2463 if table_qualified: 

2464 required_label_name = fallback_label_name = ( 

2465 c._anon_tq_label 

2466 ) 

2467 else: 

2468 required_label_name = fallback_label_name = ( 

2469 c._anon_name_label 

2470 ) 

2471 

2472 if anon_for_dupe_key and required_label_name in names: 

2473 # here, c._anon_tq_label is definitely unique to 

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

2475 # this should always be true. 

2476 # this is also an infrequent codepath because 

2477 # you need two levels of duplication to be here 

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

2479 

2480 # the column under the disambiguating label is 

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

2482 # subsequent occurrences of the column so that the 

2483 # original stays non-ambiguous 

2484 if table_qualified: 

2485 required_label_name = fallback_label_name = ( 

2486 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2487 ) 

2488 dedupe_hash += 1 

2489 else: 

2490 required_label_name = fallback_label_name = ( 

2491 c._dedupe_anon_label_idx(dedupe_hash) 

2492 ) 

2493 dedupe_hash += 1 

2494 repeated = True 

2495 else: 

2496 names[required_label_name] = c 

2497 elif anon_for_dupe_key: 

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

2499 # label so that the original stays non-ambiguous 

2500 if table_qualified: 

2501 required_label_name = fallback_label_name = ( 

2502 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2503 ) 

2504 dedupe_hash += 1 

2505 else: 

2506 required_label_name = fallback_label_name = ( 

2507 c._dedupe_anon_label_idx(dedupe_hash) 

2508 ) 

2509 dedupe_hash += 1 

2510 repeated = True 

2511 else: 

2512 names[effective_name] = c 

2513 

2514 result_append( 

2515 _ColumnsPlusNames( 

2516 required_label_name, 

2517 key_naming_convention(c), 

2518 fallback_label_name, 

2519 c, 

2520 repeated, 

2521 ) 

2522 ) 

2523 

2524 return result 

2525 

2526 

2527class HasCTE(roles.HasCTERole, SelectsRows): 

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

2529 

2530 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2531 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2532 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2533 ] 

2534 

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

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

2537 

2538 name_cte_columns: bool = False 

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

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

2541 

2542 .. versionadded:: 2.0.42 

2543 

2544 """ 

2545 

2546 @_generative 

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

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

2549 

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

2551 the parent statement such that they will each be unconditionally 

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

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

2554 

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

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

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

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

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

2560 statement. 

2561 

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

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

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

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

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

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

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

2569 larger statement. 

2570 

2571 E.g.:: 

2572 

2573 from sqlalchemy import table, column, select 

2574 

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

2576 

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

2578 

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

2580 

2581 Would render: 

2582 

2583 .. sourcecode:: sql 

2584 

2585 WITH anon_1 AS ( 

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

2587 ) 

2588 SELECT t.c1, t.c2 

2589 FROM t 

2590 

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

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

2593 statement. 

2594 

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

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

2597 

2598 from sqlalchemy import table, column 

2599 from sqlalchemy.dialects.postgresql import insert 

2600 

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

2602 

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

2604 

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

2606 update_statement = insert_stmt.on_conflict_do_update( 

2607 index_elements=[t.c.c1], 

2608 set_={ 

2609 "c1": insert_stmt.excluded.c1, 

2610 "c2": insert_stmt.excluded.c2, 

2611 }, 

2612 ).add_cte(delete_statement_cte) 

2613 

2614 print(update_statement) 

2615 

2616 The above statement renders as: 

2617 

2618 .. sourcecode:: sql 

2619 

2620 WITH deletions AS ( 

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

2622 ) 

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

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

2625 

2626 .. versionadded:: 1.4.21 

2627 

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

2629 

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

2631 

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

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

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

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

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

2637 this statement when this flag is given. 

2638 

2639 .. versionadded:: 2.0 

2640 

2641 .. seealso:: 

2642 

2643 :paramref:`.HasCTE.cte.nesting` 

2644 

2645 

2646 """ # noqa: E501 

2647 opt = _CTEOpts(nest_here) 

2648 for cte in ctes: 

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

2650 self._independent_ctes += (cte,) 

2651 self._independent_ctes_opts += (opt,) 

2652 return self 

2653 

2654 def cte( 

2655 self, 

2656 name: Optional[str] = None, 

2657 recursive: bool = False, 

2658 nesting: bool = False, 

2659 ) -> CTE: 

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

2661 or Common Table Expression instance. 

2662 

2663 Common table expressions are a SQL standard whereby SELECT 

2664 statements can draw upon secondary statements specified along 

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

2666 Special semantics regarding UNION can also be employed to 

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

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

2669 

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

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

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

2673 CTE rows. 

2674 

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

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

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

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

2679 

2680 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2682 method may be 

2683 used to establish these. 

2684 

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

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

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

2688 compile time. 

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

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

2691 conjunction with UNION ALL in order to derive rows 

2692 from those already selected. 

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

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

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

2696 :paramref:`.HasCTE.add_cte.nest_here` 

2697 parameter may also be used to more carefully 

2698 control the exact placement of a particular CTE. 

2699 

2700 .. versionadded:: 1.4.24 

2701 

2702 .. seealso:: 

2703 

2704 :meth:`.HasCTE.add_cte` 

2705 

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

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

2708 as well as additional examples. 

2709 

2710 Example 1, non recursive:: 

2711 

2712 from sqlalchemy import ( 

2713 Table, 

2714 Column, 

2715 String, 

2716 Integer, 

2717 MetaData, 

2718 select, 

2719 func, 

2720 ) 

2721 

2722 metadata = MetaData() 

2723 

2724 orders = Table( 

2725 "orders", 

2726 metadata, 

2727 Column("region", String), 

2728 Column("amount", Integer), 

2729 Column("product", String), 

2730 Column("quantity", Integer), 

2731 ) 

2732 

2733 regional_sales = ( 

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

2735 .group_by(orders.c.region) 

2736 .cte("regional_sales") 

2737 ) 

2738 

2739 

2740 top_regions = ( 

2741 select(regional_sales.c.region) 

2742 .where( 

2743 regional_sales.c.total_sales 

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

2745 ) 

2746 .cte("top_regions") 

2747 ) 

2748 

2749 statement = ( 

2750 select( 

2751 orders.c.region, 

2752 orders.c.product, 

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

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

2755 ) 

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

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

2758 ) 

2759 

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

2761 

2762 Example 2, WITH RECURSIVE:: 

2763 

2764 from sqlalchemy import ( 

2765 Table, 

2766 Column, 

2767 String, 

2768 Integer, 

2769 MetaData, 

2770 select, 

2771 func, 

2772 ) 

2773 

2774 metadata = MetaData() 

2775 

2776 parts = Table( 

2777 "parts", 

2778 metadata, 

2779 Column("part", String), 

2780 Column("sub_part", String), 

2781 Column("quantity", Integer), 

2782 ) 

2783 

2784 included_parts = ( 

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

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

2787 .cte(recursive=True) 

2788 ) 

2789 

2790 

2791 incl_alias = included_parts.alias() 

2792 parts_alias = parts.alias() 

2793 included_parts = included_parts.union_all( 

2794 select( 

2795 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2797 ) 

2798 

2799 statement = select( 

2800 included_parts.c.sub_part, 

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

2802 ).group_by(included_parts.c.sub_part) 

2803 

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

2805 

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

2807 

2808 from datetime import date 

2809 from sqlalchemy import ( 

2810 MetaData, 

2811 Table, 

2812 Column, 

2813 Integer, 

2814 Date, 

2815 select, 

2816 literal, 

2817 and_, 

2818 exists, 

2819 ) 

2820 

2821 metadata = MetaData() 

2822 

2823 visitors = Table( 

2824 "visitors", 

2825 metadata, 

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

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

2828 Column("count", Integer), 

2829 ) 

2830 

2831 # add 5 visitors for the product_id == 1 

2832 product_id = 1 

2833 day = date.today() 

2834 count = 5 

2835 

2836 update_cte = ( 

2837 visitors.update() 

2838 .where( 

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

2840 ) 

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

2842 .returning(literal(1)) 

2843 .cte("update_cte") 

2844 ) 

2845 

2846 upsert = visitors.insert().from_select( 

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

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

2849 ~exists(update_cte.select()) 

2850 ), 

2851 ) 

2852 

2853 connection.execute(upsert) 

2854 

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

2856 

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

2858 

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

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

2861 "value_a", nesting=True 

2862 ) 

2863 

2864 # Nesting CTEs takes ascendency locally 

2865 # over the CTEs at a higher level 

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

2867 

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

2869 

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

2871 shown with inline parameters below as: 

2872 

2873 .. sourcecode:: sql 

2874 

2875 WITH 

2876 value_a AS 

2877 (SELECT 'root' AS n), 

2878 value_b AS 

2879 (WITH value_a AS 

2880 (SELECT 'nesting' AS n) 

2881 SELECT value_a.n AS n FROM value_a) 

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

2883 FROM value_a, value_b 

2884 

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

2886 as follows (SQLAlchemy 2.0 and above):: 

2887 

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

2889 

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

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

2892 

2893 # Nesting CTEs takes ascendency locally 

2894 # over the CTEs at a higher level 

2895 value_b = ( 

2896 select(value_a_nested.c.n) 

2897 .add_cte(value_a_nested, nest_here=True) 

2898 .cte("value_b") 

2899 ) 

2900 

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

2902 

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

2904 

2905 edge = Table( 

2906 "edge", 

2907 metadata, 

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

2909 Column("left", Integer), 

2910 Column("right", Integer), 

2911 ) 

2912 

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

2914 

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

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

2917 ) 

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

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

2920 ) 

2921 

2922 subgraph_cte = root_node.union(left_edge, right_edge) 

2923 

2924 subgraph = select(subgraph_cte) 

2925 

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

2927 

2928 .. sourcecode:: sql 

2929 

2930 WITH RECURSIVE nodes(node) AS ( 

2931 SELECT 1 AS node 

2932 UNION 

2933 SELECT edge."left" AS "left" 

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

2935 UNION 

2936 SELECT edge."right" AS "right" 

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

2938 ) 

2939 SELECT nodes.node FROM nodes 

2940 

2941 .. seealso:: 

2942 

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

2944 :meth:`_expression.HasCTE.cte`. 

2945 

2946 """ # noqa: E501 

2947 return CTE._construct( 

2948 self, name=name, recursive=recursive, nesting=nesting 

2949 ) 

2950 

2951 

2952class Subquery(AliasedReturnsRows): 

2953 """Represent a subquery of a SELECT. 

2954 

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

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

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

2958 :class:`_expression.SelectBase` subclass 

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

2960 :class:`_expression.CompoundSelect`, and 

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

2962 it represents the 

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

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

2965 

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

2967 :class:`_expression.Alias` 

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

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

2970 :class:`_expression.Alias` always 

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

2972 :class:`.Subquery` 

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

2974 

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

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

2977 statement. 

2978 

2979 """ 

2980 

2981 __visit_name__ = "subquery" 

2982 

2983 _is_subquery = True 

2984 

2985 inherit_cache = True 

2986 

2987 element: SelectBase 

2988 

2989 @classmethod 

2990 def _factory( 

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

2992 ) -> Subquery: 

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

2994 

2995 return coercions.expect( 

2996 roles.SelectStatementRole, selectable 

2997 ).subquery(name=name) 

2998 

2999 @util.deprecated( 

3000 "1.4", 

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

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

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

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

3005 ":func:`_expression.select` " 

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

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

3008 ) 

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

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

3011 

3012 

3013class FromGrouping(GroupedElement, FromClause): 

3014 """Represent a grouping of a FROM clause""" 

3015 

3016 _traverse_internals: _TraverseInternalsType = [ 

3017 ("element", InternalTraversal.dp_clauseelement) 

3018 ] 

3019 

3020 element: FromClause 

3021 

3022 def __init__(self, element: FromClause): 

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

3024 

3025 @util.ro_non_memoized_property 

3026 def columns( 

3027 self, 

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

3029 return self.element.columns 

3030 

3031 @util.ro_non_memoized_property 

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

3033 return self.element.columns 

3034 

3035 @property 

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

3037 return self.element.primary_key 

3038 

3039 @property 

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

3041 return self.element.foreign_keys 

3042 

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

3044 return self.element.is_derived_from(fromclause) 

3045 

3046 def alias( 

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

3048 ) -> NamedFromGrouping: 

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

3050 

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

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

3053 

3054 @util.ro_non_memoized_property 

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

3056 return self.element._hide_froms 

3057 

3058 @util.ro_non_memoized_property 

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

3060 return self.element._from_objects 

3061 

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

3063 return {"element": self.element} 

3064 

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

3066 self.element = state["element"] 

3067 

3068 if TYPE_CHECKING: 

3069 

3070 def self_group( 

3071 self, against: Optional[OperatorType] = None 

3072 ) -> Self: ... 

3073 

3074 

3075class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3077 

3078 .. versionadded:: 2.0 

3079 

3080 """ 

3081 

3082 inherit_cache = True 

3083 

3084 if TYPE_CHECKING: 

3085 

3086 def self_group( 

3087 self, against: Optional[OperatorType] = None 

3088 ) -> Self: ... 

3089 

3090 

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

3092 """Represents a minimal "table" construct. 

3093 

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

3095 collection of columns, which are typically produced 

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

3097 

3098 from sqlalchemy import table, column 

3099 

3100 user = table( 

3101 "user", 

3102 column("id"), 

3103 column("name"), 

3104 column("description"), 

3105 ) 

3106 

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

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

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

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

3111 

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

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

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

3115 It's useful 

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

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

3118 is not on hand. 

3119 

3120 """ 

3121 

3122 __visit_name__ = "table" 

3123 

3124 _traverse_internals: _TraverseInternalsType = [ 

3125 ( 

3126 "columns", 

3127 InternalTraversal.dp_fromclause_canonical_column_collection, 

3128 ), 

3129 ("name", InternalTraversal.dp_string), 

3130 ("schema", InternalTraversal.dp_string), 

3131 ] 

3132 

3133 _is_table = True 

3134 

3135 fullname: str 

3136 

3137 implicit_returning = False 

3138 """:class:`_expression.TableClause` 

3139 doesn't support having a primary key or column 

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

3141 

3142 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3143 

3144 @util.ro_memoized_property 

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

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

3147 return None 

3148 

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

3150 super().__init__() 

3151 self.name = name 

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

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

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

3155 for c in columns: 

3156 self.append_column(c) 

3157 

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

3159 if schema is not None: 

3160 self.schema = schema 

3161 if self.schema is not None: 

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

3163 else: 

3164 self.fullname = self.name 

3165 if kw: 

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

3167 

3168 if TYPE_CHECKING: 

3169 

3170 @util.ro_non_memoized_property 

3171 def columns( 

3172 self, 

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

3174 

3175 @util.ro_non_memoized_property 

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

3177 

3178 def __str__(self) -> str: 

3179 if self.schema is not None: 

3180 return self.schema + "." + self.name 

3181 else: 

3182 return self.name 

3183 

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

3185 pass 

3186 

3187 @util.ro_memoized_property 

3188 def description(self) -> str: 

3189 return self.name 

3190 

3191 def _insert_col_impl( 

3192 self, 

3193 c: ColumnClause[Any], 

3194 *, 

3195 index: Optional[int] = None, 

3196 ) -> None: 

3197 existing = c.table 

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

3199 raise exc.ArgumentError( 

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

3201 % (c.key, existing) 

3202 ) 

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

3204 c.table = self 

3205 

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

3207 self._insert_col_impl(c) 

3208 

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

3210 self._insert_col_impl(c, index=index) 

3211 

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

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

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

3215 :class:`_expression.TableClause`. 

3216 

3217 E.g.:: 

3218 

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

3220 

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

3222 

3223 """ 

3224 

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

3226 

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

3228 def update(self) -> Update: 

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

3230 :class:`_expression.TableClause`. 

3231 

3232 E.g.:: 

3233 

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

3235 

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

3237 

3238 """ 

3239 return util.preloaded.sql_dml.Update( 

3240 self, 

3241 ) 

3242 

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

3244 def delete(self) -> Delete: 

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

3246 :class:`_expression.TableClause`. 

3247 

3248 E.g.:: 

3249 

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

3251 

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

3253 

3254 """ 

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

3256 

3257 @util.ro_non_memoized_property 

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

3259 return [self] 

3260 

3261 

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

3263 

3264 

3265class ForUpdateArg(ClauseElement): 

3266 _traverse_internals: _TraverseInternalsType = [ 

3267 ("of", InternalTraversal.dp_clauseelement_list), 

3268 ("nowait", InternalTraversal.dp_boolean), 

3269 ("read", InternalTraversal.dp_boolean), 

3270 ("skip_locked", InternalTraversal.dp_boolean), 

3271 ("key_share", InternalTraversal.dp_boolean), 

3272 ] 

3273 

3274 of: Optional[Sequence[ClauseElement]] 

3275 nowait: bool 

3276 read: bool 

3277 skip_locked: bool 

3278 

3279 @classmethod 

3280 def _from_argument( 

3281 cls, with_for_update: ForUpdateParameter 

3282 ) -> Optional[ForUpdateArg]: 

3283 if isinstance(with_for_update, ForUpdateArg): 

3284 return with_for_update 

3285 elif with_for_update in (None, False): 

3286 return None 

3287 elif with_for_update is True: 

3288 return ForUpdateArg() 

3289 else: 

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

3291 

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

3293 return ( 

3294 isinstance(other, ForUpdateArg) 

3295 and other.nowait == self.nowait 

3296 and other.read == self.read 

3297 and other.skip_locked == self.skip_locked 

3298 and other.key_share == self.key_share 

3299 and other.of is self.of 

3300 ) 

3301 

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

3303 return not self.__eq__(other) 

3304 

3305 def __hash__(self) -> int: 

3306 return id(self) 

3307 

3308 def __init__( 

3309 self, 

3310 *, 

3311 nowait: bool = False, 

3312 read: bool = False, 

3313 of: Optional[_ForUpdateOfArgument] = None, 

3314 skip_locked: bool = False, 

3315 key_share: bool = False, 

3316 ): 

3317 """Represents arguments specified to 

3318 :meth:`_expression.Select.for_update`. 

3319 

3320 """ 

3321 

3322 self.nowait = nowait 

3323 self.read = read 

3324 self.skip_locked = skip_locked 

3325 self.key_share = key_share 

3326 if of is not None: 

3327 self.of = [ 

3328 coercions.expect(roles.ColumnsClauseRole, elem) 

3329 for elem in util.to_list(of) 

3330 ] 

3331 else: 

3332 self.of = None 

3333 

3334 

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

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

3337 in a statement. 

3338 

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

3340 :func:`_expression.values` function. 

3341 

3342 .. versionadded:: 1.4 

3343 

3344 """ 

3345 

3346 __visit_name__ = "values" 

3347 

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

3349 

3350 _unnamed: bool 

3351 _traverse_internals: _TraverseInternalsType = [ 

3352 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3353 ("_data", InternalTraversal.dp_dml_multi_values), 

3354 ("name", InternalTraversal.dp_string), 

3355 ("literal_binds", InternalTraversal.dp_boolean), 

3356 ] + HasCTE._has_ctes_traverse_internals 

3357 

3358 name_cte_columns = True 

3359 

3360 def __init__( 

3361 self, 

3362 *columns: ColumnClause[Any], 

3363 name: Optional[str] = None, 

3364 literal_binds: bool = False, 

3365 ): 

3366 super().__init__() 

3367 self._column_args = columns 

3368 

3369 if name is None: 

3370 self._unnamed = True 

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

3372 else: 

3373 self._unnamed = False 

3374 self.name = name 

3375 self.literal_binds = literal_binds 

3376 self.named_with_column = not self._unnamed 

3377 

3378 @property 

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

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

3381 

3382 @util.ro_non_memoized_property 

3383 def _all_selected_columns(self) -> _SelectIterable: 

3384 return self._column_args 

3385 

3386 @_generative 

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

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

3389 construct that is a copy of this 

3390 one with the given name. 

3391 

3392 This method is a VALUES-specific specialization of the 

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

3394 

3395 .. seealso:: 

3396 

3397 :ref:`tutorial_using_aliases` 

3398 

3399 :func:`_expression.alias` 

3400 

3401 """ 

3402 non_none_name: str 

3403 

3404 if name is None: 

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

3406 else: 

3407 non_none_name = name 

3408 

3409 self.name = non_none_name 

3410 self.named_with_column = True 

3411 self._unnamed = False 

3412 return self 

3413 

3414 @_generative 

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

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

3417 so that 

3418 it renders as LATERAL. 

3419 

3420 .. seealso:: 

3421 

3422 :func:`_expression.lateral` 

3423 

3424 """ 

3425 non_none_name: str 

3426 

3427 if name is None: 

3428 non_none_name = self.name 

3429 else: 

3430 non_none_name = name 

3431 

3432 self._is_lateral = True 

3433 self.name = non_none_name 

3434 self._unnamed = False 

3435 return self 

3436 

3437 @_generative 

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

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

3440 adding the given data to the data list. 

3441 

3442 E.g.:: 

3443 

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

3445 

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

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

3448 constructor. 

3449 

3450 """ 

3451 

3452 self._data += (values,) 

3453 return self 

3454 

3455 def scalar_values(self) -> ScalarValues: 

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

3457 COLUMN element in a statement. 

3458 

3459 .. versionadded:: 2.0.0b4 

3460 

3461 """ 

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

3463 

3464 def _populate_column_collection( 

3465 self, 

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

3467 primary_key: ColumnSet, 

3468 foreign_keys: Set[KeyedColumnElement[Any]], 

3469 ) -> None: 

3470 for c in self._column_args: 

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

3472 _, c = c._make_proxy( 

3473 self, primary_key=primary_key, foreign_keys=foreign_keys 

3474 ) 

3475 else: 

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

3477 # no memoizations of other FROM clauses. 

3478 # see test_values.py -> test_auto_proxy_select_direct_col 

3479 c._reset_memoizations() 

3480 columns.add(c) 

3481 c.table = self 

3482 

3483 @util.ro_non_memoized_property 

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

3485 return [self] 

3486 

3487 

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

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

3490 COLUMN element in a statement. 

3491 

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

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

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

3495 an ``IN`` or ``NOT IN`` condition. 

3496 

3497 .. versionadded:: 2.0.0b4 

3498 

3499 """ 

3500 

3501 __visit_name__ = "scalar_values" 

3502 

3503 _traverse_internals: _TraverseInternalsType = [ 

3504 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3505 ("_data", InternalTraversal.dp_dml_multi_values), 

3506 ("literal_binds", InternalTraversal.dp_boolean), 

3507 ] 

3508 

3509 def __init__( 

3510 self, 

3511 columns: Sequence[ColumnClause[Any]], 

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

3513 literal_binds: bool, 

3514 ): 

3515 super().__init__() 

3516 self._column_args = columns 

3517 self._data = data 

3518 self.literal_binds = literal_binds 

3519 

3520 @property 

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

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

3523 

3524 def __clause_element__(self) -> ScalarValues: 

3525 return self 

3526 

3527 if TYPE_CHECKING: 

3528 

3529 def self_group( 

3530 self, against: Optional[OperatorType] = None 

3531 ) -> Self: ... 

3532 

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

3534 

3535 

3536class SelectBase( 

3537 roles.SelectStatementRole, 

3538 roles.DMLSelectRole, 

3539 roles.CompoundElementRole, 

3540 roles.InElementRole, 

3541 HasCTE, 

3542 SupportsCloneAnnotations, 

3543 Selectable, 

3544): 

3545 """Base class for SELECT statements. 

3546 

3547 

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

3549 :class:`_expression.CompoundSelect` and 

3550 :class:`_expression.TextualSelect`. 

3551 

3552 

3553 """ 

3554 

3555 _is_select_base = True 

3556 is_select = True 

3557 

3558 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3559 

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

3561 self._reset_memoizations() 

3562 

3563 @util.ro_non_memoized_property 

3564 def selected_columns( 

3565 self, 

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

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

3568 representing the columns that 

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

3570 

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

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

3573 within this collection cannot be directly nested inside another SELECT 

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

3575 necessary parenthesization required by SQL. 

3576 

3577 .. note:: 

3578 

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

3580 include expressions established in the columns clause using the 

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

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

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

3584 construct. 

3585 

3586 .. seealso:: 

3587 

3588 :attr:`_sql.Select.selected_columns` 

3589 

3590 .. versionadded:: 1.4 

3591 

3592 """ 

3593 raise NotImplementedError() 

3594 

3595 def _generate_fromclause_column_proxies( 

3596 self, 

3597 subquery: FromClause, 

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

3599 primary_key: ColumnSet, 

3600 foreign_keys: Set[KeyedColumnElement[Any]], 

3601 *, 

3602 proxy_compound_columns: Optional[ 

3603 Iterable[Sequence[ColumnElement[Any]]] 

3604 ] = None, 

3605 ) -> None: 

3606 raise NotImplementedError() 

3607 

3608 @util.ro_non_memoized_property 

3609 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3612 constructs. 

3613 

3614 .. versionadded:: 1.4.12 

3615 

3616 .. seealso:: 

3617 

3618 :attr:`_sql.SelectBase.exported_columns` 

3619 

3620 """ 

3621 raise NotImplementedError() 

3622 

3623 @property 

3624 def exported_columns( 

3625 self, 

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

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

3628 that represents the "exported" 

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

3630 :class:`_sql.TextClause` constructs. 

3631 

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

3633 object are synonymous 

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

3635 

3636 .. versionadded:: 1.4 

3637 

3638 .. seealso:: 

3639 

3640 :attr:`_expression.Select.exported_columns` 

3641 

3642 :attr:`_expression.Selectable.exported_columns` 

3643 

3644 :attr:`_expression.FromClause.exported_columns` 

3645 

3646 

3647 """ 

3648 return self.selected_columns.as_readonly() 

3649 

3650 def get_label_style(self) -> SelectLabelStyle: 

3651 """ 

3652 Retrieve the current label style. 

3653 

3654 Implemented by subclasses. 

3655 

3656 """ 

3657 raise NotImplementedError() 

3658 

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

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

3661 

3662 Implemented by subclasses. 

3663 

3664 """ 

3665 

3666 raise NotImplementedError() 

3667 

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

3669 raise NotImplementedError() 

3670 

3671 @util.deprecated( 

3672 "1.4", 

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

3674 "method is deprecated and will be " 

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

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

3677 ) 

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

3679 return self.scalar_subquery() 

3680 

3681 def exists(self) -> Exists: 

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

3683 which can be used as a column expression. 

3684 

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

3686 

3687 .. seealso:: 

3688 

3689 :func:`_sql.exists` 

3690 

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

3692 

3693 .. versionadded:: 1.4 

3694 

3695 """ 

3696 return Exists(self) 

3697 

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

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

3700 used as a column expression. 

3701 

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

3703 

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

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

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

3707 an enclosing SELECT. 

3708 

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

3710 subquery that can be produced using the 

3711 :meth:`_expression.SelectBase.subquery` 

3712 method. 

3713 

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

3715 :meth:`_expression.SelectBase.scalar_subquery`. 

3716 

3717 .. seealso:: 

3718 

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

3720 

3721 """ 

3722 if self._label_style is not LABEL_STYLE_NONE: 

3723 self = self.set_label_style(LABEL_STYLE_NONE) 

3724 

3725 return ScalarSelect(self) 

3726 

3727 def label(self, name: Optional[str]) -> Label[Any]: 

3728 """Return a 'scalar' representation of this selectable, embedded as a 

3729 subquery with a label. 

3730 

3731 .. seealso:: 

3732 

3733 :meth:`_expression.SelectBase.scalar_subquery`. 

3734 

3735 """ 

3736 return self.scalar_subquery().label(name) 

3737 

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

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

3740 

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

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

3743 

3744 .. seealso:: 

3745 

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

3747 

3748 """ 

3749 return Lateral._factory(self, name) 

3750 

3751 def subquery(self, name: Optional[str] = None) -> Subquery: 

3752 """Return a subquery of this :class:`_expression.SelectBase`. 

3753 

3754 A subquery is from a SQL perspective a parenthesized, named 

3755 construct that can be placed in the FROM clause of another 

3756 SELECT statement. 

3757 

3758 Given a SELECT statement such as:: 

3759 

3760 stmt = select(table.c.id, table.c.name) 

3761 

3762 The above statement might look like: 

3763 

3764 .. sourcecode:: sql 

3765 

3766 SELECT table.id, table.name FROM table 

3767 

3768 The subquery form by itself renders the same way, however when 

3769 embedded into the FROM clause of another SELECT statement, it becomes 

3770 a named sub-element:: 

3771 

3772 subq = stmt.subquery() 

3773 new_stmt = select(subq) 

3774 

3775 The above renders as: 

3776 

3777 .. sourcecode:: sql 

3778 

3779 SELECT anon_1.id, anon_1.name 

3780 FROM (SELECT table.id, table.name FROM table) AS anon_1 

3781 

3782 Historically, :meth:`_expression.SelectBase.subquery` 

3783 is equivalent to calling 

3784 the :meth:`_expression.FromClause.alias` 

3785 method on a FROM object; however, 

3786 as a :class:`_expression.SelectBase` 

3787 object is not directly FROM object, 

3788 the :meth:`_expression.SelectBase.subquery` 

3789 method provides clearer semantics. 

3790 

3791 .. versionadded:: 1.4 

3792 

3793 """ 

3794 

3795 return Subquery._construct( 

3796 self._ensure_disambiguated_names(), name=name 

3797 ) 

3798 

3799 def _ensure_disambiguated_names(self) -> Self: 

3800 """Ensure that the names generated by this selectbase will be 

3801 disambiguated in some way, if possible. 

3802 

3803 """ 

3804 

3805 raise NotImplementedError() 

3806 

3807 def alias( 

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

3809 ) -> Subquery: 

3810 """Return a named subquery against this 

3811 :class:`_expression.SelectBase`. 

3812 

3813 For a :class:`_expression.SelectBase` (as opposed to a 

3814 :class:`_expression.FromClause`), 

3815 this returns a :class:`.Subquery` object which behaves mostly the 

3816 same as the :class:`_expression.Alias` object that is used with a 

3817 :class:`_expression.FromClause`. 

3818 

3819 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3820 method is now 

3821 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3822 

3823 """ 

3824 return self.subquery(name=name) 

3825 

3826 

3827_SB = TypeVar("_SB", bound=SelectBase) 

3828 

3829 

3830class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3831 """Represent a grouping of a :class:`_expression.SelectBase`. 

3832 

3833 This differs from :class:`.Subquery` in that we are still 

3834 an "inner" SELECT statement, this is strictly for grouping inside of 

3835 compound selects. 

3836 

3837 """ 

3838 

3839 __visit_name__ = "select_statement_grouping" 

3840 _traverse_internals: _TraverseInternalsType = [ 

3841 ("element", InternalTraversal.dp_clauseelement) 

3842 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3843 

3844 _is_select_container = True 

3845 

3846 element: _SB 

3847 

3848 def __init__(self, element: _SB) -> None: 

3849 self.element = cast( 

3850 _SB, coercions.expect(roles.SelectStatementRole, element) 

3851 ) 

3852 

3853 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3854 new_element = self.element._ensure_disambiguated_names() 

3855 if new_element is not self.element: 

3856 return SelectStatementGrouping(new_element) 

3857 else: 

3858 return self 

3859 

3860 def get_label_style(self) -> SelectLabelStyle: 

3861 return self.element.get_label_style() 

3862 

3863 def set_label_style( 

3864 self, label_style: SelectLabelStyle 

3865 ) -> SelectStatementGrouping[_SB]: 

3866 return SelectStatementGrouping( 

3867 self.element.set_label_style(label_style) 

3868 ) 

3869 

3870 @property 

3871 def select_statement(self) -> _SB: 

3872 return self.element 

3873 

3874 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3875 return self 

3876 

3877 if TYPE_CHECKING: 

3878 

3879 def _ungroup(self) -> _SB: ... 

3880 

3881 # def _generate_columns_plus_names( 

3882 # self, anon_for_dupe_key: bool 

3883 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3884 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3885 

3886 def _generate_fromclause_column_proxies( 

3887 self, 

3888 subquery: FromClause, 

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

3890 primary_key: ColumnSet, 

3891 foreign_keys: Set[KeyedColumnElement[Any]], 

3892 *, 

3893 proxy_compound_columns: Optional[ 

3894 Iterable[Sequence[ColumnElement[Any]]] 

3895 ] = None, 

3896 ) -> None: 

3897 self.element._generate_fromclause_column_proxies( 

3898 subquery, 

3899 columns, 

3900 proxy_compound_columns=proxy_compound_columns, 

3901 primary_key=primary_key, 

3902 foreign_keys=foreign_keys, 

3903 ) 

3904 

3905 @util.ro_non_memoized_property 

3906 def _all_selected_columns(self) -> _SelectIterable: 

3907 return self.element._all_selected_columns 

3908 

3909 @util.ro_non_memoized_property 

3910 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

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

3912 representing the columns that 

3913 the embedded SELECT statement returns in its result set, not including 

3914 :class:`_sql.TextClause` constructs. 

3915 

3916 .. versionadded:: 1.4 

3917 

3918 .. seealso:: 

3919 

3920 :attr:`_sql.Select.selected_columns` 

3921 

3922 """ 

3923 return self.element.selected_columns 

3924 

3925 @util.ro_non_memoized_property 

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

3927 return self.element._from_objects 

3928 

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

3930 # SelectStatementGrouping not generative: has no attribute '_generate' 

3931 raise NotImplementedError 

3932 

3933 

3934class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

3935 """Base class for SELECT statements where additional elements can be 

3936 added. 

3937 

3938 This serves as the base for :class:`_expression.Select` and 

3939 :class:`_expression.CompoundSelect` 

3940 where elements such as ORDER BY, GROUP BY can be added and column 

3941 rendering can be controlled. Compare to 

3942 :class:`_expression.TextualSelect`, which, 

3943 while it subclasses :class:`_expression.SelectBase` 

3944 and is also a SELECT construct, 

3945 represents a fixed textual string which cannot be altered at this level, 

3946 only wrapped as a subquery. 

3947 

3948 """ 

3949 

3950 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3951 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3952 _limit_clause: Optional[ColumnElement[Any]] = None 

3953 _offset_clause: Optional[ColumnElement[Any]] = None 

3954 _fetch_clause: Optional[ColumnElement[Any]] = None 

3955 _fetch_clause_options: Optional[Dict[str, bool]] = None 

3956 _for_update_arg: Optional[ForUpdateArg] = None 

3957 

3958 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

3959 self._label_style = _label_style 

3960 

3961 @_generative 

3962 def with_for_update( 

3963 self, 

3964 *, 

3965 nowait: bool = False, 

3966 read: bool = False, 

3967 of: Optional[_ForUpdateOfArgument] = None, 

3968 skip_locked: bool = False, 

3969 key_share: bool = False, 

3970 ) -> Self: 

3971 """Specify a ``FOR UPDATE`` clause for this 

3972 :class:`_expression.GenerativeSelect`. 

3973 

3974 E.g.:: 

3975 

3976 stmt = select(table).with_for_update(nowait=True) 

3977 

3978 On a database like PostgreSQL or Oracle Database, the above would 

3979 render a statement like: 

3980 

3981 .. sourcecode:: sql 

3982 

3983 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

3984 

3985 on other backends, the ``nowait`` option is ignored and instead 

3986 would produce: 

3987 

3988 .. sourcecode:: sql 

3989 

3990 SELECT table.a, table.b FROM table FOR UPDATE 

3991 

3992 When called with no arguments, the statement will render with 

3993 the suffix ``FOR UPDATE``. Additional arguments can then be 

3994 provided which allow for common database-specific 

3995 variants. 

3996 

3997 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

3998 Database and PostgreSQL dialects. 

3999 

4000 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

4001 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

4002 ``nowait``, will render ``FOR SHARE NOWAIT``. 

4003 

4004 :param of: SQL expression or list of SQL expression elements, 

4005 (typically :class:`_schema.Column` objects or a compatible expression, 

4006 for some backends may also be a table expression) which will render 

4007 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4008 Database, some MySQL versions and possibly others. May render as a 

4009 table or as a column depending on backend. 

4010 

4011 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4012 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4013 if ``read=True`` is also specified. 

4014 

4015 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4016 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4017 on the PostgreSQL dialect. 

4018 

4019 """ 

4020 self._for_update_arg = ForUpdateArg( 

4021 nowait=nowait, 

4022 read=read, 

4023 of=of, 

4024 skip_locked=skip_locked, 

4025 key_share=key_share, 

4026 ) 

4027 return self 

4028 

4029 def get_label_style(self) -> SelectLabelStyle: 

4030 """ 

4031 Retrieve the current label style. 

4032 

4033 .. versionadded:: 1.4 

4034 

4035 """ 

4036 return self._label_style 

4037 

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

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

4040 

4041 There are three "label styles" available, 

4042 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4043 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4044 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4045 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4046 

4047 In modern SQLAlchemy, there is not generally a need to change the 

4048 labeling style, as per-expression labels are more effectively used by 

4049 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4050 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4051 disambiguate same-named columns from different tables, aliases, or 

4052 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4053 applies labels only to names that conflict with an existing name so 

4054 that the impact of this labeling is minimal. 

4055 

4056 The rationale for disambiguation is mostly so that all column 

4057 expressions are available from a given :attr:`_sql.FromClause.c` 

4058 collection when a subquery is created. 

4059 

4060 .. versionadded:: 1.4 - the 

4061 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4062 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4063 ``use_labels=True`` methods and/or parameters. 

4064 

4065 .. seealso:: 

4066 

4067 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4068 

4069 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` 

4070 

4071 :data:`_sql.LABEL_STYLE_NONE` 

4072 

4073 :data:`_sql.LABEL_STYLE_DEFAULT` 

4074 

4075 """ 

4076 if self._label_style is not style: 

4077 self = self._generate() 

4078 self._label_style = style 

4079 return self 

4080 

4081 @property 

4082 def _group_by_clause(self) -> ClauseList: 

4083 """ClauseList access to group_by_clauses for legacy dialects""" 

4084 return ClauseList._construct_raw( 

4085 operators.comma_op, self._group_by_clauses 

4086 ) 

4087 

4088 @property 

4089 def _order_by_clause(self) -> ClauseList: 

4090 """ClauseList access to order_by_clauses for legacy dialects""" 

4091 return ClauseList._construct_raw( 

4092 operators.comma_op, self._order_by_clauses 

4093 ) 

4094 

4095 def _offset_or_limit_clause( 

4096 self, 

4097 element: _LimitOffsetType, 

4098 name: Optional[str] = None, 

4099 type_: Optional[_TypeEngineArgument[int]] = None, 

4100 ) -> ColumnElement[Any]: 

4101 """Convert the given value to an "offset or limit" clause. 

4102 

4103 This handles incoming integers and converts to an expression; if 

4104 an expression is already given, it is passed through. 

4105 

4106 """ 

4107 return coercions.expect( 

4108 roles.LimitOffsetRole, element, name=name, type_=type_ 

4109 ) 

4110 

4111 @overload 

4112 def _offset_or_limit_clause_asint( 

4113 self, clause: ColumnElement[Any], attrname: str 

4114 ) -> NoReturn: ... 

4115 

4116 @overload 

4117 def _offset_or_limit_clause_asint( 

4118 self, clause: Optional[_OffsetLimitParam], attrname: str 

4119 ) -> Optional[int]: ... 

4120 

4121 def _offset_or_limit_clause_asint( 

4122 self, clause: Optional[ColumnElement[Any]], attrname: str 

4123 ) -> Union[NoReturn, Optional[int]]: 

4124 """Convert the "offset or limit" clause of a select construct to an 

4125 integer. 

4126 

4127 This is only possible if the value is stored as a simple bound 

4128 parameter. Otherwise, a compilation error is raised. 

4129 

4130 """ 

4131 if clause is None: 

4132 return None 

4133 try: 

4134 value = clause._limit_offset_value 

4135 except AttributeError as err: 

4136 raise exc.CompileError( 

4137 "This SELECT structure does not use a simple " 

4138 "integer value for %s" % attrname 

4139 ) from err 

4140 else: 

4141 return util.asint(value) 

4142 

4143 @property 

4144 def _limit(self) -> Optional[int]: 

4145 """Get an integer value for the limit. This should only be used 

4146 by code that cannot support a limit as a BindParameter or 

4147 other custom clause as it will throw an exception if the limit 

4148 isn't currently set to an integer. 

4149 

4150 """ 

4151 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4152 

4153 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4154 """True if the clause is a simple integer, False 

4155 if it is not present or is a SQL expression. 

4156 """ 

4157 return isinstance(clause, _OffsetLimitParam) 

4158 

4159 @property 

4160 def _offset(self) -> Optional[int]: 

4161 """Get an integer value for the offset. This should only be used 

4162 by code that cannot support an offset as a BindParameter or 

4163 other custom clause as it will throw an exception if the 

4164 offset isn't currently set to an integer. 

4165 

4166 """ 

4167 return self._offset_or_limit_clause_asint( 

4168 self._offset_clause, "offset" 

4169 ) 

4170 

4171 @property 

4172 def _has_row_limiting_clause(self) -> bool: 

4173 return ( 

4174 self._limit_clause is not None 

4175 or self._offset_clause is not None 

4176 or self._fetch_clause is not None 

4177 ) 

4178 

4179 @_generative 

4180 def limit(self, limit: _LimitOffsetType) -> Self: 

4181 """Return a new selectable with the given LIMIT criterion 

4182 applied. 

4183 

4184 This is a numerical value which usually renders as a ``LIMIT`` 

4185 expression in the resulting select. Backends that don't 

4186 support ``LIMIT`` will attempt to provide similar 

4187 functionality. 

4188 

4189 .. note:: 

4190 

4191 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4192 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4193 

4194 :param limit: an integer LIMIT parameter, or a SQL expression 

4195 that provides an integer result. Pass ``None`` to reset it. 

4196 

4197 .. seealso:: 

4198 

4199 :meth:`_sql.GenerativeSelect.fetch` 

4200 

4201 :meth:`_sql.GenerativeSelect.offset` 

4202 

4203 """ 

4204 

4205 self._fetch_clause = self._fetch_clause_options = None 

4206 self._limit_clause = self._offset_or_limit_clause(limit) 

4207 return self 

4208 

4209 @_generative 

4210 def fetch( 

4211 self, 

4212 count: _LimitOffsetType, 

4213 with_ties: bool = False, 

4214 percent: bool = False, 

4215 **dialect_kw: Any, 

4216 ) -> Self: 

4217 r"""Return a new selectable with the given FETCH FIRST criterion 

4218 applied. 

4219 

4220 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4221 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4222 select. This functionality is is currently implemented for Oracle 

4223 Database, PostgreSQL, MSSQL. 

4224 

4225 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4226 

4227 .. note:: 

4228 

4229 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4230 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4231 

4232 .. versionadded:: 1.4 

4233 

4234 :param count: an integer COUNT parameter, or a SQL expression 

4235 that provides an integer result. When ``percent=True`` this will 

4236 represent the percentage of rows to return, not the absolute value. 

4237 Pass ``None`` to reset it. 

4238 

4239 :param with_ties: When ``True``, the WITH TIES option is used 

4240 to return any additional rows that tie for the last place in the 

4241 result set according to the ``ORDER BY`` clause. The 

4242 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4243 

4244 :param percent: When ``True``, ``count`` represents the percentage 

4245 of the total number of selected rows to return. Defaults to ``False`` 

4246 

4247 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4248 may be accepted by dialects. 

4249 

4250 .. versionadded:: 2.0.41 

4251 

4252 .. seealso:: 

4253 

4254 :meth:`_sql.GenerativeSelect.limit` 

4255 

4256 :meth:`_sql.GenerativeSelect.offset` 

4257 

4258 """ 

4259 self._validate_dialect_kwargs(dialect_kw) 

4260 self._limit_clause = None 

4261 if count is None: 

4262 self._fetch_clause = self._fetch_clause_options = None 

4263 else: 

4264 self._fetch_clause = self._offset_or_limit_clause(count) 

4265 self._fetch_clause_options = { 

4266 "with_ties": with_ties, 

4267 "percent": percent, 

4268 } 

4269 return self 

4270 

4271 @_generative 

4272 def offset(self, offset: _LimitOffsetType) -> Self: 

4273 """Return a new selectable with the given OFFSET criterion 

4274 applied. 

4275 

4276 

4277 This is a numeric value which usually renders as an ``OFFSET`` 

4278 expression in the resulting select. Backends that don't 

4279 support ``OFFSET`` will attempt to provide similar 

4280 functionality. 

4281 

4282 :param offset: an integer OFFSET parameter, or a SQL expression 

4283 that provides an integer result. Pass ``None`` to reset it. 

4284 

4285 .. seealso:: 

4286 

4287 :meth:`_sql.GenerativeSelect.limit` 

4288 

4289 :meth:`_sql.GenerativeSelect.fetch` 

4290 

4291 """ 

4292 

4293 self._offset_clause = self._offset_or_limit_clause(offset) 

4294 return self 

4295 

4296 @_generative 

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

4298 def slice( 

4299 self, 

4300 start: int, 

4301 stop: int, 

4302 ) -> Self: 

4303 """Apply LIMIT / OFFSET to this statement based on a slice. 

4304 

4305 The start and stop indices behave like the argument to Python's 

4306 built-in :func:`range` function. This method provides an 

4307 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4308 query. 

4309 

4310 For example, :: 

4311 

4312 stmt = select(User).order_by(User.id).slice(1, 3) 

4313 

4314 renders as 

4315 

4316 .. sourcecode:: sql 

4317 

4318 SELECT users.id AS users_id, 

4319 users.name AS users_name 

4320 FROM users ORDER BY users.id 

4321 LIMIT ? OFFSET ? 

4322 (2, 1) 

4323 

4324 .. note:: 

4325 

4326 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4327 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4328 

4329 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4330 method generalized from the ORM. 

4331 

4332 .. seealso:: 

4333 

4334 :meth:`_sql.GenerativeSelect.limit` 

4335 

4336 :meth:`_sql.GenerativeSelect.offset` 

4337 

4338 :meth:`_sql.GenerativeSelect.fetch` 

4339 

4340 """ 

4341 sql_util = util.preloaded.sql_util 

4342 self._fetch_clause = self._fetch_clause_options = None 

4343 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4344 self._limit_clause, self._offset_clause, start, stop 

4345 ) 

4346 return self 

4347 

4348 @_generative 

4349 def order_by( 

4350 self, 

4351 __first: Union[ 

4352 Literal[None, _NoArg.NO_ARG], 

4353 _ColumnExpressionOrStrLabelArgument[Any], 

4354 ] = _NoArg.NO_ARG, 

4355 /, 

4356 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4357 ) -> Self: 

4358 r"""Return a new selectable with the given list of ORDER BY 

4359 criteria applied. 

4360 

4361 e.g.:: 

4362 

4363 stmt = select(table).order_by(table.c.id, table.c.name) 

4364 

4365 Calling this method multiple times is equivalent to calling it once 

4366 with all the clauses concatenated. All existing ORDER BY criteria may 

4367 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4368 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4369 

4370 # will erase all ORDER BY and ORDER BY new_col alone 

4371 stmt = stmt.order_by(None).order_by(new_col) 

4372 

4373 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4374 constructs which will be used to generate an ORDER BY clause. 

4375 

4376 Alternatively, an individual entry may also be the string name of a 

4377 label located elsewhere in the columns clause of the statement which 

4378 will be matched and rendered in a backend-specific way based on 

4379 context; see :ref:`tutorial_order_by_label` for background on string 

4380 label matching in ORDER BY and GROUP BY expressions. 

4381 

4382 .. seealso:: 

4383 

4384 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4385 

4386 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4387 

4388 """ 

4389 

4390 if not clauses and __first is None: 

4391 self._order_by_clauses = () 

4392 elif __first is not _NoArg.NO_ARG: 

4393 self._order_by_clauses += tuple( 

4394 coercions.expect( 

4395 roles.OrderByRole, clause, apply_propagate_attrs=self 

4396 ) 

4397 for clause in (__first,) + clauses 

4398 ) 

4399 return self 

4400 

4401 @_generative 

4402 def group_by( 

4403 self, 

4404 __first: Union[ 

4405 Literal[None, _NoArg.NO_ARG], 

4406 _ColumnExpressionOrStrLabelArgument[Any], 

4407 ] = _NoArg.NO_ARG, 

4408 /, 

4409 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4410 ) -> Self: 

4411 r"""Return a new selectable with the given list of GROUP BY 

4412 criterion applied. 

4413 

4414 All existing GROUP BY settings can be suppressed by passing ``None``. 

4415 

4416 e.g.:: 

4417 

4418 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4419 

4420 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4421 constructs which will be used to generate an GROUP BY clause. 

4422 

4423 Alternatively, an individual entry may also be the string name of a 

4424 label located elsewhere in the columns clause of the statement which 

4425 will be matched and rendered in a backend-specific way based on 

4426 context; see :ref:`tutorial_order_by_label` for background on string 

4427 label matching in ORDER BY and GROUP BY expressions. 

4428 

4429 .. seealso:: 

4430 

4431 :ref:`tutorial_group_by_w_aggregates` - in the 

4432 :ref:`unified_tutorial` 

4433 

4434 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4435 

4436 """ # noqa: E501 

4437 

4438 if not clauses and __first is None: 

4439 self._group_by_clauses = () 

4440 elif __first is not _NoArg.NO_ARG: 

4441 self._group_by_clauses += tuple( 

4442 coercions.expect( 

4443 roles.GroupByRole, clause, apply_propagate_attrs=self 

4444 ) 

4445 for clause in (__first,) + clauses 

4446 ) 

4447 return self 

4448 

4449 

4450@CompileState.plugin_for("default", "compound_select") 

4451class CompoundSelectState(CompileState): 

4452 @util.memoized_property 

4453 def _label_resolve_dict( 

4454 self, 

4455 ) -> Tuple[ 

4456 Dict[str, ColumnElement[Any]], 

4457 Dict[str, ColumnElement[Any]], 

4458 Dict[str, ColumnElement[Any]], 

4459 ]: 

4460 # TODO: this is hacky and slow 

4461 hacky_subquery = self.statement.subquery() 

4462 hacky_subquery.named_with_column = False 

4463 d = {c.key: c for c in hacky_subquery.c} 

4464 return d, d, d 

4465 

4466 

4467class _CompoundSelectKeyword(Enum): 

4468 UNION = "UNION" 

4469 UNION_ALL = "UNION ALL" 

4470 EXCEPT = "EXCEPT" 

4471 EXCEPT_ALL = "EXCEPT ALL" 

4472 INTERSECT = "INTERSECT" 

4473 INTERSECT_ALL = "INTERSECT ALL" 

4474 

4475 

4476class CompoundSelect( 

4477 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4478): 

4479 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4480 SELECT-based set operations. 

4481 

4482 

4483 .. seealso:: 

4484 

4485 :func:`_expression.union` 

4486 

4487 :func:`_expression.union_all` 

4488 

4489 :func:`_expression.intersect` 

4490 

4491 :func:`_expression.intersect_all` 

4492 

4493 :func:`_expression.except` 

4494 

4495 :func:`_expression.except_all` 

4496 

4497 """ 

4498 

4499 __visit_name__ = "compound_select" 

4500 

4501 _traverse_internals: _TraverseInternalsType = ( 

4502 [ 

4503 ("selects", InternalTraversal.dp_clauseelement_list), 

4504 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4505 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4506 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4507 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4508 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4509 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4510 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4511 ("keyword", InternalTraversal.dp_string), 

4512 ] 

4513 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4514 + HasCTE._has_ctes_traverse_internals 

4515 + DialectKWArgs._dialect_kwargs_traverse_internals 

4516 + Executable._executable_traverse_internals 

4517 ) 

4518 

4519 selects: List[SelectBase] 

4520 

4521 _is_from_container = True 

4522 _auto_correlate = False 

4523 

4524 def __init__( 

4525 self, 

4526 keyword: _CompoundSelectKeyword, 

4527 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4528 ): 

4529 self.keyword = keyword 

4530 self.selects = [ 

4531 coercions.expect( 

4532 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4533 ).self_group(against=self) 

4534 for s in selects 

4535 ] 

4536 

4537 GenerativeSelect.__init__(self) 

4538 

4539 @classmethod 

4540 def _create_union( 

4541 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4542 ) -> CompoundSelect[Unpack[_Ts]]: 

4543 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4544 

4545 @classmethod 

4546 def _create_union_all( 

4547 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4548 ) -> CompoundSelect[Unpack[_Ts]]: 

4549 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4550 

4551 @classmethod 

4552 def _create_except( 

4553 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4554 ) -> CompoundSelect[Unpack[_Ts]]: 

4555 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4556 

4557 @classmethod 

4558 def _create_except_all( 

4559 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4560 ) -> CompoundSelect[Unpack[_Ts]]: 

4561 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4562 

4563 @classmethod 

4564 def _create_intersect( 

4565 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4566 ) -> CompoundSelect[Unpack[_Ts]]: 

4567 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4568 

4569 @classmethod 

4570 def _create_intersect_all( 

4571 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4572 ) -> CompoundSelect[Unpack[_Ts]]: 

4573 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4574 

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

4576 return self.selects[0]._scalar_type() 

4577 

4578 def self_group( 

4579 self, against: Optional[OperatorType] = None 

4580 ) -> GroupedElement: 

4581 return SelectStatementGrouping(self) 

4582 

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

4584 for s in self.selects: 

4585 if s.is_derived_from(fromclause): 

4586 return True 

4587 return False 

4588 

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

4590 if self._label_style is not style: 

4591 self = self._generate() 

4592 select_0 = self.selects[0].set_label_style(style) 

4593 self.selects = [select_0] + self.selects[1:] 

4594 

4595 return self 

4596 

4597 def _ensure_disambiguated_names(self) -> Self: 

4598 new_select = self.selects[0]._ensure_disambiguated_names() 

4599 if new_select is not self.selects[0]: 

4600 self = self._generate() 

4601 self.selects = [new_select] + self.selects[1:] 

4602 

4603 return self 

4604 

4605 def _generate_fromclause_column_proxies( 

4606 self, 

4607 subquery: FromClause, 

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

4609 primary_key: ColumnSet, 

4610 foreign_keys: Set[KeyedColumnElement[Any]], 

4611 *, 

4612 proxy_compound_columns: Optional[ 

4613 Iterable[Sequence[ColumnElement[Any]]] 

4614 ] = None, 

4615 ) -> None: 

4616 # this is a slightly hacky thing - the union exports a 

4617 # column that resembles just that of the *first* selectable. 

4618 # to get at a "composite" column, particularly foreign keys, 

4619 # you have to dig through the proxies collection which we 

4620 # generate below. 

4621 select_0 = self.selects[0] 

4622 

4623 if self._label_style is not LABEL_STYLE_DEFAULT: 

4624 select_0 = select_0.set_label_style(self._label_style) 

4625 

4626 # hand-construct the "_proxies" collection to include all 

4627 # derived columns place a 'weight' annotation corresponding 

4628 # to how low in the list of select()s the column occurs, so 

4629 # that the corresponding_column() operation can resolve 

4630 # conflicts 

4631 extra_col_iterator = zip( 

4632 *[ 

4633 [ 

4634 c._annotate(dd) 

4635 for c in stmt._all_selected_columns 

4636 if is_column_element(c) 

4637 ] 

4638 for dd, stmt in [ 

4639 ({"weight": i + 1}, stmt) 

4640 for i, stmt in enumerate(self.selects) 

4641 ] 

4642 ] 

4643 ) 

4644 

4645 # the incoming proxy_compound_columns can be present also if this is 

4646 # a compound embedded in a compound. it's probably more appropriate 

4647 # that we generate new weights local to this nested compound, though 

4648 # i haven't tried to think what it means for compound nested in 

4649 # compound 

4650 select_0._generate_fromclause_column_proxies( 

4651 subquery, 

4652 columns, 

4653 proxy_compound_columns=extra_col_iterator, 

4654 primary_key=primary_key, 

4655 foreign_keys=foreign_keys, 

4656 ) 

4657 

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

4659 super()._refresh_for_new_column(column) 

4660 for select in self.selects: 

4661 select._refresh_for_new_column(column) 

4662 

4663 @util.ro_non_memoized_property 

4664 def _all_selected_columns(self) -> _SelectIterable: 

4665 return self.selects[0]._all_selected_columns 

4666 

4667 @util.ro_non_memoized_property 

4668 def selected_columns( 

4669 self, 

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

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

4672 representing the columns that 

4673 this SELECT statement or similar construct returns in its result set, 

4674 not including :class:`_sql.TextClause` constructs. 

4675 

4676 For a :class:`_expression.CompoundSelect`, the 

4677 :attr:`_expression.CompoundSelect.selected_columns` 

4678 attribute returns the selected 

4679 columns of the first SELECT statement contained within the series of 

4680 statements within the set operation. 

4681 

4682 .. seealso:: 

4683 

4684 :attr:`_sql.Select.selected_columns` 

4685 

4686 .. versionadded:: 1.4 

4687 

4688 """ 

4689 return self.selects[0].selected_columns 

4690 

4691 

4692# backwards compat 

4693for elem in _CompoundSelectKeyword: 

4694 setattr(CompoundSelect, elem.name, elem) 

4695 

4696 

4697@CompileState.plugin_for("default", "select") 

4698class SelectState(util.MemoizedSlots, CompileState): 

4699 __slots__ = ( 

4700 "from_clauses", 

4701 "froms", 

4702 "columns_plus_names", 

4703 "_label_resolve_dict", 

4704 ) 

4705 

4706 if TYPE_CHECKING: 

4707 default_select_compile_options: CacheableOptions 

4708 else: 

4709 

4710 class default_select_compile_options(CacheableOptions): 

4711 _cache_key_traversal = [] 

4712 

4713 if TYPE_CHECKING: 

4714 

4715 @classmethod 

4716 def get_plugin_class( 

4717 cls, statement: Executable 

4718 ) -> Type[SelectState]: ... 

4719 

4720 def __init__( 

4721 self, 

4722 statement: Select[Unpack[TupleAny]], 

4723 compiler: SQLCompiler, 

4724 **kw: Any, 

4725 ): 

4726 self.statement = statement 

4727 self.from_clauses = statement._from_obj 

4728 

4729 for memoized_entities in statement._memoized_select_entities: 

4730 self._setup_joins( 

4731 memoized_entities._setup_joins, memoized_entities._raw_columns 

4732 ) 

4733 

4734 if statement._setup_joins: 

4735 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4736 

4737 self.froms = self._get_froms(statement) 

4738 

4739 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4740 

4741 @classmethod 

4742 def _plugin_not_implemented(cls) -> NoReturn: 

4743 raise NotImplementedError( 

4744 "The default SELECT construct without plugins does not " 

4745 "implement this method." 

4746 ) 

4747 

4748 @classmethod 

4749 def get_column_descriptions( 

4750 cls, statement: Select[Unpack[TupleAny]] 

4751 ) -> List[Dict[str, Any]]: 

4752 return [ 

4753 { 

4754 "name": name, 

4755 "type": element.type, 

4756 "expr": element, 

4757 } 

4758 for _, name, _, element, _ in ( 

4759 statement._generate_columns_plus_names(False) 

4760 ) 

4761 ] 

4762 

4763 @classmethod 

4764 def from_statement( 

4765 cls, 

4766 statement: Select[Unpack[TupleAny]], 

4767 from_statement: roles.ReturnsRowsRole, 

4768 ) -> ExecutableReturnsRows: 

4769 cls._plugin_not_implemented() 

4770 

4771 @classmethod 

4772 def get_columns_clause_froms( 

4773 cls, statement: Select[Unpack[TupleAny]] 

4774 ) -> List[FromClause]: 

4775 return cls._normalize_froms( 

4776 itertools.chain.from_iterable( 

4777 element._from_objects for element in statement._raw_columns 

4778 ) 

4779 ) 

4780 

4781 @classmethod 

4782 def _column_naming_convention( 

4783 cls, label_style: SelectLabelStyle 

4784 ) -> _LabelConventionCallable: 

4785 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4786 

4787 dedupe = label_style is not LABEL_STYLE_NONE 

4788 

4789 pa = prefix_anon_map() 

4790 names = set() 

4791 

4792 def go( 

4793 c: Union[ColumnElement[Any], TextClause], 

4794 col_name: Optional[str] = None, 

4795 ) -> Optional[str]: 

4796 if is_text_clause(c): 

4797 return None 

4798 elif TYPE_CHECKING: 

4799 assert is_column_element(c) 

4800 

4801 if not dedupe: 

4802 name = c._proxy_key 

4803 if name is None: 

4804 name = "_no_label" 

4805 return name 

4806 

4807 name = c._tq_key_label if table_qualified else c._proxy_key 

4808 

4809 if name is None: 

4810 name = "_no_label" 

4811 if name in names: 

4812 return c._anon_label(name) % pa 

4813 else: 

4814 names.add(name) 

4815 return name 

4816 

4817 elif name in names: 

4818 return ( 

4819 c._anon_tq_key_label % pa 

4820 if table_qualified 

4821 else c._anon_key_label % pa 

4822 ) 

4823 else: 

4824 names.add(name) 

4825 return name 

4826 

4827 return go 

4828 

4829 def _get_froms( 

4830 self, statement: Select[Unpack[TupleAny]] 

4831 ) -> List[FromClause]: 

4832 ambiguous_table_name_map: _AmbiguousTableNameMap 

4833 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4834 

4835 return self._normalize_froms( 

4836 itertools.chain( 

4837 self.from_clauses, 

4838 itertools.chain.from_iterable( 

4839 [ 

4840 element._from_objects 

4841 for element in statement._raw_columns 

4842 ] 

4843 ), 

4844 itertools.chain.from_iterable( 

4845 [ 

4846 element._from_objects 

4847 for element in statement._where_criteria 

4848 ] 

4849 ), 

4850 ), 

4851 check_statement=statement, 

4852 ambiguous_table_name_map=ambiguous_table_name_map, 

4853 ) 

4854 

4855 @classmethod 

4856 def _normalize_froms( 

4857 cls, 

4858 iterable_of_froms: Iterable[FromClause], 

4859 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4860 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4861 ) -> List[FromClause]: 

4862 """given an iterable of things to select FROM, reduce them to what 

4863 would actually render in the FROM clause of a SELECT. 

4864 

4865 This does the job of checking for JOINs, tables, etc. that are in fact 

4866 overlapping due to cloning, adaption, present in overlapping joins, 

4867 etc. 

4868 

4869 """ 

4870 seen: Set[FromClause] = set() 

4871 froms: List[FromClause] = [] 

4872 

4873 for item in iterable_of_froms: 

4874 if is_subquery(item) and item.element is check_statement: 

4875 raise exc.InvalidRequestError( 

4876 "select() construct refers to itself as a FROM" 

4877 ) 

4878 

4879 if not seen.intersection(item._cloned_set): 

4880 froms.append(item) 

4881 seen.update(item._cloned_set) 

4882 

4883 if froms: 

4884 toremove = set( 

4885 itertools.chain.from_iterable( 

4886 [_expand_cloned(f._hide_froms) for f in froms] 

4887 ) 

4888 ) 

4889 if toremove: 

4890 # filter out to FROM clauses not in the list, 

4891 # using a list to maintain ordering 

4892 froms = [f for f in froms if f not in toremove] 

4893 

4894 if ambiguous_table_name_map is not None: 

4895 ambiguous_table_name_map.update( 

4896 ( 

4897 fr.name, 

4898 _anonymous_label.safe_construct( 

4899 hash(fr.name), fr.name 

4900 ), 

4901 ) 

4902 for item in froms 

4903 for fr in item._from_objects 

4904 if is_table(fr) 

4905 and fr.schema 

4906 and fr.name not in ambiguous_table_name_map 

4907 ) 

4908 

4909 return froms 

4910 

4911 def _get_display_froms( 

4912 self, 

4913 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4914 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4915 ) -> List[FromClause]: 

4916 """Return the full list of 'from' clauses to be displayed. 

4917 

4918 Takes into account a set of existing froms which may be 

4919 rendered in the FROM clause of enclosing selects; this Select 

4920 may want to leave those absent if it is automatically 

4921 correlating. 

4922 

4923 """ 

4924 

4925 froms = self.froms 

4926 

4927 if self.statement._correlate: 

4928 to_correlate = self.statement._correlate 

4929 if to_correlate: 

4930 froms = [ 

4931 f 

4932 for f in froms 

4933 if f 

4934 not in _cloned_intersection( 

4935 _cloned_intersection( 

4936 froms, explicit_correlate_froms or () 

4937 ), 

4938 to_correlate, 

4939 ) 

4940 ] 

4941 

4942 if self.statement._correlate_except is not None: 

4943 froms = [ 

4944 f 

4945 for f in froms 

4946 if f 

4947 not in _cloned_difference( 

4948 _cloned_intersection( 

4949 froms, explicit_correlate_froms or () 

4950 ), 

4951 self.statement._correlate_except, 

4952 ) 

4953 ] 

4954 

4955 if ( 

4956 self.statement._auto_correlate 

4957 and implicit_correlate_froms 

4958 and len(froms) > 1 

4959 ): 

4960 froms = [ 

4961 f 

4962 for f in froms 

4963 if f 

4964 not in _cloned_intersection(froms, implicit_correlate_froms) 

4965 ] 

4966 

4967 if not len(froms): 

4968 raise exc.InvalidRequestError( 

4969 "Select statement '%r" 

4970 "' returned no FROM clauses " 

4971 "due to auto-correlation; " 

4972 "specify correlate(<tables>) " 

4973 "to control correlation " 

4974 "manually." % self.statement 

4975 ) 

4976 

4977 return froms 

4978 

4979 def _memoized_attr__label_resolve_dict( 

4980 self, 

4981 ) -> Tuple[ 

4982 Dict[str, ColumnElement[Any]], 

4983 Dict[str, ColumnElement[Any]], 

4984 Dict[str, ColumnElement[Any]], 

4985 ]: 

4986 with_cols: Dict[str, ColumnElement[Any]] = { 

4987 c._tq_label or c.key: c 

4988 for c in self.statement._all_selected_columns 

4989 if c._allow_label_resolve 

4990 } 

4991 only_froms: Dict[str, ColumnElement[Any]] = { 

4992 c.key: c # type: ignore 

4993 for c in _select_iterables(self.froms) 

4994 if c._allow_label_resolve 

4995 } 

4996 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

4997 for key, value in only_froms.items(): 

4998 with_cols.setdefault(key, value) 

4999 

5000 return with_cols, only_froms, only_cols 

5001 

5002 @classmethod 

5003 def determine_last_joined_entity( 

5004 cls, stmt: Select[Unpack[TupleAny]] 

5005 ) -> Optional[_JoinTargetElement]: 

5006 if stmt._setup_joins: 

5007 return stmt._setup_joins[-1][0] 

5008 else: 

5009 return None 

5010 

5011 @classmethod 

5012 def all_selected_columns( 

5013 cls, statement: Select[Unpack[TupleAny]] 

5014 ) -> _SelectIterable: 

5015 return [c for c in _select_iterables(statement._raw_columns)] 

5016 

5017 def _setup_joins( 

5018 self, 

5019 args: Tuple[_SetupJoinsElement, ...], 

5020 raw_columns: List[_ColumnsClauseElement], 

5021 ) -> None: 

5022 for right, onclause, left, flags in args: 

5023 if TYPE_CHECKING: 

5024 if onclause is not None: 

5025 assert isinstance(onclause, ColumnElement) 

5026 

5027 isouter = flags["isouter"] 

5028 full = flags["full"] 

5029 

5030 if left is None: 

5031 ( 

5032 left, 

5033 replace_from_obj_index, 

5034 ) = self._join_determine_implicit_left_side( 

5035 raw_columns, left, right, onclause 

5036 ) 

5037 else: 

5038 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5039 left 

5040 ) 

5041 

5042 # these assertions can be made here, as if the right/onclause 

5043 # contained ORM elements, the select() statement would have been 

5044 # upgraded to an ORM select, and this method would not be called; 

5045 # orm.context.ORMSelectCompileState._join() would be 

5046 # used instead. 

5047 if TYPE_CHECKING: 

5048 assert isinstance(right, FromClause) 

5049 if onclause is not None: 

5050 assert isinstance(onclause, ColumnElement) 

5051 

5052 if replace_from_obj_index is not None: 

5053 # splice into an existing element in the 

5054 # self._from_obj list 

5055 left_clause = self.from_clauses[replace_from_obj_index] 

5056 

5057 self.from_clauses = ( 

5058 self.from_clauses[:replace_from_obj_index] 

5059 + ( 

5060 Join( 

5061 left_clause, 

5062 right, 

5063 onclause, 

5064 isouter=isouter, 

5065 full=full, 

5066 ), 

5067 ) 

5068 + self.from_clauses[replace_from_obj_index + 1 :] 

5069 ) 

5070 else: 

5071 assert left is not None 

5072 self.from_clauses = self.from_clauses + ( 

5073 Join(left, right, onclause, isouter=isouter, full=full), 

5074 ) 

5075 

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

5077 def _join_determine_implicit_left_side( 

5078 self, 

5079 raw_columns: List[_ColumnsClauseElement], 

5080 left: Optional[FromClause], 

5081 right: _JoinTargetElement, 

5082 onclause: Optional[ColumnElement[Any]], 

5083 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5084 """When join conditions don't express the left side explicitly, 

5085 determine if an existing FROM or entity in this query 

5086 can serve as the left hand side. 

5087 

5088 """ 

5089 

5090 sql_util = util.preloaded.sql_util 

5091 

5092 replace_from_obj_index: Optional[int] = None 

5093 

5094 from_clauses = self.from_clauses 

5095 

5096 if from_clauses: 

5097 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5098 from_clauses, right, onclause 

5099 ) 

5100 

5101 if len(indexes) == 1: 

5102 replace_from_obj_index = indexes[0] 

5103 left = from_clauses[replace_from_obj_index] 

5104 else: 

5105 potential = {} 

5106 statement = self.statement 

5107 

5108 for from_clause in itertools.chain( 

5109 itertools.chain.from_iterable( 

5110 [element._from_objects for element in raw_columns] 

5111 ), 

5112 itertools.chain.from_iterable( 

5113 [ 

5114 element._from_objects 

5115 for element in statement._where_criteria 

5116 ] 

5117 ), 

5118 ): 

5119 potential[from_clause] = () 

5120 

5121 all_clauses = list(potential.keys()) 

5122 indexes = sql_util.find_left_clause_to_join_from( 

5123 all_clauses, right, onclause 

5124 ) 

5125 

5126 if len(indexes) == 1: 

5127 left = all_clauses[indexes[0]] 

5128 

5129 if len(indexes) > 1: 

5130 raise exc.InvalidRequestError( 

5131 "Can't determine which FROM clause to join " 

5132 "from, there are multiple FROMS which can " 

5133 "join to this entity. Please use the .select_from() " 

5134 "method to establish an explicit left side, as well as " 

5135 "providing an explicit ON clause if not present already to " 

5136 "help resolve the ambiguity." 

5137 ) 

5138 elif not indexes: 

5139 raise exc.InvalidRequestError( 

5140 "Don't know how to join to %r. " 

5141 "Please use the .select_from() " 

5142 "method to establish an explicit left side, as well as " 

5143 "providing an explicit ON clause if not present already to " 

5144 "help resolve the ambiguity." % (right,) 

5145 ) 

5146 return left, replace_from_obj_index 

5147 

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

5149 def _join_place_explicit_left_side( 

5150 self, left: FromClause 

5151 ) -> Optional[int]: 

5152 replace_from_obj_index: Optional[int] = None 

5153 

5154 sql_util = util.preloaded.sql_util 

5155 

5156 from_clauses = list(self.statement._iterate_from_elements()) 

5157 

5158 if from_clauses: 

5159 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5160 self.from_clauses, left 

5161 ) 

5162 else: 

5163 indexes = [] 

5164 

5165 if len(indexes) > 1: 

5166 raise exc.InvalidRequestError( 

5167 "Can't identify which entity in which to assign the " 

5168 "left side of this join. Please use a more specific " 

5169 "ON clause." 

5170 ) 

5171 

5172 # have an index, means the left side is already present in 

5173 # an existing FROM in the self._from_obj tuple 

5174 if indexes: 

5175 replace_from_obj_index = indexes[0] 

5176 

5177 # no index, means we need to add a new element to the 

5178 # self._from_obj tuple 

5179 

5180 return replace_from_obj_index 

5181 

5182 

5183class _SelectFromElements: 

5184 __slots__ = () 

5185 

5186 _raw_columns: List[_ColumnsClauseElement] 

5187 _where_criteria: Tuple[ColumnElement[Any], ...] 

5188 _from_obj: Tuple[FromClause, ...] 

5189 

5190 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5191 # note this does not include elements 

5192 # in _setup_joins 

5193 

5194 seen = set() 

5195 for element in self._raw_columns: 

5196 for fr in element._from_objects: 

5197 if fr in seen: 

5198 continue 

5199 seen.add(fr) 

5200 yield fr 

5201 for element in self._where_criteria: 

5202 for fr in element._from_objects: 

5203 if fr in seen: 

5204 continue 

5205 seen.add(fr) 

5206 yield fr 

5207 for element in self._from_obj: 

5208 if element in seen: 

5209 continue 

5210 seen.add(element) 

5211 yield element 

5212 

5213 

5214class _MemoizedSelectEntities( 

5215 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5216): 

5217 """represents partial state from a Select object, for the case 

5218 where Select.columns() has redefined the set of columns/entities the 

5219 statement will be SELECTing from. This object represents 

5220 the entities from the SELECT before that transformation was applied, 

5221 so that transformations that were made in terms of the SELECT at that 

5222 time, such as join() as well as options(), can access the correct context. 

5223 

5224 In previous SQLAlchemy versions, this wasn't needed because these 

5225 constructs calculated everything up front, like when you called join() 

5226 or options(), it did everything to figure out how that would translate 

5227 into specific SQL constructs that would be ready to send directly to the 

5228 SQL compiler when needed. But as of 

5229 1.4, all of that stuff is done in the compilation phase, during the 

5230 "compile state" portion of the process, so that the work can all be 

5231 cached. So it needs to be able to resolve joins/options2 based on what 

5232 the list of entities was when those methods were called. 

5233 

5234 

5235 """ 

5236 

5237 __visit_name__ = "memoized_select_entities" 

5238 

5239 _traverse_internals: _TraverseInternalsType = [ 

5240 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5241 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5242 ("_with_options", InternalTraversal.dp_executable_options), 

5243 ] 

5244 

5245 _is_clone_of: Optional[ClauseElement] 

5246 _raw_columns: List[_ColumnsClauseElement] 

5247 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5248 _with_options: Tuple[ExecutableOption, ...] 

5249 

5250 _annotations = util.EMPTY_DICT 

5251 

5252 def _clone(self, **kw: Any) -> Self: 

5253 c = self.__class__.__new__(self.__class__) 

5254 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5255 

5256 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5257 return c 

5258 

5259 @classmethod 

5260 def _generate_for_statement( 

5261 cls, select_stmt: Select[Unpack[TupleAny]] 

5262 ) -> None: 

5263 if select_stmt._setup_joins or select_stmt._with_options: 

5264 self = _MemoizedSelectEntities() 

5265 self._raw_columns = select_stmt._raw_columns 

5266 self._setup_joins = select_stmt._setup_joins 

5267 self._with_options = select_stmt._with_options 

5268 

5269 select_stmt._memoized_select_entities += (self,) 

5270 select_stmt._raw_columns = [] 

5271 select_stmt._setup_joins = select_stmt._with_options = () 

5272 

5273 

5274class Select( 

5275 HasPrefixes, 

5276 HasSuffixes, 

5277 HasHints, 

5278 HasCompileState, 

5279 HasSyntaxExtensions[ 

5280 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5281 ], 

5282 _SelectFromElements, 

5283 GenerativeSelect, 

5284 TypedReturnsRows[Unpack[_Ts]], 

5285): 

5286 """Represents a ``SELECT`` statement. 

5287 

5288 The :class:`_sql.Select` object is normally constructed using the 

5289 :func:`_sql.select` function. See that function for details. 

5290 

5291 Available extension points: 

5292 

5293 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5294 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5295 keyword (if any) and the list of columns. 

5296 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5297 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5298 

5299 .. seealso:: 

5300 

5301 :func:`_sql.select` 

5302 

5303 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5304 

5305 """ 

5306 

5307 __visit_name__ = "select" 

5308 

5309 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5310 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5311 

5312 _raw_columns: List[_ColumnsClauseElement] 

5313 

5314 _distinct: bool = False 

5315 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5316 _correlate: Tuple[FromClause, ...] = () 

5317 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5318 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5319 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5320 _from_obj: Tuple[FromClause, ...] = () 

5321 

5322 _position_map = util.immutabledict( 

5323 { 

5324 "post_select": "_post_select_clause", 

5325 "pre_columns": "_pre_columns_clause", 

5326 "post_criteria": "_post_criteria_clause", 

5327 "post_body": "_post_body_clause", 

5328 } 

5329 ) 

5330 

5331 _post_select_clause: Optional[ClauseElement] = None 

5332 """extension point for a ClauseElement that will be compiled directly 

5333 after the SELECT keyword. 

5334 

5335 .. versionadded:: 2.1 

5336 

5337 """ 

5338 

5339 _pre_columns_clause: Optional[ClauseElement] = None 

5340 """extension point for a ClauseElement that will be compiled directly 

5341 before the "columns" clause; after DISTINCT (if present). 

5342 

5343 .. versionadded:: 2.1 

5344 

5345 """ 

5346 

5347 _post_criteria_clause: Optional[ClauseElement] = None 

5348 """extension point for a ClauseElement that will be compiled directly 

5349 after "criteria", following the HAVING clause but before ORDER BY. 

5350 

5351 .. versionadded:: 2.1 

5352 

5353 """ 

5354 

5355 _post_body_clause: Optional[ClauseElement] = None 

5356 """extension point for a ClauseElement that will be compiled directly 

5357 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5358 of the SELECT. 

5359 

5360 .. versionadded:: 2.1 

5361 

5362 """ 

5363 

5364 _auto_correlate = True 

5365 _is_select_statement = True 

5366 _compile_options: CacheableOptions = ( 

5367 SelectState.default_select_compile_options 

5368 ) 

5369 

5370 _traverse_internals: _TraverseInternalsType = ( 

5371 [ 

5372 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5373 ( 

5374 "_memoized_select_entities", 

5375 InternalTraversal.dp_memoized_select_entities, 

5376 ), 

5377 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5378 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5379 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5380 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5381 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5382 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5383 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5384 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5385 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5386 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5387 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5388 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5389 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5390 ("_distinct", InternalTraversal.dp_boolean), 

5391 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5392 ("_label_style", InternalTraversal.dp_plain_obj), 

5393 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5394 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5395 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5396 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5397 ] 

5398 + HasCTE._has_ctes_traverse_internals 

5399 + HasPrefixes._has_prefixes_traverse_internals 

5400 + HasSuffixes._has_suffixes_traverse_internals 

5401 + HasHints._has_hints_traverse_internals 

5402 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5403 + Executable._executable_traverse_internals 

5404 + DialectKWArgs._dialect_kwargs_traverse_internals 

5405 ) 

5406 

5407 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5408 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5409 ] 

5410 

5411 _compile_state_factory: Type[SelectState] 

5412 

5413 @classmethod 

5414 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5415 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5416 

5417 Used internally to build up :class:`.Select` constructs with 

5418 pre-established state. 

5419 

5420 """ 

5421 

5422 stmt = Select.__new__(Select) 

5423 stmt.__dict__.update(kw) 

5424 return stmt 

5425 

5426 def __init__( 

5427 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5428 ): 

5429 r"""Construct a new :class:`_expression.Select`. 

5430 

5431 The public constructor for :class:`_expression.Select` is the 

5432 :func:`_sql.select` function. 

5433 

5434 """ 

5435 self._raw_columns = [ 

5436 coercions.expect( 

5437 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5438 ) 

5439 for ent in entities 

5440 ] 

5441 GenerativeSelect.__init__(self) 

5442 

5443 def _apply_syntax_extension_to_self( 

5444 self, extension: SyntaxExtension 

5445 ) -> None: 

5446 extension.apply_to_select(self) 

5447 

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

5449 if not self._raw_columns: 

5450 return NULLTYPE 

5451 elem = self._raw_columns[0] 

5452 cols = list(elem._select_iterable) 

5453 return cols[0].type 

5454 

5455 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5456 """A synonym for the :meth:`_sql.Select.where` method.""" 

5457 

5458 return self.where(*criteria) 

5459 

5460 def _filter_by_zero( 

5461 self, 

5462 ) -> Union[ 

5463 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5464 ]: 

5465 if self._setup_joins: 

5466 meth = SelectState.get_plugin_class( 

5467 self 

5468 ).determine_last_joined_entity 

5469 _last_joined_entity = meth(self) 

5470 if _last_joined_entity is not None: 

5471 return _last_joined_entity 

5472 

5473 if self._from_obj: 

5474 return self._from_obj[0] 

5475 

5476 return self._raw_columns[0] 

5477 

5478 if TYPE_CHECKING: 

5479 

5480 @overload 

5481 def scalar_subquery( 

5482 self: Select[_MAYBE_ENTITY], 

5483 ) -> ScalarSelect[Any]: ... 

5484 

5485 @overload 

5486 def scalar_subquery( 

5487 self: Select[_NOT_ENTITY], 

5488 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5489 

5490 @overload 

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

5492 

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

5494 

5495 def filter_by(self, **kwargs: Any) -> Self: 

5496 r"""apply the given filtering criterion as a WHERE clause 

5497 to this select. 

5498 

5499 """ 

5500 from_entity = self._filter_by_zero() 

5501 

5502 clauses = [ 

5503 _entity_namespace_key(from_entity, key) == value 

5504 for key, value in kwargs.items() 

5505 ] 

5506 return self.filter(*clauses) 

5507 

5508 @property 

5509 def column_descriptions(self) -> Any: 

5510 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5511 referring to the columns which are SELECTed by this statement. 

5512 

5513 This attribute is generally useful when using the ORM, as an 

5514 extended structure which includes information about mapped 

5515 entities is returned. The section :ref:`queryguide_inspection` 

5516 contains more background. 

5517 

5518 For a Core-only statement, the structure returned by this accessor 

5519 is derived from the same objects that are returned by the 

5520 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5521 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5522 which indicate the column expressions to be selected:: 

5523 

5524 >>> stmt = select(user_table) 

5525 >>> stmt.column_descriptions 

5526 [ 

5527 { 

5528 'name': 'id', 

5529 'type': Integer(), 

5530 'expr': Column('id', Integer(), ...)}, 

5531 { 

5532 'name': 'name', 

5533 'type': String(length=30), 

5534 'expr': Column('name', String(length=30), ...)} 

5535 ] 

5536 

5537 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5538 attribute returns a structure for a Core-only set of entities, 

5539 not just ORM-only entities. 

5540 

5541 .. seealso:: 

5542 

5543 :attr:`.UpdateBase.entity_description` - entity information for 

5544 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5545 

5546 :ref:`queryguide_inspection` - ORM background 

5547 

5548 """ 

5549 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5550 return meth(self) 

5551 

5552 def from_statement( 

5553 self, statement: roles.ReturnsRowsRole 

5554 ) -> ExecutableReturnsRows: 

5555 """Apply the columns which this :class:`.Select` would select 

5556 onto another statement. 

5557 

5558 This operation is :term:`plugin-specific` and will raise a not 

5559 supported exception if this :class:`_sql.Select` does not select from 

5560 plugin-enabled entities. 

5561 

5562 

5563 The statement is typically either a :func:`_expression.text` or 

5564 :func:`_expression.select` construct, and should return the set of 

5565 columns appropriate to the entities represented by this 

5566 :class:`.Select`. 

5567 

5568 .. seealso:: 

5569 

5570 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5571 ORM Querying Guide 

5572 

5573 """ 

5574 meth = SelectState.get_plugin_class(self).from_statement 

5575 return meth(self, statement) 

5576 

5577 @_generative 

5578 def join( 

5579 self, 

5580 target: _JoinTargetArgument, 

5581 onclause: Optional[_OnClauseArgument] = None, 

5582 *, 

5583 isouter: bool = False, 

5584 full: bool = False, 

5585 ) -> Self: 

5586 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5587 object's criterion 

5588 and apply generatively, returning the newly resulting 

5589 :class:`_expression.Select`. 

5590 

5591 E.g.:: 

5592 

5593 stmt = select(user_table).join( 

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

5595 ) 

5596 

5597 The above statement generates SQL similar to: 

5598 

5599 .. sourcecode:: sql 

5600 

5601 SELECT user.id, user.name 

5602 FROM user 

5603 JOIN address ON user.id = address.user_id 

5604 

5605 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5606 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5607 source that is within the FROM clause of the existing SELECT, 

5608 and a given target :class:`_sql.FromClause`, and then adds 

5609 this :class:`_sql.Join` to the FROM clause of the newly generated 

5610 SELECT statement. This is completely reworked from the behavior 

5611 in 1.3, which would instead create a subquery of the entire 

5612 :class:`_expression.Select` and then join that subquery to the 

5613 target. 

5614 

5615 This is a **backwards incompatible change** as the previous behavior 

5616 was mostly useless, producing an unnamed subquery rejected by 

5617 most databases in any case. The new behavior is modeled after 

5618 that of the very successful :meth:`_orm.Query.join` method in the 

5619 ORM, in order to support the functionality of :class:`_orm.Query` 

5620 being available by using a :class:`_sql.Select` object with an 

5621 :class:`_orm.Session`. 

5622 

5623 See the notes for this change at :ref:`change_select_join`. 

5624 

5625 

5626 :param target: target table to join towards 

5627 

5628 :param onclause: ON clause of the join. If omitted, an ON clause 

5629 is generated automatically based on the :class:`_schema.ForeignKey` 

5630 linkages between the two tables, if one can be unambiguously 

5631 determined, otherwise an error is raised. 

5632 

5633 :param isouter: if True, generate LEFT OUTER join. Same as 

5634 :meth:`_expression.Select.outerjoin`. 

5635 

5636 :param full: if True, generate FULL OUTER join. 

5637 

5638 .. seealso:: 

5639 

5640 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5641 

5642 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5643 

5644 :meth:`_expression.Select.join_from` 

5645 

5646 :meth:`_expression.Select.outerjoin` 

5647 

5648 """ # noqa: E501 

5649 join_target = coercions.expect( 

5650 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5651 ) 

5652 if onclause is not None: 

5653 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5654 else: 

5655 onclause_element = None 

5656 

5657 self._setup_joins += ( 

5658 ( 

5659 join_target, 

5660 onclause_element, 

5661 None, 

5662 {"isouter": isouter, "full": full}, 

5663 ), 

5664 ) 

5665 return self 

5666 

5667 def outerjoin_from( 

5668 self, 

5669 from_: _FromClauseArgument, 

5670 target: _JoinTargetArgument, 

5671 onclause: Optional[_OnClauseArgument] = None, 

5672 *, 

5673 full: bool = False, 

5674 ) -> Self: 

5675 r"""Create a SQL LEFT OUTER JOIN against this 

5676 :class:`_expression.Select` object's criterion and apply generatively, 

5677 returning the newly resulting :class:`_expression.Select`. 

5678 

5679 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5680 

5681 """ 

5682 return self.join_from( 

5683 from_, target, onclause=onclause, isouter=True, full=full 

5684 ) 

5685 

5686 @_generative 

5687 def join_from( 

5688 self, 

5689 from_: _FromClauseArgument, 

5690 target: _JoinTargetArgument, 

5691 onclause: Optional[_OnClauseArgument] = None, 

5692 *, 

5693 isouter: bool = False, 

5694 full: bool = False, 

5695 ) -> Self: 

5696 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5697 object's criterion 

5698 and apply generatively, returning the newly resulting 

5699 :class:`_expression.Select`. 

5700 

5701 E.g.:: 

5702 

5703 stmt = select(user_table, address_table).join_from( 

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

5705 ) 

5706 

5707 The above statement generates SQL similar to: 

5708 

5709 .. sourcecode:: sql 

5710 

5711 SELECT user.id, user.name, address.id, address.email, address.user_id 

5712 FROM user JOIN address ON user.id = address.user_id 

5713 

5714 .. versionadded:: 1.4 

5715 

5716 :param from\_: the left side of the join, will be rendered in the 

5717 FROM clause and is roughly equivalent to using the 

5718 :meth:`.Select.select_from` method. 

5719 

5720 :param target: target table to join towards 

5721 

5722 :param onclause: ON clause of the join. 

5723 

5724 :param isouter: if True, generate LEFT OUTER join. Same as 

5725 :meth:`_expression.Select.outerjoin`. 

5726 

5727 :param full: if True, generate FULL OUTER join. 

5728 

5729 .. seealso:: 

5730 

5731 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5732 

5733 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5734 

5735 :meth:`_expression.Select.join` 

5736 

5737 """ # noqa: E501 

5738 

5739 # note the order of parsing from vs. target is important here, as we 

5740 # are also deriving the source of the plugin (i.e. the subject mapper 

5741 # in an ORM query) which should favor the "from_" over the "target" 

5742 

5743 from_ = coercions.expect( 

5744 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5745 ) 

5746 join_target = coercions.expect( 

5747 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5748 ) 

5749 if onclause is not None: 

5750 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5751 else: 

5752 onclause_element = None 

5753 

5754 self._setup_joins += ( 

5755 ( 

5756 join_target, 

5757 onclause_element, 

5758 from_, 

5759 {"isouter": isouter, "full": full}, 

5760 ), 

5761 ) 

5762 return self 

5763 

5764 def outerjoin( 

5765 self, 

5766 target: _JoinTargetArgument, 

5767 onclause: Optional[_OnClauseArgument] = None, 

5768 *, 

5769 full: bool = False, 

5770 ) -> Self: 

5771 """Create a left outer join. 

5772 

5773 Parameters are the same as that of :meth:`_expression.Select.join`. 

5774 

5775 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5776 creates a :class:`_sql.Join` object between a 

5777 :class:`_sql.FromClause` source that is within the FROM clause of 

5778 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5779 and then adds this :class:`_sql.Join` to the FROM clause of the 

5780 newly generated SELECT statement. This is completely reworked 

5781 from the behavior in 1.3, which would instead create a subquery of 

5782 the entire 

5783 :class:`_expression.Select` and then join that subquery to the 

5784 target. 

5785 

5786 This is a **backwards incompatible change** as the previous behavior 

5787 was mostly useless, producing an unnamed subquery rejected by 

5788 most databases in any case. The new behavior is modeled after 

5789 that of the very successful :meth:`_orm.Query.join` method in the 

5790 ORM, in order to support the functionality of :class:`_orm.Query` 

5791 being available by using a :class:`_sql.Select` object with an 

5792 :class:`_orm.Session`. 

5793 

5794 See the notes for this change at :ref:`change_select_join`. 

5795 

5796 .. seealso:: 

5797 

5798 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5799 

5800 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5801 

5802 :meth:`_expression.Select.join` 

5803 

5804 """ 

5805 return self.join(target, onclause=onclause, isouter=True, full=full) 

5806 

5807 def get_final_froms(self) -> Sequence[FromClause]: 

5808 """Compute the final displayed list of :class:`_expression.FromClause` 

5809 elements. 

5810 

5811 This method will run through the full computation required to 

5812 determine what FROM elements will be displayed in the resulting 

5813 SELECT statement, including shadowing individual tables with 

5814 JOIN objects, as well as full computation for ORM use cases including 

5815 eager loading clauses. 

5816 

5817 For ORM use, this accessor returns the **post compilation** 

5818 list of FROM objects; this collection will include elements such as 

5819 eagerly loaded tables and joins. The objects will **not** be 

5820 ORM enabled and not work as a replacement for the 

5821 :meth:`_sql.Select.select_froms` collection; additionally, the 

5822 method is not well performing for an ORM enabled statement as it 

5823 will incur the full ORM construction process. 

5824 

5825 To retrieve the FROM list that's implied by the "columns" collection 

5826 passed to the :class:`_sql.Select` originally, use the 

5827 :attr:`_sql.Select.columns_clause_froms` accessor. 

5828 

5829 To select from an alternative set of columns while maintaining the 

5830 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5831 pass the 

5832 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5833 parameter. 

5834 

5835 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5836 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5837 which is deprecated. 

5838 

5839 .. seealso:: 

5840 

5841 :attr:`_sql.Select.columns_clause_froms` 

5842 

5843 """ 

5844 compiler = self._default_compiler() 

5845 

5846 return self._compile_state_factory(self, compiler)._get_display_froms() 

5847 

5848 @property 

5849 @util.deprecated( 

5850 "1.4.23", 

5851 "The :attr:`_expression.Select.froms` attribute is moved to " 

5852 "the :meth:`_expression.Select.get_final_froms` method.", 

5853 ) 

5854 def froms(self) -> Sequence[FromClause]: 

5855 """Return the displayed list of :class:`_expression.FromClause` 

5856 elements. 

5857 

5858 

5859 """ 

5860 return self.get_final_froms() 

5861 

5862 @property 

5863 def columns_clause_froms(self) -> List[FromClause]: 

5864 """Return the set of :class:`_expression.FromClause` objects implied 

5865 by the columns clause of this SELECT statement. 

5866 

5867 .. versionadded:: 1.4.23 

5868 

5869 .. seealso:: 

5870 

5871 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5872 statement into account 

5873 

5874 :meth:`_sql.Select.with_only_columns` - makes use of this 

5875 collection to set up a new FROM list 

5876 

5877 """ 

5878 

5879 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5880 self 

5881 ) 

5882 

5883 @property 

5884 def inner_columns(self) -> _SelectIterable: 

5885 """An iterator of all :class:`_expression.ColumnElement` 

5886 expressions which would 

5887 be rendered into the columns clause of the resulting SELECT statement. 

5888 

5889 This method is legacy as of 1.4 and is superseded by the 

5890 :attr:`_expression.Select.exported_columns` collection. 

5891 

5892 """ 

5893 

5894 return iter(self._all_selected_columns) 

5895 

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

5897 if fromclause is not None and self in fromclause._cloned_set: 

5898 return True 

5899 

5900 for f in self._iterate_from_elements(): 

5901 if f.is_derived_from(fromclause): 

5902 return True 

5903 return False 

5904 

5905 def _copy_internals( 

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

5907 ) -> None: 

5908 # Select() object has been cloned and probably adapted by the 

5909 # given clone function. Apply the cloning function to internal 

5910 # objects 

5911 

5912 # 1. keep a dictionary of the froms we've cloned, and what 

5913 # they've become. This allows us to ensure the same cloned from 

5914 # is used when other items such as columns are "cloned" 

5915 

5916 all_the_froms = set( 

5917 itertools.chain( 

5918 _from_objects(*self._raw_columns), 

5919 _from_objects(*self._where_criteria), 

5920 _from_objects(*[elem[0] for elem in self._setup_joins]), 

5921 ) 

5922 ) 

5923 

5924 # do a clone for the froms we've gathered. what is important here 

5925 # is if any of the things we are selecting from, like tables, 

5926 # were converted into Join objects. if so, these need to be 

5927 # added to _from_obj explicitly, because otherwise they won't be 

5928 # part of the new state, as they don't associate themselves with 

5929 # their columns. 

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

5931 

5932 # 2. copy FROM collections, adding in joins that we've created. 

5933 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

5934 add_froms = ( 

5935 {f for f in new_froms.values() if isinstance(f, Join)} 

5936 .difference(all_the_froms) 

5937 .difference(existing_from_obj) 

5938 ) 

5939 

5940 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

5941 

5942 # 3. clone everything else, making sure we use columns 

5943 # corresponding to the froms we just made. 

5944 def replace( 

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

5946 **kw: Any, 

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

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

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

5950 return newelem 

5951 return None 

5952 

5953 kw["replace"] = replace 

5954 

5955 # copy everything else. for table-ish things like correlate, 

5956 # correlate_except, setup_joins, these clone normally. For 

5957 # column-expression oriented things like raw_columns, where_criteria, 

5958 # order by, we get this from the new froms. 

5959 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

5960 

5961 self._reset_memoizations() 

5962 

5963 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

5964 return itertools.chain( 

5965 super().get_children( 

5966 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

5967 **kw, 

5968 ), 

5969 self._iterate_from_elements(), 

5970 ) 

5971 

5972 @_generative 

5973 def add_columns( 

5974 self, *entities: _ColumnsClauseArgument[Any] 

5975 ) -> Select[Unpack[TupleAny]]: 

5976 r"""Return a new :func:`_expression.select` construct with 

5977 the given entities appended to its columns clause. 

5978 

5979 E.g.:: 

5980 

5981 my_select = my_select.add_columns(table.c.new_column) 

5982 

5983 The original expressions in the columns clause remain in place. 

5984 To replace the original expressions with new ones, see the method 

5985 :meth:`_expression.Select.with_only_columns`. 

5986 

5987 :param \*entities: column, table, or other entity expressions to be 

5988 added to the columns clause 

5989 

5990 .. seealso:: 

5991 

5992 :meth:`_expression.Select.with_only_columns` - replaces existing 

5993 expressions rather than appending. 

5994 

5995 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

5996 example 

5997 

5998 """ 

5999 self._reset_memoizations() 

6000 

6001 self._raw_columns = self._raw_columns + [ 

6002 coercions.expect( 

6003 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

6004 ) 

6005 for column in entities 

6006 ] 

6007 return self 

6008 

6009 def _set_entities( 

6010 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

6011 ) -> None: 

6012 self._raw_columns = [ 

6013 coercions.expect( 

6014 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6015 ) 

6016 for ent in util.to_list(entities) 

6017 ] 

6018 

6019 @util.deprecated( 

6020 "1.4", 

6021 "The :meth:`_expression.Select.column` method is deprecated and will " 

6022 "be removed in a future release. Please use " 

6023 ":meth:`_expression.Select.add_columns`", 

6024 ) 

6025 def column( 

6026 self, column: _ColumnsClauseArgument[Any] 

6027 ) -> Select[Unpack[TupleAny]]: 

6028 """Return a new :func:`_expression.select` construct with 

6029 the given column expression added to its columns clause. 

6030 

6031 E.g.:: 

6032 

6033 my_select = my_select.column(table.c.new_column) 

6034 

6035 See the documentation for 

6036 :meth:`_expression.Select.with_only_columns` 

6037 for guidelines on adding /replacing the columns of a 

6038 :class:`_expression.Select` object. 

6039 

6040 """ 

6041 return self.add_columns(column) 

6042 

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

6044 def reduce_columns( 

6045 self, only_synonyms: bool = True 

6046 ) -> Select[Unpack[TupleAny]]: 

6047 """Return a new :func:`_expression.select` construct with redundantly 

6048 named, equivalently-valued columns removed from the columns clause. 

6049 

6050 "Redundant" here means two columns where one refers to the 

6051 other either based on foreign key, or via a simple equality 

6052 comparison in the WHERE clause of the statement. The primary purpose 

6053 of this method is to automatically construct a select statement 

6054 with all uniquely-named columns, without the need to use 

6055 table-qualified labels as 

6056 :meth:`_expression.Select.set_label_style` 

6057 does. 

6058 

6059 When columns are omitted based on foreign key, the referred-to 

6060 column is the one that's kept. When columns are omitted based on 

6061 WHERE equivalence, the first column in the columns clause is the 

6062 one that's kept. 

6063 

6064 :param only_synonyms: when True, limit the removal of columns 

6065 to those which have the same name as the equivalent. Otherwise, 

6066 all columns that are equivalent to another are removed. 

6067 

6068 """ 

6069 woc: Select[Unpack[TupleAny]] 

6070 woc = self.with_only_columns( 

6071 *util.preloaded.sql_util.reduce_columns( 

6072 self._all_selected_columns, 

6073 only_synonyms=only_synonyms, 

6074 *(self._where_criteria + self._from_obj), 

6075 ) 

6076 ) 

6077 return woc 

6078 

6079 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6080 

6081 # code within this block is **programmatically, 

6082 # statically generated** by tools/generate_tuple_map_overloads.py 

6083 

6084 @overload 

6085 def with_only_columns( 

6086 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6087 ) -> Select[_T0]: ... 

6088 

6089 @overload 

6090 def with_only_columns( 

6091 self, 

6092 __ent0: _TCCA[_T0], 

6093 __ent1: _TCCA[_T1], 

6094 /, 

6095 *, 

6096 maintain_column_froms: bool = ..., 

6097 ) -> Select[_T0, _T1]: ... 

6098 

6099 @overload 

6100 def with_only_columns( 

6101 self, 

6102 __ent0: _TCCA[_T0], 

6103 __ent1: _TCCA[_T1], 

6104 __ent2: _TCCA[_T2], 

6105 /, 

6106 *, 

6107 maintain_column_froms: bool = ..., 

6108 ) -> Select[_T0, _T1, _T2]: ... 

6109 

6110 @overload 

6111 def with_only_columns( 

6112 self, 

6113 __ent0: _TCCA[_T0], 

6114 __ent1: _TCCA[_T1], 

6115 __ent2: _TCCA[_T2], 

6116 __ent3: _TCCA[_T3], 

6117 /, 

6118 *, 

6119 maintain_column_froms: bool = ..., 

6120 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6121 

6122 @overload 

6123 def with_only_columns( 

6124 self, 

6125 __ent0: _TCCA[_T0], 

6126 __ent1: _TCCA[_T1], 

6127 __ent2: _TCCA[_T2], 

6128 __ent3: _TCCA[_T3], 

6129 __ent4: _TCCA[_T4], 

6130 /, 

6131 *, 

6132 maintain_column_froms: bool = ..., 

6133 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6134 

6135 @overload 

6136 def with_only_columns( 

6137 self, 

6138 __ent0: _TCCA[_T0], 

6139 __ent1: _TCCA[_T1], 

6140 __ent2: _TCCA[_T2], 

6141 __ent3: _TCCA[_T3], 

6142 __ent4: _TCCA[_T4], 

6143 __ent5: _TCCA[_T5], 

6144 /, 

6145 *, 

6146 maintain_column_froms: bool = ..., 

6147 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

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 /, 

6160 *, 

6161 maintain_column_froms: bool = ..., 

6162 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6163 

6164 @overload 

6165 def with_only_columns( 

6166 self, 

6167 __ent0: _TCCA[_T0], 

6168 __ent1: _TCCA[_T1], 

6169 __ent2: _TCCA[_T2], 

6170 __ent3: _TCCA[_T3], 

6171 __ent4: _TCCA[_T4], 

6172 __ent5: _TCCA[_T5], 

6173 __ent6: _TCCA[_T6], 

6174 __ent7: _TCCA[_T7], 

6175 /, 

6176 *entities: _ColumnsClauseArgument[Any], 

6177 maintain_column_froms: bool = ..., 

6178 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6179 

6180 # END OVERLOADED FUNCTIONS self.with_only_columns 

6181 

6182 @overload 

6183 def with_only_columns( 

6184 self, 

6185 *entities: _ColumnsClauseArgument[Any], 

6186 maintain_column_froms: bool = False, 

6187 **__kw: Any, 

6188 ) -> Select[Unpack[TupleAny]]: ... 

6189 

6190 @_generative 

6191 def with_only_columns( 

6192 self, 

6193 *entities: _ColumnsClauseArgument[Any], 

6194 maintain_column_froms: bool = False, 

6195 **__kw: Any, 

6196 ) -> Select[Unpack[TupleAny]]: 

6197 r"""Return a new :func:`_expression.select` construct with its columns 

6198 clause replaced with the given entities. 

6199 

6200 By default, this method is exactly equivalent to as if the original 

6201 :func:`_expression.select` had been called with the given entities. 

6202 E.g. a statement:: 

6203 

6204 s = select(table1.c.a, table1.c.b) 

6205 s = s.with_only_columns(table1.c.b) 

6206 

6207 should be exactly equivalent to:: 

6208 

6209 s = select(table1.c.b) 

6210 

6211 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6212 will also dynamically alter the FROM clause of the 

6213 statement if it is not explicitly stated. 

6214 To maintain the existing set of FROMs including those implied by the 

6215 current columns clause, add the 

6216 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6217 parameter:: 

6218 

6219 s = select(table1.c.a, table2.c.b) 

6220 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6221 

6222 The above parameter performs a transfer of the effective FROMs 

6223 in the columns collection to the :meth:`_sql.Select.select_from` 

6224 method, as though the following were invoked:: 

6225 

6226 s = select(table1.c.a, table2.c.b) 

6227 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6228 

6229 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6230 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6231 collection and performs an operation equivalent to the following:: 

6232 

6233 s = select(table1.c.a, table2.c.b) 

6234 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6235 

6236 :param \*entities: column expressions to be used. 

6237 

6238 :param maintain_column_froms: boolean parameter that will ensure the 

6239 FROM list implied from the current columns clause will be transferred 

6240 to the :meth:`_sql.Select.select_from` method first. 

6241 

6242 .. versionadded:: 1.4.23 

6243 

6244 """ # noqa: E501 

6245 

6246 if __kw: 

6247 raise _no_kw() 

6248 

6249 # memoizations should be cleared here as of 

6250 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6251 # is the case for now. 

6252 self._assert_no_memoizations() 

6253 

6254 if maintain_column_froms: 

6255 self.select_from.non_generative( # type: ignore 

6256 self, *self.columns_clause_froms 

6257 ) 

6258 

6259 # then memoize the FROMs etc. 

6260 _MemoizedSelectEntities._generate_for_statement(self) 

6261 

6262 self._raw_columns = [ 

6263 coercions.expect(roles.ColumnsClauseRole, c) 

6264 for c in coercions._expression_collection_was_a_list( 

6265 "entities", "Select.with_only_columns", entities 

6266 ) 

6267 ] 

6268 return self 

6269 

6270 @property 

6271 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6272 """Return the completed WHERE clause for this 

6273 :class:`_expression.Select` statement. 

6274 

6275 This assembles the current collection of WHERE criteria 

6276 into a single :class:`_expression.BooleanClauseList` construct. 

6277 

6278 

6279 .. versionadded:: 1.4 

6280 

6281 """ 

6282 

6283 return BooleanClauseList._construct_for_whereclause( 

6284 self._where_criteria 

6285 ) 

6286 

6287 _whereclause = whereclause 

6288 

6289 @_generative 

6290 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6291 """Return a new :func:`_expression.select` construct with 

6292 the given expression added to 

6293 its WHERE clause, joined to the existing clause via AND, if any. 

6294 

6295 """ 

6296 

6297 assert isinstance(self._where_criteria, tuple) 

6298 

6299 for criterion in whereclause: 

6300 where_criteria: ColumnElement[Any] = coercions.expect( 

6301 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6302 ) 

6303 self._where_criteria += (where_criteria,) 

6304 return self 

6305 

6306 @_generative 

6307 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6308 """Return a new :func:`_expression.select` construct with 

6309 the given expression added to 

6310 its HAVING clause, joined to the existing clause via AND, if any. 

6311 

6312 """ 

6313 

6314 for criterion in having: 

6315 having_criteria = coercions.expect( 

6316 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6317 ) 

6318 self._having_criteria += (having_criteria,) 

6319 return self 

6320 

6321 @_generative 

6322 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6323 r"""Return a new :func:`_expression.select` construct which 

6324 will apply DISTINCT to the SELECT statement overall. 

6325 

6326 E.g.:: 

6327 

6328 from sqlalchemy import select 

6329 

6330 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6331 

6332 The above would produce an statement resembling: 

6333 

6334 .. sourcecode:: sql 

6335 

6336 SELECT DISTINCT user.id, user.name FROM user 

6337 

6338 The method also historically accepted an ``*expr`` parameter which 

6339 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6340 This is now replaced using the :func:`_postgresql.distinct_on` 

6341 extension:: 

6342 

6343 from sqlalchemy import select 

6344 from sqlalchemy.dialects.postgresql import distinct_on 

6345 

6346 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6347 

6348 Using this parameter on other backends which don't support this 

6349 syntax will raise an error. 

6350 

6351 :param \*expr: optional column expressions. When present, 

6352 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6353 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6354 will be raised on other backends. 

6355 

6356 .. deprecated:: 2.1 Passing expressions to 

6357 :meth:`_sql.Select.distinct` is deprecated, use 

6358 :func:`_postgresql.distinct_on` instead. 

6359 

6360 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6361 and will raise :class:`_exc.CompileError` in a future version. 

6362 

6363 .. seealso:: 

6364 

6365 :func:`_postgresql.distinct_on` 

6366 

6367 :meth:`_sql.HasSyntaxExtensions.ext` 

6368 """ 

6369 self._distinct = True 

6370 if expr: 

6371 warn_deprecated( 

6372 "Passing expression to ``distinct`` to generate a " 

6373 "DISTINCT ON clause is deprecated. Use instead the " 

6374 "``postgresql.distinct_on`` function as an extension.", 

6375 "2.1", 

6376 ) 

6377 self._distinct_on = self._distinct_on + tuple( 

6378 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6379 for e in expr 

6380 ) 

6381 return self 

6382 

6383 @_generative 

6384 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6385 r"""Return a new :func:`_expression.select` construct with the 

6386 given FROM expression(s) 

6387 merged into its list of FROM objects. 

6388 

6389 E.g.:: 

6390 

6391 table1 = table("t1", column("a")) 

6392 table2 = table("t2", column("b")) 

6393 s = select(table1.c.a).select_from( 

6394 table1.join(table2, table1.c.a == table2.c.b) 

6395 ) 

6396 

6397 The "from" list is a unique set on the identity of each element, 

6398 so adding an already present :class:`_schema.Table` 

6399 or other selectable 

6400 will have no effect. Passing a :class:`_expression.Join` that refers 

6401 to an already present :class:`_schema.Table` 

6402 or other selectable will have 

6403 the effect of concealing the presence of that selectable as 

6404 an individual element in the rendered FROM list, instead 

6405 rendering it into a JOIN clause. 

6406 

6407 While the typical purpose of :meth:`_expression.Select.select_from` 

6408 is to 

6409 replace the default, derived FROM clause with a join, it can 

6410 also be called with individual table elements, multiple times 

6411 if desired, in the case that the FROM clause cannot be fully 

6412 derived from the columns clause:: 

6413 

6414 select(func.count("*")).select_from(table1) 

6415 

6416 """ 

6417 

6418 self._from_obj += tuple( 

6419 coercions.expect( 

6420 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6421 ) 

6422 for fromclause in froms 

6423 ) 

6424 return self 

6425 

6426 @_generative 

6427 def correlate( 

6428 self, 

6429 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6430 ) -> Self: 

6431 r"""Return a new :class:`_expression.Select` 

6432 which will correlate the given FROM 

6433 clauses to that of an enclosing :class:`_expression.Select`. 

6434 

6435 Calling this method turns off the :class:`_expression.Select` object's 

6436 default behavior of "auto-correlation". Normally, FROM elements 

6437 which appear in a :class:`_expression.Select` 

6438 that encloses this one via 

6439 its :term:`WHERE clause`, ORDER BY, HAVING or 

6440 :term:`columns clause` will be omitted from this 

6441 :class:`_expression.Select` 

6442 object's :term:`FROM clause`. 

6443 Setting an explicit correlation collection using the 

6444 :meth:`_expression.Select.correlate` 

6445 method provides a fixed list of FROM objects 

6446 that can potentially take place in this process. 

6447 

6448 When :meth:`_expression.Select.correlate` 

6449 is used to apply specific FROM clauses 

6450 for correlation, the FROM elements become candidates for 

6451 correlation regardless of how deeply nested this 

6452 :class:`_expression.Select` 

6453 object is, relative to an enclosing :class:`_expression.Select` 

6454 which refers to 

6455 the same FROM object. This is in contrast to the behavior of 

6456 "auto-correlation" which only correlates to an immediate enclosing 

6457 :class:`_expression.Select`. 

6458 Multi-level correlation ensures that the link 

6459 between enclosed and enclosing :class:`_expression.Select` 

6460 is always via 

6461 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6462 correlation to take place. 

6463 

6464 If ``None`` is passed, the :class:`_expression.Select` 

6465 object will correlate 

6466 none of its FROM entries, and all will render unconditionally 

6467 in the local FROM clause. 

6468 

6469 :param \*fromclauses: one or more :class:`.FromClause` or other 

6470 FROM-compatible construct such as an ORM mapped entity to become part 

6471 of the correlate collection; alternatively pass a single value 

6472 ``None`` to remove all existing correlations. 

6473 

6474 .. seealso:: 

6475 

6476 :meth:`_expression.Select.correlate_except` 

6477 

6478 :ref:`tutorial_scalar_subquery` 

6479 

6480 """ 

6481 

6482 # tests failing when we try to change how these 

6483 # arguments are passed 

6484 

6485 self._auto_correlate = False 

6486 if not fromclauses or fromclauses[0] in {None, False}: 

6487 if len(fromclauses) > 1: 

6488 raise exc.ArgumentError( 

6489 "additional FROM objects not accepted when " 

6490 "passing None/False to correlate()" 

6491 ) 

6492 self._correlate = () 

6493 else: 

6494 self._correlate = self._correlate + tuple( 

6495 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6496 ) 

6497 return self 

6498 

6499 @_generative 

6500 def correlate_except( 

6501 self, 

6502 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6503 ) -> Self: 

6504 r"""Return a new :class:`_expression.Select` 

6505 which will omit the given FROM 

6506 clauses from the auto-correlation process. 

6507 

6508 Calling :meth:`_expression.Select.correlate_except` turns off the 

6509 :class:`_expression.Select` object's default behavior of 

6510 "auto-correlation" for the given FROM elements. An element 

6511 specified here will unconditionally appear in the FROM list, while 

6512 all other FROM elements remain subject to normal auto-correlation 

6513 behaviors. 

6514 

6515 If ``None`` is passed, or no arguments are passed, 

6516 the :class:`_expression.Select` object will correlate all of its 

6517 FROM entries. 

6518 

6519 :param \*fromclauses: a list of one or more 

6520 :class:`_expression.FromClause` 

6521 constructs, or other compatible constructs (i.e. ORM-mapped 

6522 classes) to become part of the correlate-exception collection. 

6523 

6524 .. seealso:: 

6525 

6526 :meth:`_expression.Select.correlate` 

6527 

6528 :ref:`tutorial_scalar_subquery` 

6529 

6530 """ 

6531 

6532 self._auto_correlate = False 

6533 if not fromclauses or fromclauses[0] in {None, False}: 

6534 if len(fromclauses) > 1: 

6535 raise exc.ArgumentError( 

6536 "additional FROM objects not accepted when " 

6537 "passing None/False to correlate_except()" 

6538 ) 

6539 self._correlate_except = () 

6540 else: 

6541 self._correlate_except = (self._correlate_except or ()) + tuple( 

6542 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6543 ) 

6544 

6545 return self 

6546 

6547 @HasMemoized_ro_memoized_attribute 

6548 def selected_columns( 

6549 self, 

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

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

6552 representing the columns that 

6553 this SELECT statement or similar construct returns in its result set, 

6554 not including :class:`_sql.TextClause` constructs. 

6555 

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

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

6558 within this collection cannot be directly nested inside another SELECT 

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

6560 necessary parenthesization required by SQL. 

6561 

6562 For a :func:`_expression.select` construct, the collection here is 

6563 exactly what would be rendered inside the "SELECT" statement, and the 

6564 :class:`_expression.ColumnElement` objects are directly present as they 

6565 were given, e.g.:: 

6566 

6567 col1 = column("q", Integer) 

6568 col2 = column("p", Integer) 

6569 stmt = select(col1, col2) 

6570 

6571 Above, ``stmt.selected_columns`` would be a collection that contains 

6572 the ``col1`` and ``col2`` objects directly. For a statement that is 

6573 against a :class:`_schema.Table` or other 

6574 :class:`_expression.FromClause`, the collection will use the 

6575 :class:`_expression.ColumnElement` objects that are in the 

6576 :attr:`_expression.FromClause.c` collection of the from element. 

6577 

6578 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6579 to allow the existing columns to be referenced when adding additional 

6580 criteria, e.g.:: 

6581 

6582 def filter_on_id(my_select, id): 

6583 return my_select.where(my_select.selected_columns["id"] == id) 

6584 

6585 

6586 stmt = select(MyModel) 

6587 

6588 # adds "WHERE id=:param" to the statement 

6589 stmt = filter_on_id(stmt, 42) 

6590 

6591 .. note:: 

6592 

6593 The :attr:`_sql.Select.selected_columns` collection does not 

6594 include expressions established in the columns clause using the 

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

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

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

6598 construct. 

6599 

6600 

6601 .. versionadded:: 1.4 

6602 

6603 """ 

6604 

6605 # compare to SelectState._generate_columns_plus_names, which 

6606 # generates the actual names used in the SELECT string. that 

6607 # method is more complex because it also renders columns that are 

6608 # fully ambiguous, e.g. same column more than once. 

6609 conv = cast( 

6610 "Callable[[Any], str]", 

6611 SelectState._column_naming_convention(self._label_style), 

6612 ) 

6613 

6614 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6615 [ 

6616 (conv(c), c) 

6617 for c in self._all_selected_columns 

6618 if is_column_element(c) 

6619 ] 

6620 ) 

6621 return cc.as_readonly() 

6622 

6623 @HasMemoized_ro_memoized_attribute 

6624 def _all_selected_columns(self) -> _SelectIterable: 

6625 meth = SelectState.get_plugin_class(self).all_selected_columns 

6626 return list(meth(self)) 

6627 

6628 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6629 if self._label_style is LABEL_STYLE_NONE: 

6630 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6631 return self 

6632 

6633 def _generate_fromclause_column_proxies( 

6634 self, 

6635 subquery: FromClause, 

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

6637 primary_key: ColumnSet, 

6638 foreign_keys: Set[KeyedColumnElement[Any]], 

6639 *, 

6640 proxy_compound_columns: Optional[ 

6641 Iterable[Sequence[ColumnElement[Any]]] 

6642 ] = None, 

6643 ) -> None: 

6644 """Generate column proxies to place in the exported ``.c`` 

6645 collection of a subquery.""" 

6646 

6647 if proxy_compound_columns: 

6648 extra_col_iterator = proxy_compound_columns 

6649 prox = [ 

6650 c._make_proxy( 

6651 subquery, 

6652 key=proxy_key, 

6653 name=required_label_name, 

6654 name_is_truncatable=True, 

6655 compound_select_cols=extra_cols, 

6656 primary_key=primary_key, 

6657 foreign_keys=foreign_keys, 

6658 ) 

6659 for ( 

6660 ( 

6661 required_label_name, 

6662 proxy_key, 

6663 fallback_label_name, 

6664 c, 

6665 repeated, 

6666 ), 

6667 extra_cols, 

6668 ) in ( 

6669 zip( 

6670 self._generate_columns_plus_names(False), 

6671 extra_col_iterator, 

6672 ) 

6673 ) 

6674 if is_column_element(c) 

6675 ] 

6676 else: 

6677 prox = [ 

6678 c._make_proxy( 

6679 subquery, 

6680 key=proxy_key, 

6681 name=required_label_name, 

6682 name_is_truncatable=True, 

6683 primary_key=primary_key, 

6684 foreign_keys=foreign_keys, 

6685 ) 

6686 for ( 

6687 required_label_name, 

6688 proxy_key, 

6689 fallback_label_name, 

6690 c, 

6691 repeated, 

6692 ) in (self._generate_columns_plus_names(False)) 

6693 if is_column_element(c) 

6694 ] 

6695 

6696 columns._populate_separate_keys(prox) 

6697 

6698 def _needs_parens_for_grouping(self) -> bool: 

6699 return self._has_row_limiting_clause or bool( 

6700 self._order_by_clause.clauses 

6701 ) 

6702 

6703 def self_group( 

6704 self, against: Optional[OperatorType] = None 

6705 ) -> Union[SelectStatementGrouping[Self], Self]: 

6706 """Return a 'grouping' construct as per the 

6707 :class:`_expression.ClauseElement` specification. 

6708 

6709 This produces an element that can be embedded in an expression. Note 

6710 that this method is called automatically as needed when constructing 

6711 expressions and should not require explicit use. 

6712 

6713 """ 

6714 if ( 

6715 isinstance(against, CompoundSelect) 

6716 and not self._needs_parens_for_grouping() 

6717 ): 

6718 return self 

6719 else: 

6720 return SelectStatementGrouping(self) 

6721 

6722 def union( 

6723 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6724 ) -> CompoundSelect[Unpack[_Ts]]: 

6725 r"""Return a SQL ``UNION`` of this select() construct against 

6726 the given selectables provided as positional arguments. 

6727 

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

6729 UNION. 

6730 

6731 .. versionchanged:: 1.4.28 

6732 

6733 multiple elements are now accepted. 

6734 

6735 :param \**kwargs: keyword arguments are forwarded to the constructor 

6736 for the newly created :class:`_sql.CompoundSelect` object. 

6737 

6738 """ 

6739 return CompoundSelect._create_union(self, *other) 

6740 

6741 def union_all( 

6742 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6743 ) -> CompoundSelect[Unpack[_Ts]]: 

6744 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6745 the given selectables provided as positional arguments. 

6746 

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

6748 UNION. 

6749 

6750 .. versionchanged:: 1.4.28 

6751 

6752 multiple elements are now accepted. 

6753 

6754 :param \**kwargs: keyword arguments are forwarded to the constructor 

6755 for the newly created :class:`_sql.CompoundSelect` object. 

6756 

6757 """ 

6758 return CompoundSelect._create_union_all(self, *other) 

6759 

6760 def except_( 

6761 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6762 ) -> CompoundSelect[Unpack[_Ts]]: 

6763 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6764 the given selectable provided as positional arguments. 

6765 

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

6767 UNION. 

6768 

6769 .. versionchanged:: 1.4.28 

6770 

6771 multiple elements are now accepted. 

6772 

6773 """ 

6774 return CompoundSelect._create_except(self, *other) 

6775 

6776 def except_all( 

6777 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6778 ) -> CompoundSelect[Unpack[_Ts]]: 

6779 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6780 the given selectables provided as positional arguments. 

6781 

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

6783 UNION. 

6784 

6785 .. versionchanged:: 1.4.28 

6786 

6787 multiple elements are now accepted. 

6788 

6789 """ 

6790 return CompoundSelect._create_except_all(self, *other) 

6791 

6792 def intersect( 

6793 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6794 ) -> CompoundSelect[Unpack[_Ts]]: 

6795 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6796 the given selectables provided as positional arguments. 

6797 

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

6799 UNION. 

6800 

6801 .. versionchanged:: 1.4.28 

6802 

6803 multiple elements are now accepted. 

6804 

6805 :param \**kwargs: keyword arguments are forwarded to the constructor 

6806 for the newly created :class:`_sql.CompoundSelect` object. 

6807 

6808 """ 

6809 return CompoundSelect._create_intersect(self, *other) 

6810 

6811 def intersect_all( 

6812 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6813 ) -> CompoundSelect[Unpack[_Ts]]: 

6814 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6815 against the given selectables provided as positional arguments. 

6816 

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

6818 UNION. 

6819 

6820 .. versionchanged:: 1.4.28 

6821 

6822 multiple elements are now accepted. 

6823 

6824 :param \**kwargs: keyword arguments are forwarded to the constructor 

6825 for the newly created :class:`_sql.CompoundSelect` object. 

6826 

6827 """ 

6828 return CompoundSelect._create_intersect_all(self, *other) 

6829 

6830 

6831class ScalarSelect( 

6832 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6833): 

6834 """Represent a scalar subquery. 

6835 

6836 

6837 A :class:`_sql.ScalarSelect` is created by invoking the 

6838 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6839 then participates in other SQL expressions as a SQL column expression 

6840 within the :class:`_sql.ColumnElement` hierarchy. 

6841 

6842 .. seealso:: 

6843 

6844 :meth:`_sql.SelectBase.scalar_subquery` 

6845 

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

6847 

6848 """ 

6849 

6850 _traverse_internals: _TraverseInternalsType = [ 

6851 ("element", InternalTraversal.dp_clauseelement), 

6852 ("type", InternalTraversal.dp_type), 

6853 ] 

6854 

6855 _from_objects: List[FromClause] = [] 

6856 _is_from_container = True 

6857 if not TYPE_CHECKING: 

6858 _is_implicitly_boolean = False 

6859 inherit_cache = True 

6860 

6861 element: SelectBase 

6862 

6863 def __init__(self, element: SelectBase) -> None: 

6864 self.element = element 

6865 self.type = element._scalar_type() 

6866 self._propagate_attrs = element._propagate_attrs 

6867 

6868 def __getattr__(self, attr: str) -> Any: 

6869 return getattr(self.element, attr) 

6870 

6871 def __getstate__(self) -> Dict[str, Any]: 

6872 return {"element": self.element, "type": self.type} 

6873 

6874 def __setstate__(self, state: Dict[str, Any]) -> None: 

6875 self.element = state["element"] 

6876 self.type = state["type"] 

6877 

6878 @property 

6879 def columns(self) -> NoReturn: 

6880 raise exc.InvalidRequestError( 

6881 "Scalar Select expression has no " 

6882 "columns; use this object directly " 

6883 "within a column-level expression." 

6884 ) 

6885 

6886 c = columns 

6887 

6888 @_generative 

6889 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6890 """Apply a WHERE clause to the SELECT statement referred to 

6891 by this :class:`_expression.ScalarSelect`. 

6892 

6893 """ 

6894 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6895 crit 

6896 ) 

6897 return self 

6898 

6899 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6900 return self 

6901 

6902 def _ungroup(self) -> Self: 

6903 return self 

6904 

6905 @_generative 

6906 def correlate( 

6907 self, 

6908 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6909 ) -> Self: 

6910 r"""Return a new :class:`_expression.ScalarSelect` 

6911 which will correlate the given FROM 

6912 clauses to that of an enclosing :class:`_expression.Select`. 

6913 

6914 This method is mirrored from the :meth:`_sql.Select.correlate` method 

6915 of the underlying :class:`_sql.Select`. The method applies the 

6916 :meth:_sql.Select.correlate` method, then returns a new 

6917 :class:`_sql.ScalarSelect` against that statement. 

6918 

6919 .. versionadded:: 1.4 Previously, the 

6920 :meth:`_sql.ScalarSelect.correlate` 

6921 method was only available from :class:`_sql.Select`. 

6922 

6923 :param \*fromclauses: a list of one or more 

6924 :class:`_expression.FromClause` 

6925 constructs, or other compatible constructs (i.e. ORM-mapped 

6926 classes) to become part of the correlate collection. 

6927 

6928 .. seealso:: 

6929 

6930 :meth:`_expression.ScalarSelect.correlate_except` 

6931 

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

6933 

6934 

6935 """ 

6936 self.element = cast( 

6937 "Select[Unpack[TupleAny]]", self.element 

6938 ).correlate(*fromclauses) 

6939 return self 

6940 

6941 @_generative 

6942 def correlate_except( 

6943 self, 

6944 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6945 ) -> Self: 

6946 r"""Return a new :class:`_expression.ScalarSelect` 

6947 which will omit the given FROM 

6948 clauses from the auto-correlation process. 

6949 

6950 This method is mirrored from the 

6951 :meth:`_sql.Select.correlate_except` method of the underlying 

6952 :class:`_sql.Select`. The method applies the 

6953 :meth:_sql.Select.correlate_except` method, then returns a new 

6954 :class:`_sql.ScalarSelect` against that statement. 

6955 

6956 .. versionadded:: 1.4 Previously, the 

6957 :meth:`_sql.ScalarSelect.correlate_except` 

6958 method was only available from :class:`_sql.Select`. 

6959 

6960 :param \*fromclauses: a list of one or more 

6961 :class:`_expression.FromClause` 

6962 constructs, or other compatible constructs (i.e. ORM-mapped 

6963 classes) to become part of the correlate-exception collection. 

6964 

6965 .. seealso:: 

6966 

6967 :meth:`_expression.ScalarSelect.correlate` 

6968 

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

6970 

6971 

6972 """ 

6973 

6974 self.element = cast( 

6975 "Select[Unpack[TupleAny]]", self.element 

6976 ).correlate_except(*fromclauses) 

6977 return self 

6978 

6979 

6980class Exists(UnaryExpression[bool]): 

6981 """Represent an ``EXISTS`` clause. 

6982 

6983 See :func:`_sql.exists` for a description of usage. 

6984 

6985 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

6986 instance by calling :meth:`_sql.SelectBase.exists`. 

6987 

6988 """ 

6989 

6990 inherit_cache = True 

6991 

6992 def __init__( 

6993 self, 

6994 __argument: Optional[ 

6995 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

6996 ] = None, 

6997 /, 

6998 ): 

6999 s: ScalarSelect[Any] 

7000 

7001 # TODO: this seems like we should be using coercions for this 

7002 if __argument is None: 

7003 s = Select(literal_column("*")).scalar_subquery() 

7004 elif isinstance(__argument, SelectBase): 

7005 s = __argument.scalar_subquery() 

7006 s._propagate_attrs = __argument._propagate_attrs 

7007 elif isinstance(__argument, ScalarSelect): 

7008 s = __argument 

7009 else: 

7010 s = Select(__argument).scalar_subquery() 

7011 

7012 UnaryExpression.__init__( 

7013 self, 

7014 s, 

7015 operator=operators.exists, 

7016 type_=type_api.BOOLEANTYPE, 

7017 ) 

7018 

7019 @util.ro_non_memoized_property 

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

7021 return [] 

7022 

7023 def _regroup( 

7024 self, 

7025 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7026 ) -> ScalarSelect[Any]: 

7027 

7028 assert isinstance(self.element, ScalarSelect) 

7029 element = self.element.element 

7030 if not isinstance(element, Select): 

7031 raise exc.InvalidRequestError( 

7032 "Can only apply this operation to a plain SELECT construct" 

7033 ) 

7034 new_element = fn(element) 

7035 

7036 return_value = new_element.scalar_subquery() 

7037 return return_value 

7038 

7039 def select(self) -> Select[bool]: 

7040 r"""Return a SELECT of this :class:`_expression.Exists`. 

7041 

7042 e.g.:: 

7043 

7044 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7045 

7046 This will produce a statement resembling: 

7047 

7048 .. sourcecode:: sql 

7049 

7050 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7051 

7052 .. seealso:: 

7053 

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

7055 method which allows for arbitrary column lists. 

7056 

7057 """ # noqa 

7058 

7059 return Select(self) 

7060 

7061 def correlate( 

7062 self, 

7063 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7064 ) -> Self: 

7065 """Apply correlation to the subquery noted by this 

7066 :class:`_sql.Exists`. 

7067 

7068 .. seealso:: 

7069 

7070 :meth:`_sql.ScalarSelect.correlate` 

7071 

7072 """ 

7073 e = self._clone() 

7074 e.element = self._regroup( 

7075 lambda element: element.correlate(*fromclauses) 

7076 ) 

7077 return e 

7078 

7079 def correlate_except( 

7080 self, 

7081 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7082 ) -> Self: 

7083 """Apply correlation to the subquery noted by this 

7084 :class:`_sql.Exists`. 

7085 

7086 .. seealso:: 

7087 

7088 :meth:`_sql.ScalarSelect.correlate_except` 

7089 

7090 """ 

7091 e = self._clone() 

7092 e.element = self._regroup( 

7093 lambda element: element.correlate_except(*fromclauses) 

7094 ) 

7095 return e 

7096 

7097 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7098 """Return a new :class:`_expression.Exists` construct, 

7099 applying the given 

7100 expression to the :meth:`_expression.Select.select_from` 

7101 method of the select 

7102 statement contained. 

7103 

7104 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7105 statement first, including the desired WHERE clause, then use the 

7106 :meth:`_sql.SelectBase.exists` method to produce an 

7107 :class:`_sql.Exists` object at once. 

7108 

7109 """ 

7110 e = self._clone() 

7111 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7112 return e 

7113 

7114 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7115 """Return a new :func:`_expression.exists` construct with the 

7116 given expression added to 

7117 its WHERE clause, joined to the existing clause via AND, if any. 

7118 

7119 

7120 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7121 statement first, including the desired WHERE clause, then use the 

7122 :meth:`_sql.SelectBase.exists` method to produce an 

7123 :class:`_sql.Exists` object at once. 

7124 

7125 """ 

7126 e = self._clone() 

7127 e.element = self._regroup(lambda element: element.where(*clause)) 

7128 return e 

7129 

7130 

7131class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7132 """Wrap a :class:`_expression.TextClause` construct within a 

7133 :class:`_expression.SelectBase` 

7134 interface. 

7135 

7136 This allows the :class:`_expression.TextClause` object to gain a 

7137 ``.c`` collection 

7138 and other FROM-like capabilities such as 

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

7140 :meth:`_expression.SelectBase.cte`, etc. 

7141 

7142 The :class:`_expression.TextualSelect` construct is produced via the 

7143 :meth:`_expression.TextClause.columns` 

7144 method - see that method for details. 

7145 

7146 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7147 class was renamed 

7148 from ``TextAsFrom``, to more correctly suit its role as a 

7149 SELECT-oriented object and not a FROM clause. 

7150 

7151 .. seealso:: 

7152 

7153 :func:`_expression.text` 

7154 

7155 :meth:`_expression.TextClause.columns` - primary creation interface. 

7156 

7157 """ 

7158 

7159 __visit_name__ = "textual_select" 

7160 

7161 _label_style = LABEL_STYLE_NONE 

7162 

7163 _traverse_internals: _TraverseInternalsType = ( 

7164 [ 

7165 ("element", InternalTraversal.dp_clauseelement), 

7166 ("column_args", InternalTraversal.dp_clauseelement_list), 

7167 ] 

7168 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7169 + HasCTE._has_ctes_traverse_internals 

7170 + Executable._executable_traverse_internals 

7171 ) 

7172 

7173 _is_textual = True 

7174 

7175 is_text = True 

7176 is_select = True 

7177 

7178 def __init__( 

7179 self, 

7180 text: TextClause, 

7181 columns: List[_ColumnExpressionArgument[Any]], 

7182 positional: bool = False, 

7183 ) -> None: 

7184 self._init( 

7185 text, 

7186 # convert for ORM attributes->columns, etc 

7187 [ 

7188 coercions.expect(roles.LabeledColumnExprRole, c) 

7189 for c in columns 

7190 ], 

7191 positional, 

7192 ) 

7193 

7194 def _init( 

7195 self, 

7196 text: TextClause, 

7197 columns: List[NamedColumn[Any]], 

7198 positional: bool = False, 

7199 ) -> None: 

7200 self.element = text 

7201 self.column_args = columns 

7202 self.positional = positional 

7203 

7204 @HasMemoized_ro_memoized_attribute 

7205 def selected_columns( 

7206 self, 

7207 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

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

7209 representing the columns that 

7210 this SELECT statement or similar construct returns in its result set, 

7211 not including :class:`_sql.TextClause` constructs. 

7212 

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

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

7215 within this collection cannot be directly nested inside another SELECT 

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

7217 necessary parenthesization required by SQL. 

7218 

7219 For a :class:`_expression.TextualSelect` construct, the collection 

7220 contains the :class:`_expression.ColumnElement` objects that were 

7221 passed to the constructor, typically via the 

7222 :meth:`_expression.TextClause.columns` method. 

7223 

7224 

7225 .. versionadded:: 1.4 

7226 

7227 """ 

7228 return ColumnCollection( 

7229 (c.key, c) for c in self.column_args 

7230 ).as_readonly() 

7231 

7232 @util.ro_non_memoized_property 

7233 def _all_selected_columns(self) -> _SelectIterable: 

7234 return self.column_args 

7235 

7236 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7237 return self 

7238 

7239 def _ensure_disambiguated_names(self) -> TextualSelect: 

7240 return self 

7241 

7242 @_generative 

7243 def bindparams( 

7244 self, 

7245 *binds: BindParameter[Any], 

7246 **bind_as_values: Any, 

7247 ) -> Self: 

7248 self.element = self.element.bindparams(*binds, **bind_as_values) 

7249 return self 

7250 

7251 def _generate_fromclause_column_proxies( 

7252 self, 

7253 fromclause: FromClause, 

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

7255 primary_key: ColumnSet, 

7256 foreign_keys: Set[KeyedColumnElement[Any]], 

7257 *, 

7258 proxy_compound_columns: Optional[ 

7259 Iterable[Sequence[ColumnElement[Any]]] 

7260 ] = None, 

7261 ) -> None: 

7262 if TYPE_CHECKING: 

7263 assert isinstance(fromclause, Subquery) 

7264 

7265 if proxy_compound_columns: 

7266 columns._populate_separate_keys( 

7267 c._make_proxy( 

7268 fromclause, 

7269 compound_select_cols=extra_cols, 

7270 primary_key=primary_key, 

7271 foreign_keys=foreign_keys, 

7272 ) 

7273 for c, extra_cols in zip( 

7274 self.column_args, proxy_compound_columns 

7275 ) 

7276 ) 

7277 else: 

7278 columns._populate_separate_keys( 

7279 c._make_proxy( 

7280 fromclause, 

7281 primary_key=primary_key, 

7282 foreign_keys=foreign_keys, 

7283 ) 

7284 for c in self.column_args 

7285 ) 

7286 

7287 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7288 return self.column_args[0].type 

7289 

7290 

7291TextAsFrom = TextualSelect 

7292"""Backwards compatibility with the previous name""" 

7293 

7294 

7295class AnnotatedFromClause(Annotated): 

7296 def _copy_internals(self, **kw: Any) -> None: 

7297 super()._copy_internals(**kw) 

7298 if kw.get("ind_cols_on_fromclause", False): 

7299 ee = self._Annotated__element # type: ignore 

7300 

7301 self.c = ee.__class__.c.fget(self) # type: ignore 

7302 

7303 @util.ro_memoized_property 

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

7305 """proxy the .c collection of the underlying FromClause. 

7306 

7307 Originally implemented in 2008 as a simple load of the .c collection 

7308 when the annotated construct was created (see d3621ae961a), in modern 

7309 SQLAlchemy versions this can be expensive for statements constructed 

7310 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7311 it, which works just as well. 

7312 

7313 Two different use cases seem to require the collection either copied 

7314 from the underlying one, or unique to this AnnotatedFromClause. 

7315 

7316 See test_selectable->test_annotated_corresponding_column 

7317 

7318 """ 

7319 ee = self._Annotated__element # type: ignore 

7320 return ee.c # type: ignore