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

1772 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import NamedTuple 

30from typing import NoReturn 

31from typing import Optional 

32from typing import overload 

33from typing import Protocol 

34from typing import Sequence 

35from typing import Set 

36from typing import Tuple 

37from typing import Type 

38from typing import TYPE_CHECKING 

39from typing import TypeVar 

40from typing import Union 

41 

42from . import cache_key 

43from . import coercions 

44from . import operators 

45from . import roles 

46from . import traversals 

47from . import type_api 

48from . import visitors 

49from ._typing import _ColumnsClauseArgument 

50from ._typing import _no_kw 

51from ._typing import _T 

52from ._typing import _Ts 

53from ._typing import is_column_element 

54from ._typing import is_select_statement 

55from ._typing import is_subquery 

56from ._typing import is_table 

57from ._typing import is_text_clause 

58from .annotation import Annotated 

59from .annotation import SupportsCloneAnnotations 

60from .base import _clone 

61from .base import _cloned_difference 

62from .base import _cloned_intersection 

63from .base import _entity_namespace_key 

64from .base import _EntityNamespace 

65from .base import _expand_cloned 

66from .base import _from_objects 

67from .base import _generative 

68from .base import _never_select_column 

69from .base import _NoArg 

70from .base import _select_iterables 

71from .base import CacheableOptions 

72from .base import ColumnCollection 

73from .base import ColumnSet 

74from .base import CompileState 

75from .base import DedupeColumnCollection 

76from .base import DialectKWArgs 

77from .base import Executable 

78from .base import Generative 

79from .base import HasCompileState 

80from .base import HasMemoized 

81from .base import HasSyntaxExtensions 

82from .base import Immutable 

83from .base import SyntaxExtension 

84from .coercions import _document_text_coercion 

85from .elements import _anonymous_label 

86from .elements import BindParameter 

87from .elements import BooleanClauseList 

88from .elements import ClauseElement 

89from .elements import ClauseList 

90from .elements import ColumnClause 

91from .elements import ColumnElement 

92from .elements import DQLDMLClauseElement 

93from .elements import GroupedElement 

94from .elements import literal_column 

95from .elements import TableValuedColumn 

96from .elements import UnaryExpression 

97from .operators import OperatorType 

98from .sqltypes import NULLTYPE 

99from .visitors import _TraverseInternalsType 

100from .visitors import InternalTraversal 

101from .visitors import prefix_anon_map 

102from .. import exc 

103from .. import util 

104from ..util import HasMemoized_ro_memoized_attribute 

105from ..util import warn_deprecated 

106from ..util.typing import Literal 

107from ..util.typing import Self 

108from ..util.typing import TupleAny 

109from ..util.typing import Unpack 

110 

111 

112and_ = BooleanClauseList.and_ 

113 

114 

115if TYPE_CHECKING: 

116 from ._typing import _ColumnExpressionArgument 

117 from ._typing import _ColumnExpressionOrStrLabelArgument 

118 from ._typing import _FromClauseArgument 

119 from ._typing import _JoinTargetArgument 

120 from ._typing import _LimitOffsetType 

121 from ._typing import _MAYBE_ENTITY 

122 from ._typing import _NOT_ENTITY 

123 from ._typing import _OnClauseArgument 

124 from ._typing import _SelectStatementForCompoundArgument 

125 from ._typing import _T0 

126 from ._typing import _T1 

127 from ._typing import _T2 

128 from ._typing import _T3 

129 from ._typing import _T4 

130 from ._typing import _T5 

131 from ._typing import _T6 

132 from ._typing import _T7 

133 from ._typing import _TextCoercedExpressionArgument 

134 from ._typing import _TypedColumnClauseArgument as _TCCA 

135 from ._typing import _TypeEngineArgument 

136 from .base import _AmbiguousTableNameMap 

137 from .base import ExecutableOption 

138 from .base import ReadOnlyColumnCollection 

139 from .cache_key import _CacheKeyTraversalType 

140 from .compiler import SQLCompiler 

141 from .dml import Delete 

142 from .dml import Update 

143 from .elements import BinaryExpression 

144 from .elements import KeyedColumnElement 

145 from .elements import Label 

146 from .elements import NamedColumn 

147 from .elements import TextClause 

148 from .functions import Function 

149 from .schema import ForeignKey 

150 from .schema import ForeignKeyConstraint 

151 from .sqltypes import TableValueType 

152 from .type_api import TypeEngine 

153 from .visitors import _CloneCallableType 

154 

155 

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

157_LabelConventionCallable = Callable[ 

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

159] 

160 

161 

162class _JoinTargetProtocol(Protocol): 

163 @util.ro_non_memoized_property 

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

165 

166 @util.ro_non_memoized_property 

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

168 

169 

170_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

172 

173_ForUpdateOfArgument = Union[ 

174 # single column, Table, ORM Entity 

175 Union[ 

176 "_ColumnExpressionArgument[Any]", 

177 "_FromClauseArgument", 

178 ], 

179 # or sequence of single column elements 

180 Sequence["_ColumnExpressionArgument[Any]"], 

181] 

182 

183 

184_SetupJoinsElement = Tuple[ 

185 _JoinTargetElement, 

186 Optional[_OnClauseElement], 

187 Optional["FromClause"], 

188 Dict[str, Any], 

189] 

190 

191 

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

193 

194 

195class _OffsetLimitParam(BindParameter[int]): 

196 inherit_cache = True 

197 

198 @property 

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

200 return self.effective_value 

201 

202 

203class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

205 columns that can represent rows. 

206 

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

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

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

210 PostgreSQL has functions that return rows also. 

211 

212 .. versionadded:: 1.4 

213 

214 """ 

215 

216 _is_returns_rows = True 

217 

218 # sub-elements of returns_rows 

219 _is_from_clause = False 

220 _is_select_base = False 

221 _is_select_statement = False 

222 _is_lateral = False 

223 

224 @property 

225 def selectable(self) -> ReturnsRows: 

226 return self 

227 

228 @util.ro_non_memoized_property 

229 def _all_selected_columns(self) -> _SelectIterable: 

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

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

232 

233 This is typically equivalent to .exported_columns except it is 

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

235 :class:`_expression.ColumnCollection`. 

236 

237 """ 

238 raise NotImplementedError() 

239 

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

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

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

243 

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

245 

246 """ 

247 raise NotImplementedError() 

248 

249 def _generate_fromclause_column_proxies( 

250 self, 

251 fromclause: FromClause, 

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

253 primary_key: ColumnSet, 

254 foreign_keys: Set[KeyedColumnElement[Any]], 

255 ) -> None: 

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

257 

258 raise NotImplementedError() 

259 

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

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

262 raise NotImplementedError() 

263 

264 @property 

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

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

267 that represents the "exported" 

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

269 

270 The "exported" columns represent the collection of 

271 :class:`_expression.ColumnElement` 

272 expressions that are rendered by this SQL 

273 construct. There are primary varieties which are the 

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

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

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

277 columns in a DML statement.. 

278 

279 .. versionadded:: 1.4 

280 

281 .. seealso:: 

282 

283 :attr:`_expression.FromClause.exported_columns` 

284 

285 :attr:`_expression.SelectBase.exported_columns` 

286 """ 

287 

288 raise NotImplementedError() 

289 

290 

291class ExecutableReturnsRows(Executable, ReturnsRows): 

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

293 

294 

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

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

297 

298 

299class Selectable(ReturnsRows): 

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

301 

302 __visit_name__ = "selectable" 

303 

304 is_selectable = True 

305 

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

307 raise NotImplementedError() 

308 

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

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

311 

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

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

314 

315 .. seealso:: 

316 

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

318 

319 """ 

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

321 

322 @util.deprecated( 

323 "1.4", 

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

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

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

327 ) 

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

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

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

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

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

333 

334 """ 

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

336 

337 def corresponding_column( 

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

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

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

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

342 :attr:`_expression.Selectable.exported_columns` 

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

344 which corresponds to that 

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

346 column. 

347 

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

349 to be matched. 

350 

351 :param require_embedded: only return corresponding columns for 

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

353 :class:`_expression.ColumnElement` 

354 is actually present within a sub-element 

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

356 Normally the column will match if 

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

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

359 

360 .. seealso:: 

361 

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

363 :class:`_expression.ColumnCollection` 

364 that is used for the operation. 

365 

366 :meth:`_expression.ColumnCollection.corresponding_column` 

367 - implementation 

368 method. 

369 

370 """ 

371 

372 return self.exported_columns.corresponding_column( 

373 column, require_embedded 

374 ) 

375 

376 

377class HasPrefixes: 

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

379 

380 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

381 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

382 ] 

383 

384 @_generative 

385 @_document_text_coercion( 

386 "prefixes", 

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

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

389 ) 

390 def prefix_with( 

391 self, 

392 *prefixes: _TextCoercedExpressionArgument[Any], 

393 dialect: str = "*", 

394 ) -> Self: 

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

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

397 

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

399 provided by MySQL. 

400 

401 E.g.:: 

402 

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

404 

405 # MySQL 5.7 optimizer hints 

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

407 

408 Multiple prefixes can be specified by multiple calls 

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

410 

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

412 construct which 

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

414 keyword. 

415 :param dialect: optional string dialect name which will 

416 limit rendering of this prefix to only that dialect. 

417 

418 """ 

419 self._prefixes = self._prefixes + tuple( 

420 [ 

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

422 for p in prefixes 

423 ] 

424 ) 

425 return self 

426 

427 

428class HasSuffixes: 

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

430 

431 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

432 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

433 ] 

434 

435 @_generative 

436 @_document_text_coercion( 

437 "suffixes", 

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

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

440 ) 

441 def suffix_with( 

442 self, 

443 *suffixes: _TextCoercedExpressionArgument[Any], 

444 dialect: str = "*", 

445 ) -> Self: 

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

447 

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

449 certain constructs. 

450 

451 E.g.:: 

452 

453 stmt = ( 

454 select(col1, col2) 

455 .cte() 

456 .suffix_with( 

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

458 ) 

459 ) 

460 

461 Multiple suffixes can be specified by multiple calls 

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

463 

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

465 construct which 

466 will be rendered following the target clause. 

467 :param dialect: Optional string dialect name which will 

468 limit rendering of this suffix to only that dialect. 

469 

470 """ 

471 self._suffixes = self._suffixes + tuple( 

472 [ 

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

474 for p in suffixes 

475 ] 

476 ) 

477 return self 

478 

479 

480class HasHints: 

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

482 util.immutabledict() 

483 ) 

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

485 

486 _has_hints_traverse_internals: _TraverseInternalsType = [ 

487 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

488 ("_hints", InternalTraversal.dp_table_hint_list), 

489 ] 

490 

491 @_generative 

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

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

494 other selectable object. 

495 

496 .. tip:: 

497 

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

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

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

501 the SELECT statement after the SELECT keyword, use the 

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

503 space, or for table-specific hints the 

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

505 hints in a dialect-specific location. 

506 

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

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

509 the statement as a whole. 

510 

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

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

513 etc. 

514 

515 .. seealso:: 

516 

517 :meth:`_expression.Select.with_hint` 

518 

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

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

521 MySQL or Oracle Database optimizer hints 

522 

523 """ 

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

525 

526 @_generative 

527 def with_hint( 

528 self, 

529 selectable: _FromClauseArgument, 

530 text: str, 

531 dialect_name: str = "*", 

532 ) -> Self: 

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

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

535 object. 

536 

537 .. tip:: 

538 

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

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

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

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

543 for MySQL or Oracle Database, use the 

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

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

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

547 

548 The text of the hint is rendered in the appropriate 

549 location for the database backend in use, relative 

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

551 passed as the 

552 ``selectable`` argument. The dialect implementation 

553 typically uses Python string substitution syntax 

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

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

556 following:: 

557 

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

559 

560 Would render SQL as: 

561 

562 .. sourcecode:: sql 

563 

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

565 

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

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

568 Database and MSSql simultaneously:: 

569 

570 select(mytable).with_hint( 

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

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

573 

574 .. seealso:: 

575 

576 :meth:`_expression.Select.with_statement_hint` 

577 

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

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

580 MySQL or Oracle Database optimizer hints 

581 

582 """ 

583 

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

585 

586 def _with_hint( 

587 self, 

588 selectable: Optional[_FromClauseArgument], 

589 text: str, 

590 dialect_name: str, 

591 ) -> Self: 

592 if selectable is None: 

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

594 else: 

595 self._hints = self._hints.union( 

596 { 

597 ( 

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

599 dialect_name, 

600 ): text 

601 } 

602 ) 

603 return self 

604 

605 

606class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

608 clause of a ``SELECT`` statement. 

609 

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

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

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

613 

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

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

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

617 :class:`_expression.ColumnElement` 

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

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

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

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

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

623 

624 

625 """ 

626 

627 __visit_name__ = "fromclause" 

628 named_with_column = False 

629 

630 @util.ro_non_memoized_property 

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

632 return () 

633 

634 _is_clone_of: Optional[FromClause] 

635 

636 _columns: ColumnCollection[Any, Any] 

637 

638 schema: Optional[str] = None 

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

640 

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

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

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

644 

645 """ 

646 

647 is_selectable = True 

648 _is_from_clause = True 

649 _is_join = False 

650 

651 _use_schema_map = False 

652 

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

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

655 

656 

657 e.g.:: 

658 

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

660 

661 .. seealso:: 

662 

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

664 method which allows for arbitrary column lists. 

665 

666 """ 

667 return Select(self) 

668 

669 def join( 

670 self, 

671 right: _FromClauseArgument, 

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

673 isouter: bool = False, 

674 full: bool = False, 

675 ) -> Join: 

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

677 :class:`_expression.FromClause` 

678 to another :class:`FromClause`. 

679 

680 E.g.:: 

681 

682 from sqlalchemy import join 

683 

684 j = user_table.join( 

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

686 ) 

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

688 

689 would emit SQL along the lines of: 

690 

691 .. sourcecode:: sql 

692 

693 SELECT user.id, user.name FROM user 

694 JOIN address ON user.id = address.user_id 

695 

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

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

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

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

700 class. 

701 

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

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

704 will attempt to 

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

706 

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

708 

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

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

711 

712 .. seealso:: 

713 

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

715 

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

717 

718 """ 

719 

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

721 

722 def outerjoin( 

723 self, 

724 right: _FromClauseArgument, 

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

726 full: bool = False, 

727 ) -> Join: 

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

729 :class:`_expression.FromClause` 

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

731 True. 

732 

733 E.g.:: 

734 

735 from sqlalchemy import outerjoin 

736 

737 j = user_table.outerjoin( 

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

739 ) 

740 

741 The above is equivalent to:: 

742 

743 j = user_table.join( 

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

745 ) 

746 

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

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

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

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

751 class. 

752 

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

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

755 will attempt to 

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

757 

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

759 LEFT OUTER JOIN. 

760 

761 .. seealso:: 

762 

763 :meth:`_expression.FromClause.join` 

764 

765 :class:`_expression.Join` 

766 

767 """ # noqa: E501 

768 

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

770 

771 def alias( 

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

773 ) -> NamedFromClause: 

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

775 

776 E.g.:: 

777 

778 a2 = some_table.alias("a2") 

779 

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

781 object which can be used 

782 as a FROM clause in any SELECT statement. 

783 

784 .. seealso:: 

785 

786 :ref:`tutorial_using_aliases` 

787 

788 :func:`_expression.alias` 

789 

790 """ 

791 

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

793 

794 def tablesample( 

795 self, 

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

797 name: Optional[str] = None, 

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

799 ) -> TableSample: 

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

801 

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

803 construct also 

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

805 

806 .. seealso:: 

807 

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

809 

810 """ 

811 return TableSample._construct( 

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

813 ) 

814 

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

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

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

818 

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

820 

821 """ 

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

823 # Other constructs override this to traverse through 

824 # contained elements. 

825 return fromclause in self._cloned_set 

826 

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

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

829 the other represent the same lexical identity. 

830 

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

832 if they are the same via annotation identity. 

833 

834 """ 

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

836 

837 @util.ro_non_memoized_property 

838 def description(self) -> str: 

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

840 

841 Used primarily for error message formatting. 

842 

843 """ 

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

845 

846 def _generate_fromclause_column_proxies( 

847 self, 

848 fromclause: FromClause, 

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

850 primary_key: ColumnSet, 

851 foreign_keys: Set[KeyedColumnElement[Any]], 

852 ) -> None: 

853 columns._populate_separate_keys( 

854 col._make_proxy( 

855 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

856 ) 

857 for col in self.c 

858 ) 

859 

860 @util.ro_non_memoized_property 

861 def exported_columns( 

862 self, 

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

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

865 that represents the "exported" 

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

867 

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

869 object are synonymous 

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

871 

872 .. versionadded:: 1.4 

873 

874 .. seealso:: 

875 

876 :attr:`_expression.Selectable.exported_columns` 

877 

878 :attr:`_expression.SelectBase.exported_columns` 

879 

880 

881 """ 

882 return self.c 

883 

884 @util.ro_non_memoized_property 

885 def columns( 

886 self, 

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

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

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

890 

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

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

893 other selectable-bound columns:: 

894 

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

896 

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

898 

899 """ 

900 return self.c 

901 

902 @util.ro_memoized_property 

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

904 """ 

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

906 

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

908 

909 """ 

910 if "_columns" not in self.__dict__: 

911 self._setup_collections() 

912 return self._columns.as_readonly() 

913 

914 def _setup_collections(self) -> None: 

915 assert "_columns" not in self.__dict__ 

916 assert "primary_key" not in self.__dict__ 

917 assert "foreign_keys" not in self.__dict__ 

918 

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

920 primary_key = ColumnSet() 

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

922 

923 self._populate_column_collection( 

924 columns=_columns, 

925 primary_key=primary_key, 

926 foreign_keys=foreign_keys, 

927 ) 

928 

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

930 # but greatly reduces the surface for problems 

931 self._columns = _columns 

932 self.primary_key = primary_key # type: ignore 

933 self.foreign_keys = foreign_keys # type: ignore 

934 

935 @util.ro_non_memoized_property 

936 def entity_namespace(self) -> _EntityNamespace: 

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

938 

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

940 expressions, such as:: 

941 

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

943 

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

945 be overridden using the "entity_namespace" annotation to deliver 

946 alternative results. 

947 

948 """ 

949 return self.c 

950 

951 @util.ro_memoized_property 

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

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

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

955 

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

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

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

959 

960 """ 

961 self._setup_collections() 

962 return self.primary_key 

963 

964 @util.ro_memoized_property 

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

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

967 which this FromClause references. 

968 

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

970 :class:`_schema.Table`-wide 

971 :class:`_schema.ForeignKeyConstraint`. 

972 

973 .. seealso:: 

974 

975 :attr:`_schema.Table.foreign_key_constraints` 

976 

977 """ 

978 self._setup_collections() 

979 return self.foreign_keys 

980 

981 def _reset_column_collection(self) -> None: 

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

983 

984 This collection is separate from all the other memoized things 

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

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

987 has already established strong relationships 

988 with the exported columns. 

989 

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

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

992 

993 """ 

994 

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

996 self.__dict__.pop(key, None) 

997 

998 @util.ro_non_memoized_property 

999 def _select_iterable(self) -> _SelectIterable: 

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

1001 

1002 @property 

1003 def _cols_populated(self) -> bool: 

1004 return "_columns" in self.__dict__ 

1005 

1006 def _populate_column_collection( 

1007 self, 

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

1009 primary_key: ColumnSet, 

1010 foreign_keys: Set[KeyedColumnElement[Any]], 

1011 ) -> None: 

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

1013 

1014 Each implementation has a different way of establishing 

1015 this collection. 

1016 

1017 """ 

1018 

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

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

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

1022 selectable ultimately should proxy this column. 

1023 

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

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

1026 Table objects it ultimately derives from. 

1027 

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

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

1030 but it will return None. 

1031 

1032 This method is currently used by Declarative to allow Table 

1033 columns to be added to a partially constructed inheritance 

1034 mapping that may have already produced joins. The method 

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

1036 and/or caveats aren't yet clear. 

1037 

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

1039 default via an event, which would require that 

1040 selectables maintain a weak referencing collection of all 

1041 derivations. 

1042 

1043 """ 

1044 self._reset_column_collection() 

1045 

1046 def _anonymous_fromclause( 

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

1048 ) -> FromClause: 

1049 return self.alias(name=name) 

1050 

1051 if TYPE_CHECKING: 

1052 

1053 def self_group( 

1054 self, against: Optional[OperatorType] = None 

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

1056 

1057 

1058class NamedFromClause(FromClause): 

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

1060 

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

1062 

1063 .. versionadded:: 2.0 

1064 

1065 """ 

1066 

1067 named_with_column = True 

1068 

1069 name: str 

1070 

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

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

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

1074 :class:`_expression.FromClause`. 

1075 

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

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

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

1079 such as PostgreSQL, Oracle Database and SQL Server. 

1080 

1081 E.g.: 

1082 

1083 .. sourcecode:: pycon+sql 

1084 

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

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

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

1088 >>> print(stmt) 

1089 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1090 FROM a 

1091 

1092 .. versionadded:: 1.4.0b2 

1093 

1094 .. seealso:: 

1095 

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

1097 

1098 """ 

1099 return TableValuedColumn(self, type_api.TABLEVALUE) 

1100 

1101 

1102class SelectLabelStyle(Enum): 

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

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

1105 

1106 LABEL_STYLE_NONE = 0 

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

1108 columns clause of a SELECT statement. 

1109 

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

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

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

1113 

1114 .. sourcecode:: pycon+sql 

1115 

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

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

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

1119 >>> print( 

1120 ... select(table1, table2) 

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

1122 ... .set_label_style(LABEL_STYLE_NONE) 

1123 ... ) 

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

1125 FROM table1 JOIN table2 ON true 

1126 

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

1128 

1129 .. versionadded:: 1.4 

1130 

1131 """ # noqa: E501 

1132 

1133 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1137 tables, aliases, or subqueries. 

1138 

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

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

1141 ``table2_columna``: 

1142 

1143 .. sourcecode:: pycon+sql 

1144 

1145 >>> from sqlalchemy import ( 

1146 ... table, 

1147 ... column, 

1148 ... select, 

1149 ... true, 

1150 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1151 ... ) 

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

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

1154 >>> print( 

1155 ... select(table1, table2) 

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

1157 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1158 ... ) 

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

1160 FROM table1 JOIN table2 ON true 

1161 

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

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

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

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

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

1167 

1168 

1169 .. versionadded:: 1.4 

1170 

1171 """ # noqa: E501 

1172 

1173 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1176 when generating the columns clause of a SELECT statement. 

1177 

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

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

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

1181 

1182 .. sourcecode:: pycon+sql 

1183 

1184 >>> from sqlalchemy import ( 

1185 ... table, 

1186 ... column, 

1187 ... select, 

1188 ... true, 

1189 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1190 ... ) 

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

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

1193 >>> print( 

1194 ... select(table1, table2) 

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

1196 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1197 ... ) 

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

1199 FROM table1 JOIN table2 ON true 

1200 

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

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

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

1204 

1205 .. versionadded:: 1.4 

1206 

1207 """ # noqa: E501 

1208 

1209 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1210 """The default label style, refers to 

1211 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1212 

1213 .. versionadded:: 1.4 

1214 

1215 """ 

1216 

1217 LABEL_STYLE_LEGACY_ORM = 3 

1218 

1219 

1220( 

1221 LABEL_STYLE_NONE, 

1222 LABEL_STYLE_TABLENAME_PLUS_COL, 

1223 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1224 _, 

1225) = list(SelectLabelStyle) 

1226 

1227LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1228 

1229 

1230class Join(roles.DMLTableRole, FromClause): 

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

1232 :class:`_expression.FromClause` 

1233 elements. 

1234 

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

1236 is the module-level 

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

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

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

1240 :class:`_schema.Table`). 

1241 

1242 .. seealso:: 

1243 

1244 :func:`_expression.join` 

1245 

1246 :meth:`_expression.FromClause.join` 

1247 

1248 """ 

1249 

1250 __visit_name__ = "join" 

1251 

1252 _traverse_internals: _TraverseInternalsType = [ 

1253 ("left", InternalTraversal.dp_clauseelement), 

1254 ("right", InternalTraversal.dp_clauseelement), 

1255 ("onclause", InternalTraversal.dp_clauseelement), 

1256 ("isouter", InternalTraversal.dp_boolean), 

1257 ("full", InternalTraversal.dp_boolean), 

1258 ] 

1259 

1260 _is_join = True 

1261 

1262 left: FromClause 

1263 right: FromClause 

1264 onclause: Optional[ColumnElement[bool]] 

1265 isouter: bool 

1266 full: bool 

1267 

1268 def __init__( 

1269 self, 

1270 left: _FromClauseArgument, 

1271 right: _FromClauseArgument, 

1272 onclause: Optional[_OnClauseArgument] = None, 

1273 isouter: bool = False, 

1274 full: bool = False, 

1275 ): 

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

1277 

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

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

1280 :class:`_expression.FromClause` object. 

1281 

1282 """ 

1283 

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

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

1286 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1289 # callcounts for a single compilation in that particular test 

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

1291 # 29200 -> 30373 

1292 

1293 self.left = coercions.expect( 

1294 roles.FromClauseRole, 

1295 left, 

1296 ) 

1297 self.right = coercions.expect( 

1298 roles.FromClauseRole, 

1299 right, 

1300 ).self_group() 

1301 

1302 if onclause is None: 

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

1304 else: 

1305 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1306 # not merged yet 

1307 self.onclause = coercions.expect( 

1308 roles.OnClauseRole, onclause 

1309 ).self_group(against=operators._asbool) 

1310 

1311 self.isouter = isouter 

1312 self.full = full 

1313 

1314 @util.ro_non_memoized_property 

1315 def description(self) -> str: 

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

1317 self.left.description, 

1318 id(self.left), 

1319 self.right.description, 

1320 id(self.right), 

1321 ) 

1322 

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

1324 return ( 

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

1326 # as well 

1327 hash(fromclause) == hash(self) 

1328 or self.left.is_derived_from(fromclause) 

1329 or self.right.is_derived_from(fromclause) 

1330 ) 

1331 

1332 def self_group( 

1333 self, against: Optional[OperatorType] = None 

1334 ) -> FromGrouping: 

1335 return FromGrouping(self) 

1336 

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

1338 def _populate_column_collection( 

1339 self, 

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

1341 primary_key: ColumnSet, 

1342 foreign_keys: Set[KeyedColumnElement[Any]], 

1343 ) -> None: 

1344 sqlutil = util.preloaded.sql_util 

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

1346 c for c in self.right.c 

1347 ] 

1348 

1349 primary_key.extend( # type: ignore 

1350 sqlutil.reduce_columns( 

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

1352 ) 

1353 ) 

1354 columns._populate_separate_keys( 

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

1356 ) 

1357 foreign_keys.update( 

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

1359 ) 

1360 

1361 def _copy_internals( 

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

1363 ) -> None: 

1364 # see Select._copy_internals() for similar concept 

1365 

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

1367 # determine the new FROM clauses 

1368 all_the_froms = set( 

1369 itertools.chain( 

1370 _from_objects(self.left), 

1371 _from_objects(self.right), 

1372 ) 

1373 ) 

1374 

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

1376 # cache used by the clone function 

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

1378 

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

1380 # ColumnClause with parent table referring to those 

1381 # replaced FromClause objects 

1382 def replace( 

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

1384 **kw: Any, 

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

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

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

1388 return newelem 

1389 return None 

1390 

1391 kw["replace"] = replace 

1392 

1393 # run normal _copy_internals. the clones for 

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

1395 # cache 

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

1397 

1398 self._reset_memoizations() 

1399 

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

1401 super()._refresh_for_new_column(column) 

1402 self.left._refresh_for_new_column(column) 

1403 self.right._refresh_for_new_column(column) 

1404 

1405 def _match_primaries( 

1406 self, 

1407 left: FromClause, 

1408 right: FromClause, 

1409 ) -> ColumnElement[bool]: 

1410 if isinstance(left, Join): 

1411 left_right = left.right 

1412 else: 

1413 left_right = None 

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

1415 

1416 @classmethod 

1417 def _join_condition( 

1418 cls, 

1419 a: FromClause, 

1420 b: FromClause, 

1421 *, 

1422 a_subset: Optional[FromClause] = None, 

1423 consider_as_foreign_keys: Optional[ 

1424 AbstractSet[ColumnClause[Any]] 

1425 ] = None, 

1426 ) -> ColumnElement[bool]: 

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

1428 

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

1430 

1431 """ 

1432 constraints = cls._joincond_scan_left_right( 

1433 a, a_subset, b, consider_as_foreign_keys 

1434 ) 

1435 

1436 if len(constraints) > 1: 

1437 cls._joincond_trim_constraints( 

1438 a, b, constraints, consider_as_foreign_keys 

1439 ) 

1440 

1441 if len(constraints) == 0: 

1442 if isinstance(b, FromGrouping): 

1443 hint = ( 

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

1445 "subquery using alias()?" 

1446 ) 

1447 else: 

1448 hint = "" 

1449 raise exc.NoForeignKeysError( 

1450 "Can't find any foreign key relationships " 

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

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

1453 ) 

1454 

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

1456 if len(crit) == 1: 

1457 return crit[0] 

1458 else: 

1459 return and_(*crit) 

1460 

1461 @classmethod 

1462 def _can_join( 

1463 cls, 

1464 left: FromClause, 

1465 right: FromClause, 

1466 *, 

1467 consider_as_foreign_keys: Optional[ 

1468 AbstractSet[ColumnClause[Any]] 

1469 ] = None, 

1470 ) -> bool: 

1471 if isinstance(left, Join): 

1472 left_right = left.right 

1473 else: 

1474 left_right = None 

1475 

1476 constraints = cls._joincond_scan_left_right( 

1477 a=left, 

1478 b=right, 

1479 a_subset=left_right, 

1480 consider_as_foreign_keys=consider_as_foreign_keys, 

1481 ) 

1482 

1483 return bool(constraints) 

1484 

1485 @classmethod 

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

1487 def _joincond_scan_left_right( 

1488 cls, 

1489 a: FromClause, 

1490 a_subset: Optional[FromClause], 

1491 b: FromClause, 

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

1493 ) -> collections.defaultdict[ 

1494 Optional[ForeignKeyConstraint], 

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

1496 ]: 

1497 sql_util = util.preloaded.sql_util 

1498 

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

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

1501 

1502 constraints: collections.defaultdict[ 

1503 Optional[ForeignKeyConstraint], 

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

1505 ] = collections.defaultdict(list) 

1506 

1507 for left in (a_subset, a): 

1508 if left is None: 

1509 continue 

1510 for fk in sorted( 

1511 b.foreign_keys, 

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

1513 ): 

1514 if ( 

1515 consider_as_foreign_keys is not None 

1516 and fk.parent not in consider_as_foreign_keys 

1517 ): 

1518 continue 

1519 try: 

1520 col = fk.get_referent(left) 

1521 except exc.NoReferenceError as nrte: 

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

1523 if nrte.table_name in table_names: 

1524 raise 

1525 else: 

1526 continue 

1527 

1528 if col is not None: 

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

1530 if left is not b: 

1531 for fk in sorted( 

1532 left.foreign_keys, 

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

1534 ): 

1535 if ( 

1536 consider_as_foreign_keys is not None 

1537 and fk.parent not in consider_as_foreign_keys 

1538 ): 

1539 continue 

1540 try: 

1541 col = fk.get_referent(b) 

1542 except exc.NoReferenceError as nrte: 

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

1544 if nrte.table_name in table_names: 

1545 raise 

1546 else: 

1547 continue 

1548 

1549 if col is not None: 

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

1551 if constraints: 

1552 break 

1553 return constraints 

1554 

1555 @classmethod 

1556 def _joincond_trim_constraints( 

1557 cls, 

1558 a: FromClause, 

1559 b: FromClause, 

1560 constraints: Dict[Any, Any], 

1561 consider_as_foreign_keys: Optional[Any], 

1562 ) -> None: 

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

1564 # to include just those FKCs that match exactly to 

1565 # "consider_as_foreign_keys". 

1566 if consider_as_foreign_keys: 

1567 for const in list(constraints): 

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

1569 consider_as_foreign_keys 

1570 ): 

1571 del constraints[const] 

1572 

1573 # if still multiple constraints, but 

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

1575 if len(constraints) > 1: 

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

1577 if len(dedupe) == 1: 

1578 key = list(constraints)[0] 

1579 constraints = {key: constraints[key]} 

1580 

1581 if len(constraints) != 1: 

1582 raise exc.AmbiguousForeignKeysError( 

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

1584 "tables have more than one foreign key " 

1585 "constraint relationship between them. " 

1586 "Please specify the 'onclause' of this " 

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

1588 ) 

1589 

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

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

1592 :class:`_expression.Join`. 

1593 

1594 E.g.:: 

1595 

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

1597 

1598 stmt = stmt.select() 

1599 

1600 The above will produce a SQL string resembling: 

1601 

1602 .. sourcecode:: sql 

1603 

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

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

1606 

1607 """ 

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

1609 

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

1611 def _anonymous_fromclause( 

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

1613 ) -> TODO_Any: 

1614 sqlutil = util.preloaded.sql_util 

1615 if flat: 

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

1617 left_name = name # will recurse 

1618 else: 

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

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

1621 else: 

1622 left_name = name 

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

1624 right_name = name # will recurse 

1625 else: 

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

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

1628 else: 

1629 right_name = name 

1630 left_a, right_a = ( 

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

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

1633 ) 

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

1635 sqlutil.ClauseAdapter(right_a) 

1636 ) 

1637 

1638 return left_a.join( 

1639 right_a, 

1640 adapter.traverse(self.onclause), 

1641 isouter=self.isouter, 

1642 full=self.full, 

1643 ) 

1644 else: 

1645 return ( 

1646 self.select() 

1647 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1648 .correlate(None) 

1649 .alias(name) 

1650 ) 

1651 

1652 @util.ro_non_memoized_property 

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

1654 return itertools.chain( 

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

1656 ) 

1657 

1658 @util.ro_non_memoized_property 

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

1660 self_list: List[FromClause] = [self] 

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

1662 

1663 

1664class NoInit: 

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

1666 raise NotImplementedError( 

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

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

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

1670 "selectable objects." 

1671 % ( 

1672 self.__class__.__name__, 

1673 self.__class__.__name__.lower(), 

1674 self.__class__.__name__.lower(), 

1675 ) 

1676 ) 

1677 

1678 

1679class LateralFromClause(NamedFromClause): 

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

1681 

1682 

1683# FromClause -> 

1684# AliasedReturnsRows 

1685# -> Alias only for FromClause 

1686# -> Subquery only for SelectBase 

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

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

1689# w/ non-deprecated coercion 

1690# -> TableSample -> only for FromClause 

1691 

1692 

1693class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1695 selectables.""" 

1696 

1697 _is_from_container = True 

1698 

1699 _supports_derived_columns = False 

1700 

1701 element: ReturnsRows 

1702 

1703 _traverse_internals: _TraverseInternalsType = [ 

1704 ("element", InternalTraversal.dp_clauseelement), 

1705 ("name", InternalTraversal.dp_anon_name), 

1706 ] 

1707 

1708 @classmethod 

1709 def _construct( 

1710 cls, 

1711 selectable: Any, 

1712 *, 

1713 name: Optional[str] = None, 

1714 **kw: Any, 

1715 ) -> Self: 

1716 obj = cls.__new__(cls) 

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

1718 return obj 

1719 

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

1721 self.element = coercions.expect( 

1722 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1723 ) 

1724 self.element = selectable 

1725 self._orig_name = name 

1726 if name is None: 

1727 if ( 

1728 isinstance(selectable, FromClause) 

1729 and selectable.named_with_column 

1730 ): 

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

1732 if isinstance(name, _anonymous_label): 

1733 name = None 

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

1735 self.name = name 

1736 

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

1738 super()._refresh_for_new_column(column) 

1739 self.element._refresh_for_new_column(column) 

1740 

1741 def _populate_column_collection( 

1742 self, 

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

1744 primary_key: ColumnSet, 

1745 foreign_keys: Set[KeyedColumnElement[Any]], 

1746 ) -> None: 

1747 self.element._generate_fromclause_column_proxies( 

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

1749 ) 

1750 

1751 @util.ro_non_memoized_property 

1752 def description(self) -> str: 

1753 name = self.name 

1754 if isinstance(name, _anonymous_label): 

1755 return "anon_1" 

1756 

1757 return name 

1758 

1759 @util.ro_non_memoized_property 

1760 def implicit_returning(self) -> bool: 

1761 return self.element.implicit_returning # type: ignore 

1762 

1763 @property 

1764 def original(self) -> ReturnsRows: 

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

1766 return self.element 

1767 

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

1769 if fromclause in self._cloned_set: 

1770 return True 

1771 return self.element.is_derived_from(fromclause) 

1772 

1773 def _copy_internals( 

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

1775 ) -> None: 

1776 existing_element = self.element 

1777 

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

1779 

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

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

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

1783 # performance. 

1784 if existing_element is not self.element: 

1785 self._reset_column_collection() 

1786 

1787 @property 

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

1789 return [self] 

1790 

1791 

1792class FromClauseAlias(AliasedReturnsRows): 

1793 element: FromClause 

1794 

1795 @util.ro_non_memoized_property 

1796 def description(self) -> str: 

1797 name = self.name 

1798 if isinstance(name, _anonymous_label): 

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

1800 

1801 return name 

1802 

1803 

1804class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1806 

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

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

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

1810 

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

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

1813 method available 

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

1815 

1816 .. seealso:: 

1817 

1818 :meth:`_expression.FromClause.alias` 

1819 

1820 """ 

1821 

1822 __visit_name__ = "alias" 

1823 

1824 inherit_cache = True 

1825 

1826 element: FromClause 

1827 

1828 @classmethod 

1829 def _factory( 

1830 cls, 

1831 selectable: FromClause, 

1832 name: Optional[str] = None, 

1833 flat: bool = False, 

1834 ) -> NamedFromClause: 

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

1836 name=name, flat=flat 

1837 ) 

1838 

1839 

1840class TableValuedAlias(LateralFromClause, Alias): 

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

1842 

1843 This construct provides for a SQL function that returns columns 

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

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

1846 method, e.g.: 

1847 

1848 .. sourcecode:: pycon+sql 

1849 

1850 >>> from sqlalchemy import select, func 

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

1852 ... "value" 

1853 ... ) 

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

1855 {printsql}SELECT anon_1.value 

1856 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1857 

1858 .. versionadded:: 1.4.0b2 

1859 

1860 .. seealso:: 

1861 

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

1863 

1864 """ # noqa: E501 

1865 

1866 __visit_name__ = "table_valued_alias" 

1867 

1868 _supports_derived_columns = True 

1869 _render_derived = False 

1870 _render_derived_w_types = False 

1871 joins_implicitly = False 

1872 

1873 _traverse_internals: _TraverseInternalsType = [ 

1874 ("element", InternalTraversal.dp_clauseelement), 

1875 ("name", InternalTraversal.dp_anon_name), 

1876 ("_tableval_type", InternalTraversal.dp_type), 

1877 ("_render_derived", InternalTraversal.dp_boolean), 

1878 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1879 ] 

1880 

1881 def _init( 

1882 self, 

1883 selectable: Any, 

1884 *, 

1885 name: Optional[str] = None, 

1886 table_value_type: Optional[TableValueType] = None, 

1887 joins_implicitly: bool = False, 

1888 ) -> None: 

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

1890 

1891 self.joins_implicitly = joins_implicitly 

1892 self._tableval_type = ( 

1893 type_api.TABLEVALUE 

1894 if table_value_type is None 

1895 else table_value_type 

1896 ) 

1897 

1898 @HasMemoized.memoized_attribute 

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

1900 """Return a column expression representing this 

1901 :class:`_sql.TableValuedAlias`. 

1902 

1903 This accessor is used to implement the 

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

1905 method for further details. 

1906 

1907 E.g.: 

1908 

1909 .. sourcecode:: pycon+sql 

1910 

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

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

1913 

1914 .. seealso:: 

1915 

1916 :meth:`_functions.FunctionElement.column_valued` 

1917 

1918 """ 

1919 

1920 return TableValuedColumn(self, self._tableval_type) 

1921 

1922 def alias( 

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

1924 ) -> TableValuedAlias: 

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

1926 

1927 This creates a distinct FROM object that will be distinguished 

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

1929 

1930 """ 

1931 

1932 tva: TableValuedAlias = TableValuedAlias._construct( 

1933 self, 

1934 name=name, 

1935 table_value_type=self._tableval_type, 

1936 joins_implicitly=self.joins_implicitly, 

1937 ) 

1938 

1939 if self._render_derived: 

1940 tva._render_derived = True 

1941 tva._render_derived_w_types = self._render_derived_w_types 

1942 

1943 return tva 

1944 

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

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

1947 set, so that it renders as LATERAL. 

1948 

1949 .. seealso:: 

1950 

1951 :func:`_expression.lateral` 

1952 

1953 """ 

1954 tva = self.alias(name=name) 

1955 tva._is_lateral = True 

1956 return tva 

1957 

1958 def render_derived( 

1959 self, 

1960 name: Optional[str] = None, 

1961 with_types: bool = False, 

1962 ) -> TableValuedAlias: 

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

1964 

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

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

1967 

1968 .. sourcecode:: pycon+sql 

1969 

1970 >>> print( 

1971 ... select( 

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

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

1974 ... .render_derived() 

1975 ... ) 

1976 ... ) 

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

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

1979 

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

1981 the alias expression (this syntax currently applies to the 

1982 PostgreSQL database): 

1983 

1984 .. sourcecode:: pycon+sql 

1985 

1986 >>> print( 

1987 ... select( 

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

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

1990 ... .render_derived(with_types=True) 

1991 ... ) 

1992 ... ) 

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

1994 AS anon_1(a INTEGER, b VARCHAR) 

1995 

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

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

1998 

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

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

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

2002 

2003 """ # noqa: E501 

2004 

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

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

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

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

2009 # (just saw it happen on CI) 

2010 

2011 # construct against original to prevent memory growth 

2012 # for repeated generations 

2013 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2014 self.element, 

2015 name=name, 

2016 table_value_type=self._tableval_type, 

2017 joins_implicitly=self.joins_implicitly, 

2018 ) 

2019 new_alias._render_derived = True 

2020 new_alias._render_derived_w_types = with_types 

2021 return new_alias 

2022 

2023 

2024class Lateral(FromClauseAlias, LateralFromClause): 

2025 """Represent a LATERAL subquery. 

2026 

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

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

2029 method available 

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

2031 

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

2033 PostgreSQL versions provide support for this keyword. 

2034 

2035 .. seealso:: 

2036 

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

2038 

2039 """ 

2040 

2041 __visit_name__ = "lateral" 

2042 _is_lateral = True 

2043 

2044 inherit_cache = True 

2045 

2046 @classmethod 

2047 def _factory( 

2048 cls, 

2049 selectable: Union[SelectBase, _FromClauseArgument], 

2050 name: Optional[str] = None, 

2051 ) -> LateralFromClause: 

2052 return coercions.expect( 

2053 roles.FromClauseRole, selectable, explicit_subquery=True 

2054 ).lateral(name=name) 

2055 

2056 

2057class TableSample(FromClauseAlias): 

2058 """Represent a TABLESAMPLE clause. 

2059 

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

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

2062 method 

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

2064 

2065 .. seealso:: 

2066 

2067 :func:`_expression.tablesample` 

2068 

2069 """ 

2070 

2071 __visit_name__ = "tablesample" 

2072 

2073 _traverse_internals: _TraverseInternalsType = ( 

2074 AliasedReturnsRows._traverse_internals 

2075 + [ 

2076 ("sampling", InternalTraversal.dp_clauseelement), 

2077 ("seed", InternalTraversal.dp_clauseelement), 

2078 ] 

2079 ) 

2080 

2081 @classmethod 

2082 def _factory( 

2083 cls, 

2084 selectable: _FromClauseArgument, 

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

2086 name: Optional[str] = None, 

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

2088 ) -> TableSample: 

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

2090 sampling, name=name, seed=seed 

2091 ) 

2092 

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

2094 def _init( # type: ignore[override] 

2095 self, 

2096 selectable: Any, 

2097 *, 

2098 name: Optional[str] = None, 

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

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

2101 ) -> None: 

2102 assert sampling is not None 

2103 functions = util.preloaded.sql_functions 

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

2105 sampling = functions.func.system(sampling) 

2106 

2107 self.sampling: Function[Any] = sampling 

2108 self.seed = seed 

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

2110 

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

2112 return self.sampling 

2113 

2114 

2115class CTE( 

2116 roles.DMLTableRole, 

2117 roles.IsCTERole, 

2118 Generative, 

2119 HasPrefixes, 

2120 HasSuffixes, 

2121 AliasedReturnsRows, 

2122): 

2123 """Represent a Common Table Expression. 

2124 

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

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

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

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

2129 :class:`_sql.Update` and 

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

2131 usage details on CTEs. 

2132 

2133 .. seealso:: 

2134 

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

2136 

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

2138 

2139 """ 

2140 

2141 __visit_name__ = "cte" 

2142 

2143 _traverse_internals: _TraverseInternalsType = ( 

2144 AliasedReturnsRows._traverse_internals 

2145 + [ 

2146 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2147 ("_restates", InternalTraversal.dp_clauseelement), 

2148 ("recursive", InternalTraversal.dp_boolean), 

2149 ("nesting", InternalTraversal.dp_boolean), 

2150 ] 

2151 + HasPrefixes._has_prefixes_traverse_internals 

2152 + HasSuffixes._has_suffixes_traverse_internals 

2153 ) 

2154 

2155 element: HasCTE 

2156 

2157 @classmethod 

2158 def _factory( 

2159 cls, 

2160 selectable: HasCTE, 

2161 name: Optional[str] = None, 

2162 recursive: bool = False, 

2163 ) -> CTE: 

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

2165 or Common Table Expression instance. 

2166 

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

2168 

2169 """ 

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

2171 name=name, recursive=recursive 

2172 ) 

2173 

2174 def _init( 

2175 self, 

2176 selectable: Select[Unpack[TupleAny]], 

2177 *, 

2178 name: Optional[str] = None, 

2179 recursive: bool = False, 

2180 nesting: bool = False, 

2181 _cte_alias: Optional[CTE] = None, 

2182 _restates: Optional[CTE] = None, 

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

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

2185 ) -> None: 

2186 self.recursive = recursive 

2187 self.nesting = nesting 

2188 self._cte_alias = _cte_alias 

2189 # Keep recursivity reference with union/union_all 

2190 self._restates = _restates 

2191 if _prefixes: 

2192 self._prefixes = _prefixes 

2193 if _suffixes: 

2194 self._suffixes = _suffixes 

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

2196 

2197 def _populate_column_collection( 

2198 self, 

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

2200 primary_key: ColumnSet, 

2201 foreign_keys: Set[KeyedColumnElement[Any]], 

2202 ) -> None: 

2203 if self._cte_alias is not None: 

2204 self._cte_alias._generate_fromclause_column_proxies( 

2205 self, 

2206 columns, 

2207 primary_key=primary_key, 

2208 foreign_keys=foreign_keys, 

2209 ) 

2210 else: 

2211 self.element._generate_fromclause_column_proxies( 

2212 self, 

2213 columns, 

2214 primary_key=primary_key, 

2215 foreign_keys=foreign_keys, 

2216 ) 

2217 

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

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

2220 :class:`_expression.CTE`. 

2221 

2222 This method is a CTE-specific specialization of the 

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

2224 

2225 .. seealso:: 

2226 

2227 :ref:`tutorial_using_aliases` 

2228 

2229 :func:`_expression.alias` 

2230 

2231 """ 

2232 return CTE._construct( 

2233 self.element, 

2234 name=name, 

2235 recursive=self.recursive, 

2236 nesting=self.nesting, 

2237 _cte_alias=self, 

2238 _prefixes=self._prefixes, 

2239 _suffixes=self._suffixes, 

2240 ) 

2241 

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

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

2244 of the original CTE against the given selectables provided 

2245 as positional arguments. 

2246 

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

2248 UNION. 

2249 

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

2251 

2252 .. seealso:: 

2253 

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

2255 

2256 """ 

2257 assert is_select_statement( 

2258 self.element 

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

2260 

2261 return CTE._construct( 

2262 self.element.union(*other), 

2263 name=self.name, 

2264 recursive=self.recursive, 

2265 nesting=self.nesting, 

2266 _restates=self, 

2267 _prefixes=self._prefixes, 

2268 _suffixes=self._suffixes, 

2269 ) 

2270 

2271 def union_all( 

2272 self, *other: _SelectStatementForCompoundArgument[Any] 

2273 ) -> CTE: 

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

2275 of the original CTE against the given selectables provided 

2276 as positional arguments. 

2277 

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

2279 UNION. 

2280 

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

2282 

2283 .. seealso:: 

2284 

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

2286 

2287 """ 

2288 

2289 assert is_select_statement( 

2290 self.element 

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

2292 

2293 return CTE._construct( 

2294 self.element.union_all(*other), 

2295 name=self.name, 

2296 recursive=self.recursive, 

2297 nesting=self.nesting, 

2298 _restates=self, 

2299 _prefixes=self._prefixes, 

2300 _suffixes=self._suffixes, 

2301 ) 

2302 

2303 def _get_reference_cte(self) -> CTE: 

2304 """ 

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

2306 Updated CTEs should still refer to the original CTE. 

2307 This function returns this reference identifier. 

2308 """ 

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

2310 

2311 

2312class _CTEOpts(NamedTuple): 

2313 nesting: bool 

2314 

2315 

2316class _ColumnsPlusNames(NamedTuple): 

2317 required_label_name: Optional[str] 

2318 """ 

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

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

2321 """ 

2322 

2323 proxy_key: Optional[str] 

2324 """ 

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

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

2327 select.selected_columns collection 

2328 """ 

2329 

2330 fallback_label_name: Optional[str] 

2331 """ 

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

2333 we have to render a label even though 

2334 required_label_name was not given 

2335 """ 

2336 

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

2338 """ 

2339 the ColumnElement itself 

2340 """ 

2341 

2342 repeated: bool 

2343 """ 

2344 True if this is a duplicate of a previous column 

2345 in the list of columns 

2346 """ 

2347 

2348 

2349class SelectsRows(ReturnsRows): 

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

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

2352 

2353 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2354 

2355 def _generate_columns_plus_names( 

2356 self, 

2357 anon_for_dupe_key: bool, 

2358 cols: Optional[_SelectIterable] = None, 

2359 ) -> List[_ColumnsPlusNames]: 

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

2361 the compiler. 

2362 

2363 This is distinct from the _column_naming_convention generator that's 

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

2365 different rules. the collection returned here calls upon the 

2366 _column_naming_convention as well. 

2367 

2368 """ 

2369 

2370 if cols is None: 

2371 cols = self._all_selected_columns 

2372 

2373 key_naming_convention = SelectState._column_naming_convention( 

2374 self._label_style 

2375 ) 

2376 

2377 names = {} 

2378 

2379 result: List[_ColumnsPlusNames] = [] 

2380 result_append = result.append 

2381 

2382 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2383 label_style_none = self._label_style is LABEL_STYLE_NONE 

2384 

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

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

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

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

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

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

2391 dedupe_hash = 1 

2392 

2393 for c in cols: 

2394 repeated = False 

2395 

2396 if not c._render_label_in_columns_clause: 

2397 effective_name = required_label_name = fallback_label_name = ( 

2398 None 

2399 ) 

2400 elif label_style_none: 

2401 if TYPE_CHECKING: 

2402 assert is_column_element(c) 

2403 

2404 effective_name = required_label_name = None 

2405 fallback_label_name = c._non_anon_label or c._anon_name_label 

2406 else: 

2407 if TYPE_CHECKING: 

2408 assert is_column_element(c) 

2409 

2410 if table_qualified: 

2411 required_label_name = effective_name = ( 

2412 fallback_label_name 

2413 ) = c._tq_label 

2414 else: 

2415 effective_name = fallback_label_name = c._non_anon_label 

2416 required_label_name = None 

2417 

2418 if effective_name is None: 

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

2420 # not need _expression_label but it isn't 

2421 # giving us a clue when to use anon_label instead 

2422 expr_label = c._expression_label 

2423 if expr_label is None: 

2424 repeated = c._anon_name_label in names 

2425 names[c._anon_name_label] = c 

2426 effective_name = required_label_name = None 

2427 

2428 if repeated: 

2429 # here, "required_label_name" is sent as 

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

2431 if table_qualified: 

2432 fallback_label_name = ( 

2433 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2434 ) 

2435 dedupe_hash += 1 

2436 else: 

2437 fallback_label_name = c._dedupe_anon_label_idx( 

2438 dedupe_hash 

2439 ) 

2440 dedupe_hash += 1 

2441 else: 

2442 fallback_label_name = c._anon_name_label 

2443 else: 

2444 required_label_name = effective_name = ( 

2445 fallback_label_name 

2446 ) = expr_label 

2447 

2448 if effective_name is not None: 

2449 if TYPE_CHECKING: 

2450 assert is_column_element(c) 

2451 

2452 if effective_name in names: 

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

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

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

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

2457 # different column under the same name. apply 

2458 # disambiguating label 

2459 if table_qualified: 

2460 required_label_name = fallback_label_name = ( 

2461 c._anon_tq_label 

2462 ) 

2463 else: 

2464 required_label_name = fallback_label_name = ( 

2465 c._anon_name_label 

2466 ) 

2467 

2468 if anon_for_dupe_key and required_label_name in names: 

2469 # here, c._anon_tq_label is definitely unique to 

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

2471 # this should always be true. 

2472 # this is also an infrequent codepath because 

2473 # you need two levels of duplication to be here 

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

2475 

2476 # the column under the disambiguating label is 

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

2478 # subsequent occurrences of the column so that the 

2479 # original stays non-ambiguous 

2480 if table_qualified: 

2481 required_label_name = fallback_label_name = ( 

2482 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2483 ) 

2484 dedupe_hash += 1 

2485 else: 

2486 required_label_name = fallback_label_name = ( 

2487 c._dedupe_anon_label_idx(dedupe_hash) 

2488 ) 

2489 dedupe_hash += 1 

2490 repeated = True 

2491 else: 

2492 names[required_label_name] = c 

2493 elif anon_for_dupe_key: 

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

2495 # label so that the original stays non-ambiguous 

2496 if table_qualified: 

2497 required_label_name = fallback_label_name = ( 

2498 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2499 ) 

2500 dedupe_hash += 1 

2501 else: 

2502 required_label_name = fallback_label_name = ( 

2503 c._dedupe_anon_label_idx(dedupe_hash) 

2504 ) 

2505 dedupe_hash += 1 

2506 repeated = True 

2507 else: 

2508 names[effective_name] = c 

2509 

2510 result_append( 

2511 _ColumnsPlusNames( 

2512 required_label_name, 

2513 key_naming_convention(c), 

2514 fallback_label_name, 

2515 c, 

2516 repeated, 

2517 ) 

2518 ) 

2519 

2520 return result 

2521 

2522 

2523class HasCTE(roles.HasCTERole, SelectsRows): 

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

2525 

2526 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2527 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2528 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2529 ] 

2530 

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

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

2533 

2534 @_generative 

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

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

2537 

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

2539 the parent statement such that they will each be unconditionally 

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

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

2542 

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

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

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

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

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

2548 statement. 

2549 

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

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

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

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

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

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

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

2557 larger statement. 

2558 

2559 E.g.:: 

2560 

2561 from sqlalchemy import table, column, select 

2562 

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

2564 

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

2566 

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

2568 

2569 Would render: 

2570 

2571 .. sourcecode:: sql 

2572 

2573 WITH anon_1 AS ( 

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

2575 ) 

2576 SELECT t.c1, t.c2 

2577 FROM t 

2578 

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

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

2581 statement. 

2582 

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

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

2585 

2586 from sqlalchemy import table, column 

2587 from sqlalchemy.dialects.postgresql import insert 

2588 

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

2590 

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

2592 

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

2594 update_statement = insert_stmt.on_conflict_do_update( 

2595 index_elements=[t.c.c1], 

2596 set_={ 

2597 "c1": insert_stmt.excluded.c1, 

2598 "c2": insert_stmt.excluded.c2, 

2599 }, 

2600 ).add_cte(delete_statement_cte) 

2601 

2602 print(update_statement) 

2603 

2604 The above statement renders as: 

2605 

2606 .. sourcecode:: sql 

2607 

2608 WITH deletions AS ( 

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

2610 ) 

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

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

2613 

2614 .. versionadded:: 1.4.21 

2615 

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

2617 

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

2619 

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

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

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

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

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

2625 this statement when this flag is given. 

2626 

2627 .. versionadded:: 2.0 

2628 

2629 .. seealso:: 

2630 

2631 :paramref:`.HasCTE.cte.nesting` 

2632 

2633 

2634 """ # noqa: E501 

2635 opt = _CTEOpts(nest_here) 

2636 for cte in ctes: 

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

2638 self._independent_ctes += (cte,) 

2639 self._independent_ctes_opts += (opt,) 

2640 return self 

2641 

2642 def cte( 

2643 self, 

2644 name: Optional[str] = None, 

2645 recursive: bool = False, 

2646 nesting: bool = False, 

2647 ) -> CTE: 

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

2649 or Common Table Expression instance. 

2650 

2651 Common table expressions are a SQL standard whereby SELECT 

2652 statements can draw upon secondary statements specified along 

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

2654 Special semantics regarding UNION can also be employed to 

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

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

2657 

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

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

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

2661 CTE rows. 

2662 

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

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

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

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

2667 

2668 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2670 method may be 

2671 used to establish these. 

2672 

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

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

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

2676 compile time. 

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

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

2679 conjunction with UNION ALL in order to derive rows 

2680 from those already selected. 

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

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

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

2684 :paramref:`.HasCTE.add_cte.nest_here` 

2685 parameter may also be used to more carefully 

2686 control the exact placement of a particular CTE. 

2687 

2688 .. versionadded:: 1.4.24 

2689 

2690 .. seealso:: 

2691 

2692 :meth:`.HasCTE.add_cte` 

2693 

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

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

2696 as well as additional examples. 

2697 

2698 Example 1, non recursive:: 

2699 

2700 from sqlalchemy import ( 

2701 Table, 

2702 Column, 

2703 String, 

2704 Integer, 

2705 MetaData, 

2706 select, 

2707 func, 

2708 ) 

2709 

2710 metadata = MetaData() 

2711 

2712 orders = Table( 

2713 "orders", 

2714 metadata, 

2715 Column("region", String), 

2716 Column("amount", Integer), 

2717 Column("product", String), 

2718 Column("quantity", Integer), 

2719 ) 

2720 

2721 regional_sales = ( 

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

2723 .group_by(orders.c.region) 

2724 .cte("regional_sales") 

2725 ) 

2726 

2727 

2728 top_regions = ( 

2729 select(regional_sales.c.region) 

2730 .where( 

2731 regional_sales.c.total_sales 

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

2733 ) 

2734 .cte("top_regions") 

2735 ) 

2736 

2737 statement = ( 

2738 select( 

2739 orders.c.region, 

2740 orders.c.product, 

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

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

2743 ) 

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

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

2746 ) 

2747 

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

2749 

2750 Example 2, WITH RECURSIVE:: 

2751 

2752 from sqlalchemy import ( 

2753 Table, 

2754 Column, 

2755 String, 

2756 Integer, 

2757 MetaData, 

2758 select, 

2759 func, 

2760 ) 

2761 

2762 metadata = MetaData() 

2763 

2764 parts = Table( 

2765 "parts", 

2766 metadata, 

2767 Column("part", String), 

2768 Column("sub_part", String), 

2769 Column("quantity", Integer), 

2770 ) 

2771 

2772 included_parts = ( 

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

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

2775 .cte(recursive=True) 

2776 ) 

2777 

2778 

2779 incl_alias = included_parts.alias() 

2780 parts_alias = parts.alias() 

2781 included_parts = included_parts.union_all( 

2782 select( 

2783 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2785 ) 

2786 

2787 statement = select( 

2788 included_parts.c.sub_part, 

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

2790 ).group_by(included_parts.c.sub_part) 

2791 

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

2793 

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

2795 

2796 from datetime import date 

2797 from sqlalchemy import ( 

2798 MetaData, 

2799 Table, 

2800 Column, 

2801 Integer, 

2802 Date, 

2803 select, 

2804 literal, 

2805 and_, 

2806 exists, 

2807 ) 

2808 

2809 metadata = MetaData() 

2810 

2811 visitors = Table( 

2812 "visitors", 

2813 metadata, 

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

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

2816 Column("count", Integer), 

2817 ) 

2818 

2819 # add 5 visitors for the product_id == 1 

2820 product_id = 1 

2821 day = date.today() 

2822 count = 5 

2823 

2824 update_cte = ( 

2825 visitors.update() 

2826 .where( 

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

2828 ) 

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

2830 .returning(literal(1)) 

2831 .cte("update_cte") 

2832 ) 

2833 

2834 upsert = visitors.insert().from_select( 

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

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

2837 ~exists(update_cte.select()) 

2838 ), 

2839 ) 

2840 

2841 connection.execute(upsert) 

2842 

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

2844 

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

2846 

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

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

2849 "value_a", nesting=True 

2850 ) 

2851 

2852 # Nesting CTEs takes ascendency locally 

2853 # over the CTEs at a higher level 

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

2855 

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

2857 

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

2859 shown with inline parameters below as: 

2860 

2861 .. sourcecode:: sql 

2862 

2863 WITH 

2864 value_a AS 

2865 (SELECT 'root' AS n), 

2866 value_b AS 

2867 (WITH value_a AS 

2868 (SELECT 'nesting' AS n) 

2869 SELECT value_a.n AS n FROM value_a) 

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

2871 FROM value_a, value_b 

2872 

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

2874 as follows (SQLAlchemy 2.0 and above):: 

2875 

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

2877 

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

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

2880 

2881 # Nesting CTEs takes ascendency locally 

2882 # over the CTEs at a higher level 

2883 value_b = ( 

2884 select(value_a_nested.c.n) 

2885 .add_cte(value_a_nested, nest_here=True) 

2886 .cte("value_b") 

2887 ) 

2888 

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

2890 

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

2892 

2893 edge = Table( 

2894 "edge", 

2895 metadata, 

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

2897 Column("left", Integer), 

2898 Column("right", Integer), 

2899 ) 

2900 

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

2902 

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

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

2905 ) 

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

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

2908 ) 

2909 

2910 subgraph_cte = root_node.union(left_edge, right_edge) 

2911 

2912 subgraph = select(subgraph_cte) 

2913 

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

2915 

2916 .. sourcecode:: sql 

2917 

2918 WITH RECURSIVE nodes(node) AS ( 

2919 SELECT 1 AS node 

2920 UNION 

2921 SELECT edge."left" AS "left" 

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

2923 UNION 

2924 SELECT edge."right" AS "right" 

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

2926 ) 

2927 SELECT nodes.node FROM nodes 

2928 

2929 .. seealso:: 

2930 

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

2932 :meth:`_expression.HasCTE.cte`. 

2933 

2934 """ # noqa: E501 

2935 return CTE._construct( 

2936 self, name=name, recursive=recursive, nesting=nesting 

2937 ) 

2938 

2939 

2940class Subquery(AliasedReturnsRows): 

2941 """Represent a subquery of a SELECT. 

2942 

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

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

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

2946 :class:`_expression.SelectBase` subclass 

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

2948 :class:`_expression.CompoundSelect`, and 

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

2950 it represents the 

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

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

2953 

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

2955 :class:`_expression.Alias` 

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

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

2958 :class:`_expression.Alias` always 

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

2960 :class:`.Subquery` 

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

2962 

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

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

2965 statement. 

2966 

2967 """ 

2968 

2969 __visit_name__ = "subquery" 

2970 

2971 _is_subquery = True 

2972 

2973 inherit_cache = True 

2974 

2975 element: SelectBase 

2976 

2977 @classmethod 

2978 def _factory( 

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

2980 ) -> Subquery: 

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

2982 

2983 return coercions.expect( 

2984 roles.SelectStatementRole, selectable 

2985 ).subquery(name=name) 

2986 

2987 @util.deprecated( 

2988 "1.4", 

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

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

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

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

2993 ":func:`_expression.select` " 

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

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

2996 ) 

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

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

2999 

3000 

3001class FromGrouping(GroupedElement, FromClause): 

3002 """Represent a grouping of a FROM clause""" 

3003 

3004 _traverse_internals: _TraverseInternalsType = [ 

3005 ("element", InternalTraversal.dp_clauseelement) 

3006 ] 

3007 

3008 element: FromClause 

3009 

3010 def __init__(self, element: FromClause): 

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

3012 

3013 @util.ro_non_memoized_property 

3014 def columns( 

3015 self, 

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

3017 return self.element.columns 

3018 

3019 @util.ro_non_memoized_property 

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

3021 return self.element.columns 

3022 

3023 @property 

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

3025 return self.element.primary_key 

3026 

3027 @property 

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

3029 return self.element.foreign_keys 

3030 

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

3032 return self.element.is_derived_from(fromclause) 

3033 

3034 def alias( 

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

3036 ) -> NamedFromGrouping: 

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

3038 

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

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

3041 

3042 @util.ro_non_memoized_property 

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

3044 return self.element._hide_froms 

3045 

3046 @util.ro_non_memoized_property 

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

3048 return self.element._from_objects 

3049 

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

3051 return {"element": self.element} 

3052 

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

3054 self.element = state["element"] 

3055 

3056 if TYPE_CHECKING: 

3057 

3058 def self_group( 

3059 self, against: Optional[OperatorType] = None 

3060 ) -> Self: ... 

3061 

3062 

3063class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3065 

3066 .. versionadded:: 2.0 

3067 

3068 """ 

3069 

3070 inherit_cache = True 

3071 

3072 if TYPE_CHECKING: 

3073 

3074 def self_group( 

3075 self, against: Optional[OperatorType] = None 

3076 ) -> Self: ... 

3077 

3078 

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

3080 """Represents a minimal "table" construct. 

3081 

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

3083 collection of columns, which are typically produced 

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

3085 

3086 from sqlalchemy import table, column 

3087 

3088 user = table( 

3089 "user", 

3090 column("id"), 

3091 column("name"), 

3092 column("description"), 

3093 ) 

3094 

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

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

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

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

3099 

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

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

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

3103 It's useful 

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

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

3106 is not on hand. 

3107 

3108 """ 

3109 

3110 __visit_name__ = "table" 

3111 

3112 _traverse_internals: _TraverseInternalsType = [ 

3113 ( 

3114 "columns", 

3115 InternalTraversal.dp_fromclause_canonical_column_collection, 

3116 ), 

3117 ("name", InternalTraversal.dp_string), 

3118 ("schema", InternalTraversal.dp_string), 

3119 ] 

3120 

3121 _is_table = True 

3122 

3123 fullname: str 

3124 

3125 implicit_returning = False 

3126 """:class:`_expression.TableClause` 

3127 doesn't support having a primary key or column 

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

3129 

3130 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3131 

3132 @util.ro_memoized_property 

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

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

3135 return None 

3136 

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

3138 super().__init__() 

3139 self.name = name 

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

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

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

3143 for c in columns: 

3144 self.append_column(c) 

3145 

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

3147 if schema is not None: 

3148 self.schema = schema 

3149 if self.schema is not None: 

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

3151 else: 

3152 self.fullname = self.name 

3153 if kw: 

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

3155 

3156 if TYPE_CHECKING: 

3157 

3158 @util.ro_non_memoized_property 

3159 def columns( 

3160 self, 

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

3162 

3163 @util.ro_non_memoized_property 

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

3165 

3166 def __str__(self) -> str: 

3167 if self.schema is not None: 

3168 return self.schema + "." + self.name 

3169 else: 

3170 return self.name 

3171 

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

3173 pass 

3174 

3175 @util.ro_memoized_property 

3176 def description(self) -> str: 

3177 return self.name 

3178 

3179 def _insert_col_impl( 

3180 self, 

3181 c: ColumnClause[Any], 

3182 *, 

3183 index: Optional[int] = None, 

3184 ) -> None: 

3185 existing = c.table 

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

3187 raise exc.ArgumentError( 

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

3189 % (c.key, existing) 

3190 ) 

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

3192 c.table = self 

3193 

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

3195 self._insert_col_impl(c) 

3196 

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

3198 self._insert_col_impl(c, index=index) 

3199 

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

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

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

3203 :class:`_expression.TableClause`. 

3204 

3205 E.g.:: 

3206 

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

3208 

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

3210 

3211 """ 

3212 

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

3214 

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

3216 def update(self) -> Update: 

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

3218 :class:`_expression.TableClause`. 

3219 

3220 E.g.:: 

3221 

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

3223 

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

3225 

3226 """ 

3227 return util.preloaded.sql_dml.Update( 

3228 self, 

3229 ) 

3230 

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

3232 def delete(self) -> Delete: 

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

3234 :class:`_expression.TableClause`. 

3235 

3236 E.g.:: 

3237 

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

3239 

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

3241 

3242 """ 

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

3244 

3245 @util.ro_non_memoized_property 

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

3247 return [self] 

3248 

3249 

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

3251 

3252 

3253class ForUpdateArg(ClauseElement): 

3254 _traverse_internals: _TraverseInternalsType = [ 

3255 ("of", InternalTraversal.dp_clauseelement_list), 

3256 ("nowait", InternalTraversal.dp_boolean), 

3257 ("read", InternalTraversal.dp_boolean), 

3258 ("skip_locked", InternalTraversal.dp_boolean), 

3259 ("key_share", InternalTraversal.dp_boolean), 

3260 ] 

3261 

3262 of: Optional[Sequence[ClauseElement]] 

3263 nowait: bool 

3264 read: bool 

3265 skip_locked: bool 

3266 

3267 @classmethod 

3268 def _from_argument( 

3269 cls, with_for_update: ForUpdateParameter 

3270 ) -> Optional[ForUpdateArg]: 

3271 if isinstance(with_for_update, ForUpdateArg): 

3272 return with_for_update 

3273 elif with_for_update in (None, False): 

3274 return None 

3275 elif with_for_update is True: 

3276 return ForUpdateArg() 

3277 else: 

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

3279 

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

3281 return ( 

3282 isinstance(other, ForUpdateArg) 

3283 and other.nowait == self.nowait 

3284 and other.read == self.read 

3285 and other.skip_locked == self.skip_locked 

3286 and other.key_share == self.key_share 

3287 and other.of is self.of 

3288 ) 

3289 

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

3291 return not self.__eq__(other) 

3292 

3293 def __hash__(self) -> int: 

3294 return id(self) 

3295 

3296 def __init__( 

3297 self, 

3298 *, 

3299 nowait: bool = False, 

3300 read: bool = False, 

3301 of: Optional[_ForUpdateOfArgument] = None, 

3302 skip_locked: bool = False, 

3303 key_share: bool = False, 

3304 ): 

3305 """Represents arguments specified to 

3306 :meth:`_expression.Select.for_update`. 

3307 

3308 """ 

3309 

3310 self.nowait = nowait 

3311 self.read = read 

3312 self.skip_locked = skip_locked 

3313 self.key_share = key_share 

3314 if of is not None: 

3315 self.of = [ 

3316 coercions.expect(roles.ColumnsClauseRole, elem) 

3317 for elem in util.to_list(of) 

3318 ] 

3319 else: 

3320 self.of = None 

3321 

3322 

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

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

3325 in a statement. 

3326 

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

3328 :func:`_expression.values` function. 

3329 

3330 .. versionadded:: 1.4 

3331 

3332 """ 

3333 

3334 __visit_name__ = "values" 

3335 

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

3337 

3338 _unnamed: bool 

3339 _traverse_internals: _TraverseInternalsType = [ 

3340 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3341 ("_data", InternalTraversal.dp_dml_multi_values), 

3342 ("name", InternalTraversal.dp_string), 

3343 ("literal_binds", InternalTraversal.dp_boolean), 

3344 ] 

3345 

3346 def __init__( 

3347 self, 

3348 *columns: ColumnClause[Any], 

3349 name: Optional[str] = None, 

3350 literal_binds: bool = False, 

3351 ): 

3352 super().__init__() 

3353 self._column_args = columns 

3354 

3355 if name is None: 

3356 self._unnamed = True 

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

3358 else: 

3359 self._unnamed = False 

3360 self.name = name 

3361 self.literal_binds = literal_binds 

3362 self.named_with_column = not self._unnamed 

3363 

3364 @property 

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

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

3367 

3368 @_generative 

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

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

3371 construct that is a copy of this 

3372 one with the given name. 

3373 

3374 This method is a VALUES-specific specialization of the 

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

3376 

3377 .. seealso:: 

3378 

3379 :ref:`tutorial_using_aliases` 

3380 

3381 :func:`_expression.alias` 

3382 

3383 """ 

3384 non_none_name: str 

3385 

3386 if name is None: 

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

3388 else: 

3389 non_none_name = name 

3390 

3391 self.name = non_none_name 

3392 self.named_with_column = True 

3393 self._unnamed = False 

3394 return self 

3395 

3396 @_generative 

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

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

3399 so that 

3400 it renders as LATERAL. 

3401 

3402 .. seealso:: 

3403 

3404 :func:`_expression.lateral` 

3405 

3406 """ 

3407 non_none_name: str 

3408 

3409 if name is None: 

3410 non_none_name = self.name 

3411 else: 

3412 non_none_name = name 

3413 

3414 self._is_lateral = True 

3415 self.name = non_none_name 

3416 self._unnamed = False 

3417 return self 

3418 

3419 @_generative 

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

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

3422 adding the given data to the data list. 

3423 

3424 E.g.:: 

3425 

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

3427 

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

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

3430 constructor. 

3431 

3432 """ 

3433 

3434 self._data += (values,) 

3435 return self 

3436 

3437 def scalar_values(self) -> ScalarValues: 

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

3439 COLUMN element in a statement. 

3440 

3441 .. versionadded:: 2.0.0b4 

3442 

3443 """ 

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

3445 

3446 def _populate_column_collection( 

3447 self, 

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

3449 primary_key: ColumnSet, 

3450 foreign_keys: Set[KeyedColumnElement[Any]], 

3451 ) -> None: 

3452 for c in self._column_args: 

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

3454 _, c = c._make_proxy( 

3455 self, primary_key=primary_key, foreign_keys=foreign_keys 

3456 ) 

3457 else: 

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

3459 # no memoizations of other FROM clauses. 

3460 # see test_values.py -> test_auto_proxy_select_direct_col 

3461 c._reset_memoizations() 

3462 columns.add(c) 

3463 c.table = self 

3464 

3465 @util.ro_non_memoized_property 

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

3467 return [self] 

3468 

3469 

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

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

3472 COLUMN element in a statement. 

3473 

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

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

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

3477 an ``IN`` or ``NOT IN`` condition. 

3478 

3479 .. versionadded:: 2.0.0b4 

3480 

3481 """ 

3482 

3483 __visit_name__ = "scalar_values" 

3484 

3485 _traverse_internals: _TraverseInternalsType = [ 

3486 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3487 ("_data", InternalTraversal.dp_dml_multi_values), 

3488 ("literal_binds", InternalTraversal.dp_boolean), 

3489 ] 

3490 

3491 def __init__( 

3492 self, 

3493 columns: Sequence[ColumnClause[Any]], 

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

3495 literal_binds: bool, 

3496 ): 

3497 super().__init__() 

3498 self._column_args = columns 

3499 self._data = data 

3500 self.literal_binds = literal_binds 

3501 

3502 @property 

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

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

3505 

3506 def __clause_element__(self) -> ScalarValues: 

3507 return self 

3508 

3509 if TYPE_CHECKING: 

3510 

3511 def self_group( 

3512 self, against: Optional[OperatorType] = None 

3513 ) -> Self: ... 

3514 

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

3516 

3517 

3518class SelectBase( 

3519 roles.SelectStatementRole, 

3520 roles.DMLSelectRole, 

3521 roles.CompoundElementRole, 

3522 roles.InElementRole, 

3523 HasCTE, 

3524 SupportsCloneAnnotations, 

3525 Selectable, 

3526): 

3527 """Base class for SELECT statements. 

3528 

3529 

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

3531 :class:`_expression.CompoundSelect` and 

3532 :class:`_expression.TextualSelect`. 

3533 

3534 

3535 """ 

3536 

3537 _is_select_base = True 

3538 is_select = True 

3539 

3540 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3541 

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

3543 self._reset_memoizations() 

3544 

3545 @util.ro_non_memoized_property 

3546 def selected_columns( 

3547 self, 

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

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

3550 representing the columns that 

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

3552 

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

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

3555 within this collection cannot be directly nested inside another SELECT 

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

3557 necessary parenthesization required by SQL. 

3558 

3559 .. note:: 

3560 

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

3562 include expressions established in the columns clause using the 

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

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

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

3566 construct. 

3567 

3568 .. seealso:: 

3569 

3570 :attr:`_sql.Select.selected_columns` 

3571 

3572 .. versionadded:: 1.4 

3573 

3574 """ 

3575 raise NotImplementedError() 

3576 

3577 def _generate_fromclause_column_proxies( 

3578 self, 

3579 subquery: FromClause, 

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

3581 primary_key: ColumnSet, 

3582 foreign_keys: Set[KeyedColumnElement[Any]], 

3583 *, 

3584 proxy_compound_columns: Optional[ 

3585 Iterable[Sequence[ColumnElement[Any]]] 

3586 ] = None, 

3587 ) -> None: 

3588 raise NotImplementedError() 

3589 

3590 @util.ro_non_memoized_property 

3591 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3594 constructs. 

3595 

3596 .. versionadded:: 1.4.12 

3597 

3598 .. seealso:: 

3599 

3600 :attr:`_sql.SelectBase.exported_columns` 

3601 

3602 """ 

3603 raise NotImplementedError() 

3604 

3605 @property 

3606 def exported_columns( 

3607 self, 

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

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

3610 that represents the "exported" 

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

3612 :class:`_sql.TextClause` constructs. 

3613 

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

3615 object are synonymous 

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

3617 

3618 .. versionadded:: 1.4 

3619 

3620 .. seealso:: 

3621 

3622 :attr:`_expression.Select.exported_columns` 

3623 

3624 :attr:`_expression.Selectable.exported_columns` 

3625 

3626 :attr:`_expression.FromClause.exported_columns` 

3627 

3628 

3629 """ 

3630 return self.selected_columns.as_readonly() 

3631 

3632 def get_label_style(self) -> SelectLabelStyle: 

3633 """ 

3634 Retrieve the current label style. 

3635 

3636 Implemented by subclasses. 

3637 

3638 """ 

3639 raise NotImplementedError() 

3640 

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

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

3643 

3644 Implemented by subclasses. 

3645 

3646 """ 

3647 

3648 raise NotImplementedError() 

3649 

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

3651 raise NotImplementedError() 

3652 

3653 @util.deprecated( 

3654 "1.4", 

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

3656 "method is deprecated and will be " 

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

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

3659 ) 

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

3661 return self.scalar_subquery() 

3662 

3663 def exists(self) -> Exists: 

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

3665 which can be used as a column expression. 

3666 

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

3668 

3669 .. seealso:: 

3670 

3671 :func:`_sql.exists` 

3672 

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

3674 

3675 .. versionadded:: 1.4 

3676 

3677 """ 

3678 return Exists(self) 

3679 

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

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

3682 used as a column expression. 

3683 

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

3685 

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

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

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

3689 an enclosing SELECT. 

3690 

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

3692 subquery that can be produced using the 

3693 :meth:`_expression.SelectBase.subquery` 

3694 method. 

3695 

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

3697 :meth:`_expression.SelectBase.scalar_subquery`. 

3698 

3699 .. seealso:: 

3700 

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

3702 

3703 """ 

3704 if self._label_style is not LABEL_STYLE_NONE: 

3705 self = self.set_label_style(LABEL_STYLE_NONE) 

3706 

3707 return ScalarSelect(self) 

3708 

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

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

3711 subquery with a label. 

3712 

3713 .. seealso:: 

3714 

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

3716 

3717 """ 

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

3719 

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

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

3722 

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

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

3725 

3726 .. seealso:: 

3727 

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

3729 

3730 """ 

3731 return Lateral._factory(self, name) 

3732 

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

3734 """Return a subquery of this :class:`_expression.SelectBase`. 

3735 

3736 A subquery is from a SQL perspective a parenthesized, named 

3737 construct that can be placed in the FROM clause of another 

3738 SELECT statement. 

3739 

3740 Given a SELECT statement such as:: 

3741 

3742 stmt = select(table.c.id, table.c.name) 

3743 

3744 The above statement might look like: 

3745 

3746 .. sourcecode:: sql 

3747 

3748 SELECT table.id, table.name FROM table 

3749 

3750 The subquery form by itself renders the same way, however when 

3751 embedded into the FROM clause of another SELECT statement, it becomes 

3752 a named sub-element:: 

3753 

3754 subq = stmt.subquery() 

3755 new_stmt = select(subq) 

3756 

3757 The above renders as: 

3758 

3759 .. sourcecode:: sql 

3760 

3761 SELECT anon_1.id, anon_1.name 

3762 FROM (SELECT table.id, table.name FROM table) AS anon_1 

3763 

3764 Historically, :meth:`_expression.SelectBase.subquery` 

3765 is equivalent to calling 

3766 the :meth:`_expression.FromClause.alias` 

3767 method on a FROM object; however, 

3768 as a :class:`_expression.SelectBase` 

3769 object is not directly FROM object, 

3770 the :meth:`_expression.SelectBase.subquery` 

3771 method provides clearer semantics. 

3772 

3773 .. versionadded:: 1.4 

3774 

3775 """ 

3776 

3777 return Subquery._construct( 

3778 self._ensure_disambiguated_names(), name=name 

3779 ) 

3780 

3781 def _ensure_disambiguated_names(self) -> Self: 

3782 """Ensure that the names generated by this selectbase will be 

3783 disambiguated in some way, if possible. 

3784 

3785 """ 

3786 

3787 raise NotImplementedError() 

3788 

3789 def alias( 

3790 self, name: Optional[str] = None, flat: bool = False 

3791 ) -> Subquery: 

3792 """Return a named subquery against this 

3793 :class:`_expression.SelectBase`. 

3794 

3795 For a :class:`_expression.SelectBase` (as opposed to a 

3796 :class:`_expression.FromClause`), 

3797 this returns a :class:`.Subquery` object which behaves mostly the 

3798 same as the :class:`_expression.Alias` object that is used with a 

3799 :class:`_expression.FromClause`. 

3800 

3801 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3802 method is now 

3803 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3804 

3805 """ 

3806 return self.subquery(name=name) 

3807 

3808 

3809_SB = TypeVar("_SB", bound=SelectBase) 

3810 

3811 

3812class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3813 """Represent a grouping of a :class:`_expression.SelectBase`. 

3814 

3815 This differs from :class:`.Subquery` in that we are still 

3816 an "inner" SELECT statement, this is strictly for grouping inside of 

3817 compound selects. 

3818 

3819 """ 

3820 

3821 __visit_name__ = "select_statement_grouping" 

3822 _traverse_internals: _TraverseInternalsType = [ 

3823 ("element", InternalTraversal.dp_clauseelement) 

3824 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3825 

3826 _is_select_container = True 

3827 

3828 element: _SB 

3829 

3830 def __init__(self, element: _SB) -> None: 

3831 self.element = cast( 

3832 _SB, coercions.expect(roles.SelectStatementRole, element) 

3833 ) 

3834 

3835 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3836 new_element = self.element._ensure_disambiguated_names() 

3837 if new_element is not self.element: 

3838 return SelectStatementGrouping(new_element) 

3839 else: 

3840 return self 

3841 

3842 def get_label_style(self) -> SelectLabelStyle: 

3843 return self.element.get_label_style() 

3844 

3845 def set_label_style( 

3846 self, label_style: SelectLabelStyle 

3847 ) -> SelectStatementGrouping[_SB]: 

3848 return SelectStatementGrouping( 

3849 self.element.set_label_style(label_style) 

3850 ) 

3851 

3852 @property 

3853 def select_statement(self) -> _SB: 

3854 return self.element 

3855 

3856 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3857 return self 

3858 

3859 if TYPE_CHECKING: 

3860 

3861 def _ungroup(self) -> _SB: ... 

3862 

3863 # def _generate_columns_plus_names( 

3864 # self, anon_for_dupe_key: bool 

3865 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3866 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3867 

3868 def _generate_fromclause_column_proxies( 

3869 self, 

3870 subquery: FromClause, 

3871 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

3872 primary_key: ColumnSet, 

3873 foreign_keys: Set[KeyedColumnElement[Any]], 

3874 *, 

3875 proxy_compound_columns: Optional[ 

3876 Iterable[Sequence[ColumnElement[Any]]] 

3877 ] = None, 

3878 ) -> None: 

3879 self.element._generate_fromclause_column_proxies( 

3880 subquery, 

3881 columns, 

3882 proxy_compound_columns=proxy_compound_columns, 

3883 primary_key=primary_key, 

3884 foreign_keys=foreign_keys, 

3885 ) 

3886 

3887 @util.ro_non_memoized_property 

3888 def _all_selected_columns(self) -> _SelectIterable: 

3889 return self.element._all_selected_columns 

3890 

3891 @util.ro_non_memoized_property 

3892 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

3893 """A :class:`_expression.ColumnCollection` 

3894 representing the columns that 

3895 the embedded SELECT statement returns in its result set, not including 

3896 :class:`_sql.TextClause` constructs. 

3897 

3898 .. versionadded:: 1.4 

3899 

3900 .. seealso:: 

3901 

3902 :attr:`_sql.Select.selected_columns` 

3903 

3904 """ 

3905 return self.element.selected_columns 

3906 

3907 @util.ro_non_memoized_property 

3908 def _from_objects(self) -> List[FromClause]: 

3909 return self.element._from_objects 

3910 

3911 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self: 

3912 # SelectStatementGrouping not generative: has no attribute '_generate' 

3913 raise NotImplementedError 

3914 

3915 

3916class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

3917 """Base class for SELECT statements where additional elements can be 

3918 added. 

3919 

3920 This serves as the base for :class:`_expression.Select` and 

3921 :class:`_expression.CompoundSelect` 

3922 where elements such as ORDER BY, GROUP BY can be added and column 

3923 rendering can be controlled. Compare to 

3924 :class:`_expression.TextualSelect`, which, 

3925 while it subclasses :class:`_expression.SelectBase` 

3926 and is also a SELECT construct, 

3927 represents a fixed textual string which cannot be altered at this level, 

3928 only wrapped as a subquery. 

3929 

3930 """ 

3931 

3932 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3933 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3934 _limit_clause: Optional[ColumnElement[Any]] = None 

3935 _offset_clause: Optional[ColumnElement[Any]] = None 

3936 _fetch_clause: Optional[ColumnElement[Any]] = None 

3937 _fetch_clause_options: Optional[Dict[str, bool]] = None 

3938 _for_update_arg: Optional[ForUpdateArg] = None 

3939 

3940 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

3941 self._label_style = _label_style 

3942 

3943 @_generative 

3944 def with_for_update( 

3945 self, 

3946 *, 

3947 nowait: bool = False, 

3948 read: bool = False, 

3949 of: Optional[_ForUpdateOfArgument] = None, 

3950 skip_locked: bool = False, 

3951 key_share: bool = False, 

3952 ) -> Self: 

3953 """Specify a ``FOR UPDATE`` clause for this 

3954 :class:`_expression.GenerativeSelect`. 

3955 

3956 E.g.:: 

3957 

3958 stmt = select(table).with_for_update(nowait=True) 

3959 

3960 On a database like PostgreSQL or Oracle Database, the above would 

3961 render a statement like: 

3962 

3963 .. sourcecode:: sql 

3964 

3965 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

3966 

3967 on other backends, the ``nowait`` option is ignored and instead 

3968 would produce: 

3969 

3970 .. sourcecode:: sql 

3971 

3972 SELECT table.a, table.b FROM table FOR UPDATE 

3973 

3974 When called with no arguments, the statement will render with 

3975 the suffix ``FOR UPDATE``. Additional arguments can then be 

3976 provided which allow for common database-specific 

3977 variants. 

3978 

3979 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

3980 Database and PostgreSQL dialects. 

3981 

3982 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

3983 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

3984 ``nowait``, will render ``FOR SHARE NOWAIT``. 

3985 

3986 :param of: SQL expression or list of SQL expression elements, 

3987 (typically :class:`_schema.Column` objects or a compatible expression, 

3988 for some backends may also be a table expression) which will render 

3989 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

3990 Database, some MySQL versions and possibly others. May render as a 

3991 table or as a column depending on backend. 

3992 

3993 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

3994 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

3995 if ``read=True`` is also specified. 

3996 

3997 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

3998 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

3999 on the PostgreSQL dialect. 

4000 

4001 """ 

4002 self._for_update_arg = ForUpdateArg( 

4003 nowait=nowait, 

4004 read=read, 

4005 of=of, 

4006 skip_locked=skip_locked, 

4007 key_share=key_share, 

4008 ) 

4009 return self 

4010 

4011 def get_label_style(self) -> SelectLabelStyle: 

4012 """ 

4013 Retrieve the current label style. 

4014 

4015 .. versionadded:: 1.4 

4016 

4017 """ 

4018 return self._label_style 

4019 

4020 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4021 """Return a new selectable with the specified label style. 

4022 

4023 There are three "label styles" available, 

4024 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4025 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4026 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4027 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4028 

4029 In modern SQLAlchemy, there is not generally a need to change the 

4030 labeling style, as per-expression labels are more effectively used by 

4031 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4032 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4033 disambiguate same-named columns from different tables, aliases, or 

4034 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4035 applies labels only to names that conflict with an existing name so 

4036 that the impact of this labeling is minimal. 

4037 

4038 The rationale for disambiguation is mostly so that all column 

4039 expressions are available from a given :attr:`_sql.FromClause.c` 

4040 collection when a subquery is created. 

4041 

4042 .. versionadded:: 1.4 - the 

4043 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4044 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4045 ``use_labels=True`` methods and/or parameters. 

4046 

4047 .. seealso:: 

4048 

4049 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4050 

4051 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` 

4052 

4053 :data:`_sql.LABEL_STYLE_NONE` 

4054 

4055 :data:`_sql.LABEL_STYLE_DEFAULT` 

4056 

4057 """ 

4058 if self._label_style is not style: 

4059 self = self._generate() 

4060 self._label_style = style 

4061 return self 

4062 

4063 @property 

4064 def _group_by_clause(self) -> ClauseList: 

4065 """ClauseList access to group_by_clauses for legacy dialects""" 

4066 return ClauseList._construct_raw( 

4067 operators.comma_op, self._group_by_clauses 

4068 ) 

4069 

4070 @property 

4071 def _order_by_clause(self) -> ClauseList: 

4072 """ClauseList access to order_by_clauses for legacy dialects""" 

4073 return ClauseList._construct_raw( 

4074 operators.comma_op, self._order_by_clauses 

4075 ) 

4076 

4077 def _offset_or_limit_clause( 

4078 self, 

4079 element: _LimitOffsetType, 

4080 name: Optional[str] = None, 

4081 type_: Optional[_TypeEngineArgument[int]] = None, 

4082 ) -> ColumnElement[Any]: 

4083 """Convert the given value to an "offset or limit" clause. 

4084 

4085 This handles incoming integers and converts to an expression; if 

4086 an expression is already given, it is passed through. 

4087 

4088 """ 

4089 return coercions.expect( 

4090 roles.LimitOffsetRole, element, name=name, type_=type_ 

4091 ) 

4092 

4093 @overload 

4094 def _offset_or_limit_clause_asint( 

4095 self, clause: ColumnElement[Any], attrname: str 

4096 ) -> NoReturn: ... 

4097 

4098 @overload 

4099 def _offset_or_limit_clause_asint( 

4100 self, clause: Optional[_OffsetLimitParam], attrname: str 

4101 ) -> Optional[int]: ... 

4102 

4103 def _offset_or_limit_clause_asint( 

4104 self, clause: Optional[ColumnElement[Any]], attrname: str 

4105 ) -> Union[NoReturn, Optional[int]]: 

4106 """Convert the "offset or limit" clause of a select construct to an 

4107 integer. 

4108 

4109 This is only possible if the value is stored as a simple bound 

4110 parameter. Otherwise, a compilation error is raised. 

4111 

4112 """ 

4113 if clause is None: 

4114 return None 

4115 try: 

4116 value = clause._limit_offset_value 

4117 except AttributeError as err: 

4118 raise exc.CompileError( 

4119 "This SELECT structure does not use a simple " 

4120 "integer value for %s" % attrname 

4121 ) from err 

4122 else: 

4123 return util.asint(value) 

4124 

4125 @property 

4126 def _limit(self) -> Optional[int]: 

4127 """Get an integer value for the limit. This should only be used 

4128 by code that cannot support a limit as a BindParameter or 

4129 other custom clause as it will throw an exception if the limit 

4130 isn't currently set to an integer. 

4131 

4132 """ 

4133 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4134 

4135 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4136 """True if the clause is a simple integer, False 

4137 if it is not present or is a SQL expression. 

4138 """ 

4139 return isinstance(clause, _OffsetLimitParam) 

4140 

4141 @property 

4142 def _offset(self) -> Optional[int]: 

4143 """Get an integer value for the offset. This should only be used 

4144 by code that cannot support an offset as a BindParameter or 

4145 other custom clause as it will throw an exception if the 

4146 offset isn't currently set to an integer. 

4147 

4148 """ 

4149 return self._offset_or_limit_clause_asint( 

4150 self._offset_clause, "offset" 

4151 ) 

4152 

4153 @property 

4154 def _has_row_limiting_clause(self) -> bool: 

4155 return ( 

4156 self._limit_clause is not None 

4157 or self._offset_clause is not None 

4158 or self._fetch_clause is not None 

4159 ) 

4160 

4161 @_generative 

4162 def limit(self, limit: _LimitOffsetType) -> Self: 

4163 """Return a new selectable with the given LIMIT criterion 

4164 applied. 

4165 

4166 This is a numerical value which usually renders as a ``LIMIT`` 

4167 expression in the resulting select. Backends that don't 

4168 support ``LIMIT`` will attempt to provide similar 

4169 functionality. 

4170 

4171 .. note:: 

4172 

4173 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4174 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4175 

4176 :param limit: an integer LIMIT parameter, or a SQL expression 

4177 that provides an integer result. Pass ``None`` to reset it. 

4178 

4179 .. seealso:: 

4180 

4181 :meth:`_sql.GenerativeSelect.fetch` 

4182 

4183 :meth:`_sql.GenerativeSelect.offset` 

4184 

4185 """ 

4186 

4187 self._fetch_clause = self._fetch_clause_options = None 

4188 self._limit_clause = self._offset_or_limit_clause(limit) 

4189 return self 

4190 

4191 @_generative 

4192 def fetch( 

4193 self, 

4194 count: _LimitOffsetType, 

4195 with_ties: bool = False, 

4196 percent: bool = False, 

4197 **dialect_kw: Any, 

4198 ) -> Self: 

4199 r"""Return a new selectable with the given FETCH FIRST criterion 

4200 applied. 

4201 

4202 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4203 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4204 select. This functionality is is currently implemented for Oracle 

4205 Database, PostgreSQL, MSSQL. 

4206 

4207 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4208 

4209 .. note:: 

4210 

4211 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4212 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4213 

4214 .. versionadded:: 1.4 

4215 

4216 :param count: an integer COUNT parameter, or a SQL expression 

4217 that provides an integer result. When ``percent=True`` this will 

4218 represent the percentage of rows to return, not the absolute value. 

4219 Pass ``None`` to reset it. 

4220 

4221 :param with_ties: When ``True``, the WITH TIES option is used 

4222 to return any additional rows that tie for the last place in the 

4223 result set according to the ``ORDER BY`` clause. The 

4224 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4225 

4226 :param percent: When ``True``, ``count`` represents the percentage 

4227 of the total number of selected rows to return. Defaults to ``False`` 

4228 

4229 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4230 may be accepted by dialects. 

4231 

4232 .. versionadded:: 2.0.41 

4233 

4234 .. seealso:: 

4235 

4236 :meth:`_sql.GenerativeSelect.limit` 

4237 

4238 :meth:`_sql.GenerativeSelect.offset` 

4239 

4240 """ 

4241 self._validate_dialect_kwargs(dialect_kw) 

4242 self._limit_clause = None 

4243 if count is None: 

4244 self._fetch_clause = self._fetch_clause_options = None 

4245 else: 

4246 self._fetch_clause = self._offset_or_limit_clause(count) 

4247 self._fetch_clause_options = { 

4248 "with_ties": with_ties, 

4249 "percent": percent, 

4250 } 

4251 return self 

4252 

4253 @_generative 

4254 def offset(self, offset: _LimitOffsetType) -> Self: 

4255 """Return a new selectable with the given OFFSET criterion 

4256 applied. 

4257 

4258 

4259 This is a numeric value which usually renders as an ``OFFSET`` 

4260 expression in the resulting select. Backends that don't 

4261 support ``OFFSET`` will attempt to provide similar 

4262 functionality. 

4263 

4264 :param offset: an integer OFFSET parameter, or a SQL expression 

4265 that provides an integer result. Pass ``None`` to reset it. 

4266 

4267 .. seealso:: 

4268 

4269 :meth:`_sql.GenerativeSelect.limit` 

4270 

4271 :meth:`_sql.GenerativeSelect.fetch` 

4272 

4273 """ 

4274 

4275 self._offset_clause = self._offset_or_limit_clause(offset) 

4276 return self 

4277 

4278 @_generative 

4279 @util.preload_module("sqlalchemy.sql.util") 

4280 def slice( 

4281 self, 

4282 start: int, 

4283 stop: int, 

4284 ) -> Self: 

4285 """Apply LIMIT / OFFSET to this statement based on a slice. 

4286 

4287 The start and stop indices behave like the argument to Python's 

4288 built-in :func:`range` function. This method provides an 

4289 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4290 query. 

4291 

4292 For example, :: 

4293 

4294 stmt = select(User).order_by(User.id).slice(1, 3) 

4295 

4296 renders as 

4297 

4298 .. sourcecode:: sql 

4299 

4300 SELECT users.id AS users_id, 

4301 users.name AS users_name 

4302 FROM users ORDER BY users.id 

4303 LIMIT ? OFFSET ? 

4304 (2, 1) 

4305 

4306 .. note:: 

4307 

4308 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4309 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4310 

4311 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4312 method generalized from the ORM. 

4313 

4314 .. seealso:: 

4315 

4316 :meth:`_sql.GenerativeSelect.limit` 

4317 

4318 :meth:`_sql.GenerativeSelect.offset` 

4319 

4320 :meth:`_sql.GenerativeSelect.fetch` 

4321 

4322 """ 

4323 sql_util = util.preloaded.sql_util 

4324 self._fetch_clause = self._fetch_clause_options = None 

4325 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4326 self._limit_clause, self._offset_clause, start, stop 

4327 ) 

4328 return self 

4329 

4330 @_generative 

4331 def order_by( 

4332 self, 

4333 __first: Union[ 

4334 Literal[None, _NoArg.NO_ARG], 

4335 _ColumnExpressionOrStrLabelArgument[Any], 

4336 ] = _NoArg.NO_ARG, 

4337 /, 

4338 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4339 ) -> Self: 

4340 r"""Return a new selectable with the given list of ORDER BY 

4341 criteria applied. 

4342 

4343 e.g.:: 

4344 

4345 stmt = select(table).order_by(table.c.id, table.c.name) 

4346 

4347 Calling this method multiple times is equivalent to calling it once 

4348 with all the clauses concatenated. All existing ORDER BY criteria may 

4349 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4350 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4351 

4352 # will erase all ORDER BY and ORDER BY new_col alone 

4353 stmt = stmt.order_by(None).order_by(new_col) 

4354 

4355 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4356 constructs 

4357 which will be used to generate an ORDER BY clause. 

4358 

4359 .. seealso:: 

4360 

4361 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4362 

4363 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4364 

4365 """ 

4366 

4367 if not clauses and __first is None: 

4368 self._order_by_clauses = () 

4369 elif __first is not _NoArg.NO_ARG: 

4370 self._order_by_clauses += tuple( 

4371 coercions.expect( 

4372 roles.OrderByRole, clause, apply_propagate_attrs=self 

4373 ) 

4374 for clause in (__first,) + clauses 

4375 ) 

4376 return self 

4377 

4378 @_generative 

4379 def group_by( 

4380 self, 

4381 __first: Union[ 

4382 Literal[None, _NoArg.NO_ARG], 

4383 _ColumnExpressionOrStrLabelArgument[Any], 

4384 ] = _NoArg.NO_ARG, 

4385 /, 

4386 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4387 ) -> Self: 

4388 r"""Return a new selectable with the given list of GROUP BY 

4389 criterion applied. 

4390 

4391 All existing GROUP BY settings can be suppressed by passing ``None``. 

4392 

4393 e.g.:: 

4394 

4395 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4396 

4397 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4398 constructs 

4399 which will be used to generate an GROUP BY clause. 

4400 

4401 .. seealso:: 

4402 

4403 :ref:`tutorial_group_by_w_aggregates` - in the 

4404 :ref:`unified_tutorial` 

4405 

4406 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4407 

4408 """ # noqa: E501 

4409 

4410 if not clauses and __first is None: 

4411 self._group_by_clauses = () 

4412 elif __first is not _NoArg.NO_ARG: 

4413 self._group_by_clauses += tuple( 

4414 coercions.expect( 

4415 roles.GroupByRole, clause, apply_propagate_attrs=self 

4416 ) 

4417 for clause in (__first,) + clauses 

4418 ) 

4419 return self 

4420 

4421 

4422@CompileState.plugin_for("default", "compound_select") 

4423class CompoundSelectState(CompileState): 

4424 @util.memoized_property 

4425 def _label_resolve_dict( 

4426 self, 

4427 ) -> Tuple[ 

4428 Dict[str, ColumnElement[Any]], 

4429 Dict[str, ColumnElement[Any]], 

4430 Dict[str, ColumnElement[Any]], 

4431 ]: 

4432 # TODO: this is hacky and slow 

4433 hacky_subquery = self.statement.subquery() 

4434 hacky_subquery.named_with_column = False 

4435 d = {c.key: c for c in hacky_subquery.c} 

4436 return d, d, d 

4437 

4438 

4439class _CompoundSelectKeyword(Enum): 

4440 UNION = "UNION" 

4441 UNION_ALL = "UNION ALL" 

4442 EXCEPT = "EXCEPT" 

4443 EXCEPT_ALL = "EXCEPT ALL" 

4444 INTERSECT = "INTERSECT" 

4445 INTERSECT_ALL = "INTERSECT ALL" 

4446 

4447 

4448class CompoundSelect( 

4449 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4450): 

4451 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4452 SELECT-based set operations. 

4453 

4454 

4455 .. seealso:: 

4456 

4457 :func:`_expression.union` 

4458 

4459 :func:`_expression.union_all` 

4460 

4461 :func:`_expression.intersect` 

4462 

4463 :func:`_expression.intersect_all` 

4464 

4465 :func:`_expression.except` 

4466 

4467 :func:`_expression.except_all` 

4468 

4469 """ 

4470 

4471 __visit_name__ = "compound_select" 

4472 

4473 _traverse_internals: _TraverseInternalsType = ( 

4474 [ 

4475 ("selects", InternalTraversal.dp_clauseelement_list), 

4476 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4477 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4478 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4479 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4480 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4481 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4482 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4483 ("keyword", InternalTraversal.dp_string), 

4484 ] 

4485 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4486 + HasCTE._has_ctes_traverse_internals 

4487 + DialectKWArgs._dialect_kwargs_traverse_internals 

4488 ) 

4489 

4490 selects: List[SelectBase] 

4491 

4492 _is_from_container = True 

4493 _auto_correlate = False 

4494 

4495 def __init__( 

4496 self, 

4497 keyword: _CompoundSelectKeyword, 

4498 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4499 ): 

4500 self.keyword = keyword 

4501 self.selects = [ 

4502 coercions.expect( 

4503 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4504 ).self_group(against=self) 

4505 for s in selects 

4506 ] 

4507 

4508 GenerativeSelect.__init__(self) 

4509 

4510 @classmethod 

4511 def _create_union( 

4512 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4513 ) -> CompoundSelect[Unpack[_Ts]]: 

4514 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4515 

4516 @classmethod 

4517 def _create_union_all( 

4518 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4519 ) -> CompoundSelect[Unpack[_Ts]]: 

4520 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4521 

4522 @classmethod 

4523 def _create_except( 

4524 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4525 ) -> CompoundSelect[Unpack[_Ts]]: 

4526 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4527 

4528 @classmethod 

4529 def _create_except_all( 

4530 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4531 ) -> CompoundSelect[Unpack[_Ts]]: 

4532 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4533 

4534 @classmethod 

4535 def _create_intersect( 

4536 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4537 ) -> CompoundSelect[Unpack[_Ts]]: 

4538 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4539 

4540 @classmethod 

4541 def _create_intersect_all( 

4542 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4543 ) -> CompoundSelect[Unpack[_Ts]]: 

4544 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4545 

4546 def _scalar_type(self) -> TypeEngine[Any]: 

4547 return self.selects[0]._scalar_type() 

4548 

4549 def self_group( 

4550 self, against: Optional[OperatorType] = None 

4551 ) -> GroupedElement: 

4552 return SelectStatementGrouping(self) 

4553 

4554 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

4555 for s in self.selects: 

4556 if s.is_derived_from(fromclause): 

4557 return True 

4558 return False 

4559 

4560 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4561 if self._label_style is not style: 

4562 self = self._generate() 

4563 select_0 = self.selects[0].set_label_style(style) 

4564 self.selects = [select_0] + self.selects[1:] 

4565 

4566 return self 

4567 

4568 def _ensure_disambiguated_names(self) -> Self: 

4569 new_select = self.selects[0]._ensure_disambiguated_names() 

4570 if new_select is not self.selects[0]: 

4571 self = self._generate() 

4572 self.selects = [new_select] + self.selects[1:] 

4573 

4574 return self 

4575 

4576 def _generate_fromclause_column_proxies( 

4577 self, 

4578 subquery: FromClause, 

4579 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

4580 primary_key: ColumnSet, 

4581 foreign_keys: Set[KeyedColumnElement[Any]], 

4582 *, 

4583 proxy_compound_columns: Optional[ 

4584 Iterable[Sequence[ColumnElement[Any]]] 

4585 ] = None, 

4586 ) -> None: 

4587 # this is a slightly hacky thing - the union exports a 

4588 # column that resembles just that of the *first* selectable. 

4589 # to get at a "composite" column, particularly foreign keys, 

4590 # you have to dig through the proxies collection which we 

4591 # generate below. 

4592 select_0 = self.selects[0] 

4593 

4594 if self._label_style is not LABEL_STYLE_DEFAULT: 

4595 select_0 = select_0.set_label_style(self._label_style) 

4596 

4597 # hand-construct the "_proxies" collection to include all 

4598 # derived columns place a 'weight' annotation corresponding 

4599 # to how low in the list of select()s the column occurs, so 

4600 # that the corresponding_column() operation can resolve 

4601 # conflicts 

4602 extra_col_iterator = zip( 

4603 *[ 

4604 [ 

4605 c._annotate(dd) 

4606 for c in stmt._all_selected_columns 

4607 if is_column_element(c) 

4608 ] 

4609 for dd, stmt in [ 

4610 ({"weight": i + 1}, stmt) 

4611 for i, stmt in enumerate(self.selects) 

4612 ] 

4613 ] 

4614 ) 

4615 

4616 # the incoming proxy_compound_columns can be present also if this is 

4617 # a compound embedded in a compound. it's probably more appropriate 

4618 # that we generate new weights local to this nested compound, though 

4619 # i haven't tried to think what it means for compound nested in 

4620 # compound 

4621 select_0._generate_fromclause_column_proxies( 

4622 subquery, 

4623 columns, 

4624 proxy_compound_columns=extra_col_iterator, 

4625 primary_key=primary_key, 

4626 foreign_keys=foreign_keys, 

4627 ) 

4628 

4629 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

4630 super()._refresh_for_new_column(column) 

4631 for select in self.selects: 

4632 select._refresh_for_new_column(column) 

4633 

4634 @util.ro_non_memoized_property 

4635 def _all_selected_columns(self) -> _SelectIterable: 

4636 return self.selects[0]._all_selected_columns 

4637 

4638 @util.ro_non_memoized_property 

4639 def selected_columns( 

4640 self, 

4641 ) -> ColumnCollection[str, ColumnElement[Any]]: 

4642 """A :class:`_expression.ColumnCollection` 

4643 representing the columns that 

4644 this SELECT statement or similar construct returns in its result set, 

4645 not including :class:`_sql.TextClause` constructs. 

4646 

4647 For a :class:`_expression.CompoundSelect`, the 

4648 :attr:`_expression.CompoundSelect.selected_columns` 

4649 attribute returns the selected 

4650 columns of the first SELECT statement contained within the series of 

4651 statements within the set operation. 

4652 

4653 .. seealso:: 

4654 

4655 :attr:`_sql.Select.selected_columns` 

4656 

4657 .. versionadded:: 1.4 

4658 

4659 """ 

4660 return self.selects[0].selected_columns 

4661 

4662 

4663# backwards compat 

4664for elem in _CompoundSelectKeyword: 

4665 setattr(CompoundSelect, elem.name, elem) 

4666 

4667 

4668@CompileState.plugin_for("default", "select") 

4669class SelectState(util.MemoizedSlots, CompileState): 

4670 __slots__ = ( 

4671 "from_clauses", 

4672 "froms", 

4673 "columns_plus_names", 

4674 "_label_resolve_dict", 

4675 ) 

4676 

4677 if TYPE_CHECKING: 

4678 default_select_compile_options: CacheableOptions 

4679 else: 

4680 

4681 class default_select_compile_options(CacheableOptions): 

4682 _cache_key_traversal = [] 

4683 

4684 if TYPE_CHECKING: 

4685 

4686 @classmethod 

4687 def get_plugin_class( 

4688 cls, statement: Executable 

4689 ) -> Type[SelectState]: ... 

4690 

4691 def __init__( 

4692 self, 

4693 statement: Select[Unpack[TupleAny]], 

4694 compiler: SQLCompiler, 

4695 **kw: Any, 

4696 ): 

4697 self.statement = statement 

4698 self.from_clauses = statement._from_obj 

4699 

4700 for memoized_entities in statement._memoized_select_entities: 

4701 self._setup_joins( 

4702 memoized_entities._setup_joins, memoized_entities._raw_columns 

4703 ) 

4704 

4705 if statement._setup_joins: 

4706 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4707 

4708 self.froms = self._get_froms(statement) 

4709 

4710 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4711 

4712 @classmethod 

4713 def _plugin_not_implemented(cls) -> NoReturn: 

4714 raise NotImplementedError( 

4715 "The default SELECT construct without plugins does not " 

4716 "implement this method." 

4717 ) 

4718 

4719 @classmethod 

4720 def get_column_descriptions( 

4721 cls, statement: Select[Unpack[TupleAny]] 

4722 ) -> List[Dict[str, Any]]: 

4723 return [ 

4724 { 

4725 "name": name, 

4726 "type": element.type, 

4727 "expr": element, 

4728 } 

4729 for _, name, _, element, _ in ( 

4730 statement._generate_columns_plus_names(False) 

4731 ) 

4732 ] 

4733 

4734 @classmethod 

4735 def from_statement( 

4736 cls, 

4737 statement: Select[Unpack[TupleAny]], 

4738 from_statement: roles.ReturnsRowsRole, 

4739 ) -> ExecutableReturnsRows: 

4740 cls._plugin_not_implemented() 

4741 

4742 @classmethod 

4743 def get_columns_clause_froms( 

4744 cls, statement: Select[Unpack[TupleAny]] 

4745 ) -> List[FromClause]: 

4746 return cls._normalize_froms( 

4747 itertools.chain.from_iterable( 

4748 element._from_objects for element in statement._raw_columns 

4749 ) 

4750 ) 

4751 

4752 @classmethod 

4753 def _column_naming_convention( 

4754 cls, label_style: SelectLabelStyle 

4755 ) -> _LabelConventionCallable: 

4756 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4757 

4758 dedupe = label_style is not LABEL_STYLE_NONE 

4759 

4760 pa = prefix_anon_map() 

4761 names = set() 

4762 

4763 def go( 

4764 c: Union[ColumnElement[Any], TextClause], 

4765 col_name: Optional[str] = None, 

4766 ) -> Optional[str]: 

4767 if is_text_clause(c): 

4768 return None 

4769 elif TYPE_CHECKING: 

4770 assert is_column_element(c) 

4771 

4772 if not dedupe: 

4773 name = c._proxy_key 

4774 if name is None: 

4775 name = "_no_label" 

4776 return name 

4777 

4778 name = c._tq_key_label if table_qualified else c._proxy_key 

4779 

4780 if name is None: 

4781 name = "_no_label" 

4782 if name in names: 

4783 return c._anon_label(name) % pa 

4784 else: 

4785 names.add(name) 

4786 return name 

4787 

4788 elif name in names: 

4789 return ( 

4790 c._anon_tq_key_label % pa 

4791 if table_qualified 

4792 else c._anon_key_label % pa 

4793 ) 

4794 else: 

4795 names.add(name) 

4796 return name 

4797 

4798 return go 

4799 

4800 def _get_froms( 

4801 self, statement: Select[Unpack[TupleAny]] 

4802 ) -> List[FromClause]: 

4803 ambiguous_table_name_map: _AmbiguousTableNameMap 

4804 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4805 

4806 return self._normalize_froms( 

4807 itertools.chain( 

4808 self.from_clauses, 

4809 itertools.chain.from_iterable( 

4810 [ 

4811 element._from_objects 

4812 for element in statement._raw_columns 

4813 ] 

4814 ), 

4815 itertools.chain.from_iterable( 

4816 [ 

4817 element._from_objects 

4818 for element in statement._where_criteria 

4819 ] 

4820 ), 

4821 ), 

4822 check_statement=statement, 

4823 ambiguous_table_name_map=ambiguous_table_name_map, 

4824 ) 

4825 

4826 @classmethod 

4827 def _normalize_froms( 

4828 cls, 

4829 iterable_of_froms: Iterable[FromClause], 

4830 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4831 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4832 ) -> List[FromClause]: 

4833 """given an iterable of things to select FROM, reduce them to what 

4834 would actually render in the FROM clause of a SELECT. 

4835 

4836 This does the job of checking for JOINs, tables, etc. that are in fact 

4837 overlapping due to cloning, adaption, present in overlapping joins, 

4838 etc. 

4839 

4840 """ 

4841 seen: Set[FromClause] = set() 

4842 froms: List[FromClause] = [] 

4843 

4844 for item in iterable_of_froms: 

4845 if is_subquery(item) and item.element is check_statement: 

4846 raise exc.InvalidRequestError( 

4847 "select() construct refers to itself as a FROM" 

4848 ) 

4849 

4850 if not seen.intersection(item._cloned_set): 

4851 froms.append(item) 

4852 seen.update(item._cloned_set) 

4853 

4854 if froms: 

4855 toremove = set( 

4856 itertools.chain.from_iterable( 

4857 [_expand_cloned(f._hide_froms) for f in froms] 

4858 ) 

4859 ) 

4860 if toremove: 

4861 # filter out to FROM clauses not in the list, 

4862 # using a list to maintain ordering 

4863 froms = [f for f in froms if f not in toremove] 

4864 

4865 if ambiguous_table_name_map is not None: 

4866 ambiguous_table_name_map.update( 

4867 ( 

4868 fr.name, 

4869 _anonymous_label.safe_construct( 

4870 hash(fr.name), fr.name 

4871 ), 

4872 ) 

4873 for item in froms 

4874 for fr in item._from_objects 

4875 if is_table(fr) 

4876 and fr.schema 

4877 and fr.name not in ambiguous_table_name_map 

4878 ) 

4879 

4880 return froms 

4881 

4882 def _get_display_froms( 

4883 self, 

4884 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4885 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4886 ) -> List[FromClause]: 

4887 """Return the full list of 'from' clauses to be displayed. 

4888 

4889 Takes into account a set of existing froms which may be 

4890 rendered in the FROM clause of enclosing selects; this Select 

4891 may want to leave those absent if it is automatically 

4892 correlating. 

4893 

4894 """ 

4895 

4896 froms = self.froms 

4897 

4898 if self.statement._correlate: 

4899 to_correlate = self.statement._correlate 

4900 if to_correlate: 

4901 froms = [ 

4902 f 

4903 for f in froms 

4904 if f 

4905 not in _cloned_intersection( 

4906 _cloned_intersection( 

4907 froms, explicit_correlate_froms or () 

4908 ), 

4909 to_correlate, 

4910 ) 

4911 ] 

4912 

4913 if self.statement._correlate_except is not None: 

4914 froms = [ 

4915 f 

4916 for f in froms 

4917 if f 

4918 not in _cloned_difference( 

4919 _cloned_intersection( 

4920 froms, explicit_correlate_froms or () 

4921 ), 

4922 self.statement._correlate_except, 

4923 ) 

4924 ] 

4925 

4926 if ( 

4927 self.statement._auto_correlate 

4928 and implicit_correlate_froms 

4929 and len(froms) > 1 

4930 ): 

4931 froms = [ 

4932 f 

4933 for f in froms 

4934 if f 

4935 not in _cloned_intersection(froms, implicit_correlate_froms) 

4936 ] 

4937 

4938 if not len(froms): 

4939 raise exc.InvalidRequestError( 

4940 "Select statement '%r" 

4941 "' returned no FROM clauses " 

4942 "due to auto-correlation; " 

4943 "specify correlate(<tables>) " 

4944 "to control correlation " 

4945 "manually." % self.statement 

4946 ) 

4947 

4948 return froms 

4949 

4950 def _memoized_attr__label_resolve_dict( 

4951 self, 

4952 ) -> Tuple[ 

4953 Dict[str, ColumnElement[Any]], 

4954 Dict[str, ColumnElement[Any]], 

4955 Dict[str, ColumnElement[Any]], 

4956 ]: 

4957 with_cols: Dict[str, ColumnElement[Any]] = { 

4958 c._tq_label or c.key: c 

4959 for c in self.statement._all_selected_columns 

4960 if c._allow_label_resolve 

4961 } 

4962 only_froms: Dict[str, ColumnElement[Any]] = { 

4963 c.key: c # type: ignore 

4964 for c in _select_iterables(self.froms) 

4965 if c._allow_label_resolve 

4966 } 

4967 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

4968 for key, value in only_froms.items(): 

4969 with_cols.setdefault(key, value) 

4970 

4971 return with_cols, only_froms, only_cols 

4972 

4973 @classmethod 

4974 def determine_last_joined_entity( 

4975 cls, stmt: Select[Unpack[TupleAny]] 

4976 ) -> Optional[_JoinTargetElement]: 

4977 if stmt._setup_joins: 

4978 return stmt._setup_joins[-1][0] 

4979 else: 

4980 return None 

4981 

4982 @classmethod 

4983 def all_selected_columns( 

4984 cls, statement: Select[Unpack[TupleAny]] 

4985 ) -> _SelectIterable: 

4986 return [c for c in _select_iterables(statement._raw_columns)] 

4987 

4988 def _setup_joins( 

4989 self, 

4990 args: Tuple[_SetupJoinsElement, ...], 

4991 raw_columns: List[_ColumnsClauseElement], 

4992 ) -> None: 

4993 for right, onclause, left, flags in args: 

4994 if TYPE_CHECKING: 

4995 if onclause is not None: 

4996 assert isinstance(onclause, ColumnElement) 

4997 

4998 isouter = flags["isouter"] 

4999 full = flags["full"] 

5000 

5001 if left is None: 

5002 ( 

5003 left, 

5004 replace_from_obj_index, 

5005 ) = self._join_determine_implicit_left_side( 

5006 raw_columns, left, right, onclause 

5007 ) 

5008 else: 

5009 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5010 left 

5011 ) 

5012 

5013 # these assertions can be made here, as if the right/onclause 

5014 # contained ORM elements, the select() statement would have been 

5015 # upgraded to an ORM select, and this method would not be called; 

5016 # orm.context.ORMSelectCompileState._join() would be 

5017 # used instead. 

5018 if TYPE_CHECKING: 

5019 assert isinstance(right, FromClause) 

5020 if onclause is not None: 

5021 assert isinstance(onclause, ColumnElement) 

5022 

5023 if replace_from_obj_index is not None: 

5024 # splice into an existing element in the 

5025 # self._from_obj list 

5026 left_clause = self.from_clauses[replace_from_obj_index] 

5027 

5028 self.from_clauses = ( 

5029 self.from_clauses[:replace_from_obj_index] 

5030 + ( 

5031 Join( 

5032 left_clause, 

5033 right, 

5034 onclause, 

5035 isouter=isouter, 

5036 full=full, 

5037 ), 

5038 ) 

5039 + self.from_clauses[replace_from_obj_index + 1 :] 

5040 ) 

5041 else: 

5042 assert left is not None 

5043 self.from_clauses = self.from_clauses + ( 

5044 Join(left, right, onclause, isouter=isouter, full=full), 

5045 ) 

5046 

5047 @util.preload_module("sqlalchemy.sql.util") 

5048 def _join_determine_implicit_left_side( 

5049 self, 

5050 raw_columns: List[_ColumnsClauseElement], 

5051 left: Optional[FromClause], 

5052 right: _JoinTargetElement, 

5053 onclause: Optional[ColumnElement[Any]], 

5054 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5055 """When join conditions don't express the left side explicitly, 

5056 determine if an existing FROM or entity in this query 

5057 can serve as the left hand side. 

5058 

5059 """ 

5060 

5061 sql_util = util.preloaded.sql_util 

5062 

5063 replace_from_obj_index: Optional[int] = None 

5064 

5065 from_clauses = self.from_clauses 

5066 

5067 if from_clauses: 

5068 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5069 from_clauses, right, onclause 

5070 ) 

5071 

5072 if len(indexes) == 1: 

5073 replace_from_obj_index = indexes[0] 

5074 left = from_clauses[replace_from_obj_index] 

5075 else: 

5076 potential = {} 

5077 statement = self.statement 

5078 

5079 for from_clause in itertools.chain( 

5080 itertools.chain.from_iterable( 

5081 [element._from_objects for element in raw_columns] 

5082 ), 

5083 itertools.chain.from_iterable( 

5084 [ 

5085 element._from_objects 

5086 for element in statement._where_criteria 

5087 ] 

5088 ), 

5089 ): 

5090 potential[from_clause] = () 

5091 

5092 all_clauses = list(potential.keys()) 

5093 indexes = sql_util.find_left_clause_to_join_from( 

5094 all_clauses, right, onclause 

5095 ) 

5096 

5097 if len(indexes) == 1: 

5098 left = all_clauses[indexes[0]] 

5099 

5100 if len(indexes) > 1: 

5101 raise exc.InvalidRequestError( 

5102 "Can't determine which FROM clause to join " 

5103 "from, there are multiple FROMS which can " 

5104 "join to this entity. Please use the .select_from() " 

5105 "method to establish an explicit left side, as well as " 

5106 "providing an explicit ON clause if not present already to " 

5107 "help resolve the ambiguity." 

5108 ) 

5109 elif not indexes: 

5110 raise exc.InvalidRequestError( 

5111 "Don't know how to join to %r. " 

5112 "Please use the .select_from() " 

5113 "method to establish an explicit left side, as well as " 

5114 "providing an explicit ON clause if not present already to " 

5115 "help resolve the ambiguity." % (right,) 

5116 ) 

5117 return left, replace_from_obj_index 

5118 

5119 @util.preload_module("sqlalchemy.sql.util") 

5120 def _join_place_explicit_left_side( 

5121 self, left: FromClause 

5122 ) -> Optional[int]: 

5123 replace_from_obj_index: Optional[int] = None 

5124 

5125 sql_util = util.preloaded.sql_util 

5126 

5127 from_clauses = list(self.statement._iterate_from_elements()) 

5128 

5129 if from_clauses: 

5130 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5131 self.from_clauses, left 

5132 ) 

5133 else: 

5134 indexes = [] 

5135 

5136 if len(indexes) > 1: 

5137 raise exc.InvalidRequestError( 

5138 "Can't identify which entity in which to assign the " 

5139 "left side of this join. Please use a more specific " 

5140 "ON clause." 

5141 ) 

5142 

5143 # have an index, means the left side is already present in 

5144 # an existing FROM in the self._from_obj tuple 

5145 if indexes: 

5146 replace_from_obj_index = indexes[0] 

5147 

5148 # no index, means we need to add a new element to the 

5149 # self._from_obj tuple 

5150 

5151 return replace_from_obj_index 

5152 

5153 

5154class _SelectFromElements: 

5155 __slots__ = () 

5156 

5157 _raw_columns: List[_ColumnsClauseElement] 

5158 _where_criteria: Tuple[ColumnElement[Any], ...] 

5159 _from_obj: Tuple[FromClause, ...] 

5160 

5161 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5162 # note this does not include elements 

5163 # in _setup_joins 

5164 

5165 seen = set() 

5166 for element in self._raw_columns: 

5167 for fr in element._from_objects: 

5168 if fr in seen: 

5169 continue 

5170 seen.add(fr) 

5171 yield fr 

5172 for element in self._where_criteria: 

5173 for fr in element._from_objects: 

5174 if fr in seen: 

5175 continue 

5176 seen.add(fr) 

5177 yield fr 

5178 for element in self._from_obj: 

5179 if element in seen: 

5180 continue 

5181 seen.add(element) 

5182 yield element 

5183 

5184 

5185class _MemoizedSelectEntities( 

5186 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5187): 

5188 """represents partial state from a Select object, for the case 

5189 where Select.columns() has redefined the set of columns/entities the 

5190 statement will be SELECTing from. This object represents 

5191 the entities from the SELECT before that transformation was applied, 

5192 so that transformations that were made in terms of the SELECT at that 

5193 time, such as join() as well as options(), can access the correct context. 

5194 

5195 In previous SQLAlchemy versions, this wasn't needed because these 

5196 constructs calculated everything up front, like when you called join() 

5197 or options(), it did everything to figure out how that would translate 

5198 into specific SQL constructs that would be ready to send directly to the 

5199 SQL compiler when needed. But as of 

5200 1.4, all of that stuff is done in the compilation phase, during the 

5201 "compile state" portion of the process, so that the work can all be 

5202 cached. So it needs to be able to resolve joins/options2 based on what 

5203 the list of entities was when those methods were called. 

5204 

5205 

5206 """ 

5207 

5208 __visit_name__ = "memoized_select_entities" 

5209 

5210 _traverse_internals: _TraverseInternalsType = [ 

5211 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5212 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5213 ("_with_options", InternalTraversal.dp_executable_options), 

5214 ] 

5215 

5216 _is_clone_of: Optional[ClauseElement] 

5217 _raw_columns: List[_ColumnsClauseElement] 

5218 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5219 _with_options: Tuple[ExecutableOption, ...] 

5220 

5221 _annotations = util.EMPTY_DICT 

5222 

5223 def _clone(self, **kw: Any) -> Self: 

5224 c = self.__class__.__new__(self.__class__) 

5225 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5226 

5227 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5228 return c 

5229 

5230 @classmethod 

5231 def _generate_for_statement( 

5232 cls, select_stmt: Select[Unpack[TupleAny]] 

5233 ) -> None: 

5234 if select_stmt._setup_joins or select_stmt._with_options: 

5235 self = _MemoizedSelectEntities() 

5236 self._raw_columns = select_stmt._raw_columns 

5237 self._setup_joins = select_stmt._setup_joins 

5238 self._with_options = select_stmt._with_options 

5239 

5240 select_stmt._memoized_select_entities += (self,) 

5241 select_stmt._raw_columns = [] 

5242 select_stmt._setup_joins = select_stmt._with_options = () 

5243 

5244 

5245class Select( 

5246 HasPrefixes, 

5247 HasSuffixes, 

5248 HasHints, 

5249 HasCompileState, 

5250 HasSyntaxExtensions[ 

5251 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5252 ], 

5253 _SelectFromElements, 

5254 GenerativeSelect, 

5255 TypedReturnsRows[Unpack[_Ts]], 

5256): 

5257 """Represents a ``SELECT`` statement. 

5258 

5259 The :class:`_sql.Select` object is normally constructed using the 

5260 :func:`_sql.select` function. See that function for details. 

5261 

5262 Available extension points: 

5263 

5264 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5265 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5266 keyword (if any) and the list of columns. 

5267 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5268 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5269 

5270 .. seealso:: 

5271 

5272 :func:`_sql.select` 

5273 

5274 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5275 

5276 """ 

5277 

5278 __visit_name__ = "select" 

5279 

5280 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5281 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5282 

5283 _raw_columns: List[_ColumnsClauseElement] 

5284 

5285 _distinct: bool = False 

5286 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5287 _correlate: Tuple[FromClause, ...] = () 

5288 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5289 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5290 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5291 _from_obj: Tuple[FromClause, ...] = () 

5292 

5293 _position_map = util.immutabledict( 

5294 { 

5295 "post_select": "_post_select_clause", 

5296 "pre_columns": "_pre_columns_clause", 

5297 "post_criteria": "_post_criteria_clause", 

5298 "post_body": "_post_body_clause", 

5299 } 

5300 ) 

5301 

5302 _post_select_clause: Optional[ClauseElement] = None 

5303 """extension point for a ClauseElement that will be compiled directly 

5304 after the SELECT keyword. 

5305 

5306 .. versionadded:: 2.1 

5307 

5308 """ 

5309 

5310 _pre_columns_clause: Optional[ClauseElement] = None 

5311 """extension point for a ClauseElement that will be compiled directly 

5312 before the "columns" clause; after DISTINCT (if present). 

5313 

5314 .. versionadded:: 2.1 

5315 

5316 """ 

5317 

5318 _post_criteria_clause: Optional[ClauseElement] = None 

5319 """extension point for a ClauseElement that will be compiled directly 

5320 after "criteria", following the HAVING clause but before ORDER BY. 

5321 

5322 .. versionadded:: 2.1 

5323 

5324 """ 

5325 

5326 _post_body_clause: Optional[ClauseElement] = None 

5327 """extension point for a ClauseElement that will be compiled directly 

5328 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5329 of the SELECT. 

5330 

5331 .. versionadded:: 2.1 

5332 

5333 """ 

5334 

5335 _auto_correlate = True 

5336 _is_select_statement = True 

5337 _compile_options: CacheableOptions = ( 

5338 SelectState.default_select_compile_options 

5339 ) 

5340 

5341 _traverse_internals: _TraverseInternalsType = ( 

5342 [ 

5343 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5344 ( 

5345 "_memoized_select_entities", 

5346 InternalTraversal.dp_memoized_select_entities, 

5347 ), 

5348 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5349 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5350 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5351 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5352 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5353 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5354 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5355 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5356 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5357 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5358 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5359 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5360 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5361 ("_distinct", InternalTraversal.dp_boolean), 

5362 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5363 ("_label_style", InternalTraversal.dp_plain_obj), 

5364 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5365 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5366 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5367 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5368 ] 

5369 + HasCTE._has_ctes_traverse_internals 

5370 + HasPrefixes._has_prefixes_traverse_internals 

5371 + HasSuffixes._has_suffixes_traverse_internals 

5372 + HasHints._has_hints_traverse_internals 

5373 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5374 + Executable._executable_traverse_internals 

5375 + DialectKWArgs._dialect_kwargs_traverse_internals 

5376 ) 

5377 

5378 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5379 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5380 ] 

5381 

5382 _compile_state_factory: Type[SelectState] 

5383 

5384 @classmethod 

5385 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5386 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5387 

5388 Used internally to build up :class:`.Select` constructs with 

5389 pre-established state. 

5390 

5391 """ 

5392 

5393 stmt = Select.__new__(Select) 

5394 stmt.__dict__.update(kw) 

5395 return stmt 

5396 

5397 def __init__( 

5398 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5399 ): 

5400 r"""Construct a new :class:`_expression.Select`. 

5401 

5402 The public constructor for :class:`_expression.Select` is the 

5403 :func:`_sql.select` function. 

5404 

5405 """ 

5406 self._raw_columns = [ 

5407 coercions.expect( 

5408 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5409 ) 

5410 for ent in entities 

5411 ] 

5412 GenerativeSelect.__init__(self) 

5413 

5414 def _apply_syntax_extension_to_self( 

5415 self, extension: SyntaxExtension 

5416 ) -> None: 

5417 extension.apply_to_select(self) 

5418 

5419 def _scalar_type(self) -> TypeEngine[Any]: 

5420 if not self._raw_columns: 

5421 return NULLTYPE 

5422 elem = self._raw_columns[0] 

5423 cols = list(elem._select_iterable) 

5424 return cols[0].type 

5425 

5426 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5427 """A synonym for the :meth:`_sql.Select.where` method.""" 

5428 

5429 return self.where(*criteria) 

5430 

5431 def _filter_by_zero( 

5432 self, 

5433 ) -> Union[ 

5434 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5435 ]: 

5436 if self._setup_joins: 

5437 meth = SelectState.get_plugin_class( 

5438 self 

5439 ).determine_last_joined_entity 

5440 _last_joined_entity = meth(self) 

5441 if _last_joined_entity is not None: 

5442 return _last_joined_entity 

5443 

5444 if self._from_obj: 

5445 return self._from_obj[0] 

5446 

5447 return self._raw_columns[0] 

5448 

5449 if TYPE_CHECKING: 

5450 

5451 @overload 

5452 def scalar_subquery( 

5453 self: Select[_MAYBE_ENTITY], 

5454 ) -> ScalarSelect[Any]: ... 

5455 

5456 @overload 

5457 def scalar_subquery( 

5458 self: Select[_NOT_ENTITY], 

5459 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5460 

5461 @overload 

5462 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5463 

5464 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5465 

5466 def filter_by(self, **kwargs: Any) -> Self: 

5467 r"""apply the given filtering criterion as a WHERE clause 

5468 to this select. 

5469 

5470 """ 

5471 from_entity = self._filter_by_zero() 

5472 

5473 clauses = [ 

5474 _entity_namespace_key(from_entity, key) == value 

5475 for key, value in kwargs.items() 

5476 ] 

5477 return self.filter(*clauses) 

5478 

5479 @property 

5480 def column_descriptions(self) -> Any: 

5481 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5482 referring to the columns which are SELECTed by this statement. 

5483 

5484 This attribute is generally useful when using the ORM, as an 

5485 extended structure which includes information about mapped 

5486 entities is returned. The section :ref:`queryguide_inspection` 

5487 contains more background. 

5488 

5489 For a Core-only statement, the structure returned by this accessor 

5490 is derived from the same objects that are returned by the 

5491 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5492 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5493 which indicate the column expressions to be selected:: 

5494 

5495 >>> stmt = select(user_table) 

5496 >>> stmt.column_descriptions 

5497 [ 

5498 { 

5499 'name': 'id', 

5500 'type': Integer(), 

5501 'expr': Column('id', Integer(), ...)}, 

5502 { 

5503 'name': 'name', 

5504 'type': String(length=30), 

5505 'expr': Column('name', String(length=30), ...)} 

5506 ] 

5507 

5508 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5509 attribute returns a structure for a Core-only set of entities, 

5510 not just ORM-only entities. 

5511 

5512 .. seealso:: 

5513 

5514 :attr:`.UpdateBase.entity_description` - entity information for 

5515 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5516 

5517 :ref:`queryguide_inspection` - ORM background 

5518 

5519 """ 

5520 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5521 return meth(self) 

5522 

5523 def from_statement( 

5524 self, statement: roles.ReturnsRowsRole 

5525 ) -> ExecutableReturnsRows: 

5526 """Apply the columns which this :class:`.Select` would select 

5527 onto another statement. 

5528 

5529 This operation is :term:`plugin-specific` and will raise a not 

5530 supported exception if this :class:`_sql.Select` does not select from 

5531 plugin-enabled entities. 

5532 

5533 

5534 The statement is typically either a :func:`_expression.text` or 

5535 :func:`_expression.select` construct, and should return the set of 

5536 columns appropriate to the entities represented by this 

5537 :class:`.Select`. 

5538 

5539 .. seealso:: 

5540 

5541 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5542 ORM Querying Guide 

5543 

5544 """ 

5545 meth = SelectState.get_plugin_class(self).from_statement 

5546 return meth(self, statement) 

5547 

5548 @_generative 

5549 def join( 

5550 self, 

5551 target: _JoinTargetArgument, 

5552 onclause: Optional[_OnClauseArgument] = None, 

5553 *, 

5554 isouter: bool = False, 

5555 full: bool = False, 

5556 ) -> Self: 

5557 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5558 object's criterion 

5559 and apply generatively, returning the newly resulting 

5560 :class:`_expression.Select`. 

5561 

5562 E.g.:: 

5563 

5564 stmt = select(user_table).join( 

5565 address_table, user_table.c.id == address_table.c.user_id 

5566 ) 

5567 

5568 The above statement generates SQL similar to: 

5569 

5570 .. sourcecode:: sql 

5571 

5572 SELECT user.id, user.name 

5573 FROM user 

5574 JOIN address ON user.id = address.user_id 

5575 

5576 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5577 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5578 source that is within the FROM clause of the existing SELECT, 

5579 and a given target :class:`_sql.FromClause`, and then adds 

5580 this :class:`_sql.Join` to the FROM clause of the newly generated 

5581 SELECT statement. This is completely reworked from the behavior 

5582 in 1.3, which would instead create a subquery of the entire 

5583 :class:`_expression.Select` and then join that subquery to the 

5584 target. 

5585 

5586 This is a **backwards incompatible change** as the previous behavior 

5587 was mostly useless, producing an unnamed subquery rejected by 

5588 most databases in any case. The new behavior is modeled after 

5589 that of the very successful :meth:`_orm.Query.join` method in the 

5590 ORM, in order to support the functionality of :class:`_orm.Query` 

5591 being available by using a :class:`_sql.Select` object with an 

5592 :class:`_orm.Session`. 

5593 

5594 See the notes for this change at :ref:`change_select_join`. 

5595 

5596 

5597 :param target: target table to join towards 

5598 

5599 :param onclause: ON clause of the join. If omitted, an ON clause 

5600 is generated automatically based on the :class:`_schema.ForeignKey` 

5601 linkages between the two tables, if one can be unambiguously 

5602 determined, otherwise an error is raised. 

5603 

5604 :param isouter: if True, generate LEFT OUTER join. Same as 

5605 :meth:`_expression.Select.outerjoin`. 

5606 

5607 :param full: if True, generate FULL OUTER join. 

5608 

5609 .. seealso:: 

5610 

5611 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5612 

5613 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5614 

5615 :meth:`_expression.Select.join_from` 

5616 

5617 :meth:`_expression.Select.outerjoin` 

5618 

5619 """ # noqa: E501 

5620 join_target = coercions.expect( 

5621 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5622 ) 

5623 if onclause is not None: 

5624 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5625 else: 

5626 onclause_element = None 

5627 

5628 self._setup_joins += ( 

5629 ( 

5630 join_target, 

5631 onclause_element, 

5632 None, 

5633 {"isouter": isouter, "full": full}, 

5634 ), 

5635 ) 

5636 return self 

5637 

5638 def outerjoin_from( 

5639 self, 

5640 from_: _FromClauseArgument, 

5641 target: _JoinTargetArgument, 

5642 onclause: Optional[_OnClauseArgument] = None, 

5643 *, 

5644 full: bool = False, 

5645 ) -> Self: 

5646 r"""Create a SQL LEFT OUTER JOIN against this 

5647 :class:`_expression.Select` object's criterion and apply generatively, 

5648 returning the newly resulting :class:`_expression.Select`. 

5649 

5650 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5651 

5652 """ 

5653 return self.join_from( 

5654 from_, target, onclause=onclause, isouter=True, full=full 

5655 ) 

5656 

5657 @_generative 

5658 def join_from( 

5659 self, 

5660 from_: _FromClauseArgument, 

5661 target: _JoinTargetArgument, 

5662 onclause: Optional[_OnClauseArgument] = None, 

5663 *, 

5664 isouter: bool = False, 

5665 full: bool = False, 

5666 ) -> Self: 

5667 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5668 object's criterion 

5669 and apply generatively, returning the newly resulting 

5670 :class:`_expression.Select`. 

5671 

5672 E.g.:: 

5673 

5674 stmt = select(user_table, address_table).join_from( 

5675 user_table, address_table, user_table.c.id == address_table.c.user_id 

5676 ) 

5677 

5678 The above statement generates SQL similar to: 

5679 

5680 .. sourcecode:: sql 

5681 

5682 SELECT user.id, user.name, address.id, address.email, address.user_id 

5683 FROM user JOIN address ON user.id = address.user_id 

5684 

5685 .. versionadded:: 1.4 

5686 

5687 :param from\_: the left side of the join, will be rendered in the 

5688 FROM clause and is roughly equivalent to using the 

5689 :meth:`.Select.select_from` method. 

5690 

5691 :param target: target table to join towards 

5692 

5693 :param onclause: ON clause of the join. 

5694 

5695 :param isouter: if True, generate LEFT OUTER join. Same as 

5696 :meth:`_expression.Select.outerjoin`. 

5697 

5698 :param full: if True, generate FULL OUTER join. 

5699 

5700 .. seealso:: 

5701 

5702 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5703 

5704 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5705 

5706 :meth:`_expression.Select.join` 

5707 

5708 """ # noqa: E501 

5709 

5710 # note the order of parsing from vs. target is important here, as we 

5711 # are also deriving the source of the plugin (i.e. the subject mapper 

5712 # in an ORM query) which should favor the "from_" over the "target" 

5713 

5714 from_ = coercions.expect( 

5715 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5716 ) 

5717 join_target = coercions.expect( 

5718 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5719 ) 

5720 if onclause is not None: 

5721 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5722 else: 

5723 onclause_element = None 

5724 

5725 self._setup_joins += ( 

5726 ( 

5727 join_target, 

5728 onclause_element, 

5729 from_, 

5730 {"isouter": isouter, "full": full}, 

5731 ), 

5732 ) 

5733 return self 

5734 

5735 def outerjoin( 

5736 self, 

5737 target: _JoinTargetArgument, 

5738 onclause: Optional[_OnClauseArgument] = None, 

5739 *, 

5740 full: bool = False, 

5741 ) -> Self: 

5742 """Create a left outer join. 

5743 

5744 Parameters are the same as that of :meth:`_expression.Select.join`. 

5745 

5746 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5747 creates a :class:`_sql.Join` object between a 

5748 :class:`_sql.FromClause` source that is within the FROM clause of 

5749 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5750 and then adds this :class:`_sql.Join` to the FROM clause of the 

5751 newly generated SELECT statement. This is completely reworked 

5752 from the behavior in 1.3, which would instead create a subquery of 

5753 the entire 

5754 :class:`_expression.Select` and then join that subquery to the 

5755 target. 

5756 

5757 This is a **backwards incompatible change** as the previous behavior 

5758 was mostly useless, producing an unnamed subquery rejected by 

5759 most databases in any case. The new behavior is modeled after 

5760 that of the very successful :meth:`_orm.Query.join` method in the 

5761 ORM, in order to support the functionality of :class:`_orm.Query` 

5762 being available by using a :class:`_sql.Select` object with an 

5763 :class:`_orm.Session`. 

5764 

5765 See the notes for this change at :ref:`change_select_join`. 

5766 

5767 .. seealso:: 

5768 

5769 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5770 

5771 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5772 

5773 :meth:`_expression.Select.join` 

5774 

5775 """ 

5776 return self.join(target, onclause=onclause, isouter=True, full=full) 

5777 

5778 def get_final_froms(self) -> Sequence[FromClause]: 

5779 """Compute the final displayed list of :class:`_expression.FromClause` 

5780 elements. 

5781 

5782 This method will run through the full computation required to 

5783 determine what FROM elements will be displayed in the resulting 

5784 SELECT statement, including shadowing individual tables with 

5785 JOIN objects, as well as full computation for ORM use cases including 

5786 eager loading clauses. 

5787 

5788 For ORM use, this accessor returns the **post compilation** 

5789 list of FROM objects; this collection will include elements such as 

5790 eagerly loaded tables and joins. The objects will **not** be 

5791 ORM enabled and not work as a replacement for the 

5792 :meth:`_sql.Select.select_froms` collection; additionally, the 

5793 method is not well performing for an ORM enabled statement as it 

5794 will incur the full ORM construction process. 

5795 

5796 To retrieve the FROM list that's implied by the "columns" collection 

5797 passed to the :class:`_sql.Select` originally, use the 

5798 :attr:`_sql.Select.columns_clause_froms` accessor. 

5799 

5800 To select from an alternative set of columns while maintaining the 

5801 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5802 pass the 

5803 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5804 parameter. 

5805 

5806 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5807 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5808 which is deprecated. 

5809 

5810 .. seealso:: 

5811 

5812 :attr:`_sql.Select.columns_clause_froms` 

5813 

5814 """ 

5815 compiler = self._default_compiler() 

5816 

5817 return self._compile_state_factory(self, compiler)._get_display_froms() 

5818 

5819 @property 

5820 @util.deprecated( 

5821 "1.4.23", 

5822 "The :attr:`_expression.Select.froms` attribute is moved to " 

5823 "the :meth:`_expression.Select.get_final_froms` method.", 

5824 ) 

5825 def froms(self) -> Sequence[FromClause]: 

5826 """Return the displayed list of :class:`_expression.FromClause` 

5827 elements. 

5828 

5829 

5830 """ 

5831 return self.get_final_froms() 

5832 

5833 @property 

5834 def columns_clause_froms(self) -> List[FromClause]: 

5835 """Return the set of :class:`_expression.FromClause` objects implied 

5836 by the columns clause of this SELECT statement. 

5837 

5838 .. versionadded:: 1.4.23 

5839 

5840 .. seealso:: 

5841 

5842 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5843 statement into account 

5844 

5845 :meth:`_sql.Select.with_only_columns` - makes use of this 

5846 collection to set up a new FROM list 

5847 

5848 """ 

5849 

5850 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5851 self 

5852 ) 

5853 

5854 @property 

5855 def inner_columns(self) -> _SelectIterable: 

5856 """An iterator of all :class:`_expression.ColumnElement` 

5857 expressions which would 

5858 be rendered into the columns clause of the resulting SELECT statement. 

5859 

5860 This method is legacy as of 1.4 and is superseded by the 

5861 :attr:`_expression.Select.exported_columns` collection. 

5862 

5863 """ 

5864 

5865 return iter(self._all_selected_columns) 

5866 

5867 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5868 if fromclause is not None and self in fromclause._cloned_set: 

5869 return True 

5870 

5871 for f in self._iterate_from_elements(): 

5872 if f.is_derived_from(fromclause): 

5873 return True 

5874 return False 

5875 

5876 def _copy_internals( 

5877 self, clone: _CloneCallableType = _clone, **kw: Any 

5878 ) -> None: 

5879 # Select() object has been cloned and probably adapted by the 

5880 # given clone function. Apply the cloning function to internal 

5881 # objects 

5882 

5883 # 1. keep a dictionary of the froms we've cloned, and what 

5884 # they've become. This allows us to ensure the same cloned from 

5885 # is used when other items such as columns are "cloned" 

5886 

5887 all_the_froms = set( 

5888 itertools.chain( 

5889 _from_objects(*self._raw_columns), 

5890 _from_objects(*self._where_criteria), 

5891 _from_objects(*[elem[0] for elem in self._setup_joins]), 

5892 ) 

5893 ) 

5894 

5895 # do a clone for the froms we've gathered. what is important here 

5896 # is if any of the things we are selecting from, like tables, 

5897 # were converted into Join objects. if so, these need to be 

5898 # added to _from_obj explicitly, because otherwise they won't be 

5899 # part of the new state, as they don't associate themselves with 

5900 # their columns. 

5901 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

5902 

5903 # 2. copy FROM collections, adding in joins that we've created. 

5904 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

5905 add_froms = ( 

5906 {f for f in new_froms.values() if isinstance(f, Join)} 

5907 .difference(all_the_froms) 

5908 .difference(existing_from_obj) 

5909 ) 

5910 

5911 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

5912 

5913 # 3. clone everything else, making sure we use columns 

5914 # corresponding to the froms we just made. 

5915 def replace( 

5916 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

5917 **kw: Any, 

5918 ) -> Optional[KeyedColumnElement[Any]]: 

5919 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

5920 newelem = new_froms[obj.table].corresponding_column(obj) 

5921 return newelem 

5922 return None 

5923 

5924 kw["replace"] = replace 

5925 

5926 # copy everything else. for table-ish things like correlate, 

5927 # correlate_except, setup_joins, these clone normally. For 

5928 # column-expression oriented things like raw_columns, where_criteria, 

5929 # order by, we get this from the new froms. 

5930 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

5931 

5932 self._reset_memoizations() 

5933 

5934 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

5935 return itertools.chain( 

5936 super().get_children( 

5937 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

5938 **kw, 

5939 ), 

5940 self._iterate_from_elements(), 

5941 ) 

5942 

5943 @_generative 

5944 def add_columns( 

5945 self, *entities: _ColumnsClauseArgument[Any] 

5946 ) -> Select[Unpack[TupleAny]]: 

5947 r"""Return a new :func:`_expression.select` construct with 

5948 the given entities appended to its columns clause. 

5949 

5950 E.g.:: 

5951 

5952 my_select = my_select.add_columns(table.c.new_column) 

5953 

5954 The original expressions in the columns clause remain in place. 

5955 To replace the original expressions with new ones, see the method 

5956 :meth:`_expression.Select.with_only_columns`. 

5957 

5958 :param \*entities: column, table, or other entity expressions to be 

5959 added to the columns clause 

5960 

5961 .. seealso:: 

5962 

5963 :meth:`_expression.Select.with_only_columns` - replaces existing 

5964 expressions rather than appending. 

5965 

5966 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

5967 example 

5968 

5969 """ 

5970 self._reset_memoizations() 

5971 

5972 self._raw_columns = self._raw_columns + [ 

5973 coercions.expect( 

5974 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

5975 ) 

5976 for column in entities 

5977 ] 

5978 return self 

5979 

5980 def _set_entities( 

5981 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

5982 ) -> None: 

5983 self._raw_columns = [ 

5984 coercions.expect( 

5985 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5986 ) 

5987 for ent in util.to_list(entities) 

5988 ] 

5989 

5990 @util.deprecated( 

5991 "1.4", 

5992 "The :meth:`_expression.Select.column` method is deprecated and will " 

5993 "be removed in a future release. Please use " 

5994 ":meth:`_expression.Select.add_columns`", 

5995 ) 

5996 def column( 

5997 self, column: _ColumnsClauseArgument[Any] 

5998 ) -> Select[Unpack[TupleAny]]: 

5999 """Return a new :func:`_expression.select` construct with 

6000 the given column expression added to its columns clause. 

6001 

6002 E.g.:: 

6003 

6004 my_select = my_select.column(table.c.new_column) 

6005 

6006 See the documentation for 

6007 :meth:`_expression.Select.with_only_columns` 

6008 for guidelines on adding /replacing the columns of a 

6009 :class:`_expression.Select` object. 

6010 

6011 """ 

6012 return self.add_columns(column) 

6013 

6014 @util.preload_module("sqlalchemy.sql.util") 

6015 def reduce_columns( 

6016 self, only_synonyms: bool = True 

6017 ) -> Select[Unpack[TupleAny]]: 

6018 """Return a new :func:`_expression.select` construct with redundantly 

6019 named, equivalently-valued columns removed from the columns clause. 

6020 

6021 "Redundant" here means two columns where one refers to the 

6022 other either based on foreign key, or via a simple equality 

6023 comparison in the WHERE clause of the statement. The primary purpose 

6024 of this method is to automatically construct a select statement 

6025 with all uniquely-named columns, without the need to use 

6026 table-qualified labels as 

6027 :meth:`_expression.Select.set_label_style` 

6028 does. 

6029 

6030 When columns are omitted based on foreign key, the referred-to 

6031 column is the one that's kept. When columns are omitted based on 

6032 WHERE equivalence, the first column in the columns clause is the 

6033 one that's kept. 

6034 

6035 :param only_synonyms: when True, limit the removal of columns 

6036 to those which have the same name as the equivalent. Otherwise, 

6037 all columns that are equivalent to another are removed. 

6038 

6039 """ 

6040 woc: Select[Unpack[TupleAny]] 

6041 woc = self.with_only_columns( 

6042 *util.preloaded.sql_util.reduce_columns( 

6043 self._all_selected_columns, 

6044 only_synonyms=only_synonyms, 

6045 *(self._where_criteria + self._from_obj), 

6046 ) 

6047 ) 

6048 return woc 

6049 

6050 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6051 

6052 # code within this block is **programmatically, 

6053 # statically generated** by tools/generate_tuple_map_overloads.py 

6054 

6055 @overload 

6056 def with_only_columns( 

6057 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6058 ) -> Select[_T0]: ... 

6059 

6060 @overload 

6061 def with_only_columns( 

6062 self, 

6063 __ent0: _TCCA[_T0], 

6064 __ent1: _TCCA[_T1], 

6065 /, 

6066 *, 

6067 maintain_column_froms: bool = ..., 

6068 ) -> Select[_T0, _T1]: ... 

6069 

6070 @overload 

6071 def with_only_columns( 

6072 self, 

6073 __ent0: _TCCA[_T0], 

6074 __ent1: _TCCA[_T1], 

6075 __ent2: _TCCA[_T2], 

6076 /, 

6077 *, 

6078 maintain_column_froms: bool = ..., 

6079 ) -> Select[_T0, _T1, _T2]: ... 

6080 

6081 @overload 

6082 def with_only_columns( 

6083 self, 

6084 __ent0: _TCCA[_T0], 

6085 __ent1: _TCCA[_T1], 

6086 __ent2: _TCCA[_T2], 

6087 __ent3: _TCCA[_T3], 

6088 /, 

6089 *, 

6090 maintain_column_froms: bool = ..., 

6091 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6092 

6093 @overload 

6094 def with_only_columns( 

6095 self, 

6096 __ent0: _TCCA[_T0], 

6097 __ent1: _TCCA[_T1], 

6098 __ent2: _TCCA[_T2], 

6099 __ent3: _TCCA[_T3], 

6100 __ent4: _TCCA[_T4], 

6101 /, 

6102 *, 

6103 maintain_column_froms: bool = ..., 

6104 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6105 

6106 @overload 

6107 def with_only_columns( 

6108 self, 

6109 __ent0: _TCCA[_T0], 

6110 __ent1: _TCCA[_T1], 

6111 __ent2: _TCCA[_T2], 

6112 __ent3: _TCCA[_T3], 

6113 __ent4: _TCCA[_T4], 

6114 __ent5: _TCCA[_T5], 

6115 /, 

6116 *, 

6117 maintain_column_froms: bool = ..., 

6118 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6119 

6120 @overload 

6121 def with_only_columns( 

6122 self, 

6123 __ent0: _TCCA[_T0], 

6124 __ent1: _TCCA[_T1], 

6125 __ent2: _TCCA[_T2], 

6126 __ent3: _TCCA[_T3], 

6127 __ent4: _TCCA[_T4], 

6128 __ent5: _TCCA[_T5], 

6129 __ent6: _TCCA[_T6], 

6130 /, 

6131 *, 

6132 maintain_column_froms: bool = ..., 

6133 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

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 __ent7: _TCCA[_T7], 

6146 /, 

6147 *entities: _ColumnsClauseArgument[Any], 

6148 maintain_column_froms: bool = ..., 

6149 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6150 

6151 # END OVERLOADED FUNCTIONS self.with_only_columns 

6152 

6153 @overload 

6154 def with_only_columns( 

6155 self, 

6156 *entities: _ColumnsClauseArgument[Any], 

6157 maintain_column_froms: bool = False, 

6158 **__kw: Any, 

6159 ) -> Select[Unpack[TupleAny]]: ... 

6160 

6161 @_generative 

6162 def with_only_columns( 

6163 self, 

6164 *entities: _ColumnsClauseArgument[Any], 

6165 maintain_column_froms: bool = False, 

6166 **__kw: Any, 

6167 ) -> Select[Unpack[TupleAny]]: 

6168 r"""Return a new :func:`_expression.select` construct with its columns 

6169 clause replaced with the given entities. 

6170 

6171 By default, this method is exactly equivalent to as if the original 

6172 :func:`_expression.select` had been called with the given entities. 

6173 E.g. a statement:: 

6174 

6175 s = select(table1.c.a, table1.c.b) 

6176 s = s.with_only_columns(table1.c.b) 

6177 

6178 should be exactly equivalent to:: 

6179 

6180 s = select(table1.c.b) 

6181 

6182 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6183 will also dynamically alter the FROM clause of the 

6184 statement if it is not explicitly stated. 

6185 To maintain the existing set of FROMs including those implied by the 

6186 current columns clause, add the 

6187 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6188 parameter:: 

6189 

6190 s = select(table1.c.a, table2.c.b) 

6191 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6192 

6193 The above parameter performs a transfer of the effective FROMs 

6194 in the columns collection to the :meth:`_sql.Select.select_from` 

6195 method, as though the following were invoked:: 

6196 

6197 s = select(table1.c.a, table2.c.b) 

6198 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6199 

6200 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6201 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6202 collection and performs an operation equivalent to the following:: 

6203 

6204 s = select(table1.c.a, table2.c.b) 

6205 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6206 

6207 :param \*entities: column expressions to be used. 

6208 

6209 :param maintain_column_froms: boolean parameter that will ensure the 

6210 FROM list implied from the current columns clause will be transferred 

6211 to the :meth:`_sql.Select.select_from` method first. 

6212 

6213 .. versionadded:: 1.4.23 

6214 

6215 """ # noqa: E501 

6216 

6217 if __kw: 

6218 raise _no_kw() 

6219 

6220 # memoizations should be cleared here as of 

6221 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6222 # is the case for now. 

6223 self._assert_no_memoizations() 

6224 

6225 if maintain_column_froms: 

6226 self.select_from.non_generative( # type: ignore 

6227 self, *self.columns_clause_froms 

6228 ) 

6229 

6230 # then memoize the FROMs etc. 

6231 _MemoizedSelectEntities._generate_for_statement(self) 

6232 

6233 self._raw_columns = [ 

6234 coercions.expect(roles.ColumnsClauseRole, c) 

6235 for c in coercions._expression_collection_was_a_list( 

6236 "entities", "Select.with_only_columns", entities 

6237 ) 

6238 ] 

6239 return self 

6240 

6241 @property 

6242 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6243 """Return the completed WHERE clause for this 

6244 :class:`_expression.Select` statement. 

6245 

6246 This assembles the current collection of WHERE criteria 

6247 into a single :class:`_expression.BooleanClauseList` construct. 

6248 

6249 

6250 .. versionadded:: 1.4 

6251 

6252 """ 

6253 

6254 return BooleanClauseList._construct_for_whereclause( 

6255 self._where_criteria 

6256 ) 

6257 

6258 _whereclause = whereclause 

6259 

6260 @_generative 

6261 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6262 """Return a new :func:`_expression.select` construct with 

6263 the given expression added to 

6264 its WHERE clause, joined to the existing clause via AND, if any. 

6265 

6266 """ 

6267 

6268 assert isinstance(self._where_criteria, tuple) 

6269 

6270 for criterion in whereclause: 

6271 where_criteria: ColumnElement[Any] = coercions.expect( 

6272 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6273 ) 

6274 self._where_criteria += (where_criteria,) 

6275 return self 

6276 

6277 @_generative 

6278 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6279 """Return a new :func:`_expression.select` construct with 

6280 the given expression added to 

6281 its HAVING clause, joined to the existing clause via AND, if any. 

6282 

6283 """ 

6284 

6285 for criterion in having: 

6286 having_criteria = coercions.expect( 

6287 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6288 ) 

6289 self._having_criteria += (having_criteria,) 

6290 return self 

6291 

6292 @_generative 

6293 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6294 r"""Return a new :func:`_expression.select` construct which 

6295 will apply DISTINCT to the SELECT statement overall. 

6296 

6297 E.g.:: 

6298 

6299 from sqlalchemy import select 

6300 

6301 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6302 

6303 The above would produce an statement resembling: 

6304 

6305 .. sourcecode:: sql 

6306 

6307 SELECT DISTINCT user.id, user.name FROM user 

6308 

6309 The method also historically accepted an ``*expr`` parameter which 

6310 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6311 This is now replaced using the :func:`_postgresql.distinct_on` 

6312 extension:: 

6313 

6314 from sqlalchemy import select 

6315 from sqlalchemy.dialects.postgresql import distinct_on 

6316 

6317 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6318 

6319 Using this parameter on other backends which don't support this 

6320 syntax will raise an error. 

6321 

6322 :param \*expr: optional column expressions. When present, 

6323 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6324 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6325 will be raised on other backends. 

6326 

6327 .. deprecated:: 2.1 Passing expressions to 

6328 :meth:`_sql.Select.distinct` is deprecated, use 

6329 :func:`_postgresql.distinct_on` instead. 

6330 

6331 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6332 and will raise :class:`_exc.CompileError` in a future version. 

6333 

6334 .. seealso:: 

6335 

6336 :func:`_postgresql.distinct_on` 

6337 

6338 :meth:`_sql.HasSyntaxExtensions.ext` 

6339 """ 

6340 self._distinct = True 

6341 if expr: 

6342 warn_deprecated( 

6343 "Passing expression to ``distinct`` to generate a " 

6344 "DISTINCT ON clause is deprecated. Use instead the " 

6345 "``postgresql.distinct_on`` function as an extension.", 

6346 "2.1", 

6347 ) 

6348 self._distinct_on = self._distinct_on + tuple( 

6349 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6350 for e in expr 

6351 ) 

6352 return self 

6353 

6354 @_generative 

6355 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6356 r"""Return a new :func:`_expression.select` construct with the 

6357 given FROM expression(s) 

6358 merged into its list of FROM objects. 

6359 

6360 E.g.:: 

6361 

6362 table1 = table("t1", column("a")) 

6363 table2 = table("t2", column("b")) 

6364 s = select(table1.c.a).select_from( 

6365 table1.join(table2, table1.c.a == table2.c.b) 

6366 ) 

6367 

6368 The "from" list is a unique set on the identity of each element, 

6369 so adding an already present :class:`_schema.Table` 

6370 or other selectable 

6371 will have no effect. Passing a :class:`_expression.Join` that refers 

6372 to an already present :class:`_schema.Table` 

6373 or other selectable will have 

6374 the effect of concealing the presence of that selectable as 

6375 an individual element in the rendered FROM list, instead 

6376 rendering it into a JOIN clause. 

6377 

6378 While the typical purpose of :meth:`_expression.Select.select_from` 

6379 is to 

6380 replace the default, derived FROM clause with a join, it can 

6381 also be called with individual table elements, multiple times 

6382 if desired, in the case that the FROM clause cannot be fully 

6383 derived from the columns clause:: 

6384 

6385 select(func.count("*")).select_from(table1) 

6386 

6387 """ 

6388 

6389 self._from_obj += tuple( 

6390 coercions.expect( 

6391 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6392 ) 

6393 for fromclause in froms 

6394 ) 

6395 return self 

6396 

6397 @_generative 

6398 def correlate( 

6399 self, 

6400 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6401 ) -> Self: 

6402 r"""Return a new :class:`_expression.Select` 

6403 which will correlate the given FROM 

6404 clauses to that of an enclosing :class:`_expression.Select`. 

6405 

6406 Calling this method turns off the :class:`_expression.Select` object's 

6407 default behavior of "auto-correlation". Normally, FROM elements 

6408 which appear in a :class:`_expression.Select` 

6409 that encloses this one via 

6410 its :term:`WHERE clause`, ORDER BY, HAVING or 

6411 :term:`columns clause` will be omitted from this 

6412 :class:`_expression.Select` 

6413 object's :term:`FROM clause`. 

6414 Setting an explicit correlation collection using the 

6415 :meth:`_expression.Select.correlate` 

6416 method provides a fixed list of FROM objects 

6417 that can potentially take place in this process. 

6418 

6419 When :meth:`_expression.Select.correlate` 

6420 is used to apply specific FROM clauses 

6421 for correlation, the FROM elements become candidates for 

6422 correlation regardless of how deeply nested this 

6423 :class:`_expression.Select` 

6424 object is, relative to an enclosing :class:`_expression.Select` 

6425 which refers to 

6426 the same FROM object. This is in contrast to the behavior of 

6427 "auto-correlation" which only correlates to an immediate enclosing 

6428 :class:`_expression.Select`. 

6429 Multi-level correlation ensures that the link 

6430 between enclosed and enclosing :class:`_expression.Select` 

6431 is always via 

6432 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6433 correlation to take place. 

6434 

6435 If ``None`` is passed, the :class:`_expression.Select` 

6436 object will correlate 

6437 none of its FROM entries, and all will render unconditionally 

6438 in the local FROM clause. 

6439 

6440 :param \*fromclauses: one or more :class:`.FromClause` or other 

6441 FROM-compatible construct such as an ORM mapped entity to become part 

6442 of the correlate collection; alternatively pass a single value 

6443 ``None`` to remove all existing correlations. 

6444 

6445 .. seealso:: 

6446 

6447 :meth:`_expression.Select.correlate_except` 

6448 

6449 :ref:`tutorial_scalar_subquery` 

6450 

6451 """ 

6452 

6453 # tests failing when we try to change how these 

6454 # arguments are passed 

6455 

6456 self._auto_correlate = False 

6457 if not fromclauses or fromclauses[0] in {None, False}: 

6458 if len(fromclauses) > 1: 

6459 raise exc.ArgumentError( 

6460 "additional FROM objects not accepted when " 

6461 "passing None/False to correlate()" 

6462 ) 

6463 self._correlate = () 

6464 else: 

6465 self._correlate = self._correlate + tuple( 

6466 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6467 ) 

6468 return self 

6469 

6470 @_generative 

6471 def correlate_except( 

6472 self, 

6473 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6474 ) -> Self: 

6475 r"""Return a new :class:`_expression.Select` 

6476 which will omit the given FROM 

6477 clauses from the auto-correlation process. 

6478 

6479 Calling :meth:`_expression.Select.correlate_except` turns off the 

6480 :class:`_expression.Select` object's default behavior of 

6481 "auto-correlation" for the given FROM elements. An element 

6482 specified here will unconditionally appear in the FROM list, while 

6483 all other FROM elements remain subject to normal auto-correlation 

6484 behaviors. 

6485 

6486 If ``None`` is passed, or no arguments are passed, 

6487 the :class:`_expression.Select` object will correlate all of its 

6488 FROM entries. 

6489 

6490 :param \*fromclauses: a list of one or more 

6491 :class:`_expression.FromClause` 

6492 constructs, or other compatible constructs (i.e. ORM-mapped 

6493 classes) to become part of the correlate-exception collection. 

6494 

6495 .. seealso:: 

6496 

6497 :meth:`_expression.Select.correlate` 

6498 

6499 :ref:`tutorial_scalar_subquery` 

6500 

6501 """ 

6502 

6503 self._auto_correlate = False 

6504 if not fromclauses or fromclauses[0] in {None, False}: 

6505 if len(fromclauses) > 1: 

6506 raise exc.ArgumentError( 

6507 "additional FROM objects not accepted when " 

6508 "passing None/False to correlate_except()" 

6509 ) 

6510 self._correlate_except = () 

6511 else: 

6512 self._correlate_except = (self._correlate_except or ()) + tuple( 

6513 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6514 ) 

6515 

6516 return self 

6517 

6518 @HasMemoized_ro_memoized_attribute 

6519 def selected_columns( 

6520 self, 

6521 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6522 """A :class:`_expression.ColumnCollection` 

6523 representing the columns that 

6524 this SELECT statement or similar construct returns in its result set, 

6525 not including :class:`_sql.TextClause` constructs. 

6526 

6527 This collection differs from the :attr:`_expression.FromClause.columns` 

6528 collection of a :class:`_expression.FromClause` in that the columns 

6529 within this collection cannot be directly nested inside another SELECT 

6530 statement; a subquery must be applied first which provides for the 

6531 necessary parenthesization required by SQL. 

6532 

6533 For a :func:`_expression.select` construct, the collection here is 

6534 exactly what would be rendered inside the "SELECT" statement, and the 

6535 :class:`_expression.ColumnElement` objects are directly present as they 

6536 were given, e.g.:: 

6537 

6538 col1 = column("q", Integer) 

6539 col2 = column("p", Integer) 

6540 stmt = select(col1, col2) 

6541 

6542 Above, ``stmt.selected_columns`` would be a collection that contains 

6543 the ``col1`` and ``col2`` objects directly. For a statement that is 

6544 against a :class:`_schema.Table` or other 

6545 :class:`_expression.FromClause`, the collection will use the 

6546 :class:`_expression.ColumnElement` objects that are in the 

6547 :attr:`_expression.FromClause.c` collection of the from element. 

6548 

6549 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6550 to allow the existing columns to be referenced when adding additional 

6551 criteria, e.g.:: 

6552 

6553 def filter_on_id(my_select, id): 

6554 return my_select.where(my_select.selected_columns["id"] == id) 

6555 

6556 

6557 stmt = select(MyModel) 

6558 

6559 # adds "WHERE id=:param" to the statement 

6560 stmt = filter_on_id(stmt, 42) 

6561 

6562 .. note:: 

6563 

6564 The :attr:`_sql.Select.selected_columns` collection does not 

6565 include expressions established in the columns clause using the 

6566 :func:`_sql.text` construct; these are silently omitted from the 

6567 collection. To use plain textual column expressions inside of a 

6568 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6569 construct. 

6570 

6571 

6572 .. versionadded:: 1.4 

6573 

6574 """ 

6575 

6576 # compare to SelectState._generate_columns_plus_names, which 

6577 # generates the actual names used in the SELECT string. that 

6578 # method is more complex because it also renders columns that are 

6579 # fully ambiguous, e.g. same column more than once. 

6580 conv = cast( 

6581 "Callable[[Any], str]", 

6582 SelectState._column_naming_convention(self._label_style), 

6583 ) 

6584 

6585 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6586 [ 

6587 (conv(c), c) 

6588 for c in self._all_selected_columns 

6589 if is_column_element(c) 

6590 ] 

6591 ) 

6592 return cc.as_readonly() 

6593 

6594 @HasMemoized_ro_memoized_attribute 

6595 def _all_selected_columns(self) -> _SelectIterable: 

6596 meth = SelectState.get_plugin_class(self).all_selected_columns 

6597 return list(meth(self)) 

6598 

6599 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6600 if self._label_style is LABEL_STYLE_NONE: 

6601 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6602 return self 

6603 

6604 def _generate_fromclause_column_proxies( 

6605 self, 

6606 subquery: FromClause, 

6607 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

6608 primary_key: ColumnSet, 

6609 foreign_keys: Set[KeyedColumnElement[Any]], 

6610 *, 

6611 proxy_compound_columns: Optional[ 

6612 Iterable[Sequence[ColumnElement[Any]]] 

6613 ] = None, 

6614 ) -> None: 

6615 """Generate column proxies to place in the exported ``.c`` 

6616 collection of a subquery.""" 

6617 

6618 if proxy_compound_columns: 

6619 extra_col_iterator = proxy_compound_columns 

6620 prox = [ 

6621 c._make_proxy( 

6622 subquery, 

6623 key=proxy_key, 

6624 name=required_label_name, 

6625 name_is_truncatable=True, 

6626 compound_select_cols=extra_cols, 

6627 primary_key=primary_key, 

6628 foreign_keys=foreign_keys, 

6629 ) 

6630 for ( 

6631 ( 

6632 required_label_name, 

6633 proxy_key, 

6634 fallback_label_name, 

6635 c, 

6636 repeated, 

6637 ), 

6638 extra_cols, 

6639 ) in ( 

6640 zip( 

6641 self._generate_columns_plus_names(False), 

6642 extra_col_iterator, 

6643 ) 

6644 ) 

6645 if is_column_element(c) 

6646 ] 

6647 else: 

6648 prox = [ 

6649 c._make_proxy( 

6650 subquery, 

6651 key=proxy_key, 

6652 name=required_label_name, 

6653 name_is_truncatable=True, 

6654 primary_key=primary_key, 

6655 foreign_keys=foreign_keys, 

6656 ) 

6657 for ( 

6658 required_label_name, 

6659 proxy_key, 

6660 fallback_label_name, 

6661 c, 

6662 repeated, 

6663 ) in (self._generate_columns_plus_names(False)) 

6664 if is_column_element(c) 

6665 ] 

6666 

6667 columns._populate_separate_keys(prox) 

6668 

6669 def _needs_parens_for_grouping(self) -> bool: 

6670 return self._has_row_limiting_clause or bool( 

6671 self._order_by_clause.clauses 

6672 ) 

6673 

6674 def self_group( 

6675 self, against: Optional[OperatorType] = None 

6676 ) -> Union[SelectStatementGrouping[Self], Self]: 

6677 """Return a 'grouping' construct as per the 

6678 :class:`_expression.ClauseElement` specification. 

6679 

6680 This produces an element that can be embedded in an expression. Note 

6681 that this method is called automatically as needed when constructing 

6682 expressions and should not require explicit use. 

6683 

6684 """ 

6685 if ( 

6686 isinstance(against, CompoundSelect) 

6687 and not self._needs_parens_for_grouping() 

6688 ): 

6689 return self 

6690 else: 

6691 return SelectStatementGrouping(self) 

6692 

6693 def union( 

6694 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6695 ) -> CompoundSelect[Unpack[_Ts]]: 

6696 r"""Return a SQL ``UNION`` of this select() construct against 

6697 the given selectables provided as positional arguments. 

6698 

6699 :param \*other: one or more elements with which to create a 

6700 UNION. 

6701 

6702 .. versionchanged:: 1.4.28 

6703 

6704 multiple elements are now accepted. 

6705 

6706 :param \**kwargs: keyword arguments are forwarded to the constructor 

6707 for the newly created :class:`_sql.CompoundSelect` object. 

6708 

6709 """ 

6710 return CompoundSelect._create_union(self, *other) 

6711 

6712 def union_all( 

6713 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6714 ) -> CompoundSelect[Unpack[_Ts]]: 

6715 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6716 the given selectables provided as positional arguments. 

6717 

6718 :param \*other: one or more elements with which to create a 

6719 UNION. 

6720 

6721 .. versionchanged:: 1.4.28 

6722 

6723 multiple elements are now accepted. 

6724 

6725 :param \**kwargs: keyword arguments are forwarded to the constructor 

6726 for the newly created :class:`_sql.CompoundSelect` object. 

6727 

6728 """ 

6729 return CompoundSelect._create_union_all(self, *other) 

6730 

6731 def except_( 

6732 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6733 ) -> CompoundSelect[Unpack[_Ts]]: 

6734 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6735 the given selectable provided as positional arguments. 

6736 

6737 :param \*other: one or more elements with which to create a 

6738 UNION. 

6739 

6740 .. versionchanged:: 1.4.28 

6741 

6742 multiple elements are now accepted. 

6743 

6744 """ 

6745 return CompoundSelect._create_except(self, *other) 

6746 

6747 def except_all( 

6748 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6749 ) -> CompoundSelect[Unpack[_Ts]]: 

6750 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6751 the given selectables provided as positional arguments. 

6752 

6753 :param \*other: one or more elements with which to create a 

6754 UNION. 

6755 

6756 .. versionchanged:: 1.4.28 

6757 

6758 multiple elements are now accepted. 

6759 

6760 """ 

6761 return CompoundSelect._create_except_all(self, *other) 

6762 

6763 def intersect( 

6764 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6765 ) -> CompoundSelect[Unpack[_Ts]]: 

6766 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6767 the given selectables provided as positional arguments. 

6768 

6769 :param \*other: one or more elements with which to create a 

6770 UNION. 

6771 

6772 .. versionchanged:: 1.4.28 

6773 

6774 multiple elements are now accepted. 

6775 

6776 :param \**kwargs: keyword arguments are forwarded to the constructor 

6777 for the newly created :class:`_sql.CompoundSelect` object. 

6778 

6779 """ 

6780 return CompoundSelect._create_intersect(self, *other) 

6781 

6782 def intersect_all( 

6783 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6784 ) -> CompoundSelect[Unpack[_Ts]]: 

6785 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6786 against the given selectables provided as positional arguments. 

6787 

6788 :param \*other: one or more elements with which to create a 

6789 UNION. 

6790 

6791 .. versionchanged:: 1.4.28 

6792 

6793 multiple elements are now accepted. 

6794 

6795 :param \**kwargs: keyword arguments are forwarded to the constructor 

6796 for the newly created :class:`_sql.CompoundSelect` object. 

6797 

6798 """ 

6799 return CompoundSelect._create_intersect_all(self, *other) 

6800 

6801 

6802class ScalarSelect( 

6803 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6804): 

6805 """Represent a scalar subquery. 

6806 

6807 

6808 A :class:`_sql.ScalarSelect` is created by invoking the 

6809 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6810 then participates in other SQL expressions as a SQL column expression 

6811 within the :class:`_sql.ColumnElement` hierarchy. 

6812 

6813 .. seealso:: 

6814 

6815 :meth:`_sql.SelectBase.scalar_subquery` 

6816 

6817 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6818 

6819 """ 

6820 

6821 _traverse_internals: _TraverseInternalsType = [ 

6822 ("element", InternalTraversal.dp_clauseelement), 

6823 ("type", InternalTraversal.dp_type), 

6824 ] 

6825 

6826 _from_objects: List[FromClause] = [] 

6827 _is_from_container = True 

6828 if not TYPE_CHECKING: 

6829 _is_implicitly_boolean = False 

6830 inherit_cache = True 

6831 

6832 element: SelectBase 

6833 

6834 def __init__(self, element: SelectBase) -> None: 

6835 self.element = element 

6836 self.type = element._scalar_type() 

6837 self._propagate_attrs = element._propagate_attrs 

6838 

6839 def __getattr__(self, attr: str) -> Any: 

6840 return getattr(self.element, attr) 

6841 

6842 def __getstate__(self) -> Dict[str, Any]: 

6843 return {"element": self.element, "type": self.type} 

6844 

6845 def __setstate__(self, state: Dict[str, Any]) -> None: 

6846 self.element = state["element"] 

6847 self.type = state["type"] 

6848 

6849 @property 

6850 def columns(self) -> NoReturn: 

6851 raise exc.InvalidRequestError( 

6852 "Scalar Select expression has no " 

6853 "columns; use this object directly " 

6854 "within a column-level expression." 

6855 ) 

6856 

6857 c = columns 

6858 

6859 @_generative 

6860 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6861 """Apply a WHERE clause to the SELECT statement referred to 

6862 by this :class:`_expression.ScalarSelect`. 

6863 

6864 """ 

6865 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6866 crit 

6867 ) 

6868 return self 

6869 

6870 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6871 return self 

6872 

6873 def _ungroup(self) -> Self: 

6874 return self 

6875 

6876 @_generative 

6877 def correlate( 

6878 self, 

6879 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6880 ) -> Self: 

6881 r"""Return a new :class:`_expression.ScalarSelect` 

6882 which will correlate the given FROM 

6883 clauses to that of an enclosing :class:`_expression.Select`. 

6884 

6885 This method is mirrored from the :meth:`_sql.Select.correlate` method 

6886 of the underlying :class:`_sql.Select`. The method applies the 

6887 :meth:_sql.Select.correlate` method, then returns a new 

6888 :class:`_sql.ScalarSelect` against that statement. 

6889 

6890 .. versionadded:: 1.4 Previously, the 

6891 :meth:`_sql.ScalarSelect.correlate` 

6892 method was only available from :class:`_sql.Select`. 

6893 

6894 :param \*fromclauses: a list of one or more 

6895 :class:`_expression.FromClause` 

6896 constructs, or other compatible constructs (i.e. ORM-mapped 

6897 classes) to become part of the correlate collection. 

6898 

6899 .. seealso:: 

6900 

6901 :meth:`_expression.ScalarSelect.correlate_except` 

6902 

6903 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6904 

6905 

6906 """ 

6907 self.element = cast( 

6908 "Select[Unpack[TupleAny]]", self.element 

6909 ).correlate(*fromclauses) 

6910 return self 

6911 

6912 @_generative 

6913 def correlate_except( 

6914 self, 

6915 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6916 ) -> Self: 

6917 r"""Return a new :class:`_expression.ScalarSelect` 

6918 which will omit the given FROM 

6919 clauses from the auto-correlation process. 

6920 

6921 This method is mirrored from the 

6922 :meth:`_sql.Select.correlate_except` method of the underlying 

6923 :class:`_sql.Select`. The method applies the 

6924 :meth:_sql.Select.correlate_except` method, then returns a new 

6925 :class:`_sql.ScalarSelect` against that statement. 

6926 

6927 .. versionadded:: 1.4 Previously, the 

6928 :meth:`_sql.ScalarSelect.correlate_except` 

6929 method was only available from :class:`_sql.Select`. 

6930 

6931 :param \*fromclauses: a list of one or more 

6932 :class:`_expression.FromClause` 

6933 constructs, or other compatible constructs (i.e. ORM-mapped 

6934 classes) to become part of the correlate-exception collection. 

6935 

6936 .. seealso:: 

6937 

6938 :meth:`_expression.ScalarSelect.correlate` 

6939 

6940 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6941 

6942 

6943 """ 

6944 

6945 self.element = cast( 

6946 "Select[Unpack[TupleAny]]", self.element 

6947 ).correlate_except(*fromclauses) 

6948 return self 

6949 

6950 

6951class Exists(UnaryExpression[bool]): 

6952 """Represent an ``EXISTS`` clause. 

6953 

6954 See :func:`_sql.exists` for a description of usage. 

6955 

6956 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

6957 instance by calling :meth:`_sql.SelectBase.exists`. 

6958 

6959 """ 

6960 

6961 inherit_cache = True 

6962 

6963 def __init__( 

6964 self, 

6965 __argument: Optional[ 

6966 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

6967 ] = None, 

6968 /, 

6969 ): 

6970 s: ScalarSelect[Any] 

6971 

6972 # TODO: this seems like we should be using coercions for this 

6973 if __argument is None: 

6974 s = Select(literal_column("*")).scalar_subquery() 

6975 elif isinstance(__argument, SelectBase): 

6976 s = __argument.scalar_subquery() 

6977 s._propagate_attrs = __argument._propagate_attrs 

6978 elif isinstance(__argument, ScalarSelect): 

6979 s = __argument 

6980 else: 

6981 s = Select(__argument).scalar_subquery() 

6982 

6983 UnaryExpression.__init__( 

6984 self, 

6985 s, 

6986 operator=operators.exists, 

6987 type_=type_api.BOOLEANTYPE, 

6988 ) 

6989 

6990 @util.ro_non_memoized_property 

6991 def _from_objects(self) -> List[FromClause]: 

6992 return [] 

6993 

6994 def _regroup( 

6995 self, 

6996 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

6997 ) -> ScalarSelect[Any]: 

6998 

6999 assert isinstance(self.element, ScalarSelect) 

7000 element = self.element.element 

7001 if not isinstance(element, Select): 

7002 raise exc.InvalidRequestError( 

7003 "Can only apply this operation to a plain SELECT construct" 

7004 ) 

7005 new_element = fn(element) 

7006 

7007 return_value = new_element.scalar_subquery() 

7008 return return_value 

7009 

7010 def select(self) -> Select[bool]: 

7011 r"""Return a SELECT of this :class:`_expression.Exists`. 

7012 

7013 e.g.:: 

7014 

7015 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7016 

7017 This will produce a statement resembling: 

7018 

7019 .. sourcecode:: sql 

7020 

7021 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7022 

7023 .. seealso:: 

7024 

7025 :func:`_expression.select` - general purpose 

7026 method which allows for arbitrary column lists. 

7027 

7028 """ # noqa 

7029 

7030 return Select(self) 

7031 

7032 def correlate( 

7033 self, 

7034 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7035 ) -> Self: 

7036 """Apply correlation to the subquery noted by this 

7037 :class:`_sql.Exists`. 

7038 

7039 .. seealso:: 

7040 

7041 :meth:`_sql.ScalarSelect.correlate` 

7042 

7043 """ 

7044 e = self._clone() 

7045 e.element = self._regroup( 

7046 lambda element: element.correlate(*fromclauses) 

7047 ) 

7048 return e 

7049 

7050 def correlate_except( 

7051 self, 

7052 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7053 ) -> Self: 

7054 """Apply correlation to the subquery noted by this 

7055 :class:`_sql.Exists`. 

7056 

7057 .. seealso:: 

7058 

7059 :meth:`_sql.ScalarSelect.correlate_except` 

7060 

7061 """ 

7062 e = self._clone() 

7063 e.element = self._regroup( 

7064 lambda element: element.correlate_except(*fromclauses) 

7065 ) 

7066 return e 

7067 

7068 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7069 """Return a new :class:`_expression.Exists` construct, 

7070 applying the given 

7071 expression to the :meth:`_expression.Select.select_from` 

7072 method of the select 

7073 statement contained. 

7074 

7075 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7076 statement first, including the desired WHERE clause, then use the 

7077 :meth:`_sql.SelectBase.exists` method to produce an 

7078 :class:`_sql.Exists` object at once. 

7079 

7080 """ 

7081 e = self._clone() 

7082 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7083 return e 

7084 

7085 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7086 """Return a new :func:`_expression.exists` construct with the 

7087 given expression added to 

7088 its WHERE clause, joined to the existing clause via AND, if any. 

7089 

7090 

7091 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7092 statement first, including the desired WHERE clause, then use the 

7093 :meth:`_sql.SelectBase.exists` method to produce an 

7094 :class:`_sql.Exists` object at once. 

7095 

7096 """ 

7097 e = self._clone() 

7098 e.element = self._regroup(lambda element: element.where(*clause)) 

7099 return e 

7100 

7101 

7102class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7103 """Wrap a :class:`_expression.TextClause` construct within a 

7104 :class:`_expression.SelectBase` 

7105 interface. 

7106 

7107 This allows the :class:`_expression.TextClause` object to gain a 

7108 ``.c`` collection 

7109 and other FROM-like capabilities such as 

7110 :meth:`_expression.FromClause.alias`, 

7111 :meth:`_expression.SelectBase.cte`, etc. 

7112 

7113 The :class:`_expression.TextualSelect` construct is produced via the 

7114 :meth:`_expression.TextClause.columns` 

7115 method - see that method for details. 

7116 

7117 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7118 class was renamed 

7119 from ``TextAsFrom``, to more correctly suit its role as a 

7120 SELECT-oriented object and not a FROM clause. 

7121 

7122 .. seealso:: 

7123 

7124 :func:`_expression.text` 

7125 

7126 :meth:`_expression.TextClause.columns` - primary creation interface. 

7127 

7128 """ 

7129 

7130 __visit_name__ = "textual_select" 

7131 

7132 _label_style = LABEL_STYLE_NONE 

7133 

7134 _traverse_internals: _TraverseInternalsType = ( 

7135 [ 

7136 ("element", InternalTraversal.dp_clauseelement), 

7137 ("column_args", InternalTraversal.dp_clauseelement_list), 

7138 ] 

7139 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7140 + HasCTE._has_ctes_traverse_internals 

7141 ) 

7142 

7143 _is_textual = True 

7144 

7145 is_text = True 

7146 is_select = True 

7147 

7148 def __init__( 

7149 self, 

7150 text: TextClause, 

7151 columns: List[_ColumnExpressionArgument[Any]], 

7152 positional: bool = False, 

7153 ) -> None: 

7154 self._init( 

7155 text, 

7156 # convert for ORM attributes->columns, etc 

7157 [ 

7158 coercions.expect(roles.LabeledColumnExprRole, c) 

7159 for c in columns 

7160 ], 

7161 positional, 

7162 ) 

7163 

7164 def _init( 

7165 self, 

7166 text: TextClause, 

7167 columns: List[NamedColumn[Any]], 

7168 positional: bool = False, 

7169 ) -> None: 

7170 self.element = text 

7171 self.column_args = columns 

7172 self.positional = positional 

7173 

7174 @HasMemoized_ro_memoized_attribute 

7175 def selected_columns( 

7176 self, 

7177 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7178 """A :class:`_expression.ColumnCollection` 

7179 representing the columns that 

7180 this SELECT statement or similar construct returns in its result set, 

7181 not including :class:`_sql.TextClause` constructs. 

7182 

7183 This collection differs from the :attr:`_expression.FromClause.columns` 

7184 collection of a :class:`_expression.FromClause` in that the columns 

7185 within this collection cannot be directly nested inside another SELECT 

7186 statement; a subquery must be applied first which provides for the 

7187 necessary parenthesization required by SQL. 

7188 

7189 For a :class:`_expression.TextualSelect` construct, the collection 

7190 contains the :class:`_expression.ColumnElement` objects that were 

7191 passed to the constructor, typically via the 

7192 :meth:`_expression.TextClause.columns` method. 

7193 

7194 

7195 .. versionadded:: 1.4 

7196 

7197 """ 

7198 return ColumnCollection( 

7199 (c.key, c) for c in self.column_args 

7200 ).as_readonly() 

7201 

7202 @util.ro_non_memoized_property 

7203 def _all_selected_columns(self) -> _SelectIterable: 

7204 return self.column_args 

7205 

7206 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7207 return self 

7208 

7209 def _ensure_disambiguated_names(self) -> TextualSelect: 

7210 return self 

7211 

7212 @_generative 

7213 def bindparams( 

7214 self, 

7215 *binds: BindParameter[Any], 

7216 **bind_as_values: Any, 

7217 ) -> Self: 

7218 self.element = self.element.bindparams(*binds, **bind_as_values) 

7219 return self 

7220 

7221 def _generate_fromclause_column_proxies( 

7222 self, 

7223 fromclause: FromClause, 

7224 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

7225 primary_key: ColumnSet, 

7226 foreign_keys: Set[KeyedColumnElement[Any]], 

7227 *, 

7228 proxy_compound_columns: Optional[ 

7229 Iterable[Sequence[ColumnElement[Any]]] 

7230 ] = None, 

7231 ) -> None: 

7232 if TYPE_CHECKING: 

7233 assert isinstance(fromclause, Subquery) 

7234 

7235 if proxy_compound_columns: 

7236 columns._populate_separate_keys( 

7237 c._make_proxy( 

7238 fromclause, 

7239 compound_select_cols=extra_cols, 

7240 primary_key=primary_key, 

7241 foreign_keys=foreign_keys, 

7242 ) 

7243 for c, extra_cols in zip( 

7244 self.column_args, proxy_compound_columns 

7245 ) 

7246 ) 

7247 else: 

7248 columns._populate_separate_keys( 

7249 c._make_proxy( 

7250 fromclause, 

7251 primary_key=primary_key, 

7252 foreign_keys=foreign_keys, 

7253 ) 

7254 for c in self.column_args 

7255 ) 

7256 

7257 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7258 return self.column_args[0].type 

7259 

7260 

7261TextAsFrom = TextualSelect 

7262"""Backwards compatibility with the previous name""" 

7263 

7264 

7265class AnnotatedFromClause(Annotated): 

7266 def _copy_internals(self, **kw: Any) -> None: 

7267 super()._copy_internals(**kw) 

7268 if kw.get("ind_cols_on_fromclause", False): 

7269 ee = self._Annotated__element # type: ignore 

7270 

7271 self.c = ee.__class__.c.fget(self) # type: ignore 

7272 

7273 @util.ro_memoized_property 

7274 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7275 """proxy the .c collection of the underlying FromClause. 

7276 

7277 Originally implemented in 2008 as a simple load of the .c collection 

7278 when the annotated construct was created (see d3621ae961a), in modern 

7279 SQLAlchemy versions this can be expensive for statements constructed 

7280 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7281 it, which works just as well. 

7282 

7283 Two different use cases seem to require the collection either copied 

7284 from the underlying one, or unique to this AnnotatedFromClause. 

7285 

7286 See test_selectable->test_annotated_corresponding_column 

7287 

7288 """ 

7289 ee = self._Annotated__element # type: ignore 

7290 return ee.c # type: ignore