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

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

1756 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import NamedTuple 

30from typing import NoReturn 

31from typing import Optional 

32from typing import overload 

33from typing import Sequence 

34from typing import Set 

35from typing import Tuple 

36from typing import Type 

37from typing import TYPE_CHECKING 

38from typing import TypeVar 

39from typing import Union 

40 

41from . import cache_key 

42from . import coercions 

43from . import operators 

44from . import roles 

45from . import traversals 

46from . import type_api 

47from . import visitors 

48from ._typing import _ColumnsClauseArgument 

49from ._typing import _no_kw 

50from ._typing import _T 

51from ._typing import _TP 

52from ._typing import is_column_element 

53from ._typing import is_select_statement 

54from ._typing import is_subquery 

55from ._typing import is_table 

56from ._typing import is_text_clause 

57from .annotation import Annotated 

58from .annotation import SupportsCloneAnnotations 

59from .base import _clone 

60from .base import _cloned_difference 

61from .base import _cloned_intersection 

62from .base import _entity_namespace_key 

63from .base import _EntityNamespace 

64from .base import _expand_cloned 

65from .base import _from_objects 

66from .base import _generative 

67from .base import _never_select_column 

68from .base import _NoArg 

69from .base import _select_iterables 

70from .base import CacheableOptions 

71from .base import ColumnCollection 

72from .base import ColumnSet 

73from .base import CompileState 

74from .base import DedupeColumnCollection 

75from .base import DialectKWArgs 

76from .base import Executable 

77from .base import Generative 

78from .base import HasCompileState 

79from .base import HasMemoized 

80from .base import Immutable 

81from .coercions import _document_text_coercion 

82from .elements import _anonymous_label 

83from .elements import BindParameter 

84from .elements import BooleanClauseList 

85from .elements import ClauseElement 

86from .elements import ClauseList 

87from .elements import ColumnClause 

88from .elements import ColumnElement 

89from .elements import DQLDMLClauseElement 

90from .elements import GroupedElement 

91from .elements import literal_column 

92from .elements import TableValuedColumn 

93from .elements import UnaryExpression 

94from .operators import OperatorType 

95from .sqltypes import NULLTYPE 

96from .visitors import _TraverseInternalsType 

97from .visitors import InternalTraversal 

98from .visitors import prefix_anon_map 

99from .. import exc 

100from .. import util 

101from ..util import HasMemoized_ro_memoized_attribute 

102from ..util.typing import Literal 

103from ..util.typing import Protocol 

104from ..util.typing import Self 

105 

106 

107and_ = BooleanClauseList.and_ 

108 

109 

110if TYPE_CHECKING: 

111 from ._typing import _ColumnExpressionArgument 

112 from ._typing import _ColumnExpressionOrStrLabelArgument 

113 from ._typing import _FromClauseArgument 

114 from ._typing import _JoinTargetArgument 

115 from ._typing import _LimitOffsetType 

116 from ._typing import _MAYBE_ENTITY 

117 from ._typing import _NOT_ENTITY 

118 from ._typing import _OnClauseArgument 

119 from ._typing import _SelectStatementForCompoundArgument 

120 from ._typing import _T0 

121 from ._typing import _T1 

122 from ._typing import _T2 

123 from ._typing import _T3 

124 from ._typing import _T4 

125 from ._typing import _T5 

126 from ._typing import _T6 

127 from ._typing import _T7 

128 from ._typing import _TextCoercedExpressionArgument 

129 from ._typing import _TypedColumnClauseArgument as _TCCA 

130 from ._typing import _TypeEngineArgument 

131 from .base import _AmbiguousTableNameMap 

132 from .base import ExecutableOption 

133 from .base import ReadOnlyColumnCollection 

134 from .cache_key import _CacheKeyTraversalType 

135 from .compiler import SQLCompiler 

136 from .dml import Delete 

137 from .dml import Update 

138 from .elements import BinaryExpression 

139 from .elements import KeyedColumnElement 

140 from .elements import Label 

141 from .elements import NamedColumn 

142 from .elements import TextClause 

143 from .functions import Function 

144 from .schema import ForeignKey 

145 from .schema import ForeignKeyConstraint 

146 from .sqltypes import TableValueType 

147 from .type_api import TypeEngine 

148 from .visitors import _CloneCallableType 

149 

150 

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

152_LabelConventionCallable = Callable[ 

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

154] 

155 

156 

157class _JoinTargetProtocol(Protocol): 

158 @util.ro_non_memoized_property 

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

160 

161 @util.ro_non_memoized_property 

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

163 

164 

165_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

167 

168_ForUpdateOfArgument = Union[ 

169 # single column, Table, ORM Entity 

170 Union[ 

171 "_ColumnExpressionArgument[Any]", 

172 "_FromClauseArgument", 

173 ], 

174 # or sequence of single column elements 

175 Sequence["_ColumnExpressionArgument[Any]"], 

176] 

177 

178 

179_SetupJoinsElement = Tuple[ 

180 _JoinTargetElement, 

181 Optional[_OnClauseElement], 

182 Optional["FromClause"], 

183 Dict[str, Any], 

184] 

185 

186 

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

188 

189 

190class _OffsetLimitParam(BindParameter[int]): 

191 inherit_cache = True 

192 

193 @property 

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

195 return self.effective_value 

196 

197 

198class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

200 columns that can represent rows. 

201 

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

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

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

205 PostgreSQL has functions that return rows also. 

206 

207 .. versionadded:: 1.4 

208 

209 """ 

210 

211 _is_returns_rows = True 

212 

213 # sub-elements of returns_rows 

214 _is_from_clause = False 

215 _is_select_base = False 

216 _is_select_statement = False 

217 _is_lateral = False 

218 

219 @property 

220 def selectable(self) -> ReturnsRows: 

221 return self 

222 

223 @util.ro_non_memoized_property 

224 def _all_selected_columns(self) -> _SelectIterable: 

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

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

227 

228 This is typically equivalent to .exported_columns except it is 

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

230 :class:`_expression.ColumnCollection`. 

231 

232 """ 

233 raise NotImplementedError() 

234 

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

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

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

238 

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

240 

241 """ 

242 raise NotImplementedError() 

243 

244 def _generate_fromclause_column_proxies( 

245 self, 

246 fromclause: FromClause, 

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

248 primary_key: ColumnSet, 

249 foreign_keys: Set[KeyedColumnElement[Any]], 

250 ) -> None: 

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

252 

253 raise NotImplementedError() 

254 

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

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

257 raise NotImplementedError() 

258 

259 @property 

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

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

262 that represents the "exported" 

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

264 

265 The "exported" columns represent the collection of 

266 :class:`_expression.ColumnElement` 

267 expressions that are rendered by this SQL 

268 construct. There are primary varieties which are the 

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

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

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

272 columns in a DML statement.. 

273 

274 .. versionadded:: 1.4 

275 

276 .. seealso:: 

277 

278 :attr:`_expression.FromClause.exported_columns` 

279 

280 :attr:`_expression.SelectBase.exported_columns` 

281 """ 

282 

283 raise NotImplementedError() 

284 

285 

286class ExecutableReturnsRows(Executable, ReturnsRows): 

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

288 

289 

290class TypedReturnsRows(ExecutableReturnsRows, Generic[_TP]): 

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

292 

293 

294class Selectable(ReturnsRows): 

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

296 

297 __visit_name__ = "selectable" 

298 

299 is_selectable = True 

300 

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

302 raise NotImplementedError() 

303 

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

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

306 

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

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

309 

310 .. seealso:: 

311 

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

313 

314 """ 

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

316 

317 @util.deprecated( 

318 "1.4", 

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

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

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

322 ) 

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

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

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

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

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

328 

329 """ 

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

331 

332 def corresponding_column( 

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

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

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

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

337 :attr:`_expression.Selectable.exported_columns` 

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

339 which corresponds to that 

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

341 column. 

342 

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

344 to be matched. 

345 

346 :param require_embedded: only return corresponding columns for 

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

348 :class:`_expression.ColumnElement` 

349 is actually present within a sub-element 

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

351 Normally the column will match if 

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

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

354 

355 .. seealso:: 

356 

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

358 :class:`_expression.ColumnCollection` 

359 that is used for the operation. 

360 

361 :meth:`_expression.ColumnCollection.corresponding_column` 

362 - implementation 

363 method. 

364 

365 """ 

366 

367 return self.exported_columns.corresponding_column( 

368 column, require_embedded 

369 ) 

370 

371 

372class HasPrefixes: 

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

374 

375 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

376 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

377 ] 

378 

379 @_generative 

380 @_document_text_coercion( 

381 "prefixes", 

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

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

384 ) 

385 def prefix_with( 

386 self, 

387 *prefixes: _TextCoercedExpressionArgument[Any], 

388 dialect: str = "*", 

389 ) -> Self: 

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

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

392 

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

394 provided by MySQL. 

395 

396 E.g.:: 

397 

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

399 

400 # MySQL 5.7 optimizer hints 

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

402 

403 Multiple prefixes can be specified by multiple calls 

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

405 

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

407 construct which 

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

409 keyword. 

410 :param dialect: optional string dialect name which will 

411 limit rendering of this prefix to only that dialect. 

412 

413 """ 

414 self._prefixes = self._prefixes + tuple( 

415 [ 

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

417 for p in prefixes 

418 ] 

419 ) 

420 return self 

421 

422 

423class HasSuffixes: 

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

425 

426 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

427 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

428 ] 

429 

430 @_generative 

431 @_document_text_coercion( 

432 "suffixes", 

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

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

435 ) 

436 def suffix_with( 

437 self, 

438 *suffixes: _TextCoercedExpressionArgument[Any], 

439 dialect: str = "*", 

440 ) -> Self: 

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

442 

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

444 certain constructs. 

445 

446 E.g.:: 

447 

448 stmt = ( 

449 select(col1, col2) 

450 .cte() 

451 .suffix_with( 

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

453 ) 

454 ) 

455 

456 Multiple suffixes can be specified by multiple calls 

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

458 

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

460 construct which 

461 will be rendered following the target clause. 

462 :param dialect: Optional string dialect name which will 

463 limit rendering of this suffix to only that dialect. 

464 

465 """ 

466 self._suffixes = self._suffixes + tuple( 

467 [ 

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

469 for p in suffixes 

470 ] 

471 ) 

472 return self 

473 

474 

475class HasHints: 

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

477 util.immutabledict() 

478 ) 

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

480 

481 _has_hints_traverse_internals: _TraverseInternalsType = [ 

482 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

483 ("_hints", InternalTraversal.dp_table_hint_list), 

484 ] 

485 

486 @_generative 

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

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

489 other selectable object. 

490 

491 .. tip:: 

492 

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

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

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

496 the SELECT statement after the SELECT keyword, use the 

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

498 space, or for table-specific hints the 

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

500 hints in a dialect-specific location. 

501 

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

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

504 the statement as a whole. 

505 

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

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

508 etc. 

509 

510 .. seealso:: 

511 

512 :meth:`_expression.Select.with_hint` 

513 

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

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

516 MySQL or Oracle Database optimizer hints 

517 

518 """ 

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

520 

521 @_generative 

522 def with_hint( 

523 self, 

524 selectable: _FromClauseArgument, 

525 text: str, 

526 dialect_name: str = "*", 

527 ) -> Self: 

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

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

530 object. 

531 

532 .. tip:: 

533 

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

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

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

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

538 for MySQL or Oracle Database, use the 

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

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

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

542 

543 The text of the hint is rendered in the appropriate 

544 location for the database backend in use, relative 

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

546 passed as the 

547 ``selectable`` argument. The dialect implementation 

548 typically uses Python string substitution syntax 

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

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

551 following:: 

552 

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

554 

555 Would render SQL as: 

556 

557 .. sourcecode:: sql 

558 

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

560 

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

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

563 Database and MSSql simultaneously:: 

564 

565 select(mytable).with_hint( 

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

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

568 

569 .. seealso:: 

570 

571 :meth:`_expression.Select.with_statement_hint` 

572 

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

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

575 MySQL or Oracle Database optimizer hints 

576 

577 """ 

578 

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

580 

581 def _with_hint( 

582 self, 

583 selectable: Optional[_FromClauseArgument], 

584 text: str, 

585 dialect_name: str, 

586 ) -> Self: 

587 if selectable is None: 

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

589 else: 

590 self._hints = self._hints.union( 

591 { 

592 ( 

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

594 dialect_name, 

595 ): text 

596 } 

597 ) 

598 return self 

599 

600 

601class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

603 clause of a ``SELECT`` statement. 

604 

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

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

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

608 

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

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

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

612 :class:`_expression.ColumnElement` 

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

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

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

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

617 :meth:`_expression.FromClause.select`. 

618 

619 

620 """ 

621 

622 __visit_name__ = "fromclause" 

623 named_with_column = False 

624 

625 @util.ro_non_memoized_property 

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

627 return () 

628 

629 _is_clone_of: Optional[FromClause] 

630 

631 _columns: ColumnCollection[Any, Any] 

632 

633 schema: Optional[str] = None 

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

635 

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

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

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

639 

640 """ 

641 

642 is_selectable = True 

643 _is_from_clause = True 

644 _is_join = False 

645 

646 _use_schema_map = False 

647 

648 def select(self) -> Select[Any]: 

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

650 

651 

652 e.g.:: 

653 

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

655 

656 .. seealso:: 

657 

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

659 method which allows for arbitrary column lists. 

660 

661 """ 

662 return Select(self) 

663 

664 def join( 

665 self, 

666 right: _FromClauseArgument, 

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

668 isouter: bool = False, 

669 full: bool = False, 

670 ) -> Join: 

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

672 :class:`_expression.FromClause` 

673 to another :class:`FromClause`. 

674 

675 E.g.:: 

676 

677 from sqlalchemy import join 

678 

679 j = user_table.join( 

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

681 ) 

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

683 

684 would emit SQL along the lines of: 

685 

686 .. sourcecode:: sql 

687 

688 SELECT user.id, user.name FROM user 

689 JOIN address ON user.id = address.user_id 

690 

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

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

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

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

695 class. 

696 

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

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

699 will attempt to 

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

701 

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

703 

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

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

706 

707 .. seealso:: 

708 

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

710 

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

712 

713 """ 

714 

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

716 

717 def outerjoin( 

718 self, 

719 right: _FromClauseArgument, 

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

721 full: bool = False, 

722 ) -> Join: 

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

724 :class:`_expression.FromClause` 

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

726 True. 

727 

728 E.g.:: 

729 

730 from sqlalchemy import outerjoin 

731 

732 j = user_table.outerjoin( 

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

734 ) 

735 

736 The above is equivalent to:: 

737 

738 j = user_table.join( 

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

740 ) 

741 

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

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

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

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

746 class. 

747 

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

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

750 will attempt to 

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

752 

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

754 LEFT OUTER JOIN. 

755 

756 .. seealso:: 

757 

758 :meth:`_expression.FromClause.join` 

759 

760 :class:`_expression.Join` 

761 

762 """ # noqa: E501 

763 

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

765 

766 def alias( 

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

768 ) -> NamedFromClause: 

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

770 

771 E.g.:: 

772 

773 a2 = some_table.alias("a2") 

774 

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

776 object which can be used 

777 as a FROM clause in any SELECT statement. 

778 

779 .. seealso:: 

780 

781 :ref:`tutorial_using_aliases` 

782 

783 :func:`_expression.alias` 

784 

785 """ 

786 

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

788 

789 def tablesample( 

790 self, 

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

792 name: Optional[str] = None, 

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

794 ) -> TableSample: 

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

796 

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

798 construct also 

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

800 

801 .. seealso:: 

802 

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

804 

805 """ 

806 return TableSample._construct( 

807 self, sampling=sampling, name=name, seed=seed 

808 ) 

809 

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

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

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

813 

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

815 

816 """ 

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

818 # Other constructs override this to traverse through 

819 # contained elements. 

820 return fromclause in self._cloned_set 

821 

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

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

824 the other represent the same lexical identity. 

825 

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

827 if they are the same via annotation identity. 

828 

829 """ 

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

831 

832 @util.ro_non_memoized_property 

833 def description(self) -> str: 

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

835 

836 Used primarily for error message formatting. 

837 

838 """ 

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

840 

841 def _generate_fromclause_column_proxies( 

842 self, 

843 fromclause: FromClause, 

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

845 primary_key: ColumnSet, 

846 foreign_keys: Set[KeyedColumnElement[Any]], 

847 ) -> None: 

848 columns._populate_separate_keys( 

849 col._make_proxy( 

850 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

851 ) 

852 for col in self.c 

853 ) 

854 

855 @util.ro_non_memoized_property 

856 def exported_columns( 

857 self, 

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

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

860 that represents the "exported" 

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

862 

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

864 object are synonymous 

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

866 

867 .. versionadded:: 1.4 

868 

869 .. seealso:: 

870 

871 :attr:`_expression.Selectable.exported_columns` 

872 

873 :attr:`_expression.SelectBase.exported_columns` 

874 

875 

876 """ 

877 return self.c 

878 

879 @util.ro_non_memoized_property 

880 def columns( 

881 self, 

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

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

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

885 

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

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

888 other selectable-bound columns:: 

889 

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

891 

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

893 

894 """ 

895 return self.c 

896 

897 @util.ro_memoized_property 

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

899 """ 

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

901 

902 :return: a :class:`.ColumnCollection` 

903 

904 """ 

905 if "_columns" not in self.__dict__: 

906 self._setup_collections() 

907 return self._columns.as_readonly() 

908 

909 def _setup_collections(self) -> None: 

910 assert "_columns" not in self.__dict__ 

911 assert "primary_key" not in self.__dict__ 

912 assert "foreign_keys" not in self.__dict__ 

913 

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

915 primary_key = ColumnSet() 

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

917 

918 self._populate_column_collection( 

919 columns=_columns, 

920 primary_key=primary_key, 

921 foreign_keys=foreign_keys, 

922 ) 

923 

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

925 # but greatly reduces the surface for problems 

926 self._columns = _columns 

927 self.primary_key = primary_key # type: ignore 

928 self.foreign_keys = foreign_keys # type: ignore 

929 

930 @util.ro_non_memoized_property 

931 def entity_namespace(self) -> _EntityNamespace: 

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

933 

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

935 expressions, such as:: 

936 

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

938 

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

940 be overridden using the "entity_namespace" annotation to deliver 

941 alternative results. 

942 

943 """ 

944 return self.c 

945 

946 @util.ro_memoized_property 

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

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

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

950 

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

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

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

954 

955 """ 

956 self._setup_collections() 

957 return self.primary_key 

958 

959 @util.ro_memoized_property 

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

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

962 which this FromClause references. 

963 

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

965 :class:`_schema.Table`-wide 

966 :class:`_schema.ForeignKeyConstraint`. 

967 

968 .. seealso:: 

969 

970 :attr:`_schema.Table.foreign_key_constraints` 

971 

972 """ 

973 self._setup_collections() 

974 return self.foreign_keys 

975 

976 def _reset_column_collection(self) -> None: 

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

978 

979 This collection is separate from all the other memoized things 

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

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

982 has already established strong relationships 

983 with the exported columns. 

984 

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

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

987 

988 """ 

989 

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

991 self.__dict__.pop(key, None) 

992 

993 @util.ro_non_memoized_property 

994 def _select_iterable(self) -> _SelectIterable: 

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

996 

997 @property 

998 def _cols_populated(self) -> bool: 

999 return "_columns" in self.__dict__ 

1000 

1001 def _populate_column_collection( 

1002 self, 

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

1004 primary_key: ColumnSet, 

1005 foreign_keys: Set[KeyedColumnElement[Any]], 

1006 ) -> None: 

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

1008 

1009 Each implementation has a different way of establishing 

1010 this collection. 

1011 

1012 """ 

1013 

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

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

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

1017 selectable ultimately should proxy this column. 

1018 

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

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

1021 Table objects it ultimately derives from. 

1022 

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

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

1025 but it will return None. 

1026 

1027 This method is currently used by Declarative to allow Table 

1028 columns to be added to a partially constructed inheritance 

1029 mapping that may have already produced joins. The method 

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

1031 and/or caveats aren't yet clear. 

1032 

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

1034 default via an event, which would require that 

1035 selectables maintain a weak referencing collection of all 

1036 derivations. 

1037 

1038 """ 

1039 self._reset_column_collection() 

1040 

1041 def _anonymous_fromclause( 

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

1043 ) -> FromClause: 

1044 return self.alias(name=name) 

1045 

1046 if TYPE_CHECKING: 

1047 

1048 def self_group( 

1049 self, against: Optional[OperatorType] = None 

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

1051 

1052 

1053class NamedFromClause(FromClause): 

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

1055 

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

1057 

1058 .. versionadded:: 2.0 

1059 

1060 """ 

1061 

1062 named_with_column = True 

1063 

1064 name: str 

1065 

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

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

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

1069 :class:`_expression.FromClause`. 

1070 

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

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

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

1074 such as PostgreSQL, Oracle Database and SQL Server. 

1075 

1076 E.g.: 

1077 

1078 .. sourcecode:: pycon+sql 

1079 

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

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

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

1083 >>> print(stmt) 

1084 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1085 FROM a 

1086 

1087 .. versionadded:: 1.4.0b2 

1088 

1089 .. seealso:: 

1090 

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

1092 

1093 """ 

1094 return TableValuedColumn(self, type_api.TABLEVALUE) 

1095 

1096 

1097class SelectLabelStyle(Enum): 

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

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

1100 

1101 LABEL_STYLE_NONE = 0 

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

1103 columns clause of a SELECT statement. 

1104 

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

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

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

1108 

1109 .. sourcecode:: pycon+sql 

1110 

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

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

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

1114 >>> print( 

1115 ... select(table1, table2) 

1116 ... .join(table2, true()) 

1117 ... .set_label_style(LABEL_STYLE_NONE) 

1118 ... ) 

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

1120 FROM table1 JOIN table2 ON true 

1121 

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

1123 

1124 .. versionadded:: 1.4 

1125 

1126 """ # noqa: E501 

1127 

1128 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1132 tables, aliases, or subqueries. 

1133 

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

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

1136 ``table2_columna``: 

1137 

1138 .. sourcecode:: pycon+sql 

1139 

1140 >>> from sqlalchemy import ( 

1141 ... table, 

1142 ... column, 

1143 ... select, 

1144 ... true, 

1145 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1146 ... ) 

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

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

1149 >>> print( 

1150 ... select(table1, table2) 

1151 ... .join(table2, true()) 

1152 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1153 ... ) 

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

1155 FROM table1 JOIN table2 ON true 

1156 

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

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

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

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

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

1162 

1163 

1164 .. versionadded:: 1.4 

1165 

1166 """ # noqa: E501 

1167 

1168 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1171 when generating the columns clause of a SELECT statement. 

1172 

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

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

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

1176 

1177 .. sourcecode:: pycon+sql 

1178 

1179 >>> from sqlalchemy import ( 

1180 ... table, 

1181 ... column, 

1182 ... select, 

1183 ... true, 

1184 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1185 ... ) 

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

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

1188 >>> print( 

1189 ... select(table1, table2) 

1190 ... .join(table2, true()) 

1191 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1192 ... ) 

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

1194 FROM table1 JOIN table2 ON true 

1195 

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

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

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

1199 

1200 .. versionadded:: 1.4 

1201 

1202 """ # noqa: E501 

1203 

1204 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1205 """The default label style, refers to 

1206 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1207 

1208 .. versionadded:: 1.4 

1209 

1210 """ 

1211 

1212 LABEL_STYLE_LEGACY_ORM = 3 

1213 

1214 

1215( 

1216 LABEL_STYLE_NONE, 

1217 LABEL_STYLE_TABLENAME_PLUS_COL, 

1218 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1219 _, 

1220) = list(SelectLabelStyle) 

1221 

1222LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1223 

1224 

1225class Join(roles.DMLTableRole, FromClause): 

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

1227 :class:`_expression.FromClause` 

1228 elements. 

1229 

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

1231 is the module-level 

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

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

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

1235 :class:`_schema.Table`). 

1236 

1237 .. seealso:: 

1238 

1239 :func:`_expression.join` 

1240 

1241 :meth:`_expression.FromClause.join` 

1242 

1243 """ 

1244 

1245 __visit_name__ = "join" 

1246 

1247 _traverse_internals: _TraverseInternalsType = [ 

1248 ("left", InternalTraversal.dp_clauseelement), 

1249 ("right", InternalTraversal.dp_clauseelement), 

1250 ("onclause", InternalTraversal.dp_clauseelement), 

1251 ("isouter", InternalTraversal.dp_boolean), 

1252 ("full", InternalTraversal.dp_boolean), 

1253 ] 

1254 

1255 _is_join = True 

1256 

1257 left: FromClause 

1258 right: FromClause 

1259 onclause: Optional[ColumnElement[bool]] 

1260 isouter: bool 

1261 full: bool 

1262 

1263 def __init__( 

1264 self, 

1265 left: _FromClauseArgument, 

1266 right: _FromClauseArgument, 

1267 onclause: Optional[_OnClauseArgument] = None, 

1268 isouter: bool = False, 

1269 full: bool = False, 

1270 ): 

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

1272 

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

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

1275 :class:`_expression.FromClause` object. 

1276 

1277 """ 

1278 

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

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

1281 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1284 # callcounts for a single compilation in that particular test 

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

1286 # 29200 -> 30373 

1287 

1288 self.left = coercions.expect( 

1289 roles.FromClauseRole, 

1290 left, 

1291 ) 

1292 self.right = coercions.expect( 

1293 roles.FromClauseRole, 

1294 right, 

1295 ).self_group() 

1296 

1297 if onclause is None: 

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

1299 else: 

1300 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1301 # not merged yet 

1302 self.onclause = coercions.expect( 

1303 roles.OnClauseRole, onclause 

1304 ).self_group(against=operators._asbool) 

1305 

1306 self.isouter = isouter 

1307 self.full = full 

1308 

1309 @util.ro_non_memoized_property 

1310 def description(self) -> str: 

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

1312 self.left.description, 

1313 id(self.left), 

1314 self.right.description, 

1315 id(self.right), 

1316 ) 

1317 

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

1319 return ( 

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

1321 # as well 

1322 hash(fromclause) == hash(self) 

1323 or self.left.is_derived_from(fromclause) 

1324 or self.right.is_derived_from(fromclause) 

1325 ) 

1326 

1327 def self_group( 

1328 self, against: Optional[OperatorType] = None 

1329 ) -> FromGrouping: 

1330 return FromGrouping(self) 

1331 

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

1333 def _populate_column_collection( 

1334 self, 

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

1336 primary_key: ColumnSet, 

1337 foreign_keys: Set[KeyedColumnElement[Any]], 

1338 ) -> None: 

1339 sqlutil = util.preloaded.sql_util 

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

1341 c for c in self.right.c 

1342 ] 

1343 

1344 primary_key.extend( # type: ignore 

1345 sqlutil.reduce_columns( 

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

1347 ) 

1348 ) 

1349 columns._populate_separate_keys( 

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

1351 ) 

1352 foreign_keys.update( 

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

1354 ) 

1355 

1356 def _copy_internals( 

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

1358 ) -> None: 

1359 # see Select._copy_internals() for similar concept 

1360 

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

1362 # determine the new FROM clauses 

1363 all_the_froms = set( 

1364 itertools.chain( 

1365 _from_objects(self.left), 

1366 _from_objects(self.right), 

1367 ) 

1368 ) 

1369 

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

1371 # cache used by the clone function 

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

1373 

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

1375 # ColumnClause with parent table referring to those 

1376 # replaced FromClause objects 

1377 def replace( 

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

1379 **kw: Any, 

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

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

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

1383 return newelem 

1384 return None 

1385 

1386 kw["replace"] = replace 

1387 

1388 # run normal _copy_internals. the clones for 

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

1390 # cache 

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

1392 

1393 self._reset_memoizations() 

1394 

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

1396 super()._refresh_for_new_column(column) 

1397 self.left._refresh_for_new_column(column) 

1398 self.right._refresh_for_new_column(column) 

1399 

1400 def _match_primaries( 

1401 self, 

1402 left: FromClause, 

1403 right: FromClause, 

1404 ) -> ColumnElement[bool]: 

1405 if isinstance(left, Join): 

1406 left_right = left.right 

1407 else: 

1408 left_right = None 

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

1410 

1411 @classmethod 

1412 def _join_condition( 

1413 cls, 

1414 a: FromClause, 

1415 b: FromClause, 

1416 *, 

1417 a_subset: Optional[FromClause] = None, 

1418 consider_as_foreign_keys: Optional[ 

1419 AbstractSet[ColumnClause[Any]] 

1420 ] = None, 

1421 ) -> ColumnElement[bool]: 

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

1423 

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

1425 

1426 """ 

1427 constraints = cls._joincond_scan_left_right( 

1428 a, a_subset, b, consider_as_foreign_keys 

1429 ) 

1430 

1431 if len(constraints) > 1: 

1432 cls._joincond_trim_constraints( 

1433 a, b, constraints, consider_as_foreign_keys 

1434 ) 

1435 

1436 if len(constraints) == 0: 

1437 if isinstance(b, FromGrouping): 

1438 hint = ( 

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

1440 "subquery using alias()?" 

1441 ) 

1442 else: 

1443 hint = "" 

1444 raise exc.NoForeignKeysError( 

1445 "Can't find any foreign key relationships " 

1446 "between '%s' and '%s'.%s" 

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

1448 ) 

1449 

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

1451 if len(crit) == 1: 

1452 return crit[0] 

1453 else: 

1454 return and_(*crit) 

1455 

1456 @classmethod 

1457 def _can_join( 

1458 cls, 

1459 left: FromClause, 

1460 right: FromClause, 

1461 *, 

1462 consider_as_foreign_keys: Optional[ 

1463 AbstractSet[ColumnClause[Any]] 

1464 ] = None, 

1465 ) -> bool: 

1466 if isinstance(left, Join): 

1467 left_right = left.right 

1468 else: 

1469 left_right = None 

1470 

1471 constraints = cls._joincond_scan_left_right( 

1472 a=left, 

1473 b=right, 

1474 a_subset=left_right, 

1475 consider_as_foreign_keys=consider_as_foreign_keys, 

1476 ) 

1477 

1478 return bool(constraints) 

1479 

1480 @classmethod 

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

1482 def _joincond_scan_left_right( 

1483 cls, 

1484 a: FromClause, 

1485 a_subset: Optional[FromClause], 

1486 b: FromClause, 

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

1488 ) -> collections.defaultdict[ 

1489 Optional[ForeignKeyConstraint], 

1490 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1491 ]: 

1492 sql_util = util.preloaded.sql_util 

1493 

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

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

1496 

1497 constraints: collections.defaultdict[ 

1498 Optional[ForeignKeyConstraint], 

1499 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1500 ] = collections.defaultdict(list) 

1501 

1502 for left in (a_subset, a): 

1503 if left is None: 

1504 continue 

1505 for fk in sorted( 

1506 b.foreign_keys, 

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

1508 ): 

1509 if ( 

1510 consider_as_foreign_keys is not None 

1511 and fk.parent not in consider_as_foreign_keys 

1512 ): 

1513 continue 

1514 try: 

1515 col = fk.get_referent(left) 

1516 except exc.NoReferenceError as nrte: 

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

1518 if nrte.table_name in table_names: 

1519 raise 

1520 else: 

1521 continue 

1522 

1523 if col is not None: 

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

1525 if left is not b: 

1526 for fk in sorted( 

1527 left.foreign_keys, 

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

1529 ): 

1530 if ( 

1531 consider_as_foreign_keys is not None 

1532 and fk.parent not in consider_as_foreign_keys 

1533 ): 

1534 continue 

1535 try: 

1536 col = fk.get_referent(b) 

1537 except exc.NoReferenceError as nrte: 

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

1539 if nrte.table_name in table_names: 

1540 raise 

1541 else: 

1542 continue 

1543 

1544 if col is not None: 

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

1546 if constraints: 

1547 break 

1548 return constraints 

1549 

1550 @classmethod 

1551 def _joincond_trim_constraints( 

1552 cls, 

1553 a: FromClause, 

1554 b: FromClause, 

1555 constraints: Dict[Any, Any], 

1556 consider_as_foreign_keys: Optional[Any], 

1557 ) -> None: 

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

1559 # to include just those FKCs that match exactly to 

1560 # "consider_as_foreign_keys". 

1561 if consider_as_foreign_keys: 

1562 for const in list(constraints): 

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

1564 consider_as_foreign_keys 

1565 ): 

1566 del constraints[const] 

1567 

1568 # if still multiple constraints, but 

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

1570 if len(constraints) > 1: 

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

1572 if len(dedupe) == 1: 

1573 key = list(constraints)[0] 

1574 constraints = {key: constraints[key]} 

1575 

1576 if len(constraints) != 1: 

1577 raise exc.AmbiguousForeignKeysError( 

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

1579 "tables have more than one foreign key " 

1580 "constraint relationship between them. " 

1581 "Please specify the 'onclause' of this " 

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

1583 ) 

1584 

1585 def select(self) -> Select[Any]: 

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

1587 :class:`_expression.Join`. 

1588 

1589 E.g.:: 

1590 

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

1592 

1593 stmt = stmt.select() 

1594 

1595 The above will produce a SQL string resembling: 

1596 

1597 .. sourcecode:: sql 

1598 

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

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

1601 

1602 """ 

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

1604 

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

1606 def _anonymous_fromclause( 

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

1608 ) -> TODO_Any: 

1609 sqlutil = util.preloaded.sql_util 

1610 if flat: 

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

1612 left_name = name # will recurse 

1613 else: 

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

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

1616 else: 

1617 left_name = name 

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

1619 right_name = name # will recurse 

1620 else: 

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

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

1623 else: 

1624 right_name = name 

1625 left_a, right_a = ( 

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

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

1628 ) 

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

1630 sqlutil.ClauseAdapter(right_a) 

1631 ) 

1632 

1633 return left_a.join( 

1634 right_a, 

1635 adapter.traverse(self.onclause), 

1636 isouter=self.isouter, 

1637 full=self.full, 

1638 ) 

1639 else: 

1640 return ( 

1641 self.select() 

1642 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1643 .correlate(None) 

1644 .alias(name) 

1645 ) 

1646 

1647 @util.ro_non_memoized_property 

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

1649 return itertools.chain( 

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

1651 ) 

1652 

1653 @util.ro_non_memoized_property 

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

1655 self_list: List[FromClause] = [self] 

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

1657 

1658 

1659class NoInit: 

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

1661 raise NotImplementedError( 

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

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

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

1665 "selectable objects." 

1666 % ( 

1667 self.__class__.__name__, 

1668 self.__class__.__name__.lower(), 

1669 self.__class__.__name__.lower(), 

1670 ) 

1671 ) 

1672 

1673 

1674class LateralFromClause(NamedFromClause): 

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

1676 

1677 

1678# FromClause -> 

1679# AliasedReturnsRows 

1680# -> Alias only for FromClause 

1681# -> Subquery only for SelectBase 

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

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

1684# w/ non-deprecated coercion 

1685# -> TableSample -> only for FromClause 

1686 

1687 

1688class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1690 selectables.""" 

1691 

1692 _is_from_container = True 

1693 

1694 _supports_derived_columns = False 

1695 

1696 element: ReturnsRows 

1697 

1698 _traverse_internals: _TraverseInternalsType = [ 

1699 ("element", InternalTraversal.dp_clauseelement), 

1700 ("name", InternalTraversal.dp_anon_name), 

1701 ] 

1702 

1703 @classmethod 

1704 def _construct( 

1705 cls, 

1706 selectable: Any, 

1707 *, 

1708 name: Optional[str] = None, 

1709 **kw: Any, 

1710 ) -> Self: 

1711 obj = cls.__new__(cls) 

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

1713 return obj 

1714 

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

1716 self.element = coercions.expect( 

1717 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1718 ) 

1719 self.element = selectable 

1720 self._orig_name = name 

1721 if name is None: 

1722 if ( 

1723 isinstance(selectable, FromClause) 

1724 and selectable.named_with_column 

1725 ): 

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

1727 if isinstance(name, _anonymous_label): 

1728 name = None 

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

1730 self.name = name 

1731 

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

1733 super()._refresh_for_new_column(column) 

1734 self.element._refresh_for_new_column(column) 

1735 

1736 def _populate_column_collection( 

1737 self, 

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

1739 primary_key: ColumnSet, 

1740 foreign_keys: Set[KeyedColumnElement[Any]], 

1741 ) -> None: 

1742 self.element._generate_fromclause_column_proxies( 

1743 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1744 ) 

1745 

1746 @util.ro_non_memoized_property 

1747 def description(self) -> str: 

1748 name = self.name 

1749 if isinstance(name, _anonymous_label): 

1750 name = "anon_1" 

1751 

1752 return name 

1753 

1754 @util.ro_non_memoized_property 

1755 def implicit_returning(self) -> bool: 

1756 return self.element.implicit_returning # type: ignore 

1757 

1758 @property 

1759 def original(self) -> ReturnsRows: 

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

1761 return self.element 

1762 

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

1764 if fromclause in self._cloned_set: 

1765 return True 

1766 return self.element.is_derived_from(fromclause) 

1767 

1768 def _copy_internals( 

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

1770 ) -> None: 

1771 existing_element = self.element 

1772 

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

1774 

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

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

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

1778 # performance. 

1779 if existing_element is not self.element: 

1780 self._reset_column_collection() 

1781 

1782 @property 

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

1784 return [self] 

1785 

1786 

1787class FromClauseAlias(AliasedReturnsRows): 

1788 element: FromClause 

1789 

1790 

1791class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1793 

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

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

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

1797 

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

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

1800 method available 

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

1802 

1803 .. seealso:: 

1804 

1805 :meth:`_expression.FromClause.alias` 

1806 

1807 """ 

1808 

1809 __visit_name__ = "alias" 

1810 

1811 inherit_cache = True 

1812 

1813 element: FromClause 

1814 

1815 @classmethod 

1816 def _factory( 

1817 cls, 

1818 selectable: FromClause, 

1819 name: Optional[str] = None, 

1820 flat: bool = False, 

1821 ) -> NamedFromClause: 

1822 return coercions.expect( 

1823 roles.FromClauseRole, selectable, allow_select=True 

1824 ).alias(name=name, flat=flat) 

1825 

1826 

1827class TableValuedAlias(LateralFromClause, Alias): 

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

1829 

1830 This construct provides for a SQL function that returns columns 

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

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

1833 method, e.g.: 

1834 

1835 .. sourcecode:: pycon+sql 

1836 

1837 >>> from sqlalchemy import select, func 

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

1839 ... "value" 

1840 ... ) 

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

1842 {printsql}SELECT anon_1.value 

1843 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1844 

1845 .. versionadded:: 1.4.0b2 

1846 

1847 .. seealso:: 

1848 

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

1850 

1851 """ # noqa: E501 

1852 

1853 __visit_name__ = "table_valued_alias" 

1854 

1855 _supports_derived_columns = True 

1856 _render_derived = False 

1857 _render_derived_w_types = False 

1858 joins_implicitly = False 

1859 

1860 _traverse_internals: _TraverseInternalsType = [ 

1861 ("element", InternalTraversal.dp_clauseelement), 

1862 ("name", InternalTraversal.dp_anon_name), 

1863 ("_tableval_type", InternalTraversal.dp_type), 

1864 ("_render_derived", InternalTraversal.dp_boolean), 

1865 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1866 ] 

1867 

1868 def _init( 

1869 self, 

1870 selectable: Any, 

1871 *, 

1872 name: Optional[str] = None, 

1873 table_value_type: Optional[TableValueType] = None, 

1874 joins_implicitly: bool = False, 

1875 ) -> None: 

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

1877 

1878 self.joins_implicitly = joins_implicitly 

1879 self._tableval_type = ( 

1880 type_api.TABLEVALUE 

1881 if table_value_type is None 

1882 else table_value_type 

1883 ) 

1884 

1885 @HasMemoized.memoized_attribute 

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

1887 """Return a column expression representing this 

1888 :class:`_sql.TableValuedAlias`. 

1889 

1890 This accessor is used to implement the 

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

1892 method for further details. 

1893 

1894 E.g.: 

1895 

1896 .. sourcecode:: pycon+sql 

1897 

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

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

1900 

1901 .. seealso:: 

1902 

1903 :meth:`_functions.FunctionElement.column_valued` 

1904 

1905 """ 

1906 

1907 return TableValuedColumn(self, self._tableval_type) 

1908 

1909 def alias( 

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

1911 ) -> TableValuedAlias: 

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

1913 

1914 This creates a distinct FROM object that will be distinguished 

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

1916 

1917 """ 

1918 

1919 tva: TableValuedAlias = TableValuedAlias._construct( 

1920 self, 

1921 name=name, 

1922 table_value_type=self._tableval_type, 

1923 joins_implicitly=self.joins_implicitly, 

1924 ) 

1925 

1926 if self._render_derived: 

1927 tva._render_derived = True 

1928 tva._render_derived_w_types = self._render_derived_w_types 

1929 

1930 return tva 

1931 

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

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

1934 set, so that it renders as LATERAL. 

1935 

1936 .. seealso:: 

1937 

1938 :func:`_expression.lateral` 

1939 

1940 """ 

1941 tva = self.alias(name=name) 

1942 tva._is_lateral = True 

1943 return tva 

1944 

1945 def render_derived( 

1946 self, 

1947 name: Optional[str] = None, 

1948 with_types: bool = False, 

1949 ) -> TableValuedAlias: 

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

1951 

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

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

1954 

1955 .. sourcecode:: pycon+sql 

1956 

1957 >>> print( 

1958 ... select( 

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

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

1961 ... .render_derived() 

1962 ... ) 

1963 ... ) 

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

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

1966 

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

1968 the alias expression (this syntax currently applies to the 

1969 PostgreSQL database): 

1970 

1971 .. sourcecode:: pycon+sql 

1972 

1973 >>> print( 

1974 ... select( 

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

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

1977 ... .render_derived(with_types=True) 

1978 ... ) 

1979 ... ) 

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

1981 AS anon_1(a INTEGER, b VARCHAR) 

1982 

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

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

1985 

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

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

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

1989 

1990 """ # noqa: E501 

1991 

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

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

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

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

1996 # (just saw it happen on CI) 

1997 

1998 # construct against original to prevent memory growth 

1999 # for repeated generations 

2000 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2001 self.element, 

2002 name=name, 

2003 table_value_type=self._tableval_type, 

2004 joins_implicitly=self.joins_implicitly, 

2005 ) 

2006 new_alias._render_derived = True 

2007 new_alias._render_derived_w_types = with_types 

2008 return new_alias 

2009 

2010 

2011class Lateral(FromClauseAlias, LateralFromClause): 

2012 """Represent a LATERAL subquery. 

2013 

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

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

2016 method available 

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

2018 

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

2020 PostgreSQL versions provide support for this keyword. 

2021 

2022 .. seealso:: 

2023 

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

2025 

2026 """ 

2027 

2028 __visit_name__ = "lateral" 

2029 _is_lateral = True 

2030 

2031 inherit_cache = True 

2032 

2033 @classmethod 

2034 def _factory( 

2035 cls, 

2036 selectable: Union[SelectBase, _FromClauseArgument], 

2037 name: Optional[str] = None, 

2038 ) -> LateralFromClause: 

2039 return coercions.expect( 

2040 roles.FromClauseRole, selectable, explicit_subquery=True 

2041 ).lateral(name=name) 

2042 

2043 

2044class TableSample(FromClauseAlias): 

2045 """Represent a TABLESAMPLE clause. 

2046 

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

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

2049 method 

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

2051 

2052 .. seealso:: 

2053 

2054 :func:`_expression.tablesample` 

2055 

2056 """ 

2057 

2058 __visit_name__ = "tablesample" 

2059 

2060 _traverse_internals: _TraverseInternalsType = ( 

2061 AliasedReturnsRows._traverse_internals 

2062 + [ 

2063 ("sampling", InternalTraversal.dp_clauseelement), 

2064 ("seed", InternalTraversal.dp_clauseelement), 

2065 ] 

2066 ) 

2067 

2068 @classmethod 

2069 def _factory( 

2070 cls, 

2071 selectable: _FromClauseArgument, 

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

2073 name: Optional[str] = None, 

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

2075 ) -> TableSample: 

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

2077 sampling, name=name, seed=seed 

2078 ) 

2079 

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

2081 def _init( # type: ignore[override] 

2082 self, 

2083 selectable: Any, 

2084 *, 

2085 name: Optional[str] = None, 

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

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

2088 ) -> None: 

2089 assert sampling is not None 

2090 functions = util.preloaded.sql_functions 

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

2092 sampling = functions.func.system(sampling) 

2093 

2094 self.sampling: Function[Any] = sampling 

2095 self.seed = seed 

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

2097 

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

2099 return self.sampling 

2100 

2101 

2102class CTE( 

2103 roles.DMLTableRole, 

2104 roles.IsCTERole, 

2105 Generative, 

2106 HasPrefixes, 

2107 HasSuffixes, 

2108 AliasedReturnsRows, 

2109): 

2110 """Represent a Common Table Expression. 

2111 

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

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

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

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

2116 :class:`_sql.Update` and 

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

2118 usage details on CTEs. 

2119 

2120 .. seealso:: 

2121 

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

2123 

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

2125 

2126 """ 

2127 

2128 __visit_name__ = "cte" 

2129 

2130 _traverse_internals: _TraverseInternalsType = ( 

2131 AliasedReturnsRows._traverse_internals 

2132 + [ 

2133 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2134 ("_restates", InternalTraversal.dp_clauseelement), 

2135 ("recursive", InternalTraversal.dp_boolean), 

2136 ("nesting", InternalTraversal.dp_boolean), 

2137 ] 

2138 + HasPrefixes._has_prefixes_traverse_internals 

2139 + HasSuffixes._has_suffixes_traverse_internals 

2140 ) 

2141 

2142 element: HasCTE 

2143 

2144 @classmethod 

2145 def _factory( 

2146 cls, 

2147 selectable: HasCTE, 

2148 name: Optional[str] = None, 

2149 recursive: bool = False, 

2150 ) -> CTE: 

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

2152 or Common Table Expression instance. 

2153 

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

2155 

2156 """ 

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

2158 name=name, recursive=recursive 

2159 ) 

2160 

2161 def _init( 

2162 self, 

2163 selectable: Select[Any], 

2164 *, 

2165 name: Optional[str] = None, 

2166 recursive: bool = False, 

2167 nesting: bool = False, 

2168 _cte_alias: Optional[CTE] = None, 

2169 _restates: Optional[CTE] = None, 

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

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

2172 ) -> None: 

2173 self.recursive = recursive 

2174 self.nesting = nesting 

2175 self._cte_alias = _cte_alias 

2176 # Keep recursivity reference with union/union_all 

2177 self._restates = _restates 

2178 if _prefixes: 

2179 self._prefixes = _prefixes 

2180 if _suffixes: 

2181 self._suffixes = _suffixes 

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

2183 

2184 def _populate_column_collection( 

2185 self, 

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

2187 primary_key: ColumnSet, 

2188 foreign_keys: Set[KeyedColumnElement[Any]], 

2189 ) -> None: 

2190 if self._cte_alias is not None: 

2191 self._cte_alias._generate_fromclause_column_proxies( 

2192 self, 

2193 columns, 

2194 primary_key=primary_key, 

2195 foreign_keys=foreign_keys, 

2196 ) 

2197 else: 

2198 self.element._generate_fromclause_column_proxies( 

2199 self, 

2200 columns, 

2201 primary_key=primary_key, 

2202 foreign_keys=foreign_keys, 

2203 ) 

2204 

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

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

2207 :class:`_expression.CTE`. 

2208 

2209 This method is a CTE-specific specialization of the 

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

2211 

2212 .. seealso:: 

2213 

2214 :ref:`tutorial_using_aliases` 

2215 

2216 :func:`_expression.alias` 

2217 

2218 """ 

2219 return CTE._construct( 

2220 self.element, 

2221 name=name, 

2222 recursive=self.recursive, 

2223 nesting=self.nesting, 

2224 _cte_alias=self, 

2225 _prefixes=self._prefixes, 

2226 _suffixes=self._suffixes, 

2227 ) 

2228 

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

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

2231 of the original CTE against the given selectables provided 

2232 as positional arguments. 

2233 

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

2235 UNION. 

2236 

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

2238 

2239 .. seealso:: 

2240 

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

2242 

2243 """ 

2244 assert is_select_statement( 

2245 self.element 

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

2247 

2248 return CTE._construct( 

2249 self.element.union(*other), 

2250 name=self.name, 

2251 recursive=self.recursive, 

2252 nesting=self.nesting, 

2253 _restates=self, 

2254 _prefixes=self._prefixes, 

2255 _suffixes=self._suffixes, 

2256 ) 

2257 

2258 def union_all( 

2259 self, *other: _SelectStatementForCompoundArgument[Any] 

2260 ) -> CTE: 

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

2262 of the original CTE against the given selectables provided 

2263 as positional arguments. 

2264 

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

2266 UNION. 

2267 

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

2269 

2270 .. seealso:: 

2271 

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

2273 

2274 """ 

2275 

2276 assert is_select_statement( 

2277 self.element 

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

2279 

2280 return CTE._construct( 

2281 self.element.union_all(*other), 

2282 name=self.name, 

2283 recursive=self.recursive, 

2284 nesting=self.nesting, 

2285 _restates=self, 

2286 _prefixes=self._prefixes, 

2287 _suffixes=self._suffixes, 

2288 ) 

2289 

2290 def _get_reference_cte(self) -> CTE: 

2291 """ 

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

2293 Updated CTEs should still refer to the original CTE. 

2294 This function returns this reference identifier. 

2295 """ 

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

2297 

2298 

2299class _CTEOpts(NamedTuple): 

2300 nesting: bool 

2301 

2302 

2303class _ColumnsPlusNames(NamedTuple): 

2304 required_label_name: Optional[str] 

2305 """ 

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

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

2308 """ 

2309 

2310 proxy_key: Optional[str] 

2311 """ 

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

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

2314 select.selected_columns collection 

2315 """ 

2316 

2317 fallback_label_name: Optional[str] 

2318 """ 

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

2320 we have to render a label even though 

2321 required_label_name was not given 

2322 """ 

2323 

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

2325 """ 

2326 the ColumnElement itself 

2327 """ 

2328 

2329 repeated: bool 

2330 """ 

2331 True if this is a duplicate of a previous column 

2332 in the list of columns 

2333 """ 

2334 

2335 

2336class SelectsRows(ReturnsRows): 

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

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

2339 

2340 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2341 

2342 def _generate_columns_plus_names( 

2343 self, 

2344 anon_for_dupe_key: bool, 

2345 cols: Optional[_SelectIterable] = None, 

2346 ) -> List[_ColumnsPlusNames]: 

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

2348 the compiler. 

2349 

2350 This is distinct from the _column_naming_convention generator that's 

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

2352 different rules. the collection returned here calls upon the 

2353 _column_naming_convention as well. 

2354 

2355 """ 

2356 

2357 if cols is None: 

2358 cols = self._all_selected_columns 

2359 

2360 key_naming_convention = SelectState._column_naming_convention( 

2361 self._label_style 

2362 ) 

2363 

2364 names = {} 

2365 

2366 result: List[_ColumnsPlusNames] = [] 

2367 result_append = result.append 

2368 

2369 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2370 label_style_none = self._label_style is LABEL_STYLE_NONE 

2371 

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

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

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

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

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

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

2378 dedupe_hash = 1 

2379 

2380 for c in cols: 

2381 repeated = False 

2382 

2383 if not c._render_label_in_columns_clause: 

2384 effective_name = required_label_name = fallback_label_name = ( 

2385 None 

2386 ) 

2387 elif label_style_none: 

2388 if TYPE_CHECKING: 

2389 assert is_column_element(c) 

2390 

2391 effective_name = required_label_name = None 

2392 fallback_label_name = c._non_anon_label or c._anon_name_label 

2393 else: 

2394 if TYPE_CHECKING: 

2395 assert is_column_element(c) 

2396 

2397 if table_qualified: 

2398 required_label_name = effective_name = ( 

2399 fallback_label_name 

2400 ) = c._tq_label 

2401 else: 

2402 effective_name = fallback_label_name = c._non_anon_label 

2403 required_label_name = None 

2404 

2405 if effective_name is None: 

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

2407 # not need _expression_label but it isn't 

2408 # giving us a clue when to use anon_label instead 

2409 expr_label = c._expression_label 

2410 if expr_label is None: 

2411 repeated = c._anon_name_label in names 

2412 names[c._anon_name_label] = c 

2413 effective_name = required_label_name = None 

2414 

2415 if repeated: 

2416 # here, "required_label_name" is sent as 

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

2418 if table_qualified: 

2419 fallback_label_name = ( 

2420 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2421 ) 

2422 dedupe_hash += 1 

2423 else: 

2424 fallback_label_name = c._dedupe_anon_label_idx( 

2425 dedupe_hash 

2426 ) 

2427 dedupe_hash += 1 

2428 else: 

2429 fallback_label_name = c._anon_name_label 

2430 else: 

2431 required_label_name = effective_name = ( 

2432 fallback_label_name 

2433 ) = expr_label 

2434 

2435 if effective_name is not None: 

2436 if TYPE_CHECKING: 

2437 assert is_column_element(c) 

2438 

2439 if effective_name in names: 

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

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

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

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

2444 # different column under the same name. apply 

2445 # disambiguating label 

2446 if table_qualified: 

2447 required_label_name = fallback_label_name = ( 

2448 c._anon_tq_label 

2449 ) 

2450 else: 

2451 required_label_name = fallback_label_name = ( 

2452 c._anon_name_label 

2453 ) 

2454 

2455 if anon_for_dupe_key and required_label_name in names: 

2456 # here, c._anon_tq_label is definitely unique to 

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

2458 # this should always be true. 

2459 # this is also an infrequent codepath because 

2460 # you need two levels of duplication to be here 

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

2462 

2463 # the column under the disambiguating label is 

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

2465 # subsequent occurrences of the column so that the 

2466 # original stays non-ambiguous 

2467 if table_qualified: 

2468 required_label_name = fallback_label_name = ( 

2469 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2470 ) 

2471 dedupe_hash += 1 

2472 else: 

2473 required_label_name = fallback_label_name = ( 

2474 c._dedupe_anon_label_idx(dedupe_hash) 

2475 ) 

2476 dedupe_hash += 1 

2477 repeated = True 

2478 else: 

2479 names[required_label_name] = c 

2480 elif anon_for_dupe_key: 

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

2482 # label so that the original stays non-ambiguous 

2483 if table_qualified: 

2484 required_label_name = fallback_label_name = ( 

2485 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2486 ) 

2487 dedupe_hash += 1 

2488 else: 

2489 required_label_name = fallback_label_name = ( 

2490 c._dedupe_anon_label_idx(dedupe_hash) 

2491 ) 

2492 dedupe_hash += 1 

2493 repeated = True 

2494 else: 

2495 names[effective_name] = c 

2496 

2497 result_append( 

2498 _ColumnsPlusNames( 

2499 required_label_name, 

2500 key_naming_convention(c), 

2501 fallback_label_name, 

2502 c, 

2503 repeated, 

2504 ) 

2505 ) 

2506 

2507 return result 

2508 

2509 

2510class HasCTE(roles.HasCTERole, SelectsRows): 

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

2512 

2513 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2514 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2515 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2516 ] 

2517 

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

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

2520 

2521 @_generative 

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

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

2524 

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

2526 the parent statement such that they will each be unconditionally 

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

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

2529 

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

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

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

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

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

2535 statement. 

2536 

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

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

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

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

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

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

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

2544 larger statement. 

2545 

2546 E.g.:: 

2547 

2548 from sqlalchemy import table, column, select 

2549 

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

2551 

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

2553 

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

2555 

2556 Would render: 

2557 

2558 .. sourcecode:: sql 

2559 

2560 WITH anon_1 AS ( 

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

2562 ) 

2563 SELECT t.c1, t.c2 

2564 FROM t 

2565 

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

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

2568 statement. 

2569 

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

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

2572 

2573 from sqlalchemy import table, column 

2574 from sqlalchemy.dialects.postgresql import insert 

2575 

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

2577 

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

2579 

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

2581 update_statement = insert_stmt.on_conflict_do_update( 

2582 index_elements=[t.c.c1], 

2583 set_={ 

2584 "c1": insert_stmt.excluded.c1, 

2585 "c2": insert_stmt.excluded.c2, 

2586 }, 

2587 ).add_cte(delete_statement_cte) 

2588 

2589 print(update_statement) 

2590 

2591 The above statement renders as: 

2592 

2593 .. sourcecode:: sql 

2594 

2595 WITH deletions AS ( 

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

2597 ) 

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

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

2600 

2601 .. versionadded:: 1.4.21 

2602 

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

2604 

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

2606 

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

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

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

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

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

2612 this statement when this flag is given. 

2613 

2614 .. versionadded:: 2.0 

2615 

2616 .. seealso:: 

2617 

2618 :paramref:`.HasCTE.cte.nesting` 

2619 

2620 

2621 """ # noqa: E501 

2622 opt = _CTEOpts(nest_here) 

2623 for cte in ctes: 

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

2625 self._independent_ctes += (cte,) 

2626 self._independent_ctes_opts += (opt,) 

2627 return self 

2628 

2629 def cte( 

2630 self, 

2631 name: Optional[str] = None, 

2632 recursive: bool = False, 

2633 nesting: bool = False, 

2634 ) -> CTE: 

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

2636 or Common Table Expression instance. 

2637 

2638 Common table expressions are a SQL standard whereby SELECT 

2639 statements can draw upon secondary statements specified along 

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

2641 Special semantics regarding UNION can also be employed to 

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

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

2644 

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

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

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

2648 CTE rows. 

2649 

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

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

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

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

2654 

2655 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2657 method may be 

2658 used to establish these. 

2659 

2660 .. versionchanged:: 1.3.13 Added support for prefixes. 

2661 In particular - MATERIALIZED and NOT MATERIALIZED. 

2662 

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

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

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

2666 compile time. 

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

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

2669 conjunction with UNION ALL in order to derive rows 

2670 from those already selected. 

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

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

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

2674 :paramref:`.HasCTE.add_cte.nest_here` 

2675 parameter may also be used to more carefully 

2676 control the exact placement of a particular CTE. 

2677 

2678 .. versionadded:: 1.4.24 

2679 

2680 .. seealso:: 

2681 

2682 :meth:`.HasCTE.add_cte` 

2683 

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

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

2686 as well as additional examples. 

2687 

2688 Example 1, non recursive:: 

2689 

2690 from sqlalchemy import ( 

2691 Table, 

2692 Column, 

2693 String, 

2694 Integer, 

2695 MetaData, 

2696 select, 

2697 func, 

2698 ) 

2699 

2700 metadata = MetaData() 

2701 

2702 orders = Table( 

2703 "orders", 

2704 metadata, 

2705 Column("region", String), 

2706 Column("amount", Integer), 

2707 Column("product", String), 

2708 Column("quantity", Integer), 

2709 ) 

2710 

2711 regional_sales = ( 

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

2713 .group_by(orders.c.region) 

2714 .cte("regional_sales") 

2715 ) 

2716 

2717 

2718 top_regions = ( 

2719 select(regional_sales.c.region) 

2720 .where( 

2721 regional_sales.c.total_sales 

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

2723 ) 

2724 .cte("top_regions") 

2725 ) 

2726 

2727 statement = ( 

2728 select( 

2729 orders.c.region, 

2730 orders.c.product, 

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

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

2733 ) 

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

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

2736 ) 

2737 

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

2739 

2740 Example 2, WITH RECURSIVE:: 

2741 

2742 from sqlalchemy import ( 

2743 Table, 

2744 Column, 

2745 String, 

2746 Integer, 

2747 MetaData, 

2748 select, 

2749 func, 

2750 ) 

2751 

2752 metadata = MetaData() 

2753 

2754 parts = Table( 

2755 "parts", 

2756 metadata, 

2757 Column("part", String), 

2758 Column("sub_part", String), 

2759 Column("quantity", Integer), 

2760 ) 

2761 

2762 included_parts = ( 

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

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

2765 .cte(recursive=True) 

2766 ) 

2767 

2768 

2769 incl_alias = included_parts.alias() 

2770 parts_alias = parts.alias() 

2771 included_parts = included_parts.union_all( 

2772 select( 

2773 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2775 ) 

2776 

2777 statement = select( 

2778 included_parts.c.sub_part, 

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

2780 ).group_by(included_parts.c.sub_part) 

2781 

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

2783 

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

2785 

2786 from datetime import date 

2787 from sqlalchemy import ( 

2788 MetaData, 

2789 Table, 

2790 Column, 

2791 Integer, 

2792 Date, 

2793 select, 

2794 literal, 

2795 and_, 

2796 exists, 

2797 ) 

2798 

2799 metadata = MetaData() 

2800 

2801 visitors = Table( 

2802 "visitors", 

2803 metadata, 

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

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

2806 Column("count", Integer), 

2807 ) 

2808 

2809 # add 5 visitors for the product_id == 1 

2810 product_id = 1 

2811 day = date.today() 

2812 count = 5 

2813 

2814 update_cte = ( 

2815 visitors.update() 

2816 .where( 

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

2818 ) 

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

2820 .returning(literal(1)) 

2821 .cte("update_cte") 

2822 ) 

2823 

2824 upsert = visitors.insert().from_select( 

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

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

2827 ~exists(update_cte.select()) 

2828 ), 

2829 ) 

2830 

2831 connection.execute(upsert) 

2832 

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

2834 

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

2836 

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

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

2839 "value_a", nesting=True 

2840 ) 

2841 

2842 # Nesting CTEs takes ascendency locally 

2843 # over the CTEs at a higher level 

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

2845 

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

2847 

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

2849 shown with inline parameters below as: 

2850 

2851 .. sourcecode:: sql 

2852 

2853 WITH 

2854 value_a AS 

2855 (SELECT 'root' AS n), 

2856 value_b AS 

2857 (WITH value_a AS 

2858 (SELECT 'nesting' AS n) 

2859 SELECT value_a.n AS n FROM value_a) 

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

2861 FROM value_a, value_b 

2862 

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

2864 as follows (SQLAlchemy 2.0 and above):: 

2865 

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

2867 

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

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

2870 

2871 # Nesting CTEs takes ascendency locally 

2872 # over the CTEs at a higher level 

2873 value_b = ( 

2874 select(value_a_nested.c.n) 

2875 .add_cte(value_a_nested, nest_here=True) 

2876 .cte("value_b") 

2877 ) 

2878 

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

2880 

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

2882 

2883 edge = Table( 

2884 "edge", 

2885 metadata, 

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

2887 Column("left", Integer), 

2888 Column("right", Integer), 

2889 ) 

2890 

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

2892 

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

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

2895 ) 

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

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

2898 ) 

2899 

2900 subgraph_cte = root_node.union(left_edge, right_edge) 

2901 

2902 subgraph = select(subgraph_cte) 

2903 

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

2905 

2906 .. sourcecode:: sql 

2907 

2908 WITH RECURSIVE nodes(node) AS ( 

2909 SELECT 1 AS node 

2910 UNION 

2911 SELECT edge."left" AS "left" 

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

2913 UNION 

2914 SELECT edge."right" AS "right" 

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

2916 ) 

2917 SELECT nodes.node FROM nodes 

2918 

2919 .. seealso:: 

2920 

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

2922 :meth:`_expression.HasCTE.cte`. 

2923 

2924 """ # noqa: E501 

2925 return CTE._construct( 

2926 self, name=name, recursive=recursive, nesting=nesting 

2927 ) 

2928 

2929 

2930class Subquery(AliasedReturnsRows): 

2931 """Represent a subquery of a SELECT. 

2932 

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

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

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

2936 :class:`_expression.SelectBase` subclass 

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

2938 :class:`_expression.CompoundSelect`, and 

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

2940 it represents the 

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

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

2943 

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

2945 :class:`_expression.Alias` 

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

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

2948 :class:`_expression.Alias` always 

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

2950 :class:`.Subquery` 

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

2952 

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

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

2955 statement. 

2956 

2957 """ 

2958 

2959 __visit_name__ = "subquery" 

2960 

2961 _is_subquery = True 

2962 

2963 inherit_cache = True 

2964 

2965 element: SelectBase 

2966 

2967 @classmethod 

2968 def _factory( 

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

2970 ) -> Subquery: 

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

2972 

2973 return coercions.expect( 

2974 roles.SelectStatementRole, selectable 

2975 ).subquery(name=name) 

2976 

2977 @util.deprecated( 

2978 "1.4", 

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

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

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

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

2983 ":func:`_expression.select` " 

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

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

2986 ) 

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

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

2989 

2990 

2991class FromGrouping(GroupedElement, FromClause): 

2992 """Represent a grouping of a FROM clause""" 

2993 

2994 _traverse_internals: _TraverseInternalsType = [ 

2995 ("element", InternalTraversal.dp_clauseelement) 

2996 ] 

2997 

2998 element: FromClause 

2999 

3000 def __init__(self, element: FromClause): 

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

3002 

3003 @util.ro_non_memoized_property 

3004 def columns( 

3005 self, 

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

3007 return self.element.columns 

3008 

3009 @util.ro_non_memoized_property 

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

3011 return self.element.columns 

3012 

3013 @property 

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

3015 return self.element.primary_key 

3016 

3017 @property 

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

3019 return self.element.foreign_keys 

3020 

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

3022 return self.element.is_derived_from(fromclause) 

3023 

3024 def alias( 

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

3026 ) -> NamedFromGrouping: 

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

3028 

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

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

3031 

3032 @util.ro_non_memoized_property 

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

3034 return self.element._hide_froms 

3035 

3036 @util.ro_non_memoized_property 

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

3038 return self.element._from_objects 

3039 

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

3041 return {"element": self.element} 

3042 

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

3044 self.element = state["element"] 

3045 

3046 if TYPE_CHECKING: 

3047 

3048 def self_group( 

3049 self, against: Optional[OperatorType] = None 

3050 ) -> Self: ... 

3051 

3052 

3053class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3055 

3056 .. versionadded:: 2.0 

3057 

3058 """ 

3059 

3060 inherit_cache = True 

3061 

3062 if TYPE_CHECKING: 

3063 

3064 def self_group( 

3065 self, against: Optional[OperatorType] = None 

3066 ) -> Self: ... 

3067 

3068 

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

3070 """Represents a minimal "table" construct. 

3071 

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

3073 collection of columns, which are typically produced 

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

3075 

3076 from sqlalchemy import table, column 

3077 

3078 user = table( 

3079 "user", 

3080 column("id"), 

3081 column("name"), 

3082 column("description"), 

3083 ) 

3084 

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

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

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

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

3089 

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

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

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

3093 It's useful 

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

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

3096 is not on hand. 

3097 

3098 """ 

3099 

3100 __visit_name__ = "table" 

3101 

3102 _traverse_internals: _TraverseInternalsType = [ 

3103 ( 

3104 "columns", 

3105 InternalTraversal.dp_fromclause_canonical_column_collection, 

3106 ), 

3107 ("name", InternalTraversal.dp_string), 

3108 ("schema", InternalTraversal.dp_string), 

3109 ] 

3110 

3111 _is_table = True 

3112 

3113 fullname: str 

3114 

3115 implicit_returning = False 

3116 """:class:`_expression.TableClause` 

3117 doesn't support having a primary key or column 

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

3119 

3120 @util.ro_memoized_property 

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

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

3123 return None 

3124 

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

3126 super().__init__() 

3127 self.name = name 

3128 self._columns = DedupeColumnCollection() 

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

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

3131 for c in columns: 

3132 self.append_column(c) 

3133 

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

3135 if schema is not None: 

3136 self.schema = schema 

3137 if self.schema is not None: 

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

3139 else: 

3140 self.fullname = self.name 

3141 if kw: 

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

3143 

3144 if TYPE_CHECKING: 

3145 

3146 @util.ro_non_memoized_property 

3147 def columns( 

3148 self, 

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

3150 

3151 @util.ro_non_memoized_property 

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

3153 

3154 def __str__(self) -> str: 

3155 if self.schema is not None: 

3156 return self.schema + "." + self.name 

3157 else: 

3158 return self.name 

3159 

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

3161 pass 

3162 

3163 @util.ro_memoized_property 

3164 def description(self) -> str: 

3165 return self.name 

3166 

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

3168 existing = c.table 

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

3170 raise exc.ArgumentError( 

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

3172 % (c.key, existing) 

3173 ) 

3174 

3175 self._columns.add(c) 

3176 c.table = self 

3177 

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

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

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

3181 :class:`_expression.TableClause`. 

3182 

3183 E.g.:: 

3184 

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

3186 

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

3188 

3189 """ 

3190 

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

3192 

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

3194 def update(self) -> Update: 

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

3196 :class:`_expression.TableClause`. 

3197 

3198 E.g.:: 

3199 

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

3201 

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

3203 

3204 """ 

3205 return util.preloaded.sql_dml.Update( 

3206 self, 

3207 ) 

3208 

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

3210 def delete(self) -> Delete: 

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

3212 :class:`_expression.TableClause`. 

3213 

3214 E.g.:: 

3215 

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

3217 

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

3219 

3220 """ 

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

3222 

3223 @util.ro_non_memoized_property 

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

3225 return [self] 

3226 

3227 

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

3229 

3230 

3231class ForUpdateArg(ClauseElement): 

3232 _traverse_internals: _TraverseInternalsType = [ 

3233 ("of", InternalTraversal.dp_clauseelement_list), 

3234 ("nowait", InternalTraversal.dp_boolean), 

3235 ("read", InternalTraversal.dp_boolean), 

3236 ("skip_locked", InternalTraversal.dp_boolean), 

3237 ("key_share", InternalTraversal.dp_boolean), 

3238 ] 

3239 

3240 of: Optional[Sequence[ClauseElement]] 

3241 nowait: bool 

3242 read: bool 

3243 skip_locked: bool 

3244 

3245 @classmethod 

3246 def _from_argument( 

3247 cls, with_for_update: ForUpdateParameter 

3248 ) -> Optional[ForUpdateArg]: 

3249 if isinstance(with_for_update, ForUpdateArg): 

3250 return with_for_update 

3251 elif with_for_update in (None, False): 

3252 return None 

3253 elif with_for_update is True: 

3254 return ForUpdateArg() 

3255 else: 

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

3257 

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

3259 return ( 

3260 isinstance(other, ForUpdateArg) 

3261 and other.nowait == self.nowait 

3262 and other.read == self.read 

3263 and other.skip_locked == self.skip_locked 

3264 and other.key_share == self.key_share 

3265 and other.of is self.of 

3266 ) 

3267 

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

3269 return not self.__eq__(other) 

3270 

3271 def __hash__(self) -> int: 

3272 return id(self) 

3273 

3274 def __init__( 

3275 self, 

3276 *, 

3277 nowait: bool = False, 

3278 read: bool = False, 

3279 of: Optional[_ForUpdateOfArgument] = None, 

3280 skip_locked: bool = False, 

3281 key_share: bool = False, 

3282 ): 

3283 """Represents arguments specified to 

3284 :meth:`_expression.Select.for_update`. 

3285 

3286 """ 

3287 

3288 self.nowait = nowait 

3289 self.read = read 

3290 self.skip_locked = skip_locked 

3291 self.key_share = key_share 

3292 if of is not None: 

3293 self.of = [ 

3294 coercions.expect(roles.ColumnsClauseRole, elem) 

3295 for elem in util.to_list(of) 

3296 ] 

3297 else: 

3298 self.of = None 

3299 

3300 

3301class Values(roles.InElementRole, Generative, LateralFromClause): 

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

3303 in a statement. 

3304 

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

3306 :func:`_expression.values` function. 

3307 

3308 .. versionadded:: 1.4 

3309 

3310 """ 

3311 

3312 __visit_name__ = "values" 

3313 

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

3315 

3316 _unnamed: bool 

3317 _traverse_internals: _TraverseInternalsType = [ 

3318 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3319 ("_data", InternalTraversal.dp_dml_multi_values), 

3320 ("name", InternalTraversal.dp_string), 

3321 ("literal_binds", InternalTraversal.dp_boolean), 

3322 ] 

3323 

3324 def __init__( 

3325 self, 

3326 *columns: ColumnClause[Any], 

3327 name: Optional[str] = None, 

3328 literal_binds: bool = False, 

3329 ): 

3330 super().__init__() 

3331 self._column_args = columns 

3332 

3333 if name is None: 

3334 self._unnamed = True 

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

3336 else: 

3337 self._unnamed = False 

3338 self.name = name 

3339 self.literal_binds = literal_binds 

3340 self.named_with_column = not self._unnamed 

3341 

3342 @property 

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

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

3345 

3346 @_generative 

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

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

3349 construct that is a copy of this 

3350 one with the given name. 

3351 

3352 This method is a VALUES-specific specialization of the 

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

3354 

3355 .. seealso:: 

3356 

3357 :ref:`tutorial_using_aliases` 

3358 

3359 :func:`_expression.alias` 

3360 

3361 """ 

3362 non_none_name: str 

3363 

3364 if name is None: 

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

3366 else: 

3367 non_none_name = name 

3368 

3369 self.name = non_none_name 

3370 self.named_with_column = True 

3371 self._unnamed = False 

3372 return self 

3373 

3374 @_generative 

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

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

3377 so that 

3378 it renders as LATERAL. 

3379 

3380 .. seealso:: 

3381 

3382 :func:`_expression.lateral` 

3383 

3384 """ 

3385 non_none_name: str 

3386 

3387 if name is None: 

3388 non_none_name = self.name 

3389 else: 

3390 non_none_name = name 

3391 

3392 self._is_lateral = True 

3393 self.name = non_none_name 

3394 self._unnamed = False 

3395 return self 

3396 

3397 @_generative 

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

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

3400 adding the given data to the data list. 

3401 

3402 E.g.:: 

3403 

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

3405 

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

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

3408 constructor. 

3409 

3410 """ 

3411 

3412 self._data += (values,) 

3413 return self 

3414 

3415 def scalar_values(self) -> ScalarValues: 

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

3417 COLUMN element in a statement. 

3418 

3419 .. versionadded:: 2.0.0b4 

3420 

3421 """ 

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

3423 

3424 def _populate_column_collection( 

3425 self, 

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

3427 primary_key: ColumnSet, 

3428 foreign_keys: Set[KeyedColumnElement[Any]], 

3429 ) -> None: 

3430 for c in self._column_args: 

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

3432 _, c = c._make_proxy( 

3433 self, primary_key=primary_key, foreign_keys=foreign_keys 

3434 ) 

3435 else: 

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

3437 # no memoizations of other FROM clauses. 

3438 # see test_values.py -> test_auto_proxy_select_direct_col 

3439 c._reset_memoizations() 

3440 columns.add(c) 

3441 c.table = self 

3442 

3443 @util.ro_non_memoized_property 

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

3445 return [self] 

3446 

3447 

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

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

3450 COLUMN element in a statement. 

3451 

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

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

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

3455 an ``IN`` or ``NOT IN`` condition. 

3456 

3457 .. versionadded:: 2.0.0b4 

3458 

3459 """ 

3460 

3461 __visit_name__ = "scalar_values" 

3462 

3463 _traverse_internals: _TraverseInternalsType = [ 

3464 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3465 ("_data", InternalTraversal.dp_dml_multi_values), 

3466 ("literal_binds", InternalTraversal.dp_boolean), 

3467 ] 

3468 

3469 def __init__( 

3470 self, 

3471 columns: Sequence[ColumnClause[Any]], 

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

3473 literal_binds: bool, 

3474 ): 

3475 super().__init__() 

3476 self._column_args = columns 

3477 self._data = data 

3478 self.literal_binds = literal_binds 

3479 

3480 @property 

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

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

3483 

3484 def __clause_element__(self) -> ScalarValues: 

3485 return self 

3486 

3487 if TYPE_CHECKING: 

3488 

3489 def self_group( 

3490 self, against: Optional[OperatorType] = None 

3491 ) -> Self: ... 

3492 

3493 

3494class SelectBase( 

3495 roles.SelectStatementRole, 

3496 roles.DMLSelectRole, 

3497 roles.CompoundElementRole, 

3498 roles.InElementRole, 

3499 HasCTE, 

3500 SupportsCloneAnnotations, 

3501 Selectable, 

3502): 

3503 """Base class for SELECT statements. 

3504 

3505 

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

3507 :class:`_expression.CompoundSelect` and 

3508 :class:`_expression.TextualSelect`. 

3509 

3510 

3511 """ 

3512 

3513 _is_select_base = True 

3514 is_select = True 

3515 

3516 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3517 

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

3519 self._reset_memoizations() 

3520 

3521 @util.ro_non_memoized_property 

3522 def selected_columns( 

3523 self, 

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

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

3526 representing the columns that 

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

3528 

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

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

3531 within this collection cannot be directly nested inside another SELECT 

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

3533 necessary parenthesization required by SQL. 

3534 

3535 .. note:: 

3536 

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

3538 include expressions established in the columns clause using the 

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

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

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

3542 construct. 

3543 

3544 .. seealso:: 

3545 

3546 :attr:`_sql.Select.selected_columns` 

3547 

3548 .. versionadded:: 1.4 

3549 

3550 """ 

3551 raise NotImplementedError() 

3552 

3553 def _generate_fromclause_column_proxies( 

3554 self, 

3555 subquery: FromClause, 

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

3557 primary_key: ColumnSet, 

3558 foreign_keys: Set[KeyedColumnElement[Any]], 

3559 *, 

3560 proxy_compound_columns: Optional[ 

3561 Iterable[Sequence[ColumnElement[Any]]] 

3562 ] = None, 

3563 ) -> None: 

3564 raise NotImplementedError() 

3565 

3566 @util.ro_non_memoized_property 

3567 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3570 constructs. 

3571 

3572 .. versionadded:: 1.4.12 

3573 

3574 .. seealso:: 

3575 

3576 :attr:`_sql.SelectBase.exported_columns` 

3577 

3578 """ 

3579 raise NotImplementedError() 

3580 

3581 @property 

3582 def exported_columns( 

3583 self, 

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

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

3586 that represents the "exported" 

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

3588 :class:`_sql.TextClause` constructs. 

3589 

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

3591 object are synonymous 

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

3593 

3594 .. versionadded:: 1.4 

3595 

3596 .. seealso:: 

3597 

3598 :attr:`_expression.Select.exported_columns` 

3599 

3600 :attr:`_expression.Selectable.exported_columns` 

3601 

3602 :attr:`_expression.FromClause.exported_columns` 

3603 

3604 

3605 """ 

3606 return self.selected_columns.as_readonly() 

3607 

3608 @property 

3609 @util.deprecated( 

3610 "1.4", 

3611 "The :attr:`_expression.SelectBase.c` and " 

3612 ":attr:`_expression.SelectBase.columns` attributes " 

3613 "are deprecated and will be removed in a future release; these " 

3614 "attributes implicitly create a subquery that should be explicit. " 

3615 "Please call :meth:`_expression.SelectBase.subquery` " 

3616 "first in order to create " 

3617 "a subquery, which then contains this attribute. To access the " 

3618 "columns that this SELECT object SELECTs " 

3619 "from, use the :attr:`_expression.SelectBase.selected_columns` " 

3620 "attribute.", 

3621 ) 

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

3623 return self._implicit_subquery.columns 

3624 

3625 @property 

3626 def columns( 

3627 self, 

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

3629 return self.c 

3630 

3631 def get_label_style(self) -> SelectLabelStyle: 

3632 """ 

3633 Retrieve the current label style. 

3634 

3635 Implemented by subclasses. 

3636 

3637 """ 

3638 raise NotImplementedError() 

3639 

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

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

3642 

3643 Implemented by subclasses. 

3644 

3645 """ 

3646 

3647 raise NotImplementedError() 

3648 

3649 @util.deprecated( 

3650 "1.4", 

3651 "The :meth:`_expression.SelectBase.select` method is deprecated " 

3652 "and will be removed in a future release; this method implicitly " 

3653 "creates a subquery that should be explicit. " 

3654 "Please call :meth:`_expression.SelectBase.subquery` " 

3655 "first in order to create " 

3656 "a subquery, which then can be selected.", 

3657 ) 

3658 def select(self, *arg: Any, **kw: Any) -> Select[Any]: 

3659 return self._implicit_subquery.select(*arg, **kw) 

3660 

3661 @HasMemoized.memoized_attribute 

3662 def _implicit_subquery(self) -> Subquery: 

3663 return self.subquery() 

3664 

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

3666 raise NotImplementedError() 

3667 

3668 @util.deprecated( 

3669 "1.4", 

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

3671 "method is deprecated and will be " 

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

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

3674 ) 

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

3676 return self.scalar_subquery() 

3677 

3678 def exists(self) -> Exists: 

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

3680 which can be used as a column expression. 

3681 

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

3683 

3684 .. seealso:: 

3685 

3686 :func:`_sql.exists` 

3687 

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

3689 

3690 .. versionadded:: 1.4 

3691 

3692 """ 

3693 return Exists(self) 

3694 

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

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

3697 used as a column expression. 

3698 

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

3700 

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

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

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

3704 an enclosing SELECT. 

3705 

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

3707 subquery that can be produced using the 

3708 :meth:`_expression.SelectBase.subquery` 

3709 method. 

3710 

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

3712 :meth:`_expression.SelectBase.scalar_subquery`. 

3713 

3714 .. seealso:: 

3715 

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

3717 

3718 """ 

3719 if self._label_style is not LABEL_STYLE_NONE: 

3720 self = self.set_label_style(LABEL_STYLE_NONE) 

3721 

3722 return ScalarSelect(self) 

3723 

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

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

3726 subquery with a label. 

3727 

3728 .. seealso:: 

3729 

3730 :meth:`_expression.SelectBase.scalar_subquery`. 

3731 

3732 """ 

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

3734 

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

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

3737 

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

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

3740 

3741 .. seealso:: 

3742 

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

3744 

3745 """ 

3746 return Lateral._factory(self, name) 

3747 

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

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

3750 

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

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

3753 SELECT statement. 

3754 

3755 Given a SELECT statement such as:: 

3756 

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

3758 

3759 The above statement might look like: 

3760 

3761 .. sourcecode:: sql 

3762 

3763 SELECT table.id, table.name FROM table 

3764 

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

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

3767 a named sub-element:: 

3768 

3769 subq = stmt.subquery() 

3770 new_stmt = select(subq) 

3771 

3772 The above renders as: 

3773 

3774 .. sourcecode:: sql 

3775 

3776 SELECT anon_1.id, anon_1.name 

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

3778 

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

3780 is equivalent to calling 

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

3782 method on a FROM object; however, 

3783 as a :class:`_expression.SelectBase` 

3784 object is not directly FROM object, 

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

3786 method provides clearer semantics. 

3787 

3788 .. versionadded:: 1.4 

3789 

3790 """ 

3791 

3792 return Subquery._construct( 

3793 self._ensure_disambiguated_names(), name=name 

3794 ) 

3795 

3796 def _ensure_disambiguated_names(self) -> Self: 

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

3798 disambiguated in some way, if possible. 

3799 

3800 """ 

3801 

3802 raise NotImplementedError() 

3803 

3804 def alias( 

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

3806 ) -> Subquery: 

3807 """Return a named subquery against this 

3808 :class:`_expression.SelectBase`. 

3809 

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

3811 :class:`_expression.FromClause`), 

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

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

3814 :class:`_expression.FromClause`. 

3815 

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

3817 method is now 

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

3819 

3820 """ 

3821 return self.subquery(name=name) 

3822 

3823 

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

3825 

3826 

3827class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3828 """Represent a grouping of a :class:`_expression.SelectBase`. 

3829 

3830 This differs from :class:`.Subquery` in that we are still 

3831 an "inner" SELECT statement, this is strictly for grouping inside of 

3832 compound selects. 

3833 

3834 """ 

3835 

3836 __visit_name__ = "select_statement_grouping" 

3837 _traverse_internals: _TraverseInternalsType = [ 

3838 ("element", InternalTraversal.dp_clauseelement) 

3839 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3840 

3841 _is_select_container = True 

3842 

3843 element: _SB 

3844 

3845 def __init__(self, element: _SB) -> None: 

3846 self.element = cast( 

3847 _SB, coercions.expect(roles.SelectStatementRole, element) 

3848 ) 

3849 

3850 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3851 new_element = self.element._ensure_disambiguated_names() 

3852 if new_element is not self.element: 

3853 return SelectStatementGrouping(new_element) 

3854 else: 

3855 return self 

3856 

3857 def get_label_style(self) -> SelectLabelStyle: 

3858 return self.element.get_label_style() 

3859 

3860 def set_label_style( 

3861 self, label_style: SelectLabelStyle 

3862 ) -> SelectStatementGrouping[_SB]: 

3863 return SelectStatementGrouping( 

3864 self.element.set_label_style(label_style) 

3865 ) 

3866 

3867 @property 

3868 def select_statement(self) -> _SB: 

3869 return self.element 

3870 

3871 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3872 return self 

3873 

3874 if TYPE_CHECKING: 

3875 

3876 def _ungroup(self) -> _SB: ... 

3877 

3878 # def _generate_columns_plus_names( 

3879 # self, anon_for_dupe_key: bool 

3880 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3881 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3882 

3883 def _generate_fromclause_column_proxies( 

3884 self, 

3885 subquery: FromClause, 

3886 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

3887 primary_key: ColumnSet, 

3888 foreign_keys: Set[KeyedColumnElement[Any]], 

3889 *, 

3890 proxy_compound_columns: Optional[ 

3891 Iterable[Sequence[ColumnElement[Any]]] 

3892 ] = None, 

3893 ) -> None: 

3894 self.element._generate_fromclause_column_proxies( 

3895 subquery, 

3896 columns, 

3897 proxy_compound_columns=proxy_compound_columns, 

3898 primary_key=primary_key, 

3899 foreign_keys=foreign_keys, 

3900 ) 

3901 

3902 @util.ro_non_memoized_property 

3903 def _all_selected_columns(self) -> _SelectIterable: 

3904 return self.element._all_selected_columns 

3905 

3906 @util.ro_non_memoized_property 

3907 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

3908 """A :class:`_expression.ColumnCollection` 

3909 representing the columns that 

3910 the embedded SELECT statement returns in its result set, not including 

3911 :class:`_sql.TextClause` constructs. 

3912 

3913 .. versionadded:: 1.4 

3914 

3915 .. seealso:: 

3916 

3917 :attr:`_sql.Select.selected_columns` 

3918 

3919 """ 

3920 return self.element.selected_columns 

3921 

3922 @util.ro_non_memoized_property 

3923 def _from_objects(self) -> List[FromClause]: 

3924 return self.element._from_objects 

3925 

3926 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self: 

3927 # SelectStatementGrouping not generative: has no attribute '_generate' 

3928 raise NotImplementedError 

3929 

3930 

3931class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

3932 """Base class for SELECT statements where additional elements can be 

3933 added. 

3934 

3935 This serves as the base for :class:`_expression.Select` and 

3936 :class:`_expression.CompoundSelect` 

3937 where elements such as ORDER BY, GROUP BY can be added and column 

3938 rendering can be controlled. Compare to 

3939 :class:`_expression.TextualSelect`, which, 

3940 while it subclasses :class:`_expression.SelectBase` 

3941 and is also a SELECT construct, 

3942 represents a fixed textual string which cannot be altered at this level, 

3943 only wrapped as a subquery. 

3944 

3945 """ 

3946 

3947 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3948 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3949 _limit_clause: Optional[ColumnElement[Any]] = None 

3950 _offset_clause: Optional[ColumnElement[Any]] = None 

3951 _fetch_clause: Optional[ColumnElement[Any]] = None 

3952 _fetch_clause_options: Optional[Dict[str, bool]] = None 

3953 _for_update_arg: Optional[ForUpdateArg] = None 

3954 

3955 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

3956 self._label_style = _label_style 

3957 

3958 @_generative 

3959 def with_for_update( 

3960 self, 

3961 *, 

3962 nowait: bool = False, 

3963 read: bool = False, 

3964 of: Optional[_ForUpdateOfArgument] = None, 

3965 skip_locked: bool = False, 

3966 key_share: bool = False, 

3967 ) -> Self: 

3968 """Specify a ``FOR UPDATE`` clause for this 

3969 :class:`_expression.GenerativeSelect`. 

3970 

3971 E.g.:: 

3972 

3973 stmt = select(table).with_for_update(nowait=True) 

3974 

3975 On a database like PostgreSQL or Oracle Database, the above would 

3976 render a statement like: 

3977 

3978 .. sourcecode:: sql 

3979 

3980 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

3981 

3982 on other backends, the ``nowait`` option is ignored and instead 

3983 would produce: 

3984 

3985 .. sourcecode:: sql 

3986 

3987 SELECT table.a, table.b FROM table FOR UPDATE 

3988 

3989 When called with no arguments, the statement will render with 

3990 the suffix ``FOR UPDATE``. Additional arguments can then be 

3991 provided which allow for common database-specific 

3992 variants. 

3993 

3994 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

3995 Database and PostgreSQL dialects. 

3996 

3997 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

3998 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

3999 ``nowait``, will render ``FOR SHARE NOWAIT``. 

4000 

4001 :param of: SQL expression or list of SQL expression elements, 

4002 (typically :class:`_schema.Column` objects or a compatible expression, 

4003 for some backends may also be a table expression) which will render 

4004 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4005 Database, some MySQL versions and possibly others. May render as a 

4006 table or as a column depending on backend. 

4007 

4008 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4009 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4010 if ``read=True`` is also specified. 

4011 

4012 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4013 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4014 on the PostgreSQL dialect. 

4015 

4016 """ 

4017 self._for_update_arg = ForUpdateArg( 

4018 nowait=nowait, 

4019 read=read, 

4020 of=of, 

4021 skip_locked=skip_locked, 

4022 key_share=key_share, 

4023 ) 

4024 return self 

4025 

4026 def get_label_style(self) -> SelectLabelStyle: 

4027 """ 

4028 Retrieve the current label style. 

4029 

4030 .. versionadded:: 1.4 

4031 

4032 """ 

4033 return self._label_style 

4034 

4035 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4036 """Return a new selectable with the specified label style. 

4037 

4038 There are three "label styles" available, 

4039 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4040 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4041 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4042 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4043 

4044 In modern SQLAlchemy, there is not generally a need to change the 

4045 labeling style, as per-expression labels are more effectively used by 

4046 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4047 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4048 disambiguate same-named columns from different tables, aliases, or 

4049 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4050 applies labels only to names that conflict with an existing name so 

4051 that the impact of this labeling is minimal. 

4052 

4053 The rationale for disambiguation is mostly so that all column 

4054 expressions are available from a given :attr:`_sql.FromClause.c` 

4055 collection when a subquery is created. 

4056 

4057 .. versionadded:: 1.4 - the 

4058 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4059 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4060 ``use_labels=True`` methods and/or parameters. 

4061 

4062 .. seealso:: 

4063 

4064 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4065 

4066 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` 

4067 

4068 :data:`_sql.LABEL_STYLE_NONE` 

4069 

4070 :data:`_sql.LABEL_STYLE_DEFAULT` 

4071 

4072 """ 

4073 if self._label_style is not style: 

4074 self = self._generate() 

4075 self._label_style = style 

4076 return self 

4077 

4078 @property 

4079 def _group_by_clause(self) -> ClauseList: 

4080 """ClauseList access to group_by_clauses for legacy dialects""" 

4081 return ClauseList._construct_raw( 

4082 operators.comma_op, self._group_by_clauses 

4083 ) 

4084 

4085 @property 

4086 def _order_by_clause(self) -> ClauseList: 

4087 """ClauseList access to order_by_clauses for legacy dialects""" 

4088 return ClauseList._construct_raw( 

4089 operators.comma_op, self._order_by_clauses 

4090 ) 

4091 

4092 def _offset_or_limit_clause( 

4093 self, 

4094 element: _LimitOffsetType, 

4095 name: Optional[str] = None, 

4096 type_: Optional[_TypeEngineArgument[int]] = None, 

4097 ) -> ColumnElement[Any]: 

4098 """Convert the given value to an "offset or limit" clause. 

4099 

4100 This handles incoming integers and converts to an expression; if 

4101 an expression is already given, it is passed through. 

4102 

4103 """ 

4104 return coercions.expect( 

4105 roles.LimitOffsetRole, element, name=name, type_=type_ 

4106 ) 

4107 

4108 @overload 

4109 def _offset_or_limit_clause_asint( 

4110 self, clause: ColumnElement[Any], attrname: str 

4111 ) -> NoReturn: ... 

4112 

4113 @overload 

4114 def _offset_or_limit_clause_asint( 

4115 self, clause: Optional[_OffsetLimitParam], attrname: str 

4116 ) -> Optional[int]: ... 

4117 

4118 def _offset_or_limit_clause_asint( 

4119 self, clause: Optional[ColumnElement[Any]], attrname: str 

4120 ) -> Union[NoReturn, Optional[int]]: 

4121 """Convert the "offset or limit" clause of a select construct to an 

4122 integer. 

4123 

4124 This is only possible if the value is stored as a simple bound 

4125 parameter. Otherwise, a compilation error is raised. 

4126 

4127 """ 

4128 if clause is None: 

4129 return None 

4130 try: 

4131 value = clause._limit_offset_value 

4132 except AttributeError as err: 

4133 raise exc.CompileError( 

4134 "This SELECT structure does not use a simple " 

4135 "integer value for %s" % attrname 

4136 ) from err 

4137 else: 

4138 return util.asint(value) 

4139 

4140 @property 

4141 def _limit(self) -> Optional[int]: 

4142 """Get an integer value for the limit. This should only be used 

4143 by code that cannot support a limit as a BindParameter or 

4144 other custom clause as it will throw an exception if the limit 

4145 isn't currently set to an integer. 

4146 

4147 """ 

4148 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4149 

4150 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4151 """True if the clause is a simple integer, False 

4152 if it is not present or is a SQL expression. 

4153 """ 

4154 return isinstance(clause, _OffsetLimitParam) 

4155 

4156 @property 

4157 def _offset(self) -> Optional[int]: 

4158 """Get an integer value for the offset. This should only be used 

4159 by code that cannot support an offset as a BindParameter or 

4160 other custom clause as it will throw an exception if the 

4161 offset isn't currently set to an integer. 

4162 

4163 """ 

4164 return self._offset_or_limit_clause_asint( 

4165 self._offset_clause, "offset" 

4166 ) 

4167 

4168 @property 

4169 def _has_row_limiting_clause(self) -> bool: 

4170 return ( 

4171 self._limit_clause is not None 

4172 or self._offset_clause is not None 

4173 or self._fetch_clause is not None 

4174 ) 

4175 

4176 @_generative 

4177 def limit(self, limit: _LimitOffsetType) -> Self: 

4178 """Return a new selectable with the given LIMIT criterion 

4179 applied. 

4180 

4181 This is a numerical value which usually renders as a ``LIMIT`` 

4182 expression in the resulting select. Backends that don't 

4183 support ``LIMIT`` will attempt to provide similar 

4184 functionality. 

4185 

4186 .. note:: 

4187 

4188 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4189 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4190 

4191 :param limit: an integer LIMIT parameter, or a SQL expression 

4192 that provides an integer result. Pass ``None`` to reset it. 

4193 

4194 .. seealso:: 

4195 

4196 :meth:`_sql.GenerativeSelect.fetch` 

4197 

4198 :meth:`_sql.GenerativeSelect.offset` 

4199 

4200 """ 

4201 

4202 self._fetch_clause = self._fetch_clause_options = None 

4203 self._limit_clause = self._offset_or_limit_clause(limit) 

4204 return self 

4205 

4206 @_generative 

4207 def fetch( 

4208 self, 

4209 count: _LimitOffsetType, 

4210 with_ties: bool = False, 

4211 percent: bool = False, 

4212 **dialect_kw: Any, 

4213 ) -> Self: 

4214 r"""Return a new selectable with the given FETCH FIRST criterion 

4215 applied. 

4216 

4217 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4218 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4219 select. This functionality is is currently implemented for Oracle 

4220 Database, PostgreSQL, MSSQL. 

4221 

4222 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4223 

4224 .. note:: 

4225 

4226 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4227 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4228 

4229 .. versionadded:: 1.4 

4230 

4231 :param count: an integer COUNT parameter, or a SQL expression 

4232 that provides an integer result. When ``percent=True`` this will 

4233 represent the percentage of rows to return, not the absolute value. 

4234 Pass ``None`` to reset it. 

4235 

4236 :param with_ties: When ``True``, the WITH TIES option is used 

4237 to return any additional rows that tie for the last place in the 

4238 result set according to the ``ORDER BY`` clause. The 

4239 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4240 

4241 :param percent: When ``True``, ``count`` represents the percentage 

4242 of the total number of selected rows to return. Defaults to ``False`` 

4243 

4244 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4245 may be accepted by dialects. 

4246 

4247 .. versionadded:: 2.0.41 

4248 

4249 .. seealso:: 

4250 

4251 :meth:`_sql.GenerativeSelect.limit` 

4252 

4253 :meth:`_sql.GenerativeSelect.offset` 

4254 

4255 """ 

4256 self._validate_dialect_kwargs(dialect_kw) 

4257 self._limit_clause = None 

4258 if count is None: 

4259 self._fetch_clause = self._fetch_clause_options = None 

4260 else: 

4261 self._fetch_clause = self._offset_or_limit_clause(count) 

4262 self._fetch_clause_options = { 

4263 "with_ties": with_ties, 

4264 "percent": percent, 

4265 } 

4266 return self 

4267 

4268 @_generative 

4269 def offset(self, offset: _LimitOffsetType) -> Self: 

4270 """Return a new selectable with the given OFFSET criterion 

4271 applied. 

4272 

4273 

4274 This is a numeric value which usually renders as an ``OFFSET`` 

4275 expression in the resulting select. Backends that don't 

4276 support ``OFFSET`` will attempt to provide similar 

4277 functionality. 

4278 

4279 :param offset: an integer OFFSET parameter, or a SQL expression 

4280 that provides an integer result. Pass ``None`` to reset it. 

4281 

4282 .. seealso:: 

4283 

4284 :meth:`_sql.GenerativeSelect.limit` 

4285 

4286 :meth:`_sql.GenerativeSelect.fetch` 

4287 

4288 """ 

4289 

4290 self._offset_clause = self._offset_or_limit_clause(offset) 

4291 return self 

4292 

4293 @_generative 

4294 @util.preload_module("sqlalchemy.sql.util") 

4295 def slice( 

4296 self, 

4297 start: int, 

4298 stop: int, 

4299 ) -> Self: 

4300 """Apply LIMIT / OFFSET to this statement based on a slice. 

4301 

4302 The start and stop indices behave like the argument to Python's 

4303 built-in :func:`range` function. This method provides an 

4304 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4305 query. 

4306 

4307 For example, :: 

4308 

4309 stmt = select(User).order_by(User.id).slice(1, 3) 

4310 

4311 renders as 

4312 

4313 .. sourcecode:: sql 

4314 

4315 SELECT users.id AS users_id, 

4316 users.name AS users_name 

4317 FROM users ORDER BY users.id 

4318 LIMIT ? OFFSET ? 

4319 (2, 1) 

4320 

4321 .. note:: 

4322 

4323 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4324 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4325 

4326 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4327 method generalized from the ORM. 

4328 

4329 .. seealso:: 

4330 

4331 :meth:`_sql.GenerativeSelect.limit` 

4332 

4333 :meth:`_sql.GenerativeSelect.offset` 

4334 

4335 :meth:`_sql.GenerativeSelect.fetch` 

4336 

4337 """ 

4338 sql_util = util.preloaded.sql_util 

4339 self._fetch_clause = self._fetch_clause_options = None 

4340 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4341 self._limit_clause, self._offset_clause, start, stop 

4342 ) 

4343 return self 

4344 

4345 @_generative 

4346 def order_by( 

4347 self, 

4348 __first: Union[ 

4349 Literal[None, _NoArg.NO_ARG], 

4350 _ColumnExpressionOrStrLabelArgument[Any], 

4351 ] = _NoArg.NO_ARG, 

4352 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4353 ) -> Self: 

4354 r"""Return a new selectable with the given list of ORDER BY 

4355 criteria applied. 

4356 

4357 e.g.:: 

4358 

4359 stmt = select(table).order_by(table.c.id, table.c.name) 

4360 

4361 Calling this method multiple times is equivalent to calling it once 

4362 with all the clauses concatenated. All existing ORDER BY criteria may 

4363 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4364 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4365 

4366 # will erase all ORDER BY and ORDER BY new_col alone 

4367 stmt = stmt.order_by(None).order_by(new_col) 

4368 

4369 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4370 constructs 

4371 which will be used to generate an ORDER BY clause. 

4372 

4373 .. seealso:: 

4374 

4375 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4376 

4377 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4378 

4379 """ 

4380 

4381 if not clauses and __first is None: 

4382 self._order_by_clauses = () 

4383 elif __first is not _NoArg.NO_ARG: 

4384 self._order_by_clauses += tuple( 

4385 coercions.expect( 

4386 roles.OrderByRole, clause, apply_propagate_attrs=self 

4387 ) 

4388 for clause in (__first,) + clauses 

4389 ) 

4390 return self 

4391 

4392 @_generative 

4393 def group_by( 

4394 self, 

4395 __first: Union[ 

4396 Literal[None, _NoArg.NO_ARG], 

4397 _ColumnExpressionOrStrLabelArgument[Any], 

4398 ] = _NoArg.NO_ARG, 

4399 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4400 ) -> Self: 

4401 r"""Return a new selectable with the given list of GROUP BY 

4402 criterion applied. 

4403 

4404 All existing GROUP BY settings can be suppressed by passing ``None``. 

4405 

4406 e.g.:: 

4407 

4408 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4409 

4410 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4411 constructs 

4412 which will be used to generate an GROUP BY clause. 

4413 

4414 .. seealso:: 

4415 

4416 :ref:`tutorial_group_by_w_aggregates` - in the 

4417 :ref:`unified_tutorial` 

4418 

4419 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4420 

4421 """ # noqa: E501 

4422 

4423 if not clauses and __first is None: 

4424 self._group_by_clauses = () 

4425 elif __first is not _NoArg.NO_ARG: 

4426 self._group_by_clauses += tuple( 

4427 coercions.expect( 

4428 roles.GroupByRole, clause, apply_propagate_attrs=self 

4429 ) 

4430 for clause in (__first,) + clauses 

4431 ) 

4432 return self 

4433 

4434 

4435@CompileState.plugin_for("default", "compound_select") 

4436class CompoundSelectState(CompileState): 

4437 @util.memoized_property 

4438 def _label_resolve_dict( 

4439 self, 

4440 ) -> Tuple[ 

4441 Dict[str, ColumnElement[Any]], 

4442 Dict[str, ColumnElement[Any]], 

4443 Dict[str, ColumnElement[Any]], 

4444 ]: 

4445 # TODO: this is hacky and slow 

4446 hacky_subquery = self.statement.subquery() 

4447 hacky_subquery.named_with_column = False 

4448 d = {c.key: c for c in hacky_subquery.c} 

4449 return d, d, d 

4450 

4451 

4452class _CompoundSelectKeyword(Enum): 

4453 UNION = "UNION" 

4454 UNION_ALL = "UNION ALL" 

4455 EXCEPT = "EXCEPT" 

4456 EXCEPT_ALL = "EXCEPT ALL" 

4457 INTERSECT = "INTERSECT" 

4458 INTERSECT_ALL = "INTERSECT ALL" 

4459 

4460 

4461class CompoundSelect(HasCompileState, GenerativeSelect, TypedReturnsRows[_TP]): 

4462 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4463 SELECT-based set operations. 

4464 

4465 

4466 .. seealso:: 

4467 

4468 :func:`_expression.union` 

4469 

4470 :func:`_expression.union_all` 

4471 

4472 :func:`_expression.intersect` 

4473 

4474 :func:`_expression.intersect_all` 

4475 

4476 :func:`_expression.except` 

4477 

4478 :func:`_expression.except_all` 

4479 

4480 """ 

4481 

4482 __visit_name__ = "compound_select" 

4483 

4484 _traverse_internals: _TraverseInternalsType = ( 

4485 [ 

4486 ("selects", InternalTraversal.dp_clauseelement_list), 

4487 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4488 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4489 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4490 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4491 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4492 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4493 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4494 ("keyword", InternalTraversal.dp_string), 

4495 ] 

4496 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4497 + HasCTE._has_ctes_traverse_internals 

4498 + DialectKWArgs._dialect_kwargs_traverse_internals 

4499 ) 

4500 

4501 selects: List[SelectBase] 

4502 

4503 _is_from_container = True 

4504 _auto_correlate = False 

4505 

4506 def __init__( 

4507 self, 

4508 keyword: _CompoundSelectKeyword, 

4509 *selects: _SelectStatementForCompoundArgument[_TP], 

4510 ): 

4511 self.keyword = keyword 

4512 self.selects = [ 

4513 coercions.expect( 

4514 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4515 ).self_group(against=self) 

4516 for s in selects 

4517 ] 

4518 

4519 GenerativeSelect.__init__(self) 

4520 

4521 @classmethod 

4522 def _create_union( 

4523 cls, *selects: _SelectStatementForCompoundArgument[_TP] 

4524 ) -> CompoundSelect[_TP]: 

4525 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4526 

4527 @classmethod 

4528 def _create_union_all( 

4529 cls, *selects: _SelectStatementForCompoundArgument[_TP] 

4530 ) -> CompoundSelect[_TP]: 

4531 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4532 

4533 @classmethod 

4534 def _create_except( 

4535 cls, *selects: _SelectStatementForCompoundArgument[_TP] 

4536 ) -> CompoundSelect[_TP]: 

4537 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4538 

4539 @classmethod 

4540 def _create_except_all( 

4541 cls, *selects: _SelectStatementForCompoundArgument[_TP] 

4542 ) -> CompoundSelect[_TP]: 

4543 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4544 

4545 @classmethod 

4546 def _create_intersect( 

4547 cls, *selects: _SelectStatementForCompoundArgument[_TP] 

4548 ) -> CompoundSelect[_TP]: 

4549 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4550 

4551 @classmethod 

4552 def _create_intersect_all( 

4553 cls, *selects: _SelectStatementForCompoundArgument[_TP] 

4554 ) -> CompoundSelect[_TP]: 

4555 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4556 

4557 def _scalar_type(self) -> TypeEngine[Any]: 

4558 return self.selects[0]._scalar_type() 

4559 

4560 def self_group( 

4561 self, against: Optional[OperatorType] = None 

4562 ) -> GroupedElement: 

4563 return SelectStatementGrouping(self) 

4564 

4565 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

4566 for s in self.selects: 

4567 if s.is_derived_from(fromclause): 

4568 return True 

4569 return False 

4570 

4571 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4572 if self._label_style is not style: 

4573 self = self._generate() 

4574 select_0 = self.selects[0].set_label_style(style) 

4575 self.selects = [select_0] + self.selects[1:] 

4576 

4577 return self 

4578 

4579 def _ensure_disambiguated_names(self) -> Self: 

4580 new_select = self.selects[0]._ensure_disambiguated_names() 

4581 if new_select is not self.selects[0]: 

4582 self = self._generate() 

4583 self.selects = [new_select] + self.selects[1:] 

4584 

4585 return self 

4586 

4587 def _generate_fromclause_column_proxies( 

4588 self, 

4589 subquery: FromClause, 

4590 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

4591 primary_key: ColumnSet, 

4592 foreign_keys: Set[KeyedColumnElement[Any]], 

4593 *, 

4594 proxy_compound_columns: Optional[ 

4595 Iterable[Sequence[ColumnElement[Any]]] 

4596 ] = None, 

4597 ) -> None: 

4598 # this is a slightly hacky thing - the union exports a 

4599 # column that resembles just that of the *first* selectable. 

4600 # to get at a "composite" column, particularly foreign keys, 

4601 # you have to dig through the proxies collection which we 

4602 # generate below. 

4603 select_0 = self.selects[0] 

4604 

4605 if self._label_style is not LABEL_STYLE_DEFAULT: 

4606 select_0 = select_0.set_label_style(self._label_style) 

4607 

4608 # hand-construct the "_proxies" collection to include all 

4609 # derived columns place a 'weight' annotation corresponding 

4610 # to how low in the list of select()s the column occurs, so 

4611 # that the corresponding_column() operation can resolve 

4612 # conflicts 

4613 extra_col_iterator = zip( 

4614 *[ 

4615 [ 

4616 c._annotate(dd) 

4617 for c in stmt._all_selected_columns 

4618 if is_column_element(c) 

4619 ] 

4620 for dd, stmt in [ 

4621 ({"weight": i + 1}, stmt) 

4622 for i, stmt in enumerate(self.selects) 

4623 ] 

4624 ] 

4625 ) 

4626 

4627 # the incoming proxy_compound_columns can be present also if this is 

4628 # a compound embedded in a compound. it's probably more appropriate 

4629 # that we generate new weights local to this nested compound, though 

4630 # i haven't tried to think what it means for compound nested in 

4631 # compound 

4632 select_0._generate_fromclause_column_proxies( 

4633 subquery, 

4634 columns, 

4635 proxy_compound_columns=extra_col_iterator, 

4636 primary_key=primary_key, 

4637 foreign_keys=foreign_keys, 

4638 ) 

4639 

4640 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

4641 super()._refresh_for_new_column(column) 

4642 for select in self.selects: 

4643 select._refresh_for_new_column(column) 

4644 

4645 @util.ro_non_memoized_property 

4646 def _all_selected_columns(self) -> _SelectIterable: 

4647 return self.selects[0]._all_selected_columns 

4648 

4649 @util.ro_non_memoized_property 

4650 def selected_columns( 

4651 self, 

4652 ) -> ColumnCollection[str, ColumnElement[Any]]: 

4653 """A :class:`_expression.ColumnCollection` 

4654 representing the columns that 

4655 this SELECT statement or similar construct returns in its result set, 

4656 not including :class:`_sql.TextClause` constructs. 

4657 

4658 For a :class:`_expression.CompoundSelect`, the 

4659 :attr:`_expression.CompoundSelect.selected_columns` 

4660 attribute returns the selected 

4661 columns of the first SELECT statement contained within the series of 

4662 statements within the set operation. 

4663 

4664 .. seealso:: 

4665 

4666 :attr:`_sql.Select.selected_columns` 

4667 

4668 .. versionadded:: 1.4 

4669 

4670 """ 

4671 return self.selects[0].selected_columns 

4672 

4673 

4674# backwards compat 

4675for elem in _CompoundSelectKeyword: 

4676 setattr(CompoundSelect, elem.name, elem) 

4677 

4678 

4679@CompileState.plugin_for("default", "select") 

4680class SelectState(util.MemoizedSlots, CompileState): 

4681 __slots__ = ( 

4682 "from_clauses", 

4683 "froms", 

4684 "columns_plus_names", 

4685 "_label_resolve_dict", 

4686 ) 

4687 

4688 if TYPE_CHECKING: 

4689 default_select_compile_options: CacheableOptions 

4690 else: 

4691 

4692 class default_select_compile_options(CacheableOptions): 

4693 _cache_key_traversal = [] 

4694 

4695 if TYPE_CHECKING: 

4696 

4697 @classmethod 

4698 def get_plugin_class( 

4699 cls, statement: Executable 

4700 ) -> Type[SelectState]: ... 

4701 

4702 def __init__( 

4703 self, 

4704 statement: Select[Any], 

4705 compiler: SQLCompiler, 

4706 **kw: Any, 

4707 ): 

4708 self.statement = statement 

4709 self.from_clauses = statement._from_obj 

4710 

4711 for memoized_entities in statement._memoized_select_entities: 

4712 self._setup_joins( 

4713 memoized_entities._setup_joins, memoized_entities._raw_columns 

4714 ) 

4715 

4716 if statement._setup_joins: 

4717 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4718 

4719 self.froms = self._get_froms(statement) 

4720 

4721 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4722 

4723 @classmethod 

4724 def _plugin_not_implemented(cls) -> NoReturn: 

4725 raise NotImplementedError( 

4726 "The default SELECT construct without plugins does not " 

4727 "implement this method." 

4728 ) 

4729 

4730 @classmethod 

4731 def get_column_descriptions( 

4732 cls, statement: Select[Any] 

4733 ) -> List[Dict[str, Any]]: 

4734 return [ 

4735 { 

4736 "name": name, 

4737 "type": element.type, 

4738 "expr": element, 

4739 } 

4740 for _, name, _, element, _ in ( 

4741 statement._generate_columns_plus_names(False) 

4742 ) 

4743 ] 

4744 

4745 @classmethod 

4746 def from_statement( 

4747 cls, statement: Select[Any], from_statement: roles.ReturnsRowsRole 

4748 ) -> ExecutableReturnsRows: 

4749 cls._plugin_not_implemented() 

4750 

4751 @classmethod 

4752 def get_columns_clause_froms( 

4753 cls, statement: Select[Any] 

4754 ) -> List[FromClause]: 

4755 return cls._normalize_froms( 

4756 itertools.chain.from_iterable( 

4757 element._from_objects for element in statement._raw_columns 

4758 ) 

4759 ) 

4760 

4761 @classmethod 

4762 def _column_naming_convention( 

4763 cls, label_style: SelectLabelStyle 

4764 ) -> _LabelConventionCallable: 

4765 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4766 

4767 dedupe = label_style is not LABEL_STYLE_NONE 

4768 

4769 pa = prefix_anon_map() 

4770 names = set() 

4771 

4772 def go( 

4773 c: Union[ColumnElement[Any], TextClause], 

4774 col_name: Optional[str] = None, 

4775 ) -> Optional[str]: 

4776 if is_text_clause(c): 

4777 return None 

4778 elif TYPE_CHECKING: 

4779 assert is_column_element(c) 

4780 

4781 if not dedupe: 

4782 name = c._proxy_key 

4783 if name is None: 

4784 name = "_no_label" 

4785 return name 

4786 

4787 name = c._tq_key_label if table_qualified else c._proxy_key 

4788 

4789 if name is None: 

4790 name = "_no_label" 

4791 if name in names: 

4792 return c._anon_label(name) % pa 

4793 else: 

4794 names.add(name) 

4795 return name 

4796 

4797 elif name in names: 

4798 return ( 

4799 c._anon_tq_key_label % pa 

4800 if table_qualified 

4801 else c._anon_key_label % pa 

4802 ) 

4803 else: 

4804 names.add(name) 

4805 return name 

4806 

4807 return go 

4808 

4809 def _get_froms(self, statement: Select[Any]) -> List[FromClause]: 

4810 ambiguous_table_name_map: _AmbiguousTableNameMap 

4811 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4812 

4813 return self._normalize_froms( 

4814 itertools.chain( 

4815 self.from_clauses, 

4816 itertools.chain.from_iterable( 

4817 [ 

4818 element._from_objects 

4819 for element in statement._raw_columns 

4820 ] 

4821 ), 

4822 itertools.chain.from_iterable( 

4823 [ 

4824 element._from_objects 

4825 for element in statement._where_criteria 

4826 ] 

4827 ), 

4828 ), 

4829 check_statement=statement, 

4830 ambiguous_table_name_map=ambiguous_table_name_map, 

4831 ) 

4832 

4833 @classmethod 

4834 def _normalize_froms( 

4835 cls, 

4836 iterable_of_froms: Iterable[FromClause], 

4837 check_statement: Optional[Select[Any]] = None, 

4838 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4839 ) -> List[FromClause]: 

4840 """given an iterable of things to select FROM, reduce them to what 

4841 would actually render in the FROM clause of a SELECT. 

4842 

4843 This does the job of checking for JOINs, tables, etc. that are in fact 

4844 overlapping due to cloning, adaption, present in overlapping joins, 

4845 etc. 

4846 

4847 """ 

4848 seen: Set[FromClause] = set() 

4849 froms: List[FromClause] = [] 

4850 

4851 for item in iterable_of_froms: 

4852 if is_subquery(item) and item.element is check_statement: 

4853 raise exc.InvalidRequestError( 

4854 "select() construct refers to itself as a FROM" 

4855 ) 

4856 

4857 if not seen.intersection(item._cloned_set): 

4858 froms.append(item) 

4859 seen.update(item._cloned_set) 

4860 

4861 if froms: 

4862 toremove = set( 

4863 itertools.chain.from_iterable( 

4864 [_expand_cloned(f._hide_froms) for f in froms] 

4865 ) 

4866 ) 

4867 if toremove: 

4868 # filter out to FROM clauses not in the list, 

4869 # using a list to maintain ordering 

4870 froms = [f for f in froms if f not in toremove] 

4871 

4872 if ambiguous_table_name_map is not None: 

4873 ambiguous_table_name_map.update( 

4874 ( 

4875 fr.name, 

4876 _anonymous_label.safe_construct( 

4877 hash(fr.name), fr.name 

4878 ), 

4879 ) 

4880 for item in froms 

4881 for fr in item._from_objects 

4882 if is_table(fr) 

4883 and fr.schema 

4884 and fr.name not in ambiguous_table_name_map 

4885 ) 

4886 

4887 return froms 

4888 

4889 def _get_display_froms( 

4890 self, 

4891 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4892 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4893 ) -> List[FromClause]: 

4894 """Return the full list of 'from' clauses to be displayed. 

4895 

4896 Takes into account a set of existing froms which may be 

4897 rendered in the FROM clause of enclosing selects; this Select 

4898 may want to leave those absent if it is automatically 

4899 correlating. 

4900 

4901 """ 

4902 

4903 froms = self.froms 

4904 

4905 if self.statement._correlate: 

4906 to_correlate = self.statement._correlate 

4907 if to_correlate: 

4908 froms = [ 

4909 f 

4910 for f in froms 

4911 if f 

4912 not in _cloned_intersection( 

4913 _cloned_intersection( 

4914 froms, explicit_correlate_froms or () 

4915 ), 

4916 to_correlate, 

4917 ) 

4918 ] 

4919 

4920 if self.statement._correlate_except is not None: 

4921 froms = [ 

4922 f 

4923 for f in froms 

4924 if f 

4925 not in _cloned_difference( 

4926 _cloned_intersection( 

4927 froms, explicit_correlate_froms or () 

4928 ), 

4929 self.statement._correlate_except, 

4930 ) 

4931 ] 

4932 

4933 if ( 

4934 self.statement._auto_correlate 

4935 and implicit_correlate_froms 

4936 and len(froms) > 1 

4937 ): 

4938 froms = [ 

4939 f 

4940 for f in froms 

4941 if f 

4942 not in _cloned_intersection(froms, implicit_correlate_froms) 

4943 ] 

4944 

4945 if not len(froms): 

4946 raise exc.InvalidRequestError( 

4947 "Select statement '%r" 

4948 "' returned no FROM clauses " 

4949 "due to auto-correlation; " 

4950 "specify correlate(<tables>) " 

4951 "to control correlation " 

4952 "manually." % self.statement 

4953 ) 

4954 

4955 return froms 

4956 

4957 def _memoized_attr__label_resolve_dict( 

4958 self, 

4959 ) -> Tuple[ 

4960 Dict[str, ColumnElement[Any]], 

4961 Dict[str, ColumnElement[Any]], 

4962 Dict[str, ColumnElement[Any]], 

4963 ]: 

4964 with_cols: Dict[str, ColumnElement[Any]] = { 

4965 c._tq_label or c.key: c 

4966 for c in self.statement._all_selected_columns 

4967 if c._allow_label_resolve 

4968 } 

4969 only_froms: Dict[str, ColumnElement[Any]] = { 

4970 c.key: c # type: ignore 

4971 for c in _select_iterables(self.froms) 

4972 if c._allow_label_resolve 

4973 } 

4974 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

4975 for key, value in only_froms.items(): 

4976 with_cols.setdefault(key, value) 

4977 

4978 return with_cols, only_froms, only_cols 

4979 

4980 @classmethod 

4981 def determine_last_joined_entity( 

4982 cls, stmt: Select[Any] 

4983 ) -> Optional[_JoinTargetElement]: 

4984 if stmt._setup_joins: 

4985 return stmt._setup_joins[-1][0] 

4986 else: 

4987 return None 

4988 

4989 @classmethod 

4990 def all_selected_columns(cls, statement: Select[Any]) -> _SelectIterable: 

4991 return [c for c in _select_iterables(statement._raw_columns)] 

4992 

4993 def _setup_joins( 

4994 self, 

4995 args: Tuple[_SetupJoinsElement, ...], 

4996 raw_columns: List[_ColumnsClauseElement], 

4997 ) -> None: 

4998 for right, onclause, left, flags in args: 

4999 if TYPE_CHECKING: 

5000 if onclause is not None: 

5001 assert isinstance(onclause, ColumnElement) 

5002 

5003 isouter = flags["isouter"] 

5004 full = flags["full"] 

5005 

5006 if left is None: 

5007 ( 

5008 left, 

5009 replace_from_obj_index, 

5010 ) = self._join_determine_implicit_left_side( 

5011 raw_columns, left, right, onclause 

5012 ) 

5013 else: 

5014 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5015 left 

5016 ) 

5017 

5018 # these assertions can be made here, as if the right/onclause 

5019 # contained ORM elements, the select() statement would have been 

5020 # upgraded to an ORM select, and this method would not be called; 

5021 # orm.context.ORMSelectCompileState._join() would be 

5022 # used instead. 

5023 if TYPE_CHECKING: 

5024 assert isinstance(right, FromClause) 

5025 if onclause is not None: 

5026 assert isinstance(onclause, ColumnElement) 

5027 

5028 if replace_from_obj_index is not None: 

5029 # splice into an existing element in the 

5030 # self._from_obj list 

5031 left_clause = self.from_clauses[replace_from_obj_index] 

5032 

5033 self.from_clauses = ( 

5034 self.from_clauses[:replace_from_obj_index] 

5035 + ( 

5036 Join( 

5037 left_clause, 

5038 right, 

5039 onclause, 

5040 isouter=isouter, 

5041 full=full, 

5042 ), 

5043 ) 

5044 + self.from_clauses[replace_from_obj_index + 1 :] 

5045 ) 

5046 else: 

5047 assert left is not None 

5048 self.from_clauses = self.from_clauses + ( 

5049 Join(left, right, onclause, isouter=isouter, full=full), 

5050 ) 

5051 

5052 @util.preload_module("sqlalchemy.sql.util") 

5053 def _join_determine_implicit_left_side( 

5054 self, 

5055 raw_columns: List[_ColumnsClauseElement], 

5056 left: Optional[FromClause], 

5057 right: _JoinTargetElement, 

5058 onclause: Optional[ColumnElement[Any]], 

5059 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5060 """When join conditions don't express the left side explicitly, 

5061 determine if an existing FROM or entity in this query 

5062 can serve as the left hand side. 

5063 

5064 """ 

5065 

5066 sql_util = util.preloaded.sql_util 

5067 

5068 replace_from_obj_index: Optional[int] = None 

5069 

5070 from_clauses = self.from_clauses 

5071 

5072 if from_clauses: 

5073 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5074 from_clauses, right, onclause 

5075 ) 

5076 

5077 if len(indexes) == 1: 

5078 replace_from_obj_index = indexes[0] 

5079 left = from_clauses[replace_from_obj_index] 

5080 else: 

5081 potential = {} 

5082 statement = self.statement 

5083 

5084 for from_clause in itertools.chain( 

5085 itertools.chain.from_iterable( 

5086 [element._from_objects for element in raw_columns] 

5087 ), 

5088 itertools.chain.from_iterable( 

5089 [ 

5090 element._from_objects 

5091 for element in statement._where_criteria 

5092 ] 

5093 ), 

5094 ): 

5095 potential[from_clause] = () 

5096 

5097 all_clauses = list(potential.keys()) 

5098 indexes = sql_util.find_left_clause_to_join_from( 

5099 all_clauses, right, onclause 

5100 ) 

5101 

5102 if len(indexes) == 1: 

5103 left = all_clauses[indexes[0]] 

5104 

5105 if len(indexes) > 1: 

5106 raise exc.InvalidRequestError( 

5107 "Can't determine which FROM clause to join " 

5108 "from, there are multiple FROMS which can " 

5109 "join to this entity. Please use the .select_from() " 

5110 "method to establish an explicit left side, as well as " 

5111 "providing an explicit ON clause if not present already to " 

5112 "help resolve the ambiguity." 

5113 ) 

5114 elif not indexes: 

5115 raise exc.InvalidRequestError( 

5116 "Don't know how to join to %r. " 

5117 "Please use the .select_from() " 

5118 "method to establish an explicit left side, as well as " 

5119 "providing an explicit ON clause if not present already to " 

5120 "help resolve the ambiguity." % (right,) 

5121 ) 

5122 return left, replace_from_obj_index 

5123 

5124 @util.preload_module("sqlalchemy.sql.util") 

5125 def _join_place_explicit_left_side( 

5126 self, left: FromClause 

5127 ) -> Optional[int]: 

5128 replace_from_obj_index: Optional[int] = None 

5129 

5130 sql_util = util.preloaded.sql_util 

5131 

5132 from_clauses = list(self.statement._iterate_from_elements()) 

5133 

5134 if from_clauses: 

5135 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5136 self.from_clauses, left 

5137 ) 

5138 else: 

5139 indexes = [] 

5140 

5141 if len(indexes) > 1: 

5142 raise exc.InvalidRequestError( 

5143 "Can't identify which entity in which to assign the " 

5144 "left side of this join. Please use a more specific " 

5145 "ON clause." 

5146 ) 

5147 

5148 # have an index, means the left side is already present in 

5149 # an existing FROM in the self._from_obj tuple 

5150 if indexes: 

5151 replace_from_obj_index = indexes[0] 

5152 

5153 # no index, means we need to add a new element to the 

5154 # self._from_obj tuple 

5155 

5156 return replace_from_obj_index 

5157 

5158 

5159class _SelectFromElements: 

5160 __slots__ = () 

5161 

5162 _raw_columns: List[_ColumnsClauseElement] 

5163 _where_criteria: Tuple[ColumnElement[Any], ...] 

5164 _from_obj: Tuple[FromClause, ...] 

5165 

5166 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5167 # note this does not include elements 

5168 # in _setup_joins 

5169 

5170 seen = set() 

5171 for element in self._raw_columns: 

5172 for fr in element._from_objects: 

5173 if fr in seen: 

5174 continue 

5175 seen.add(fr) 

5176 yield fr 

5177 for element in self._where_criteria: 

5178 for fr in element._from_objects: 

5179 if fr in seen: 

5180 continue 

5181 seen.add(fr) 

5182 yield fr 

5183 for element in self._from_obj: 

5184 if element in seen: 

5185 continue 

5186 seen.add(element) 

5187 yield element 

5188 

5189 

5190class _MemoizedSelectEntities( 

5191 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5192): 

5193 """represents partial state from a Select object, for the case 

5194 where Select.columns() has redefined the set of columns/entities the 

5195 statement will be SELECTing from. This object represents 

5196 the entities from the SELECT before that transformation was applied, 

5197 so that transformations that were made in terms of the SELECT at that 

5198 time, such as join() as well as options(), can access the correct context. 

5199 

5200 In previous SQLAlchemy versions, this wasn't needed because these 

5201 constructs calculated everything up front, like when you called join() 

5202 or options(), it did everything to figure out how that would translate 

5203 into specific SQL constructs that would be ready to send directly to the 

5204 SQL compiler when needed. But as of 

5205 1.4, all of that stuff is done in the compilation phase, during the 

5206 "compile state" portion of the process, so that the work can all be 

5207 cached. So it needs to be able to resolve joins/options2 based on what 

5208 the list of entities was when those methods were called. 

5209 

5210 

5211 """ 

5212 

5213 __visit_name__ = "memoized_select_entities" 

5214 

5215 _traverse_internals: _TraverseInternalsType = [ 

5216 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5217 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5218 ("_with_options", InternalTraversal.dp_executable_options), 

5219 ] 

5220 

5221 _is_clone_of: Optional[ClauseElement] 

5222 _raw_columns: List[_ColumnsClauseElement] 

5223 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5224 _with_options: Tuple[ExecutableOption, ...] 

5225 

5226 _annotations = util.EMPTY_DICT 

5227 

5228 def _clone(self, **kw: Any) -> Self: 

5229 c = self.__class__.__new__(self.__class__) 

5230 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5231 

5232 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5233 return c 

5234 

5235 @classmethod 

5236 def _generate_for_statement(cls, select_stmt: Select[Any]) -> None: 

5237 if select_stmt._setup_joins or select_stmt._with_options: 

5238 self = _MemoizedSelectEntities() 

5239 self._raw_columns = select_stmt._raw_columns 

5240 self._setup_joins = select_stmt._setup_joins 

5241 self._with_options = select_stmt._with_options 

5242 

5243 select_stmt._memoized_select_entities += (self,) 

5244 select_stmt._raw_columns = [] 

5245 select_stmt._setup_joins = select_stmt._with_options = () 

5246 

5247 

5248class Select( 

5249 HasPrefixes, 

5250 HasSuffixes, 

5251 HasHints, 

5252 HasCompileState, 

5253 _SelectFromElements, 

5254 GenerativeSelect, 

5255 TypedReturnsRows[_TP], 

5256): 

5257 """Represents a ``SELECT`` statement. 

5258 

5259 The :class:`_sql.Select` object is normally constructed using the 

5260 :func:`_sql.select` function. See that function for details. 

5261 

5262 .. seealso:: 

5263 

5264 :func:`_sql.select` 

5265 

5266 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5267 

5268 """ 

5269 

5270 __visit_name__ = "select" 

5271 

5272 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5273 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5274 

5275 _raw_columns: List[_ColumnsClauseElement] 

5276 

5277 _distinct: bool = False 

5278 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5279 _correlate: Tuple[FromClause, ...] = () 

5280 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5281 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5282 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5283 _from_obj: Tuple[FromClause, ...] = () 

5284 _auto_correlate = True 

5285 _is_select_statement = True 

5286 _compile_options: CacheableOptions = ( 

5287 SelectState.default_select_compile_options 

5288 ) 

5289 

5290 _traverse_internals: _TraverseInternalsType = ( 

5291 [ 

5292 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5293 ( 

5294 "_memoized_select_entities", 

5295 InternalTraversal.dp_memoized_select_entities, 

5296 ), 

5297 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5298 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5299 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5300 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5301 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5302 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5303 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5304 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5305 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5306 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5307 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5308 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5309 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5310 ("_distinct", InternalTraversal.dp_boolean), 

5311 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5312 ("_label_style", InternalTraversal.dp_plain_obj), 

5313 ] 

5314 + HasCTE._has_ctes_traverse_internals 

5315 + HasPrefixes._has_prefixes_traverse_internals 

5316 + HasSuffixes._has_suffixes_traverse_internals 

5317 + HasHints._has_hints_traverse_internals 

5318 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5319 + Executable._executable_traverse_internals 

5320 + DialectKWArgs._dialect_kwargs_traverse_internals 

5321 ) 

5322 

5323 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5324 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5325 ] 

5326 

5327 _compile_state_factory: Type[SelectState] 

5328 

5329 @classmethod 

5330 def _create_raw_select(cls, **kw: Any) -> Select[Any]: 

5331 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5332 

5333 Used internally to build up :class:`.Select` constructs with 

5334 pre-established state. 

5335 

5336 """ 

5337 

5338 stmt = Select.__new__(Select) 

5339 stmt.__dict__.update(kw) 

5340 return stmt 

5341 

5342 def __init__( 

5343 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5344 ): 

5345 r"""Construct a new :class:`_expression.Select`. 

5346 

5347 The public constructor for :class:`_expression.Select` is the 

5348 :func:`_sql.select` function. 

5349 

5350 """ 

5351 self._raw_columns = [ 

5352 coercions.expect( 

5353 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5354 ) 

5355 for ent in entities 

5356 ] 

5357 GenerativeSelect.__init__(self) 

5358 

5359 def _scalar_type(self) -> TypeEngine[Any]: 

5360 if not self._raw_columns: 

5361 return NULLTYPE 

5362 elem = self._raw_columns[0] 

5363 cols = list(elem._select_iterable) 

5364 return cols[0].type 

5365 

5366 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5367 """A synonym for the :meth:`_sql.Select.where` method.""" 

5368 

5369 return self.where(*criteria) 

5370 

5371 def _filter_by_zero( 

5372 self, 

5373 ) -> Union[ 

5374 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5375 ]: 

5376 if self._setup_joins: 

5377 meth = SelectState.get_plugin_class( 

5378 self 

5379 ).determine_last_joined_entity 

5380 _last_joined_entity = meth(self) 

5381 if _last_joined_entity is not None: 

5382 return _last_joined_entity 

5383 

5384 if self._from_obj: 

5385 return self._from_obj[0] 

5386 

5387 return self._raw_columns[0] 

5388 

5389 if TYPE_CHECKING: 

5390 

5391 @overload 

5392 def scalar_subquery( 

5393 self: Select[Tuple[_MAYBE_ENTITY]], 

5394 ) -> ScalarSelect[Any]: ... 

5395 

5396 @overload 

5397 def scalar_subquery( 

5398 self: Select[Tuple[_NOT_ENTITY]], 

5399 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5400 

5401 @overload 

5402 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5403 

5404 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5405 

5406 def filter_by(self, **kwargs: Any) -> Self: 

5407 r"""apply the given filtering criterion as a WHERE clause 

5408 to this select. 

5409 

5410 """ 

5411 from_entity = self._filter_by_zero() 

5412 

5413 clauses = [ 

5414 _entity_namespace_key(from_entity, key) == value 

5415 for key, value in kwargs.items() 

5416 ] 

5417 return self.filter(*clauses) 

5418 

5419 @property 

5420 def column_descriptions(self) -> Any: 

5421 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5422 referring to the columns which are SELECTed by this statement. 

5423 

5424 This attribute is generally useful when using the ORM, as an 

5425 extended structure which includes information about mapped 

5426 entities is returned. The section :ref:`queryguide_inspection` 

5427 contains more background. 

5428 

5429 For a Core-only statement, the structure returned by this accessor 

5430 is derived from the same objects that are returned by the 

5431 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5432 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5433 which indicate the column expressions to be selected:: 

5434 

5435 >>> stmt = select(user_table) 

5436 >>> stmt.column_descriptions 

5437 [ 

5438 { 

5439 'name': 'id', 

5440 'type': Integer(), 

5441 'expr': Column('id', Integer(), ...)}, 

5442 { 

5443 'name': 'name', 

5444 'type': String(length=30), 

5445 'expr': Column('name', String(length=30), ...)} 

5446 ] 

5447 

5448 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5449 attribute returns a structure for a Core-only set of entities, 

5450 not just ORM-only entities. 

5451 

5452 .. seealso:: 

5453 

5454 :attr:`.UpdateBase.entity_description` - entity information for 

5455 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5456 

5457 :ref:`queryguide_inspection` - ORM background 

5458 

5459 """ 

5460 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5461 return meth(self) 

5462 

5463 def from_statement( 

5464 self, statement: roles.ReturnsRowsRole 

5465 ) -> ExecutableReturnsRows: 

5466 """Apply the columns which this :class:`.Select` would select 

5467 onto another statement. 

5468 

5469 This operation is :term:`plugin-specific` and will raise a not 

5470 supported exception if this :class:`_sql.Select` does not select from 

5471 plugin-enabled entities. 

5472 

5473 

5474 The statement is typically either a :func:`_expression.text` or 

5475 :func:`_expression.select` construct, and should return the set of 

5476 columns appropriate to the entities represented by this 

5477 :class:`.Select`. 

5478 

5479 .. seealso:: 

5480 

5481 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5482 ORM Querying Guide 

5483 

5484 """ 

5485 meth = SelectState.get_plugin_class(self).from_statement 

5486 return meth(self, statement) 

5487 

5488 @_generative 

5489 def join( 

5490 self, 

5491 target: _JoinTargetArgument, 

5492 onclause: Optional[_OnClauseArgument] = None, 

5493 *, 

5494 isouter: bool = False, 

5495 full: bool = False, 

5496 ) -> Self: 

5497 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5498 object's criterion 

5499 and apply generatively, returning the newly resulting 

5500 :class:`_expression.Select`. 

5501 

5502 E.g.:: 

5503 

5504 stmt = select(user_table).join( 

5505 address_table, user_table.c.id == address_table.c.user_id 

5506 ) 

5507 

5508 The above statement generates SQL similar to: 

5509 

5510 .. sourcecode:: sql 

5511 

5512 SELECT user.id, user.name 

5513 FROM user 

5514 JOIN address ON user.id = address.user_id 

5515 

5516 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5517 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5518 source that is within the FROM clause of the existing SELECT, 

5519 and a given target :class:`_sql.FromClause`, and then adds 

5520 this :class:`_sql.Join` to the FROM clause of the newly generated 

5521 SELECT statement. This is completely reworked from the behavior 

5522 in 1.3, which would instead create a subquery of the entire 

5523 :class:`_expression.Select` and then join that subquery to the 

5524 target. 

5525 

5526 This is a **backwards incompatible change** as the previous behavior 

5527 was mostly useless, producing an unnamed subquery rejected by 

5528 most databases in any case. The new behavior is modeled after 

5529 that of the very successful :meth:`_orm.Query.join` method in the 

5530 ORM, in order to support the functionality of :class:`_orm.Query` 

5531 being available by using a :class:`_sql.Select` object with an 

5532 :class:`_orm.Session`. 

5533 

5534 See the notes for this change at :ref:`change_select_join`. 

5535 

5536 

5537 :param target: target table to join towards 

5538 

5539 :param onclause: ON clause of the join. If omitted, an ON clause 

5540 is generated automatically based on the :class:`_schema.ForeignKey` 

5541 linkages between the two tables, if one can be unambiguously 

5542 determined, otherwise an error is raised. 

5543 

5544 :param isouter: if True, generate LEFT OUTER join. Same as 

5545 :meth:`_expression.Select.outerjoin`. 

5546 

5547 :param full: if True, generate FULL OUTER join. 

5548 

5549 .. seealso:: 

5550 

5551 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5552 

5553 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5554 

5555 :meth:`_expression.Select.join_from` 

5556 

5557 :meth:`_expression.Select.outerjoin` 

5558 

5559 """ # noqa: E501 

5560 join_target = coercions.expect( 

5561 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5562 ) 

5563 if onclause is not None: 

5564 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5565 else: 

5566 onclause_element = None 

5567 

5568 self._setup_joins += ( 

5569 ( 

5570 join_target, 

5571 onclause_element, 

5572 None, 

5573 {"isouter": isouter, "full": full}, 

5574 ), 

5575 ) 

5576 return self 

5577 

5578 def outerjoin_from( 

5579 self, 

5580 from_: _FromClauseArgument, 

5581 target: _JoinTargetArgument, 

5582 onclause: Optional[_OnClauseArgument] = None, 

5583 *, 

5584 full: bool = False, 

5585 ) -> Self: 

5586 r"""Create a SQL LEFT OUTER JOIN against this 

5587 :class:`_expression.Select` object's criterion and apply generatively, 

5588 returning the newly resulting :class:`_expression.Select`. 

5589 

5590 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5591 

5592 """ 

5593 return self.join_from( 

5594 from_, target, onclause=onclause, isouter=True, full=full 

5595 ) 

5596 

5597 @_generative 

5598 def join_from( 

5599 self, 

5600 from_: _FromClauseArgument, 

5601 target: _JoinTargetArgument, 

5602 onclause: Optional[_OnClauseArgument] = None, 

5603 *, 

5604 isouter: bool = False, 

5605 full: bool = False, 

5606 ) -> Self: 

5607 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5608 object's criterion 

5609 and apply generatively, returning the newly resulting 

5610 :class:`_expression.Select`. 

5611 

5612 E.g.:: 

5613 

5614 stmt = select(user_table, address_table).join_from( 

5615 user_table, address_table, user_table.c.id == address_table.c.user_id 

5616 ) 

5617 

5618 The above statement generates SQL similar to: 

5619 

5620 .. sourcecode:: sql 

5621 

5622 SELECT user.id, user.name, address.id, address.email, address.user_id 

5623 FROM user JOIN address ON user.id = address.user_id 

5624 

5625 .. versionadded:: 1.4 

5626 

5627 :param from\_: the left side of the join, will be rendered in the 

5628 FROM clause and is roughly equivalent to using the 

5629 :meth:`.Select.select_from` method. 

5630 

5631 :param target: target table to join towards 

5632 

5633 :param onclause: ON clause of the join. 

5634 

5635 :param isouter: if True, generate LEFT OUTER join. Same as 

5636 :meth:`_expression.Select.outerjoin`. 

5637 

5638 :param full: if True, generate FULL OUTER join. 

5639 

5640 .. seealso:: 

5641 

5642 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5643 

5644 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5645 

5646 :meth:`_expression.Select.join` 

5647 

5648 """ # noqa: E501 

5649 

5650 # note the order of parsing from vs. target is important here, as we 

5651 # are also deriving the source of the plugin (i.e. the subject mapper 

5652 # in an ORM query) which should favor the "from_" over the "target" 

5653 

5654 from_ = coercions.expect( 

5655 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5656 ) 

5657 join_target = coercions.expect( 

5658 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5659 ) 

5660 if onclause is not None: 

5661 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5662 else: 

5663 onclause_element = None 

5664 

5665 self._setup_joins += ( 

5666 ( 

5667 join_target, 

5668 onclause_element, 

5669 from_, 

5670 {"isouter": isouter, "full": full}, 

5671 ), 

5672 ) 

5673 return self 

5674 

5675 def outerjoin( 

5676 self, 

5677 target: _JoinTargetArgument, 

5678 onclause: Optional[_OnClauseArgument] = None, 

5679 *, 

5680 full: bool = False, 

5681 ) -> Self: 

5682 """Create a left outer join. 

5683 

5684 Parameters are the same as that of :meth:`_expression.Select.join`. 

5685 

5686 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5687 creates a :class:`_sql.Join` object between a 

5688 :class:`_sql.FromClause` source that is within the FROM clause of 

5689 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5690 and then adds this :class:`_sql.Join` to the FROM clause of the 

5691 newly generated SELECT statement. This is completely reworked 

5692 from the behavior in 1.3, which would instead create a subquery of 

5693 the entire 

5694 :class:`_expression.Select` and then join that subquery to the 

5695 target. 

5696 

5697 This is a **backwards incompatible change** as the previous behavior 

5698 was mostly useless, producing an unnamed subquery rejected by 

5699 most databases in any case. The new behavior is modeled after 

5700 that of the very successful :meth:`_orm.Query.join` method in the 

5701 ORM, in order to support the functionality of :class:`_orm.Query` 

5702 being available by using a :class:`_sql.Select` object with an 

5703 :class:`_orm.Session`. 

5704 

5705 See the notes for this change at :ref:`change_select_join`. 

5706 

5707 .. seealso:: 

5708 

5709 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5710 

5711 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5712 

5713 :meth:`_expression.Select.join` 

5714 

5715 """ 

5716 return self.join(target, onclause=onclause, isouter=True, full=full) 

5717 

5718 def get_final_froms(self) -> Sequence[FromClause]: 

5719 """Compute the final displayed list of :class:`_expression.FromClause` 

5720 elements. 

5721 

5722 This method will run through the full computation required to 

5723 determine what FROM elements will be displayed in the resulting 

5724 SELECT statement, including shadowing individual tables with 

5725 JOIN objects, as well as full computation for ORM use cases including 

5726 eager loading clauses. 

5727 

5728 For ORM use, this accessor returns the **post compilation** 

5729 list of FROM objects; this collection will include elements such as 

5730 eagerly loaded tables and joins. The objects will **not** be 

5731 ORM enabled and not work as a replacement for the 

5732 :meth:`_sql.Select.select_froms` collection; additionally, the 

5733 method is not well performing for an ORM enabled statement as it 

5734 will incur the full ORM construction process. 

5735 

5736 To retrieve the FROM list that's implied by the "columns" collection 

5737 passed to the :class:`_sql.Select` originally, use the 

5738 :attr:`_sql.Select.columns_clause_froms` accessor. 

5739 

5740 To select from an alternative set of columns while maintaining the 

5741 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5742 pass the 

5743 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5744 parameter. 

5745 

5746 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5747 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5748 which is deprecated. 

5749 

5750 .. seealso:: 

5751 

5752 :attr:`_sql.Select.columns_clause_froms` 

5753 

5754 """ 

5755 compiler = self._default_compiler() 

5756 

5757 return self._compile_state_factory(self, compiler)._get_display_froms() 

5758 

5759 @property 

5760 @util.deprecated( 

5761 "1.4.23", 

5762 "The :attr:`_expression.Select.froms` attribute is moved to " 

5763 "the :meth:`_expression.Select.get_final_froms` method.", 

5764 ) 

5765 def froms(self) -> Sequence[FromClause]: 

5766 """Return the displayed list of :class:`_expression.FromClause` 

5767 elements. 

5768 

5769 

5770 """ 

5771 return self.get_final_froms() 

5772 

5773 @property 

5774 def columns_clause_froms(self) -> List[FromClause]: 

5775 """Return the set of :class:`_expression.FromClause` objects implied 

5776 by the columns clause of this SELECT statement. 

5777 

5778 .. versionadded:: 1.4.23 

5779 

5780 .. seealso:: 

5781 

5782 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5783 statement into account 

5784 

5785 :meth:`_sql.Select.with_only_columns` - makes use of this 

5786 collection to set up a new FROM list 

5787 

5788 """ 

5789 

5790 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5791 self 

5792 ) 

5793 

5794 @property 

5795 def inner_columns(self) -> _SelectIterable: 

5796 """An iterator of all :class:`_expression.ColumnElement` 

5797 expressions which would 

5798 be rendered into the columns clause of the resulting SELECT statement. 

5799 

5800 This method is legacy as of 1.4 and is superseded by the 

5801 :attr:`_expression.Select.exported_columns` collection. 

5802 

5803 """ 

5804 

5805 return iter(self._all_selected_columns) 

5806 

5807 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5808 if fromclause is not None and self in fromclause._cloned_set: 

5809 return True 

5810 

5811 for f in self._iterate_from_elements(): 

5812 if f.is_derived_from(fromclause): 

5813 return True 

5814 return False 

5815 

5816 def _copy_internals( 

5817 self, clone: _CloneCallableType = _clone, **kw: Any 

5818 ) -> None: 

5819 # Select() object has been cloned and probably adapted by the 

5820 # given clone function. Apply the cloning function to internal 

5821 # objects 

5822 

5823 # 1. keep a dictionary of the froms we've cloned, and what 

5824 # they've become. This allows us to ensure the same cloned from 

5825 # is used when other items such as columns are "cloned" 

5826 

5827 all_the_froms = set( 

5828 itertools.chain( 

5829 _from_objects(*self._raw_columns), 

5830 _from_objects(*self._where_criteria), 

5831 _from_objects(*[elem[0] for elem in self._setup_joins]), 

5832 ) 

5833 ) 

5834 

5835 # do a clone for the froms we've gathered. what is important here 

5836 # is if any of the things we are selecting from, like tables, 

5837 # were converted into Join objects. if so, these need to be 

5838 # added to _from_obj explicitly, because otherwise they won't be 

5839 # part of the new state, as they don't associate themselves with 

5840 # their columns. 

5841 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

5842 

5843 # 2. copy FROM collections, adding in joins that we've created. 

5844 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

5845 add_froms = ( 

5846 {f for f in new_froms.values() if isinstance(f, Join)} 

5847 .difference(all_the_froms) 

5848 .difference(existing_from_obj) 

5849 ) 

5850 

5851 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

5852 

5853 # 3. clone everything else, making sure we use columns 

5854 # corresponding to the froms we just made. 

5855 def replace( 

5856 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

5857 **kw: Any, 

5858 ) -> Optional[KeyedColumnElement[Any]]: 

5859 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

5860 newelem = new_froms[obj.table].corresponding_column(obj) 

5861 return newelem 

5862 return None 

5863 

5864 kw["replace"] = replace 

5865 

5866 # copy everything else. for table-ish things like correlate, 

5867 # correlate_except, setup_joins, these clone normally. For 

5868 # column-expression oriented things like raw_columns, where_criteria, 

5869 # order by, we get this from the new froms. 

5870 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

5871 

5872 self._reset_memoizations() 

5873 

5874 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

5875 return itertools.chain( 

5876 super().get_children( 

5877 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

5878 **kw, 

5879 ), 

5880 self._iterate_from_elements(), 

5881 ) 

5882 

5883 @_generative 

5884 def add_columns( 

5885 self, *entities: _ColumnsClauseArgument[Any] 

5886 ) -> Select[Any]: 

5887 r"""Return a new :func:`_expression.select` construct with 

5888 the given entities appended to its columns clause. 

5889 

5890 E.g.:: 

5891 

5892 my_select = my_select.add_columns(table.c.new_column) 

5893 

5894 The original expressions in the columns clause remain in place. 

5895 To replace the original expressions with new ones, see the method 

5896 :meth:`_expression.Select.with_only_columns`. 

5897 

5898 :param \*entities: column, table, or other entity expressions to be 

5899 added to the columns clause 

5900 

5901 .. seealso:: 

5902 

5903 :meth:`_expression.Select.with_only_columns` - replaces existing 

5904 expressions rather than appending. 

5905 

5906 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

5907 example 

5908 

5909 """ 

5910 self._reset_memoizations() 

5911 

5912 self._raw_columns = self._raw_columns + [ 

5913 coercions.expect( 

5914 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

5915 ) 

5916 for column in entities 

5917 ] 

5918 return self 

5919 

5920 def _set_entities( 

5921 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

5922 ) -> None: 

5923 self._raw_columns = [ 

5924 coercions.expect( 

5925 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5926 ) 

5927 for ent in util.to_list(entities) 

5928 ] 

5929 

5930 @util.deprecated( 

5931 "1.4", 

5932 "The :meth:`_expression.Select.column` method is deprecated and will " 

5933 "be removed in a future release. Please use " 

5934 ":meth:`_expression.Select.add_columns`", 

5935 ) 

5936 def column(self, column: _ColumnsClauseArgument[Any]) -> Select[Any]: 

5937 """Return a new :func:`_expression.select` construct with 

5938 the given column expression added to its columns clause. 

5939 

5940 E.g.:: 

5941 

5942 my_select = my_select.column(table.c.new_column) 

5943 

5944 See the documentation for 

5945 :meth:`_expression.Select.with_only_columns` 

5946 for guidelines on adding /replacing the columns of a 

5947 :class:`_expression.Select` object. 

5948 

5949 """ 

5950 return self.add_columns(column) 

5951 

5952 @util.preload_module("sqlalchemy.sql.util") 

5953 def reduce_columns(self, only_synonyms: bool = True) -> Select[Any]: 

5954 """Return a new :func:`_expression.select` construct with redundantly 

5955 named, equivalently-valued columns removed from the columns clause. 

5956 

5957 "Redundant" here means two columns where one refers to the 

5958 other either based on foreign key, or via a simple equality 

5959 comparison in the WHERE clause of the statement. The primary purpose 

5960 of this method is to automatically construct a select statement 

5961 with all uniquely-named columns, without the need to use 

5962 table-qualified labels as 

5963 :meth:`_expression.Select.set_label_style` 

5964 does. 

5965 

5966 When columns are omitted based on foreign key, the referred-to 

5967 column is the one that's kept. When columns are omitted based on 

5968 WHERE equivalence, the first column in the columns clause is the 

5969 one that's kept. 

5970 

5971 :param only_synonyms: when True, limit the removal of columns 

5972 to those which have the same name as the equivalent. Otherwise, 

5973 all columns that are equivalent to another are removed. 

5974 

5975 """ 

5976 woc: Select[Any] 

5977 woc = self.with_only_columns( 

5978 *util.preloaded.sql_util.reduce_columns( 

5979 self._all_selected_columns, 

5980 only_synonyms=only_synonyms, 

5981 *(self._where_criteria + self._from_obj), 

5982 ) 

5983 ) 

5984 return woc 

5985 

5986 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

5987 

5988 # code within this block is **programmatically, 

5989 # statically generated** by tools/generate_tuple_map_overloads.py 

5990 

5991 @overload 

5992 def with_only_columns( 

5993 self, __ent0: _TCCA[_T0], *, maintain_column_froms: bool = ... 

5994 ) -> Select[Tuple[_T0]]: ... 

5995 

5996 @overload 

5997 def with_only_columns( 

5998 self, 

5999 __ent0: _TCCA[_T0], 

6000 __ent1: _TCCA[_T1], 

6001 *, 

6002 maintain_column_froms: bool = ..., 

6003 ) -> Select[Tuple[_T0, _T1]]: ... 

6004 

6005 @overload 

6006 def with_only_columns( 

6007 self, 

6008 __ent0: _TCCA[_T0], 

6009 __ent1: _TCCA[_T1], 

6010 __ent2: _TCCA[_T2], 

6011 *, 

6012 maintain_column_froms: bool = ..., 

6013 ) -> Select[Tuple[_T0, _T1, _T2]]: ... 

6014 

6015 @overload 

6016 def with_only_columns( 

6017 self, 

6018 __ent0: _TCCA[_T0], 

6019 __ent1: _TCCA[_T1], 

6020 __ent2: _TCCA[_T2], 

6021 __ent3: _TCCA[_T3], 

6022 *, 

6023 maintain_column_froms: bool = ..., 

6024 ) -> Select[Tuple[_T0, _T1, _T2, _T3]]: ... 

6025 

6026 @overload 

6027 def with_only_columns( 

6028 self, 

6029 __ent0: _TCCA[_T0], 

6030 __ent1: _TCCA[_T1], 

6031 __ent2: _TCCA[_T2], 

6032 __ent3: _TCCA[_T3], 

6033 __ent4: _TCCA[_T4], 

6034 *, 

6035 maintain_column_froms: bool = ..., 

6036 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4]]: ... 

6037 

6038 @overload 

6039 def with_only_columns( 

6040 self, 

6041 __ent0: _TCCA[_T0], 

6042 __ent1: _TCCA[_T1], 

6043 __ent2: _TCCA[_T2], 

6044 __ent3: _TCCA[_T3], 

6045 __ent4: _TCCA[_T4], 

6046 __ent5: _TCCA[_T5], 

6047 *, 

6048 maintain_column_froms: bool = ..., 

6049 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ... 

6050 

6051 @overload 

6052 def with_only_columns( 

6053 self, 

6054 __ent0: _TCCA[_T0], 

6055 __ent1: _TCCA[_T1], 

6056 __ent2: _TCCA[_T2], 

6057 __ent3: _TCCA[_T3], 

6058 __ent4: _TCCA[_T4], 

6059 __ent5: _TCCA[_T5], 

6060 __ent6: _TCCA[_T6], 

6061 *, 

6062 maintain_column_froms: bool = ..., 

6063 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ... 

6064 

6065 @overload 

6066 def with_only_columns( 

6067 self, 

6068 __ent0: _TCCA[_T0], 

6069 __ent1: _TCCA[_T1], 

6070 __ent2: _TCCA[_T2], 

6071 __ent3: _TCCA[_T3], 

6072 __ent4: _TCCA[_T4], 

6073 __ent5: _TCCA[_T5], 

6074 __ent6: _TCCA[_T6], 

6075 __ent7: _TCCA[_T7], 

6076 *, 

6077 maintain_column_froms: bool = ..., 

6078 ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ... 

6079 

6080 # END OVERLOADED FUNCTIONS self.with_only_columns 

6081 

6082 @overload 

6083 def with_only_columns( 

6084 self, 

6085 *entities: _ColumnsClauseArgument[Any], 

6086 maintain_column_froms: bool = False, 

6087 **__kw: Any, 

6088 ) -> Select[Any]: ... 

6089 

6090 @_generative 

6091 def with_only_columns( 

6092 self, 

6093 *entities: _ColumnsClauseArgument[Any], 

6094 maintain_column_froms: bool = False, 

6095 **__kw: Any, 

6096 ) -> Select[Any]: 

6097 r"""Return a new :func:`_expression.select` construct with its columns 

6098 clause replaced with the given entities. 

6099 

6100 By default, this method is exactly equivalent to as if the original 

6101 :func:`_expression.select` had been called with the given entities. 

6102 E.g. a statement:: 

6103 

6104 s = select(table1.c.a, table1.c.b) 

6105 s = s.with_only_columns(table1.c.b) 

6106 

6107 should be exactly equivalent to:: 

6108 

6109 s = select(table1.c.b) 

6110 

6111 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6112 will also dynamically alter the FROM clause of the 

6113 statement if it is not explicitly stated. 

6114 To maintain the existing set of FROMs including those implied by the 

6115 current columns clause, add the 

6116 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6117 parameter:: 

6118 

6119 s = select(table1.c.a, table2.c.b) 

6120 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6121 

6122 The above parameter performs a transfer of the effective FROMs 

6123 in the columns collection to the :meth:`_sql.Select.select_from` 

6124 method, as though the following were invoked:: 

6125 

6126 s = select(table1.c.a, table2.c.b) 

6127 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6128 

6129 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6130 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6131 collection and performs an operation equivalent to the following:: 

6132 

6133 s = select(table1.c.a, table2.c.b) 

6134 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6135 

6136 :param \*entities: column expressions to be used. 

6137 

6138 :param maintain_column_froms: boolean parameter that will ensure the 

6139 FROM list implied from the current columns clause will be transferred 

6140 to the :meth:`_sql.Select.select_from` method first. 

6141 

6142 .. versionadded:: 1.4.23 

6143 

6144 """ # noqa: E501 

6145 

6146 if __kw: 

6147 raise _no_kw() 

6148 

6149 # memoizations should be cleared here as of 

6150 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6151 # is the case for now. 

6152 self._assert_no_memoizations() 

6153 

6154 if maintain_column_froms: 

6155 self.select_from.non_generative( # type: ignore 

6156 self, *self.columns_clause_froms 

6157 ) 

6158 

6159 # then memoize the FROMs etc. 

6160 _MemoizedSelectEntities._generate_for_statement(self) 

6161 

6162 self._raw_columns = [ 

6163 coercions.expect(roles.ColumnsClauseRole, c) 

6164 for c in coercions._expression_collection_was_a_list( 

6165 "entities", "Select.with_only_columns", entities 

6166 ) 

6167 ] 

6168 return self 

6169 

6170 @property 

6171 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6172 """Return the completed WHERE clause for this 

6173 :class:`_expression.Select` statement. 

6174 

6175 This assembles the current collection of WHERE criteria 

6176 into a single :class:`_expression.BooleanClauseList` construct. 

6177 

6178 

6179 .. versionadded:: 1.4 

6180 

6181 """ 

6182 

6183 return BooleanClauseList._construct_for_whereclause( 

6184 self._where_criteria 

6185 ) 

6186 

6187 _whereclause = whereclause 

6188 

6189 @_generative 

6190 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6191 """Return a new :func:`_expression.select` construct with 

6192 the given expression added to 

6193 its WHERE clause, joined to the existing clause via AND, if any. 

6194 

6195 """ 

6196 

6197 assert isinstance(self._where_criteria, tuple) 

6198 

6199 for criterion in whereclause: 

6200 where_criteria: ColumnElement[Any] = coercions.expect( 

6201 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6202 ) 

6203 self._where_criteria += (where_criteria,) 

6204 return self 

6205 

6206 @_generative 

6207 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6208 """Return a new :func:`_expression.select` construct with 

6209 the given expression added to 

6210 its HAVING clause, joined to the existing clause via AND, if any. 

6211 

6212 """ 

6213 

6214 for criterion in having: 

6215 having_criteria = coercions.expect( 

6216 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6217 ) 

6218 self._having_criteria += (having_criteria,) 

6219 return self 

6220 

6221 @_generative 

6222 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6223 r"""Return a new :func:`_expression.select` construct which 

6224 will apply DISTINCT to the SELECT statement overall. 

6225 

6226 E.g.:: 

6227 

6228 from sqlalchemy import select 

6229 

6230 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6231 

6232 The above would produce an statement resembling: 

6233 

6234 .. sourcecode:: sql 

6235 

6236 SELECT DISTINCT user.id, user.name FROM user 

6237 

6238 The method also accepts an ``*expr`` parameter which produces the 

6239 PostgreSQL dialect-specific ``DISTINCT ON`` expression. Using this 

6240 parameter on other backends which don't support this syntax will 

6241 raise an error. 

6242 

6243 :param \*expr: optional column expressions. When present, 

6244 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6245 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6246 will be raised on other backends. 

6247 

6248 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6249 and will raise :class:`_exc.CompileError` in a future version. 

6250 

6251 """ 

6252 if expr: 

6253 self._distinct = True 

6254 self._distinct_on = self._distinct_on + tuple( 

6255 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6256 for e in expr 

6257 ) 

6258 else: 

6259 self._distinct = True 

6260 return self 

6261 

6262 @_generative 

6263 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6264 r"""Return a new :func:`_expression.select` construct with the 

6265 given FROM expression(s) 

6266 merged into its list of FROM objects. 

6267 

6268 E.g.:: 

6269 

6270 table1 = table("t1", column("a")) 

6271 table2 = table("t2", column("b")) 

6272 s = select(table1.c.a).select_from( 

6273 table1.join(table2, table1.c.a == table2.c.b) 

6274 ) 

6275 

6276 The "from" list is a unique set on the identity of each element, 

6277 so adding an already present :class:`_schema.Table` 

6278 or other selectable 

6279 will have no effect. Passing a :class:`_expression.Join` that refers 

6280 to an already present :class:`_schema.Table` 

6281 or other selectable will have 

6282 the effect of concealing the presence of that selectable as 

6283 an individual element in the rendered FROM list, instead 

6284 rendering it into a JOIN clause. 

6285 

6286 While the typical purpose of :meth:`_expression.Select.select_from` 

6287 is to 

6288 replace the default, derived FROM clause with a join, it can 

6289 also be called with individual table elements, multiple times 

6290 if desired, in the case that the FROM clause cannot be fully 

6291 derived from the columns clause:: 

6292 

6293 select(func.count("*")).select_from(table1) 

6294 

6295 """ 

6296 

6297 self._from_obj += tuple( 

6298 coercions.expect( 

6299 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6300 ) 

6301 for fromclause in froms 

6302 ) 

6303 return self 

6304 

6305 @_generative 

6306 def correlate( 

6307 self, 

6308 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6309 ) -> Self: 

6310 r"""Return a new :class:`_expression.Select` 

6311 which will correlate the given FROM 

6312 clauses to that of an enclosing :class:`_expression.Select`. 

6313 

6314 Calling this method turns off the :class:`_expression.Select` object's 

6315 default behavior of "auto-correlation". Normally, FROM elements 

6316 which appear in a :class:`_expression.Select` 

6317 that encloses this one via 

6318 its :term:`WHERE clause`, ORDER BY, HAVING or 

6319 :term:`columns clause` will be omitted from this 

6320 :class:`_expression.Select` 

6321 object's :term:`FROM clause`. 

6322 Setting an explicit correlation collection using the 

6323 :meth:`_expression.Select.correlate` 

6324 method provides a fixed list of FROM objects 

6325 that can potentially take place in this process. 

6326 

6327 When :meth:`_expression.Select.correlate` 

6328 is used to apply specific FROM clauses 

6329 for correlation, the FROM elements become candidates for 

6330 correlation regardless of how deeply nested this 

6331 :class:`_expression.Select` 

6332 object is, relative to an enclosing :class:`_expression.Select` 

6333 which refers to 

6334 the same FROM object. This is in contrast to the behavior of 

6335 "auto-correlation" which only correlates to an immediate enclosing 

6336 :class:`_expression.Select`. 

6337 Multi-level correlation ensures that the link 

6338 between enclosed and enclosing :class:`_expression.Select` 

6339 is always via 

6340 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6341 correlation to take place. 

6342 

6343 If ``None`` is passed, the :class:`_expression.Select` 

6344 object will correlate 

6345 none of its FROM entries, and all will render unconditionally 

6346 in the local FROM clause. 

6347 

6348 :param \*fromclauses: one or more :class:`.FromClause` or other 

6349 FROM-compatible construct such as an ORM mapped entity to become part 

6350 of the correlate collection; alternatively pass a single value 

6351 ``None`` to remove all existing correlations. 

6352 

6353 .. seealso:: 

6354 

6355 :meth:`_expression.Select.correlate_except` 

6356 

6357 :ref:`tutorial_scalar_subquery` 

6358 

6359 """ 

6360 

6361 # tests failing when we try to change how these 

6362 # arguments are passed 

6363 

6364 self._auto_correlate = False 

6365 if not fromclauses or fromclauses[0] in {None, False}: 

6366 if len(fromclauses) > 1: 

6367 raise exc.ArgumentError( 

6368 "additional FROM objects not accepted when " 

6369 "passing None/False to correlate()" 

6370 ) 

6371 self._correlate = () 

6372 else: 

6373 self._correlate = self._correlate + tuple( 

6374 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6375 ) 

6376 return self 

6377 

6378 @_generative 

6379 def correlate_except( 

6380 self, 

6381 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6382 ) -> Self: 

6383 r"""Return a new :class:`_expression.Select` 

6384 which will omit the given FROM 

6385 clauses from the auto-correlation process. 

6386 

6387 Calling :meth:`_expression.Select.correlate_except` turns off the 

6388 :class:`_expression.Select` object's default behavior of 

6389 "auto-correlation" for the given FROM elements. An element 

6390 specified here will unconditionally appear in the FROM list, while 

6391 all other FROM elements remain subject to normal auto-correlation 

6392 behaviors. 

6393 

6394 If ``None`` is passed, or no arguments are passed, 

6395 the :class:`_expression.Select` object will correlate all of its 

6396 FROM entries. 

6397 

6398 :param \*fromclauses: a list of one or more 

6399 :class:`_expression.FromClause` 

6400 constructs, or other compatible constructs (i.e. ORM-mapped 

6401 classes) to become part of the correlate-exception collection. 

6402 

6403 .. seealso:: 

6404 

6405 :meth:`_expression.Select.correlate` 

6406 

6407 :ref:`tutorial_scalar_subquery` 

6408 

6409 """ 

6410 

6411 self._auto_correlate = False 

6412 if not fromclauses or fromclauses[0] in {None, False}: 

6413 if len(fromclauses) > 1: 

6414 raise exc.ArgumentError( 

6415 "additional FROM objects not accepted when " 

6416 "passing None/False to correlate_except()" 

6417 ) 

6418 self._correlate_except = () 

6419 else: 

6420 self._correlate_except = (self._correlate_except or ()) + tuple( 

6421 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6422 ) 

6423 

6424 return self 

6425 

6426 @HasMemoized_ro_memoized_attribute 

6427 def selected_columns( 

6428 self, 

6429 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6430 """A :class:`_expression.ColumnCollection` 

6431 representing the columns that 

6432 this SELECT statement or similar construct returns in its result set, 

6433 not including :class:`_sql.TextClause` constructs. 

6434 

6435 This collection differs from the :attr:`_expression.FromClause.columns` 

6436 collection of a :class:`_expression.FromClause` in that the columns 

6437 within this collection cannot be directly nested inside another SELECT 

6438 statement; a subquery must be applied first which provides for the 

6439 necessary parenthesization required by SQL. 

6440 

6441 For a :func:`_expression.select` construct, the collection here is 

6442 exactly what would be rendered inside the "SELECT" statement, and the 

6443 :class:`_expression.ColumnElement` objects are directly present as they 

6444 were given, e.g.:: 

6445 

6446 col1 = column("q", Integer) 

6447 col2 = column("p", Integer) 

6448 stmt = select(col1, col2) 

6449 

6450 Above, ``stmt.selected_columns`` would be a collection that contains 

6451 the ``col1`` and ``col2`` objects directly. For a statement that is 

6452 against a :class:`_schema.Table` or other 

6453 :class:`_expression.FromClause`, the collection will use the 

6454 :class:`_expression.ColumnElement` objects that are in the 

6455 :attr:`_expression.FromClause.c` collection of the from element. 

6456 

6457 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6458 to allow the existing columns to be referenced when adding additional 

6459 criteria, e.g.:: 

6460 

6461 def filter_on_id(my_select, id): 

6462 return my_select.where(my_select.selected_columns["id"] == id) 

6463 

6464 

6465 stmt = select(MyModel) 

6466 

6467 # adds "WHERE id=:param" to the statement 

6468 stmt = filter_on_id(stmt, 42) 

6469 

6470 .. note:: 

6471 

6472 The :attr:`_sql.Select.selected_columns` collection does not 

6473 include expressions established in the columns clause using the 

6474 :func:`_sql.text` construct; these are silently omitted from the 

6475 collection. To use plain textual column expressions inside of a 

6476 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6477 construct. 

6478 

6479 

6480 .. versionadded:: 1.4 

6481 

6482 """ 

6483 

6484 # compare to SelectState._generate_columns_plus_names, which 

6485 # generates the actual names used in the SELECT string. that 

6486 # method is more complex because it also renders columns that are 

6487 # fully ambiguous, e.g. same column more than once. 

6488 conv = cast( 

6489 "Callable[[Any], str]", 

6490 SelectState._column_naming_convention(self._label_style), 

6491 ) 

6492 

6493 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6494 [ 

6495 (conv(c), c) 

6496 for c in self._all_selected_columns 

6497 if is_column_element(c) 

6498 ] 

6499 ) 

6500 return cc.as_readonly() 

6501 

6502 @HasMemoized_ro_memoized_attribute 

6503 def _all_selected_columns(self) -> _SelectIterable: 

6504 meth = SelectState.get_plugin_class(self).all_selected_columns 

6505 return list(meth(self)) 

6506 

6507 def _ensure_disambiguated_names(self) -> Select[Any]: 

6508 if self._label_style is LABEL_STYLE_NONE: 

6509 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6510 return self 

6511 

6512 def _generate_fromclause_column_proxies( 

6513 self, 

6514 subquery: FromClause, 

6515 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

6516 primary_key: ColumnSet, 

6517 foreign_keys: Set[KeyedColumnElement[Any]], 

6518 *, 

6519 proxy_compound_columns: Optional[ 

6520 Iterable[Sequence[ColumnElement[Any]]] 

6521 ] = None, 

6522 ) -> None: 

6523 """Generate column proxies to place in the exported ``.c`` 

6524 collection of a subquery.""" 

6525 

6526 if proxy_compound_columns: 

6527 extra_col_iterator = proxy_compound_columns 

6528 prox = [ 

6529 c._make_proxy( 

6530 subquery, 

6531 key=proxy_key, 

6532 name=required_label_name, 

6533 name_is_truncatable=True, 

6534 compound_select_cols=extra_cols, 

6535 primary_key=primary_key, 

6536 foreign_keys=foreign_keys, 

6537 ) 

6538 for ( 

6539 ( 

6540 required_label_name, 

6541 proxy_key, 

6542 fallback_label_name, 

6543 c, 

6544 repeated, 

6545 ), 

6546 extra_cols, 

6547 ) in ( 

6548 zip( 

6549 self._generate_columns_plus_names(False), 

6550 extra_col_iterator, 

6551 ) 

6552 ) 

6553 if is_column_element(c) 

6554 ] 

6555 else: 

6556 prox = [ 

6557 c._make_proxy( 

6558 subquery, 

6559 key=proxy_key, 

6560 name=required_label_name, 

6561 name_is_truncatable=True, 

6562 primary_key=primary_key, 

6563 foreign_keys=foreign_keys, 

6564 ) 

6565 for ( 

6566 required_label_name, 

6567 proxy_key, 

6568 fallback_label_name, 

6569 c, 

6570 repeated, 

6571 ) in (self._generate_columns_plus_names(False)) 

6572 if is_column_element(c) 

6573 ] 

6574 

6575 columns._populate_separate_keys(prox) 

6576 

6577 def _needs_parens_for_grouping(self) -> bool: 

6578 return self._has_row_limiting_clause or bool( 

6579 self._order_by_clause.clauses 

6580 ) 

6581 

6582 def self_group( 

6583 self, against: Optional[OperatorType] = None 

6584 ) -> Union[SelectStatementGrouping[Self], Self]: 

6585 """Return a 'grouping' construct as per the 

6586 :class:`_expression.ClauseElement` specification. 

6587 

6588 This produces an element that can be embedded in an expression. Note 

6589 that this method is called automatically as needed when constructing 

6590 expressions and should not require explicit use. 

6591 

6592 """ 

6593 if ( 

6594 isinstance(against, CompoundSelect) 

6595 and not self._needs_parens_for_grouping() 

6596 ): 

6597 return self 

6598 else: 

6599 return SelectStatementGrouping(self) 

6600 

6601 def union( 

6602 self, *other: _SelectStatementForCompoundArgument[_TP] 

6603 ) -> CompoundSelect[_TP]: 

6604 r"""Return a SQL ``UNION`` of this select() construct against 

6605 the given selectables provided as positional arguments. 

6606 

6607 :param \*other: one or more elements with which to create a 

6608 UNION. 

6609 

6610 .. versionchanged:: 1.4.28 

6611 

6612 multiple elements are now accepted. 

6613 

6614 :param \**kwargs: keyword arguments are forwarded to the constructor 

6615 for the newly created :class:`_sql.CompoundSelect` object. 

6616 

6617 """ 

6618 return CompoundSelect._create_union(self, *other) 

6619 

6620 def union_all( 

6621 self, *other: _SelectStatementForCompoundArgument[_TP] 

6622 ) -> CompoundSelect[_TP]: 

6623 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6624 the given selectables provided as positional arguments. 

6625 

6626 :param \*other: one or more elements with which to create a 

6627 UNION. 

6628 

6629 .. versionchanged:: 1.4.28 

6630 

6631 multiple elements are now accepted. 

6632 

6633 :param \**kwargs: keyword arguments are forwarded to the constructor 

6634 for the newly created :class:`_sql.CompoundSelect` object. 

6635 

6636 """ 

6637 return CompoundSelect._create_union_all(self, *other) 

6638 

6639 def except_( 

6640 self, *other: _SelectStatementForCompoundArgument[_TP] 

6641 ) -> CompoundSelect[_TP]: 

6642 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6643 the given selectable provided as positional arguments. 

6644 

6645 :param \*other: one or more elements with which to create a 

6646 UNION. 

6647 

6648 .. versionchanged:: 1.4.28 

6649 

6650 multiple elements are now accepted. 

6651 

6652 """ 

6653 return CompoundSelect._create_except(self, *other) 

6654 

6655 def except_all( 

6656 self, *other: _SelectStatementForCompoundArgument[_TP] 

6657 ) -> CompoundSelect[_TP]: 

6658 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6659 the given selectables provided as positional arguments. 

6660 

6661 :param \*other: one or more elements with which to create a 

6662 UNION. 

6663 

6664 .. versionchanged:: 1.4.28 

6665 

6666 multiple elements are now accepted. 

6667 

6668 """ 

6669 return CompoundSelect._create_except_all(self, *other) 

6670 

6671 def intersect( 

6672 self, *other: _SelectStatementForCompoundArgument[_TP] 

6673 ) -> CompoundSelect[_TP]: 

6674 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6675 the given selectables provided as positional arguments. 

6676 

6677 :param \*other: one or more elements with which to create a 

6678 UNION. 

6679 

6680 .. versionchanged:: 1.4.28 

6681 

6682 multiple elements are now accepted. 

6683 

6684 :param \**kwargs: keyword arguments are forwarded to the constructor 

6685 for the newly created :class:`_sql.CompoundSelect` object. 

6686 

6687 """ 

6688 return CompoundSelect._create_intersect(self, *other) 

6689 

6690 def intersect_all( 

6691 self, *other: _SelectStatementForCompoundArgument[_TP] 

6692 ) -> CompoundSelect[_TP]: 

6693 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6694 against the given selectables provided as positional arguments. 

6695 

6696 :param \*other: one or more elements with which to create a 

6697 UNION. 

6698 

6699 .. versionchanged:: 1.4.28 

6700 

6701 multiple elements are now accepted. 

6702 

6703 :param \**kwargs: keyword arguments are forwarded to the constructor 

6704 for the newly created :class:`_sql.CompoundSelect` object. 

6705 

6706 """ 

6707 return CompoundSelect._create_intersect_all(self, *other) 

6708 

6709 

6710class ScalarSelect( 

6711 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6712): 

6713 """Represent a scalar subquery. 

6714 

6715 

6716 A :class:`_sql.ScalarSelect` is created by invoking the 

6717 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6718 then participates in other SQL expressions as a SQL column expression 

6719 within the :class:`_sql.ColumnElement` hierarchy. 

6720 

6721 .. seealso:: 

6722 

6723 :meth:`_sql.SelectBase.scalar_subquery` 

6724 

6725 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6726 

6727 """ 

6728 

6729 _traverse_internals: _TraverseInternalsType = [ 

6730 ("element", InternalTraversal.dp_clauseelement), 

6731 ("type", InternalTraversal.dp_type), 

6732 ] 

6733 

6734 _from_objects: List[FromClause] = [] 

6735 _is_from_container = True 

6736 if not TYPE_CHECKING: 

6737 _is_implicitly_boolean = False 

6738 inherit_cache = True 

6739 

6740 element: SelectBase 

6741 

6742 def __init__(self, element: SelectBase) -> None: 

6743 self.element = element 

6744 self.type = element._scalar_type() 

6745 self._propagate_attrs = element._propagate_attrs 

6746 

6747 def __getattr__(self, attr: str) -> Any: 

6748 return getattr(self.element, attr) 

6749 

6750 def __getstate__(self) -> Dict[str, Any]: 

6751 return {"element": self.element, "type": self.type} 

6752 

6753 def __setstate__(self, state: Dict[str, Any]) -> None: 

6754 self.element = state["element"] 

6755 self.type = state["type"] 

6756 

6757 @property 

6758 def columns(self) -> NoReturn: 

6759 raise exc.InvalidRequestError( 

6760 "Scalar Select expression has no " 

6761 "columns; use this object directly " 

6762 "within a column-level expression." 

6763 ) 

6764 

6765 c = columns 

6766 

6767 @_generative 

6768 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6769 """Apply a WHERE clause to the SELECT statement referred to 

6770 by this :class:`_expression.ScalarSelect`. 

6771 

6772 """ 

6773 self.element = cast("Select[Any]", self.element).where(crit) 

6774 return self 

6775 

6776 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6777 return self 

6778 

6779 if TYPE_CHECKING: 

6780 

6781 def _ungroup(self) -> Select[Any]: ... 

6782 

6783 @_generative 

6784 def correlate( 

6785 self, 

6786 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6787 ) -> Self: 

6788 r"""Return a new :class:`_expression.ScalarSelect` 

6789 which will correlate the given FROM 

6790 clauses to that of an enclosing :class:`_expression.Select`. 

6791 

6792 This method is mirrored from the :meth:`_sql.Select.correlate` method 

6793 of the underlying :class:`_sql.Select`. The method applies the 

6794 :meth:_sql.Select.correlate` method, then returns a new 

6795 :class:`_sql.ScalarSelect` against that statement. 

6796 

6797 .. versionadded:: 1.4 Previously, the 

6798 :meth:`_sql.ScalarSelect.correlate` 

6799 method was only available from :class:`_sql.Select`. 

6800 

6801 :param \*fromclauses: a list of one or more 

6802 :class:`_expression.FromClause` 

6803 constructs, or other compatible constructs (i.e. ORM-mapped 

6804 classes) to become part of the correlate collection. 

6805 

6806 .. seealso:: 

6807 

6808 :meth:`_expression.ScalarSelect.correlate_except` 

6809 

6810 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6811 

6812 

6813 """ 

6814 self.element = cast("Select[Any]", self.element).correlate( 

6815 *fromclauses 

6816 ) 

6817 return self 

6818 

6819 @_generative 

6820 def correlate_except( 

6821 self, 

6822 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6823 ) -> Self: 

6824 r"""Return a new :class:`_expression.ScalarSelect` 

6825 which will omit the given FROM 

6826 clauses from the auto-correlation process. 

6827 

6828 This method is mirrored from the 

6829 :meth:`_sql.Select.correlate_except` method of the underlying 

6830 :class:`_sql.Select`. The method applies the 

6831 :meth:_sql.Select.correlate_except` method, then returns a new 

6832 :class:`_sql.ScalarSelect` against that statement. 

6833 

6834 .. versionadded:: 1.4 Previously, the 

6835 :meth:`_sql.ScalarSelect.correlate_except` 

6836 method was only available from :class:`_sql.Select`. 

6837 

6838 :param \*fromclauses: a list of one or more 

6839 :class:`_expression.FromClause` 

6840 constructs, or other compatible constructs (i.e. ORM-mapped 

6841 classes) to become part of the correlate-exception collection. 

6842 

6843 .. seealso:: 

6844 

6845 :meth:`_expression.ScalarSelect.correlate` 

6846 

6847 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6848 

6849 

6850 """ 

6851 

6852 self.element = cast("Select[Any]", self.element).correlate_except( 

6853 *fromclauses 

6854 ) 

6855 return self 

6856 

6857 

6858class Exists(UnaryExpression[bool]): 

6859 """Represent an ``EXISTS`` clause. 

6860 

6861 See :func:`_sql.exists` for a description of usage. 

6862 

6863 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

6864 instance by calling :meth:`_sql.SelectBase.exists`. 

6865 

6866 """ 

6867 

6868 inherit_cache = True 

6869 element: Union[SelectStatementGrouping[Select[Any]], ScalarSelect[Any]] 

6870 

6871 def __init__( 

6872 self, 

6873 __argument: Optional[ 

6874 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

6875 ] = None, 

6876 ): 

6877 s: ScalarSelect[Any] 

6878 

6879 # TODO: this seems like we should be using coercions for this 

6880 if __argument is None: 

6881 s = Select(literal_column("*")).scalar_subquery() 

6882 elif isinstance(__argument, SelectBase): 

6883 s = __argument.scalar_subquery() 

6884 s._propagate_attrs = __argument._propagate_attrs 

6885 elif isinstance(__argument, ScalarSelect): 

6886 s = __argument 

6887 else: 

6888 s = Select(__argument).scalar_subquery() 

6889 

6890 UnaryExpression.__init__( 

6891 self, 

6892 s, 

6893 operator=operators.exists, 

6894 type_=type_api.BOOLEANTYPE, 

6895 wraps_column_expression=True, 

6896 ) 

6897 

6898 @util.ro_non_memoized_property 

6899 def _from_objects(self) -> List[FromClause]: 

6900 return [] 

6901 

6902 def _regroup( 

6903 self, fn: Callable[[Select[Any]], Select[Any]] 

6904 ) -> SelectStatementGrouping[Select[Any]]: 

6905 element = self.element._ungroup() 

6906 new_element = fn(element) 

6907 

6908 return_value = new_element.self_group(against=operators.exists) 

6909 assert isinstance(return_value, SelectStatementGrouping) 

6910 return return_value 

6911 

6912 def select(self) -> Select[Tuple[bool]]: 

6913 r"""Return a SELECT of this :class:`_expression.Exists`. 

6914 

6915 e.g.:: 

6916 

6917 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

6918 

6919 This will produce a statement resembling: 

6920 

6921 .. sourcecode:: sql 

6922 

6923 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

6924 

6925 .. seealso:: 

6926 

6927 :func:`_expression.select` - general purpose 

6928 method which allows for arbitrary column lists. 

6929 

6930 """ # noqa 

6931 

6932 return Select(self) 

6933 

6934 def correlate( 

6935 self, 

6936 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6937 ) -> Self: 

6938 """Apply correlation to the subquery noted by this 

6939 :class:`_sql.Exists`. 

6940 

6941 .. seealso:: 

6942 

6943 :meth:`_sql.ScalarSelect.correlate` 

6944 

6945 """ 

6946 e = self._clone() 

6947 e.element = self._regroup( 

6948 lambda element: element.correlate(*fromclauses) 

6949 ) 

6950 return e 

6951 

6952 def correlate_except( 

6953 self, 

6954 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6955 ) -> Self: 

6956 """Apply correlation to the subquery noted by this 

6957 :class:`_sql.Exists`. 

6958 

6959 .. seealso:: 

6960 

6961 :meth:`_sql.ScalarSelect.correlate_except` 

6962 

6963 """ 

6964 

6965 e = self._clone() 

6966 e.element = self._regroup( 

6967 lambda element: element.correlate_except(*fromclauses) 

6968 ) 

6969 return e 

6970 

6971 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6972 """Return a new :class:`_expression.Exists` construct, 

6973 applying the given 

6974 expression to the :meth:`_expression.Select.select_from` 

6975 method of the select 

6976 statement contained. 

6977 

6978 .. note:: it is typically preferable to build a :class:`_sql.Select` 

6979 statement first, including the desired WHERE clause, then use the 

6980 :meth:`_sql.SelectBase.exists` method to produce an 

6981 :class:`_sql.Exists` object at once. 

6982 

6983 """ 

6984 e = self._clone() 

6985 e.element = self._regroup(lambda element: element.select_from(*froms)) 

6986 return e 

6987 

6988 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

6989 """Return a new :func:`_expression.exists` construct with the 

6990 given expression added to 

6991 its WHERE clause, joined to the existing clause via AND, if any. 

6992 

6993 

6994 .. note:: it is typically preferable to build a :class:`_sql.Select` 

6995 statement first, including the desired WHERE clause, then use the 

6996 :meth:`_sql.SelectBase.exists` method to produce an 

6997 :class:`_sql.Exists` object at once. 

6998 

6999 """ 

7000 e = self._clone() 

7001 e.element = self._regroup(lambda element: element.where(*clause)) 

7002 return e 

7003 

7004 

7005class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7006 """Wrap a :class:`_expression.TextClause` construct within a 

7007 :class:`_expression.SelectBase` 

7008 interface. 

7009 

7010 This allows the :class:`_expression.TextClause` object to gain a 

7011 ``.c`` collection 

7012 and other FROM-like capabilities such as 

7013 :meth:`_expression.FromClause.alias`, 

7014 :meth:`_expression.SelectBase.cte`, etc. 

7015 

7016 The :class:`_expression.TextualSelect` construct is produced via the 

7017 :meth:`_expression.TextClause.columns` 

7018 method - see that method for details. 

7019 

7020 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7021 class was renamed 

7022 from ``TextAsFrom``, to more correctly suit its role as a 

7023 SELECT-oriented object and not a FROM clause. 

7024 

7025 .. seealso:: 

7026 

7027 :func:`_expression.text` 

7028 

7029 :meth:`_expression.TextClause.columns` - primary creation interface. 

7030 

7031 """ 

7032 

7033 __visit_name__ = "textual_select" 

7034 

7035 _label_style = LABEL_STYLE_NONE 

7036 

7037 _traverse_internals: _TraverseInternalsType = ( 

7038 [ 

7039 ("element", InternalTraversal.dp_clauseelement), 

7040 ("column_args", InternalTraversal.dp_clauseelement_list), 

7041 ] 

7042 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7043 + HasCTE._has_ctes_traverse_internals 

7044 ) 

7045 

7046 _is_textual = True 

7047 

7048 is_text = True 

7049 is_select = True 

7050 

7051 def __init__( 

7052 self, 

7053 text: TextClause, 

7054 columns: List[_ColumnExpressionArgument[Any]], 

7055 positional: bool = False, 

7056 ) -> None: 

7057 self._init( 

7058 text, 

7059 # convert for ORM attributes->columns, etc 

7060 [ 

7061 coercions.expect(roles.LabeledColumnExprRole, c) 

7062 for c in columns 

7063 ], 

7064 positional, 

7065 ) 

7066 

7067 def _init( 

7068 self, 

7069 text: TextClause, 

7070 columns: List[NamedColumn[Any]], 

7071 positional: bool = False, 

7072 ) -> None: 

7073 self.element = text 

7074 self.column_args = columns 

7075 self.positional = positional 

7076 

7077 @HasMemoized_ro_memoized_attribute 

7078 def selected_columns( 

7079 self, 

7080 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7081 """A :class:`_expression.ColumnCollection` 

7082 representing the columns that 

7083 this SELECT statement or similar construct returns in its result set, 

7084 not including :class:`_sql.TextClause` constructs. 

7085 

7086 This collection differs from the :attr:`_expression.FromClause.columns` 

7087 collection of a :class:`_expression.FromClause` in that the columns 

7088 within this collection cannot be directly nested inside another SELECT 

7089 statement; a subquery must be applied first which provides for the 

7090 necessary parenthesization required by SQL. 

7091 

7092 For a :class:`_expression.TextualSelect` construct, the collection 

7093 contains the :class:`_expression.ColumnElement` objects that were 

7094 passed to the constructor, typically via the 

7095 :meth:`_expression.TextClause.columns` method. 

7096 

7097 

7098 .. versionadded:: 1.4 

7099 

7100 """ 

7101 return ColumnCollection( 

7102 (c.key, c) for c in self.column_args 

7103 ).as_readonly() 

7104 

7105 @util.ro_non_memoized_property 

7106 def _all_selected_columns(self) -> _SelectIterable: 

7107 return self.column_args 

7108 

7109 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7110 return self 

7111 

7112 def _ensure_disambiguated_names(self) -> TextualSelect: 

7113 return self 

7114 

7115 @_generative 

7116 def bindparams( 

7117 self, 

7118 *binds: BindParameter[Any], 

7119 **bind_as_values: Any, 

7120 ) -> Self: 

7121 self.element = self.element.bindparams(*binds, **bind_as_values) 

7122 return self 

7123 

7124 def _generate_fromclause_column_proxies( 

7125 self, 

7126 fromclause: FromClause, 

7127 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

7128 primary_key: ColumnSet, 

7129 foreign_keys: Set[KeyedColumnElement[Any]], 

7130 *, 

7131 proxy_compound_columns: Optional[ 

7132 Iterable[Sequence[ColumnElement[Any]]] 

7133 ] = None, 

7134 ) -> None: 

7135 if TYPE_CHECKING: 

7136 assert isinstance(fromclause, Subquery) 

7137 

7138 if proxy_compound_columns: 

7139 columns._populate_separate_keys( 

7140 c._make_proxy( 

7141 fromclause, 

7142 compound_select_cols=extra_cols, 

7143 primary_key=primary_key, 

7144 foreign_keys=foreign_keys, 

7145 ) 

7146 for c, extra_cols in zip( 

7147 self.column_args, proxy_compound_columns 

7148 ) 

7149 ) 

7150 else: 

7151 columns._populate_separate_keys( 

7152 c._make_proxy( 

7153 fromclause, 

7154 primary_key=primary_key, 

7155 foreign_keys=foreign_keys, 

7156 ) 

7157 for c in self.column_args 

7158 ) 

7159 

7160 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7161 return self.column_args[0].type 

7162 

7163 

7164TextAsFrom = TextualSelect 

7165"""Backwards compatibility with the previous name""" 

7166 

7167 

7168class AnnotatedFromClause(Annotated): 

7169 def _copy_internals(self, **kw: Any) -> None: 

7170 super()._copy_internals(**kw) 

7171 if kw.get("ind_cols_on_fromclause", False): 

7172 ee = self._Annotated__element # type: ignore 

7173 

7174 self.c = ee.__class__.c.fget(self) # type: ignore 

7175 

7176 @util.ro_memoized_property 

7177 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7178 """proxy the .c collection of the underlying FromClause. 

7179 

7180 Originally implemented in 2008 as a simple load of the .c collection 

7181 when the annotated construct was created (see d3621ae961a), in modern 

7182 SQLAlchemy versions this can be expensive for statements constructed 

7183 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7184 it, which works just as well. 

7185 

7186 Two different use cases seem to require the collection either copied 

7187 from the underlying one, or unique to this AnnotatedFromClause. 

7188 

7189 See test_selectable->test_annotated_corresponding_column 

7190 

7191 """ 

7192 ee = self._Annotated__element # type: ignore 

7193 return ee.c # type: ignore