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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1778 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import Literal 

30from typing import NamedTuple 

31from typing import NoReturn 

32from typing import Optional 

33from typing import overload 

34from typing import Protocol 

35from typing import Sequence 

36from typing import Set 

37from typing import Tuple 

38from typing import Type 

39from typing import TYPE_CHECKING 

40from typing import TypeVar 

41from typing import Union 

42 

43from . import cache_key 

44from . import coercions 

45from . import operators 

46from . import roles 

47from . import traversals 

48from . import type_api 

49from . import visitors 

50from ._typing import _ColumnsClauseArgument 

51from ._typing import _no_kw 

52from ._typing import _T 

53from ._typing import _Ts 

54from ._typing import is_column_element 

55from ._typing import is_select_statement 

56from ._typing import is_subquery 

57from ._typing import is_table 

58from ._typing import is_text_clause 

59from .annotation import Annotated 

60from .annotation import SupportsCloneAnnotations 

61from .base import _clone 

62from .base import _cloned_difference 

63from .base import _cloned_intersection 

64from .base import _entity_namespace_key 

65from .base import _EntityNamespace 

66from .base import _expand_cloned 

67from .base import _from_objects 

68from .base import _generative 

69from .base import _never_select_column 

70from .base import _NoArg 

71from .base import _select_iterables 

72from .base import CacheableOptions 

73from .base import ColumnCollection 

74from .base import ColumnSet 

75from .base import CompileState 

76from .base import DedupeColumnCollection 

77from .base import DialectKWArgs 

78from .base import Executable 

79from .base import Generative 

80from .base import HasCompileState 

81from .base import HasMemoized 

82from .base import HasSyntaxExtensions 

83from .base import Immutable 

84from .base import SyntaxExtension 

85from .coercions import _document_text_coercion 

86from .elements import _anonymous_label 

87from .elements import BindParameter 

88from .elements import BooleanClauseList 

89from .elements import ClauseElement 

90from .elements import ClauseList 

91from .elements import ColumnClause 

92from .elements import ColumnElement 

93from .elements import DQLDMLClauseElement 

94from .elements import GroupedElement 

95from .elements import literal_column 

96from .elements import TableValuedColumn 

97from .elements import UnaryExpression 

98from .operators import OperatorType 

99from .sqltypes import NULLTYPE 

100from .visitors import _TraverseInternalsType 

101from .visitors import InternalTraversal 

102from .visitors import prefix_anon_map 

103from .. import exc 

104from .. import util 

105from ..util import HasMemoized_ro_memoized_attribute 

106from ..util import warn_deprecated 

107from ..util.typing import Self 

108from ..util.typing import TupleAny 

109from ..util.typing import Unpack 

110 

111 

112and_ = BooleanClauseList.and_ 

113 

114 

115if TYPE_CHECKING: 

116 from ._typing import _ColumnExpressionArgument 

117 from ._typing import _ColumnExpressionOrStrLabelArgument 

118 from ._typing import _FromClauseArgument 

119 from ._typing import _JoinTargetArgument 

120 from ._typing import _LimitOffsetType 

121 from ._typing import _MAYBE_ENTITY 

122 from ._typing import _NOT_ENTITY 

123 from ._typing import _OnClauseArgument 

124 from ._typing import _SelectStatementForCompoundArgument 

125 from ._typing import _T0 

126 from ._typing import _T1 

127 from ._typing import _T2 

128 from ._typing import _T3 

129 from ._typing import _T4 

130 from ._typing import _T5 

131 from ._typing import _T6 

132 from ._typing import _T7 

133 from ._typing import _TextCoercedExpressionArgument 

134 from ._typing import _TypedColumnClauseArgument as _TCCA 

135 from ._typing import _TypeEngineArgument 

136 from .base import _AmbiguousTableNameMap 

137 from .base import ExecutableOption 

138 from .base import ReadOnlyColumnCollection 

139 from .cache_key import _CacheKeyTraversalType 

140 from .compiler import SQLCompiler 

141 from .dml import Delete 

142 from .dml import Update 

143 from .elements import BinaryExpression 

144 from .elements import KeyedColumnElement 

145 from .elements import Label 

146 from .elements import NamedColumn 

147 from .elements import TextClause 

148 from .functions import Function 

149 from .schema import ForeignKey 

150 from .schema import ForeignKeyConstraint 

151 from .sqltypes import TableValueType 

152 from .type_api import TypeEngine 

153 from .visitors import _CloneCallableType 

154 

155 

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

157_LabelConventionCallable = Callable[ 

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

159] 

160 

161 

162class _JoinTargetProtocol(Protocol): 

163 @util.ro_non_memoized_property 

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

165 

166 @util.ro_non_memoized_property 

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

168 

169 

170_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

172 

173_ForUpdateOfArgument = Union[ 

174 # single column, Table, ORM Entity 

175 Union[ 

176 "_ColumnExpressionArgument[Any]", 

177 "_FromClauseArgument", 

178 ], 

179 # or sequence of single column elements 

180 Sequence["_ColumnExpressionArgument[Any]"], 

181] 

182 

183 

184_SetupJoinsElement = Tuple[ 

185 _JoinTargetElement, 

186 Optional[_OnClauseElement], 

187 Optional["FromClause"], 

188 Dict[str, Any], 

189] 

190 

191 

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

193 

194 

195class _OffsetLimitParam(BindParameter[int]): 

196 inherit_cache = True 

197 

198 @property 

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

200 return self.effective_value 

201 

202 

203class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

205 columns that can represent rows. 

206 

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

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

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

210 PostgreSQL has functions that return rows also. 

211 

212 .. versionadded:: 1.4 

213 

214 """ 

215 

216 _is_returns_rows = True 

217 

218 # sub-elements of returns_rows 

219 _is_from_clause = False 

220 _is_select_base = False 

221 _is_select_statement = False 

222 _is_lateral = False 

223 

224 @property 

225 def selectable(self) -> ReturnsRows: 

226 return self 

227 

228 @util.ro_non_memoized_property 

229 def _all_selected_columns(self) -> _SelectIterable: 

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

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

232 

233 This is typically equivalent to .exported_columns except it is 

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

235 :class:`_expression.ColumnCollection`. 

236 

237 """ 

238 raise NotImplementedError() 

239 

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

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

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

243 

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

245 

246 """ 

247 raise NotImplementedError() 

248 

249 def _generate_fromclause_column_proxies( 

250 self, 

251 fromclause: FromClause, 

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

253 primary_key: ColumnSet, 

254 foreign_keys: Set[KeyedColumnElement[Any]], 

255 ) -> None: 

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

257 

258 raise NotImplementedError() 

259 

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

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

262 raise NotImplementedError() 

263 

264 @property 

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

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

267 that represents the "exported" 

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

269 

270 The "exported" columns represent the collection of 

271 :class:`_expression.ColumnElement` 

272 expressions that are rendered by this SQL 

273 construct. There are primary varieties which are the 

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

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

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

277 columns in a DML statement.. 

278 

279 .. versionadded:: 1.4 

280 

281 .. seealso:: 

282 

283 :attr:`_expression.FromClause.exported_columns` 

284 

285 :attr:`_expression.SelectBase.exported_columns` 

286 """ 

287 

288 raise NotImplementedError() 

289 

290 

291class ExecutableReturnsRows(Executable, ReturnsRows): 

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

293 

294 

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

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

297 

298 

299class Selectable(ReturnsRows): 

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

301 

302 __visit_name__ = "selectable" 

303 

304 is_selectable = True 

305 

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

307 raise NotImplementedError() 

308 

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

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

311 

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

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

314 

315 .. seealso:: 

316 

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

318 

319 """ 

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

321 

322 @util.deprecated( 

323 "1.4", 

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

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

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

327 ) 

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

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

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

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

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

333 

334 """ 

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

336 

337 def corresponding_column( 

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

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

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

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

342 :attr:`_expression.Selectable.exported_columns` 

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

344 which corresponds to that 

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

346 column. 

347 

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

349 to be matched. 

350 

351 :param require_embedded: only return corresponding columns for 

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

353 :class:`_expression.ColumnElement` 

354 is actually present within a sub-element 

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

356 Normally the column will match if 

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

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

359 

360 .. seealso:: 

361 

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

363 :class:`_expression.ColumnCollection` 

364 that is used for the operation. 

365 

366 :meth:`_expression.ColumnCollection.corresponding_column` 

367 - implementation 

368 method. 

369 

370 """ 

371 

372 return self.exported_columns.corresponding_column( 

373 column, require_embedded 

374 ) 

375 

376 

377class HasPrefixes: 

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

379 

380 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

381 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

382 ] 

383 

384 @_generative 

385 @_document_text_coercion( 

386 "prefixes", 

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

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

389 ) 

390 def prefix_with( 

391 self, 

392 *prefixes: _TextCoercedExpressionArgument[Any], 

393 dialect: str = "*", 

394 ) -> Self: 

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

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

397 

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

399 provided by MySQL. 

400 

401 E.g.:: 

402 

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

404 

405 # MySQL 5.7 optimizer hints 

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

407 

408 Multiple prefixes can be specified by multiple calls 

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

410 

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

412 construct which 

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

414 keyword. 

415 :param dialect: optional string dialect name which will 

416 limit rendering of this prefix to only that dialect. 

417 

418 """ 

419 self._prefixes = self._prefixes + tuple( 

420 [ 

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

422 for p in prefixes 

423 ] 

424 ) 

425 return self 

426 

427 

428class HasSuffixes: 

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

430 

431 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

432 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

433 ] 

434 

435 @_generative 

436 @_document_text_coercion( 

437 "suffixes", 

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

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

440 ) 

441 def suffix_with( 

442 self, 

443 *suffixes: _TextCoercedExpressionArgument[Any], 

444 dialect: str = "*", 

445 ) -> Self: 

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

447 

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

449 certain constructs. 

450 

451 E.g.:: 

452 

453 stmt = ( 

454 select(col1, col2) 

455 .cte() 

456 .suffix_with( 

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

458 ) 

459 ) 

460 

461 Multiple suffixes can be specified by multiple calls 

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

463 

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

465 construct which 

466 will be rendered following the target clause. 

467 :param dialect: Optional string dialect name which will 

468 limit rendering of this suffix to only that dialect. 

469 

470 """ 

471 self._suffixes = self._suffixes + tuple( 

472 [ 

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

474 for p in suffixes 

475 ] 

476 ) 

477 return self 

478 

479 

480class HasHints: 

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

482 util.immutabledict() 

483 ) 

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

485 

486 _has_hints_traverse_internals: _TraverseInternalsType = [ 

487 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

488 ("_hints", InternalTraversal.dp_table_hint_list), 

489 ] 

490 

491 @_generative 

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

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

494 other selectable object. 

495 

496 .. tip:: 

497 

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

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

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

501 the SELECT statement after the SELECT keyword, use the 

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

503 space, or for table-specific hints the 

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

505 hints in a dialect-specific location. 

506 

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

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

509 the statement as a whole. 

510 

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

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

513 etc. 

514 

515 .. seealso:: 

516 

517 :meth:`_expression.Select.with_hint` 

518 

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

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

521 MySQL or Oracle Database optimizer hints 

522 

523 """ 

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

525 

526 @_generative 

527 def with_hint( 

528 self, 

529 selectable: _FromClauseArgument, 

530 text: str, 

531 dialect_name: str = "*", 

532 ) -> Self: 

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

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

535 object. 

536 

537 .. tip:: 

538 

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

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

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

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

543 for MySQL or Oracle Database, use the 

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

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

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

547 

548 The text of the hint is rendered in the appropriate 

549 location for the database backend in use, relative 

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

551 passed as the 

552 ``selectable`` argument. The dialect implementation 

553 typically uses Python string substitution syntax 

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

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

556 following:: 

557 

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

559 

560 Would render SQL as: 

561 

562 .. sourcecode:: sql 

563 

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

565 

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

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

568 Database and MSSql simultaneously:: 

569 

570 select(mytable).with_hint( 

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

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

573 

574 .. seealso:: 

575 

576 :meth:`_expression.Select.with_statement_hint` 

577 

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

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

580 MySQL or Oracle Database optimizer hints 

581 

582 """ 

583 

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

585 

586 def _with_hint( 

587 self, 

588 selectable: Optional[_FromClauseArgument], 

589 text: str, 

590 dialect_name: str, 

591 ) -> Self: 

592 if selectable is None: 

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

594 else: 

595 self._hints = self._hints.union( 

596 { 

597 ( 

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

599 dialect_name, 

600 ): text 

601 } 

602 ) 

603 return self 

604 

605 

606class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

608 clause of a ``SELECT`` statement. 

609 

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

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

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

613 

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

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

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

617 :class:`_expression.ColumnElement` 

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

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

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

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

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

623 

624 

625 """ 

626 

627 __visit_name__ = "fromclause" 

628 named_with_column = False 

629 

630 @util.ro_non_memoized_property 

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

632 return () 

633 

634 _is_clone_of: Optional[FromClause] 

635 

636 _columns: ColumnCollection[Any, Any] 

637 

638 schema: Optional[str] = None 

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

640 

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

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

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

644 

645 """ 

646 

647 is_selectable = True 

648 _is_from_clause = True 

649 _is_join = False 

650 

651 _use_schema_map = False 

652 

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

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

655 

656 

657 e.g.:: 

658 

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

660 

661 .. seealso:: 

662 

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

664 method which allows for arbitrary column lists. 

665 

666 """ 

667 return Select(self) 

668 

669 def join( 

670 self, 

671 right: _FromClauseArgument, 

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

673 isouter: bool = False, 

674 full: bool = False, 

675 ) -> Join: 

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

677 :class:`_expression.FromClause` 

678 to another :class:`FromClause`. 

679 

680 E.g.:: 

681 

682 from sqlalchemy import join 

683 

684 j = user_table.join( 

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

686 ) 

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

688 

689 would emit SQL along the lines of: 

690 

691 .. sourcecode:: sql 

692 

693 SELECT user.id, user.name FROM user 

694 JOIN address ON user.id = address.user_id 

695 

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

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

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

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

700 class. 

701 

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

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

704 will attempt to 

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

706 

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

708 

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

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

711 

712 .. seealso:: 

713 

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

715 

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

717 

718 """ 

719 

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

721 

722 def outerjoin( 

723 self, 

724 right: _FromClauseArgument, 

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

726 full: bool = False, 

727 ) -> Join: 

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

729 :class:`_expression.FromClause` 

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

731 True. 

732 

733 E.g.:: 

734 

735 from sqlalchemy import outerjoin 

736 

737 j = user_table.outerjoin( 

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

739 ) 

740 

741 The above is equivalent to:: 

742 

743 j = user_table.join( 

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

745 ) 

746 

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

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

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

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

751 class. 

752 

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

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

755 will attempt to 

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

757 

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

759 LEFT OUTER JOIN. 

760 

761 .. seealso:: 

762 

763 :meth:`_expression.FromClause.join` 

764 

765 :class:`_expression.Join` 

766 

767 """ # noqa: E501 

768 

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

770 

771 def alias( 

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

773 ) -> NamedFromClause: 

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

775 

776 E.g.:: 

777 

778 a2 = some_table.alias("a2") 

779 

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

781 object which can be used 

782 as a FROM clause in any SELECT statement. 

783 

784 .. seealso:: 

785 

786 :ref:`tutorial_using_aliases` 

787 

788 :func:`_expression.alias` 

789 

790 """ 

791 

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

793 

794 def tablesample( 

795 self, 

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

797 name: Optional[str] = None, 

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

799 ) -> TableSample: 

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

801 

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

803 construct also 

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

805 

806 .. seealso:: 

807 

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

809 

810 """ 

811 return TableSample._construct( 

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

813 ) 

814 

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

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

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

818 

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

820 

821 """ 

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

823 # Other constructs override this to traverse through 

824 # contained elements. 

825 return fromclause in self._cloned_set 

826 

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

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

829 the other represent the same lexical identity. 

830 

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

832 if they are the same via annotation identity. 

833 

834 """ 

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

836 

837 @util.ro_non_memoized_property 

838 def description(self) -> str: 

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

840 

841 Used primarily for error message formatting. 

842 

843 """ 

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

845 

846 def _generate_fromclause_column_proxies( 

847 self, 

848 fromclause: FromClause, 

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

850 primary_key: ColumnSet, 

851 foreign_keys: Set[KeyedColumnElement[Any]], 

852 ) -> None: 

853 columns._populate_separate_keys( 

854 col._make_proxy( 

855 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

856 ) 

857 for col in self.c 

858 ) 

859 

860 @util.ro_non_memoized_property 

861 def exported_columns( 

862 self, 

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

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

865 that represents the "exported" 

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

867 

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

869 object are synonymous 

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

871 

872 .. versionadded:: 1.4 

873 

874 .. seealso:: 

875 

876 :attr:`_expression.Selectable.exported_columns` 

877 

878 :attr:`_expression.SelectBase.exported_columns` 

879 

880 

881 """ 

882 return self.c 

883 

884 @util.ro_non_memoized_property 

885 def columns( 

886 self, 

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

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

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

890 

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

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

893 other selectable-bound columns:: 

894 

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

896 

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

898 

899 """ 

900 return self.c 

901 

902 @util.ro_memoized_property 

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

904 """ 

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

906 

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

908 

909 """ 

910 if "_columns" not in self.__dict__: 

911 self._setup_collections() 

912 return self._columns.as_readonly() 

913 

914 def _setup_collections(self) -> None: 

915 assert "_columns" not in self.__dict__ 

916 assert "primary_key" not in self.__dict__ 

917 assert "foreign_keys" not in self.__dict__ 

918 

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

920 primary_key = ColumnSet() 

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

922 

923 self._populate_column_collection( 

924 columns=_columns, 

925 primary_key=primary_key, 

926 foreign_keys=foreign_keys, 

927 ) 

928 

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

930 # but greatly reduces the surface for problems 

931 self._columns = _columns 

932 self.primary_key = primary_key # type: ignore 

933 self.foreign_keys = foreign_keys # type: ignore 

934 

935 @util.ro_non_memoized_property 

936 def entity_namespace(self) -> _EntityNamespace: 

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

938 

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

940 expressions, such as:: 

941 

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

943 

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

945 be overridden using the "entity_namespace" annotation to deliver 

946 alternative results. 

947 

948 """ 

949 return self.c 

950 

951 @util.ro_memoized_property 

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

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

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

955 

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

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

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

959 

960 """ 

961 self._setup_collections() 

962 return self.primary_key 

963 

964 @util.ro_memoized_property 

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

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

967 which this FromClause references. 

968 

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

970 :class:`_schema.Table`-wide 

971 :class:`_schema.ForeignKeyConstraint`. 

972 

973 .. seealso:: 

974 

975 :attr:`_schema.Table.foreign_key_constraints` 

976 

977 """ 

978 self._setup_collections() 

979 return self.foreign_keys 

980 

981 def _reset_column_collection(self) -> None: 

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

983 

984 This collection is separate from all the other memoized things 

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

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

987 has already established strong relationships 

988 with the exported columns. 

989 

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

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

992 

993 """ 

994 

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

996 self.__dict__.pop(key, None) 

997 

998 @util.ro_non_memoized_property 

999 def _select_iterable(self) -> _SelectIterable: 

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

1001 

1002 @property 

1003 def _cols_populated(self) -> bool: 

1004 return "_columns" in self.__dict__ 

1005 

1006 def _populate_column_collection( 

1007 self, 

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

1009 primary_key: ColumnSet, 

1010 foreign_keys: Set[KeyedColumnElement[Any]], 

1011 ) -> None: 

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

1013 

1014 Each implementation has a different way of establishing 

1015 this collection. 

1016 

1017 """ 

1018 

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

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

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

1022 selectable ultimately should proxy this column. 

1023 

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

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

1026 Table objects it ultimately derives from. 

1027 

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

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

1030 but it will return None. 

1031 

1032 This method is currently used by Declarative to allow Table 

1033 columns to be added to a partially constructed inheritance 

1034 mapping that may have already produced joins. The method 

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

1036 and/or caveats aren't yet clear. 

1037 

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

1039 default via an event, which would require that 

1040 selectables maintain a weak referencing collection of all 

1041 derivations. 

1042 

1043 """ 

1044 self._reset_column_collection() 

1045 

1046 def _anonymous_fromclause( 

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

1048 ) -> FromClause: 

1049 return self.alias(name=name) 

1050 

1051 if TYPE_CHECKING: 

1052 

1053 def self_group( 

1054 self, against: Optional[OperatorType] = None 

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

1056 

1057 

1058class NamedFromClause(FromClause): 

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

1060 

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

1062 

1063 .. versionadded:: 2.0 

1064 

1065 """ 

1066 

1067 named_with_column = True 

1068 

1069 name: str 

1070 

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

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

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

1074 :class:`_expression.FromClause`. 

1075 

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

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

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

1079 such as PostgreSQL, Oracle Database and SQL Server. 

1080 

1081 E.g.: 

1082 

1083 .. sourcecode:: pycon+sql 

1084 

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

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

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

1088 >>> print(stmt) 

1089 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1090 FROM a 

1091 

1092 .. versionadded:: 1.4.0b2 

1093 

1094 .. seealso:: 

1095 

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

1097 

1098 """ 

1099 return TableValuedColumn(self, type_api.TABLEVALUE) 

1100 

1101 

1102class SelectLabelStyle(Enum): 

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

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

1105 

1106 LABEL_STYLE_NONE = 0 

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

1108 columns clause of a SELECT statement. 

1109 

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

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

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

1113 

1114 .. sourcecode:: pycon+sql 

1115 

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

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

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

1119 >>> print( 

1120 ... select(table1, table2) 

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

1122 ... .set_label_style(LABEL_STYLE_NONE) 

1123 ... ) 

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

1125 FROM table1 JOIN table2 ON true 

1126 

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

1128 

1129 .. versionadded:: 1.4 

1130 

1131 """ # noqa: E501 

1132 

1133 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1137 tables, aliases, or subqueries. 

1138 

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

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

1141 ``table2_columna``: 

1142 

1143 .. sourcecode:: pycon+sql 

1144 

1145 >>> from sqlalchemy import ( 

1146 ... table, 

1147 ... column, 

1148 ... select, 

1149 ... true, 

1150 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1151 ... ) 

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

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

1154 >>> print( 

1155 ... select(table1, table2) 

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

1157 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1158 ... ) 

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

1160 FROM table1 JOIN table2 ON true 

1161 

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

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

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

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

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

1167 

1168 

1169 .. versionadded:: 1.4 

1170 

1171 """ # noqa: E501 

1172 

1173 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1176 when generating the columns clause of a SELECT statement. 

1177 

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

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

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

1181 

1182 .. sourcecode:: pycon+sql 

1183 

1184 >>> from sqlalchemy import ( 

1185 ... table, 

1186 ... column, 

1187 ... select, 

1188 ... true, 

1189 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1190 ... ) 

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

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

1193 >>> print( 

1194 ... select(table1, table2) 

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

1196 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1197 ... ) 

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

1199 FROM table1 JOIN table2 ON true 

1200 

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

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

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

1204 

1205 .. versionadded:: 1.4 

1206 

1207 """ # noqa: E501 

1208 

1209 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1210 """The default label style, refers to 

1211 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1212 

1213 .. versionadded:: 1.4 

1214 

1215 """ 

1216 

1217 LABEL_STYLE_LEGACY_ORM = 3 

1218 

1219 

1220( 

1221 LABEL_STYLE_NONE, 

1222 LABEL_STYLE_TABLENAME_PLUS_COL, 

1223 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1224 _, 

1225) = list(SelectLabelStyle) 

1226 

1227LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1228 

1229 

1230class Join(roles.DMLTableRole, FromClause): 

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

1232 :class:`_expression.FromClause` 

1233 elements. 

1234 

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

1236 is the module-level 

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

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

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

1240 :class:`_schema.Table`). 

1241 

1242 .. seealso:: 

1243 

1244 :func:`_expression.join` 

1245 

1246 :meth:`_expression.FromClause.join` 

1247 

1248 """ 

1249 

1250 __visit_name__ = "join" 

1251 

1252 _traverse_internals: _TraverseInternalsType = [ 

1253 ("left", InternalTraversal.dp_clauseelement), 

1254 ("right", InternalTraversal.dp_clauseelement), 

1255 ("onclause", InternalTraversal.dp_clauseelement), 

1256 ("isouter", InternalTraversal.dp_boolean), 

1257 ("full", InternalTraversal.dp_boolean), 

1258 ] 

1259 

1260 _is_join = True 

1261 

1262 left: FromClause 

1263 right: FromClause 

1264 onclause: Optional[ColumnElement[bool]] 

1265 isouter: bool 

1266 full: bool 

1267 

1268 def __init__( 

1269 self, 

1270 left: _FromClauseArgument, 

1271 right: _FromClauseArgument, 

1272 onclause: Optional[_OnClauseArgument] = None, 

1273 isouter: bool = False, 

1274 full: bool = False, 

1275 ): 

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

1277 

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

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

1280 :class:`_expression.FromClause` object. 

1281 

1282 """ 

1283 

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

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

1286 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1289 # callcounts for a single compilation in that particular test 

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

1291 # 29200 -> 30373 

1292 

1293 self.left = coercions.expect( 

1294 roles.FromClauseRole, 

1295 left, 

1296 ) 

1297 self.right = coercions.expect( 

1298 roles.FromClauseRole, 

1299 right, 

1300 ).self_group() 

1301 

1302 if onclause is None: 

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

1304 else: 

1305 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1306 # not merged yet 

1307 self.onclause = coercions.expect( 

1308 roles.OnClauseRole, onclause 

1309 ).self_group(against=operators._asbool) 

1310 

1311 self.isouter = isouter 

1312 self.full = full 

1313 

1314 @util.ro_non_memoized_property 

1315 def description(self) -> str: 

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

1317 self.left.description, 

1318 id(self.left), 

1319 self.right.description, 

1320 id(self.right), 

1321 ) 

1322 

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

1324 return ( 

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

1326 # as well 

1327 hash(fromclause) == hash(self) 

1328 or self.left.is_derived_from(fromclause) 

1329 or self.right.is_derived_from(fromclause) 

1330 ) 

1331 

1332 def self_group( 

1333 self, against: Optional[OperatorType] = None 

1334 ) -> FromGrouping: 

1335 return FromGrouping(self) 

1336 

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

1338 def _populate_column_collection( 

1339 self, 

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

1341 primary_key: ColumnSet, 

1342 foreign_keys: Set[KeyedColumnElement[Any]], 

1343 ) -> None: 

1344 sqlutil = util.preloaded.sql_util 

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

1346 c for c in self.right.c 

1347 ] 

1348 

1349 primary_key.extend( 

1350 sqlutil.reduce_columns( 

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

1352 ) 

1353 ) 

1354 columns._populate_separate_keys( 

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

1356 ) 

1357 foreign_keys.update( 

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

1359 ) 

1360 

1361 def _copy_internals( 

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

1363 ) -> None: 

1364 # see Select._copy_internals() for similar concept 

1365 

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

1367 # determine the new FROM clauses 

1368 all_the_froms = set( 

1369 itertools.chain( 

1370 _from_objects(self.left), 

1371 _from_objects(self.right), 

1372 ) 

1373 ) 

1374 

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

1376 # cache used by the clone function 

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

1378 

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

1380 # ColumnClause with parent table referring to those 

1381 # replaced FromClause objects 

1382 def replace( 

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

1384 **kw: Any, 

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

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

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

1388 return newelem 

1389 return None 

1390 

1391 kw["replace"] = replace 

1392 

1393 # run normal _copy_internals. the clones for 

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

1395 # cache 

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

1397 

1398 self._reset_memoizations() 

1399 

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

1401 super()._refresh_for_new_column(column) 

1402 self.left._refresh_for_new_column(column) 

1403 self.right._refresh_for_new_column(column) 

1404 

1405 def _match_primaries( 

1406 self, 

1407 left: FromClause, 

1408 right: FromClause, 

1409 ) -> ColumnElement[bool]: 

1410 if isinstance(left, Join): 

1411 left_right = left.right 

1412 else: 

1413 left_right = None 

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

1415 

1416 @classmethod 

1417 def _join_condition( 

1418 cls, 

1419 a: FromClause, 

1420 b: FromClause, 

1421 *, 

1422 a_subset: Optional[FromClause] = None, 

1423 consider_as_foreign_keys: Optional[ 

1424 AbstractSet[ColumnClause[Any]] 

1425 ] = None, 

1426 ) -> ColumnElement[bool]: 

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

1428 

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

1430 

1431 """ 

1432 constraints = cls._joincond_scan_left_right( 

1433 a, a_subset, b, consider_as_foreign_keys 

1434 ) 

1435 

1436 if len(constraints) > 1: 

1437 cls._joincond_trim_constraints( 

1438 a, b, constraints, consider_as_foreign_keys 

1439 ) 

1440 

1441 if len(constraints) == 0: 

1442 if isinstance(b, FromGrouping): 

1443 hint = ( 

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

1445 "subquery using alias()?" 

1446 ) 

1447 else: 

1448 hint = "" 

1449 raise exc.NoForeignKeysError( 

1450 "Can't find any foreign key relationships " 

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

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

1453 ) 

1454 

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

1456 if len(crit) == 1: 

1457 return crit[0] 

1458 else: 

1459 return and_(*crit) 

1460 

1461 @classmethod 

1462 def _can_join( 

1463 cls, 

1464 left: FromClause, 

1465 right: FromClause, 

1466 *, 

1467 consider_as_foreign_keys: Optional[ 

1468 AbstractSet[ColumnClause[Any]] 

1469 ] = None, 

1470 ) -> bool: 

1471 if isinstance(left, Join): 

1472 left_right = left.right 

1473 else: 

1474 left_right = None 

1475 

1476 constraints = cls._joincond_scan_left_right( 

1477 a=left, 

1478 b=right, 

1479 a_subset=left_right, 

1480 consider_as_foreign_keys=consider_as_foreign_keys, 

1481 ) 

1482 

1483 return bool(constraints) 

1484 

1485 @classmethod 

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

1487 def _joincond_scan_left_right( 

1488 cls, 

1489 a: FromClause, 

1490 a_subset: Optional[FromClause], 

1491 b: FromClause, 

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

1493 ) -> collections.defaultdict[ 

1494 Optional[ForeignKeyConstraint], 

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

1496 ]: 

1497 sql_util = util.preloaded.sql_util 

1498 

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

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

1501 

1502 constraints: collections.defaultdict[ 

1503 Optional[ForeignKeyConstraint], 

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

1505 ] = collections.defaultdict(list) 

1506 

1507 for left in (a_subset, a): 

1508 if left is None: 

1509 continue 

1510 for fk in sorted( 

1511 b.foreign_keys, 

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

1513 ): 

1514 if ( 

1515 consider_as_foreign_keys is not None 

1516 and fk.parent not in consider_as_foreign_keys 

1517 ): 

1518 continue 

1519 try: 

1520 col = fk.get_referent(left) 

1521 except exc.NoReferenceError as nrte: 

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

1523 if nrte.table_name in table_names: 

1524 raise 

1525 else: 

1526 continue 

1527 

1528 if col is not None: 

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

1530 if left is not b: 

1531 for fk in sorted( 

1532 left.foreign_keys, 

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

1534 ): 

1535 if ( 

1536 consider_as_foreign_keys is not None 

1537 and fk.parent not in consider_as_foreign_keys 

1538 ): 

1539 continue 

1540 try: 

1541 col = fk.get_referent(b) 

1542 except exc.NoReferenceError as nrte: 

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

1544 if nrte.table_name in table_names: 

1545 raise 

1546 else: 

1547 continue 

1548 

1549 if col is not None: 

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

1551 if constraints: 

1552 break 

1553 return constraints 

1554 

1555 @classmethod 

1556 def _joincond_trim_constraints( 

1557 cls, 

1558 a: FromClause, 

1559 b: FromClause, 

1560 constraints: Dict[Any, Any], 

1561 consider_as_foreign_keys: Optional[Any], 

1562 ) -> None: 

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

1564 # to include just those FKCs that match exactly to 

1565 # "consider_as_foreign_keys". 

1566 if consider_as_foreign_keys: 

1567 for const in list(constraints): 

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

1569 consider_as_foreign_keys 

1570 ): 

1571 del constraints[const] 

1572 

1573 # if still multiple constraints, but 

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

1575 if len(constraints) > 1: 

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

1577 if len(dedupe) == 1: 

1578 key = list(constraints)[0] 

1579 constraints = {key: constraints[key]} 

1580 

1581 if len(constraints) != 1: 

1582 raise exc.AmbiguousForeignKeysError( 

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

1584 "tables have more than one foreign key " 

1585 "constraint relationship between them. " 

1586 "Please specify the 'onclause' of this " 

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

1588 ) 

1589 

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

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

1592 :class:`_expression.Join`. 

1593 

1594 E.g.:: 

1595 

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

1597 

1598 stmt = stmt.select() 

1599 

1600 The above will produce a SQL string resembling: 

1601 

1602 .. sourcecode:: sql 

1603 

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

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

1606 

1607 """ 

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

1609 

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

1611 def _anonymous_fromclause( 

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

1613 ) -> TODO_Any: 

1614 sqlutil = util.preloaded.sql_util 

1615 if flat: 

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

1617 left_name = name # will recurse 

1618 else: 

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

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

1621 else: 

1622 left_name = name 

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

1624 right_name = name # will recurse 

1625 else: 

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

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

1628 else: 

1629 right_name = name 

1630 left_a, right_a = ( 

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

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

1633 ) 

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

1635 sqlutil.ClauseAdapter(right_a) 

1636 ) 

1637 

1638 return left_a.join( 

1639 right_a, 

1640 adapter.traverse(self.onclause), 

1641 isouter=self.isouter, 

1642 full=self.full, 

1643 ) 

1644 else: 

1645 return ( 

1646 self.select() 

1647 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1648 .correlate(None) 

1649 .alias(name) 

1650 ) 

1651 

1652 @util.ro_non_memoized_property 

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

1654 return itertools.chain( 

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

1656 ) 

1657 

1658 @util.ro_non_memoized_property 

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

1660 self_list: List[FromClause] = [self] 

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

1662 

1663 

1664class NoInit: 

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

1666 raise NotImplementedError( 

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

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

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

1670 "selectable objects." 

1671 % ( 

1672 self.__class__.__name__, 

1673 self.__class__.__name__.lower(), 

1674 self.__class__.__name__.lower(), 

1675 ) 

1676 ) 

1677 

1678 

1679class LateralFromClause(NamedFromClause): 

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

1681 

1682 

1683# FromClause -> 

1684# AliasedReturnsRows 

1685# -> Alias only for FromClause 

1686# -> Subquery only for SelectBase 

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

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

1689# w/ non-deprecated coercion 

1690# -> TableSample -> only for FromClause 

1691 

1692 

1693class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1695 selectables.""" 

1696 

1697 _is_from_container = True 

1698 

1699 _supports_derived_columns = False 

1700 

1701 element: ReturnsRows 

1702 

1703 _traverse_internals: _TraverseInternalsType = [ 

1704 ("element", InternalTraversal.dp_clauseelement), 

1705 ("name", InternalTraversal.dp_anon_name), 

1706 ] 

1707 

1708 @classmethod 

1709 def _construct( 

1710 cls, 

1711 selectable: Any, 

1712 *, 

1713 name: Optional[str] = None, 

1714 **kw: Any, 

1715 ) -> Self: 

1716 obj = cls.__new__(cls) 

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

1718 return obj 

1719 

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

1721 self.element = coercions.expect( 

1722 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1723 ) 

1724 self.element = selectable 

1725 self._orig_name = name 

1726 if name is None: 

1727 if ( 

1728 isinstance(selectable, FromClause) 

1729 and selectable.named_with_column 

1730 ): 

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

1732 if isinstance(name, _anonymous_label): 

1733 name = None 

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

1735 self.name = name 

1736 

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

1738 super()._refresh_for_new_column(column) 

1739 self.element._refresh_for_new_column(column) 

1740 

1741 def _populate_column_collection( 

1742 self, 

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

1744 primary_key: ColumnSet, 

1745 foreign_keys: Set[KeyedColumnElement[Any]], 

1746 ) -> None: 

1747 self.element._generate_fromclause_column_proxies( 

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

1749 ) 

1750 

1751 @util.ro_non_memoized_property 

1752 def description(self) -> str: 

1753 name = self.name 

1754 if isinstance(name, _anonymous_label): 

1755 return "anon_1" 

1756 

1757 return name 

1758 

1759 @util.ro_non_memoized_property 

1760 def implicit_returning(self) -> bool: 

1761 return self.element.implicit_returning # type: ignore 

1762 

1763 @property 

1764 def original(self) -> ReturnsRows: 

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

1766 return self.element 

1767 

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

1769 if fromclause in self._cloned_set: 

1770 return True 

1771 return self.element.is_derived_from(fromclause) 

1772 

1773 def _copy_internals( 

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

1775 ) -> None: 

1776 existing_element = self.element 

1777 

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

1779 

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

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

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

1783 # performance. 

1784 if existing_element is not self.element: 

1785 self._reset_column_collection() 

1786 

1787 @property 

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

1789 return [self] 

1790 

1791 

1792class FromClauseAlias(AliasedReturnsRows): 

1793 element: FromClause 

1794 

1795 @util.ro_non_memoized_property 

1796 def description(self) -> str: 

1797 name = self.name 

1798 if isinstance(name, _anonymous_label): 

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

1800 

1801 return name 

1802 

1803 

1804class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1806 

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

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

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

1810 

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

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

1813 method available 

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

1815 

1816 .. seealso:: 

1817 

1818 :meth:`_expression.FromClause.alias` 

1819 

1820 """ 

1821 

1822 __visit_name__ = "alias" 

1823 

1824 inherit_cache = True 

1825 

1826 element: FromClause 

1827 

1828 @classmethod 

1829 def _factory( 

1830 cls, 

1831 selectable: FromClause, 

1832 name: Optional[str] = None, 

1833 flat: bool = False, 

1834 ) -> NamedFromClause: 

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

1836 name=name, flat=flat 

1837 ) 

1838 

1839 

1840class TableValuedAlias(LateralFromClause, Alias): 

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

1842 

1843 This construct provides for a SQL function that returns columns 

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

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

1846 method, e.g.: 

1847 

1848 .. sourcecode:: pycon+sql 

1849 

1850 >>> from sqlalchemy import select, func 

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

1852 ... "value" 

1853 ... ) 

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

1855 {printsql}SELECT anon_1.value 

1856 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1857 

1858 .. versionadded:: 1.4.0b2 

1859 

1860 .. seealso:: 

1861 

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

1863 

1864 """ # noqa: E501 

1865 

1866 __visit_name__ = "table_valued_alias" 

1867 

1868 _supports_derived_columns = True 

1869 _render_derived = False 

1870 _render_derived_w_types = False 

1871 joins_implicitly = False 

1872 

1873 _traverse_internals: _TraverseInternalsType = [ 

1874 ("element", InternalTraversal.dp_clauseelement), 

1875 ("name", InternalTraversal.dp_anon_name), 

1876 ("_tableval_type", InternalTraversal.dp_type), 

1877 ("_render_derived", InternalTraversal.dp_boolean), 

1878 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1879 ] 

1880 

1881 def _init( 

1882 self, 

1883 selectable: Any, 

1884 *, 

1885 name: Optional[str] = None, 

1886 table_value_type: Optional[TableValueType] = None, 

1887 joins_implicitly: bool = False, 

1888 ) -> None: 

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

1890 

1891 self.joins_implicitly = joins_implicitly 

1892 self._tableval_type = ( 

1893 type_api.TABLEVALUE 

1894 if table_value_type is None 

1895 else table_value_type 

1896 ) 

1897 

1898 @HasMemoized.memoized_attribute 

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

1900 """Return a column expression representing this 

1901 :class:`_sql.TableValuedAlias`. 

1902 

1903 This accessor is used to implement the 

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

1905 method for further details. 

1906 

1907 E.g.: 

1908 

1909 .. sourcecode:: pycon+sql 

1910 

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

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

1913 

1914 .. seealso:: 

1915 

1916 :meth:`_functions.FunctionElement.column_valued` 

1917 

1918 """ 

1919 

1920 return TableValuedColumn(self, self._tableval_type) 

1921 

1922 def alias( 

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

1924 ) -> TableValuedAlias: 

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

1926 

1927 This creates a distinct FROM object that will be distinguished 

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

1929 

1930 """ 

1931 

1932 tva: TableValuedAlias = TableValuedAlias._construct( 

1933 self, 

1934 name=name, 

1935 table_value_type=self._tableval_type, 

1936 joins_implicitly=self.joins_implicitly, 

1937 ) 

1938 

1939 if self._render_derived: 

1940 tva._render_derived = True 

1941 tva._render_derived_w_types = self._render_derived_w_types 

1942 

1943 return tva 

1944 

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

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

1947 set, so that it renders as LATERAL. 

1948 

1949 .. seealso:: 

1950 

1951 :func:`_expression.lateral` 

1952 

1953 """ 

1954 tva = self.alias(name=name) 

1955 tva._is_lateral = True 

1956 return tva 

1957 

1958 def render_derived( 

1959 self, 

1960 name: Optional[str] = None, 

1961 with_types: bool = False, 

1962 ) -> TableValuedAlias: 

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

1964 

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

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

1967 

1968 .. sourcecode:: pycon+sql 

1969 

1970 >>> print( 

1971 ... select( 

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

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

1974 ... .render_derived() 

1975 ... ) 

1976 ... ) 

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

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

1979 

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

1981 the alias expression (this syntax currently applies to the 

1982 PostgreSQL database): 

1983 

1984 .. sourcecode:: pycon+sql 

1985 

1986 >>> print( 

1987 ... select( 

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

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

1990 ... .render_derived(with_types=True) 

1991 ... ) 

1992 ... ) 

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

1994 AS anon_1(a INTEGER, b VARCHAR) 

1995 

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

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

1998 

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

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

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

2002 

2003 """ # noqa: E501 

2004 

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

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

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

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

2009 # (just saw it happen on CI) 

2010 

2011 # construct against original to prevent memory growth 

2012 # for repeated generations 

2013 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2014 self.element, 

2015 name=name, 

2016 table_value_type=self._tableval_type, 

2017 joins_implicitly=self.joins_implicitly, 

2018 ) 

2019 new_alias._render_derived = True 

2020 new_alias._render_derived_w_types = with_types 

2021 return new_alias 

2022 

2023 

2024class Lateral(FromClauseAlias, LateralFromClause): 

2025 """Represent a LATERAL subquery. 

2026 

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

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

2029 method available 

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

2031 

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

2033 PostgreSQL versions provide support for this keyword. 

2034 

2035 .. seealso:: 

2036 

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

2038 

2039 """ 

2040 

2041 __visit_name__ = "lateral" 

2042 _is_lateral = True 

2043 

2044 inherit_cache = True 

2045 

2046 @classmethod 

2047 def _factory( 

2048 cls, 

2049 selectable: Union[SelectBase, _FromClauseArgument], 

2050 name: Optional[str] = None, 

2051 ) -> LateralFromClause: 

2052 return coercions.expect( 

2053 roles.FromClauseRole, selectable, explicit_subquery=True 

2054 ).lateral(name=name) 

2055 

2056 

2057class TableSample(FromClauseAlias): 

2058 """Represent a TABLESAMPLE clause. 

2059 

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

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

2062 method 

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

2064 

2065 .. seealso:: 

2066 

2067 :func:`_expression.tablesample` 

2068 

2069 """ 

2070 

2071 __visit_name__ = "tablesample" 

2072 

2073 _traverse_internals: _TraverseInternalsType = ( 

2074 AliasedReturnsRows._traverse_internals 

2075 + [ 

2076 ("sampling", InternalTraversal.dp_clauseelement), 

2077 ("seed", InternalTraversal.dp_clauseelement), 

2078 ] 

2079 ) 

2080 

2081 @classmethod 

2082 def _factory( 

2083 cls, 

2084 selectable: _FromClauseArgument, 

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

2086 name: Optional[str] = None, 

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

2088 ) -> TableSample: 

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

2090 sampling, name=name, seed=seed 

2091 ) 

2092 

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

2094 def _init( # type: ignore[override] 

2095 self, 

2096 selectable: Any, 

2097 *, 

2098 name: Optional[str] = None, 

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

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

2101 ) -> None: 

2102 assert sampling is not None 

2103 functions = util.preloaded.sql_functions 

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

2105 sampling = functions.func.system(sampling) 

2106 

2107 self.sampling: Function[Any] = sampling 

2108 self.seed = seed 

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

2110 

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

2112 return self.sampling 

2113 

2114 

2115class CTE( 

2116 roles.DMLTableRole, 

2117 roles.IsCTERole, 

2118 Generative, 

2119 HasPrefixes, 

2120 HasSuffixes, 

2121 AliasedReturnsRows, 

2122): 

2123 """Represent a Common Table Expression. 

2124 

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

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

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

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

2129 :class:`_sql.Update` and 

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

2131 usage details on CTEs. 

2132 

2133 .. seealso:: 

2134 

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

2136 

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

2138 

2139 """ 

2140 

2141 __visit_name__ = "cte" 

2142 

2143 _traverse_internals: _TraverseInternalsType = ( 

2144 AliasedReturnsRows._traverse_internals 

2145 + [ 

2146 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2147 ("_restates", InternalTraversal.dp_clauseelement), 

2148 ("recursive", InternalTraversal.dp_boolean), 

2149 ("nesting", InternalTraversal.dp_boolean), 

2150 ] 

2151 + HasPrefixes._has_prefixes_traverse_internals 

2152 + HasSuffixes._has_suffixes_traverse_internals 

2153 ) 

2154 

2155 element: HasCTE 

2156 

2157 @classmethod 

2158 def _factory( 

2159 cls, 

2160 selectable: HasCTE, 

2161 name: Optional[str] = None, 

2162 recursive: bool = False, 

2163 ) -> CTE: 

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

2165 or Common Table Expression instance. 

2166 

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

2168 

2169 """ 

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

2171 name=name, recursive=recursive 

2172 ) 

2173 

2174 def _init( 

2175 self, 

2176 selectable: HasCTE, 

2177 *, 

2178 name: Optional[str] = None, 

2179 recursive: bool = False, 

2180 nesting: bool = False, 

2181 _cte_alias: Optional[CTE] = None, 

2182 _restates: Optional[CTE] = None, 

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

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

2185 ) -> None: 

2186 self.recursive = recursive 

2187 self.nesting = nesting 

2188 self._cte_alias = _cte_alias 

2189 # Keep recursivity reference with union/union_all 

2190 self._restates = _restates 

2191 if _prefixes: 

2192 self._prefixes = _prefixes 

2193 if _suffixes: 

2194 self._suffixes = _suffixes 

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

2196 

2197 def _populate_column_collection( 

2198 self, 

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

2200 primary_key: ColumnSet, 

2201 foreign_keys: Set[KeyedColumnElement[Any]], 

2202 ) -> None: 

2203 if self._cte_alias is not None: 

2204 self._cte_alias._generate_fromclause_column_proxies( 

2205 self, 

2206 columns, 

2207 primary_key=primary_key, 

2208 foreign_keys=foreign_keys, 

2209 ) 

2210 else: 

2211 self.element._generate_fromclause_column_proxies( 

2212 self, 

2213 columns, 

2214 primary_key=primary_key, 

2215 foreign_keys=foreign_keys, 

2216 ) 

2217 

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

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

2220 :class:`_expression.CTE`. 

2221 

2222 This method is a CTE-specific specialization of the 

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

2224 

2225 .. seealso:: 

2226 

2227 :ref:`tutorial_using_aliases` 

2228 

2229 :func:`_expression.alias` 

2230 

2231 """ 

2232 return CTE._construct( 

2233 self.element, 

2234 name=name, 

2235 recursive=self.recursive, 

2236 nesting=self.nesting, 

2237 _cte_alias=self, 

2238 _prefixes=self._prefixes, 

2239 _suffixes=self._suffixes, 

2240 ) 

2241 

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

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

2244 of the original CTE against the given selectables provided 

2245 as positional arguments. 

2246 

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

2248 UNION. 

2249 

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

2251 

2252 .. seealso:: 

2253 

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

2255 

2256 """ 

2257 assert is_select_statement( 

2258 self.element 

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

2260 

2261 return CTE._construct( 

2262 self.element.union(*other), 

2263 name=self.name, 

2264 recursive=self.recursive, 

2265 nesting=self.nesting, 

2266 _restates=self, 

2267 _prefixes=self._prefixes, 

2268 _suffixes=self._suffixes, 

2269 ) 

2270 

2271 def union_all( 

2272 self, *other: _SelectStatementForCompoundArgument[Any] 

2273 ) -> CTE: 

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

2275 of the original CTE against the given selectables provided 

2276 as positional arguments. 

2277 

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

2279 UNION. 

2280 

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

2282 

2283 .. seealso:: 

2284 

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

2286 

2287 """ 

2288 

2289 assert is_select_statement( 

2290 self.element 

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

2292 

2293 return CTE._construct( 

2294 self.element.union_all(*other), 

2295 name=self.name, 

2296 recursive=self.recursive, 

2297 nesting=self.nesting, 

2298 _restates=self, 

2299 _prefixes=self._prefixes, 

2300 _suffixes=self._suffixes, 

2301 ) 

2302 

2303 def _get_reference_cte(self) -> CTE: 

2304 """ 

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

2306 Updated CTEs should still refer to the original CTE. 

2307 This function returns this reference identifier. 

2308 """ 

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

2310 

2311 

2312class _CTEOpts(NamedTuple): 

2313 nesting: bool 

2314 

2315 

2316class _ColumnsPlusNames(NamedTuple): 

2317 required_label_name: Optional[str] 

2318 """ 

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

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

2321 """ 

2322 

2323 proxy_key: Optional[str] 

2324 """ 

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

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

2327 select.selected_columns collection 

2328 """ 

2329 

2330 fallback_label_name: Optional[str] 

2331 """ 

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

2333 we have to render a label even though 

2334 required_label_name was not given 

2335 """ 

2336 

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

2338 """ 

2339 the ColumnElement itself 

2340 """ 

2341 

2342 repeated: bool 

2343 """ 

2344 True if this is a duplicate of a previous column 

2345 in the list of columns 

2346 """ 

2347 

2348 

2349class SelectsRows(ReturnsRows): 

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

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

2352 

2353 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2354 

2355 def _generate_columns_plus_names( 

2356 self, 

2357 anon_for_dupe_key: bool, 

2358 cols: Optional[_SelectIterable] = None, 

2359 ) -> List[_ColumnsPlusNames]: 

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

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

2362 on a :class:`.FromClause`. 

2363 

2364 This is distinct from the _column_naming_convention generator that's 

2365 intended for population of the Select.selected_columns collection, 

2366 different rules. the collection returned here calls upon the 

2367 _column_naming_convention as well. 

2368 

2369 """ 

2370 

2371 if cols is None: 

2372 cols = self._all_selected_columns 

2373 

2374 key_naming_convention = SelectState._column_naming_convention( 

2375 self._label_style 

2376 ) 

2377 

2378 names = {} 

2379 

2380 result: List[_ColumnsPlusNames] = [] 

2381 result_append = result.append 

2382 

2383 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2384 label_style_none = self._label_style is LABEL_STYLE_NONE 

2385 

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

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

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

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

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

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

2392 dedupe_hash = 1 

2393 

2394 for c in cols: 

2395 repeated = False 

2396 

2397 if not c._render_label_in_columns_clause: 

2398 effective_name = required_label_name = fallback_label_name = ( 

2399 None 

2400 ) 

2401 elif label_style_none: 

2402 if TYPE_CHECKING: 

2403 assert is_column_element(c) 

2404 

2405 effective_name = required_label_name = None 

2406 fallback_label_name = c._non_anon_label or c._anon_name_label 

2407 else: 

2408 if TYPE_CHECKING: 

2409 assert is_column_element(c) 

2410 

2411 if table_qualified: 

2412 required_label_name = effective_name = ( 

2413 fallback_label_name 

2414 ) = c._tq_label 

2415 else: 

2416 effective_name = fallback_label_name = c._non_anon_label 

2417 required_label_name = None 

2418 

2419 if effective_name is None: 

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

2421 # not need _expression_label but it isn't 

2422 # giving us a clue when to use anon_label instead 

2423 expr_label = c._expression_label 

2424 if expr_label is None: 

2425 repeated = c._anon_name_label in names 

2426 names[c._anon_name_label] = c 

2427 effective_name = required_label_name = None 

2428 

2429 if repeated: 

2430 # here, "required_label_name" is sent as 

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

2432 if table_qualified: 

2433 fallback_label_name = ( 

2434 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2435 ) 

2436 dedupe_hash += 1 

2437 else: 

2438 fallback_label_name = c._dedupe_anon_label_idx( 

2439 dedupe_hash 

2440 ) 

2441 dedupe_hash += 1 

2442 else: 

2443 fallback_label_name = c._anon_name_label 

2444 else: 

2445 required_label_name = effective_name = ( 

2446 fallback_label_name 

2447 ) = expr_label 

2448 

2449 if effective_name is not None: 

2450 if TYPE_CHECKING: 

2451 assert is_column_element(c) 

2452 

2453 if effective_name in names: 

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

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

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

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

2458 # different column under the same name. apply 

2459 # disambiguating label 

2460 if table_qualified: 

2461 required_label_name = fallback_label_name = ( 

2462 c._anon_tq_label 

2463 ) 

2464 else: 

2465 required_label_name = fallback_label_name = ( 

2466 c._anon_name_label 

2467 ) 

2468 

2469 if anon_for_dupe_key and required_label_name in names: 

2470 # here, c._anon_tq_label is definitely unique to 

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

2472 # this should always be true. 

2473 # this is also an infrequent codepath because 

2474 # you need two levels of duplication to be here 

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

2476 

2477 # the column under the disambiguating label is 

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

2479 # subsequent occurrences of the column so that the 

2480 # original stays non-ambiguous 

2481 if table_qualified: 

2482 required_label_name = fallback_label_name = ( 

2483 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2484 ) 

2485 dedupe_hash += 1 

2486 else: 

2487 required_label_name = fallback_label_name = ( 

2488 c._dedupe_anon_label_idx(dedupe_hash) 

2489 ) 

2490 dedupe_hash += 1 

2491 repeated = True 

2492 else: 

2493 names[required_label_name] = c 

2494 elif anon_for_dupe_key: 

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

2496 # label so that the original stays non-ambiguous 

2497 if table_qualified: 

2498 required_label_name = fallback_label_name = ( 

2499 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2500 ) 

2501 dedupe_hash += 1 

2502 else: 

2503 required_label_name = fallback_label_name = ( 

2504 c._dedupe_anon_label_idx(dedupe_hash) 

2505 ) 

2506 dedupe_hash += 1 

2507 repeated = True 

2508 else: 

2509 names[effective_name] = c 

2510 

2511 result_append( 

2512 _ColumnsPlusNames( 

2513 required_label_name, 

2514 key_naming_convention(c), 

2515 fallback_label_name, 

2516 c, 

2517 repeated, 

2518 ) 

2519 ) 

2520 

2521 return result 

2522 

2523 

2524class HasCTE(roles.HasCTERole, SelectsRows): 

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

2526 

2527 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2528 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2529 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2530 ] 

2531 

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

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

2534 

2535 name_cte_columns: bool = False 

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

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

2538 

2539 .. versionadded:: 2.0.42 

2540 

2541 """ 

2542 

2543 @_generative 

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

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

2546 

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

2548 the parent statement such that they will each be unconditionally 

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

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

2551 

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

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

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

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

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

2557 statement. 

2558 

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

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

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

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

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

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

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

2566 larger statement. 

2567 

2568 E.g.:: 

2569 

2570 from sqlalchemy import table, column, select 

2571 

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

2573 

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

2575 

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

2577 

2578 Would render: 

2579 

2580 .. sourcecode:: sql 

2581 

2582 WITH anon_1 AS ( 

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

2584 ) 

2585 SELECT t.c1, t.c2 

2586 FROM t 

2587 

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

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

2590 statement. 

2591 

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

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

2594 

2595 from sqlalchemy import table, column 

2596 from sqlalchemy.dialects.postgresql import insert 

2597 

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

2599 

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

2601 

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

2603 update_statement = insert_stmt.on_conflict_do_update( 

2604 index_elements=[t.c.c1], 

2605 set_={ 

2606 "c1": insert_stmt.excluded.c1, 

2607 "c2": insert_stmt.excluded.c2, 

2608 }, 

2609 ).add_cte(delete_statement_cte) 

2610 

2611 print(update_statement) 

2612 

2613 The above statement renders as: 

2614 

2615 .. sourcecode:: sql 

2616 

2617 WITH deletions AS ( 

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

2619 ) 

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

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

2622 

2623 .. versionadded:: 1.4.21 

2624 

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

2626 

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

2628 

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

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

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

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

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

2634 this statement when this flag is given. 

2635 

2636 .. versionadded:: 2.0 

2637 

2638 .. seealso:: 

2639 

2640 :paramref:`.HasCTE.cte.nesting` 

2641 

2642 

2643 """ # noqa: E501 

2644 opt = _CTEOpts(nest_here) 

2645 for cte in ctes: 

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

2647 self._independent_ctes += (cte,) 

2648 self._independent_ctes_opts += (opt,) 

2649 return self 

2650 

2651 def cte( 

2652 self, 

2653 name: Optional[str] = None, 

2654 recursive: bool = False, 

2655 nesting: bool = False, 

2656 ) -> CTE: 

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

2658 or Common Table Expression instance. 

2659 

2660 Common table expressions are a SQL standard whereby SELECT 

2661 statements can draw upon secondary statements specified along 

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

2663 Special semantics regarding UNION can also be employed to 

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

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

2666 

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

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

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

2670 CTE rows. 

2671 

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

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

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

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

2676 

2677 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2679 method may be 

2680 used to establish these. 

2681 

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

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

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

2685 compile time. 

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

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

2688 conjunction with UNION ALL in order to derive rows 

2689 from those already selected. 

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

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

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

2693 :paramref:`.HasCTE.add_cte.nest_here` 

2694 parameter may also be used to more carefully 

2695 control the exact placement of a particular CTE. 

2696 

2697 .. versionadded:: 1.4.24 

2698 

2699 .. seealso:: 

2700 

2701 :meth:`.HasCTE.add_cte` 

2702 

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

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

2705 as well as additional examples. 

2706 

2707 Example 1, non recursive:: 

2708 

2709 from sqlalchemy import ( 

2710 Table, 

2711 Column, 

2712 String, 

2713 Integer, 

2714 MetaData, 

2715 select, 

2716 func, 

2717 ) 

2718 

2719 metadata = MetaData() 

2720 

2721 orders = Table( 

2722 "orders", 

2723 metadata, 

2724 Column("region", String), 

2725 Column("amount", Integer), 

2726 Column("product", String), 

2727 Column("quantity", Integer), 

2728 ) 

2729 

2730 regional_sales = ( 

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

2732 .group_by(orders.c.region) 

2733 .cte("regional_sales") 

2734 ) 

2735 

2736 

2737 top_regions = ( 

2738 select(regional_sales.c.region) 

2739 .where( 

2740 regional_sales.c.total_sales 

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

2742 ) 

2743 .cte("top_regions") 

2744 ) 

2745 

2746 statement = ( 

2747 select( 

2748 orders.c.region, 

2749 orders.c.product, 

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

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

2752 ) 

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

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

2755 ) 

2756 

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

2758 

2759 Example 2, WITH RECURSIVE:: 

2760 

2761 from sqlalchemy import ( 

2762 Table, 

2763 Column, 

2764 String, 

2765 Integer, 

2766 MetaData, 

2767 select, 

2768 func, 

2769 ) 

2770 

2771 metadata = MetaData() 

2772 

2773 parts = Table( 

2774 "parts", 

2775 metadata, 

2776 Column("part", String), 

2777 Column("sub_part", String), 

2778 Column("quantity", Integer), 

2779 ) 

2780 

2781 included_parts = ( 

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

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

2784 .cte(recursive=True) 

2785 ) 

2786 

2787 

2788 incl_alias = included_parts.alias() 

2789 parts_alias = parts.alias() 

2790 included_parts = included_parts.union_all( 

2791 select( 

2792 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2794 ) 

2795 

2796 statement = select( 

2797 included_parts.c.sub_part, 

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

2799 ).group_by(included_parts.c.sub_part) 

2800 

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

2802 

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

2804 

2805 from datetime import date 

2806 from sqlalchemy import ( 

2807 MetaData, 

2808 Table, 

2809 Column, 

2810 Integer, 

2811 Date, 

2812 select, 

2813 literal, 

2814 and_, 

2815 exists, 

2816 ) 

2817 

2818 metadata = MetaData() 

2819 

2820 visitors = Table( 

2821 "visitors", 

2822 metadata, 

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

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

2825 Column("count", Integer), 

2826 ) 

2827 

2828 # add 5 visitors for the product_id == 1 

2829 product_id = 1 

2830 day = date.today() 

2831 count = 5 

2832 

2833 update_cte = ( 

2834 visitors.update() 

2835 .where( 

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

2837 ) 

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

2839 .returning(literal(1)) 

2840 .cte("update_cte") 

2841 ) 

2842 

2843 upsert = visitors.insert().from_select( 

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

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

2846 ~exists(update_cte.select()) 

2847 ), 

2848 ) 

2849 

2850 connection.execute(upsert) 

2851 

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

2853 

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

2855 

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

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

2858 "value_a", nesting=True 

2859 ) 

2860 

2861 # Nesting CTEs takes ascendency locally 

2862 # over the CTEs at a higher level 

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

2864 

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

2866 

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

2868 shown with inline parameters below as: 

2869 

2870 .. sourcecode:: sql 

2871 

2872 WITH 

2873 value_a AS 

2874 (SELECT 'root' AS n), 

2875 value_b AS 

2876 (WITH value_a AS 

2877 (SELECT 'nesting' AS n) 

2878 SELECT value_a.n AS n FROM value_a) 

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

2880 FROM value_a, value_b 

2881 

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

2883 as follows (SQLAlchemy 2.0 and above):: 

2884 

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

2886 

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

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

2889 

2890 # Nesting CTEs takes ascendency locally 

2891 # over the CTEs at a higher level 

2892 value_b = ( 

2893 select(value_a_nested.c.n) 

2894 .add_cte(value_a_nested, nest_here=True) 

2895 .cte("value_b") 

2896 ) 

2897 

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

2899 

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

2901 

2902 edge = Table( 

2903 "edge", 

2904 metadata, 

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

2906 Column("left", Integer), 

2907 Column("right", Integer), 

2908 ) 

2909 

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

2911 

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

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

2914 ) 

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

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

2917 ) 

2918 

2919 subgraph_cte = root_node.union(left_edge, right_edge) 

2920 

2921 subgraph = select(subgraph_cte) 

2922 

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

2924 

2925 .. sourcecode:: sql 

2926 

2927 WITH RECURSIVE nodes(node) AS ( 

2928 SELECT 1 AS node 

2929 UNION 

2930 SELECT edge."left" AS "left" 

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

2932 UNION 

2933 SELECT edge."right" AS "right" 

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

2935 ) 

2936 SELECT nodes.node FROM nodes 

2937 

2938 .. seealso:: 

2939 

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

2941 :meth:`_expression.HasCTE.cte`. 

2942 

2943 """ # noqa: E501 

2944 return CTE._construct( 

2945 self, name=name, recursive=recursive, nesting=nesting 

2946 ) 

2947 

2948 

2949class Subquery(AliasedReturnsRows): 

2950 """Represent a subquery of a SELECT. 

2951 

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

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

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

2955 :class:`_expression.SelectBase` subclass 

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

2957 :class:`_expression.CompoundSelect`, and 

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

2959 it represents the 

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

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

2962 

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

2964 :class:`_expression.Alias` 

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

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

2967 :class:`_expression.Alias` always 

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

2969 :class:`.Subquery` 

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

2971 

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

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

2974 statement. 

2975 

2976 """ 

2977 

2978 __visit_name__ = "subquery" 

2979 

2980 _is_subquery = True 

2981 

2982 inherit_cache = True 

2983 

2984 element: SelectBase 

2985 

2986 @classmethod 

2987 def _factory( 

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

2989 ) -> Subquery: 

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

2991 

2992 return coercions.expect( 

2993 roles.SelectStatementRole, selectable 

2994 ).subquery(name=name) 

2995 

2996 @util.deprecated( 

2997 "1.4", 

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

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

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

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

3002 ":func:`_expression.select` " 

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

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

3005 ) 

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

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

3008 

3009 

3010class FromGrouping(GroupedElement, FromClause): 

3011 """Represent a grouping of a FROM clause""" 

3012 

3013 _traverse_internals: _TraverseInternalsType = [ 

3014 ("element", InternalTraversal.dp_clauseelement) 

3015 ] 

3016 

3017 element: FromClause 

3018 

3019 def __init__(self, element: FromClause): 

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

3021 

3022 @util.ro_non_memoized_property 

3023 def columns( 

3024 self, 

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

3026 return self.element.columns 

3027 

3028 @util.ro_non_memoized_property 

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

3030 return self.element.columns 

3031 

3032 @property 

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

3034 return self.element.primary_key 

3035 

3036 @property 

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

3038 return self.element.foreign_keys 

3039 

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

3041 return self.element.is_derived_from(fromclause) 

3042 

3043 def alias( 

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

3045 ) -> NamedFromGrouping: 

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

3047 

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

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

3050 

3051 @util.ro_non_memoized_property 

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

3053 return self.element._hide_froms 

3054 

3055 @util.ro_non_memoized_property 

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

3057 return self.element._from_objects 

3058 

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

3060 return {"element": self.element} 

3061 

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

3063 self.element = state["element"] 

3064 

3065 if TYPE_CHECKING: 

3066 

3067 def self_group( 

3068 self, against: Optional[OperatorType] = None 

3069 ) -> Self: ... 

3070 

3071 

3072class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3074 

3075 .. versionadded:: 2.0 

3076 

3077 """ 

3078 

3079 inherit_cache = True 

3080 

3081 if TYPE_CHECKING: 

3082 

3083 def self_group( 

3084 self, against: Optional[OperatorType] = None 

3085 ) -> Self: ... 

3086 

3087 

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

3089 """Represents a minimal "table" construct. 

3090 

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

3092 collection of columns, which are typically produced 

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

3094 

3095 from sqlalchemy import table, column 

3096 

3097 user = table( 

3098 "user", 

3099 column("id"), 

3100 column("name"), 

3101 column("description"), 

3102 ) 

3103 

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

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

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

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

3108 

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

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

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

3112 It's useful 

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

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

3115 is not on hand. 

3116 

3117 """ 

3118 

3119 __visit_name__ = "table" 

3120 

3121 _traverse_internals: _TraverseInternalsType = [ 

3122 ( 

3123 "columns", 

3124 InternalTraversal.dp_fromclause_canonical_column_collection, 

3125 ), 

3126 ("name", InternalTraversal.dp_string), 

3127 ("schema", InternalTraversal.dp_string), 

3128 ] 

3129 

3130 _is_table = True 

3131 

3132 fullname: str 

3133 

3134 implicit_returning = False 

3135 """:class:`_expression.TableClause` 

3136 doesn't support having a primary key or column 

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

3138 

3139 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3140 

3141 @util.ro_memoized_property 

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

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

3144 return None 

3145 

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

3147 super().__init__() 

3148 self.name = name 

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

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

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

3152 for c in columns: 

3153 self.append_column(c) 

3154 

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

3156 if schema is not None: 

3157 self.schema = schema 

3158 if self.schema is not None: 

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

3160 else: 

3161 self.fullname = self.name 

3162 if kw: 

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

3164 

3165 if TYPE_CHECKING: 

3166 

3167 @util.ro_non_memoized_property 

3168 def columns( 

3169 self, 

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

3171 

3172 @util.ro_non_memoized_property 

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

3174 

3175 def __str__(self) -> str: 

3176 if self.schema is not None: 

3177 return self.schema + "." + self.name 

3178 else: 

3179 return self.name 

3180 

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

3182 pass 

3183 

3184 @util.ro_memoized_property 

3185 def description(self) -> str: 

3186 return self.name 

3187 

3188 def _insert_col_impl( 

3189 self, 

3190 c: ColumnClause[Any], 

3191 *, 

3192 index: Optional[int] = None, 

3193 ) -> None: 

3194 existing = c.table 

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

3196 raise exc.ArgumentError( 

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

3198 % (c.key, existing) 

3199 ) 

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

3201 c.table = self 

3202 

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

3204 self._insert_col_impl(c) 

3205 

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

3207 self._insert_col_impl(c, index=index) 

3208 

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

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

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

3212 :class:`_expression.TableClause`. 

3213 

3214 E.g.:: 

3215 

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

3217 

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

3219 

3220 """ 

3221 

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

3223 

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

3225 def update(self) -> Update: 

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

3227 :class:`_expression.TableClause`. 

3228 

3229 E.g.:: 

3230 

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

3232 

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

3234 

3235 """ 

3236 return util.preloaded.sql_dml.Update( 

3237 self, 

3238 ) 

3239 

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

3241 def delete(self) -> Delete: 

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

3243 :class:`_expression.TableClause`. 

3244 

3245 E.g.:: 

3246 

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

3248 

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

3250 

3251 """ 

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

3253 

3254 @util.ro_non_memoized_property 

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

3256 return [self] 

3257 

3258 

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

3260 

3261 

3262class ForUpdateArg(ClauseElement): 

3263 _traverse_internals: _TraverseInternalsType = [ 

3264 ("of", InternalTraversal.dp_clauseelement_list), 

3265 ("nowait", InternalTraversal.dp_boolean), 

3266 ("read", InternalTraversal.dp_boolean), 

3267 ("skip_locked", InternalTraversal.dp_boolean), 

3268 ("key_share", InternalTraversal.dp_boolean), 

3269 ] 

3270 

3271 of: Optional[Sequence[ClauseElement]] 

3272 nowait: bool 

3273 read: bool 

3274 skip_locked: bool 

3275 

3276 @classmethod 

3277 def _from_argument( 

3278 cls, with_for_update: ForUpdateParameter 

3279 ) -> Optional[ForUpdateArg]: 

3280 if isinstance(with_for_update, ForUpdateArg): 

3281 return with_for_update 

3282 elif with_for_update in (None, False): 

3283 return None 

3284 elif with_for_update is True: 

3285 return ForUpdateArg() 

3286 else: 

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

3288 

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

3290 return ( 

3291 isinstance(other, ForUpdateArg) 

3292 and other.nowait == self.nowait 

3293 and other.read == self.read 

3294 and other.skip_locked == self.skip_locked 

3295 and other.key_share == self.key_share 

3296 and other.of is self.of 

3297 ) 

3298 

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

3300 return not self.__eq__(other) 

3301 

3302 def __hash__(self) -> int: 

3303 return id(self) 

3304 

3305 def __init__( 

3306 self, 

3307 *, 

3308 nowait: bool = False, 

3309 read: bool = False, 

3310 of: Optional[_ForUpdateOfArgument] = None, 

3311 skip_locked: bool = False, 

3312 key_share: bool = False, 

3313 ): 

3314 """Represents arguments specified to 

3315 :meth:`_expression.Select.for_update`. 

3316 

3317 """ 

3318 

3319 self.nowait = nowait 

3320 self.read = read 

3321 self.skip_locked = skip_locked 

3322 self.key_share = key_share 

3323 if of is not None: 

3324 self.of = [ 

3325 coercions.expect(roles.ColumnsClauseRole, elem) 

3326 for elem in util.to_list(of) 

3327 ] 

3328 else: 

3329 self.of = None 

3330 

3331 

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

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

3334 in a statement. 

3335 

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

3337 :func:`_expression.values` function. 

3338 

3339 .. versionadded:: 1.4 

3340 

3341 """ 

3342 

3343 __visit_name__ = "values" 

3344 

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

3346 

3347 _unnamed: bool 

3348 _traverse_internals: _TraverseInternalsType = [ 

3349 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3350 ("_data", InternalTraversal.dp_dml_multi_values), 

3351 ("name", InternalTraversal.dp_string), 

3352 ("literal_binds", InternalTraversal.dp_boolean), 

3353 ] + HasCTE._has_ctes_traverse_internals 

3354 

3355 name_cte_columns = True 

3356 

3357 def __init__( 

3358 self, 

3359 *columns: ColumnClause[Any], 

3360 name: Optional[str] = None, 

3361 literal_binds: bool = False, 

3362 ): 

3363 super().__init__() 

3364 self._column_args = columns 

3365 

3366 if name is None: 

3367 self._unnamed = True 

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

3369 else: 

3370 self._unnamed = False 

3371 self.name = name 

3372 self.literal_binds = literal_binds 

3373 self.named_with_column = not self._unnamed 

3374 

3375 @property 

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

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

3378 

3379 @util.ro_non_memoized_property 

3380 def _all_selected_columns(self) -> _SelectIterable: 

3381 return self._column_args 

3382 

3383 @_generative 

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

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

3386 construct that is a copy of this 

3387 one with the given name. 

3388 

3389 This method is a VALUES-specific specialization of the 

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

3391 

3392 .. seealso:: 

3393 

3394 :ref:`tutorial_using_aliases` 

3395 

3396 :func:`_expression.alias` 

3397 

3398 """ 

3399 non_none_name: str 

3400 

3401 if name is None: 

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

3403 else: 

3404 non_none_name = name 

3405 

3406 self.name = non_none_name 

3407 self.named_with_column = True 

3408 self._unnamed = False 

3409 return self 

3410 

3411 @_generative 

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

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

3414 so that 

3415 it renders as LATERAL. 

3416 

3417 .. seealso:: 

3418 

3419 :func:`_expression.lateral` 

3420 

3421 """ 

3422 non_none_name: str 

3423 

3424 if name is None: 

3425 non_none_name = self.name 

3426 else: 

3427 non_none_name = name 

3428 

3429 self._is_lateral = True 

3430 self.name = non_none_name 

3431 self._unnamed = False 

3432 return self 

3433 

3434 @_generative 

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

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

3437 adding the given data to the data list. 

3438 

3439 E.g.:: 

3440 

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

3442 

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

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

3445 constructor. 

3446 

3447 """ 

3448 

3449 self._data += (values,) 

3450 return self 

3451 

3452 def scalar_values(self) -> ScalarValues: 

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

3454 COLUMN element in a statement. 

3455 

3456 .. versionadded:: 2.0.0b4 

3457 

3458 """ 

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

3460 

3461 def _populate_column_collection( 

3462 self, 

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

3464 primary_key: ColumnSet, 

3465 foreign_keys: Set[KeyedColumnElement[Any]], 

3466 ) -> None: 

3467 for c in self._column_args: 

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

3469 _, c = c._make_proxy( 

3470 self, primary_key=primary_key, foreign_keys=foreign_keys 

3471 ) 

3472 else: 

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

3474 # no memoizations of other FROM clauses. 

3475 # see test_values.py -> test_auto_proxy_select_direct_col 

3476 c._reset_memoizations() 

3477 columns.add(c) 

3478 c.table = self 

3479 

3480 @util.ro_non_memoized_property 

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

3482 return [self] 

3483 

3484 

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

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

3487 COLUMN element in a statement. 

3488 

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

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

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

3492 an ``IN`` or ``NOT IN`` condition. 

3493 

3494 .. versionadded:: 2.0.0b4 

3495 

3496 """ 

3497 

3498 __visit_name__ = "scalar_values" 

3499 

3500 _traverse_internals: _TraverseInternalsType = [ 

3501 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3502 ("_data", InternalTraversal.dp_dml_multi_values), 

3503 ("literal_binds", InternalTraversal.dp_boolean), 

3504 ] 

3505 

3506 def __init__( 

3507 self, 

3508 columns: Sequence[ColumnClause[Any]], 

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

3510 literal_binds: bool, 

3511 ): 

3512 super().__init__() 

3513 self._column_args = columns 

3514 self._data = data 

3515 self.literal_binds = literal_binds 

3516 

3517 @property 

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

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

3520 

3521 def __clause_element__(self) -> ScalarValues: 

3522 return self 

3523 

3524 if TYPE_CHECKING: 

3525 

3526 def self_group( 

3527 self, against: Optional[OperatorType] = None 

3528 ) -> Self: ... 

3529 

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

3531 

3532 

3533class SelectBase( 

3534 roles.SelectStatementRole, 

3535 roles.DMLSelectRole, 

3536 roles.CompoundElementRole, 

3537 roles.InElementRole, 

3538 HasCTE, 

3539 SupportsCloneAnnotations, 

3540 Selectable, 

3541): 

3542 """Base class for SELECT statements. 

3543 

3544 

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

3546 :class:`_expression.CompoundSelect` and 

3547 :class:`_expression.TextualSelect`. 

3548 

3549 

3550 """ 

3551 

3552 _is_select_base = True 

3553 is_select = True 

3554 

3555 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3556 

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

3558 self._reset_memoizations() 

3559 

3560 @util.ro_non_memoized_property 

3561 def selected_columns( 

3562 self, 

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

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

3565 representing the columns that 

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

3567 

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

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

3570 within this collection cannot be directly nested inside another SELECT 

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

3572 necessary parenthesization required by SQL. 

3573 

3574 .. note:: 

3575 

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

3577 include expressions established in the columns clause using the 

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

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

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

3581 construct. 

3582 

3583 .. seealso:: 

3584 

3585 :attr:`_sql.Select.selected_columns` 

3586 

3587 .. versionadded:: 1.4 

3588 

3589 """ 

3590 raise NotImplementedError() 

3591 

3592 def _generate_fromclause_column_proxies( 

3593 self, 

3594 subquery: FromClause, 

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

3596 primary_key: ColumnSet, 

3597 foreign_keys: Set[KeyedColumnElement[Any]], 

3598 *, 

3599 proxy_compound_columns: Optional[ 

3600 Iterable[Sequence[ColumnElement[Any]]] 

3601 ] = None, 

3602 ) -> None: 

3603 raise NotImplementedError() 

3604 

3605 @util.ro_non_memoized_property 

3606 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3609 constructs. 

3610 

3611 .. versionadded:: 1.4.12 

3612 

3613 .. seealso:: 

3614 

3615 :attr:`_sql.SelectBase.exported_columns` 

3616 

3617 """ 

3618 raise NotImplementedError() 

3619 

3620 @property 

3621 def exported_columns( 

3622 self, 

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

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

3625 that represents the "exported" 

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

3627 :class:`_sql.TextClause` constructs. 

3628 

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

3630 object are synonymous 

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

3632 

3633 .. versionadded:: 1.4 

3634 

3635 .. seealso:: 

3636 

3637 :attr:`_expression.Select.exported_columns` 

3638 

3639 :attr:`_expression.Selectable.exported_columns` 

3640 

3641 :attr:`_expression.FromClause.exported_columns` 

3642 

3643 

3644 """ 

3645 return self.selected_columns.as_readonly() 

3646 

3647 def get_label_style(self) -> SelectLabelStyle: 

3648 """ 

3649 Retrieve the current label style. 

3650 

3651 Implemented by subclasses. 

3652 

3653 """ 

3654 raise NotImplementedError() 

3655 

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

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

3658 

3659 Implemented by subclasses. 

3660 

3661 """ 

3662 

3663 raise NotImplementedError() 

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 /, 

4353 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4354 ) -> Self: 

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

4356 criteria applied. 

4357 

4358 e.g.:: 

4359 

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

4361 

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

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

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

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

4366 

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

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

4369 

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

4371 constructs 

4372 which will be used to generate an ORDER BY clause. 

4373 

4374 .. seealso:: 

4375 

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

4377 

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

4379 

4380 """ 

4381 

4382 if not clauses and __first is None: 

4383 self._order_by_clauses = () 

4384 elif __first is not _NoArg.NO_ARG: 

4385 self._order_by_clauses += tuple( 

4386 coercions.expect( 

4387 roles.OrderByRole, clause, apply_propagate_attrs=self 

4388 ) 

4389 for clause in (__first,) + clauses 

4390 ) 

4391 return self 

4392 

4393 @_generative 

4394 def group_by( 

4395 self, 

4396 __first: Union[ 

4397 Literal[None, _NoArg.NO_ARG], 

4398 _ColumnExpressionOrStrLabelArgument[Any], 

4399 ] = _NoArg.NO_ARG, 

4400 /, 

4401 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4402 ) -> Self: 

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

4404 criterion applied. 

4405 

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

4407 

4408 e.g.:: 

4409 

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

4411 

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

4413 constructs 

4414 which will be used to generate an GROUP BY clause. 

4415 

4416 .. seealso:: 

4417 

4418 :ref:`tutorial_group_by_w_aggregates` - in the 

4419 :ref:`unified_tutorial` 

4420 

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

4422 

4423 """ # noqa: E501 

4424 

4425 if not clauses and __first is None: 

4426 self._group_by_clauses = () 

4427 elif __first is not _NoArg.NO_ARG: 

4428 self._group_by_clauses += tuple( 

4429 coercions.expect( 

4430 roles.GroupByRole, clause, apply_propagate_attrs=self 

4431 ) 

4432 for clause in (__first,) + clauses 

4433 ) 

4434 return self 

4435 

4436 

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

4438class CompoundSelectState(CompileState): 

4439 @util.memoized_property 

4440 def _label_resolve_dict( 

4441 self, 

4442 ) -> Tuple[ 

4443 Dict[str, ColumnElement[Any]], 

4444 Dict[str, ColumnElement[Any]], 

4445 Dict[str, ColumnElement[Any]], 

4446 ]: 

4447 # TODO: this is hacky and slow 

4448 hacky_subquery = self.statement.subquery() 

4449 hacky_subquery.named_with_column = False 

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

4451 return d, d, d 

4452 

4453 

4454class _CompoundSelectKeyword(Enum): 

4455 UNION = "UNION" 

4456 UNION_ALL = "UNION ALL" 

4457 EXCEPT = "EXCEPT" 

4458 EXCEPT_ALL = "EXCEPT ALL" 

4459 INTERSECT = "INTERSECT" 

4460 INTERSECT_ALL = "INTERSECT ALL" 

4461 

4462 

4463class CompoundSelect( 

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

4465): 

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

4467 SELECT-based set operations. 

4468 

4469 

4470 .. seealso:: 

4471 

4472 :func:`_expression.union` 

4473 

4474 :func:`_expression.union_all` 

4475 

4476 :func:`_expression.intersect` 

4477 

4478 :func:`_expression.intersect_all` 

4479 

4480 :func:`_expression.except` 

4481 

4482 :func:`_expression.except_all` 

4483 

4484 """ 

4485 

4486 __visit_name__ = "compound_select" 

4487 

4488 _traverse_internals: _TraverseInternalsType = ( 

4489 [ 

4490 ("selects", InternalTraversal.dp_clauseelement_list), 

4491 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4492 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4493 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4494 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4495 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4496 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4497 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4498 ("keyword", InternalTraversal.dp_string), 

4499 ] 

4500 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4501 + HasCTE._has_ctes_traverse_internals 

4502 + DialectKWArgs._dialect_kwargs_traverse_internals 

4503 ) 

4504 

4505 selects: List[SelectBase] 

4506 

4507 _is_from_container = True 

4508 _auto_correlate = False 

4509 

4510 def __init__( 

4511 self, 

4512 keyword: _CompoundSelectKeyword, 

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

4514 ): 

4515 self.keyword = keyword 

4516 self.selects = [ 

4517 coercions.expect( 

4518 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4519 ).self_group(against=self) 

4520 for s in selects 

4521 ] 

4522 

4523 GenerativeSelect.__init__(self) 

4524 

4525 @classmethod 

4526 def _create_union( 

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

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

4529 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4530 

4531 @classmethod 

4532 def _create_union_all( 

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

4534 ) -> CompoundSelect[Unpack[_Ts]]: 

4535 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4536 

4537 @classmethod 

4538 def _create_except( 

4539 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4540 ) -> CompoundSelect[Unpack[_Ts]]: 

4541 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4542 

4543 @classmethod 

4544 def _create_except_all( 

4545 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4546 ) -> CompoundSelect[Unpack[_Ts]]: 

4547 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4548 

4549 @classmethod 

4550 def _create_intersect( 

4551 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4552 ) -> CompoundSelect[Unpack[_Ts]]: 

4553 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4554 

4555 @classmethod 

4556 def _create_intersect_all( 

4557 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4558 ) -> CompoundSelect[Unpack[_Ts]]: 

4559 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4560 

4561 def _scalar_type(self) -> TypeEngine[Any]: 

4562 return self.selects[0]._scalar_type() 

4563 

4564 def self_group( 

4565 self, against: Optional[OperatorType] = None 

4566 ) -> GroupedElement: 

4567 return SelectStatementGrouping(self) 

4568 

4569 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

4570 for s in self.selects: 

4571 if s.is_derived_from(fromclause): 

4572 return True 

4573 return False 

4574 

4575 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4576 if self._label_style is not style: 

4577 self = self._generate() 

4578 select_0 = self.selects[0].set_label_style(style) 

4579 self.selects = [select_0] + self.selects[1:] 

4580 

4581 return self 

4582 

4583 def _ensure_disambiguated_names(self) -> Self: 

4584 new_select = self.selects[0]._ensure_disambiguated_names() 

4585 if new_select is not self.selects[0]: 

4586 self = self._generate() 

4587 self.selects = [new_select] + self.selects[1:] 

4588 

4589 return self 

4590 

4591 def _generate_fromclause_column_proxies( 

4592 self, 

4593 subquery: FromClause, 

4594 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

4595 primary_key: ColumnSet, 

4596 foreign_keys: Set[KeyedColumnElement[Any]], 

4597 *, 

4598 proxy_compound_columns: Optional[ 

4599 Iterable[Sequence[ColumnElement[Any]]] 

4600 ] = None, 

4601 ) -> None: 

4602 # this is a slightly hacky thing - the union exports a 

4603 # column that resembles just that of the *first* selectable. 

4604 # to get at a "composite" column, particularly foreign keys, 

4605 # you have to dig through the proxies collection which we 

4606 # generate below. 

4607 select_0 = self.selects[0] 

4608 

4609 if self._label_style is not LABEL_STYLE_DEFAULT: 

4610 select_0 = select_0.set_label_style(self._label_style) 

4611 

4612 # hand-construct the "_proxies" collection to include all 

4613 # derived columns place a 'weight' annotation corresponding 

4614 # to how low in the list of select()s the column occurs, so 

4615 # that the corresponding_column() operation can resolve 

4616 # conflicts 

4617 extra_col_iterator = zip( 

4618 *[ 

4619 [ 

4620 c._annotate(dd) 

4621 for c in stmt._all_selected_columns 

4622 if is_column_element(c) 

4623 ] 

4624 for dd, stmt in [ 

4625 ({"weight": i + 1}, stmt) 

4626 for i, stmt in enumerate(self.selects) 

4627 ] 

4628 ] 

4629 ) 

4630 

4631 # the incoming proxy_compound_columns can be present also if this is 

4632 # a compound embedded in a compound. it's probably more appropriate 

4633 # that we generate new weights local to this nested compound, though 

4634 # i haven't tried to think what it means for compound nested in 

4635 # compound 

4636 select_0._generate_fromclause_column_proxies( 

4637 subquery, 

4638 columns, 

4639 proxy_compound_columns=extra_col_iterator, 

4640 primary_key=primary_key, 

4641 foreign_keys=foreign_keys, 

4642 ) 

4643 

4644 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

4645 super()._refresh_for_new_column(column) 

4646 for select in self.selects: 

4647 select._refresh_for_new_column(column) 

4648 

4649 @util.ro_non_memoized_property 

4650 def _all_selected_columns(self) -> _SelectIterable: 

4651 return self.selects[0]._all_selected_columns 

4652 

4653 @util.ro_non_memoized_property 

4654 def selected_columns( 

4655 self, 

4656 ) -> ColumnCollection[str, ColumnElement[Any]]: 

4657 """A :class:`_expression.ColumnCollection` 

4658 representing the columns that 

4659 this SELECT statement or similar construct returns in its result set, 

4660 not including :class:`_sql.TextClause` constructs. 

4661 

4662 For a :class:`_expression.CompoundSelect`, the 

4663 :attr:`_expression.CompoundSelect.selected_columns` 

4664 attribute returns the selected 

4665 columns of the first SELECT statement contained within the series of 

4666 statements within the set operation. 

4667 

4668 .. seealso:: 

4669 

4670 :attr:`_sql.Select.selected_columns` 

4671 

4672 .. versionadded:: 1.4 

4673 

4674 """ 

4675 return self.selects[0].selected_columns 

4676 

4677 

4678# backwards compat 

4679for elem in _CompoundSelectKeyword: 

4680 setattr(CompoundSelect, elem.name, elem) 

4681 

4682 

4683@CompileState.plugin_for("default", "select") 

4684class SelectState(util.MemoizedSlots, CompileState): 

4685 __slots__ = ( 

4686 "from_clauses", 

4687 "froms", 

4688 "columns_plus_names", 

4689 "_label_resolve_dict", 

4690 ) 

4691 

4692 if TYPE_CHECKING: 

4693 default_select_compile_options: CacheableOptions 

4694 else: 

4695 

4696 class default_select_compile_options(CacheableOptions): 

4697 _cache_key_traversal = [] 

4698 

4699 if TYPE_CHECKING: 

4700 

4701 @classmethod 

4702 def get_plugin_class( 

4703 cls, statement: Executable 

4704 ) -> Type[SelectState]: ... 

4705 

4706 def __init__( 

4707 self, 

4708 statement: Select[Unpack[TupleAny]], 

4709 compiler: SQLCompiler, 

4710 **kw: Any, 

4711 ): 

4712 self.statement = statement 

4713 self.from_clauses = statement._from_obj 

4714 

4715 for memoized_entities in statement._memoized_select_entities: 

4716 self._setup_joins( 

4717 memoized_entities._setup_joins, memoized_entities._raw_columns 

4718 ) 

4719 

4720 if statement._setup_joins: 

4721 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4722 

4723 self.froms = self._get_froms(statement) 

4724 

4725 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4726 

4727 @classmethod 

4728 def _plugin_not_implemented(cls) -> NoReturn: 

4729 raise NotImplementedError( 

4730 "The default SELECT construct without plugins does not " 

4731 "implement this method." 

4732 ) 

4733 

4734 @classmethod 

4735 def get_column_descriptions( 

4736 cls, statement: Select[Unpack[TupleAny]] 

4737 ) -> List[Dict[str, Any]]: 

4738 return [ 

4739 { 

4740 "name": name, 

4741 "type": element.type, 

4742 "expr": element, 

4743 } 

4744 for _, name, _, element, _ in ( 

4745 statement._generate_columns_plus_names(False) 

4746 ) 

4747 ] 

4748 

4749 @classmethod 

4750 def from_statement( 

4751 cls, 

4752 statement: Select[Unpack[TupleAny]], 

4753 from_statement: roles.ReturnsRowsRole, 

4754 ) -> ExecutableReturnsRows: 

4755 cls._plugin_not_implemented() 

4756 

4757 @classmethod 

4758 def get_columns_clause_froms( 

4759 cls, statement: Select[Unpack[TupleAny]] 

4760 ) -> List[FromClause]: 

4761 return cls._normalize_froms( 

4762 itertools.chain.from_iterable( 

4763 element._from_objects for element in statement._raw_columns 

4764 ) 

4765 ) 

4766 

4767 @classmethod 

4768 def _column_naming_convention( 

4769 cls, label_style: SelectLabelStyle 

4770 ) -> _LabelConventionCallable: 

4771 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4772 

4773 dedupe = label_style is not LABEL_STYLE_NONE 

4774 

4775 pa = prefix_anon_map() 

4776 names = set() 

4777 

4778 def go( 

4779 c: Union[ColumnElement[Any], TextClause], 

4780 col_name: Optional[str] = None, 

4781 ) -> Optional[str]: 

4782 if is_text_clause(c): 

4783 return None 

4784 elif TYPE_CHECKING: 

4785 assert is_column_element(c) 

4786 

4787 if not dedupe: 

4788 name = c._proxy_key 

4789 if name is None: 

4790 name = "_no_label" 

4791 return name 

4792 

4793 name = c._tq_key_label if table_qualified else c._proxy_key 

4794 

4795 if name is None: 

4796 name = "_no_label" 

4797 if name in names: 

4798 return c._anon_label(name) % pa 

4799 else: 

4800 names.add(name) 

4801 return name 

4802 

4803 elif name in names: 

4804 return ( 

4805 c._anon_tq_key_label % pa 

4806 if table_qualified 

4807 else c._anon_key_label % pa 

4808 ) 

4809 else: 

4810 names.add(name) 

4811 return name 

4812 

4813 return go 

4814 

4815 def _get_froms( 

4816 self, statement: Select[Unpack[TupleAny]] 

4817 ) -> List[FromClause]: 

4818 ambiguous_table_name_map: _AmbiguousTableNameMap 

4819 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4820 

4821 return self._normalize_froms( 

4822 itertools.chain( 

4823 self.from_clauses, 

4824 itertools.chain.from_iterable( 

4825 [ 

4826 element._from_objects 

4827 for element in statement._raw_columns 

4828 ] 

4829 ), 

4830 itertools.chain.from_iterable( 

4831 [ 

4832 element._from_objects 

4833 for element in statement._where_criteria 

4834 ] 

4835 ), 

4836 ), 

4837 check_statement=statement, 

4838 ambiguous_table_name_map=ambiguous_table_name_map, 

4839 ) 

4840 

4841 @classmethod 

4842 def _normalize_froms( 

4843 cls, 

4844 iterable_of_froms: Iterable[FromClause], 

4845 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4846 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4847 ) -> List[FromClause]: 

4848 """given an iterable of things to select FROM, reduce them to what 

4849 would actually render in the FROM clause of a SELECT. 

4850 

4851 This does the job of checking for JOINs, tables, etc. that are in fact 

4852 overlapping due to cloning, adaption, present in overlapping joins, 

4853 etc. 

4854 

4855 """ 

4856 seen: Set[FromClause] = set() 

4857 froms: List[FromClause] = [] 

4858 

4859 for item in iterable_of_froms: 

4860 if is_subquery(item) and item.element is check_statement: 

4861 raise exc.InvalidRequestError( 

4862 "select() construct refers to itself as a FROM" 

4863 ) 

4864 

4865 if not seen.intersection(item._cloned_set): 

4866 froms.append(item) 

4867 seen.update(item._cloned_set) 

4868 

4869 if froms: 

4870 toremove = set( 

4871 itertools.chain.from_iterable( 

4872 [_expand_cloned(f._hide_froms) for f in froms] 

4873 ) 

4874 ) 

4875 if toremove: 

4876 # filter out to FROM clauses not in the list, 

4877 # using a list to maintain ordering 

4878 froms = [f for f in froms if f not in toremove] 

4879 

4880 if ambiguous_table_name_map is not None: 

4881 ambiguous_table_name_map.update( 

4882 ( 

4883 fr.name, 

4884 _anonymous_label.safe_construct( 

4885 hash(fr.name), fr.name 

4886 ), 

4887 ) 

4888 for item in froms 

4889 for fr in item._from_objects 

4890 if is_table(fr) 

4891 and fr.schema 

4892 and fr.name not in ambiguous_table_name_map 

4893 ) 

4894 

4895 return froms 

4896 

4897 def _get_display_froms( 

4898 self, 

4899 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4900 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4901 ) -> List[FromClause]: 

4902 """Return the full list of 'from' clauses to be displayed. 

4903 

4904 Takes into account a set of existing froms which may be 

4905 rendered in the FROM clause of enclosing selects; this Select 

4906 may want to leave those absent if it is automatically 

4907 correlating. 

4908 

4909 """ 

4910 

4911 froms = self.froms 

4912 

4913 if self.statement._correlate: 

4914 to_correlate = self.statement._correlate 

4915 if to_correlate: 

4916 froms = [ 

4917 f 

4918 for f in froms 

4919 if f 

4920 not in _cloned_intersection( 

4921 _cloned_intersection( 

4922 froms, explicit_correlate_froms or () 

4923 ), 

4924 to_correlate, 

4925 ) 

4926 ] 

4927 

4928 if self.statement._correlate_except is not None: 

4929 froms = [ 

4930 f 

4931 for f in froms 

4932 if f 

4933 not in _cloned_difference( 

4934 _cloned_intersection( 

4935 froms, explicit_correlate_froms or () 

4936 ), 

4937 self.statement._correlate_except, 

4938 ) 

4939 ] 

4940 

4941 if ( 

4942 self.statement._auto_correlate 

4943 and implicit_correlate_froms 

4944 and len(froms) > 1 

4945 ): 

4946 froms = [ 

4947 f 

4948 for f in froms 

4949 if f 

4950 not in _cloned_intersection(froms, implicit_correlate_froms) 

4951 ] 

4952 

4953 if not len(froms): 

4954 raise exc.InvalidRequestError( 

4955 "Select statement '%r" 

4956 "' returned no FROM clauses " 

4957 "due to auto-correlation; " 

4958 "specify correlate(<tables>) " 

4959 "to control correlation " 

4960 "manually." % self.statement 

4961 ) 

4962 

4963 return froms 

4964 

4965 def _memoized_attr__label_resolve_dict( 

4966 self, 

4967 ) -> Tuple[ 

4968 Dict[str, ColumnElement[Any]], 

4969 Dict[str, ColumnElement[Any]], 

4970 Dict[str, ColumnElement[Any]], 

4971 ]: 

4972 with_cols: Dict[str, ColumnElement[Any]] = { 

4973 c._tq_label or c.key: c 

4974 for c in self.statement._all_selected_columns 

4975 if c._allow_label_resolve 

4976 } 

4977 only_froms: Dict[str, ColumnElement[Any]] = { 

4978 c.key: c # type: ignore 

4979 for c in _select_iterables(self.froms) 

4980 if c._allow_label_resolve 

4981 } 

4982 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

4983 for key, value in only_froms.items(): 

4984 with_cols.setdefault(key, value) 

4985 

4986 return with_cols, only_froms, only_cols 

4987 

4988 @classmethod 

4989 def determine_last_joined_entity( 

4990 cls, stmt: Select[Unpack[TupleAny]] 

4991 ) -> Optional[_JoinTargetElement]: 

4992 if stmt._setup_joins: 

4993 return stmt._setup_joins[-1][0] 

4994 else: 

4995 return None 

4996 

4997 @classmethod 

4998 def all_selected_columns( 

4999 cls, statement: Select[Unpack[TupleAny]] 

5000 ) -> _SelectIterable: 

5001 return [c for c in _select_iterables(statement._raw_columns)] 

5002 

5003 def _setup_joins( 

5004 self, 

5005 args: Tuple[_SetupJoinsElement, ...], 

5006 raw_columns: List[_ColumnsClauseElement], 

5007 ) -> None: 

5008 for right, onclause, left, flags in args: 

5009 if TYPE_CHECKING: 

5010 if onclause is not None: 

5011 assert isinstance(onclause, ColumnElement) 

5012 

5013 isouter = flags["isouter"] 

5014 full = flags["full"] 

5015 

5016 if left is None: 

5017 ( 

5018 left, 

5019 replace_from_obj_index, 

5020 ) = self._join_determine_implicit_left_side( 

5021 raw_columns, left, right, onclause 

5022 ) 

5023 else: 

5024 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5025 left 

5026 ) 

5027 

5028 # these assertions can be made here, as if the right/onclause 

5029 # contained ORM elements, the select() statement would have been 

5030 # upgraded to an ORM select, and this method would not be called; 

5031 # orm.context.ORMSelectCompileState._join() would be 

5032 # used instead. 

5033 if TYPE_CHECKING: 

5034 assert isinstance(right, FromClause) 

5035 if onclause is not None: 

5036 assert isinstance(onclause, ColumnElement) 

5037 

5038 if replace_from_obj_index is not None: 

5039 # splice into an existing element in the 

5040 # self._from_obj list 

5041 left_clause = self.from_clauses[replace_from_obj_index] 

5042 

5043 self.from_clauses = ( 

5044 self.from_clauses[:replace_from_obj_index] 

5045 + ( 

5046 Join( 

5047 left_clause, 

5048 right, 

5049 onclause, 

5050 isouter=isouter, 

5051 full=full, 

5052 ), 

5053 ) 

5054 + self.from_clauses[replace_from_obj_index + 1 :] 

5055 ) 

5056 else: 

5057 assert left is not None 

5058 self.from_clauses = self.from_clauses + ( 

5059 Join(left, right, onclause, isouter=isouter, full=full), 

5060 ) 

5061 

5062 @util.preload_module("sqlalchemy.sql.util") 

5063 def _join_determine_implicit_left_side( 

5064 self, 

5065 raw_columns: List[_ColumnsClauseElement], 

5066 left: Optional[FromClause], 

5067 right: _JoinTargetElement, 

5068 onclause: Optional[ColumnElement[Any]], 

5069 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5070 """When join conditions don't express the left side explicitly, 

5071 determine if an existing FROM or entity in this query 

5072 can serve as the left hand side. 

5073 

5074 """ 

5075 

5076 sql_util = util.preloaded.sql_util 

5077 

5078 replace_from_obj_index: Optional[int] = None 

5079 

5080 from_clauses = self.from_clauses 

5081 

5082 if from_clauses: 

5083 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5084 from_clauses, right, onclause 

5085 ) 

5086 

5087 if len(indexes) == 1: 

5088 replace_from_obj_index = indexes[0] 

5089 left = from_clauses[replace_from_obj_index] 

5090 else: 

5091 potential = {} 

5092 statement = self.statement 

5093 

5094 for from_clause in itertools.chain( 

5095 itertools.chain.from_iterable( 

5096 [element._from_objects for element in raw_columns] 

5097 ), 

5098 itertools.chain.from_iterable( 

5099 [ 

5100 element._from_objects 

5101 for element in statement._where_criteria 

5102 ] 

5103 ), 

5104 ): 

5105 potential[from_clause] = () 

5106 

5107 all_clauses = list(potential.keys()) 

5108 indexes = sql_util.find_left_clause_to_join_from( 

5109 all_clauses, right, onclause 

5110 ) 

5111 

5112 if len(indexes) == 1: 

5113 left = all_clauses[indexes[0]] 

5114 

5115 if len(indexes) > 1: 

5116 raise exc.InvalidRequestError( 

5117 "Can't determine which FROM clause to join " 

5118 "from, there are multiple FROMS which can " 

5119 "join to this entity. Please use the .select_from() " 

5120 "method to establish an explicit left side, as well as " 

5121 "providing an explicit ON clause if not present already to " 

5122 "help resolve the ambiguity." 

5123 ) 

5124 elif not indexes: 

5125 raise exc.InvalidRequestError( 

5126 "Don't know how to join to %r. " 

5127 "Please use the .select_from() " 

5128 "method to establish an explicit left side, as well as " 

5129 "providing an explicit ON clause if not present already to " 

5130 "help resolve the ambiguity." % (right,) 

5131 ) 

5132 return left, replace_from_obj_index 

5133 

5134 @util.preload_module("sqlalchemy.sql.util") 

5135 def _join_place_explicit_left_side( 

5136 self, left: FromClause 

5137 ) -> Optional[int]: 

5138 replace_from_obj_index: Optional[int] = None 

5139 

5140 sql_util = util.preloaded.sql_util 

5141 

5142 from_clauses = list(self.statement._iterate_from_elements()) 

5143 

5144 if from_clauses: 

5145 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5146 self.from_clauses, left 

5147 ) 

5148 else: 

5149 indexes = [] 

5150 

5151 if len(indexes) > 1: 

5152 raise exc.InvalidRequestError( 

5153 "Can't identify which entity in which to assign the " 

5154 "left side of this join. Please use a more specific " 

5155 "ON clause." 

5156 ) 

5157 

5158 # have an index, means the left side is already present in 

5159 # an existing FROM in the self._from_obj tuple 

5160 if indexes: 

5161 replace_from_obj_index = indexes[0] 

5162 

5163 # no index, means we need to add a new element to the 

5164 # self._from_obj tuple 

5165 

5166 return replace_from_obj_index 

5167 

5168 

5169class _SelectFromElements: 

5170 __slots__ = () 

5171 

5172 _raw_columns: List[_ColumnsClauseElement] 

5173 _where_criteria: Tuple[ColumnElement[Any], ...] 

5174 _from_obj: Tuple[FromClause, ...] 

5175 

5176 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5177 # note this does not include elements 

5178 # in _setup_joins 

5179 

5180 seen = set() 

5181 for element in self._raw_columns: 

5182 for fr in element._from_objects: 

5183 if fr in seen: 

5184 continue 

5185 seen.add(fr) 

5186 yield fr 

5187 for element in self._where_criteria: 

5188 for fr in element._from_objects: 

5189 if fr in seen: 

5190 continue 

5191 seen.add(fr) 

5192 yield fr 

5193 for element in self._from_obj: 

5194 if element in seen: 

5195 continue 

5196 seen.add(element) 

5197 yield element 

5198 

5199 

5200class _MemoizedSelectEntities( 

5201 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5202): 

5203 """represents partial state from a Select object, for the case 

5204 where Select.columns() has redefined the set of columns/entities the 

5205 statement will be SELECTing from. This object represents 

5206 the entities from the SELECT before that transformation was applied, 

5207 so that transformations that were made in terms of the SELECT at that 

5208 time, such as join() as well as options(), can access the correct context. 

5209 

5210 In previous SQLAlchemy versions, this wasn't needed because these 

5211 constructs calculated everything up front, like when you called join() 

5212 or options(), it did everything to figure out how that would translate 

5213 into specific SQL constructs that would be ready to send directly to the 

5214 SQL compiler when needed. But as of 

5215 1.4, all of that stuff is done in the compilation phase, during the 

5216 "compile state" portion of the process, so that the work can all be 

5217 cached. So it needs to be able to resolve joins/options2 based on what 

5218 the list of entities was when those methods were called. 

5219 

5220 

5221 """ 

5222 

5223 __visit_name__ = "memoized_select_entities" 

5224 

5225 _traverse_internals: _TraverseInternalsType = [ 

5226 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5227 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5228 ("_with_options", InternalTraversal.dp_executable_options), 

5229 ] 

5230 

5231 _is_clone_of: Optional[ClauseElement] 

5232 _raw_columns: List[_ColumnsClauseElement] 

5233 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5234 _with_options: Tuple[ExecutableOption, ...] 

5235 

5236 _annotations = util.EMPTY_DICT 

5237 

5238 def _clone(self, **kw: Any) -> Self: 

5239 c = self.__class__.__new__(self.__class__) 

5240 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5241 

5242 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5243 return c 

5244 

5245 @classmethod 

5246 def _generate_for_statement( 

5247 cls, select_stmt: Select[Unpack[TupleAny]] 

5248 ) -> None: 

5249 if select_stmt._setup_joins or select_stmt._with_options: 

5250 self = _MemoizedSelectEntities() 

5251 self._raw_columns = select_stmt._raw_columns 

5252 self._setup_joins = select_stmt._setup_joins 

5253 self._with_options = select_stmt._with_options 

5254 

5255 select_stmt._memoized_select_entities += (self,) 

5256 select_stmt._raw_columns = [] 

5257 select_stmt._setup_joins = select_stmt._with_options = () 

5258 

5259 

5260class Select( 

5261 HasPrefixes, 

5262 HasSuffixes, 

5263 HasHints, 

5264 HasCompileState, 

5265 HasSyntaxExtensions[ 

5266 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5267 ], 

5268 _SelectFromElements, 

5269 GenerativeSelect, 

5270 TypedReturnsRows[Unpack[_Ts]], 

5271): 

5272 """Represents a ``SELECT`` statement. 

5273 

5274 The :class:`_sql.Select` object is normally constructed using the 

5275 :func:`_sql.select` function. See that function for details. 

5276 

5277 Available extension points: 

5278 

5279 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5280 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5281 keyword (if any) and the list of columns. 

5282 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5283 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5284 

5285 .. seealso:: 

5286 

5287 :func:`_sql.select` 

5288 

5289 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5290 

5291 """ 

5292 

5293 __visit_name__ = "select" 

5294 

5295 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5296 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5297 

5298 _raw_columns: List[_ColumnsClauseElement] 

5299 

5300 _distinct: bool = False 

5301 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5302 _correlate: Tuple[FromClause, ...] = () 

5303 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5304 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5305 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5306 _from_obj: Tuple[FromClause, ...] = () 

5307 

5308 _position_map = util.immutabledict( 

5309 { 

5310 "post_select": "_post_select_clause", 

5311 "pre_columns": "_pre_columns_clause", 

5312 "post_criteria": "_post_criteria_clause", 

5313 "post_body": "_post_body_clause", 

5314 } 

5315 ) 

5316 

5317 _post_select_clause: Optional[ClauseElement] = None 

5318 """extension point for a ClauseElement that will be compiled directly 

5319 after the SELECT keyword. 

5320 

5321 .. versionadded:: 2.1 

5322 

5323 """ 

5324 

5325 _pre_columns_clause: Optional[ClauseElement] = None 

5326 """extension point for a ClauseElement that will be compiled directly 

5327 before the "columns" clause; after DISTINCT (if present). 

5328 

5329 .. versionadded:: 2.1 

5330 

5331 """ 

5332 

5333 _post_criteria_clause: Optional[ClauseElement] = None 

5334 """extension point for a ClauseElement that will be compiled directly 

5335 after "criteria", following the HAVING clause but before ORDER BY. 

5336 

5337 .. versionadded:: 2.1 

5338 

5339 """ 

5340 

5341 _post_body_clause: Optional[ClauseElement] = None 

5342 """extension point for a ClauseElement that will be compiled directly 

5343 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5344 of the SELECT. 

5345 

5346 .. versionadded:: 2.1 

5347 

5348 """ 

5349 

5350 _auto_correlate = True 

5351 _is_select_statement = True 

5352 _compile_options: CacheableOptions = ( 

5353 SelectState.default_select_compile_options 

5354 ) 

5355 

5356 _traverse_internals: _TraverseInternalsType = ( 

5357 [ 

5358 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5359 ( 

5360 "_memoized_select_entities", 

5361 InternalTraversal.dp_memoized_select_entities, 

5362 ), 

5363 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5364 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5365 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5366 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5367 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5368 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5369 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5370 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5371 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5372 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5373 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5374 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5375 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5376 ("_distinct", InternalTraversal.dp_boolean), 

5377 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5378 ("_label_style", InternalTraversal.dp_plain_obj), 

5379 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5380 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5381 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5382 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5383 ] 

5384 + HasCTE._has_ctes_traverse_internals 

5385 + HasPrefixes._has_prefixes_traverse_internals 

5386 + HasSuffixes._has_suffixes_traverse_internals 

5387 + HasHints._has_hints_traverse_internals 

5388 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5389 + Executable._executable_traverse_internals 

5390 + DialectKWArgs._dialect_kwargs_traverse_internals 

5391 ) 

5392 

5393 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5394 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5395 ] 

5396 

5397 _compile_state_factory: Type[SelectState] 

5398 

5399 @classmethod 

5400 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5401 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5402 

5403 Used internally to build up :class:`.Select` constructs with 

5404 pre-established state. 

5405 

5406 """ 

5407 

5408 stmt = Select.__new__(Select) 

5409 stmt.__dict__.update(kw) 

5410 return stmt 

5411 

5412 def __init__( 

5413 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5414 ): 

5415 r"""Construct a new :class:`_expression.Select`. 

5416 

5417 The public constructor for :class:`_expression.Select` is the 

5418 :func:`_sql.select` function. 

5419 

5420 """ 

5421 self._raw_columns = [ 

5422 coercions.expect( 

5423 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5424 ) 

5425 for ent in entities 

5426 ] 

5427 GenerativeSelect.__init__(self) 

5428 

5429 def _apply_syntax_extension_to_self( 

5430 self, extension: SyntaxExtension 

5431 ) -> None: 

5432 extension.apply_to_select(self) 

5433 

5434 def _scalar_type(self) -> TypeEngine[Any]: 

5435 if not self._raw_columns: 

5436 return NULLTYPE 

5437 elem = self._raw_columns[0] 

5438 cols = list(elem._select_iterable) 

5439 return cols[0].type 

5440 

5441 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5442 """A synonym for the :meth:`_sql.Select.where` method.""" 

5443 

5444 return self.where(*criteria) 

5445 

5446 def _filter_by_zero( 

5447 self, 

5448 ) -> Union[ 

5449 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5450 ]: 

5451 if self._setup_joins: 

5452 meth = SelectState.get_plugin_class( 

5453 self 

5454 ).determine_last_joined_entity 

5455 _last_joined_entity = meth(self) 

5456 if _last_joined_entity is not None: 

5457 return _last_joined_entity 

5458 

5459 if self._from_obj: 

5460 return self._from_obj[0] 

5461 

5462 return self._raw_columns[0] 

5463 

5464 if TYPE_CHECKING: 

5465 

5466 @overload 

5467 def scalar_subquery( 

5468 self: Select[_MAYBE_ENTITY], 

5469 ) -> ScalarSelect[Any]: ... 

5470 

5471 @overload 

5472 def scalar_subquery( 

5473 self: Select[_NOT_ENTITY], 

5474 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5475 

5476 @overload 

5477 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5478 

5479 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5480 

5481 def filter_by(self, **kwargs: Any) -> Self: 

5482 r"""apply the given filtering criterion as a WHERE clause 

5483 to this select. 

5484 

5485 """ 

5486 from_entity = self._filter_by_zero() 

5487 

5488 clauses = [ 

5489 _entity_namespace_key(from_entity, key) == value 

5490 for key, value in kwargs.items() 

5491 ] 

5492 return self.filter(*clauses) 

5493 

5494 @property 

5495 def column_descriptions(self) -> Any: 

5496 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5497 referring to the columns which are SELECTed by this statement. 

5498 

5499 This attribute is generally useful when using the ORM, as an 

5500 extended structure which includes information about mapped 

5501 entities is returned. The section :ref:`queryguide_inspection` 

5502 contains more background. 

5503 

5504 For a Core-only statement, the structure returned by this accessor 

5505 is derived from the same objects that are returned by the 

5506 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5507 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5508 which indicate the column expressions to be selected:: 

5509 

5510 >>> stmt = select(user_table) 

5511 >>> stmt.column_descriptions 

5512 [ 

5513 { 

5514 'name': 'id', 

5515 'type': Integer(), 

5516 'expr': Column('id', Integer(), ...)}, 

5517 { 

5518 'name': 'name', 

5519 'type': String(length=30), 

5520 'expr': Column('name', String(length=30), ...)} 

5521 ] 

5522 

5523 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5524 attribute returns a structure for a Core-only set of entities, 

5525 not just ORM-only entities. 

5526 

5527 .. seealso:: 

5528 

5529 :attr:`.UpdateBase.entity_description` - entity information for 

5530 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5531 

5532 :ref:`queryguide_inspection` - ORM background 

5533 

5534 """ 

5535 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5536 return meth(self) 

5537 

5538 def from_statement( 

5539 self, statement: roles.ReturnsRowsRole 

5540 ) -> ExecutableReturnsRows: 

5541 """Apply the columns which this :class:`.Select` would select 

5542 onto another statement. 

5543 

5544 This operation is :term:`plugin-specific` and will raise a not 

5545 supported exception if this :class:`_sql.Select` does not select from 

5546 plugin-enabled entities. 

5547 

5548 

5549 The statement is typically either a :func:`_expression.text` or 

5550 :func:`_expression.select` construct, and should return the set of 

5551 columns appropriate to the entities represented by this 

5552 :class:`.Select`. 

5553 

5554 .. seealso:: 

5555 

5556 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5557 ORM Querying Guide 

5558 

5559 """ 

5560 meth = SelectState.get_plugin_class(self).from_statement 

5561 return meth(self, statement) 

5562 

5563 @_generative 

5564 def join( 

5565 self, 

5566 target: _JoinTargetArgument, 

5567 onclause: Optional[_OnClauseArgument] = None, 

5568 *, 

5569 isouter: bool = False, 

5570 full: bool = False, 

5571 ) -> Self: 

5572 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5573 object's criterion 

5574 and apply generatively, returning the newly resulting 

5575 :class:`_expression.Select`. 

5576 

5577 E.g.:: 

5578 

5579 stmt = select(user_table).join( 

5580 address_table, user_table.c.id == address_table.c.user_id 

5581 ) 

5582 

5583 The above statement generates SQL similar to: 

5584 

5585 .. sourcecode:: sql 

5586 

5587 SELECT user.id, user.name 

5588 FROM user 

5589 JOIN address ON user.id = address.user_id 

5590 

5591 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5592 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5593 source that is within the FROM clause of the existing SELECT, 

5594 and a given target :class:`_sql.FromClause`, and then adds 

5595 this :class:`_sql.Join` to the FROM clause of the newly generated 

5596 SELECT statement. This is completely reworked from the behavior 

5597 in 1.3, which would instead create a subquery of the entire 

5598 :class:`_expression.Select` and then join that subquery to the 

5599 target. 

5600 

5601 This is a **backwards incompatible change** as the previous behavior 

5602 was mostly useless, producing an unnamed subquery rejected by 

5603 most databases in any case. The new behavior is modeled after 

5604 that of the very successful :meth:`_orm.Query.join` method in the 

5605 ORM, in order to support the functionality of :class:`_orm.Query` 

5606 being available by using a :class:`_sql.Select` object with an 

5607 :class:`_orm.Session`. 

5608 

5609 See the notes for this change at :ref:`change_select_join`. 

5610 

5611 

5612 :param target: target table to join towards 

5613 

5614 :param onclause: ON clause of the join. If omitted, an ON clause 

5615 is generated automatically based on the :class:`_schema.ForeignKey` 

5616 linkages between the two tables, if one can be unambiguously 

5617 determined, otherwise an error is raised. 

5618 

5619 :param isouter: if True, generate LEFT OUTER join. Same as 

5620 :meth:`_expression.Select.outerjoin`. 

5621 

5622 :param full: if True, generate FULL OUTER join. 

5623 

5624 .. seealso:: 

5625 

5626 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5627 

5628 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5629 

5630 :meth:`_expression.Select.join_from` 

5631 

5632 :meth:`_expression.Select.outerjoin` 

5633 

5634 """ # noqa: E501 

5635 join_target = coercions.expect( 

5636 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5637 ) 

5638 if onclause is not None: 

5639 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5640 else: 

5641 onclause_element = None 

5642 

5643 self._setup_joins += ( 

5644 ( 

5645 join_target, 

5646 onclause_element, 

5647 None, 

5648 {"isouter": isouter, "full": full}, 

5649 ), 

5650 ) 

5651 return self 

5652 

5653 def outerjoin_from( 

5654 self, 

5655 from_: _FromClauseArgument, 

5656 target: _JoinTargetArgument, 

5657 onclause: Optional[_OnClauseArgument] = None, 

5658 *, 

5659 full: bool = False, 

5660 ) -> Self: 

5661 r"""Create a SQL LEFT OUTER JOIN against this 

5662 :class:`_expression.Select` object's criterion and apply generatively, 

5663 returning the newly resulting :class:`_expression.Select`. 

5664 

5665 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5666 

5667 """ 

5668 return self.join_from( 

5669 from_, target, onclause=onclause, isouter=True, full=full 

5670 ) 

5671 

5672 @_generative 

5673 def join_from( 

5674 self, 

5675 from_: _FromClauseArgument, 

5676 target: _JoinTargetArgument, 

5677 onclause: Optional[_OnClauseArgument] = None, 

5678 *, 

5679 isouter: bool = False, 

5680 full: bool = False, 

5681 ) -> Self: 

5682 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5683 object's criterion 

5684 and apply generatively, returning the newly resulting 

5685 :class:`_expression.Select`. 

5686 

5687 E.g.:: 

5688 

5689 stmt = select(user_table, address_table).join_from( 

5690 user_table, address_table, user_table.c.id == address_table.c.user_id 

5691 ) 

5692 

5693 The above statement generates SQL similar to: 

5694 

5695 .. sourcecode:: sql 

5696 

5697 SELECT user.id, user.name, address.id, address.email, address.user_id 

5698 FROM user JOIN address ON user.id = address.user_id 

5699 

5700 .. versionadded:: 1.4 

5701 

5702 :param from\_: the left side of the join, will be rendered in the 

5703 FROM clause and is roughly equivalent to using the 

5704 :meth:`.Select.select_from` method. 

5705 

5706 :param target: target table to join towards 

5707 

5708 :param onclause: ON clause of the join. 

5709 

5710 :param isouter: if True, generate LEFT OUTER join. Same as 

5711 :meth:`_expression.Select.outerjoin`. 

5712 

5713 :param full: if True, generate FULL OUTER join. 

5714 

5715 .. seealso:: 

5716 

5717 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5718 

5719 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5720 

5721 :meth:`_expression.Select.join` 

5722 

5723 """ # noqa: E501 

5724 

5725 # note the order of parsing from vs. target is important here, as we 

5726 # are also deriving the source of the plugin (i.e. the subject mapper 

5727 # in an ORM query) which should favor the "from_" over the "target" 

5728 

5729 from_ = coercions.expect( 

5730 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5731 ) 

5732 join_target = coercions.expect( 

5733 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5734 ) 

5735 if onclause is not None: 

5736 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5737 else: 

5738 onclause_element = None 

5739 

5740 self._setup_joins += ( 

5741 ( 

5742 join_target, 

5743 onclause_element, 

5744 from_, 

5745 {"isouter": isouter, "full": full}, 

5746 ), 

5747 ) 

5748 return self 

5749 

5750 def outerjoin( 

5751 self, 

5752 target: _JoinTargetArgument, 

5753 onclause: Optional[_OnClauseArgument] = None, 

5754 *, 

5755 full: bool = False, 

5756 ) -> Self: 

5757 """Create a left outer join. 

5758 

5759 Parameters are the same as that of :meth:`_expression.Select.join`. 

5760 

5761 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5762 creates a :class:`_sql.Join` object between a 

5763 :class:`_sql.FromClause` source that is within the FROM clause of 

5764 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5765 and then adds this :class:`_sql.Join` to the FROM clause of the 

5766 newly generated SELECT statement. This is completely reworked 

5767 from the behavior in 1.3, which would instead create a subquery of 

5768 the entire 

5769 :class:`_expression.Select` and then join that subquery to the 

5770 target. 

5771 

5772 This is a **backwards incompatible change** as the previous behavior 

5773 was mostly useless, producing an unnamed subquery rejected by 

5774 most databases in any case. The new behavior is modeled after 

5775 that of the very successful :meth:`_orm.Query.join` method in the 

5776 ORM, in order to support the functionality of :class:`_orm.Query` 

5777 being available by using a :class:`_sql.Select` object with an 

5778 :class:`_orm.Session`. 

5779 

5780 See the notes for this change at :ref:`change_select_join`. 

5781 

5782 .. seealso:: 

5783 

5784 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5785 

5786 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5787 

5788 :meth:`_expression.Select.join` 

5789 

5790 """ 

5791 return self.join(target, onclause=onclause, isouter=True, full=full) 

5792 

5793 def get_final_froms(self) -> Sequence[FromClause]: 

5794 """Compute the final displayed list of :class:`_expression.FromClause` 

5795 elements. 

5796 

5797 This method will run through the full computation required to 

5798 determine what FROM elements will be displayed in the resulting 

5799 SELECT statement, including shadowing individual tables with 

5800 JOIN objects, as well as full computation for ORM use cases including 

5801 eager loading clauses. 

5802 

5803 For ORM use, this accessor returns the **post compilation** 

5804 list of FROM objects; this collection will include elements such as 

5805 eagerly loaded tables and joins. The objects will **not** be 

5806 ORM enabled and not work as a replacement for the 

5807 :meth:`_sql.Select.select_froms` collection; additionally, the 

5808 method is not well performing for an ORM enabled statement as it 

5809 will incur the full ORM construction process. 

5810 

5811 To retrieve the FROM list that's implied by the "columns" collection 

5812 passed to the :class:`_sql.Select` originally, use the 

5813 :attr:`_sql.Select.columns_clause_froms` accessor. 

5814 

5815 To select from an alternative set of columns while maintaining the 

5816 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5817 pass the 

5818 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5819 parameter. 

5820 

5821 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5822 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5823 which is deprecated. 

5824 

5825 .. seealso:: 

5826 

5827 :attr:`_sql.Select.columns_clause_froms` 

5828 

5829 """ 

5830 compiler = self._default_compiler() 

5831 

5832 return self._compile_state_factory(self, compiler)._get_display_froms() 

5833 

5834 @property 

5835 @util.deprecated( 

5836 "1.4.23", 

5837 "The :attr:`_expression.Select.froms` attribute is moved to " 

5838 "the :meth:`_expression.Select.get_final_froms` method.", 

5839 ) 

5840 def froms(self) -> Sequence[FromClause]: 

5841 """Return the displayed list of :class:`_expression.FromClause` 

5842 elements. 

5843 

5844 

5845 """ 

5846 return self.get_final_froms() 

5847 

5848 @property 

5849 def columns_clause_froms(self) -> List[FromClause]: 

5850 """Return the set of :class:`_expression.FromClause` objects implied 

5851 by the columns clause of this SELECT statement. 

5852 

5853 .. versionadded:: 1.4.23 

5854 

5855 .. seealso:: 

5856 

5857 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5858 statement into account 

5859 

5860 :meth:`_sql.Select.with_only_columns` - makes use of this 

5861 collection to set up a new FROM list 

5862 

5863 """ 

5864 

5865 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5866 self 

5867 ) 

5868 

5869 @property 

5870 def inner_columns(self) -> _SelectIterable: 

5871 """An iterator of all :class:`_expression.ColumnElement` 

5872 expressions which would 

5873 be rendered into the columns clause of the resulting SELECT statement. 

5874 

5875 This method is legacy as of 1.4 and is superseded by the 

5876 :attr:`_expression.Select.exported_columns` collection. 

5877 

5878 """ 

5879 

5880 return iter(self._all_selected_columns) 

5881 

5882 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5883 if fromclause is not None and self in fromclause._cloned_set: 

5884 return True 

5885 

5886 for f in self._iterate_from_elements(): 

5887 if f.is_derived_from(fromclause): 

5888 return True 

5889 return False 

5890 

5891 def _copy_internals( 

5892 self, clone: _CloneCallableType = _clone, **kw: Any 

5893 ) -> None: 

5894 # Select() object has been cloned and probably adapted by the 

5895 # given clone function. Apply the cloning function to internal 

5896 # objects 

5897 

5898 # 1. keep a dictionary of the froms we've cloned, and what 

5899 # they've become. This allows us to ensure the same cloned from 

5900 # is used when other items such as columns are "cloned" 

5901 

5902 all_the_froms = set( 

5903 itertools.chain( 

5904 _from_objects(*self._raw_columns), 

5905 _from_objects(*self._where_criteria), 

5906 _from_objects(*[elem[0] for elem in self._setup_joins]), 

5907 ) 

5908 ) 

5909 

5910 # do a clone for the froms we've gathered. what is important here 

5911 # is if any of the things we are selecting from, like tables, 

5912 # were converted into Join objects. if so, these need to be 

5913 # added to _from_obj explicitly, because otherwise they won't be 

5914 # part of the new state, as they don't associate themselves with 

5915 # their columns. 

5916 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

5917 

5918 # 2. copy FROM collections, adding in joins that we've created. 

5919 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

5920 add_froms = ( 

5921 {f for f in new_froms.values() if isinstance(f, Join)} 

5922 .difference(all_the_froms) 

5923 .difference(existing_from_obj) 

5924 ) 

5925 

5926 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

5927 

5928 # 3. clone everything else, making sure we use columns 

5929 # corresponding to the froms we just made. 

5930 def replace( 

5931 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

5932 **kw: Any, 

5933 ) -> Optional[KeyedColumnElement[Any]]: 

5934 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

5935 newelem = new_froms[obj.table].corresponding_column(obj) 

5936 return newelem 

5937 return None 

5938 

5939 kw["replace"] = replace 

5940 

5941 # copy everything else. for table-ish things like correlate, 

5942 # correlate_except, setup_joins, these clone normally. For 

5943 # column-expression oriented things like raw_columns, where_criteria, 

5944 # order by, we get this from the new froms. 

5945 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

5946 

5947 self._reset_memoizations() 

5948 

5949 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

5950 return itertools.chain( 

5951 super().get_children( 

5952 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

5953 **kw, 

5954 ), 

5955 self._iterate_from_elements(), 

5956 ) 

5957 

5958 @_generative 

5959 def add_columns( 

5960 self, *entities: _ColumnsClauseArgument[Any] 

5961 ) -> Select[Unpack[TupleAny]]: 

5962 r"""Return a new :func:`_expression.select` construct with 

5963 the given entities appended to its columns clause. 

5964 

5965 E.g.:: 

5966 

5967 my_select = my_select.add_columns(table.c.new_column) 

5968 

5969 The original expressions in the columns clause remain in place. 

5970 To replace the original expressions with new ones, see the method 

5971 :meth:`_expression.Select.with_only_columns`. 

5972 

5973 :param \*entities: column, table, or other entity expressions to be 

5974 added to the columns clause 

5975 

5976 .. seealso:: 

5977 

5978 :meth:`_expression.Select.with_only_columns` - replaces existing 

5979 expressions rather than appending. 

5980 

5981 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

5982 example 

5983 

5984 """ 

5985 self._reset_memoizations() 

5986 

5987 self._raw_columns = self._raw_columns + [ 

5988 coercions.expect( 

5989 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

5990 ) 

5991 for column in entities 

5992 ] 

5993 return self 

5994 

5995 def _set_entities( 

5996 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

5997 ) -> None: 

5998 self._raw_columns = [ 

5999 coercions.expect( 

6000 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6001 ) 

6002 for ent in util.to_list(entities) 

6003 ] 

6004 

6005 @util.deprecated( 

6006 "1.4", 

6007 "The :meth:`_expression.Select.column` method is deprecated and will " 

6008 "be removed in a future release. Please use " 

6009 ":meth:`_expression.Select.add_columns`", 

6010 ) 

6011 def column( 

6012 self, column: _ColumnsClauseArgument[Any] 

6013 ) -> Select[Unpack[TupleAny]]: 

6014 """Return a new :func:`_expression.select` construct with 

6015 the given column expression added to its columns clause. 

6016 

6017 E.g.:: 

6018 

6019 my_select = my_select.column(table.c.new_column) 

6020 

6021 See the documentation for 

6022 :meth:`_expression.Select.with_only_columns` 

6023 for guidelines on adding /replacing the columns of a 

6024 :class:`_expression.Select` object. 

6025 

6026 """ 

6027 return self.add_columns(column) 

6028 

6029 @util.preload_module("sqlalchemy.sql.util") 

6030 def reduce_columns( 

6031 self, only_synonyms: bool = True 

6032 ) -> Select[Unpack[TupleAny]]: 

6033 """Return a new :func:`_expression.select` construct with redundantly 

6034 named, equivalently-valued columns removed from the columns clause. 

6035 

6036 "Redundant" here means two columns where one refers to the 

6037 other either based on foreign key, or via a simple equality 

6038 comparison in the WHERE clause of the statement. The primary purpose 

6039 of this method is to automatically construct a select statement 

6040 with all uniquely-named columns, without the need to use 

6041 table-qualified labels as 

6042 :meth:`_expression.Select.set_label_style` 

6043 does. 

6044 

6045 When columns are omitted based on foreign key, the referred-to 

6046 column is the one that's kept. When columns are omitted based on 

6047 WHERE equivalence, the first column in the columns clause is the 

6048 one that's kept. 

6049 

6050 :param only_synonyms: when True, limit the removal of columns 

6051 to those which have the same name as the equivalent. Otherwise, 

6052 all columns that are equivalent to another are removed. 

6053 

6054 """ 

6055 woc: Select[Unpack[TupleAny]] 

6056 woc = self.with_only_columns( 

6057 *util.preloaded.sql_util.reduce_columns( 

6058 self._all_selected_columns, 

6059 only_synonyms=only_synonyms, 

6060 *(self._where_criteria + self._from_obj), 

6061 ) 

6062 ) 

6063 return woc 

6064 

6065 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6066 

6067 # code within this block is **programmatically, 

6068 # statically generated** by tools/generate_tuple_map_overloads.py 

6069 

6070 @overload 

6071 def with_only_columns( 

6072 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6073 ) -> Select[_T0]: ... 

6074 

6075 @overload 

6076 def with_only_columns( 

6077 self, 

6078 __ent0: _TCCA[_T0], 

6079 __ent1: _TCCA[_T1], 

6080 /, 

6081 *, 

6082 maintain_column_froms: bool = ..., 

6083 ) -> Select[_T0, _T1]: ... 

6084 

6085 @overload 

6086 def with_only_columns( 

6087 self, 

6088 __ent0: _TCCA[_T0], 

6089 __ent1: _TCCA[_T1], 

6090 __ent2: _TCCA[_T2], 

6091 /, 

6092 *, 

6093 maintain_column_froms: bool = ..., 

6094 ) -> Select[_T0, _T1, _T2]: ... 

6095 

6096 @overload 

6097 def with_only_columns( 

6098 self, 

6099 __ent0: _TCCA[_T0], 

6100 __ent1: _TCCA[_T1], 

6101 __ent2: _TCCA[_T2], 

6102 __ent3: _TCCA[_T3], 

6103 /, 

6104 *, 

6105 maintain_column_froms: bool = ..., 

6106 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6107 

6108 @overload 

6109 def with_only_columns( 

6110 self, 

6111 __ent0: _TCCA[_T0], 

6112 __ent1: _TCCA[_T1], 

6113 __ent2: _TCCA[_T2], 

6114 __ent3: _TCCA[_T3], 

6115 __ent4: _TCCA[_T4], 

6116 /, 

6117 *, 

6118 maintain_column_froms: bool = ..., 

6119 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6120 

6121 @overload 

6122 def with_only_columns( 

6123 self, 

6124 __ent0: _TCCA[_T0], 

6125 __ent1: _TCCA[_T1], 

6126 __ent2: _TCCA[_T2], 

6127 __ent3: _TCCA[_T3], 

6128 __ent4: _TCCA[_T4], 

6129 __ent5: _TCCA[_T5], 

6130 /, 

6131 *, 

6132 maintain_column_froms: bool = ..., 

6133 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6134 

6135 @overload 

6136 def with_only_columns( 

6137 self, 

6138 __ent0: _TCCA[_T0], 

6139 __ent1: _TCCA[_T1], 

6140 __ent2: _TCCA[_T2], 

6141 __ent3: _TCCA[_T3], 

6142 __ent4: _TCCA[_T4], 

6143 __ent5: _TCCA[_T5], 

6144 __ent6: _TCCA[_T6], 

6145 /, 

6146 *, 

6147 maintain_column_froms: bool = ..., 

6148 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6149 

6150 @overload 

6151 def with_only_columns( 

6152 self, 

6153 __ent0: _TCCA[_T0], 

6154 __ent1: _TCCA[_T1], 

6155 __ent2: _TCCA[_T2], 

6156 __ent3: _TCCA[_T3], 

6157 __ent4: _TCCA[_T4], 

6158 __ent5: _TCCA[_T5], 

6159 __ent6: _TCCA[_T6], 

6160 __ent7: _TCCA[_T7], 

6161 /, 

6162 *entities: _ColumnsClauseArgument[Any], 

6163 maintain_column_froms: bool = ..., 

6164 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6165 

6166 # END OVERLOADED FUNCTIONS self.with_only_columns 

6167 

6168 @overload 

6169 def with_only_columns( 

6170 self, 

6171 *entities: _ColumnsClauseArgument[Any], 

6172 maintain_column_froms: bool = False, 

6173 **__kw: Any, 

6174 ) -> Select[Unpack[TupleAny]]: ... 

6175 

6176 @_generative 

6177 def with_only_columns( 

6178 self, 

6179 *entities: _ColumnsClauseArgument[Any], 

6180 maintain_column_froms: bool = False, 

6181 **__kw: Any, 

6182 ) -> Select[Unpack[TupleAny]]: 

6183 r"""Return a new :func:`_expression.select` construct with its columns 

6184 clause replaced with the given entities. 

6185 

6186 By default, this method is exactly equivalent to as if the original 

6187 :func:`_expression.select` had been called with the given entities. 

6188 E.g. a statement:: 

6189 

6190 s = select(table1.c.a, table1.c.b) 

6191 s = s.with_only_columns(table1.c.b) 

6192 

6193 should be exactly equivalent to:: 

6194 

6195 s = select(table1.c.b) 

6196 

6197 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6198 will also dynamically alter the FROM clause of the 

6199 statement if it is not explicitly stated. 

6200 To maintain the existing set of FROMs including those implied by the 

6201 current columns clause, add the 

6202 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6203 parameter:: 

6204 

6205 s = select(table1.c.a, table2.c.b) 

6206 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6207 

6208 The above parameter performs a transfer of the effective FROMs 

6209 in the columns collection to the :meth:`_sql.Select.select_from` 

6210 method, as though the following were invoked:: 

6211 

6212 s = select(table1.c.a, table2.c.b) 

6213 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6214 

6215 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6216 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6217 collection and performs an operation equivalent to the following:: 

6218 

6219 s = select(table1.c.a, table2.c.b) 

6220 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6221 

6222 :param \*entities: column expressions to be used. 

6223 

6224 :param maintain_column_froms: boolean parameter that will ensure the 

6225 FROM list implied from the current columns clause will be transferred 

6226 to the :meth:`_sql.Select.select_from` method first. 

6227 

6228 .. versionadded:: 1.4.23 

6229 

6230 """ # noqa: E501 

6231 

6232 if __kw: 

6233 raise _no_kw() 

6234 

6235 # memoizations should be cleared here as of 

6236 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6237 # is the case for now. 

6238 self._assert_no_memoizations() 

6239 

6240 if maintain_column_froms: 

6241 self.select_from.non_generative( # type: ignore 

6242 self, *self.columns_clause_froms 

6243 ) 

6244 

6245 # then memoize the FROMs etc. 

6246 _MemoizedSelectEntities._generate_for_statement(self) 

6247 

6248 self._raw_columns = [ 

6249 coercions.expect(roles.ColumnsClauseRole, c) 

6250 for c in coercions._expression_collection_was_a_list( 

6251 "entities", "Select.with_only_columns", entities 

6252 ) 

6253 ] 

6254 return self 

6255 

6256 @property 

6257 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6258 """Return the completed WHERE clause for this 

6259 :class:`_expression.Select` statement. 

6260 

6261 This assembles the current collection of WHERE criteria 

6262 into a single :class:`_expression.BooleanClauseList` construct. 

6263 

6264 

6265 .. versionadded:: 1.4 

6266 

6267 """ 

6268 

6269 return BooleanClauseList._construct_for_whereclause( 

6270 self._where_criteria 

6271 ) 

6272 

6273 _whereclause = whereclause 

6274 

6275 @_generative 

6276 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6277 """Return a new :func:`_expression.select` construct with 

6278 the given expression added to 

6279 its WHERE clause, joined to the existing clause via AND, if any. 

6280 

6281 """ 

6282 

6283 assert isinstance(self._where_criteria, tuple) 

6284 

6285 for criterion in whereclause: 

6286 where_criteria: ColumnElement[Any] = coercions.expect( 

6287 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6288 ) 

6289 self._where_criteria += (where_criteria,) 

6290 return self 

6291 

6292 @_generative 

6293 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6294 """Return a new :func:`_expression.select` construct with 

6295 the given expression added to 

6296 its HAVING clause, joined to the existing clause via AND, if any. 

6297 

6298 """ 

6299 

6300 for criterion in having: 

6301 having_criteria = coercions.expect( 

6302 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6303 ) 

6304 self._having_criteria += (having_criteria,) 

6305 return self 

6306 

6307 @_generative 

6308 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6309 r"""Return a new :func:`_expression.select` construct which 

6310 will apply DISTINCT to the SELECT statement overall. 

6311 

6312 E.g.:: 

6313 

6314 from sqlalchemy import select 

6315 

6316 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6317 

6318 The above would produce an statement resembling: 

6319 

6320 .. sourcecode:: sql 

6321 

6322 SELECT DISTINCT user.id, user.name FROM user 

6323 

6324 The method also historically accepted an ``*expr`` parameter which 

6325 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6326 This is now replaced using the :func:`_postgresql.distinct_on` 

6327 extension:: 

6328 

6329 from sqlalchemy import select 

6330 from sqlalchemy.dialects.postgresql import distinct_on 

6331 

6332 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6333 

6334 Using this parameter on other backends which don't support this 

6335 syntax will raise an error. 

6336 

6337 :param \*expr: optional column expressions. When present, 

6338 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6339 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6340 will be raised on other backends. 

6341 

6342 .. deprecated:: 2.1 Passing expressions to 

6343 :meth:`_sql.Select.distinct` is deprecated, use 

6344 :func:`_postgresql.distinct_on` instead. 

6345 

6346 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6347 and will raise :class:`_exc.CompileError` in a future version. 

6348 

6349 .. seealso:: 

6350 

6351 :func:`_postgresql.distinct_on` 

6352 

6353 :meth:`_sql.HasSyntaxExtensions.ext` 

6354 """ 

6355 self._distinct = True 

6356 if expr: 

6357 warn_deprecated( 

6358 "Passing expression to ``distinct`` to generate a " 

6359 "DISTINCT ON clause is deprecated. Use instead the " 

6360 "``postgresql.distinct_on`` function as an extension.", 

6361 "2.1", 

6362 ) 

6363 self._distinct_on = self._distinct_on + tuple( 

6364 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6365 for e in expr 

6366 ) 

6367 return self 

6368 

6369 @_generative 

6370 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6371 r"""Return a new :func:`_expression.select` construct with the 

6372 given FROM expression(s) 

6373 merged into its list of FROM objects. 

6374 

6375 E.g.:: 

6376 

6377 table1 = table("t1", column("a")) 

6378 table2 = table("t2", column("b")) 

6379 s = select(table1.c.a).select_from( 

6380 table1.join(table2, table1.c.a == table2.c.b) 

6381 ) 

6382 

6383 The "from" list is a unique set on the identity of each element, 

6384 so adding an already present :class:`_schema.Table` 

6385 or other selectable 

6386 will have no effect. Passing a :class:`_expression.Join` that refers 

6387 to an already present :class:`_schema.Table` 

6388 or other selectable will have 

6389 the effect of concealing the presence of that selectable as 

6390 an individual element in the rendered FROM list, instead 

6391 rendering it into a JOIN clause. 

6392 

6393 While the typical purpose of :meth:`_expression.Select.select_from` 

6394 is to 

6395 replace the default, derived FROM clause with a join, it can 

6396 also be called with individual table elements, multiple times 

6397 if desired, in the case that the FROM clause cannot be fully 

6398 derived from the columns clause:: 

6399 

6400 select(func.count("*")).select_from(table1) 

6401 

6402 """ 

6403 

6404 self._from_obj += tuple( 

6405 coercions.expect( 

6406 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6407 ) 

6408 for fromclause in froms 

6409 ) 

6410 return self 

6411 

6412 @_generative 

6413 def correlate( 

6414 self, 

6415 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6416 ) -> Self: 

6417 r"""Return a new :class:`_expression.Select` 

6418 which will correlate the given FROM 

6419 clauses to that of an enclosing :class:`_expression.Select`. 

6420 

6421 Calling this method turns off the :class:`_expression.Select` object's 

6422 default behavior of "auto-correlation". Normally, FROM elements 

6423 which appear in a :class:`_expression.Select` 

6424 that encloses this one via 

6425 its :term:`WHERE clause`, ORDER BY, HAVING or 

6426 :term:`columns clause` will be omitted from this 

6427 :class:`_expression.Select` 

6428 object's :term:`FROM clause`. 

6429 Setting an explicit correlation collection using the 

6430 :meth:`_expression.Select.correlate` 

6431 method provides a fixed list of FROM objects 

6432 that can potentially take place in this process. 

6433 

6434 When :meth:`_expression.Select.correlate` 

6435 is used to apply specific FROM clauses 

6436 for correlation, the FROM elements become candidates for 

6437 correlation regardless of how deeply nested this 

6438 :class:`_expression.Select` 

6439 object is, relative to an enclosing :class:`_expression.Select` 

6440 which refers to 

6441 the same FROM object. This is in contrast to the behavior of 

6442 "auto-correlation" which only correlates to an immediate enclosing 

6443 :class:`_expression.Select`. 

6444 Multi-level correlation ensures that the link 

6445 between enclosed and enclosing :class:`_expression.Select` 

6446 is always via 

6447 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6448 correlation to take place. 

6449 

6450 If ``None`` is passed, the :class:`_expression.Select` 

6451 object will correlate 

6452 none of its FROM entries, and all will render unconditionally 

6453 in the local FROM clause. 

6454 

6455 :param \*fromclauses: one or more :class:`.FromClause` or other 

6456 FROM-compatible construct such as an ORM mapped entity to become part 

6457 of the correlate collection; alternatively pass a single value 

6458 ``None`` to remove all existing correlations. 

6459 

6460 .. seealso:: 

6461 

6462 :meth:`_expression.Select.correlate_except` 

6463 

6464 :ref:`tutorial_scalar_subquery` 

6465 

6466 """ 

6467 

6468 # tests failing when we try to change how these 

6469 # arguments are passed 

6470 

6471 self._auto_correlate = False 

6472 if not fromclauses or fromclauses[0] in {None, False}: 

6473 if len(fromclauses) > 1: 

6474 raise exc.ArgumentError( 

6475 "additional FROM objects not accepted when " 

6476 "passing None/False to correlate()" 

6477 ) 

6478 self._correlate = () 

6479 else: 

6480 self._correlate = self._correlate + tuple( 

6481 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6482 ) 

6483 return self 

6484 

6485 @_generative 

6486 def correlate_except( 

6487 self, 

6488 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6489 ) -> Self: 

6490 r"""Return a new :class:`_expression.Select` 

6491 which will omit the given FROM 

6492 clauses from the auto-correlation process. 

6493 

6494 Calling :meth:`_expression.Select.correlate_except` turns off the 

6495 :class:`_expression.Select` object's default behavior of 

6496 "auto-correlation" for the given FROM elements. An element 

6497 specified here will unconditionally appear in the FROM list, while 

6498 all other FROM elements remain subject to normal auto-correlation 

6499 behaviors. 

6500 

6501 If ``None`` is passed, or no arguments are passed, 

6502 the :class:`_expression.Select` object will correlate all of its 

6503 FROM entries. 

6504 

6505 :param \*fromclauses: a list of one or more 

6506 :class:`_expression.FromClause` 

6507 constructs, or other compatible constructs (i.e. ORM-mapped 

6508 classes) to become part of the correlate-exception collection. 

6509 

6510 .. seealso:: 

6511 

6512 :meth:`_expression.Select.correlate` 

6513 

6514 :ref:`tutorial_scalar_subquery` 

6515 

6516 """ 

6517 

6518 self._auto_correlate = False 

6519 if not fromclauses or fromclauses[0] in {None, False}: 

6520 if len(fromclauses) > 1: 

6521 raise exc.ArgumentError( 

6522 "additional FROM objects not accepted when " 

6523 "passing None/False to correlate_except()" 

6524 ) 

6525 self._correlate_except = () 

6526 else: 

6527 self._correlate_except = (self._correlate_except or ()) + tuple( 

6528 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6529 ) 

6530 

6531 return self 

6532 

6533 @HasMemoized_ro_memoized_attribute 

6534 def selected_columns( 

6535 self, 

6536 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6537 """A :class:`_expression.ColumnCollection` 

6538 representing the columns that 

6539 this SELECT statement or similar construct returns in its result set, 

6540 not including :class:`_sql.TextClause` constructs. 

6541 

6542 This collection differs from the :attr:`_expression.FromClause.columns` 

6543 collection of a :class:`_expression.FromClause` in that the columns 

6544 within this collection cannot be directly nested inside another SELECT 

6545 statement; a subquery must be applied first which provides for the 

6546 necessary parenthesization required by SQL. 

6547 

6548 For a :func:`_expression.select` construct, the collection here is 

6549 exactly what would be rendered inside the "SELECT" statement, and the 

6550 :class:`_expression.ColumnElement` objects are directly present as they 

6551 were given, e.g.:: 

6552 

6553 col1 = column("q", Integer) 

6554 col2 = column("p", Integer) 

6555 stmt = select(col1, col2) 

6556 

6557 Above, ``stmt.selected_columns`` would be a collection that contains 

6558 the ``col1`` and ``col2`` objects directly. For a statement that is 

6559 against a :class:`_schema.Table` or other 

6560 :class:`_expression.FromClause`, the collection will use the 

6561 :class:`_expression.ColumnElement` objects that are in the 

6562 :attr:`_expression.FromClause.c` collection of the from element. 

6563 

6564 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6565 to allow the existing columns to be referenced when adding additional 

6566 criteria, e.g.:: 

6567 

6568 def filter_on_id(my_select, id): 

6569 return my_select.where(my_select.selected_columns["id"] == id) 

6570 

6571 

6572 stmt = select(MyModel) 

6573 

6574 # adds "WHERE id=:param" to the statement 

6575 stmt = filter_on_id(stmt, 42) 

6576 

6577 .. note:: 

6578 

6579 The :attr:`_sql.Select.selected_columns` collection does not 

6580 include expressions established in the columns clause using the 

6581 :func:`_sql.text` construct; these are silently omitted from the 

6582 collection. To use plain textual column expressions inside of a 

6583 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6584 construct. 

6585 

6586 

6587 .. versionadded:: 1.4 

6588 

6589 """ 

6590 

6591 # compare to SelectState._generate_columns_plus_names, which 

6592 # generates the actual names used in the SELECT string. that 

6593 # method is more complex because it also renders columns that are 

6594 # fully ambiguous, e.g. same column more than once. 

6595 conv = cast( 

6596 "Callable[[Any], str]", 

6597 SelectState._column_naming_convention(self._label_style), 

6598 ) 

6599 

6600 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6601 [ 

6602 (conv(c), c) 

6603 for c in self._all_selected_columns 

6604 if is_column_element(c) 

6605 ] 

6606 ) 

6607 return cc.as_readonly() 

6608 

6609 @HasMemoized_ro_memoized_attribute 

6610 def _all_selected_columns(self) -> _SelectIterable: 

6611 meth = SelectState.get_plugin_class(self).all_selected_columns 

6612 return list(meth(self)) 

6613 

6614 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6615 if self._label_style is LABEL_STYLE_NONE: 

6616 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6617 return self 

6618 

6619 def _generate_fromclause_column_proxies( 

6620 self, 

6621 subquery: FromClause, 

6622 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

6623 primary_key: ColumnSet, 

6624 foreign_keys: Set[KeyedColumnElement[Any]], 

6625 *, 

6626 proxy_compound_columns: Optional[ 

6627 Iterable[Sequence[ColumnElement[Any]]] 

6628 ] = None, 

6629 ) -> None: 

6630 """Generate column proxies to place in the exported ``.c`` 

6631 collection of a subquery.""" 

6632 

6633 if proxy_compound_columns: 

6634 extra_col_iterator = proxy_compound_columns 

6635 prox = [ 

6636 c._make_proxy( 

6637 subquery, 

6638 key=proxy_key, 

6639 name=required_label_name, 

6640 name_is_truncatable=True, 

6641 compound_select_cols=extra_cols, 

6642 primary_key=primary_key, 

6643 foreign_keys=foreign_keys, 

6644 ) 

6645 for ( 

6646 ( 

6647 required_label_name, 

6648 proxy_key, 

6649 fallback_label_name, 

6650 c, 

6651 repeated, 

6652 ), 

6653 extra_cols, 

6654 ) in ( 

6655 zip( 

6656 self._generate_columns_plus_names(False), 

6657 extra_col_iterator, 

6658 ) 

6659 ) 

6660 if is_column_element(c) 

6661 ] 

6662 else: 

6663 prox = [ 

6664 c._make_proxy( 

6665 subquery, 

6666 key=proxy_key, 

6667 name=required_label_name, 

6668 name_is_truncatable=True, 

6669 primary_key=primary_key, 

6670 foreign_keys=foreign_keys, 

6671 ) 

6672 for ( 

6673 required_label_name, 

6674 proxy_key, 

6675 fallback_label_name, 

6676 c, 

6677 repeated, 

6678 ) in (self._generate_columns_plus_names(False)) 

6679 if is_column_element(c) 

6680 ] 

6681 

6682 columns._populate_separate_keys(prox) 

6683 

6684 def _needs_parens_for_grouping(self) -> bool: 

6685 return self._has_row_limiting_clause or bool( 

6686 self._order_by_clause.clauses 

6687 ) 

6688 

6689 def self_group( 

6690 self, against: Optional[OperatorType] = None 

6691 ) -> Union[SelectStatementGrouping[Self], Self]: 

6692 """Return a 'grouping' construct as per the 

6693 :class:`_expression.ClauseElement` specification. 

6694 

6695 This produces an element that can be embedded in an expression. Note 

6696 that this method is called automatically as needed when constructing 

6697 expressions and should not require explicit use. 

6698 

6699 """ 

6700 if ( 

6701 isinstance(against, CompoundSelect) 

6702 and not self._needs_parens_for_grouping() 

6703 ): 

6704 return self 

6705 else: 

6706 return SelectStatementGrouping(self) 

6707 

6708 def union( 

6709 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6710 ) -> CompoundSelect[Unpack[_Ts]]: 

6711 r"""Return a SQL ``UNION`` of this select() construct against 

6712 the given selectables provided as positional arguments. 

6713 

6714 :param \*other: one or more elements with which to create a 

6715 UNION. 

6716 

6717 .. versionchanged:: 1.4.28 

6718 

6719 multiple elements are now accepted. 

6720 

6721 :param \**kwargs: keyword arguments are forwarded to the constructor 

6722 for the newly created :class:`_sql.CompoundSelect` object. 

6723 

6724 """ 

6725 return CompoundSelect._create_union(self, *other) 

6726 

6727 def union_all( 

6728 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6729 ) -> CompoundSelect[Unpack[_Ts]]: 

6730 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6731 the given selectables provided as positional arguments. 

6732 

6733 :param \*other: one or more elements with which to create a 

6734 UNION. 

6735 

6736 .. versionchanged:: 1.4.28 

6737 

6738 multiple elements are now accepted. 

6739 

6740 :param \**kwargs: keyword arguments are forwarded to the constructor 

6741 for the newly created :class:`_sql.CompoundSelect` object. 

6742 

6743 """ 

6744 return CompoundSelect._create_union_all(self, *other) 

6745 

6746 def except_( 

6747 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6748 ) -> CompoundSelect[Unpack[_Ts]]: 

6749 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6750 the given selectable provided as positional arguments. 

6751 

6752 :param \*other: one or more elements with which to create a 

6753 UNION. 

6754 

6755 .. versionchanged:: 1.4.28 

6756 

6757 multiple elements are now accepted. 

6758 

6759 """ 

6760 return CompoundSelect._create_except(self, *other) 

6761 

6762 def except_all( 

6763 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6764 ) -> CompoundSelect[Unpack[_Ts]]: 

6765 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6766 the given selectables provided as positional arguments. 

6767 

6768 :param \*other: one or more elements with which to create a 

6769 UNION. 

6770 

6771 .. versionchanged:: 1.4.28 

6772 

6773 multiple elements are now accepted. 

6774 

6775 """ 

6776 return CompoundSelect._create_except_all(self, *other) 

6777 

6778 def intersect( 

6779 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6780 ) -> CompoundSelect[Unpack[_Ts]]: 

6781 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6782 the given selectables provided as positional arguments. 

6783 

6784 :param \*other: one or more elements with which to create a 

6785 UNION. 

6786 

6787 .. versionchanged:: 1.4.28 

6788 

6789 multiple elements are now accepted. 

6790 

6791 :param \**kwargs: keyword arguments are forwarded to the constructor 

6792 for the newly created :class:`_sql.CompoundSelect` object. 

6793 

6794 """ 

6795 return CompoundSelect._create_intersect(self, *other) 

6796 

6797 def intersect_all( 

6798 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6799 ) -> CompoundSelect[Unpack[_Ts]]: 

6800 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6801 against the given selectables provided as positional arguments. 

6802 

6803 :param \*other: one or more elements with which to create a 

6804 UNION. 

6805 

6806 .. versionchanged:: 1.4.28 

6807 

6808 multiple elements are now accepted. 

6809 

6810 :param \**kwargs: keyword arguments are forwarded to the constructor 

6811 for the newly created :class:`_sql.CompoundSelect` object. 

6812 

6813 """ 

6814 return CompoundSelect._create_intersect_all(self, *other) 

6815 

6816 

6817class ScalarSelect( 

6818 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6819): 

6820 """Represent a scalar subquery. 

6821 

6822 

6823 A :class:`_sql.ScalarSelect` is created by invoking the 

6824 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6825 then participates in other SQL expressions as a SQL column expression 

6826 within the :class:`_sql.ColumnElement` hierarchy. 

6827 

6828 .. seealso:: 

6829 

6830 :meth:`_sql.SelectBase.scalar_subquery` 

6831 

6832 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6833 

6834 """ 

6835 

6836 _traverse_internals: _TraverseInternalsType = [ 

6837 ("element", InternalTraversal.dp_clauseelement), 

6838 ("type", InternalTraversal.dp_type), 

6839 ] 

6840 

6841 _from_objects: List[FromClause] = [] 

6842 _is_from_container = True 

6843 if not TYPE_CHECKING: 

6844 _is_implicitly_boolean = False 

6845 inherit_cache = True 

6846 

6847 element: SelectBase 

6848 

6849 def __init__(self, element: SelectBase) -> None: 

6850 self.element = element 

6851 self.type = element._scalar_type() 

6852 self._propagate_attrs = element._propagate_attrs 

6853 

6854 def __getattr__(self, attr: str) -> Any: 

6855 return getattr(self.element, attr) 

6856 

6857 def __getstate__(self) -> Dict[str, Any]: 

6858 return {"element": self.element, "type": self.type} 

6859 

6860 def __setstate__(self, state: Dict[str, Any]) -> None: 

6861 self.element = state["element"] 

6862 self.type = state["type"] 

6863 

6864 @property 

6865 def columns(self) -> NoReturn: 

6866 raise exc.InvalidRequestError( 

6867 "Scalar Select expression has no " 

6868 "columns; use this object directly " 

6869 "within a column-level expression." 

6870 ) 

6871 

6872 c = columns 

6873 

6874 @_generative 

6875 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6876 """Apply a WHERE clause to the SELECT statement referred to 

6877 by this :class:`_expression.ScalarSelect`. 

6878 

6879 """ 

6880 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6881 crit 

6882 ) 

6883 return self 

6884 

6885 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6886 return self 

6887 

6888 def _ungroup(self) -> Self: 

6889 return self 

6890 

6891 @_generative 

6892 def correlate( 

6893 self, 

6894 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6895 ) -> Self: 

6896 r"""Return a new :class:`_expression.ScalarSelect` 

6897 which will correlate the given FROM 

6898 clauses to that of an enclosing :class:`_expression.Select`. 

6899 

6900 This method is mirrored from the :meth:`_sql.Select.correlate` method 

6901 of the underlying :class:`_sql.Select`. The method applies the 

6902 :meth:_sql.Select.correlate` method, then returns a new 

6903 :class:`_sql.ScalarSelect` against that statement. 

6904 

6905 .. versionadded:: 1.4 Previously, the 

6906 :meth:`_sql.ScalarSelect.correlate` 

6907 method was only available from :class:`_sql.Select`. 

6908 

6909 :param \*fromclauses: a list of one or more 

6910 :class:`_expression.FromClause` 

6911 constructs, or other compatible constructs (i.e. ORM-mapped 

6912 classes) to become part of the correlate collection. 

6913 

6914 .. seealso:: 

6915 

6916 :meth:`_expression.ScalarSelect.correlate_except` 

6917 

6918 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6919 

6920 

6921 """ 

6922 self.element = cast( 

6923 "Select[Unpack[TupleAny]]", self.element 

6924 ).correlate(*fromclauses) 

6925 return self 

6926 

6927 @_generative 

6928 def correlate_except( 

6929 self, 

6930 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6931 ) -> Self: 

6932 r"""Return a new :class:`_expression.ScalarSelect` 

6933 which will omit the given FROM 

6934 clauses from the auto-correlation process. 

6935 

6936 This method is mirrored from the 

6937 :meth:`_sql.Select.correlate_except` method of the underlying 

6938 :class:`_sql.Select`. The method applies the 

6939 :meth:_sql.Select.correlate_except` method, then returns a new 

6940 :class:`_sql.ScalarSelect` against that statement. 

6941 

6942 .. versionadded:: 1.4 Previously, the 

6943 :meth:`_sql.ScalarSelect.correlate_except` 

6944 method was only available from :class:`_sql.Select`. 

6945 

6946 :param \*fromclauses: a list of one or more 

6947 :class:`_expression.FromClause` 

6948 constructs, or other compatible constructs (i.e. ORM-mapped 

6949 classes) to become part of the correlate-exception collection. 

6950 

6951 .. seealso:: 

6952 

6953 :meth:`_expression.ScalarSelect.correlate` 

6954 

6955 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6956 

6957 

6958 """ 

6959 

6960 self.element = cast( 

6961 "Select[Unpack[TupleAny]]", self.element 

6962 ).correlate_except(*fromclauses) 

6963 return self 

6964 

6965 

6966class Exists(UnaryExpression[bool]): 

6967 """Represent an ``EXISTS`` clause. 

6968 

6969 See :func:`_sql.exists` for a description of usage. 

6970 

6971 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

6972 instance by calling :meth:`_sql.SelectBase.exists`. 

6973 

6974 """ 

6975 

6976 inherit_cache = True 

6977 

6978 def __init__( 

6979 self, 

6980 __argument: Optional[ 

6981 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

6982 ] = None, 

6983 /, 

6984 ): 

6985 s: ScalarSelect[Any] 

6986 

6987 # TODO: this seems like we should be using coercions for this 

6988 if __argument is None: 

6989 s = Select(literal_column("*")).scalar_subquery() 

6990 elif isinstance(__argument, SelectBase): 

6991 s = __argument.scalar_subquery() 

6992 s._propagate_attrs = __argument._propagate_attrs 

6993 elif isinstance(__argument, ScalarSelect): 

6994 s = __argument 

6995 else: 

6996 s = Select(__argument).scalar_subquery() 

6997 

6998 UnaryExpression.__init__( 

6999 self, 

7000 s, 

7001 operator=operators.exists, 

7002 type_=type_api.BOOLEANTYPE, 

7003 ) 

7004 

7005 @util.ro_non_memoized_property 

7006 def _from_objects(self) -> List[FromClause]: 

7007 return [] 

7008 

7009 def _regroup( 

7010 self, 

7011 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7012 ) -> ScalarSelect[Any]: 

7013 

7014 assert isinstance(self.element, ScalarSelect) 

7015 element = self.element.element 

7016 if not isinstance(element, Select): 

7017 raise exc.InvalidRequestError( 

7018 "Can only apply this operation to a plain SELECT construct" 

7019 ) 

7020 new_element = fn(element) 

7021 

7022 return_value = new_element.scalar_subquery() 

7023 return return_value 

7024 

7025 def select(self) -> Select[bool]: 

7026 r"""Return a SELECT of this :class:`_expression.Exists`. 

7027 

7028 e.g.:: 

7029 

7030 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7031 

7032 This will produce a statement resembling: 

7033 

7034 .. sourcecode:: sql 

7035 

7036 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7037 

7038 .. seealso:: 

7039 

7040 :func:`_expression.select` - general purpose 

7041 method which allows for arbitrary column lists. 

7042 

7043 """ # noqa 

7044 

7045 return Select(self) 

7046 

7047 def correlate( 

7048 self, 

7049 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7050 ) -> Self: 

7051 """Apply correlation to the subquery noted by this 

7052 :class:`_sql.Exists`. 

7053 

7054 .. seealso:: 

7055 

7056 :meth:`_sql.ScalarSelect.correlate` 

7057 

7058 """ 

7059 e = self._clone() 

7060 e.element = self._regroup( 

7061 lambda element: element.correlate(*fromclauses) 

7062 ) 

7063 return e 

7064 

7065 def correlate_except( 

7066 self, 

7067 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7068 ) -> Self: 

7069 """Apply correlation to the subquery noted by this 

7070 :class:`_sql.Exists`. 

7071 

7072 .. seealso:: 

7073 

7074 :meth:`_sql.ScalarSelect.correlate_except` 

7075 

7076 """ 

7077 e = self._clone() 

7078 e.element = self._regroup( 

7079 lambda element: element.correlate_except(*fromclauses) 

7080 ) 

7081 return e 

7082 

7083 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7084 """Return a new :class:`_expression.Exists` construct, 

7085 applying the given 

7086 expression to the :meth:`_expression.Select.select_from` 

7087 method of the select 

7088 statement contained. 

7089 

7090 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7091 statement first, including the desired WHERE clause, then use the 

7092 :meth:`_sql.SelectBase.exists` method to produce an 

7093 :class:`_sql.Exists` object at once. 

7094 

7095 """ 

7096 e = self._clone() 

7097 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7098 return e 

7099 

7100 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7101 """Return a new :func:`_expression.exists` construct with the 

7102 given expression added to 

7103 its WHERE clause, joined to the existing clause via AND, if any. 

7104 

7105 

7106 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7107 statement first, including the desired WHERE clause, then use the 

7108 :meth:`_sql.SelectBase.exists` method to produce an 

7109 :class:`_sql.Exists` object at once. 

7110 

7111 """ 

7112 e = self._clone() 

7113 e.element = self._regroup(lambda element: element.where(*clause)) 

7114 return e 

7115 

7116 

7117class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7118 """Wrap a :class:`_expression.TextClause` construct within a 

7119 :class:`_expression.SelectBase` 

7120 interface. 

7121 

7122 This allows the :class:`_expression.TextClause` object to gain a 

7123 ``.c`` collection 

7124 and other FROM-like capabilities such as 

7125 :meth:`_expression.FromClause.alias`, 

7126 :meth:`_expression.SelectBase.cte`, etc. 

7127 

7128 The :class:`_expression.TextualSelect` construct is produced via the 

7129 :meth:`_expression.TextClause.columns` 

7130 method - see that method for details. 

7131 

7132 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7133 class was renamed 

7134 from ``TextAsFrom``, to more correctly suit its role as a 

7135 SELECT-oriented object and not a FROM clause. 

7136 

7137 .. seealso:: 

7138 

7139 :func:`_expression.text` 

7140 

7141 :meth:`_expression.TextClause.columns` - primary creation interface. 

7142 

7143 """ 

7144 

7145 __visit_name__ = "textual_select" 

7146 

7147 _label_style = LABEL_STYLE_NONE 

7148 

7149 _traverse_internals: _TraverseInternalsType = ( 

7150 [ 

7151 ("element", InternalTraversal.dp_clauseelement), 

7152 ("column_args", InternalTraversal.dp_clauseelement_list), 

7153 ] 

7154 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7155 + HasCTE._has_ctes_traverse_internals 

7156 ) 

7157 

7158 _is_textual = True 

7159 

7160 is_text = True 

7161 is_select = True 

7162 

7163 def __init__( 

7164 self, 

7165 text: TextClause, 

7166 columns: List[_ColumnExpressionArgument[Any]], 

7167 positional: bool = False, 

7168 ) -> None: 

7169 self._init( 

7170 text, 

7171 # convert for ORM attributes->columns, etc 

7172 [ 

7173 coercions.expect(roles.LabeledColumnExprRole, c) 

7174 for c in columns 

7175 ], 

7176 positional, 

7177 ) 

7178 

7179 def _init( 

7180 self, 

7181 text: TextClause, 

7182 columns: List[NamedColumn[Any]], 

7183 positional: bool = False, 

7184 ) -> None: 

7185 self.element = text 

7186 self.column_args = columns 

7187 self.positional = positional 

7188 

7189 @HasMemoized_ro_memoized_attribute 

7190 def selected_columns( 

7191 self, 

7192 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7193 """A :class:`_expression.ColumnCollection` 

7194 representing the columns that 

7195 this SELECT statement or similar construct returns in its result set, 

7196 not including :class:`_sql.TextClause` constructs. 

7197 

7198 This collection differs from the :attr:`_expression.FromClause.columns` 

7199 collection of a :class:`_expression.FromClause` in that the columns 

7200 within this collection cannot be directly nested inside another SELECT 

7201 statement; a subquery must be applied first which provides for the 

7202 necessary parenthesization required by SQL. 

7203 

7204 For a :class:`_expression.TextualSelect` construct, the collection 

7205 contains the :class:`_expression.ColumnElement` objects that were 

7206 passed to the constructor, typically via the 

7207 :meth:`_expression.TextClause.columns` method. 

7208 

7209 

7210 .. versionadded:: 1.4 

7211 

7212 """ 

7213 return ColumnCollection( 

7214 (c.key, c) for c in self.column_args 

7215 ).as_readonly() 

7216 

7217 @util.ro_non_memoized_property 

7218 def _all_selected_columns(self) -> _SelectIterable: 

7219 return self.column_args 

7220 

7221 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7222 return self 

7223 

7224 def _ensure_disambiguated_names(self) -> TextualSelect: 

7225 return self 

7226 

7227 @_generative 

7228 def bindparams( 

7229 self, 

7230 *binds: BindParameter[Any], 

7231 **bind_as_values: Any, 

7232 ) -> Self: 

7233 self.element = self.element.bindparams(*binds, **bind_as_values) 

7234 return self 

7235 

7236 def _generate_fromclause_column_proxies( 

7237 self, 

7238 fromclause: FromClause, 

7239 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

7240 primary_key: ColumnSet, 

7241 foreign_keys: Set[KeyedColumnElement[Any]], 

7242 *, 

7243 proxy_compound_columns: Optional[ 

7244 Iterable[Sequence[ColumnElement[Any]]] 

7245 ] = None, 

7246 ) -> None: 

7247 if TYPE_CHECKING: 

7248 assert isinstance(fromclause, Subquery) 

7249 

7250 if proxy_compound_columns: 

7251 columns._populate_separate_keys( 

7252 c._make_proxy( 

7253 fromclause, 

7254 compound_select_cols=extra_cols, 

7255 primary_key=primary_key, 

7256 foreign_keys=foreign_keys, 

7257 ) 

7258 for c, extra_cols in zip( 

7259 self.column_args, proxy_compound_columns 

7260 ) 

7261 ) 

7262 else: 

7263 columns._populate_separate_keys( 

7264 c._make_proxy( 

7265 fromclause, 

7266 primary_key=primary_key, 

7267 foreign_keys=foreign_keys, 

7268 ) 

7269 for c in self.column_args 

7270 ) 

7271 

7272 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7273 return self.column_args[0].type 

7274 

7275 

7276TextAsFrom = TextualSelect 

7277"""Backwards compatibility with the previous name""" 

7278 

7279 

7280class AnnotatedFromClause(Annotated): 

7281 def _copy_internals(self, **kw: Any) -> None: 

7282 super()._copy_internals(**kw) 

7283 if kw.get("ind_cols_on_fromclause", False): 

7284 ee = self._Annotated__element # type: ignore 

7285 

7286 self.c = ee.__class__.c.fget(self) # type: ignore 

7287 

7288 @util.ro_memoized_property 

7289 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7290 """proxy the .c collection of the underlying FromClause. 

7291 

7292 Originally implemented in 2008 as a simple load of the .c collection 

7293 when the annotated construct was created (see d3621ae961a), in modern 

7294 SQLAlchemy versions this can be expensive for statements constructed 

7295 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7296 it, which works just as well. 

7297 

7298 Two different use cases seem to require the collection either copied 

7299 from the underlying one, or unique to this AnnotatedFromClause. 

7300 

7301 See test_selectable->test_annotated_corresponding_column 

7302 

7303 """ 

7304 ee = self._Annotated__element # type: ignore 

7305 return ee.c # type: ignore