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

1793 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import Literal 

30from typing import NamedTuple 

31from typing import NoReturn 

32from typing import Optional 

33from typing import overload 

34from typing import Protocol 

35from typing import Sequence 

36from typing import Set 

37from typing import Tuple 

38from typing import Type 

39from typing import TYPE_CHECKING 

40from typing import TypeVar 

41from typing import Union 

42 

43from . import cache_key 

44from . import coercions 

45from . import operators 

46from . import roles 

47from . import traversals 

48from . import type_api 

49from . import visitors 

50from ._typing import _ColumnsClauseArgument 

51from ._typing import _no_kw 

52from ._typing import _T 

53from ._typing import _Ts 

54from ._typing import is_column_element 

55from ._typing import is_select_statement 

56from ._typing import is_subquery 

57from ._typing import is_table 

58from ._typing import is_text_clause 

59from .annotation import Annotated 

60from .annotation import SupportsCloneAnnotations 

61from .base import _clone 

62from .base import _cloned_difference 

63from .base import _cloned_intersection 

64from .base import _entity_namespace_key 

65from .base import _EntityNamespace 

66from .base import _expand_cloned 

67from .base import _from_objects 

68from .base import _generative 

69from .base import _never_select_column 

70from .base import _NoArg 

71from .base import _select_iterables 

72from .base import CacheableOptions 

73from .base import ColumnCollection 

74from .base import ColumnSet 

75from .base import CompileState 

76from .base import DedupeColumnCollection 

77from .base import DialectKWArgs 

78from .base import Executable 

79from .base import ExecutableStatement 

80from .base import Generative 

81from .base import HasCompileState 

82from .base import HasMemoized 

83from .base import HasSyntaxExtensions 

84from .base import Immutable 

85from .base import SyntaxExtension 

86from .coercions import _document_text_coercion 

87from .elements import _anonymous_label 

88from .elements import BindParameter 

89from .elements import BooleanClauseList 

90from .elements import ClauseElement 

91from .elements import ClauseList 

92from .elements import ColumnClause 

93from .elements import ColumnElement 

94from .elements import DQLDMLClauseElement 

95from .elements import GroupedElement 

96from .elements import literal_column 

97from .elements import TableValuedColumn 

98from .elements import UnaryExpression 

99from .operators import OperatorType 

100from .sqltypes import NULLTYPE 

101from .visitors import _TraverseInternalsType 

102from .visitors import InternalTraversal 

103from .visitors import prefix_anon_map 

104from .. import exc 

105from .. import util 

106from ..util import HasMemoized_ro_memoized_attribute 

107from ..util import warn_deprecated 

108from ..util.typing import Self 

109from ..util.typing import TupleAny 

110from ..util.typing import Unpack 

111 

112 

113and_ = BooleanClauseList.and_ 

114 

115 

116if TYPE_CHECKING: 

117 from ._typing import _ColumnExpressionArgument 

118 from ._typing import _ColumnExpressionOrStrLabelArgument 

119 from ._typing import _FromClauseArgument 

120 from ._typing import _JoinTargetArgument 

121 from ._typing import _LimitOffsetType 

122 from ._typing import _MAYBE_ENTITY 

123 from ._typing import _NOT_ENTITY 

124 from ._typing import _OnClauseArgument 

125 from ._typing import _SelectStatementForCompoundArgument 

126 from ._typing import _T0 

127 from ._typing import _T1 

128 from ._typing import _T2 

129 from ._typing import _T3 

130 from ._typing import _T4 

131 from ._typing import _T5 

132 from ._typing import _T6 

133 from ._typing import _T7 

134 from ._typing import _TextCoercedExpressionArgument 

135 from ._typing import _TypedColumnClauseArgument as _TCCA 

136 from ._typing import _TypeEngineArgument 

137 from .base import _AmbiguousTableNameMap 

138 from .base import ExecutableOption 

139 from .base import ReadOnlyColumnCollection 

140 from .cache_key import _CacheKeyTraversalType 

141 from .compiler import SQLCompiler 

142 from .ddl import CreateTableAs 

143 from .dml import Delete 

144 from .dml import Update 

145 from .elements import BinaryExpression 

146 from .elements import KeyedColumnElement 

147 from .elements import Label 

148 from .elements import NamedColumn 

149 from .elements import TextClause 

150 from .functions import Function 

151 from .schema import ForeignKey 

152 from .schema import ForeignKeyConstraint 

153 from .schema import MetaData 

154 from .sqltypes import TableValueType 

155 from .type_api import TypeEngine 

156 from .visitors import _CloneCallableType 

157 

158 

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

160_LabelConventionCallable = Callable[ 

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

162] 

163 

164 

165class _JoinTargetProtocol(Protocol): 

166 @util.ro_non_memoized_property 

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

168 

169 @util.ro_non_memoized_property 

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

171 

172 

173_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

175 

176_ForUpdateOfArgument = Union[ 

177 # single column, Table, ORM Entity 

178 Union[ 

179 "_ColumnExpressionArgument[Any]", 

180 "_FromClauseArgument", 

181 ], 

182 # or sequence of single column elements 

183 Sequence["_ColumnExpressionArgument[Any]"], 

184] 

185 

186 

187_SetupJoinsElement = Tuple[ 

188 _JoinTargetElement, 

189 Optional[_OnClauseElement], 

190 Optional["FromClause"], 

191 Dict[str, Any], 

192] 

193 

194 

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

196 

197 

198class _OffsetLimitParam(BindParameter[int]): 

199 inherit_cache = True 

200 

201 @property 

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

203 return self.effective_value 

204 

205 

206class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

208 columns that can represent rows. 

209 

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

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

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

213 PostgreSQL has functions that return rows also. 

214 

215 .. versionadded:: 1.4 

216 

217 """ 

218 

219 _is_returns_rows = True 

220 

221 # sub-elements of returns_rows 

222 _is_from_clause = False 

223 _is_select_base = False 

224 _is_select_statement = False 

225 _is_lateral = False 

226 

227 @property 

228 def selectable(self) -> ReturnsRows: 

229 return self 

230 

231 @util.ro_non_memoized_property 

232 def _all_selected_columns(self) -> _SelectIterable: 

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

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

235 

236 This is typically equivalent to .exported_columns except it is 

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

238 :class:`_expression.ColumnCollection`. 

239 

240 """ 

241 raise NotImplementedError() 

242 

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

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

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

246 

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

248 

249 """ 

250 raise NotImplementedError() 

251 

252 def _generate_fromclause_column_proxies( 

253 self, 

254 fromclause: FromClause, 

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

256 primary_key: ColumnSet, 

257 foreign_keys: Set[KeyedColumnElement[Any]], 

258 ) -> None: 

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

260 

261 raise NotImplementedError() 

262 

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

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

265 raise NotImplementedError() 

266 

267 @property 

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

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

270 that represents the "exported" 

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

272 

273 The "exported" columns represent the collection of 

274 :class:`_expression.ColumnElement` 

275 expressions that are rendered by this SQL 

276 construct. There are primary varieties which are the 

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

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

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

280 columns in a DML statement.. 

281 

282 .. versionadded:: 1.4 

283 

284 .. seealso:: 

285 

286 :attr:`_expression.FromClause.exported_columns` 

287 

288 :attr:`_expression.SelectBase.exported_columns` 

289 """ 

290 

291 raise NotImplementedError() 

292 

293 

294class ExecutableReturnsRows(ExecutableStatement, ReturnsRows): 

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

296 

297 

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

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

300 

301 

302class Selectable(ReturnsRows): 

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

304 

305 __visit_name__ = "selectable" 

306 

307 is_selectable = True 

308 

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

310 raise NotImplementedError() 

311 

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

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

314 

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

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

317 

318 .. seealso:: 

319 

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

321 

322 """ 

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

324 

325 @util.deprecated( 

326 "1.4", 

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

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

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

330 ) 

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

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

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

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

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

336 

337 """ 

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

339 

340 def corresponding_column( 

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

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

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

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

345 :attr:`_expression.Selectable.exported_columns` 

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

347 which corresponds to that 

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

349 column. 

350 

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

352 to be matched. 

353 

354 :param require_embedded: only return corresponding columns for 

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

356 :class:`_expression.ColumnElement` 

357 is actually present within a sub-element 

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

359 Normally the column will match if 

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

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

362 

363 .. seealso:: 

364 

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

366 :class:`_expression.ColumnCollection` 

367 that is used for the operation. 

368 

369 :meth:`_expression.ColumnCollection.corresponding_column` 

370 - implementation 

371 method. 

372 

373 """ 

374 

375 return self.exported_columns.corresponding_column( 

376 column, require_embedded 

377 ) 

378 

379 

380class HasPrefixes: 

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

382 

383 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

384 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

385 ] 

386 

387 @_generative 

388 @_document_text_coercion( 

389 "prefixes", 

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

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

392 ) 

393 def prefix_with( 

394 self, 

395 *prefixes: _TextCoercedExpressionArgument[Any], 

396 dialect: str = "*", 

397 ) -> Self: 

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

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

400 

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

402 provided by MySQL. 

403 

404 E.g.:: 

405 

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

407 

408 # MySQL 5.7 optimizer hints 

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

410 

411 Multiple prefixes can be specified by multiple calls 

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

413 

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

415 construct which 

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

417 keyword. 

418 :param dialect: optional string dialect name which will 

419 limit rendering of this prefix to only that dialect. 

420 

421 """ 

422 self._prefixes = self._prefixes + tuple( 

423 [ 

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

425 for p in prefixes 

426 ] 

427 ) 

428 return self 

429 

430 

431class HasSuffixes: 

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

433 

434 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

435 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

436 ] 

437 

438 @_generative 

439 @_document_text_coercion( 

440 "suffixes", 

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

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

443 ) 

444 def suffix_with( 

445 self, 

446 *suffixes: _TextCoercedExpressionArgument[Any], 

447 dialect: str = "*", 

448 ) -> Self: 

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

450 

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

452 certain constructs. 

453 

454 E.g.:: 

455 

456 stmt = ( 

457 select(col1, col2) 

458 .cte() 

459 .suffix_with( 

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

461 ) 

462 ) 

463 

464 Multiple suffixes can be specified by multiple calls 

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

466 

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

468 construct which 

469 will be rendered following the target clause. 

470 :param dialect: Optional string dialect name which will 

471 limit rendering of this suffix to only that dialect. 

472 

473 """ 

474 self._suffixes = self._suffixes + tuple( 

475 [ 

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

477 for p in suffixes 

478 ] 

479 ) 

480 return self 

481 

482 

483class HasHints: 

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

485 util.immutabledict() 

486 ) 

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

488 

489 _has_hints_traverse_internals: _TraverseInternalsType = [ 

490 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

491 ("_hints", InternalTraversal.dp_table_hint_list), 

492 ] 

493 

494 @_generative 

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

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

497 other selectable object. 

498 

499 .. tip:: 

500 

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

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

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

504 the SELECT statement after the SELECT keyword, use the 

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

506 space, or for table-specific hints the 

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

508 hints in a dialect-specific location. 

509 

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

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

512 the statement as a whole. 

513 

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

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

516 etc. 

517 

518 .. seealso:: 

519 

520 :meth:`_expression.Select.with_hint` 

521 

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

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

524 MySQL or Oracle Database optimizer hints 

525 

526 """ 

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

528 

529 @_generative 

530 def with_hint( 

531 self, 

532 selectable: _FromClauseArgument, 

533 text: str, 

534 dialect_name: str = "*", 

535 ) -> Self: 

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

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

538 object. 

539 

540 .. tip:: 

541 

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

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

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

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

546 for MySQL or Oracle Database, use the 

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

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

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

550 

551 The text of the hint is rendered in the appropriate 

552 location for the database backend in use, relative 

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

554 passed as the 

555 ``selectable`` argument. The dialect implementation 

556 typically uses Python string substitution syntax 

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

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

559 following:: 

560 

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

562 

563 Would render SQL as: 

564 

565 .. sourcecode:: sql 

566 

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

568 

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

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

571 Database and MSSql simultaneously:: 

572 

573 select(mytable).with_hint( 

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

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

576 

577 .. seealso:: 

578 

579 :meth:`_expression.Select.with_statement_hint` 

580 

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

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

583 MySQL or Oracle Database optimizer hints 

584 

585 """ 

586 

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

588 

589 def _with_hint( 

590 self, 

591 selectable: Optional[_FromClauseArgument], 

592 text: str, 

593 dialect_name: str, 

594 ) -> Self: 

595 if selectable is None: 

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

597 else: 

598 self._hints = self._hints.union( 

599 { 

600 ( 

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

602 dialect_name, 

603 ): text 

604 } 

605 ) 

606 return self 

607 

608 

609class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

611 clause of a ``SELECT`` statement. 

612 

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

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

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

616 

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

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

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

620 :class:`_expression.ColumnElement` 

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

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

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

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

625 :meth:`_expression.FromClause.select`. 

626 

627 

628 """ 

629 

630 __visit_name__ = "fromclause" 

631 named_with_column = False 

632 

633 @util.ro_non_memoized_property 

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

635 return () 

636 

637 _is_clone_of: Optional[FromClause] 

638 

639 _columns: ColumnCollection[Any, Any] 

640 

641 schema: Optional[str] = None 

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

643 

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

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

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

647 

648 """ 

649 

650 is_selectable = True 

651 _is_from_clause = True 

652 _is_join = False 

653 

654 _use_schema_map = False 

655 

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

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

658 

659 

660 e.g.:: 

661 

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

663 

664 .. seealso:: 

665 

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

667 method which allows for arbitrary column lists. 

668 

669 """ 

670 return Select(self) 

671 

672 def join( 

673 self, 

674 right: _FromClauseArgument, 

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

676 isouter: bool = False, 

677 full: bool = False, 

678 ) -> Join: 

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

680 :class:`_expression.FromClause` 

681 to another :class:`FromClause`. 

682 

683 E.g.:: 

684 

685 from sqlalchemy import join 

686 

687 j = user_table.join( 

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

689 ) 

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

691 

692 would emit SQL along the lines of: 

693 

694 .. sourcecode:: sql 

695 

696 SELECT user.id, user.name FROM user 

697 JOIN address ON user.id = address.user_id 

698 

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

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

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

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

703 class. 

704 

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

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

707 will attempt to 

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

709 

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

711 

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

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

714 

715 .. seealso:: 

716 

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

718 

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

720 

721 """ 

722 

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

724 

725 def outerjoin( 

726 self, 

727 right: _FromClauseArgument, 

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

729 full: bool = False, 

730 ) -> Join: 

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

732 :class:`_expression.FromClause` 

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

734 True. 

735 

736 E.g.:: 

737 

738 from sqlalchemy import outerjoin 

739 

740 j = user_table.outerjoin( 

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

742 ) 

743 

744 The above is equivalent to:: 

745 

746 j = user_table.join( 

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

748 ) 

749 

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

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

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

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

754 class. 

755 

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

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

758 will attempt to 

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

760 

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

762 LEFT OUTER JOIN. 

763 

764 .. seealso:: 

765 

766 :meth:`_expression.FromClause.join` 

767 

768 :class:`_expression.Join` 

769 

770 """ # noqa: E501 

771 

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

773 

774 def alias( 

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

776 ) -> NamedFromClause: 

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

778 

779 E.g.:: 

780 

781 a2 = some_table.alias("a2") 

782 

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

784 object which can be used 

785 as a FROM clause in any SELECT statement. 

786 

787 .. seealso:: 

788 

789 :ref:`tutorial_using_aliases` 

790 

791 :func:`_expression.alias` 

792 

793 """ 

794 

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

796 

797 def tablesample( 

798 self, 

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

800 name: Optional[str] = None, 

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

802 ) -> TableSample: 

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

804 

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

806 construct also 

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

808 

809 .. seealso:: 

810 

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

812 

813 """ 

814 return TableSample._construct( 

815 self, sampling=sampling, name=name, seed=seed 

816 ) 

817 

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

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

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

821 

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

823 

824 """ 

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

826 # Other constructs override this to traverse through 

827 # contained elements. 

828 return fromclause in self._cloned_set 

829 

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

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

832 the other represent the same lexical identity. 

833 

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

835 if they are the same via annotation identity. 

836 

837 """ 

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

839 

840 @util.ro_non_memoized_property 

841 def description(self) -> str: 

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

843 

844 Used primarily for error message formatting. 

845 

846 """ 

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

848 

849 def _generate_fromclause_column_proxies( 

850 self, 

851 fromclause: FromClause, 

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

853 primary_key: ColumnSet, 

854 foreign_keys: Set[KeyedColumnElement[Any]], 

855 ) -> None: 

856 columns._populate_separate_keys( 

857 col._make_proxy( 

858 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

859 ) 

860 for col in self.c 

861 ) 

862 

863 @util.ro_non_memoized_property 

864 def exported_columns( 

865 self, 

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

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

868 that represents the "exported" 

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

870 

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

872 object are synonymous 

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

874 

875 .. versionadded:: 1.4 

876 

877 .. seealso:: 

878 

879 :attr:`_expression.Selectable.exported_columns` 

880 

881 :attr:`_expression.SelectBase.exported_columns` 

882 

883 

884 """ 

885 return self.c 

886 

887 @util.ro_non_memoized_property 

888 def columns( 

889 self, 

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

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

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

893 

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

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

896 other selectable-bound columns:: 

897 

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

899 

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

901 

902 """ 

903 return self.c 

904 

905 @util.ro_memoized_property 

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

907 """ 

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

909 

910 :return: a :class:`.ColumnCollection` 

911 

912 """ 

913 if "_columns" not in self.__dict__: 

914 self._setup_collections() 

915 return self._columns.as_readonly() 

916 

917 def _setup_collections(self) -> None: 

918 with util.mini_gil: 

919 # detect another thread that raced ahead 

920 if "_columns" in self.__dict__: 

921 assert "primary_key" in self.__dict__ 

922 assert "foreign_keys" in self.__dict__ 

923 return 

924 

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

926 primary_key = ColumnSet() 

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

928 

929 self._populate_column_collection( 

930 columns=_columns, 

931 primary_key=primary_key, 

932 foreign_keys=foreign_keys, 

933 ) 

934 

935 # assigning these three collections separately is not itself 

936 # atomic, but greatly reduces the surface for problems 

937 self._columns = _columns 

938 self.primary_key = primary_key # type: ignore 

939 self.foreign_keys = foreign_keys # type: ignore 

940 

941 @util.ro_non_memoized_property 

942 def entity_namespace(self) -> _EntityNamespace: 

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

944 

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

946 expressions, such as:: 

947 

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

949 

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

951 be overridden using the "entity_namespace" annotation to deliver 

952 alternative results. 

953 

954 """ 

955 return self.c 

956 

957 @util.ro_memoized_property 

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

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

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

961 

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

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

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

965 

966 """ 

967 self._setup_collections() 

968 return self.primary_key 

969 

970 @util.ro_memoized_property 

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

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

973 which this FromClause references. 

974 

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

976 :class:`_schema.Table`-wide 

977 :class:`_schema.ForeignKeyConstraint`. 

978 

979 .. seealso:: 

980 

981 :attr:`_schema.Table.foreign_key_constraints` 

982 

983 """ 

984 self._setup_collections() 

985 return self.foreign_keys 

986 

987 def _reset_column_collection(self) -> None: 

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

989 

990 This collection is separate from all the other memoized things 

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

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

993 has already established strong relationships 

994 with the exported columns. 

995 

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

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

998 

999 """ 

1000 

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

1002 self.__dict__.pop(key, None) 

1003 

1004 @util.ro_non_memoized_property 

1005 def _select_iterable(self) -> _SelectIterable: 

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

1007 

1008 @property 

1009 def _cols_populated(self) -> bool: 

1010 return "_columns" in self.__dict__ 

1011 

1012 def _populate_column_collection( 

1013 self, 

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

1015 primary_key: ColumnSet, 

1016 foreign_keys: Set[KeyedColumnElement[Any]], 

1017 ) -> None: 

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

1019 

1020 Each implementation has a different way of establishing 

1021 this collection. 

1022 

1023 """ 

1024 

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

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

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

1028 selectable ultimately should proxy this column. 

1029 

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

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

1032 Table objects it ultimately derives from. 

1033 

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

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

1036 but it will return None. 

1037 

1038 This method is currently used by Declarative to allow Table 

1039 columns to be added to a partially constructed inheritance 

1040 mapping that may have already produced joins. The method 

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

1042 and/or caveats aren't yet clear. 

1043 

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

1045 default via an event, which would require that 

1046 selectables maintain a weak referencing collection of all 

1047 derivations. 

1048 

1049 """ 

1050 self._reset_column_collection() 

1051 

1052 def _anonymous_fromclause( 

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

1054 ) -> FromClause: 

1055 return self.alias(name=name) 

1056 

1057 if TYPE_CHECKING: 

1058 

1059 def self_group( 

1060 self, against: Optional[OperatorType] = None 

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

1062 

1063 

1064class NamedFromClause(FromClause): 

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

1066 

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

1068 

1069 .. versionadded:: 2.0 

1070 

1071 """ 

1072 

1073 named_with_column = True 

1074 

1075 name: str 

1076 

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

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

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

1080 :class:`_expression.FromClause`. 

1081 

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

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

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

1085 such as PostgreSQL, Oracle Database and SQL Server. 

1086 

1087 E.g.: 

1088 

1089 .. sourcecode:: pycon+sql 

1090 

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

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

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

1094 >>> print(stmt) 

1095 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1096 FROM a 

1097 

1098 .. versionadded:: 1.4.0b2 

1099 

1100 .. seealso:: 

1101 

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

1103 

1104 """ 

1105 return TableValuedColumn(self, type_api.TABLEVALUE) 

1106 

1107 

1108class SelectLabelStyle(Enum): 

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

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

1111 

1112 LABEL_STYLE_NONE = 0 

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

1114 columns clause of a SELECT statement. 

1115 

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

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

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

1119 

1120 .. sourcecode:: pycon+sql 

1121 

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

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

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

1125 >>> print( 

1126 ... select(table1, table2) 

1127 ... .join(table2, true()) 

1128 ... .set_label_style(LABEL_STYLE_NONE) 

1129 ... ) 

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

1131 FROM table1 JOIN table2 ON true 

1132 

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

1134 

1135 .. versionadded:: 1.4 

1136 

1137 """ # noqa: E501 

1138 

1139 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1143 tables, aliases, or subqueries. 

1144 

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

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

1147 ``table2_columna``: 

1148 

1149 .. sourcecode:: pycon+sql 

1150 

1151 >>> from sqlalchemy import ( 

1152 ... table, 

1153 ... column, 

1154 ... select, 

1155 ... true, 

1156 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1157 ... ) 

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

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

1160 >>> print( 

1161 ... select(table1, table2) 

1162 ... .join(table2, true()) 

1163 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1164 ... ) 

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

1166 FROM table1 JOIN table2 ON true 

1167 

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

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

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

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

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

1173 

1174 

1175 .. versionadded:: 1.4 

1176 

1177 """ # noqa: E501 

1178 

1179 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1182 when generating the columns clause of a SELECT statement. 

1183 

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

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

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

1187 

1188 .. sourcecode:: pycon+sql 

1189 

1190 >>> from sqlalchemy import ( 

1191 ... table, 

1192 ... column, 

1193 ... select, 

1194 ... true, 

1195 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1196 ... ) 

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

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

1199 >>> print( 

1200 ... select(table1, table2) 

1201 ... .join(table2, true()) 

1202 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1203 ... ) 

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

1205 FROM table1 JOIN table2 ON true 

1206 

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

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

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

1210 

1211 .. versionadded:: 1.4 

1212 

1213 """ # noqa: E501 

1214 

1215 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1216 """The default label style, refers to 

1217 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1218 

1219 .. versionadded:: 1.4 

1220 

1221 """ 

1222 

1223 LABEL_STYLE_LEGACY_ORM = 3 

1224 

1225 

1226( 

1227 LABEL_STYLE_NONE, 

1228 LABEL_STYLE_TABLENAME_PLUS_COL, 

1229 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1230 _, 

1231) = list(SelectLabelStyle) 

1232 

1233LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1234 

1235 

1236class Join(roles.DMLTableRole, FromClause): 

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

1238 :class:`_expression.FromClause` 

1239 elements. 

1240 

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

1242 is the module-level 

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

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

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

1246 :class:`_schema.Table`). 

1247 

1248 .. seealso:: 

1249 

1250 :func:`_expression.join` 

1251 

1252 :meth:`_expression.FromClause.join` 

1253 

1254 """ 

1255 

1256 __visit_name__ = "join" 

1257 

1258 _traverse_internals: _TraverseInternalsType = [ 

1259 ("left", InternalTraversal.dp_clauseelement), 

1260 ("right", InternalTraversal.dp_clauseelement), 

1261 ("onclause", InternalTraversal.dp_clauseelement), 

1262 ("isouter", InternalTraversal.dp_boolean), 

1263 ("full", InternalTraversal.dp_boolean), 

1264 ] 

1265 

1266 _is_join = True 

1267 

1268 left: FromClause 

1269 right: FromClause 

1270 onclause: Optional[ColumnElement[bool]] 

1271 isouter: bool 

1272 full: bool 

1273 

1274 def __init__( 

1275 self, 

1276 left: _FromClauseArgument, 

1277 right: _FromClauseArgument, 

1278 onclause: Optional[_OnClauseArgument] = None, 

1279 isouter: bool = False, 

1280 full: bool = False, 

1281 ): 

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

1283 

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

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

1286 :class:`_expression.FromClause` object. 

1287 

1288 """ 

1289 

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

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

1292 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1295 # callcounts for a single compilation in that particular test 

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

1297 # 29200 -> 30373 

1298 

1299 self.left = coercions.expect( 

1300 roles.FromClauseRole, 

1301 left, 

1302 ) 

1303 self.right = coercions.expect( 

1304 roles.FromClauseRole, 

1305 right, 

1306 ).self_group() 

1307 

1308 if onclause is None: 

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

1310 else: 

1311 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1312 # not merged yet 

1313 self.onclause = coercions.expect( 

1314 roles.OnClauseRole, onclause 

1315 ).self_group(against=operators._asbool) 

1316 

1317 self.isouter = isouter 

1318 self.full = full 

1319 

1320 @util.ro_non_memoized_property 

1321 def description(self) -> str: 

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

1323 self.left.description, 

1324 id(self.left), 

1325 self.right.description, 

1326 id(self.right), 

1327 ) 

1328 

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

1330 return ( 

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

1332 # as well 

1333 hash(fromclause) == hash(self) 

1334 or self.left.is_derived_from(fromclause) 

1335 or self.right.is_derived_from(fromclause) 

1336 ) 

1337 

1338 def self_group( 

1339 self, against: Optional[OperatorType] = None 

1340 ) -> FromGrouping: 

1341 return FromGrouping(self) 

1342 

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

1344 def _populate_column_collection( 

1345 self, 

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

1347 primary_key: ColumnSet, 

1348 foreign_keys: Set[KeyedColumnElement[Any]], 

1349 ) -> None: 

1350 sqlutil = util.preloaded.sql_util 

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

1352 c for c in self.right.c 

1353 ] 

1354 

1355 primary_key.extend( 

1356 sqlutil.reduce_columns( 

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

1358 ) 

1359 ) 

1360 columns._populate_separate_keys( 

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

1362 ) 

1363 foreign_keys.update( 

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

1365 ) 

1366 

1367 def _copy_internals( 

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

1369 ) -> None: 

1370 # see Select._copy_internals() for similar concept 

1371 

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

1373 # determine the new FROM clauses 

1374 all_the_froms = set( 

1375 itertools.chain( 

1376 _from_objects(self.left), 

1377 _from_objects(self.right), 

1378 ) 

1379 ) 

1380 

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

1382 # cache used by the clone function 

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

1384 

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

1386 # ColumnClause with parent table referring to those 

1387 # replaced FromClause objects 

1388 def replace( 

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

1390 **kw: Any, 

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

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

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

1394 return newelem 

1395 return None 

1396 

1397 kw["replace"] = replace 

1398 

1399 # run normal _copy_internals. the clones for 

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

1401 # cache 

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

1403 

1404 self._reset_memoizations() 

1405 

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

1407 super()._refresh_for_new_column(column) 

1408 self.left._refresh_for_new_column(column) 

1409 self.right._refresh_for_new_column(column) 

1410 

1411 def _match_primaries( 

1412 self, 

1413 left: FromClause, 

1414 right: FromClause, 

1415 ) -> ColumnElement[bool]: 

1416 if isinstance(left, Join): 

1417 left_right = left.right 

1418 else: 

1419 left_right = None 

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

1421 

1422 @classmethod 

1423 def _join_condition( 

1424 cls, 

1425 a: FromClause, 

1426 b: FromClause, 

1427 *, 

1428 a_subset: Optional[FromClause] = None, 

1429 consider_as_foreign_keys: Optional[ 

1430 AbstractSet[ColumnClause[Any]] 

1431 ] = None, 

1432 ) -> ColumnElement[bool]: 

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

1434 

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

1436 

1437 """ 

1438 constraints = cls._joincond_scan_left_right( 

1439 a, a_subset, b, consider_as_foreign_keys 

1440 ) 

1441 

1442 if len(constraints) > 1: 

1443 cls._joincond_trim_constraints( 

1444 a, b, constraints, consider_as_foreign_keys 

1445 ) 

1446 

1447 if len(constraints) == 0: 

1448 if isinstance(b, FromGrouping): 

1449 hint = ( 

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

1451 "subquery using alias()?" 

1452 ) 

1453 else: 

1454 hint = "" 

1455 raise exc.NoForeignKeysError( 

1456 "Can't find any foreign key relationships " 

1457 "between '%s' and '%s'.%s" 

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

1459 ) 

1460 

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

1462 if len(crit) == 1: 

1463 return crit[0] 

1464 else: 

1465 return and_(*crit) 

1466 

1467 @classmethod 

1468 def _can_join( 

1469 cls, 

1470 left: FromClause, 

1471 right: FromClause, 

1472 *, 

1473 consider_as_foreign_keys: Optional[ 

1474 AbstractSet[ColumnClause[Any]] 

1475 ] = None, 

1476 ) -> bool: 

1477 if isinstance(left, Join): 

1478 left_right = left.right 

1479 else: 

1480 left_right = None 

1481 

1482 constraints = cls._joincond_scan_left_right( 

1483 a=left, 

1484 b=right, 

1485 a_subset=left_right, 

1486 consider_as_foreign_keys=consider_as_foreign_keys, 

1487 ) 

1488 

1489 return bool(constraints) 

1490 

1491 @classmethod 

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

1493 def _joincond_scan_left_right( 

1494 cls, 

1495 a: FromClause, 

1496 a_subset: Optional[FromClause], 

1497 b: FromClause, 

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

1499 ) -> collections.defaultdict[ 

1500 Optional[ForeignKeyConstraint], 

1501 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1502 ]: 

1503 sql_util = util.preloaded.sql_util 

1504 

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

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

1507 

1508 constraints: collections.defaultdict[ 

1509 Optional[ForeignKeyConstraint], 

1510 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1511 ] = collections.defaultdict(list) 

1512 

1513 for left in (a_subset, a): 

1514 if left is None: 

1515 continue 

1516 for fk in sorted( 

1517 b.foreign_keys, 

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

1519 ): 

1520 if ( 

1521 consider_as_foreign_keys is not None 

1522 and fk.parent not in consider_as_foreign_keys 

1523 ): 

1524 continue 

1525 try: 

1526 col = fk.get_referent(left) 

1527 except exc.NoReferenceError as nrte: 

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

1529 if nrte.table_name in table_names: 

1530 raise 

1531 else: 

1532 continue 

1533 

1534 if col is not None: 

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

1536 if left is not b: 

1537 for fk in sorted( 

1538 left.foreign_keys, 

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

1540 ): 

1541 if ( 

1542 consider_as_foreign_keys is not None 

1543 and fk.parent not in consider_as_foreign_keys 

1544 ): 

1545 continue 

1546 try: 

1547 col = fk.get_referent(b) 

1548 except exc.NoReferenceError as nrte: 

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

1550 if nrte.table_name in table_names: 

1551 raise 

1552 else: 

1553 continue 

1554 

1555 if col is not None: 

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

1557 if constraints: 

1558 break 

1559 return constraints 

1560 

1561 @classmethod 

1562 def _joincond_trim_constraints( 

1563 cls, 

1564 a: FromClause, 

1565 b: FromClause, 

1566 constraints: Dict[Any, Any], 

1567 consider_as_foreign_keys: Optional[Any], 

1568 ) -> None: 

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

1570 # to include just those FKCs that match exactly to 

1571 # "consider_as_foreign_keys". 

1572 if consider_as_foreign_keys: 

1573 for const in list(constraints): 

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

1575 consider_as_foreign_keys 

1576 ): 

1577 del constraints[const] 

1578 

1579 # if still multiple constraints, but 

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

1581 if len(constraints) > 1: 

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

1583 if len(dedupe) == 1: 

1584 key = list(constraints)[0] 

1585 constraints = {key: constraints[key]} 

1586 

1587 if len(constraints) != 1: 

1588 raise exc.AmbiguousForeignKeysError( 

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

1590 "tables have more than one foreign key " 

1591 "constraint relationship between them. " 

1592 "Please specify the 'onclause' of this " 

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

1594 ) 

1595 

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

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

1598 :class:`_expression.Join`. 

1599 

1600 E.g.:: 

1601 

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

1603 

1604 stmt = stmt.select() 

1605 

1606 The above will produce a SQL string resembling: 

1607 

1608 .. sourcecode:: sql 

1609 

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

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

1612 

1613 """ 

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

1615 

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

1617 def _anonymous_fromclause( 

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

1619 ) -> TODO_Any: 

1620 sqlutil = util.preloaded.sql_util 

1621 if flat: 

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

1623 left_name = name # will recurse 

1624 else: 

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

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

1627 else: 

1628 left_name = name 

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

1630 right_name = name # will recurse 

1631 else: 

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

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

1634 else: 

1635 right_name = name 

1636 left_a, right_a = ( 

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

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

1639 ) 

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

1641 sqlutil.ClauseAdapter(right_a) 

1642 ) 

1643 

1644 return left_a.join( 

1645 right_a, 

1646 adapter.traverse(self.onclause), 

1647 isouter=self.isouter, 

1648 full=self.full, 

1649 ) 

1650 else: 

1651 return ( 

1652 self.select() 

1653 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1654 .correlate(None) 

1655 .alias(name) 

1656 ) 

1657 

1658 @util.ro_non_memoized_property 

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

1660 return itertools.chain( 

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

1662 ) 

1663 

1664 @util.ro_non_memoized_property 

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

1666 self_list: List[FromClause] = [self] 

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

1668 

1669 

1670class NoInit: 

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

1672 raise NotImplementedError( 

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

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

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

1676 "selectable objects." 

1677 % ( 

1678 self.__class__.__name__, 

1679 self.__class__.__name__.lower(), 

1680 self.__class__.__name__.lower(), 

1681 ) 

1682 ) 

1683 

1684 

1685class LateralFromClause(NamedFromClause): 

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

1687 

1688 

1689# FromClause -> 

1690# AliasedReturnsRows 

1691# -> Alias only for FromClause 

1692# -> Subquery only for SelectBase 

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

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

1695# w/ non-deprecated coercion 

1696# -> TableSample -> only for FromClause 

1697 

1698 

1699class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1701 selectables.""" 

1702 

1703 _is_from_container = True 

1704 

1705 _supports_derived_columns = False 

1706 

1707 element: ReturnsRows 

1708 

1709 _traverse_internals: _TraverseInternalsType = [ 

1710 ("element", InternalTraversal.dp_clauseelement), 

1711 ("name", InternalTraversal.dp_anon_name), 

1712 ] 

1713 

1714 @classmethod 

1715 def _construct( 

1716 cls, 

1717 selectable: Any, 

1718 *, 

1719 name: Optional[str] = None, 

1720 **kw: Any, 

1721 ) -> Self: 

1722 obj = cls.__new__(cls) 

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

1724 return obj 

1725 

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

1727 self.element = coercions.expect( 

1728 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1729 ) 

1730 self.element = selectable 

1731 self._orig_name = name 

1732 if name is None: 

1733 if ( 

1734 isinstance(selectable, FromClause) 

1735 and selectable.named_with_column 

1736 ): 

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

1738 if isinstance(name, _anonymous_label): 

1739 name = None 

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

1741 self.name = name 

1742 

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

1744 super()._refresh_for_new_column(column) 

1745 self.element._refresh_for_new_column(column) 

1746 

1747 def _populate_column_collection( 

1748 self, 

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

1750 primary_key: ColumnSet, 

1751 foreign_keys: Set[KeyedColumnElement[Any]], 

1752 ) -> None: 

1753 self.element._generate_fromclause_column_proxies( 

1754 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1755 ) 

1756 

1757 @util.ro_non_memoized_property 

1758 def description(self) -> str: 

1759 name = self.name 

1760 if isinstance(name, _anonymous_label): 

1761 return "anon_1" 

1762 

1763 return name 

1764 

1765 @util.ro_non_memoized_property 

1766 def implicit_returning(self) -> bool: 

1767 return self.element.implicit_returning # type: ignore 

1768 

1769 @property 

1770 def original(self) -> ReturnsRows: 

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

1772 return self.element 

1773 

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

1775 if fromclause in self._cloned_set: 

1776 return True 

1777 return self.element.is_derived_from(fromclause) 

1778 

1779 def _copy_internals( 

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

1781 ) -> None: 

1782 existing_element = self.element 

1783 

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

1785 

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

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

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

1789 # performance. 

1790 if existing_element is not self.element: 

1791 self._reset_column_collection() 

1792 

1793 @property 

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

1795 return [self] 

1796 

1797 

1798class FromClauseAlias(AliasedReturnsRows): 

1799 element: FromClause 

1800 

1801 @util.ro_non_memoized_property 

1802 def description(self) -> str: 

1803 name = self.name 

1804 if isinstance(name, _anonymous_label): 

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

1806 

1807 return name 

1808 

1809 

1810class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1812 

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

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

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

1816 

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

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

1819 method available 

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

1821 

1822 .. seealso:: 

1823 

1824 :meth:`_expression.FromClause.alias` 

1825 

1826 """ 

1827 

1828 __visit_name__ = "alias" 

1829 

1830 inherit_cache = True 

1831 

1832 element: FromClause 

1833 

1834 @classmethod 

1835 def _factory( 

1836 cls, 

1837 selectable: FromClause, 

1838 name: Optional[str] = None, 

1839 flat: bool = False, 

1840 ) -> NamedFromClause: 

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

1842 name=name, flat=flat 

1843 ) 

1844 

1845 

1846class TableValuedAlias(LateralFromClause, Alias): 

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

1848 

1849 This construct provides for a SQL function that returns columns 

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

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

1852 method, e.g.: 

1853 

1854 .. sourcecode:: pycon+sql 

1855 

1856 >>> from sqlalchemy import select, func 

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

1858 ... "value" 

1859 ... ) 

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

1861 {printsql}SELECT anon_1.value 

1862 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1863 

1864 .. versionadded:: 1.4.0b2 

1865 

1866 .. seealso:: 

1867 

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

1869 

1870 """ # noqa: E501 

1871 

1872 __visit_name__ = "table_valued_alias" 

1873 

1874 _supports_derived_columns = True 

1875 _render_derived = False 

1876 _render_derived_w_types = False 

1877 joins_implicitly = False 

1878 

1879 _traverse_internals: _TraverseInternalsType = [ 

1880 ("element", InternalTraversal.dp_clauseelement), 

1881 ("name", InternalTraversal.dp_anon_name), 

1882 ("_tableval_type", InternalTraversal.dp_type), 

1883 ("_render_derived", InternalTraversal.dp_boolean), 

1884 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1885 ] 

1886 

1887 def _init( 

1888 self, 

1889 selectable: Any, 

1890 *, 

1891 name: Optional[str] = None, 

1892 table_value_type: Optional[TableValueType] = None, 

1893 joins_implicitly: bool = False, 

1894 ) -> None: 

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

1896 

1897 self.joins_implicitly = joins_implicitly 

1898 self._tableval_type = ( 

1899 type_api.TABLEVALUE 

1900 if table_value_type is None 

1901 else table_value_type 

1902 ) 

1903 

1904 @HasMemoized.memoized_attribute 

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

1906 """Return a column expression representing this 

1907 :class:`_sql.TableValuedAlias`. 

1908 

1909 This accessor is used to implement the 

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

1911 method for further details. 

1912 

1913 E.g.: 

1914 

1915 .. sourcecode:: pycon+sql 

1916 

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

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

1919 

1920 .. seealso:: 

1921 

1922 :meth:`_functions.FunctionElement.column_valued` 

1923 

1924 """ 

1925 

1926 return TableValuedColumn(self, self._tableval_type) 

1927 

1928 def alias( 

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

1930 ) -> TableValuedAlias: 

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

1932 

1933 This creates a distinct FROM object that will be distinguished 

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

1935 

1936 """ 

1937 

1938 tva: TableValuedAlias = TableValuedAlias._construct( 

1939 self, 

1940 name=name, 

1941 table_value_type=self._tableval_type, 

1942 joins_implicitly=self.joins_implicitly, 

1943 ) 

1944 

1945 if self._render_derived: 

1946 tva._render_derived = True 

1947 tva._render_derived_w_types = self._render_derived_w_types 

1948 

1949 return tva 

1950 

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

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

1953 set, so that it renders as LATERAL. 

1954 

1955 .. seealso:: 

1956 

1957 :func:`_expression.lateral` 

1958 

1959 """ 

1960 tva = self.alias(name=name) 

1961 tva._is_lateral = True 

1962 return tva 

1963 

1964 def render_derived( 

1965 self, 

1966 name: Optional[str] = None, 

1967 with_types: bool = False, 

1968 ) -> TableValuedAlias: 

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

1970 

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

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

1973 

1974 .. sourcecode:: pycon+sql 

1975 

1976 >>> print( 

1977 ... select( 

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

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

1980 ... .render_derived() 

1981 ... ) 

1982 ... ) 

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

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

1985 

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

1987 the alias expression (this syntax currently applies to the 

1988 PostgreSQL database): 

1989 

1990 .. sourcecode:: pycon+sql 

1991 

1992 >>> print( 

1993 ... select( 

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

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

1996 ... .render_derived(with_types=True) 

1997 ... ) 

1998 ... ) 

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

2000 AS anon_1(a INTEGER, b VARCHAR) 

2001 

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

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

2004 

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

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

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

2008 

2009 """ # noqa: E501 

2010 

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

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

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

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

2015 # (just saw it happen on CI) 

2016 

2017 # construct against original to prevent memory growth 

2018 # for repeated generations 

2019 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2020 self.element, 

2021 name=name, 

2022 table_value_type=self._tableval_type, 

2023 joins_implicitly=self.joins_implicitly, 

2024 ) 

2025 new_alias._render_derived = True 

2026 new_alias._render_derived_w_types = with_types 

2027 return new_alias 

2028 

2029 

2030class Lateral(FromClauseAlias, LateralFromClause): 

2031 """Represent a LATERAL subquery. 

2032 

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

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

2035 method available 

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

2037 

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

2039 PostgreSQL versions provide support for this keyword. 

2040 

2041 .. seealso:: 

2042 

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

2044 

2045 """ 

2046 

2047 __visit_name__ = "lateral" 

2048 _is_lateral = True 

2049 

2050 inherit_cache = True 

2051 

2052 @classmethod 

2053 def _factory( 

2054 cls, 

2055 selectable: Union[SelectBase, _FromClauseArgument], 

2056 name: Optional[str] = None, 

2057 ) -> LateralFromClause: 

2058 return coercions.expect( 

2059 roles.FromClauseRole, selectable, explicit_subquery=True 

2060 ).lateral(name=name) 

2061 

2062 

2063class TableSample(FromClauseAlias): 

2064 """Represent a TABLESAMPLE clause. 

2065 

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

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

2068 method 

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

2070 

2071 .. seealso:: 

2072 

2073 :func:`_expression.tablesample` 

2074 

2075 """ 

2076 

2077 __visit_name__ = "tablesample" 

2078 

2079 _traverse_internals: _TraverseInternalsType = ( 

2080 AliasedReturnsRows._traverse_internals 

2081 + [ 

2082 ("sampling", InternalTraversal.dp_clauseelement), 

2083 ("seed", InternalTraversal.dp_clauseelement), 

2084 ] 

2085 ) 

2086 

2087 @classmethod 

2088 def _factory( 

2089 cls, 

2090 selectable: _FromClauseArgument, 

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

2092 name: Optional[str] = None, 

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

2094 ) -> TableSample: 

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

2096 sampling, name=name, seed=seed 

2097 ) 

2098 

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

2100 def _init( # type: ignore[override] 

2101 self, 

2102 selectable: Any, 

2103 *, 

2104 name: Optional[str] = None, 

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

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

2107 ) -> None: 

2108 assert sampling is not None 

2109 functions = util.preloaded.sql_functions 

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

2111 sampling = functions.func.system(sampling) 

2112 

2113 self.sampling: Function[Any] = sampling 

2114 self.seed = seed 

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

2116 

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

2118 return self.sampling 

2119 

2120 

2121class CTE( 

2122 roles.DMLTableRole, 

2123 roles.IsCTERole, 

2124 Generative, 

2125 HasPrefixes, 

2126 HasSuffixes, 

2127 AliasedReturnsRows, 

2128): 

2129 """Represent a Common Table Expression. 

2130 

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

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

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

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

2135 :class:`_sql.Update` and 

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

2137 usage details on CTEs. 

2138 

2139 .. seealso:: 

2140 

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

2142 

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

2144 

2145 """ 

2146 

2147 __visit_name__ = "cte" 

2148 

2149 _traverse_internals: _TraverseInternalsType = ( 

2150 AliasedReturnsRows._traverse_internals 

2151 + [ 

2152 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2153 ("_restates", InternalTraversal.dp_clauseelement), 

2154 ("recursive", InternalTraversal.dp_boolean), 

2155 ("nesting", InternalTraversal.dp_boolean), 

2156 ] 

2157 + HasPrefixes._has_prefixes_traverse_internals 

2158 + HasSuffixes._has_suffixes_traverse_internals 

2159 ) 

2160 

2161 element: HasCTE 

2162 

2163 @classmethod 

2164 def _factory( 

2165 cls, 

2166 selectable: HasCTE, 

2167 name: Optional[str] = None, 

2168 recursive: bool = False, 

2169 ) -> CTE: 

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

2171 or Common Table Expression instance. 

2172 

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

2174 

2175 """ 

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

2177 name=name, recursive=recursive 

2178 ) 

2179 

2180 def _init( 

2181 self, 

2182 selectable: HasCTE, 

2183 *, 

2184 name: Optional[str] = None, 

2185 recursive: bool = False, 

2186 nesting: bool = False, 

2187 _cte_alias: Optional[CTE] = None, 

2188 _restates: Optional[CTE] = None, 

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

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

2191 ) -> None: 

2192 self.recursive = recursive 

2193 self.nesting = nesting 

2194 self._cte_alias = _cte_alias 

2195 # Keep recursivity reference with union/union_all 

2196 self._restates = _restates 

2197 if _prefixes: 

2198 self._prefixes = _prefixes 

2199 if _suffixes: 

2200 self._suffixes = _suffixes 

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

2202 

2203 def _populate_column_collection( 

2204 self, 

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

2206 primary_key: ColumnSet, 

2207 foreign_keys: Set[KeyedColumnElement[Any]], 

2208 ) -> None: 

2209 if self._cte_alias is not None: 

2210 self._cte_alias._generate_fromclause_column_proxies( 

2211 self, 

2212 columns, 

2213 primary_key=primary_key, 

2214 foreign_keys=foreign_keys, 

2215 ) 

2216 else: 

2217 self.element._generate_fromclause_column_proxies( 

2218 self, 

2219 columns, 

2220 primary_key=primary_key, 

2221 foreign_keys=foreign_keys, 

2222 ) 

2223 

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

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

2226 :class:`_expression.CTE`. 

2227 

2228 This method is a CTE-specific specialization of the 

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

2230 

2231 .. seealso:: 

2232 

2233 :ref:`tutorial_using_aliases` 

2234 

2235 :func:`_expression.alias` 

2236 

2237 """ 

2238 return CTE._construct( 

2239 self.element, 

2240 name=name, 

2241 recursive=self.recursive, 

2242 nesting=self.nesting, 

2243 _cte_alias=self, 

2244 _prefixes=self._prefixes, 

2245 _suffixes=self._suffixes, 

2246 ) 

2247 

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

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

2250 of the original CTE against the given selectables provided 

2251 as positional arguments. 

2252 

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

2254 UNION. 

2255 

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

2257 

2258 .. seealso:: 

2259 

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

2261 

2262 """ 

2263 assert is_select_statement( 

2264 self.element 

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

2266 

2267 return CTE._construct( 

2268 self.element.union(*other), 

2269 name=self.name, 

2270 recursive=self.recursive, 

2271 nesting=self.nesting, 

2272 _restates=self, 

2273 _prefixes=self._prefixes, 

2274 _suffixes=self._suffixes, 

2275 ) 

2276 

2277 def union_all( 

2278 self, *other: _SelectStatementForCompoundArgument[Any] 

2279 ) -> CTE: 

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

2281 of the original CTE against the given selectables provided 

2282 as positional arguments. 

2283 

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

2285 UNION. 

2286 

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

2288 

2289 .. seealso:: 

2290 

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

2292 

2293 """ 

2294 

2295 assert is_select_statement( 

2296 self.element 

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

2298 

2299 return CTE._construct( 

2300 self.element.union_all(*other), 

2301 name=self.name, 

2302 recursive=self.recursive, 

2303 nesting=self.nesting, 

2304 _restates=self, 

2305 _prefixes=self._prefixes, 

2306 _suffixes=self._suffixes, 

2307 ) 

2308 

2309 def _get_reference_cte(self) -> CTE: 

2310 """ 

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

2312 Updated CTEs should still refer to the original CTE. 

2313 This function returns this reference identifier. 

2314 """ 

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

2316 

2317 

2318class _CTEOpts(NamedTuple): 

2319 nesting: bool 

2320 

2321 

2322class _ColumnsPlusNames(NamedTuple): 

2323 required_label_name: Optional[str] 

2324 """ 

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

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

2327 """ 

2328 

2329 proxy_key: Optional[str] 

2330 """ 

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

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

2333 select.selected_columns collection 

2334 """ 

2335 

2336 fallback_label_name: Optional[str] 

2337 """ 

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

2339 we have to render a label even though 

2340 required_label_name was not given 

2341 """ 

2342 

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

2344 """ 

2345 the ColumnElement itself 

2346 """ 

2347 

2348 repeated: bool 

2349 """ 

2350 True if this is a duplicate of a previous column 

2351 in the list of columns 

2352 """ 

2353 

2354 

2355class SelectsRows(ReturnsRows): 

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

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

2358 

2359 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2360 

2361 def _generate_columns_plus_names( 

2362 self, 

2363 anon_for_dupe_key: bool, 

2364 cols: Optional[_SelectIterable] = None, 

2365 ) -> List[_ColumnsPlusNames]: 

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

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

2368 on a :class:`.FromClause`. 

2369 

2370 This is distinct from the _column_naming_convention generator that's 

2371 intended for population of the Select.selected_columns collection, 

2372 different rules. the collection returned here calls upon the 

2373 _column_naming_convention as well. 

2374 

2375 """ 

2376 

2377 if cols is None: 

2378 cols = self._all_selected_columns 

2379 

2380 key_naming_convention = SelectState._column_naming_convention( 

2381 self._label_style 

2382 ) 

2383 

2384 names = {} 

2385 

2386 result: List[_ColumnsPlusNames] = [] 

2387 result_append = result.append 

2388 

2389 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2390 label_style_none = self._label_style is LABEL_STYLE_NONE 

2391 

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

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

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

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

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

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

2398 dedupe_hash = 1 

2399 

2400 for c in cols: 

2401 repeated = False 

2402 

2403 if not c._render_label_in_columns_clause: 

2404 effective_name = required_label_name = fallback_label_name = ( 

2405 None 

2406 ) 

2407 elif label_style_none: 

2408 if TYPE_CHECKING: 

2409 assert is_column_element(c) 

2410 

2411 effective_name = required_label_name = None 

2412 fallback_label_name = c._non_anon_label or c._anon_name_label 

2413 else: 

2414 if TYPE_CHECKING: 

2415 assert is_column_element(c) 

2416 

2417 if table_qualified: 

2418 required_label_name = effective_name = ( 

2419 fallback_label_name 

2420 ) = c._tq_label 

2421 else: 

2422 effective_name = fallback_label_name = c._non_anon_label 

2423 required_label_name = None 

2424 

2425 if effective_name is None: 

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

2427 # not need _expression_label but it isn't 

2428 # giving us a clue when to use anon_label instead 

2429 expr_label = c._expression_label 

2430 if expr_label is None: 

2431 repeated = c._anon_name_label in names 

2432 names[c._anon_name_label] = c 

2433 effective_name = required_label_name = None 

2434 

2435 if repeated: 

2436 # here, "required_label_name" is sent as 

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

2438 if table_qualified: 

2439 fallback_label_name = ( 

2440 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2441 ) 

2442 dedupe_hash += 1 

2443 else: 

2444 fallback_label_name = c._dedupe_anon_label_idx( 

2445 dedupe_hash 

2446 ) 

2447 dedupe_hash += 1 

2448 else: 

2449 fallback_label_name = c._anon_name_label 

2450 else: 

2451 required_label_name = effective_name = ( 

2452 fallback_label_name 

2453 ) = expr_label 

2454 

2455 if effective_name is not None: 

2456 if TYPE_CHECKING: 

2457 assert is_column_element(c) 

2458 

2459 if effective_name in names: 

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

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

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

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

2464 # different column under the same name. apply 

2465 # disambiguating label 

2466 if table_qualified: 

2467 required_label_name = fallback_label_name = ( 

2468 c._anon_tq_label 

2469 ) 

2470 else: 

2471 required_label_name = fallback_label_name = ( 

2472 c._anon_name_label 

2473 ) 

2474 

2475 if anon_for_dupe_key and required_label_name in names: 

2476 # here, c._anon_tq_label is definitely unique to 

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

2478 # this should always be true. 

2479 # this is also an infrequent codepath because 

2480 # you need two levels of duplication to be here 

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

2482 

2483 # the column under the disambiguating label is 

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

2485 # subsequent occurrences of the column so that the 

2486 # original stays non-ambiguous 

2487 if table_qualified: 

2488 required_label_name = fallback_label_name = ( 

2489 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2490 ) 

2491 dedupe_hash += 1 

2492 else: 

2493 required_label_name = fallback_label_name = ( 

2494 c._dedupe_anon_label_idx(dedupe_hash) 

2495 ) 

2496 dedupe_hash += 1 

2497 repeated = True 

2498 else: 

2499 names[required_label_name] = c 

2500 elif anon_for_dupe_key: 

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

2502 # label so that the original stays non-ambiguous 

2503 if table_qualified: 

2504 required_label_name = fallback_label_name = ( 

2505 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2506 ) 

2507 dedupe_hash += 1 

2508 else: 

2509 required_label_name = fallback_label_name = ( 

2510 c._dedupe_anon_label_idx(dedupe_hash) 

2511 ) 

2512 dedupe_hash += 1 

2513 repeated = True 

2514 else: 

2515 names[effective_name] = c 

2516 

2517 result_append( 

2518 _ColumnsPlusNames( 

2519 required_label_name, 

2520 key_naming_convention(c), 

2521 fallback_label_name, 

2522 c, 

2523 repeated, 

2524 ) 

2525 ) 

2526 

2527 return result 

2528 

2529 

2530class HasCTE(roles.HasCTERole, SelectsRows): 

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

2532 

2533 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2534 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2535 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2536 ] 

2537 

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

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

2540 

2541 name_cte_columns: bool = False 

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

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

2544 

2545 .. versionadded:: 2.0.42 

2546 

2547 """ 

2548 

2549 @_generative 

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

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

2552 

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

2554 the parent statement such that they will each be unconditionally 

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

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

2557 

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

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

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

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

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

2563 statement. 

2564 

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

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

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

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

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

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

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

2572 larger statement. 

2573 

2574 E.g.:: 

2575 

2576 from sqlalchemy import table, column, select 

2577 

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

2579 

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

2581 

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

2583 

2584 Would render: 

2585 

2586 .. sourcecode:: sql 

2587 

2588 WITH anon_1 AS ( 

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

2590 ) 

2591 SELECT t.c1, t.c2 

2592 FROM t 

2593 

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

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

2596 statement. 

2597 

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

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

2600 

2601 from sqlalchemy import table, column 

2602 from sqlalchemy.dialects.postgresql import insert 

2603 

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

2605 

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

2607 

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

2609 update_statement = insert_stmt.on_conflict_do_update( 

2610 index_elements=[t.c.c1], 

2611 set_={ 

2612 "c1": insert_stmt.excluded.c1, 

2613 "c2": insert_stmt.excluded.c2, 

2614 }, 

2615 ).add_cte(delete_statement_cte) 

2616 

2617 print(update_statement) 

2618 

2619 The above statement renders as: 

2620 

2621 .. sourcecode:: sql 

2622 

2623 WITH deletions AS ( 

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

2625 ) 

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

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

2628 

2629 .. versionadded:: 1.4.21 

2630 

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

2632 

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

2634 

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

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

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

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

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

2640 this statement when this flag is given. 

2641 

2642 .. versionadded:: 2.0 

2643 

2644 .. seealso:: 

2645 

2646 :paramref:`.HasCTE.cte.nesting` 

2647 

2648 

2649 """ # noqa: E501 

2650 opt = _CTEOpts(nest_here) 

2651 for cte in ctes: 

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

2653 self._independent_ctes += (cte,) 

2654 self._independent_ctes_opts += (opt,) 

2655 return self 

2656 

2657 def cte( 

2658 self, 

2659 name: Optional[str] = None, 

2660 recursive: bool = False, 

2661 nesting: bool = False, 

2662 ) -> CTE: 

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

2664 or Common Table Expression instance. 

2665 

2666 Common table expressions are a SQL standard whereby SELECT 

2667 statements can draw upon secondary statements specified along 

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

2669 Special semantics regarding UNION can also be employed to 

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

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

2672 

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

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

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

2676 CTE rows. 

2677 

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

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

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

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

2682 

2683 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2685 method may be 

2686 used to establish these. 

2687 

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

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

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

2691 compile time. 

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

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

2694 conjunction with UNION ALL in order to derive rows 

2695 from those already selected. 

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

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

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

2699 :paramref:`.HasCTE.add_cte.nest_here` 

2700 parameter may also be used to more carefully 

2701 control the exact placement of a particular CTE. 

2702 

2703 .. versionadded:: 1.4.24 

2704 

2705 .. seealso:: 

2706 

2707 :meth:`.HasCTE.add_cte` 

2708 

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

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

2711 as well as additional examples. 

2712 

2713 Example 1, non recursive:: 

2714 

2715 from sqlalchemy import ( 

2716 Table, 

2717 Column, 

2718 String, 

2719 Integer, 

2720 MetaData, 

2721 select, 

2722 func, 

2723 ) 

2724 

2725 metadata = MetaData() 

2726 

2727 orders = Table( 

2728 "orders", 

2729 metadata, 

2730 Column("region", String), 

2731 Column("amount", Integer), 

2732 Column("product", String), 

2733 Column("quantity", Integer), 

2734 ) 

2735 

2736 regional_sales = ( 

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

2738 .group_by(orders.c.region) 

2739 .cte("regional_sales") 

2740 ) 

2741 

2742 

2743 top_regions = ( 

2744 select(regional_sales.c.region) 

2745 .where( 

2746 regional_sales.c.total_sales 

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

2748 ) 

2749 .cte("top_regions") 

2750 ) 

2751 

2752 statement = ( 

2753 select( 

2754 orders.c.region, 

2755 orders.c.product, 

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

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

2758 ) 

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

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

2761 ) 

2762 

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

2764 

2765 Example 2, WITH RECURSIVE:: 

2766 

2767 from sqlalchemy import ( 

2768 Table, 

2769 Column, 

2770 String, 

2771 Integer, 

2772 MetaData, 

2773 select, 

2774 func, 

2775 ) 

2776 

2777 metadata = MetaData() 

2778 

2779 parts = Table( 

2780 "parts", 

2781 metadata, 

2782 Column("part", String), 

2783 Column("sub_part", String), 

2784 Column("quantity", Integer), 

2785 ) 

2786 

2787 included_parts = ( 

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

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

2790 .cte(recursive=True) 

2791 ) 

2792 

2793 

2794 incl_alias = included_parts.alias() 

2795 parts_alias = parts.alias() 

2796 included_parts = included_parts.union_all( 

2797 select( 

2798 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2800 ) 

2801 

2802 statement = select( 

2803 included_parts.c.sub_part, 

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

2805 ).group_by(included_parts.c.sub_part) 

2806 

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

2808 

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

2810 

2811 from datetime import date 

2812 from sqlalchemy import ( 

2813 MetaData, 

2814 Table, 

2815 Column, 

2816 Integer, 

2817 Date, 

2818 select, 

2819 literal, 

2820 and_, 

2821 exists, 

2822 ) 

2823 

2824 metadata = MetaData() 

2825 

2826 visitors = Table( 

2827 "visitors", 

2828 metadata, 

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

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

2831 Column("count", Integer), 

2832 ) 

2833 

2834 # add 5 visitors for the product_id == 1 

2835 product_id = 1 

2836 day = date.today() 

2837 count = 5 

2838 

2839 update_cte = ( 

2840 visitors.update() 

2841 .where( 

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

2843 ) 

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

2845 .returning(literal(1)) 

2846 .cte("update_cte") 

2847 ) 

2848 

2849 upsert = visitors.insert().from_select( 

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

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

2852 ~exists(update_cte.select()) 

2853 ), 

2854 ) 

2855 

2856 connection.execute(upsert) 

2857 

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

2859 

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

2861 

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

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

2864 "value_a", nesting=True 

2865 ) 

2866 

2867 # Nesting CTEs takes ascendency locally 

2868 # over the CTEs at a higher level 

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

2870 

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

2872 

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

2874 shown with inline parameters below as: 

2875 

2876 .. sourcecode:: sql 

2877 

2878 WITH 

2879 value_a AS 

2880 (SELECT 'root' AS n), 

2881 value_b AS 

2882 (WITH value_a AS 

2883 (SELECT 'nesting' AS n) 

2884 SELECT value_a.n AS n FROM value_a) 

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

2886 FROM value_a, value_b 

2887 

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

2889 as follows (SQLAlchemy 2.0 and above):: 

2890 

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

2892 

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

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

2895 

2896 # Nesting CTEs takes ascendency locally 

2897 # over the CTEs at a higher level 

2898 value_b = ( 

2899 select(value_a_nested.c.n) 

2900 .add_cte(value_a_nested, nest_here=True) 

2901 .cte("value_b") 

2902 ) 

2903 

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

2905 

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

2907 

2908 edge = Table( 

2909 "edge", 

2910 metadata, 

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

2912 Column("left", Integer), 

2913 Column("right", Integer), 

2914 ) 

2915 

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

2917 

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

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

2920 ) 

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

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

2923 ) 

2924 

2925 subgraph_cte = root_node.union(left_edge, right_edge) 

2926 

2927 subgraph = select(subgraph_cte) 

2928 

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

2930 

2931 .. sourcecode:: sql 

2932 

2933 WITH RECURSIVE nodes(node) AS ( 

2934 SELECT 1 AS node 

2935 UNION 

2936 SELECT edge."left" AS "left" 

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

2938 UNION 

2939 SELECT edge."right" AS "right" 

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

2941 ) 

2942 SELECT nodes.node FROM nodes 

2943 

2944 .. seealso:: 

2945 

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

2947 :meth:`_expression.HasCTE.cte`. 

2948 

2949 """ # noqa: E501 

2950 return CTE._construct( 

2951 self, name=name, recursive=recursive, nesting=nesting 

2952 ) 

2953 

2954 

2955class Subquery(AliasedReturnsRows): 

2956 """Represent a subquery of a SELECT. 

2957 

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

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

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

2961 :class:`_expression.SelectBase` subclass 

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

2963 :class:`_expression.CompoundSelect`, and 

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

2965 it represents the 

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

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

2968 

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

2970 :class:`_expression.Alias` 

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

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

2973 :class:`_expression.Alias` always 

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

2975 :class:`.Subquery` 

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

2977 

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

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

2980 statement. 

2981 

2982 """ 

2983 

2984 __visit_name__ = "subquery" 

2985 

2986 _is_subquery = True 

2987 

2988 inherit_cache = True 

2989 

2990 element: SelectBase 

2991 

2992 @classmethod 

2993 def _factory( 

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

2995 ) -> Subquery: 

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

2997 

2998 return coercions.expect( 

2999 roles.SelectStatementRole, selectable 

3000 ).subquery(name=name) 

3001 

3002 @util.deprecated( 

3003 "1.4", 

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

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

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

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

3008 ":func:`_expression.select` " 

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

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

3011 ) 

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

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

3014 

3015 

3016class FromGrouping(GroupedElement, FromClause): 

3017 """Represent a grouping of a FROM clause""" 

3018 

3019 _traverse_internals: _TraverseInternalsType = [ 

3020 ("element", InternalTraversal.dp_clauseelement) 

3021 ] 

3022 

3023 element: FromClause 

3024 

3025 def __init__(self, element: FromClause): 

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

3027 

3028 @util.ro_non_memoized_property 

3029 def columns( 

3030 self, 

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

3032 return self.element.columns 

3033 

3034 @util.ro_non_memoized_property 

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

3036 return self.element.columns 

3037 

3038 @property 

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

3040 return self.element.primary_key 

3041 

3042 @property 

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

3044 return self.element.foreign_keys 

3045 

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

3047 return self.element.is_derived_from(fromclause) 

3048 

3049 def alias( 

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

3051 ) -> NamedFromGrouping: 

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

3053 

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

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

3056 

3057 @util.ro_non_memoized_property 

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

3059 return self.element._hide_froms 

3060 

3061 @util.ro_non_memoized_property 

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

3063 return self.element._from_objects 

3064 

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

3066 return {"element": self.element} 

3067 

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

3069 self.element = state["element"] 

3070 

3071 if TYPE_CHECKING: 

3072 

3073 def self_group( 

3074 self, against: Optional[OperatorType] = None 

3075 ) -> Self: ... 

3076 

3077 

3078class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

3080 

3081 .. versionadded:: 2.0 

3082 

3083 """ 

3084 

3085 inherit_cache = True 

3086 

3087 if TYPE_CHECKING: 

3088 

3089 def self_group( 

3090 self, against: Optional[OperatorType] = None 

3091 ) -> Self: ... 

3092 

3093 

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

3095 """Represents a minimal "table" construct. 

3096 

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

3098 collection of columns, which are typically produced 

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

3100 

3101 from sqlalchemy import table, column 

3102 

3103 user = table( 

3104 "user", 

3105 column("id"), 

3106 column("name"), 

3107 column("description"), 

3108 ) 

3109 

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

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

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

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

3114 

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

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

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

3118 It's useful 

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

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

3121 is not on hand. 

3122 

3123 """ 

3124 

3125 __visit_name__ = "table" 

3126 

3127 _traverse_internals: _TraverseInternalsType = [ 

3128 ( 

3129 "columns", 

3130 InternalTraversal.dp_fromclause_canonical_column_collection, 

3131 ), 

3132 ("name", InternalTraversal.dp_string), 

3133 ("schema", InternalTraversal.dp_string), 

3134 ] 

3135 

3136 _is_table = True 

3137 

3138 fullname: str 

3139 

3140 implicit_returning = False 

3141 """:class:`_expression.TableClause` 

3142 doesn't support having a primary key or column 

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

3144 

3145 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3146 

3147 @util.ro_memoized_property 

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

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

3150 return None 

3151 

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

3153 super().__init__() 

3154 self.name = name 

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

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

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

3158 for c in columns: 

3159 self.append_column(c) 

3160 

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

3162 if schema is not None: 

3163 self.schema = schema 

3164 if self.schema is not None: 

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

3166 else: 

3167 self.fullname = self.name 

3168 if kw: 

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

3170 

3171 if TYPE_CHECKING: 

3172 

3173 @util.ro_non_memoized_property 

3174 def columns( 

3175 self, 

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

3177 

3178 @util.ro_non_memoized_property 

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

3180 

3181 def __str__(self) -> str: 

3182 if self.schema is not None: 

3183 return self.schema + "." + self.name 

3184 else: 

3185 return self.name 

3186 

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

3188 pass 

3189 

3190 @util.ro_memoized_property 

3191 def description(self) -> str: 

3192 return self.name 

3193 

3194 def _insert_col_impl( 

3195 self, 

3196 c: ColumnClause[Any], 

3197 *, 

3198 index: Optional[int] = None, 

3199 ) -> None: 

3200 existing = c.table 

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

3202 raise exc.ArgumentError( 

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

3204 % (c.key, existing) 

3205 ) 

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

3207 c.table = self 

3208 

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

3210 self._insert_col_impl(c) 

3211 

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

3213 self._insert_col_impl(c, index=index) 

3214 

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

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

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

3218 :class:`_expression.TableClause`. 

3219 

3220 E.g.:: 

3221 

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

3223 

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

3225 

3226 """ 

3227 

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

3229 

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

3231 def update(self) -> Update: 

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

3233 :class:`_expression.TableClause`. 

3234 

3235 E.g.:: 

3236 

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

3238 

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

3240 

3241 """ 

3242 return util.preloaded.sql_dml.Update( 

3243 self, 

3244 ) 

3245 

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

3247 def delete(self) -> Delete: 

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

3249 :class:`_expression.TableClause`. 

3250 

3251 E.g.:: 

3252 

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

3254 

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

3256 

3257 """ 

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

3259 

3260 @util.ro_non_memoized_property 

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

3262 return [self] 

3263 

3264 

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

3266 

3267 

3268class ForUpdateArg(ClauseElement): 

3269 _traverse_internals: _TraverseInternalsType = [ 

3270 ("of", InternalTraversal.dp_clauseelement_list), 

3271 ("nowait", InternalTraversal.dp_boolean), 

3272 ("read", InternalTraversal.dp_boolean), 

3273 ("skip_locked", InternalTraversal.dp_boolean), 

3274 ("key_share", InternalTraversal.dp_boolean), 

3275 ] 

3276 

3277 of: Optional[Sequence[ClauseElement]] 

3278 nowait: bool 

3279 read: bool 

3280 skip_locked: bool 

3281 

3282 @classmethod 

3283 def _from_argument( 

3284 cls, with_for_update: ForUpdateParameter 

3285 ) -> Optional[ForUpdateArg]: 

3286 if isinstance(with_for_update, ForUpdateArg): 

3287 return with_for_update 

3288 elif with_for_update in (None, False): 

3289 return None 

3290 elif with_for_update is True: 

3291 return ForUpdateArg() 

3292 else: 

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

3294 

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

3296 return ( 

3297 isinstance(other, ForUpdateArg) 

3298 and other.nowait == self.nowait 

3299 and other.read == self.read 

3300 and other.skip_locked == self.skip_locked 

3301 and other.key_share == self.key_share 

3302 and other.of is self.of 

3303 ) 

3304 

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

3306 return not self.__eq__(other) 

3307 

3308 def __hash__(self) -> int: 

3309 return id(self) 

3310 

3311 def __init__( 

3312 self, 

3313 *, 

3314 nowait: bool = False, 

3315 read: bool = False, 

3316 of: Optional[_ForUpdateOfArgument] = None, 

3317 skip_locked: bool = False, 

3318 key_share: bool = False, 

3319 ): 

3320 """Represents arguments specified to 

3321 :meth:`_expression.Select.for_update`. 

3322 

3323 """ 

3324 

3325 self.nowait = nowait 

3326 self.read = read 

3327 self.skip_locked = skip_locked 

3328 self.key_share = key_share 

3329 if of is not None: 

3330 self.of = [ 

3331 coercions.expect(roles.ColumnsClauseRole, elem) 

3332 for elem in util.to_list(of) 

3333 ] 

3334 else: 

3335 self.of = None 

3336 

3337 

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

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

3340 in a statement. 

3341 

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

3343 :func:`_expression.values` function. 

3344 

3345 .. versionadded:: 1.4 

3346 

3347 """ 

3348 

3349 __visit_name__ = "values" 

3350 

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

3352 

3353 _unnamed: bool 

3354 _traverse_internals: _TraverseInternalsType = [ 

3355 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3356 ("_data", InternalTraversal.dp_dml_multi_values), 

3357 ("name", InternalTraversal.dp_string), 

3358 ("literal_binds", InternalTraversal.dp_boolean), 

3359 ] + HasCTE._has_ctes_traverse_internals 

3360 

3361 name_cte_columns = True 

3362 

3363 def __init__( 

3364 self, 

3365 *columns: ColumnClause[Any], 

3366 name: Optional[str] = None, 

3367 literal_binds: bool = False, 

3368 ): 

3369 super().__init__() 

3370 self._column_args = columns 

3371 

3372 if name is None: 

3373 self._unnamed = True 

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

3375 else: 

3376 self._unnamed = False 

3377 self.name = name 

3378 self.literal_binds = literal_binds 

3379 self.named_with_column = not self._unnamed 

3380 

3381 @property 

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

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

3384 

3385 @util.ro_non_memoized_property 

3386 def _all_selected_columns(self) -> _SelectIterable: 

3387 return self._column_args 

3388 

3389 @_generative 

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

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

3392 construct that is a copy of this 

3393 one with the given name. 

3394 

3395 This method is a VALUES-specific specialization of the 

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

3397 

3398 .. seealso:: 

3399 

3400 :ref:`tutorial_using_aliases` 

3401 

3402 :func:`_expression.alias` 

3403 

3404 """ 

3405 non_none_name: str 

3406 

3407 if name is None: 

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

3409 else: 

3410 non_none_name = name 

3411 

3412 self.name = non_none_name 

3413 self.named_with_column = True 

3414 self._unnamed = False 

3415 return self 

3416 

3417 @_generative 

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

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

3420 so that 

3421 it renders as LATERAL. 

3422 

3423 .. seealso:: 

3424 

3425 :func:`_expression.lateral` 

3426 

3427 """ 

3428 non_none_name: str 

3429 

3430 if name is None: 

3431 non_none_name = self.name 

3432 else: 

3433 non_none_name = name 

3434 

3435 self._is_lateral = True 

3436 self.name = non_none_name 

3437 self._unnamed = False 

3438 return self 

3439 

3440 @_generative 

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

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

3443 adding the given data to the data list. 

3444 

3445 E.g.:: 

3446 

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

3448 

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

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

3451 constructor. 

3452 

3453 """ 

3454 

3455 self._data += (values,) 

3456 return self 

3457 

3458 def scalar_values(self) -> ScalarValues: 

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

3460 COLUMN element in a statement. 

3461 

3462 .. versionadded:: 2.0.0b4 

3463 

3464 """ 

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

3466 

3467 def _populate_column_collection( 

3468 self, 

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

3470 primary_key: ColumnSet, 

3471 foreign_keys: Set[KeyedColumnElement[Any]], 

3472 ) -> None: 

3473 for c in self._column_args: 

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

3475 _, c = c._make_proxy( 

3476 self, primary_key=primary_key, foreign_keys=foreign_keys 

3477 ) 

3478 else: 

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

3480 # no memoizations of other FROM clauses. 

3481 # see test_values.py -> test_auto_proxy_select_direct_col 

3482 c._reset_memoizations() 

3483 columns.add(c) 

3484 c.table = self 

3485 

3486 @util.ro_non_memoized_property 

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

3488 return [self] 

3489 

3490 

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

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

3493 COLUMN element in a statement. 

3494 

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

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

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

3498 an ``IN`` or ``NOT IN`` condition. 

3499 

3500 .. versionadded:: 2.0.0b4 

3501 

3502 """ 

3503 

3504 __visit_name__ = "scalar_values" 

3505 

3506 _traverse_internals: _TraverseInternalsType = [ 

3507 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3508 ("_data", InternalTraversal.dp_dml_multi_values), 

3509 ("literal_binds", InternalTraversal.dp_boolean), 

3510 ] 

3511 

3512 def __init__( 

3513 self, 

3514 columns: Sequence[ColumnClause[Any]], 

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

3516 literal_binds: bool, 

3517 ): 

3518 super().__init__() 

3519 self._column_args = columns 

3520 self._data = data 

3521 self.literal_binds = literal_binds 

3522 

3523 @property 

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

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

3526 

3527 def __clause_element__(self) -> ScalarValues: 

3528 return self 

3529 

3530 if TYPE_CHECKING: 

3531 

3532 def self_group( 

3533 self, against: Optional[OperatorType] = None 

3534 ) -> Self: ... 

3535 

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

3537 

3538 

3539class SelectBase( 

3540 roles.SelectStatementRole, 

3541 roles.DMLSelectRole, 

3542 roles.CompoundElementRole, 

3543 roles.InElementRole, 

3544 HasCTE, 

3545 SupportsCloneAnnotations, 

3546 Selectable, 

3547): 

3548 """Base class for SELECT statements. 

3549 

3550 

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

3552 :class:`_expression.CompoundSelect` and 

3553 :class:`_expression.TextualSelect`. 

3554 

3555 

3556 """ 

3557 

3558 _is_select_base = True 

3559 is_select = True 

3560 

3561 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3562 

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

3564 self._reset_memoizations() 

3565 

3566 @util.ro_non_memoized_property 

3567 def selected_columns( 

3568 self, 

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

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

3571 representing the columns that 

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

3573 

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

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

3576 within this collection cannot be directly nested inside another SELECT 

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

3578 necessary parenthesization required by SQL. 

3579 

3580 .. note:: 

3581 

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

3583 include expressions established in the columns clause using the 

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

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

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

3587 construct. 

3588 

3589 .. seealso:: 

3590 

3591 :attr:`_sql.Select.selected_columns` 

3592 

3593 .. versionadded:: 1.4 

3594 

3595 """ 

3596 raise NotImplementedError() 

3597 

3598 def _generate_fromclause_column_proxies( 

3599 self, 

3600 subquery: FromClause, 

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

3602 primary_key: ColumnSet, 

3603 foreign_keys: Set[KeyedColumnElement[Any]], 

3604 *, 

3605 proxy_compound_columns: Optional[ 

3606 Iterable[Sequence[ColumnElement[Any]]] 

3607 ] = None, 

3608 ) -> None: 

3609 raise NotImplementedError() 

3610 

3611 @util.ro_non_memoized_property 

3612 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3615 constructs. 

3616 

3617 .. versionadded:: 1.4.12 

3618 

3619 .. seealso:: 

3620 

3621 :attr:`_sql.SelectBase.exported_columns` 

3622 

3623 """ 

3624 raise NotImplementedError() 

3625 

3626 @property 

3627 def exported_columns( 

3628 self, 

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

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

3631 that represents the "exported" 

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

3633 :class:`_sql.TextClause` constructs. 

3634 

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

3636 object are synonymous 

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

3638 

3639 .. versionadded:: 1.4 

3640 

3641 .. seealso:: 

3642 

3643 :attr:`_expression.Select.exported_columns` 

3644 

3645 :attr:`_expression.Selectable.exported_columns` 

3646 

3647 :attr:`_expression.FromClause.exported_columns` 

3648 

3649 

3650 """ 

3651 return self.selected_columns.as_readonly() 

3652 

3653 def get_label_style(self) -> SelectLabelStyle: 

3654 """ 

3655 Retrieve the current label style. 

3656 

3657 Implemented by subclasses. 

3658 

3659 """ 

3660 raise NotImplementedError() 

3661 

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

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

3664 

3665 Implemented by subclasses. 

3666 

3667 """ 

3668 

3669 raise NotImplementedError() 

3670 

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

3672 raise NotImplementedError() 

3673 

3674 @util.deprecated( 

3675 "1.4", 

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

3677 "method is deprecated and will be " 

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

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

3680 ) 

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

3682 return self.scalar_subquery() 

3683 

3684 def exists(self) -> Exists: 

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

3686 which can be used as a column expression. 

3687 

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

3689 

3690 .. seealso:: 

3691 

3692 :func:`_sql.exists` 

3693 

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

3695 

3696 .. versionadded:: 1.4 

3697 

3698 """ 

3699 return Exists(self) 

3700 

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

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

3703 used as a column expression. 

3704 

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

3706 

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

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

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

3710 an enclosing SELECT. 

3711 

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

3713 subquery that can be produced using the 

3714 :meth:`_expression.SelectBase.subquery` 

3715 method. 

3716 

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

3718 :meth:`_expression.SelectBase.scalar_subquery`. 

3719 

3720 .. seealso:: 

3721 

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

3723 

3724 """ 

3725 if self._label_style is not LABEL_STYLE_NONE: 

3726 self = self.set_label_style(LABEL_STYLE_NONE) 

3727 

3728 return ScalarSelect(self) 

3729 

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

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

3732 subquery with a label. 

3733 

3734 .. seealso:: 

3735 

3736 :meth:`_expression.SelectBase.scalar_subquery`. 

3737 

3738 """ 

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

3740 

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

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

3743 

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

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

3746 

3747 .. seealso:: 

3748 

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

3750 

3751 """ 

3752 return Lateral._factory(self, name) 

3753 

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

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

3756 

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

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

3759 SELECT statement. 

3760 

3761 Given a SELECT statement such as:: 

3762 

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

3764 

3765 The above statement might look like: 

3766 

3767 .. sourcecode:: sql 

3768 

3769 SELECT table.id, table.name FROM table 

3770 

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

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

3773 a named sub-element:: 

3774 

3775 subq = stmt.subquery() 

3776 new_stmt = select(subq) 

3777 

3778 The above renders as: 

3779 

3780 .. sourcecode:: sql 

3781 

3782 SELECT anon_1.id, anon_1.name 

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

3784 

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

3786 is equivalent to calling 

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

3788 method on a FROM object; however, 

3789 as a :class:`_expression.SelectBase` 

3790 object is not directly FROM object, 

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

3792 method provides clearer semantics. 

3793 

3794 .. versionadded:: 1.4 

3795 

3796 """ 

3797 

3798 return Subquery._construct( 

3799 self._ensure_disambiguated_names(), name=name 

3800 ) 

3801 

3802 @util.preload_module("sqlalchemy.sql.ddl") 

3803 def into( 

3804 self, 

3805 target: str, 

3806 *, 

3807 metadata: Optional["MetaData"] = None, 

3808 schema: Optional[str] = None, 

3809 temporary: bool = False, 

3810 if_not_exists: bool = False, 

3811 ) -> CreateTableAs: 

3812 """Create a :class:`_schema.CreateTableAs` construct from this SELECT. 

3813 

3814 This method provides a convenient way to create a ``CREATE TABLE ... 

3815 AS`` statement from a SELECT, as well as compound SELECTs like UNION. 

3816 The new table will be created with columns matching the SELECT list. 

3817 

3818 Supported on all included backends, the construct emits 

3819 ``CREATE TABLE...AS`` for all backends except SQL Server, which instead 

3820 emits a ``SELECT..INTO`` statement. 

3821 

3822 e.g.:: 

3823 

3824 from sqlalchemy import select 

3825 

3826 # Create a new table from a SELECT 

3827 stmt = ( 

3828 select(users.c.id, users.c.name) 

3829 .where(users.c.status == "active") 

3830 .into("active_users") 

3831 ) 

3832 

3833 with engine.begin() as conn: 

3834 conn.execute(stmt) 

3835 

3836 # With optional flags 

3837 stmt = ( 

3838 select(users.c.id) 

3839 .where(users.c.status == "inactive") 

3840 .into("inactive_users", schema="analytics", if_not_exists=True) 

3841 ) 

3842 

3843 .. versionadded:: 2.1 

3844 

3845 :param target: Name of the table to create as a string. Must be 

3846 unqualified; use the ``schema`` parameter for qualification. 

3847 

3848 :param metadata: :class:`_schema.MetaData`, optional 

3849 If provided, the :class:`_schema.Table` object available via the 

3850 :attr:`.CreateTableAs.table` attribute will be associated with this 

3851 :class:`.MetaData`. Otherwise, a new, empty :class:`.MetaData` 

3852 is created. 

3853 

3854 :param schema: Optional schema name for the new table. 

3855 

3856 :param temporary: If True, create a temporary table where supported 

3857 

3858 :param if_not_exists: If True, add IF NOT EXISTS clause where supported 

3859 

3860 :return: A :class:`_schema.CreateTableAs` construct. 

3861 

3862 .. seealso:: 

3863 

3864 :ref:`metadata_create_table_as` - in :ref:`metadata_toplevel` 

3865 

3866 :class:`_schema.CreateTableAs` 

3867 

3868 """ 

3869 sql_ddl = util.preloaded.sql_ddl 

3870 

3871 return sql_ddl.CreateTableAs( 

3872 self, 

3873 target, 

3874 metadata=metadata, 

3875 schema=schema, 

3876 temporary=temporary, 

3877 if_not_exists=if_not_exists, 

3878 ) 

3879 

3880 def _ensure_disambiguated_names(self) -> Self: 

3881 """Ensure that the names generated by this selectbase will be 

3882 disambiguated in some way, if possible. 

3883 

3884 """ 

3885 

3886 raise NotImplementedError() 

3887 

3888 def alias( 

3889 self, name: Optional[str] = None, flat: bool = False 

3890 ) -> Subquery: 

3891 """Return a named subquery against this 

3892 :class:`_expression.SelectBase`. 

3893 

3894 For a :class:`_expression.SelectBase` (as opposed to a 

3895 :class:`_expression.FromClause`), 

3896 this returns a :class:`.Subquery` object which behaves mostly the 

3897 same as the :class:`_expression.Alias` object that is used with a 

3898 :class:`_expression.FromClause`. 

3899 

3900 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3901 method is now 

3902 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3903 

3904 """ 

3905 return self.subquery(name=name) 

3906 

3907 

3908_SB = TypeVar("_SB", bound=SelectBase) 

3909 

3910 

3911class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3912 """Represent a grouping of a :class:`_expression.SelectBase`. 

3913 

3914 This differs from :class:`.Subquery` in that we are still 

3915 an "inner" SELECT statement, this is strictly for grouping inside of 

3916 compound selects. 

3917 

3918 """ 

3919 

3920 __visit_name__ = "select_statement_grouping" 

3921 _traverse_internals: _TraverseInternalsType = [ 

3922 ("element", InternalTraversal.dp_clauseelement) 

3923 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

3924 

3925 _is_select_container = True 

3926 

3927 element: _SB 

3928 

3929 def __init__(self, element: _SB) -> None: 

3930 self.element = cast( 

3931 _SB, coercions.expect(roles.SelectStatementRole, element) 

3932 ) 

3933 

3934 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3935 new_element = self.element._ensure_disambiguated_names() 

3936 if new_element is not self.element: 

3937 return SelectStatementGrouping(new_element) 

3938 else: 

3939 return self 

3940 

3941 def get_label_style(self) -> SelectLabelStyle: 

3942 return self.element.get_label_style() 

3943 

3944 def set_label_style( 

3945 self, label_style: SelectLabelStyle 

3946 ) -> SelectStatementGrouping[_SB]: 

3947 return SelectStatementGrouping( 

3948 self.element.set_label_style(label_style) 

3949 ) 

3950 

3951 @property 

3952 def select_statement(self) -> _SB: 

3953 return self.element 

3954 

3955 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

3956 return self 

3957 

3958 if TYPE_CHECKING: 

3959 

3960 def _ungroup(self) -> _SB: ... 

3961 

3962 # def _generate_columns_plus_names( 

3963 # self, anon_for_dupe_key: bool 

3964 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3965 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3966 

3967 def _generate_fromclause_column_proxies( 

3968 self, 

3969 subquery: FromClause, 

3970 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

3971 primary_key: ColumnSet, 

3972 foreign_keys: Set[KeyedColumnElement[Any]], 

3973 *, 

3974 proxy_compound_columns: Optional[ 

3975 Iterable[Sequence[ColumnElement[Any]]] 

3976 ] = None, 

3977 ) -> None: 

3978 self.element._generate_fromclause_column_proxies( 

3979 subquery, 

3980 columns, 

3981 proxy_compound_columns=proxy_compound_columns, 

3982 primary_key=primary_key, 

3983 foreign_keys=foreign_keys, 

3984 ) 

3985 

3986 @util.ro_non_memoized_property 

3987 def _all_selected_columns(self) -> _SelectIterable: 

3988 return self.element._all_selected_columns 

3989 

3990 @util.ro_non_memoized_property 

3991 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

3992 """A :class:`_expression.ColumnCollection` 

3993 representing the columns that 

3994 the embedded SELECT statement returns in its result set, not including 

3995 :class:`_sql.TextClause` constructs. 

3996 

3997 .. versionadded:: 1.4 

3998 

3999 .. seealso:: 

4000 

4001 :attr:`_sql.Select.selected_columns` 

4002 

4003 """ 

4004 return self.element.selected_columns 

4005 

4006 @util.ro_non_memoized_property 

4007 def _from_objects(self) -> List[FromClause]: 

4008 return self.element._from_objects 

4009 

4010 def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self: 

4011 # SelectStatementGrouping not generative: has no attribute '_generate' 

4012 raise NotImplementedError 

4013 

4014 

4015class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

4016 """Base class for SELECT statements where additional elements can be 

4017 added. 

4018 

4019 This serves as the base for :class:`_expression.Select` and 

4020 :class:`_expression.CompoundSelect` 

4021 where elements such as ORDER BY, GROUP BY can be added and column 

4022 rendering can be controlled. Compare to 

4023 :class:`_expression.TextualSelect`, which, 

4024 while it subclasses :class:`_expression.SelectBase` 

4025 and is also a SELECT construct, 

4026 represents a fixed textual string which cannot be altered at this level, 

4027 only wrapped as a subquery. 

4028 

4029 """ 

4030 

4031 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

4032 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

4033 _limit_clause: Optional[ColumnElement[Any]] = None 

4034 _offset_clause: Optional[ColumnElement[Any]] = None 

4035 _fetch_clause: Optional[ColumnElement[Any]] = None 

4036 _fetch_clause_options: Optional[Dict[str, bool]] = None 

4037 _for_update_arg: Optional[ForUpdateArg] = None 

4038 

4039 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

4040 self._label_style = _label_style 

4041 

4042 @_generative 

4043 def with_for_update( 

4044 self, 

4045 *, 

4046 nowait: bool = False, 

4047 read: bool = False, 

4048 of: Optional[_ForUpdateOfArgument] = None, 

4049 skip_locked: bool = False, 

4050 key_share: bool = False, 

4051 ) -> Self: 

4052 """Specify a ``FOR UPDATE`` clause for this 

4053 :class:`_expression.GenerativeSelect`. 

4054 

4055 E.g.:: 

4056 

4057 stmt = select(table).with_for_update(nowait=True) 

4058 

4059 On a database like PostgreSQL or Oracle Database, the above would 

4060 render a statement like: 

4061 

4062 .. sourcecode:: sql 

4063 

4064 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

4065 

4066 on other backends, the ``nowait`` option is ignored and instead 

4067 would produce: 

4068 

4069 .. sourcecode:: sql 

4070 

4071 SELECT table.a, table.b FROM table FOR UPDATE 

4072 

4073 When called with no arguments, the statement will render with 

4074 the suffix ``FOR UPDATE``. Additional arguments can then be 

4075 provided which allow for common database-specific 

4076 variants. 

4077 

4078 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

4079 Database and PostgreSQL dialects. 

4080 

4081 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

4082 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

4083 ``nowait``, will render ``FOR SHARE NOWAIT``. 

4084 

4085 :param of: SQL expression or list of SQL expression elements, 

4086 (typically :class:`_schema.Column` objects or a compatible expression, 

4087 for some backends may also be a table expression) which will render 

4088 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4089 Database, some MySQL versions and possibly others. May render as a 

4090 table or as a column depending on backend. 

4091 

4092 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4093 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4094 if ``read=True`` is also specified. 

4095 

4096 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4097 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4098 on the PostgreSQL dialect. 

4099 

4100 """ 

4101 self._for_update_arg = ForUpdateArg( 

4102 nowait=nowait, 

4103 read=read, 

4104 of=of, 

4105 skip_locked=skip_locked, 

4106 key_share=key_share, 

4107 ) 

4108 return self 

4109 

4110 def get_label_style(self) -> SelectLabelStyle: 

4111 """ 

4112 Retrieve the current label style. 

4113 

4114 .. versionadded:: 1.4 

4115 

4116 """ 

4117 return self._label_style 

4118 

4119 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4120 """Return a new selectable with the specified label style. 

4121 

4122 There are three "label styles" available, 

4123 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4124 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4125 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4126 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4127 

4128 In modern SQLAlchemy, there is not generally a need to change the 

4129 labeling style, as per-expression labels are more effectively used by 

4130 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4131 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4132 disambiguate same-named columns from different tables, aliases, or 

4133 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4134 applies labels only to names that conflict with an existing name so 

4135 that the impact of this labeling is minimal. 

4136 

4137 The rationale for disambiguation is mostly so that all column 

4138 expressions are available from a given :attr:`_sql.FromClause.c` 

4139 collection when a subquery is created. 

4140 

4141 .. versionadded:: 1.4 - the 

4142 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4143 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4144 ``use_labels=True`` methods and/or parameters. 

4145 

4146 .. seealso:: 

4147 

4148 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4149 

4150 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL` 

4151 

4152 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE` 

4153 

4154 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DEFAULT` 

4155 

4156 """ 

4157 if self._label_style is not style: 

4158 self = self._generate() 

4159 self._label_style = style 

4160 return self 

4161 

4162 @property 

4163 def _group_by_clause(self) -> ClauseList: 

4164 """ClauseList access to group_by_clauses for legacy dialects""" 

4165 return ClauseList._construct_raw( 

4166 operators.comma_op, self._group_by_clauses 

4167 ) 

4168 

4169 @property 

4170 def _order_by_clause(self) -> ClauseList: 

4171 """ClauseList access to order_by_clauses for legacy dialects""" 

4172 return ClauseList._construct_raw( 

4173 operators.comma_op, self._order_by_clauses 

4174 ) 

4175 

4176 def _offset_or_limit_clause( 

4177 self, 

4178 element: _LimitOffsetType, 

4179 name: Optional[str] = None, 

4180 type_: Optional[_TypeEngineArgument[int]] = None, 

4181 ) -> ColumnElement[Any]: 

4182 """Convert the given value to an "offset or limit" clause. 

4183 

4184 This handles incoming integers and converts to an expression; if 

4185 an expression is already given, it is passed through. 

4186 

4187 """ 

4188 return coercions.expect( 

4189 roles.LimitOffsetRole, element, name=name, type_=type_ 

4190 ) 

4191 

4192 @overload 

4193 def _offset_or_limit_clause_asint( 

4194 self, clause: ColumnElement[Any], attrname: str 

4195 ) -> NoReturn: ... 

4196 

4197 @overload 

4198 def _offset_or_limit_clause_asint( 

4199 self, clause: Optional[_OffsetLimitParam], attrname: str 

4200 ) -> Optional[int]: ... 

4201 

4202 def _offset_or_limit_clause_asint( 

4203 self, clause: Optional[ColumnElement[Any]], attrname: str 

4204 ) -> Union[NoReturn, Optional[int]]: 

4205 """Convert the "offset or limit" clause of a select construct to an 

4206 integer. 

4207 

4208 This is only possible if the value is stored as a simple bound 

4209 parameter. Otherwise, a compilation error is raised. 

4210 

4211 """ 

4212 if clause is None: 

4213 return None 

4214 try: 

4215 value = clause._limit_offset_value 

4216 except AttributeError as err: 

4217 raise exc.CompileError( 

4218 "This SELECT structure does not use a simple " 

4219 "integer value for %s" % attrname 

4220 ) from err 

4221 else: 

4222 return util.asint(value) 

4223 

4224 @property 

4225 def _limit(self) -> Optional[int]: 

4226 """Get an integer value for the limit. This should only be used 

4227 by code that cannot support a limit as a BindParameter or 

4228 other custom clause as it will throw an exception if the limit 

4229 isn't currently set to an integer. 

4230 

4231 """ 

4232 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4233 

4234 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4235 """True if the clause is a simple integer, False 

4236 if it is not present or is a SQL expression. 

4237 """ 

4238 return isinstance(clause, _OffsetLimitParam) 

4239 

4240 @property 

4241 def _offset(self) -> Optional[int]: 

4242 """Get an integer value for the offset. This should only be used 

4243 by code that cannot support an offset as a BindParameter or 

4244 other custom clause as it will throw an exception if the 

4245 offset isn't currently set to an integer. 

4246 

4247 """ 

4248 return self._offset_or_limit_clause_asint( 

4249 self._offset_clause, "offset" 

4250 ) 

4251 

4252 @property 

4253 def _has_row_limiting_clause(self) -> bool: 

4254 return ( 

4255 self._limit_clause is not None 

4256 or self._offset_clause is not None 

4257 or self._fetch_clause is not None 

4258 ) 

4259 

4260 @_generative 

4261 def limit(self, limit: _LimitOffsetType) -> Self: 

4262 """Return a new selectable with the given LIMIT criterion 

4263 applied. 

4264 

4265 This is a numerical value which usually renders as a ``LIMIT`` 

4266 expression in the resulting select. Backends that don't 

4267 support ``LIMIT`` will attempt to provide similar 

4268 functionality. 

4269 

4270 .. note:: 

4271 

4272 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4273 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4274 

4275 :param limit: an integer LIMIT parameter, or a SQL expression 

4276 that provides an integer result. Pass ``None`` to reset it. 

4277 

4278 .. seealso:: 

4279 

4280 :meth:`_sql.GenerativeSelect.fetch` 

4281 

4282 :meth:`_sql.GenerativeSelect.offset` 

4283 

4284 """ 

4285 

4286 self._fetch_clause = self._fetch_clause_options = None 

4287 self._limit_clause = self._offset_or_limit_clause(limit) 

4288 return self 

4289 

4290 @_generative 

4291 def fetch( 

4292 self, 

4293 count: _LimitOffsetType, 

4294 with_ties: bool = False, 

4295 percent: bool = False, 

4296 **dialect_kw: Any, 

4297 ) -> Self: 

4298 r"""Return a new selectable with the given FETCH FIRST criterion 

4299 applied. 

4300 

4301 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4302 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4303 select. This functionality is is currently implemented for Oracle 

4304 Database, PostgreSQL, MSSQL. 

4305 

4306 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4307 

4308 .. note:: 

4309 

4310 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4311 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4312 

4313 .. versionadded:: 1.4 

4314 

4315 :param count: an integer COUNT parameter, or a SQL expression 

4316 that provides an integer result. When ``percent=True`` this will 

4317 represent the percentage of rows to return, not the absolute value. 

4318 Pass ``None`` to reset it. 

4319 

4320 :param with_ties: When ``True``, the WITH TIES option is used 

4321 to return any additional rows that tie for the last place in the 

4322 result set according to the ``ORDER BY`` clause. The 

4323 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4324 

4325 :param percent: When ``True``, ``count`` represents the percentage 

4326 of the total number of selected rows to return. Defaults to ``False`` 

4327 

4328 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4329 may be accepted by dialects. 

4330 

4331 .. versionadded:: 2.0.41 

4332 

4333 .. seealso:: 

4334 

4335 :meth:`_sql.GenerativeSelect.limit` 

4336 

4337 :meth:`_sql.GenerativeSelect.offset` 

4338 

4339 """ 

4340 self._validate_dialect_kwargs(dialect_kw) 

4341 self._limit_clause = None 

4342 if count is None: 

4343 self._fetch_clause = self._fetch_clause_options = None 

4344 else: 

4345 self._fetch_clause = self._offset_or_limit_clause(count) 

4346 self._fetch_clause_options = { 

4347 "with_ties": with_ties, 

4348 "percent": percent, 

4349 } 

4350 return self 

4351 

4352 @_generative 

4353 def offset(self, offset: _LimitOffsetType) -> Self: 

4354 """Return a new selectable with the given OFFSET criterion 

4355 applied. 

4356 

4357 

4358 This is a numeric value which usually renders as an ``OFFSET`` 

4359 expression in the resulting select. Backends that don't 

4360 support ``OFFSET`` will attempt to provide similar 

4361 functionality. 

4362 

4363 :param offset: an integer OFFSET parameter, or a SQL expression 

4364 that provides an integer result. Pass ``None`` to reset it. 

4365 

4366 .. seealso:: 

4367 

4368 :meth:`_sql.GenerativeSelect.limit` 

4369 

4370 :meth:`_sql.GenerativeSelect.fetch` 

4371 

4372 """ 

4373 

4374 self._offset_clause = self._offset_or_limit_clause(offset) 

4375 return self 

4376 

4377 @_generative 

4378 @util.preload_module("sqlalchemy.sql.util") 

4379 def slice( 

4380 self, 

4381 start: int, 

4382 stop: int, 

4383 ) -> Self: 

4384 """Apply LIMIT / OFFSET to this statement based on a slice. 

4385 

4386 The start and stop indices behave like the argument to Python's 

4387 built-in :func:`range` function. This method provides an 

4388 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4389 query. 

4390 

4391 For example, :: 

4392 

4393 stmt = select(User).order_by(User.id).slice(1, 3) 

4394 

4395 renders as 

4396 

4397 .. sourcecode:: sql 

4398 

4399 SELECT users.id AS users_id, 

4400 users.name AS users_name 

4401 FROM users ORDER BY users.id 

4402 LIMIT ? OFFSET ? 

4403 (2, 1) 

4404 

4405 .. note:: 

4406 

4407 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4408 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4409 

4410 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4411 method generalized from the ORM. 

4412 

4413 .. seealso:: 

4414 

4415 :meth:`_sql.GenerativeSelect.limit` 

4416 

4417 :meth:`_sql.GenerativeSelect.offset` 

4418 

4419 :meth:`_sql.GenerativeSelect.fetch` 

4420 

4421 """ 

4422 sql_util = util.preloaded.sql_util 

4423 self._fetch_clause = self._fetch_clause_options = None 

4424 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4425 self._limit_clause, self._offset_clause, start, stop 

4426 ) 

4427 return self 

4428 

4429 @_generative 

4430 def order_by( 

4431 self, 

4432 __first: Union[ 

4433 Literal[None, _NoArg.NO_ARG], 

4434 _ColumnExpressionOrStrLabelArgument[Any], 

4435 ] = _NoArg.NO_ARG, 

4436 /, 

4437 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4438 ) -> Self: 

4439 r"""Return a new selectable with the given list of ORDER BY 

4440 criteria applied. 

4441 

4442 e.g.:: 

4443 

4444 stmt = select(table).order_by(table.c.id, table.c.name) 

4445 

4446 Calling this method multiple times is equivalent to calling it once 

4447 with all the clauses concatenated. All existing ORDER BY criteria may 

4448 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4449 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4450 

4451 # will erase all ORDER BY and ORDER BY new_col alone 

4452 stmt = stmt.order_by(None).order_by(new_col) 

4453 

4454 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4455 constructs which will be used to generate an ORDER BY clause. 

4456 

4457 Alternatively, an individual entry may also be the string name of a 

4458 label located elsewhere in the columns clause of the statement which 

4459 will be matched and rendered in a backend-specific way based on 

4460 context; see :ref:`tutorial_order_by_label` for background on string 

4461 label matching in ORDER BY and GROUP BY expressions. 

4462 

4463 .. seealso:: 

4464 

4465 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4466 

4467 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4468 

4469 """ 

4470 

4471 if not clauses and __first is None: 

4472 self._order_by_clauses = () 

4473 elif __first is not _NoArg.NO_ARG: 

4474 self._order_by_clauses += tuple( 

4475 coercions.expect( 

4476 roles.OrderByRole, clause, apply_propagate_attrs=self 

4477 ) 

4478 for clause in (__first,) + clauses 

4479 ) 

4480 return self 

4481 

4482 @_generative 

4483 def group_by( 

4484 self, 

4485 __first: Union[ 

4486 Literal[None, _NoArg.NO_ARG], 

4487 _ColumnExpressionOrStrLabelArgument[Any], 

4488 ] = _NoArg.NO_ARG, 

4489 /, 

4490 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4491 ) -> Self: 

4492 r"""Return a new selectable with the given list of GROUP BY 

4493 criterion applied. 

4494 

4495 All existing GROUP BY settings can be suppressed by passing ``None``. 

4496 

4497 e.g.:: 

4498 

4499 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4500 

4501 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4502 constructs which will be used to generate an GROUP BY clause. 

4503 

4504 Alternatively, an individual entry may also be the string name of a 

4505 label located elsewhere in the columns clause of the statement which 

4506 will be matched and rendered in a backend-specific way based on 

4507 context; see :ref:`tutorial_order_by_label` for background on string 

4508 label matching in ORDER BY and GROUP BY expressions. 

4509 

4510 .. seealso:: 

4511 

4512 :ref:`tutorial_group_by_w_aggregates` - in the 

4513 :ref:`unified_tutorial` 

4514 

4515 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4516 

4517 """ # noqa: E501 

4518 

4519 if not clauses and __first is None: 

4520 self._group_by_clauses = () 

4521 elif __first is not _NoArg.NO_ARG: 

4522 self._group_by_clauses += tuple( 

4523 coercions.expect( 

4524 roles.GroupByRole, clause, apply_propagate_attrs=self 

4525 ) 

4526 for clause in (__first,) + clauses 

4527 ) 

4528 return self 

4529 

4530 

4531@CompileState.plugin_for("default", "compound_select") 

4532class CompoundSelectState(CompileState): 

4533 @util.memoized_property 

4534 def _label_resolve_dict( 

4535 self, 

4536 ) -> Tuple[ 

4537 Dict[str, ColumnElement[Any]], 

4538 Dict[str, ColumnElement[Any]], 

4539 Dict[str, ColumnElement[Any]], 

4540 ]: 

4541 # TODO: this is hacky and slow 

4542 hacky_subquery = self.statement.subquery() 

4543 hacky_subquery.named_with_column = False 

4544 d = {c.key: c for c in hacky_subquery.c} 

4545 return d, d, d 

4546 

4547 

4548class _CompoundSelectKeyword(Enum): 

4549 UNION = "UNION" 

4550 UNION_ALL = "UNION ALL" 

4551 EXCEPT = "EXCEPT" 

4552 EXCEPT_ALL = "EXCEPT ALL" 

4553 INTERSECT = "INTERSECT" 

4554 INTERSECT_ALL = "INTERSECT ALL" 

4555 

4556 

4557class CompoundSelect( 

4558 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4559): 

4560 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4561 SELECT-based set operations. 

4562 

4563 

4564 .. seealso:: 

4565 

4566 :func:`_expression.union` 

4567 

4568 :func:`_expression.union_all` 

4569 

4570 :func:`_expression.intersect` 

4571 

4572 :func:`_expression.intersect_all` 

4573 

4574 :func:`_expression.except` 

4575 

4576 :func:`_expression.except_all` 

4577 

4578 """ 

4579 

4580 __visit_name__ = "compound_select" 

4581 

4582 _traverse_internals: _TraverseInternalsType = ( 

4583 [ 

4584 ("selects", InternalTraversal.dp_clauseelement_list), 

4585 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4586 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4587 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4588 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4589 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4590 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4591 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4592 ("keyword", InternalTraversal.dp_string), 

4593 ] 

4594 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4595 + HasCTE._has_ctes_traverse_internals 

4596 + DialectKWArgs._dialect_kwargs_traverse_internals 

4597 + ExecutableStatement._executable_traverse_internals 

4598 ) 

4599 

4600 selects: List[SelectBase] 

4601 

4602 _is_from_container = True 

4603 _auto_correlate = False 

4604 

4605 def __init__( 

4606 self, 

4607 keyword: _CompoundSelectKeyword, 

4608 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4609 ): 

4610 self.keyword = keyword 

4611 self.selects = [ 

4612 coercions.expect( 

4613 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4614 ).self_group(against=self) 

4615 for s in selects 

4616 ] 

4617 

4618 GenerativeSelect.__init__(self) 

4619 

4620 @classmethod 

4621 def _create_union( 

4622 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4623 ) -> CompoundSelect[Unpack[_Ts]]: 

4624 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4625 

4626 @classmethod 

4627 def _create_union_all( 

4628 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4629 ) -> CompoundSelect[Unpack[_Ts]]: 

4630 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4631 

4632 @classmethod 

4633 def _create_except( 

4634 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4635 ) -> CompoundSelect[Unpack[_Ts]]: 

4636 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4637 

4638 @classmethod 

4639 def _create_except_all( 

4640 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4641 ) -> CompoundSelect[Unpack[_Ts]]: 

4642 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4643 

4644 @classmethod 

4645 def _create_intersect( 

4646 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4647 ) -> CompoundSelect[Unpack[_Ts]]: 

4648 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4649 

4650 @classmethod 

4651 def _create_intersect_all( 

4652 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4653 ) -> CompoundSelect[Unpack[_Ts]]: 

4654 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4655 

4656 def _scalar_type(self) -> TypeEngine[Any]: 

4657 return self.selects[0]._scalar_type() 

4658 

4659 def self_group( 

4660 self, against: Optional[OperatorType] = None 

4661 ) -> GroupedElement: 

4662 return SelectStatementGrouping(self) 

4663 

4664 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

4665 for s in self.selects: 

4666 if s.is_derived_from(fromclause): 

4667 return True 

4668 return False 

4669 

4670 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4671 if self._label_style is not style: 

4672 self = self._generate() 

4673 select_0 = self.selects[0].set_label_style(style) 

4674 self.selects = [select_0] + self.selects[1:] 

4675 

4676 return self 

4677 

4678 def _ensure_disambiguated_names(self) -> Self: 

4679 new_select = self.selects[0]._ensure_disambiguated_names() 

4680 if new_select is not self.selects[0]: 

4681 self = self._generate() 

4682 self.selects = [new_select] + self.selects[1:] 

4683 

4684 return self 

4685 

4686 def _generate_fromclause_column_proxies( 

4687 self, 

4688 subquery: FromClause, 

4689 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

4690 primary_key: ColumnSet, 

4691 foreign_keys: Set[KeyedColumnElement[Any]], 

4692 *, 

4693 proxy_compound_columns: Optional[ 

4694 Iterable[Sequence[ColumnElement[Any]]] 

4695 ] = None, 

4696 ) -> None: 

4697 # this is a slightly hacky thing - the union exports a 

4698 # column that resembles just that of the *first* selectable. 

4699 # to get at a "composite" column, particularly foreign keys, 

4700 # you have to dig through the proxies collection which we 

4701 # generate below. 

4702 select_0 = self.selects[0] 

4703 

4704 if self._label_style is not LABEL_STYLE_DEFAULT: 

4705 select_0 = select_0.set_label_style(self._label_style) 

4706 

4707 # hand-construct the "_proxies" collection to include all 

4708 # derived columns place a 'weight' annotation corresponding 

4709 # to how low in the list of select()s the column occurs, so 

4710 # that the corresponding_column() operation can resolve 

4711 # conflicts 

4712 extra_col_iterator = zip( 

4713 *[ 

4714 [ 

4715 c._annotate(dd) 

4716 for c in stmt._all_selected_columns 

4717 if is_column_element(c) 

4718 ] 

4719 for dd, stmt in [ 

4720 ({"weight": i + 1}, stmt) 

4721 for i, stmt in enumerate(self.selects) 

4722 ] 

4723 ] 

4724 ) 

4725 

4726 # the incoming proxy_compound_columns can be present also if this is 

4727 # a compound embedded in a compound. it's probably more appropriate 

4728 # that we generate new weights local to this nested compound, though 

4729 # i haven't tried to think what it means for compound nested in 

4730 # compound 

4731 select_0._generate_fromclause_column_proxies( 

4732 subquery, 

4733 columns, 

4734 proxy_compound_columns=extra_col_iterator, 

4735 primary_key=primary_key, 

4736 foreign_keys=foreign_keys, 

4737 ) 

4738 

4739 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

4740 super()._refresh_for_new_column(column) 

4741 for select in self.selects: 

4742 select._refresh_for_new_column(column) 

4743 

4744 @util.ro_non_memoized_property 

4745 def _all_selected_columns(self) -> _SelectIterable: 

4746 return self.selects[0]._all_selected_columns 

4747 

4748 @util.ro_non_memoized_property 

4749 def selected_columns( 

4750 self, 

4751 ) -> ColumnCollection[str, ColumnElement[Any]]: 

4752 """A :class:`_expression.ColumnCollection` 

4753 representing the columns that 

4754 this SELECT statement or similar construct returns in its result set, 

4755 not including :class:`_sql.TextClause` constructs. 

4756 

4757 For a :class:`_expression.CompoundSelect`, the 

4758 :attr:`_expression.CompoundSelect.selected_columns` 

4759 attribute returns the selected 

4760 columns of the first SELECT statement contained within the series of 

4761 statements within the set operation. 

4762 

4763 .. seealso:: 

4764 

4765 :attr:`_sql.Select.selected_columns` 

4766 

4767 .. versionadded:: 1.4 

4768 

4769 """ 

4770 return self.selects[0].selected_columns 

4771 

4772 

4773# backwards compat 

4774for elem in _CompoundSelectKeyword: 

4775 setattr(CompoundSelect, elem.name, elem) 

4776 

4777 

4778@CompileState.plugin_for("default", "select") 

4779class SelectState(util.MemoizedSlots, CompileState): 

4780 __slots__ = ( 

4781 "from_clauses", 

4782 "froms", 

4783 "columns_plus_names", 

4784 "_label_resolve_dict", 

4785 ) 

4786 

4787 if TYPE_CHECKING: 

4788 default_select_compile_options: CacheableOptions 

4789 else: 

4790 

4791 class default_select_compile_options(CacheableOptions): 

4792 _cache_key_traversal = [] 

4793 

4794 if TYPE_CHECKING: 

4795 

4796 @classmethod 

4797 def get_plugin_class( 

4798 cls, statement: Executable 

4799 ) -> Type[SelectState]: ... 

4800 

4801 def __init__( 

4802 self, 

4803 statement: Select[Unpack[TupleAny]], 

4804 compiler: SQLCompiler, 

4805 **kw: Any, 

4806 ): 

4807 self.statement = statement 

4808 self.from_clauses = statement._from_obj 

4809 

4810 for memoized_entities in statement._memoized_select_entities: 

4811 self._setup_joins( 

4812 memoized_entities._setup_joins, memoized_entities._raw_columns 

4813 ) 

4814 

4815 if statement._setup_joins: 

4816 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4817 

4818 self.froms = self._get_froms(statement) 

4819 

4820 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4821 

4822 @classmethod 

4823 def _plugin_not_implemented(cls) -> NoReturn: 

4824 raise NotImplementedError( 

4825 "The default SELECT construct without plugins does not " 

4826 "implement this method." 

4827 ) 

4828 

4829 @classmethod 

4830 def get_column_descriptions( 

4831 cls, statement: Select[Unpack[TupleAny]] 

4832 ) -> List[Dict[str, Any]]: 

4833 return [ 

4834 { 

4835 "name": name, 

4836 "type": element.type, 

4837 "expr": element, 

4838 } 

4839 for _, name, _, element, _ in ( 

4840 statement._generate_columns_plus_names(False) 

4841 ) 

4842 ] 

4843 

4844 @classmethod 

4845 def from_statement( 

4846 cls, 

4847 statement: Select[Unpack[TupleAny]], 

4848 from_statement: roles.ReturnsRowsRole, 

4849 ) -> ExecutableReturnsRows: 

4850 cls._plugin_not_implemented() 

4851 

4852 @classmethod 

4853 def get_columns_clause_froms( 

4854 cls, statement: Select[Unpack[TupleAny]] 

4855 ) -> List[FromClause]: 

4856 return cls._normalize_froms( 

4857 itertools.chain.from_iterable( 

4858 element._from_objects for element in statement._raw_columns 

4859 ) 

4860 ) 

4861 

4862 @classmethod 

4863 def _column_naming_convention( 

4864 cls, label_style: SelectLabelStyle 

4865 ) -> _LabelConventionCallable: 

4866 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4867 

4868 dedupe = label_style is not LABEL_STYLE_NONE 

4869 

4870 pa = prefix_anon_map() 

4871 names = set() 

4872 

4873 def go( 

4874 c: Union[ColumnElement[Any], TextClause], 

4875 col_name: Optional[str] = None, 

4876 ) -> Optional[str]: 

4877 if is_text_clause(c): 

4878 return None 

4879 elif TYPE_CHECKING: 

4880 assert is_column_element(c) 

4881 

4882 if not dedupe: 

4883 name = c._proxy_key 

4884 if name is None: 

4885 name = "_no_label" 

4886 return name 

4887 

4888 name = c._tq_key_label if table_qualified else c._proxy_key 

4889 

4890 if name is None: 

4891 name = "_no_label" 

4892 if name in names: 

4893 return c._anon_label(name) % pa 

4894 else: 

4895 names.add(name) 

4896 return name 

4897 

4898 elif name in names: 

4899 return ( 

4900 c._anon_tq_key_label % pa 

4901 if table_qualified 

4902 else c._anon_key_label % pa 

4903 ) 

4904 else: 

4905 names.add(name) 

4906 return name 

4907 

4908 return go 

4909 

4910 def _get_froms( 

4911 self, statement: Select[Unpack[TupleAny]] 

4912 ) -> List[FromClause]: 

4913 ambiguous_table_name_map: _AmbiguousTableNameMap 

4914 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4915 

4916 return self._normalize_froms( 

4917 itertools.chain( 

4918 self.from_clauses, 

4919 itertools.chain.from_iterable( 

4920 [ 

4921 element._from_objects 

4922 for element in statement._raw_columns 

4923 ] 

4924 ), 

4925 itertools.chain.from_iterable( 

4926 [ 

4927 element._from_objects 

4928 for element in statement._where_criteria 

4929 ] 

4930 ), 

4931 ), 

4932 check_statement=statement, 

4933 ambiguous_table_name_map=ambiguous_table_name_map, 

4934 ) 

4935 

4936 @classmethod 

4937 def _normalize_froms( 

4938 cls, 

4939 iterable_of_froms: Iterable[FromClause], 

4940 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4941 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4942 ) -> List[FromClause]: 

4943 """given an iterable of things to select FROM, reduce them to what 

4944 would actually render in the FROM clause of a SELECT. 

4945 

4946 This does the job of checking for JOINs, tables, etc. that are in fact 

4947 overlapping due to cloning, adaption, present in overlapping joins, 

4948 etc. 

4949 

4950 """ 

4951 seen: Set[FromClause] = set() 

4952 froms: List[FromClause] = [] 

4953 

4954 for item in iterable_of_froms: 

4955 if is_subquery(item) and item.element is check_statement: 

4956 raise exc.InvalidRequestError( 

4957 "select() construct refers to itself as a FROM" 

4958 ) 

4959 

4960 if not seen.intersection(item._cloned_set): 

4961 froms.append(item) 

4962 seen.update(item._cloned_set) 

4963 

4964 if froms: 

4965 toremove = set( 

4966 itertools.chain.from_iterable( 

4967 [_expand_cloned(f._hide_froms) for f in froms] 

4968 ) 

4969 ) 

4970 if toremove: 

4971 # filter out to FROM clauses not in the list, 

4972 # using a list to maintain ordering 

4973 froms = [f for f in froms if f not in toremove] 

4974 

4975 if ambiguous_table_name_map is not None: 

4976 ambiguous_table_name_map.update( 

4977 ( 

4978 fr.name, 

4979 _anonymous_label.safe_construct( 

4980 hash(fr.name), fr.name 

4981 ), 

4982 ) 

4983 for item in froms 

4984 for fr in item._from_objects 

4985 if is_table(fr) 

4986 and fr.schema 

4987 and fr.name not in ambiguous_table_name_map 

4988 ) 

4989 

4990 return froms 

4991 

4992 def _get_display_froms( 

4993 self, 

4994 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4995 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4996 ) -> List[FromClause]: 

4997 """Return the full list of 'from' clauses to be displayed. 

4998 

4999 Takes into account a set of existing froms which may be 

5000 rendered in the FROM clause of enclosing selects; this Select 

5001 may want to leave those absent if it is automatically 

5002 correlating. 

5003 

5004 """ 

5005 

5006 froms = self.froms 

5007 

5008 if self.statement._correlate: 

5009 to_correlate = self.statement._correlate 

5010 if to_correlate: 

5011 froms = [ 

5012 f 

5013 for f in froms 

5014 if f 

5015 not in _cloned_intersection( 

5016 _cloned_intersection( 

5017 froms, explicit_correlate_froms or () 

5018 ), 

5019 to_correlate, 

5020 ) 

5021 ] 

5022 

5023 if self.statement._correlate_except is not None: 

5024 froms = [ 

5025 f 

5026 for f in froms 

5027 if f 

5028 not in _cloned_difference( 

5029 _cloned_intersection( 

5030 froms, explicit_correlate_froms or () 

5031 ), 

5032 self.statement._correlate_except, 

5033 ) 

5034 ] 

5035 

5036 if ( 

5037 self.statement._auto_correlate 

5038 and implicit_correlate_froms 

5039 and len(froms) > 1 

5040 ): 

5041 froms = [ 

5042 f 

5043 for f in froms 

5044 if f 

5045 not in _cloned_intersection(froms, implicit_correlate_froms) 

5046 ] 

5047 

5048 if not len(froms): 

5049 raise exc.InvalidRequestError( 

5050 "Select statement '%r" 

5051 "' returned no FROM clauses " 

5052 "due to auto-correlation; " 

5053 "specify correlate(<tables>) " 

5054 "to control correlation " 

5055 "manually." % self.statement 

5056 ) 

5057 

5058 return froms 

5059 

5060 def _memoized_attr__label_resolve_dict( 

5061 self, 

5062 ) -> Tuple[ 

5063 Dict[str, ColumnElement[Any]], 

5064 Dict[str, ColumnElement[Any]], 

5065 Dict[str, ColumnElement[Any]], 

5066 ]: 

5067 with_cols: Dict[str, ColumnElement[Any]] = { 

5068 c._tq_label or c.key: c 

5069 for c in self.statement._all_selected_columns 

5070 if c._allow_label_resolve 

5071 } 

5072 only_froms: Dict[str, ColumnElement[Any]] = { 

5073 c.key: c # type: ignore 

5074 for c in _select_iterables(self.froms) 

5075 if c._allow_label_resolve 

5076 } 

5077 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

5078 for key, value in only_froms.items(): 

5079 with_cols.setdefault(key, value) 

5080 

5081 return with_cols, only_froms, only_cols 

5082 

5083 @classmethod 

5084 def determine_last_joined_entity( 

5085 cls, stmt: Select[Unpack[TupleAny]] 

5086 ) -> Optional[_JoinTargetElement]: 

5087 if stmt._setup_joins: 

5088 return stmt._setup_joins[-1][0] 

5089 else: 

5090 return None 

5091 

5092 @classmethod 

5093 def all_selected_columns( 

5094 cls, statement: Select[Unpack[TupleAny]] 

5095 ) -> _SelectIterable: 

5096 return [c for c in _select_iterables(statement._raw_columns)] 

5097 

5098 def _setup_joins( 

5099 self, 

5100 args: Tuple[_SetupJoinsElement, ...], 

5101 raw_columns: List[_ColumnsClauseElement], 

5102 ) -> None: 

5103 for right, onclause, left, flags in args: 

5104 if TYPE_CHECKING: 

5105 if onclause is not None: 

5106 assert isinstance(onclause, ColumnElement) 

5107 

5108 explicit_left = left 

5109 isouter = flags["isouter"] 

5110 full = flags["full"] 

5111 

5112 if left is None: 

5113 ( 

5114 left, 

5115 replace_from_obj_index, 

5116 ) = self._join_determine_implicit_left_side( 

5117 raw_columns, left, right, onclause 

5118 ) 

5119 else: 

5120 (replace_from_obj_index) = self._join_place_explicit_left_side( 

5121 left 

5122 ) 

5123 

5124 # these assertions can be made here, as if the right/onclause 

5125 # contained ORM elements, the select() statement would have been 

5126 # upgraded to an ORM select, and this method would not be called; 

5127 # orm.context.ORMSelectCompileState._join() would be 

5128 # used instead. 

5129 if TYPE_CHECKING: 

5130 assert isinstance(right, FromClause) 

5131 if onclause is not None: 

5132 assert isinstance(onclause, ColumnElement) 

5133 

5134 if replace_from_obj_index is not None: 

5135 # splice into an existing element in the 

5136 # self._from_obj list 

5137 left_clause = self.from_clauses[replace_from_obj_index] 

5138 

5139 if explicit_left is not None and onclause is None: 

5140 onclause = Join._join_condition(explicit_left, right) 

5141 

5142 self.from_clauses = ( 

5143 self.from_clauses[:replace_from_obj_index] 

5144 + ( 

5145 Join( 

5146 left_clause, 

5147 right, 

5148 onclause, 

5149 isouter=isouter, 

5150 full=full, 

5151 ), 

5152 ) 

5153 + self.from_clauses[replace_from_obj_index + 1 :] 

5154 ) 

5155 else: 

5156 assert left is not None 

5157 self.from_clauses = self.from_clauses + ( 

5158 Join(left, right, onclause, isouter=isouter, full=full), 

5159 ) 

5160 

5161 @util.preload_module("sqlalchemy.sql.util") 

5162 def _join_determine_implicit_left_side( 

5163 self, 

5164 raw_columns: List[_ColumnsClauseElement], 

5165 left: Optional[FromClause], 

5166 right: _JoinTargetElement, 

5167 onclause: Optional[ColumnElement[Any]], 

5168 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5169 """When join conditions don't express the left side explicitly, 

5170 determine if an existing FROM or entity in this query 

5171 can serve as the left hand side. 

5172 

5173 """ 

5174 

5175 sql_util = util.preloaded.sql_util 

5176 

5177 replace_from_obj_index: Optional[int] = None 

5178 

5179 from_clauses = self.from_clauses 

5180 

5181 if from_clauses: 

5182 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5183 from_clauses, right, onclause 

5184 ) 

5185 

5186 if len(indexes) == 1: 

5187 replace_from_obj_index = indexes[0] 

5188 left = from_clauses[replace_from_obj_index] 

5189 else: 

5190 potential = {} 

5191 statement = self.statement 

5192 

5193 for from_clause in itertools.chain( 

5194 itertools.chain.from_iterable( 

5195 [element._from_objects for element in raw_columns] 

5196 ), 

5197 itertools.chain.from_iterable( 

5198 [ 

5199 element._from_objects 

5200 for element in statement._where_criteria 

5201 ] 

5202 ), 

5203 ): 

5204 potential[from_clause] = () 

5205 

5206 all_clauses = list(potential.keys()) 

5207 indexes = sql_util.find_left_clause_to_join_from( 

5208 all_clauses, right, onclause 

5209 ) 

5210 

5211 if len(indexes) == 1: 

5212 left = all_clauses[indexes[0]] 

5213 

5214 if len(indexes) > 1: 

5215 raise exc.InvalidRequestError( 

5216 "Can't determine which FROM clause to join " 

5217 "from, there are multiple FROMS which can " 

5218 "join to this entity. Please use the .select_from() " 

5219 "method to establish an explicit left side, as well as " 

5220 "providing an explicit ON clause if not present already to " 

5221 "help resolve the ambiguity." 

5222 ) 

5223 elif not indexes: 

5224 raise exc.InvalidRequestError( 

5225 "Don't know how to join to %r. " 

5226 "Please use the .select_from() " 

5227 "method to establish an explicit left side, as well as " 

5228 "providing an explicit ON clause if not present already to " 

5229 "help resolve the ambiguity." % (right,) 

5230 ) 

5231 return left, replace_from_obj_index 

5232 

5233 @util.preload_module("sqlalchemy.sql.util") 

5234 def _join_place_explicit_left_side( 

5235 self, left: FromClause 

5236 ) -> Optional[int]: 

5237 replace_from_obj_index: Optional[int] = None 

5238 

5239 sql_util = util.preloaded.sql_util 

5240 

5241 from_clauses = list(self.statement._iterate_from_elements()) 

5242 

5243 if from_clauses: 

5244 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5245 self.from_clauses, left 

5246 ) 

5247 else: 

5248 indexes = [] 

5249 

5250 if len(indexes) > 1: 

5251 raise exc.InvalidRequestError( 

5252 "Can't identify which entity in which to assign the " 

5253 "left side of this join. Please use a more specific " 

5254 "ON clause." 

5255 ) 

5256 

5257 # have an index, means the left side is already present in 

5258 # an existing FROM in the self._from_obj tuple 

5259 if indexes: 

5260 replace_from_obj_index = indexes[0] 

5261 

5262 # no index, means we need to add a new element to the 

5263 # self._from_obj tuple 

5264 

5265 return replace_from_obj_index 

5266 

5267 

5268class _SelectFromElements: 

5269 __slots__ = () 

5270 

5271 _raw_columns: List[_ColumnsClauseElement] 

5272 _where_criteria: Tuple[ColumnElement[Any], ...] 

5273 _from_obj: Tuple[FromClause, ...] 

5274 

5275 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5276 # note this does not include elements 

5277 # in _setup_joins 

5278 

5279 seen = set() 

5280 for element in self._raw_columns: 

5281 for fr in element._from_objects: 

5282 if fr in seen: 

5283 continue 

5284 seen.add(fr) 

5285 yield fr 

5286 for element in self._where_criteria: 

5287 for fr in element._from_objects: 

5288 if fr in seen: 

5289 continue 

5290 seen.add(fr) 

5291 yield fr 

5292 for element in self._from_obj: 

5293 if element in seen: 

5294 continue 

5295 seen.add(element) 

5296 yield element 

5297 

5298 

5299class _MemoizedSelectEntities( 

5300 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5301): 

5302 """represents partial state from a Select object, for the case 

5303 where Select.columns() has redefined the set of columns/entities the 

5304 statement will be SELECTing from. This object represents 

5305 the entities from the SELECT before that transformation was applied, 

5306 so that transformations that were made in terms of the SELECT at that 

5307 time, such as join() as well as options(), can access the correct context. 

5308 

5309 In previous SQLAlchemy versions, this wasn't needed because these 

5310 constructs calculated everything up front, like when you called join() 

5311 or options(), it did everything to figure out how that would translate 

5312 into specific SQL constructs that would be ready to send directly to the 

5313 SQL compiler when needed. But as of 

5314 1.4, all of that stuff is done in the compilation phase, during the 

5315 "compile state" portion of the process, so that the work can all be 

5316 cached. So it needs to be able to resolve joins/options2 based on what 

5317 the list of entities was when those methods were called. 

5318 

5319 

5320 """ 

5321 

5322 __visit_name__ = "memoized_select_entities" 

5323 

5324 _traverse_internals: _TraverseInternalsType = [ 

5325 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5326 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5327 ("_with_options", InternalTraversal.dp_executable_options), 

5328 ] 

5329 

5330 _is_clone_of: Optional[ClauseElement] 

5331 _raw_columns: List[_ColumnsClauseElement] 

5332 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5333 _with_options: Tuple[ExecutableOption, ...] 

5334 

5335 _annotations = util.EMPTY_DICT 

5336 

5337 def _clone(self, **kw: Any) -> Self: 

5338 c = self.__class__.__new__(self.__class__) 

5339 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5340 

5341 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5342 return c 

5343 

5344 @classmethod 

5345 def _generate_for_statement( 

5346 cls, select_stmt: Select[Unpack[TupleAny]] 

5347 ) -> None: 

5348 if select_stmt._setup_joins or select_stmt._with_options: 

5349 self = _MemoizedSelectEntities() 

5350 self._raw_columns = select_stmt._raw_columns 

5351 self._setup_joins = select_stmt._setup_joins 

5352 self._with_options = select_stmt._with_options 

5353 

5354 select_stmt._memoized_select_entities += (self,) 

5355 select_stmt._raw_columns = [] 

5356 select_stmt._setup_joins = select_stmt._with_options = () 

5357 

5358 

5359class Select( 

5360 HasPrefixes, 

5361 HasSuffixes, 

5362 HasHints, 

5363 HasCompileState, 

5364 HasSyntaxExtensions[ 

5365 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5366 ], 

5367 _SelectFromElements, 

5368 GenerativeSelect, 

5369 TypedReturnsRows[Unpack[_Ts]], 

5370): 

5371 """Represents a ``SELECT`` statement. 

5372 

5373 The :class:`_sql.Select` object is normally constructed using the 

5374 :func:`_sql.select` function. See that function for details. 

5375 

5376 Available extension points: 

5377 

5378 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5379 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5380 keyword (if any) and the list of columns. 

5381 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5382 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5383 

5384 .. seealso:: 

5385 

5386 :func:`_sql.select` 

5387 

5388 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5389 

5390 """ 

5391 

5392 __visit_name__ = "select" 

5393 

5394 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5395 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5396 

5397 _raw_columns: List[_ColumnsClauseElement] 

5398 

5399 _distinct: bool = False 

5400 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5401 _correlate: Tuple[FromClause, ...] = () 

5402 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5403 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5404 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5405 _from_obj: Tuple[FromClause, ...] = () 

5406 

5407 _position_map = util.immutabledict( 

5408 { 

5409 "post_select": "_post_select_clause", 

5410 "pre_columns": "_pre_columns_clause", 

5411 "post_criteria": "_post_criteria_clause", 

5412 "post_body": "_post_body_clause", 

5413 } 

5414 ) 

5415 

5416 _post_select_clause: Optional[ClauseElement] = None 

5417 """extension point for a ClauseElement that will be compiled directly 

5418 after the SELECT keyword. 

5419 

5420 .. versionadded:: 2.1 

5421 

5422 """ 

5423 

5424 _pre_columns_clause: Optional[ClauseElement] = None 

5425 """extension point for a ClauseElement that will be compiled directly 

5426 before the "columns" clause; after DISTINCT (if present). 

5427 

5428 .. versionadded:: 2.1 

5429 

5430 """ 

5431 

5432 _post_criteria_clause: Optional[ClauseElement] = None 

5433 """extension point for a ClauseElement that will be compiled directly 

5434 after "criteria", following the HAVING clause but before ORDER BY. 

5435 

5436 .. versionadded:: 2.1 

5437 

5438 """ 

5439 

5440 _post_body_clause: Optional[ClauseElement] = None 

5441 """extension point for a ClauseElement that will be compiled directly 

5442 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5443 of the SELECT. 

5444 

5445 .. versionadded:: 2.1 

5446 

5447 """ 

5448 

5449 _auto_correlate = True 

5450 _is_select_statement = True 

5451 _compile_options: CacheableOptions = ( 

5452 SelectState.default_select_compile_options 

5453 ) 

5454 

5455 _traverse_internals: _TraverseInternalsType = ( 

5456 [ 

5457 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5458 ( 

5459 "_memoized_select_entities", 

5460 InternalTraversal.dp_memoized_select_entities, 

5461 ), 

5462 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5463 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5464 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5465 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5466 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5467 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5468 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5469 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5470 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5471 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5472 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5473 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5474 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5475 ("_distinct", InternalTraversal.dp_boolean), 

5476 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5477 ("_label_style", InternalTraversal.dp_plain_obj), 

5478 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5479 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5480 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5481 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5482 ] 

5483 + HasCTE._has_ctes_traverse_internals 

5484 + HasPrefixes._has_prefixes_traverse_internals 

5485 + HasSuffixes._has_suffixes_traverse_internals 

5486 + HasHints._has_hints_traverse_internals 

5487 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5488 + ExecutableStatement._executable_traverse_internals 

5489 + DialectKWArgs._dialect_kwargs_traverse_internals 

5490 ) 

5491 

5492 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5493 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5494 ] 

5495 

5496 _compile_state_factory: Type[SelectState] 

5497 

5498 @classmethod 

5499 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5500 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5501 

5502 Used internally to build up :class:`.Select` constructs with 

5503 pre-established state. 

5504 

5505 """ 

5506 

5507 stmt = Select.__new__(Select) 

5508 stmt.__dict__.update(kw) 

5509 return stmt 

5510 

5511 def __init__( 

5512 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5513 ): 

5514 r"""Construct a new :class:`_expression.Select`. 

5515 

5516 The public constructor for :class:`_expression.Select` is the 

5517 :func:`_sql.select` function. 

5518 

5519 """ 

5520 self._raw_columns = [ 

5521 coercions.expect( 

5522 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5523 ) 

5524 for ent in entities 

5525 ] 

5526 GenerativeSelect.__init__(self) 

5527 

5528 def _apply_syntax_extension_to_self( 

5529 self, extension: SyntaxExtension 

5530 ) -> None: 

5531 extension.apply_to_select(self) 

5532 

5533 def _scalar_type(self) -> TypeEngine[Any]: 

5534 if not self._raw_columns: 

5535 return NULLTYPE 

5536 elem = self._raw_columns[0] 

5537 cols = list(elem._select_iterable) 

5538 return cols[0].type 

5539 

5540 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5541 """A synonym for the :meth:`_sql.Select.where` method.""" 

5542 

5543 return self.where(*criteria) 

5544 

5545 def _filter_by_zero( 

5546 self, 

5547 ) -> Union[ 

5548 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5549 ]: 

5550 if self._setup_joins: 

5551 meth = SelectState.get_plugin_class( 

5552 self 

5553 ).determine_last_joined_entity 

5554 _last_joined_entity = meth(self) 

5555 if _last_joined_entity is not None: 

5556 return _last_joined_entity 

5557 

5558 if self._from_obj: 

5559 return self._from_obj[0] 

5560 

5561 return self._raw_columns[0] 

5562 

5563 if TYPE_CHECKING: 

5564 

5565 @overload 

5566 def scalar_subquery( 

5567 self: Select[_MAYBE_ENTITY], 

5568 ) -> ScalarSelect[Any]: ... 

5569 

5570 @overload 

5571 def scalar_subquery( 

5572 self: Select[_NOT_ENTITY], 

5573 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5574 

5575 @overload 

5576 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5577 

5578 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5579 

5580 def filter_by(self, **kwargs: Any) -> Self: 

5581 r"""apply the given filtering criterion as a WHERE clause 

5582 to this select. 

5583 

5584 """ 

5585 from_entity = self._filter_by_zero() 

5586 

5587 clauses = [ 

5588 _entity_namespace_key(from_entity, key) == value 

5589 for key, value in kwargs.items() 

5590 ] 

5591 return self.filter(*clauses) 

5592 

5593 @property 

5594 def column_descriptions(self) -> Any: 

5595 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5596 referring to the columns which are SELECTed by this statement. 

5597 

5598 This attribute is generally useful when using the ORM, as an 

5599 extended structure which includes information about mapped 

5600 entities is returned. The section :ref:`queryguide_inspection` 

5601 contains more background. 

5602 

5603 For a Core-only statement, the structure returned by this accessor 

5604 is derived from the same objects that are returned by the 

5605 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5606 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5607 which indicate the column expressions to be selected:: 

5608 

5609 >>> stmt = select(user_table) 

5610 >>> stmt.column_descriptions 

5611 [ 

5612 { 

5613 'name': 'id', 

5614 'type': Integer(), 

5615 'expr': Column('id', Integer(), ...)}, 

5616 { 

5617 'name': 'name', 

5618 'type': String(length=30), 

5619 'expr': Column('name', String(length=30), ...)} 

5620 ] 

5621 

5622 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5623 attribute returns a structure for a Core-only set of entities, 

5624 not just ORM-only entities. 

5625 

5626 .. seealso:: 

5627 

5628 :attr:`.UpdateBase.entity_description` - entity information for 

5629 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5630 

5631 :ref:`queryguide_inspection` - ORM background 

5632 

5633 """ 

5634 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5635 return meth(self) 

5636 

5637 def from_statement( 

5638 self, statement: roles.ReturnsRowsRole 

5639 ) -> ExecutableReturnsRows: 

5640 """Apply the columns which this :class:`.Select` would select 

5641 onto another statement. 

5642 

5643 This operation is :term:`plugin-specific` and will raise a not 

5644 supported exception if this :class:`_sql.Select` does not select from 

5645 plugin-enabled entities. 

5646 

5647 

5648 The statement is typically either a :func:`_expression.text` or 

5649 :func:`_expression.select` construct, and should return the set of 

5650 columns appropriate to the entities represented by this 

5651 :class:`.Select`. 

5652 

5653 .. seealso:: 

5654 

5655 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5656 ORM Querying Guide 

5657 

5658 """ 

5659 meth = SelectState.get_plugin_class(self).from_statement 

5660 return meth(self, statement) 

5661 

5662 @_generative 

5663 def join( 

5664 self, 

5665 target: _JoinTargetArgument, 

5666 onclause: Optional[_OnClauseArgument] = None, 

5667 *, 

5668 isouter: bool = False, 

5669 full: bool = False, 

5670 ) -> Self: 

5671 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5672 object's criterion 

5673 and apply generatively, returning the newly resulting 

5674 :class:`_expression.Select`. 

5675 

5676 E.g.:: 

5677 

5678 stmt = select(user_table).join( 

5679 address_table, user_table.c.id == address_table.c.user_id 

5680 ) 

5681 

5682 The above statement generates SQL similar to: 

5683 

5684 .. sourcecode:: sql 

5685 

5686 SELECT user.id, user.name 

5687 FROM user 

5688 JOIN address ON user.id = address.user_id 

5689 

5690 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5691 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5692 source that is within the FROM clause of the existing SELECT, 

5693 and a given target :class:`_sql.FromClause`, and then adds 

5694 this :class:`_sql.Join` to the FROM clause of the newly generated 

5695 SELECT statement. This is completely reworked from the behavior 

5696 in 1.3, which would instead create a subquery of the entire 

5697 :class:`_expression.Select` and then join that subquery to the 

5698 target. 

5699 

5700 This is a **backwards incompatible change** as the previous behavior 

5701 was mostly useless, producing an unnamed subquery rejected by 

5702 most databases in any case. The new behavior is modeled after 

5703 that of the very successful :meth:`_orm.Query.join` method in the 

5704 ORM, in order to support the functionality of :class:`_orm.Query` 

5705 being available by using a :class:`_sql.Select` object with an 

5706 :class:`_orm.Session`. 

5707 

5708 See the notes for this change at :ref:`change_select_join`. 

5709 

5710 

5711 :param target: target table to join towards 

5712 

5713 :param onclause: ON clause of the join. If omitted, an ON clause 

5714 is generated automatically based on the :class:`_schema.ForeignKey` 

5715 linkages between the two tables, if one can be unambiguously 

5716 determined, otherwise an error is raised. 

5717 

5718 :param isouter: if True, generate LEFT OUTER join. Same as 

5719 :meth:`_expression.Select.outerjoin`. 

5720 

5721 :param full: if True, generate FULL OUTER join. 

5722 

5723 .. seealso:: 

5724 

5725 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5726 

5727 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5728 

5729 :meth:`_expression.Select.join_from` 

5730 

5731 :meth:`_expression.Select.outerjoin` 

5732 

5733 """ # noqa: E501 

5734 join_target = coercions.expect( 

5735 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5736 ) 

5737 if onclause is not None: 

5738 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5739 else: 

5740 onclause_element = None 

5741 

5742 self._setup_joins += ( 

5743 ( 

5744 join_target, 

5745 onclause_element, 

5746 None, 

5747 {"isouter": isouter, "full": full}, 

5748 ), 

5749 ) 

5750 return self 

5751 

5752 def outerjoin_from( 

5753 self, 

5754 from_: _FromClauseArgument, 

5755 target: _JoinTargetArgument, 

5756 onclause: Optional[_OnClauseArgument] = None, 

5757 *, 

5758 full: bool = False, 

5759 ) -> Self: 

5760 r"""Create a SQL LEFT OUTER JOIN against this 

5761 :class:`_expression.Select` object's criterion and apply generatively, 

5762 returning the newly resulting :class:`_expression.Select`. 

5763 

5764 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5765 

5766 """ 

5767 return self.join_from( 

5768 from_, target, onclause=onclause, isouter=True, full=full 

5769 ) 

5770 

5771 @_generative 

5772 def join_from( 

5773 self, 

5774 from_: _FromClauseArgument, 

5775 target: _JoinTargetArgument, 

5776 onclause: Optional[_OnClauseArgument] = None, 

5777 *, 

5778 isouter: bool = False, 

5779 full: bool = False, 

5780 ) -> Self: 

5781 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5782 object's criterion 

5783 and apply generatively, returning the newly resulting 

5784 :class:`_expression.Select`. 

5785 

5786 E.g.:: 

5787 

5788 stmt = select(user_table, address_table).join_from( 

5789 user_table, address_table, user_table.c.id == address_table.c.user_id 

5790 ) 

5791 

5792 The above statement generates SQL similar to: 

5793 

5794 .. sourcecode:: sql 

5795 

5796 SELECT user.id, user.name, address.id, address.email, address.user_id 

5797 FROM user JOIN address ON user.id = address.user_id 

5798 

5799 .. versionadded:: 1.4 

5800 

5801 :param from\_: the left side of the join, will be rendered in the 

5802 FROM clause and is roughly equivalent to using the 

5803 :meth:`.Select.select_from` method. 

5804 

5805 :param target: target table to join towards 

5806 

5807 :param onclause: ON clause of the join. 

5808 

5809 :param isouter: if True, generate LEFT OUTER join. Same as 

5810 :meth:`_expression.Select.outerjoin`. 

5811 

5812 :param full: if True, generate FULL OUTER join. 

5813 

5814 .. seealso:: 

5815 

5816 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5817 

5818 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5819 

5820 :meth:`_expression.Select.join` 

5821 

5822 """ # noqa: E501 

5823 

5824 # note the order of parsing from vs. target is important here, as we 

5825 # are also deriving the source of the plugin (i.e. the subject mapper 

5826 # in an ORM query) which should favor the "from_" over the "target" 

5827 

5828 from_ = coercions.expect( 

5829 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5830 ) 

5831 join_target = coercions.expect( 

5832 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5833 ) 

5834 if onclause is not None: 

5835 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5836 else: 

5837 onclause_element = None 

5838 

5839 self._setup_joins += ( 

5840 ( 

5841 join_target, 

5842 onclause_element, 

5843 from_, 

5844 {"isouter": isouter, "full": full}, 

5845 ), 

5846 ) 

5847 return self 

5848 

5849 def outerjoin( 

5850 self, 

5851 target: _JoinTargetArgument, 

5852 onclause: Optional[_OnClauseArgument] = None, 

5853 *, 

5854 full: bool = False, 

5855 ) -> Self: 

5856 """Create a left outer join. 

5857 

5858 Parameters are the same as that of :meth:`_expression.Select.join`. 

5859 

5860 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5861 creates a :class:`_sql.Join` object between a 

5862 :class:`_sql.FromClause` source that is within the FROM clause of 

5863 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5864 and then adds this :class:`_sql.Join` to the FROM clause of the 

5865 newly generated SELECT statement. This is completely reworked 

5866 from the behavior in 1.3, which would instead create a subquery of 

5867 the entire 

5868 :class:`_expression.Select` and then join that subquery to the 

5869 target. 

5870 

5871 This is a **backwards incompatible change** as the previous behavior 

5872 was mostly useless, producing an unnamed subquery rejected by 

5873 most databases in any case. The new behavior is modeled after 

5874 that of the very successful :meth:`_orm.Query.join` method in the 

5875 ORM, in order to support the functionality of :class:`_orm.Query` 

5876 being available by using a :class:`_sql.Select` object with an 

5877 :class:`_orm.Session`. 

5878 

5879 See the notes for this change at :ref:`change_select_join`. 

5880 

5881 .. seealso:: 

5882 

5883 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5884 

5885 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5886 

5887 :meth:`_expression.Select.join` 

5888 

5889 """ 

5890 return self.join(target, onclause=onclause, isouter=True, full=full) 

5891 

5892 def get_final_froms(self) -> Sequence[FromClause]: 

5893 """Compute the final displayed list of :class:`_expression.FromClause` 

5894 elements. 

5895 

5896 This method will run through the full computation required to 

5897 determine what FROM elements will be displayed in the resulting 

5898 SELECT statement, including shadowing individual tables with 

5899 JOIN objects, as well as full computation for ORM use cases including 

5900 eager loading clauses. 

5901 

5902 For ORM use, this accessor returns the **post compilation** 

5903 list of FROM objects; this collection will include elements such as 

5904 eagerly loaded tables and joins. The objects will **not** be 

5905 ORM enabled and not work as a replacement for the 

5906 :meth:`_sql.Select.select_froms` collection; additionally, the 

5907 method is not well performing for an ORM enabled statement as it 

5908 will incur the full ORM construction process. 

5909 

5910 To retrieve the FROM list that's implied by the "columns" collection 

5911 passed to the :class:`_sql.Select` originally, use the 

5912 :attr:`_sql.Select.columns_clause_froms` accessor. 

5913 

5914 To select from an alternative set of columns while maintaining the 

5915 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5916 pass the 

5917 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5918 parameter. 

5919 

5920 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5921 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5922 which is deprecated. 

5923 

5924 .. seealso:: 

5925 

5926 :attr:`_sql.Select.columns_clause_froms` 

5927 

5928 """ 

5929 compiler = self._default_compiler() 

5930 

5931 return self._compile_state_factory(self, compiler)._get_display_froms() 

5932 

5933 @property 

5934 @util.deprecated( 

5935 "1.4.23", 

5936 "The :attr:`_expression.Select.froms` attribute is moved to " 

5937 "the :meth:`_expression.Select.get_final_froms` method.", 

5938 ) 

5939 def froms(self) -> Sequence[FromClause]: 

5940 """Return the displayed list of :class:`_expression.FromClause` 

5941 elements. 

5942 

5943 

5944 """ 

5945 return self.get_final_froms() 

5946 

5947 @property 

5948 def columns_clause_froms(self) -> List[FromClause]: 

5949 """Return the set of :class:`_expression.FromClause` objects implied 

5950 by the columns clause of this SELECT statement. 

5951 

5952 .. versionadded:: 1.4.23 

5953 

5954 .. seealso:: 

5955 

5956 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5957 statement into account 

5958 

5959 :meth:`_sql.Select.with_only_columns` - makes use of this 

5960 collection to set up a new FROM list 

5961 

5962 """ 

5963 

5964 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5965 self 

5966 ) 

5967 

5968 @property 

5969 def inner_columns(self) -> _SelectIterable: 

5970 """An iterator of all :class:`_expression.ColumnElement` 

5971 expressions which would 

5972 be rendered into the columns clause of the resulting SELECT statement. 

5973 

5974 This method is legacy as of 1.4 and is superseded by the 

5975 :attr:`_expression.Select.exported_columns` collection. 

5976 

5977 """ 

5978 

5979 return iter(self._all_selected_columns) 

5980 

5981 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5982 if fromclause is not None and self in fromclause._cloned_set: 

5983 return True 

5984 

5985 for f in self._iterate_from_elements(): 

5986 if f.is_derived_from(fromclause): 

5987 return True 

5988 return False 

5989 

5990 def _copy_internals( 

5991 self, clone: _CloneCallableType = _clone, **kw: Any 

5992 ) -> None: 

5993 # Select() object has been cloned and probably adapted by the 

5994 # given clone function. Apply the cloning function to internal 

5995 # objects 

5996 

5997 # 1. keep a dictionary of the froms we've cloned, and what 

5998 # they've become. This allows us to ensure the same cloned from 

5999 # is used when other items such as columns are "cloned" 

6000 

6001 all_the_froms = set( 

6002 itertools.chain( 

6003 _from_objects(*self._raw_columns), 

6004 _from_objects(*self._where_criteria), 

6005 _from_objects(*[elem[0] for elem in self._setup_joins]), 

6006 ) 

6007 ) 

6008 

6009 # do a clone for the froms we've gathered. what is important here 

6010 # is if any of the things we are selecting from, like tables, 

6011 # were converted into Join objects. if so, these need to be 

6012 # added to _from_obj explicitly, because otherwise they won't be 

6013 # part of the new state, as they don't associate themselves with 

6014 # their columns. 

6015 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

6016 

6017 # 2. copy FROM collections, adding in joins that we've created. 

6018 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

6019 add_froms = ( 

6020 {f for f in new_froms.values() if isinstance(f, Join)} 

6021 .difference(all_the_froms) 

6022 .difference(existing_from_obj) 

6023 ) 

6024 

6025 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

6026 

6027 # 3. clone everything else, making sure we use columns 

6028 # corresponding to the froms we just made. 

6029 def replace( 

6030 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

6031 **kw: Any, 

6032 ) -> Optional[KeyedColumnElement[Any]]: 

6033 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

6034 newelem = new_froms[obj.table].corresponding_column(obj) 

6035 return newelem 

6036 return None 

6037 

6038 kw["replace"] = replace 

6039 

6040 # copy everything else. for table-ish things like correlate, 

6041 # correlate_except, setup_joins, these clone normally. For 

6042 # column-expression oriented things like raw_columns, where_criteria, 

6043 # order by, we get this from the new froms. 

6044 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

6045 

6046 self._reset_memoizations() 

6047 

6048 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

6049 return itertools.chain( 

6050 super().get_children( 

6051 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

6052 **kw, 

6053 ), 

6054 self._iterate_from_elements(), 

6055 ) 

6056 

6057 @_generative 

6058 def add_columns( 

6059 self, *entities: _ColumnsClauseArgument[Any] 

6060 ) -> Select[Unpack[TupleAny]]: 

6061 r"""Return a new :func:`_expression.select` construct with 

6062 the given entities appended to its columns clause. 

6063 

6064 E.g.:: 

6065 

6066 my_select = my_select.add_columns(table.c.new_column) 

6067 

6068 The original expressions in the columns clause remain in place. 

6069 To replace the original expressions with new ones, see the method 

6070 :meth:`_expression.Select.with_only_columns`. 

6071 

6072 :param \*entities: column, table, or other entity expressions to be 

6073 added to the columns clause 

6074 

6075 .. seealso:: 

6076 

6077 :meth:`_expression.Select.with_only_columns` - replaces existing 

6078 expressions rather than appending. 

6079 

6080 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

6081 example 

6082 

6083 """ 

6084 self._reset_memoizations() 

6085 

6086 self._raw_columns = self._raw_columns + [ 

6087 coercions.expect( 

6088 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

6089 ) 

6090 for column in entities 

6091 ] 

6092 return self 

6093 

6094 def _set_entities( 

6095 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

6096 ) -> None: 

6097 self._raw_columns = [ 

6098 coercions.expect( 

6099 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6100 ) 

6101 for ent in util.to_list(entities) 

6102 ] 

6103 

6104 @util.deprecated( 

6105 "1.4", 

6106 "The :meth:`_expression.Select.column` method is deprecated and will " 

6107 "be removed in a future release. Please use " 

6108 ":meth:`_expression.Select.add_columns`", 

6109 ) 

6110 def column( 

6111 self, column: _ColumnsClauseArgument[Any] 

6112 ) -> Select[Unpack[TupleAny]]: 

6113 """Return a new :func:`_expression.select` construct with 

6114 the given column expression added to its columns clause. 

6115 

6116 E.g.:: 

6117 

6118 my_select = my_select.column(table.c.new_column) 

6119 

6120 See the documentation for 

6121 :meth:`_expression.Select.with_only_columns` 

6122 for guidelines on adding /replacing the columns of a 

6123 :class:`_expression.Select` object. 

6124 

6125 """ 

6126 return self.add_columns(column) 

6127 

6128 @util.preload_module("sqlalchemy.sql.util") 

6129 def reduce_columns( 

6130 self, only_synonyms: bool = True 

6131 ) -> Select[Unpack[TupleAny]]: 

6132 """Return a new :func:`_expression.select` construct with redundantly 

6133 named, equivalently-valued columns removed from the columns clause. 

6134 

6135 "Redundant" here means two columns where one refers to the 

6136 other either based on foreign key, or via a simple equality 

6137 comparison in the WHERE clause of the statement. The primary purpose 

6138 of this method is to automatically construct a select statement 

6139 with all uniquely-named columns, without the need to use 

6140 table-qualified labels as 

6141 :meth:`_expression.Select.set_label_style` 

6142 does. 

6143 

6144 When columns are omitted based on foreign key, the referred-to 

6145 column is the one that's kept. When columns are omitted based on 

6146 WHERE equivalence, the first column in the columns clause is the 

6147 one that's kept. 

6148 

6149 :param only_synonyms: when True, limit the removal of columns 

6150 to those which have the same name as the equivalent. Otherwise, 

6151 all columns that are equivalent to another are removed. 

6152 

6153 """ 

6154 woc: Select[Unpack[TupleAny]] 

6155 woc = self.with_only_columns( 

6156 *util.preloaded.sql_util.reduce_columns( 

6157 self._all_selected_columns, 

6158 only_synonyms=only_synonyms, 

6159 *(self._where_criteria + self._from_obj), 

6160 ) 

6161 ) 

6162 return woc 

6163 

6164 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6165 

6166 # code within this block is **programmatically, 

6167 # statically generated** by tools/generate_tuple_map_overloads.py 

6168 

6169 @overload 

6170 def with_only_columns( 

6171 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6172 ) -> Select[_T0]: ... 

6173 

6174 @overload 

6175 def with_only_columns( 

6176 self, 

6177 __ent0: _TCCA[_T0], 

6178 __ent1: _TCCA[_T1], 

6179 /, 

6180 *, 

6181 maintain_column_froms: bool = ..., 

6182 ) -> Select[_T0, _T1]: ... 

6183 

6184 @overload 

6185 def with_only_columns( 

6186 self, 

6187 __ent0: _TCCA[_T0], 

6188 __ent1: _TCCA[_T1], 

6189 __ent2: _TCCA[_T2], 

6190 /, 

6191 *, 

6192 maintain_column_froms: bool = ..., 

6193 ) -> Select[_T0, _T1, _T2]: ... 

6194 

6195 @overload 

6196 def with_only_columns( 

6197 self, 

6198 __ent0: _TCCA[_T0], 

6199 __ent1: _TCCA[_T1], 

6200 __ent2: _TCCA[_T2], 

6201 __ent3: _TCCA[_T3], 

6202 /, 

6203 *, 

6204 maintain_column_froms: bool = ..., 

6205 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6206 

6207 @overload 

6208 def with_only_columns( 

6209 self, 

6210 __ent0: _TCCA[_T0], 

6211 __ent1: _TCCA[_T1], 

6212 __ent2: _TCCA[_T2], 

6213 __ent3: _TCCA[_T3], 

6214 __ent4: _TCCA[_T4], 

6215 /, 

6216 *, 

6217 maintain_column_froms: bool = ..., 

6218 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6219 

6220 @overload 

6221 def with_only_columns( 

6222 self, 

6223 __ent0: _TCCA[_T0], 

6224 __ent1: _TCCA[_T1], 

6225 __ent2: _TCCA[_T2], 

6226 __ent3: _TCCA[_T3], 

6227 __ent4: _TCCA[_T4], 

6228 __ent5: _TCCA[_T5], 

6229 /, 

6230 *, 

6231 maintain_column_froms: bool = ..., 

6232 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6233 

6234 @overload 

6235 def with_only_columns( 

6236 self, 

6237 __ent0: _TCCA[_T0], 

6238 __ent1: _TCCA[_T1], 

6239 __ent2: _TCCA[_T2], 

6240 __ent3: _TCCA[_T3], 

6241 __ent4: _TCCA[_T4], 

6242 __ent5: _TCCA[_T5], 

6243 __ent6: _TCCA[_T6], 

6244 /, 

6245 *, 

6246 maintain_column_froms: bool = ..., 

6247 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6248 

6249 @overload 

6250 def with_only_columns( 

6251 self, 

6252 __ent0: _TCCA[_T0], 

6253 __ent1: _TCCA[_T1], 

6254 __ent2: _TCCA[_T2], 

6255 __ent3: _TCCA[_T3], 

6256 __ent4: _TCCA[_T4], 

6257 __ent5: _TCCA[_T5], 

6258 __ent6: _TCCA[_T6], 

6259 __ent7: _TCCA[_T7], 

6260 /, 

6261 *entities: _ColumnsClauseArgument[Any], 

6262 maintain_column_froms: bool = ..., 

6263 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6264 

6265 # END OVERLOADED FUNCTIONS self.with_only_columns 

6266 

6267 @overload 

6268 def with_only_columns( 

6269 self, 

6270 *entities: _ColumnsClauseArgument[Any], 

6271 maintain_column_froms: bool = False, 

6272 **__kw: Any, 

6273 ) -> Select[Unpack[TupleAny]]: ... 

6274 

6275 @_generative 

6276 def with_only_columns( 

6277 self, 

6278 *entities: _ColumnsClauseArgument[Any], 

6279 maintain_column_froms: bool = False, 

6280 **__kw: Any, 

6281 ) -> Select[Unpack[TupleAny]]: 

6282 r"""Return a new :func:`_expression.select` construct with its columns 

6283 clause replaced with the given entities. 

6284 

6285 By default, this method is exactly equivalent to as if the original 

6286 :func:`_expression.select` had been called with the given entities. 

6287 E.g. a statement:: 

6288 

6289 s = select(table1.c.a, table1.c.b) 

6290 s = s.with_only_columns(table1.c.b) 

6291 

6292 should be exactly equivalent to:: 

6293 

6294 s = select(table1.c.b) 

6295 

6296 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6297 will also dynamically alter the FROM clause of the 

6298 statement if it is not explicitly stated. 

6299 To maintain the existing set of FROMs including those implied by the 

6300 current columns clause, add the 

6301 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6302 parameter:: 

6303 

6304 s = select(table1.c.a, table2.c.b) 

6305 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6306 

6307 The above parameter performs a transfer of the effective FROMs 

6308 in the columns collection to the :meth:`_sql.Select.select_from` 

6309 method, as though the following were invoked:: 

6310 

6311 s = select(table1.c.a, table2.c.b) 

6312 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6313 

6314 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6315 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6316 collection and performs an operation equivalent to the following:: 

6317 

6318 s = select(table1.c.a, table2.c.b) 

6319 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6320 

6321 :param \*entities: column expressions to be used. 

6322 

6323 :param maintain_column_froms: boolean parameter that will ensure the 

6324 FROM list implied from the current columns clause will be transferred 

6325 to the :meth:`_sql.Select.select_from` method first. 

6326 

6327 .. versionadded:: 1.4.23 

6328 

6329 """ # noqa: E501 

6330 

6331 if __kw: 

6332 raise _no_kw() 

6333 

6334 # memoizations should be cleared here as of 

6335 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6336 # is the case for now. 

6337 self._assert_no_memoizations() 

6338 

6339 if maintain_column_froms: 

6340 self.select_from.non_generative( # type: ignore 

6341 self, *self.columns_clause_froms 

6342 ) 

6343 

6344 # then memoize the FROMs etc. 

6345 _MemoizedSelectEntities._generate_for_statement(self) 

6346 

6347 self._raw_columns = [ 

6348 coercions.expect(roles.ColumnsClauseRole, c) 

6349 for c in coercions._expression_collection_was_a_list( 

6350 "entities", "Select.with_only_columns", entities 

6351 ) 

6352 ] 

6353 return self 

6354 

6355 @property 

6356 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6357 """Return the completed WHERE clause for this 

6358 :class:`_expression.Select` statement. 

6359 

6360 This assembles the current collection of WHERE criteria 

6361 into a single :class:`_expression.BooleanClauseList` construct. 

6362 

6363 

6364 .. versionadded:: 1.4 

6365 

6366 """ 

6367 

6368 return BooleanClauseList._construct_for_whereclause( 

6369 self._where_criteria 

6370 ) 

6371 

6372 _whereclause = whereclause 

6373 

6374 @_generative 

6375 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6376 """Return a new :func:`_expression.select` construct with 

6377 the given expression added to 

6378 its WHERE clause, joined to the existing clause via AND, if any. 

6379 

6380 """ 

6381 

6382 assert isinstance(self._where_criteria, tuple) 

6383 

6384 for criterion in whereclause: 

6385 where_criteria: ColumnElement[Any] = coercions.expect( 

6386 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6387 ) 

6388 self._where_criteria += (where_criteria,) 

6389 return self 

6390 

6391 @_generative 

6392 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6393 """Return a new :func:`_expression.select` construct with 

6394 the given expression added to 

6395 its HAVING clause, joined to the existing clause via AND, if any. 

6396 

6397 """ 

6398 

6399 for criterion in having: 

6400 having_criteria = coercions.expect( 

6401 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6402 ) 

6403 self._having_criteria += (having_criteria,) 

6404 return self 

6405 

6406 @_generative 

6407 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6408 r"""Return a new :func:`_expression.select` construct which 

6409 will apply DISTINCT to the SELECT statement overall. 

6410 

6411 E.g.:: 

6412 

6413 from sqlalchemy import select 

6414 

6415 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6416 

6417 The above would produce an statement resembling: 

6418 

6419 .. sourcecode:: sql 

6420 

6421 SELECT DISTINCT user.id, user.name FROM user 

6422 

6423 The method also historically accepted an ``*expr`` parameter which 

6424 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6425 This is now replaced using the :func:`_postgresql.distinct_on` 

6426 extension:: 

6427 

6428 from sqlalchemy import select 

6429 from sqlalchemy.dialects.postgresql import distinct_on 

6430 

6431 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6432 

6433 Using this parameter on other backends which don't support this 

6434 syntax will raise an error. 

6435 

6436 :param \*expr: optional column expressions. When present, 

6437 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6438 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6439 will be raised on other backends. 

6440 

6441 .. deprecated:: 2.1 Passing expressions to 

6442 :meth:`_sql.Select.distinct` is deprecated, use 

6443 :func:`_postgresql.distinct_on` instead. 

6444 

6445 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6446 and will raise :class:`_exc.CompileError` in a future version. 

6447 

6448 .. seealso:: 

6449 

6450 :func:`_postgresql.distinct_on` 

6451 

6452 :meth:`_sql.HasSyntaxExtensions.ext` 

6453 """ 

6454 self._distinct = True 

6455 if expr: 

6456 warn_deprecated( 

6457 "Passing expression to ``distinct`` to generate a " 

6458 "DISTINCT ON clause is deprecated. Use instead the " 

6459 "``postgresql.distinct_on`` function as an extension.", 

6460 "2.1", 

6461 ) 

6462 self._distinct_on = self._distinct_on + tuple( 

6463 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6464 for e in expr 

6465 ) 

6466 return self 

6467 

6468 @_generative 

6469 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6470 r"""Return a new :func:`_expression.select` construct with the 

6471 given FROM expression(s) 

6472 merged into its list of FROM objects. 

6473 

6474 E.g.:: 

6475 

6476 table1 = table("t1", column("a")) 

6477 table2 = table("t2", column("b")) 

6478 s = select(table1.c.a).select_from( 

6479 table1.join(table2, table1.c.a == table2.c.b) 

6480 ) 

6481 

6482 The "from" list is a unique set on the identity of each element, 

6483 so adding an already present :class:`_schema.Table` 

6484 or other selectable 

6485 will have no effect. Passing a :class:`_expression.Join` that refers 

6486 to an already present :class:`_schema.Table` 

6487 or other selectable will have 

6488 the effect of concealing the presence of that selectable as 

6489 an individual element in the rendered FROM list, instead 

6490 rendering it into a JOIN clause. 

6491 

6492 While the typical purpose of :meth:`_expression.Select.select_from` 

6493 is to 

6494 replace the default, derived FROM clause with a join, it can 

6495 also be called with individual table elements, multiple times 

6496 if desired, in the case that the FROM clause cannot be fully 

6497 derived from the columns clause:: 

6498 

6499 select(func.count("*")).select_from(table1) 

6500 

6501 """ 

6502 

6503 self._from_obj += tuple( 

6504 coercions.expect( 

6505 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6506 ) 

6507 for fromclause in froms 

6508 ) 

6509 return self 

6510 

6511 @_generative 

6512 def correlate( 

6513 self, 

6514 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6515 ) -> Self: 

6516 r"""Return a new :class:`_expression.Select` 

6517 which will correlate the given FROM 

6518 clauses to that of an enclosing :class:`_expression.Select`. 

6519 

6520 Calling this method turns off the :class:`_expression.Select` object's 

6521 default behavior of "auto-correlation". Normally, FROM elements 

6522 which appear in a :class:`_expression.Select` 

6523 that encloses this one via 

6524 its :term:`WHERE clause`, ORDER BY, HAVING or 

6525 :term:`columns clause` will be omitted from this 

6526 :class:`_expression.Select` 

6527 object's :term:`FROM clause`. 

6528 Setting an explicit correlation collection using the 

6529 :meth:`_expression.Select.correlate` 

6530 method provides a fixed list of FROM objects 

6531 that can potentially take place in this process. 

6532 

6533 When :meth:`_expression.Select.correlate` 

6534 is used to apply specific FROM clauses 

6535 for correlation, the FROM elements become candidates for 

6536 correlation regardless of how deeply nested this 

6537 :class:`_expression.Select` 

6538 object is, relative to an enclosing :class:`_expression.Select` 

6539 which refers to 

6540 the same FROM object. This is in contrast to the behavior of 

6541 "auto-correlation" which only correlates to an immediate enclosing 

6542 :class:`_expression.Select`. 

6543 Multi-level correlation ensures that the link 

6544 between enclosed and enclosing :class:`_expression.Select` 

6545 is always via 

6546 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6547 correlation to take place. 

6548 

6549 If ``None`` is passed, the :class:`_expression.Select` 

6550 object will correlate 

6551 none of its FROM entries, and all will render unconditionally 

6552 in the local FROM clause. 

6553 

6554 :param \*fromclauses: one or more :class:`.FromClause` or other 

6555 FROM-compatible construct such as an ORM mapped entity to become part 

6556 of the correlate collection; alternatively pass a single value 

6557 ``None`` to remove all existing correlations. 

6558 

6559 .. seealso:: 

6560 

6561 :meth:`_expression.Select.correlate_except` 

6562 

6563 :ref:`tutorial_scalar_subquery` 

6564 

6565 """ 

6566 

6567 # tests failing when we try to change how these 

6568 # arguments are passed 

6569 

6570 self._auto_correlate = False 

6571 if not fromclauses or fromclauses[0] in {None, False}: 

6572 if len(fromclauses) > 1: 

6573 raise exc.ArgumentError( 

6574 "additional FROM objects not accepted when " 

6575 "passing None/False to correlate()" 

6576 ) 

6577 self._correlate = () 

6578 else: 

6579 self._correlate = self._correlate + tuple( 

6580 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6581 ) 

6582 return self 

6583 

6584 @_generative 

6585 def correlate_except( 

6586 self, 

6587 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6588 ) -> Self: 

6589 r"""Return a new :class:`_expression.Select` 

6590 which will omit the given FROM 

6591 clauses from the auto-correlation process. 

6592 

6593 Calling :meth:`_expression.Select.correlate_except` turns off the 

6594 :class:`_expression.Select` object's default behavior of 

6595 "auto-correlation" for the given FROM elements. An element 

6596 specified here will unconditionally appear in the FROM list, while 

6597 all other FROM elements remain subject to normal auto-correlation 

6598 behaviors. 

6599 

6600 If ``None`` is passed, or no arguments are passed, 

6601 the :class:`_expression.Select` object will correlate all of its 

6602 FROM entries. 

6603 

6604 :param \*fromclauses: a list of one or more 

6605 :class:`_expression.FromClause` 

6606 constructs, or other compatible constructs (i.e. ORM-mapped 

6607 classes) to become part of the correlate-exception collection. 

6608 

6609 .. seealso:: 

6610 

6611 :meth:`_expression.Select.correlate` 

6612 

6613 :ref:`tutorial_scalar_subquery` 

6614 

6615 """ 

6616 

6617 self._auto_correlate = False 

6618 if not fromclauses or fromclauses[0] in {None, False}: 

6619 if len(fromclauses) > 1: 

6620 raise exc.ArgumentError( 

6621 "additional FROM objects not accepted when " 

6622 "passing None/False to correlate_except()" 

6623 ) 

6624 self._correlate_except = () 

6625 else: 

6626 self._correlate_except = (self._correlate_except or ()) + tuple( 

6627 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6628 ) 

6629 

6630 return self 

6631 

6632 @HasMemoized_ro_memoized_attribute 

6633 def selected_columns( 

6634 self, 

6635 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6636 """A :class:`_expression.ColumnCollection` 

6637 representing the columns that 

6638 this SELECT statement or similar construct returns in its result set, 

6639 not including :class:`_sql.TextClause` constructs. 

6640 

6641 This collection differs from the :attr:`_expression.FromClause.columns` 

6642 collection of a :class:`_expression.FromClause` in that the columns 

6643 within this collection cannot be directly nested inside another SELECT 

6644 statement; a subquery must be applied first which provides for the 

6645 necessary parenthesization required by SQL. 

6646 

6647 For a :func:`_expression.select` construct, the collection here is 

6648 exactly what would be rendered inside the "SELECT" statement, and the 

6649 :class:`_expression.ColumnElement` objects are directly present as they 

6650 were given, e.g.:: 

6651 

6652 col1 = column("q", Integer) 

6653 col2 = column("p", Integer) 

6654 stmt = select(col1, col2) 

6655 

6656 Above, ``stmt.selected_columns`` would be a collection that contains 

6657 the ``col1`` and ``col2`` objects directly. For a statement that is 

6658 against a :class:`_schema.Table` or other 

6659 :class:`_expression.FromClause`, the collection will use the 

6660 :class:`_expression.ColumnElement` objects that are in the 

6661 :attr:`_expression.FromClause.c` collection of the from element. 

6662 

6663 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6664 to allow the existing columns to be referenced when adding additional 

6665 criteria, e.g.:: 

6666 

6667 def filter_on_id(my_select, id): 

6668 return my_select.where(my_select.selected_columns["id"] == id) 

6669 

6670 

6671 stmt = select(MyModel) 

6672 

6673 # adds "WHERE id=:param" to the statement 

6674 stmt = filter_on_id(stmt, 42) 

6675 

6676 .. note:: 

6677 

6678 The :attr:`_sql.Select.selected_columns` collection does not 

6679 include expressions established in the columns clause using the 

6680 :func:`_sql.text` construct; these are silently omitted from the 

6681 collection. To use plain textual column expressions inside of a 

6682 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6683 construct. 

6684 

6685 

6686 .. versionadded:: 1.4 

6687 

6688 """ 

6689 

6690 # compare to SelectState._generate_columns_plus_names, which 

6691 # generates the actual names used in the SELECT string. that 

6692 # method is more complex because it also renders columns that are 

6693 # fully ambiguous, e.g. same column more than once. 

6694 conv = cast( 

6695 "Callable[[Any], str]", 

6696 SelectState._column_naming_convention(self._label_style), 

6697 ) 

6698 

6699 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6700 [ 

6701 (conv(c), c) 

6702 for c in self._all_selected_columns 

6703 if is_column_element(c) 

6704 ] 

6705 ) 

6706 return cc.as_readonly() 

6707 

6708 @HasMemoized_ro_memoized_attribute 

6709 def _all_selected_columns(self) -> _SelectIterable: 

6710 meth = SelectState.get_plugin_class(self).all_selected_columns 

6711 return list(meth(self)) 

6712 

6713 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6714 if self._label_style is LABEL_STYLE_NONE: 

6715 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6716 return self 

6717 

6718 def _generate_fromclause_column_proxies( 

6719 self, 

6720 subquery: FromClause, 

6721 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

6722 primary_key: ColumnSet, 

6723 foreign_keys: Set[KeyedColumnElement[Any]], 

6724 *, 

6725 proxy_compound_columns: Optional[ 

6726 Iterable[Sequence[ColumnElement[Any]]] 

6727 ] = None, 

6728 ) -> None: 

6729 """Generate column proxies to place in the exported ``.c`` 

6730 collection of a subquery.""" 

6731 

6732 if proxy_compound_columns: 

6733 extra_col_iterator = proxy_compound_columns 

6734 prox = [ 

6735 c._make_proxy( 

6736 subquery, 

6737 key=proxy_key, 

6738 name=required_label_name, 

6739 name_is_truncatable=True, 

6740 compound_select_cols=extra_cols, 

6741 primary_key=primary_key, 

6742 foreign_keys=foreign_keys, 

6743 ) 

6744 for ( 

6745 ( 

6746 required_label_name, 

6747 proxy_key, 

6748 fallback_label_name, 

6749 c, 

6750 repeated, 

6751 ), 

6752 extra_cols, 

6753 ) in ( 

6754 zip( 

6755 self._generate_columns_plus_names(False), 

6756 extra_col_iterator, 

6757 ) 

6758 ) 

6759 if is_column_element(c) 

6760 ] 

6761 else: 

6762 prox = [ 

6763 c._make_proxy( 

6764 subquery, 

6765 key=proxy_key, 

6766 name=required_label_name, 

6767 name_is_truncatable=True, 

6768 primary_key=primary_key, 

6769 foreign_keys=foreign_keys, 

6770 ) 

6771 for ( 

6772 required_label_name, 

6773 proxy_key, 

6774 fallback_label_name, 

6775 c, 

6776 repeated, 

6777 ) in (self._generate_columns_plus_names(False)) 

6778 if is_column_element(c) 

6779 ] 

6780 

6781 columns._populate_separate_keys(prox) 

6782 

6783 def _needs_parens_for_grouping(self) -> bool: 

6784 return self._has_row_limiting_clause or bool( 

6785 self._order_by_clause.clauses 

6786 ) 

6787 

6788 def self_group( 

6789 self, against: Optional[OperatorType] = None 

6790 ) -> Union[SelectStatementGrouping[Self], Self]: 

6791 """Return a 'grouping' construct as per the 

6792 :class:`_expression.ClauseElement` specification. 

6793 

6794 This produces an element that can be embedded in an expression. Note 

6795 that this method is called automatically as needed when constructing 

6796 expressions and should not require explicit use. 

6797 

6798 """ 

6799 if ( 

6800 isinstance(against, CompoundSelect) 

6801 and not self._needs_parens_for_grouping() 

6802 ): 

6803 return self 

6804 else: 

6805 return SelectStatementGrouping(self) 

6806 

6807 def union( 

6808 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6809 ) -> CompoundSelect[Unpack[_Ts]]: 

6810 r"""Return a SQL ``UNION`` of this select() construct against 

6811 the given selectables provided as positional arguments. 

6812 

6813 :param \*other: one or more elements with which to create a 

6814 UNION. 

6815 

6816 .. versionchanged:: 1.4.28 

6817 

6818 multiple elements are now accepted. 

6819 

6820 :param \**kwargs: keyword arguments are forwarded to the constructor 

6821 for the newly created :class:`_sql.CompoundSelect` object. 

6822 

6823 """ 

6824 return CompoundSelect._create_union(self, *other) 

6825 

6826 def union_all( 

6827 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6828 ) -> CompoundSelect[Unpack[_Ts]]: 

6829 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6830 the given selectables provided as positional arguments. 

6831 

6832 :param \*other: one or more elements with which to create a 

6833 UNION. 

6834 

6835 .. versionchanged:: 1.4.28 

6836 

6837 multiple elements are now accepted. 

6838 

6839 :param \**kwargs: keyword arguments are forwarded to the constructor 

6840 for the newly created :class:`_sql.CompoundSelect` object. 

6841 

6842 """ 

6843 return CompoundSelect._create_union_all(self, *other) 

6844 

6845 def except_( 

6846 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6847 ) -> CompoundSelect[Unpack[_Ts]]: 

6848 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6849 the given selectable provided as positional arguments. 

6850 

6851 :param \*other: one or more elements with which to create a 

6852 UNION. 

6853 

6854 .. versionchanged:: 1.4.28 

6855 

6856 multiple elements are now accepted. 

6857 

6858 """ 

6859 return CompoundSelect._create_except(self, *other) 

6860 

6861 def except_all( 

6862 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6863 ) -> CompoundSelect[Unpack[_Ts]]: 

6864 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6865 the given selectables provided as positional arguments. 

6866 

6867 :param \*other: one or more elements with which to create a 

6868 UNION. 

6869 

6870 .. versionchanged:: 1.4.28 

6871 

6872 multiple elements are now accepted. 

6873 

6874 """ 

6875 return CompoundSelect._create_except_all(self, *other) 

6876 

6877 def intersect( 

6878 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6879 ) -> CompoundSelect[Unpack[_Ts]]: 

6880 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6881 the given selectables provided as positional arguments. 

6882 

6883 :param \*other: one or more elements with which to create a 

6884 UNION. 

6885 

6886 .. versionchanged:: 1.4.28 

6887 

6888 multiple elements are now accepted. 

6889 

6890 :param \**kwargs: keyword arguments are forwarded to the constructor 

6891 for the newly created :class:`_sql.CompoundSelect` object. 

6892 

6893 """ 

6894 return CompoundSelect._create_intersect(self, *other) 

6895 

6896 def intersect_all( 

6897 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6898 ) -> CompoundSelect[Unpack[_Ts]]: 

6899 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6900 against the given selectables provided as positional arguments. 

6901 

6902 :param \*other: one or more elements with which to create a 

6903 UNION. 

6904 

6905 .. versionchanged:: 1.4.28 

6906 

6907 multiple elements are now accepted. 

6908 

6909 :param \**kwargs: keyword arguments are forwarded to the constructor 

6910 for the newly created :class:`_sql.CompoundSelect` object. 

6911 

6912 """ 

6913 return CompoundSelect._create_intersect_all(self, *other) 

6914 

6915 

6916class ScalarSelect( 

6917 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6918): 

6919 """Represent a scalar subquery. 

6920 

6921 

6922 A :class:`_sql.ScalarSelect` is created by invoking the 

6923 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6924 then participates in other SQL expressions as a SQL column expression 

6925 within the :class:`_sql.ColumnElement` hierarchy. 

6926 

6927 .. seealso:: 

6928 

6929 :meth:`_sql.SelectBase.scalar_subquery` 

6930 

6931 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6932 

6933 """ 

6934 

6935 _traverse_internals: _TraverseInternalsType = [ 

6936 ("element", InternalTraversal.dp_clauseelement), 

6937 ("type", InternalTraversal.dp_type), 

6938 ] 

6939 

6940 _from_objects: List[FromClause] = [] 

6941 _is_from_container = True 

6942 if not TYPE_CHECKING: 

6943 _is_implicitly_boolean = False 

6944 inherit_cache = True 

6945 

6946 element: SelectBase 

6947 

6948 def __init__(self, element: SelectBase) -> None: 

6949 self.element = element 

6950 self.type = element._scalar_type() 

6951 self._propagate_attrs = element._propagate_attrs 

6952 

6953 def __getattr__(self, attr: str) -> Any: 

6954 return getattr(self.element, attr) 

6955 

6956 def __getstate__(self) -> Dict[str, Any]: 

6957 return {"element": self.element, "type": self.type} 

6958 

6959 def __setstate__(self, state: Dict[str, Any]) -> None: 

6960 self.element = state["element"] 

6961 self.type = state["type"] 

6962 

6963 @property 

6964 def columns(self) -> NoReturn: 

6965 raise exc.InvalidRequestError( 

6966 "Scalar Select expression has no " 

6967 "columns; use this object directly " 

6968 "within a column-level expression." 

6969 ) 

6970 

6971 c = columns 

6972 

6973 @_generative 

6974 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6975 """Apply a WHERE clause to the SELECT statement referred to 

6976 by this :class:`_expression.ScalarSelect`. 

6977 

6978 """ 

6979 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6980 crit 

6981 ) 

6982 return self 

6983 

6984 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6985 return self 

6986 

6987 def _ungroup(self) -> Self: 

6988 return self 

6989 

6990 @_generative 

6991 def correlate( 

6992 self, 

6993 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6994 ) -> Self: 

6995 r"""Return a new :class:`_expression.ScalarSelect` 

6996 which will correlate the given FROM 

6997 clauses to that of an enclosing :class:`_expression.Select`. 

6998 

6999 This method is mirrored from the :meth:`_sql.Select.correlate` method 

7000 of the underlying :class:`_sql.Select`. The method applies the 

7001 :meth:_sql.Select.correlate` method, then returns a new 

7002 :class:`_sql.ScalarSelect` against that statement. 

7003 

7004 .. versionadded:: 1.4 Previously, the 

7005 :meth:`_sql.ScalarSelect.correlate` 

7006 method was only available from :class:`_sql.Select`. 

7007 

7008 :param \*fromclauses: a list of one or more 

7009 :class:`_expression.FromClause` 

7010 constructs, or other compatible constructs (i.e. ORM-mapped 

7011 classes) to become part of the correlate collection. 

7012 

7013 .. seealso:: 

7014 

7015 :meth:`_expression.ScalarSelect.correlate_except` 

7016 

7017 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7018 

7019 

7020 """ 

7021 self.element = cast( 

7022 "Select[Unpack[TupleAny]]", self.element 

7023 ).correlate(*fromclauses) 

7024 return self 

7025 

7026 @_generative 

7027 def correlate_except( 

7028 self, 

7029 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7030 ) -> Self: 

7031 r"""Return a new :class:`_expression.ScalarSelect` 

7032 which will omit the given FROM 

7033 clauses from the auto-correlation process. 

7034 

7035 This method is mirrored from the 

7036 :meth:`_sql.Select.correlate_except` method of the underlying 

7037 :class:`_sql.Select`. The method applies the 

7038 :meth:_sql.Select.correlate_except` method, then returns a new 

7039 :class:`_sql.ScalarSelect` against that statement. 

7040 

7041 .. versionadded:: 1.4 Previously, the 

7042 :meth:`_sql.ScalarSelect.correlate_except` 

7043 method was only available from :class:`_sql.Select`. 

7044 

7045 :param \*fromclauses: a list of one or more 

7046 :class:`_expression.FromClause` 

7047 constructs, or other compatible constructs (i.e. ORM-mapped 

7048 classes) to become part of the correlate-exception collection. 

7049 

7050 .. seealso:: 

7051 

7052 :meth:`_expression.ScalarSelect.correlate` 

7053 

7054 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7055 

7056 

7057 """ 

7058 

7059 self.element = cast( 

7060 "Select[Unpack[TupleAny]]", self.element 

7061 ).correlate_except(*fromclauses) 

7062 return self 

7063 

7064 

7065class Exists(UnaryExpression[bool]): 

7066 """Represent an ``EXISTS`` clause. 

7067 

7068 See :func:`_sql.exists` for a description of usage. 

7069 

7070 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

7071 instance by calling :meth:`_sql.SelectBase.exists`. 

7072 

7073 """ 

7074 

7075 inherit_cache = True 

7076 

7077 def __init__( 

7078 self, 

7079 __argument: Optional[ 

7080 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

7081 ] = None, 

7082 /, 

7083 ): 

7084 s: ScalarSelect[Any] 

7085 

7086 # TODO: this seems like we should be using coercions for this 

7087 if __argument is None: 

7088 s = Select(literal_column("*")).scalar_subquery() 

7089 elif isinstance(__argument, SelectBase): 

7090 s = __argument.scalar_subquery() 

7091 s._propagate_attrs = __argument._propagate_attrs 

7092 elif isinstance(__argument, ScalarSelect): 

7093 s = __argument 

7094 else: 

7095 s = Select(__argument).scalar_subquery() 

7096 

7097 UnaryExpression.__init__( 

7098 self, 

7099 s, 

7100 operator=operators.exists, 

7101 type_=type_api.BOOLEANTYPE, 

7102 ) 

7103 

7104 @util.ro_non_memoized_property 

7105 def _from_objects(self) -> List[FromClause]: 

7106 return [] 

7107 

7108 def _regroup( 

7109 self, 

7110 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7111 ) -> ScalarSelect[Any]: 

7112 

7113 assert isinstance(self.element, ScalarSelect) 

7114 element = self.element.element 

7115 if not isinstance(element, Select): 

7116 raise exc.InvalidRequestError( 

7117 "Can only apply this operation to a plain SELECT construct" 

7118 ) 

7119 new_element = fn(element) 

7120 

7121 return_value = new_element.scalar_subquery() 

7122 return return_value 

7123 

7124 def select(self) -> Select[bool]: 

7125 r"""Return a SELECT of this :class:`_expression.Exists`. 

7126 

7127 e.g.:: 

7128 

7129 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7130 

7131 This will produce a statement resembling: 

7132 

7133 .. sourcecode:: sql 

7134 

7135 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7136 

7137 .. seealso:: 

7138 

7139 :func:`_expression.select` - general purpose 

7140 method which allows for arbitrary column lists. 

7141 

7142 """ # noqa 

7143 

7144 return Select(self) 

7145 

7146 def correlate( 

7147 self, 

7148 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7149 ) -> Self: 

7150 """Apply correlation to the subquery noted by this 

7151 :class:`_sql.Exists`. 

7152 

7153 .. seealso:: 

7154 

7155 :meth:`_sql.ScalarSelect.correlate` 

7156 

7157 """ 

7158 e = self._clone() 

7159 e.element = self._regroup( 

7160 lambda element: element.correlate(*fromclauses) 

7161 ) 

7162 return e 

7163 

7164 def correlate_except( 

7165 self, 

7166 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7167 ) -> Self: 

7168 """Apply correlation to the subquery noted by this 

7169 :class:`_sql.Exists`. 

7170 

7171 .. seealso:: 

7172 

7173 :meth:`_sql.ScalarSelect.correlate_except` 

7174 

7175 """ 

7176 e = self._clone() 

7177 e.element = self._regroup( 

7178 lambda element: element.correlate_except(*fromclauses) 

7179 ) 

7180 return e 

7181 

7182 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7183 """Return a new :class:`_expression.Exists` construct, 

7184 applying the given 

7185 expression to the :meth:`_expression.Select.select_from` 

7186 method of the select 

7187 statement contained. 

7188 

7189 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7190 statement first, including the desired WHERE clause, then use the 

7191 :meth:`_sql.SelectBase.exists` method to produce an 

7192 :class:`_sql.Exists` object at once. 

7193 

7194 """ 

7195 e = self._clone() 

7196 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7197 return e 

7198 

7199 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7200 """Return a new :func:`_expression.exists` construct with the 

7201 given expression added to 

7202 its WHERE clause, joined to the existing clause via AND, if any. 

7203 

7204 

7205 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7206 statement first, including the desired WHERE clause, then use the 

7207 :meth:`_sql.SelectBase.exists` method to produce an 

7208 :class:`_sql.Exists` object at once. 

7209 

7210 """ 

7211 e = self._clone() 

7212 e.element = self._regroup(lambda element: element.where(*clause)) 

7213 return e 

7214 

7215 

7216class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7217 """Wrap a :class:`_expression.TextClause` construct within a 

7218 :class:`_expression.SelectBase` 

7219 interface. 

7220 

7221 This allows the :class:`_expression.TextClause` object to gain a 

7222 ``.c`` collection 

7223 and other FROM-like capabilities such as 

7224 :meth:`_expression.FromClause.alias`, 

7225 :meth:`_expression.SelectBase.cte`, etc. 

7226 

7227 The :class:`_expression.TextualSelect` construct is produced via the 

7228 :meth:`_expression.TextClause.columns` 

7229 method - see that method for details. 

7230 

7231 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7232 class was renamed 

7233 from ``TextAsFrom``, to more correctly suit its role as a 

7234 SELECT-oriented object and not a FROM clause. 

7235 

7236 .. seealso:: 

7237 

7238 :func:`_expression.text` 

7239 

7240 :meth:`_expression.TextClause.columns` - primary creation interface. 

7241 

7242 """ 

7243 

7244 __visit_name__ = "textual_select" 

7245 

7246 _label_style = LABEL_STYLE_NONE 

7247 

7248 _traverse_internals: _TraverseInternalsType = ( 

7249 [ 

7250 ("element", InternalTraversal.dp_clauseelement), 

7251 ("column_args", InternalTraversal.dp_clauseelement_list), 

7252 ] 

7253 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7254 + HasCTE._has_ctes_traverse_internals 

7255 + ExecutableStatement._executable_traverse_internals 

7256 ) 

7257 

7258 _is_textual = True 

7259 

7260 is_text = True 

7261 is_select = True 

7262 

7263 def __init__( 

7264 self, 

7265 text: TextClause, 

7266 columns: List[_ColumnExpressionArgument[Any]], 

7267 positional: bool = False, 

7268 ) -> None: 

7269 self._init( 

7270 text, 

7271 # convert for ORM attributes->columns, etc 

7272 [ 

7273 coercions.expect(roles.LabeledColumnExprRole, c) 

7274 for c in columns 

7275 ], 

7276 positional, 

7277 ) 

7278 

7279 def _init( 

7280 self, 

7281 text: TextClause, 

7282 columns: List[NamedColumn[Any]], 

7283 positional: bool = False, 

7284 ) -> None: 

7285 self.element = text 

7286 self.column_args = columns 

7287 self.positional = positional 

7288 

7289 @HasMemoized_ro_memoized_attribute 

7290 def selected_columns( 

7291 self, 

7292 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7293 """A :class:`_expression.ColumnCollection` 

7294 representing the columns that 

7295 this SELECT statement or similar construct returns in its result set, 

7296 not including :class:`_sql.TextClause` constructs. 

7297 

7298 This collection differs from the :attr:`_expression.FromClause.columns` 

7299 collection of a :class:`_expression.FromClause` in that the columns 

7300 within this collection cannot be directly nested inside another SELECT 

7301 statement; a subquery must be applied first which provides for the 

7302 necessary parenthesization required by SQL. 

7303 

7304 For a :class:`_expression.TextualSelect` construct, the collection 

7305 contains the :class:`_expression.ColumnElement` objects that were 

7306 passed to the constructor, typically via the 

7307 :meth:`_expression.TextClause.columns` method. 

7308 

7309 

7310 .. versionadded:: 1.4 

7311 

7312 """ 

7313 return ColumnCollection( 

7314 (c.key, c) for c in self.column_args 

7315 ).as_readonly() 

7316 

7317 @util.ro_non_memoized_property 

7318 def _all_selected_columns(self) -> _SelectIterable: 

7319 return self.column_args 

7320 

7321 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7322 return self 

7323 

7324 def _ensure_disambiguated_names(self) -> TextualSelect: 

7325 return self 

7326 

7327 @_generative 

7328 def bindparams( 

7329 self, 

7330 *binds: BindParameter[Any], 

7331 **bind_as_values: Any, 

7332 ) -> Self: 

7333 self.element = self.element.bindparams(*binds, **bind_as_values) 

7334 return self 

7335 

7336 def _generate_fromclause_column_proxies( 

7337 self, 

7338 fromclause: FromClause, 

7339 columns: ColumnCollection[str, KeyedColumnElement[Any]], 

7340 primary_key: ColumnSet, 

7341 foreign_keys: Set[KeyedColumnElement[Any]], 

7342 *, 

7343 proxy_compound_columns: Optional[ 

7344 Iterable[Sequence[ColumnElement[Any]]] 

7345 ] = None, 

7346 ) -> None: 

7347 if TYPE_CHECKING: 

7348 assert isinstance(fromclause, Subquery) 

7349 

7350 if proxy_compound_columns: 

7351 columns._populate_separate_keys( 

7352 c._make_proxy( 

7353 fromclause, 

7354 compound_select_cols=extra_cols, 

7355 primary_key=primary_key, 

7356 foreign_keys=foreign_keys, 

7357 ) 

7358 for c, extra_cols in zip( 

7359 self.column_args, proxy_compound_columns 

7360 ) 

7361 ) 

7362 else: 

7363 columns._populate_separate_keys( 

7364 c._make_proxy( 

7365 fromclause, 

7366 primary_key=primary_key, 

7367 foreign_keys=foreign_keys, 

7368 ) 

7369 for c in self.column_args 

7370 ) 

7371 

7372 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7373 return self.column_args[0].type 

7374 

7375 

7376TextAsFrom = TextualSelect 

7377"""Backwards compatibility with the previous name""" 

7378 

7379 

7380class AnnotatedFromClause(Annotated): 

7381 def _copy_internals( 

7382 self, 

7383 _annotations_traversal: bool = False, 

7384 ind_cols_on_fromclause: bool = False, 

7385 **kw: Any, 

7386 ) -> None: 

7387 super()._copy_internals(**kw) 

7388 

7389 # passed from annotations._shallow_annotate(), _deep_annotate(), etc. 

7390 # the traversals used by annotations for these cases are not currently 

7391 # designed around expecting that inner elements inside of 

7392 # AnnotatedFromClause's element are also deep copied, so skip for these 

7393 # cases. in other cases such as plain visitors.cloned_traverse(), we 

7394 # expect this to happen. see issue #12915 

7395 if not _annotations_traversal: 

7396 ee = self._Annotated__element # type: ignore 

7397 ee._copy_internals(**kw) 

7398 

7399 if ind_cols_on_fromclause: 

7400 # passed from annotations._deep_annotate(). See that function 

7401 # for notes 

7402 ee = self._Annotated__element # type: ignore 

7403 self.c = ee.__class__.c.fget(self) # type: ignore 

7404 

7405 @util.ro_memoized_property 

7406 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7407 """proxy the .c collection of the underlying FromClause. 

7408 

7409 Originally implemented in 2008 as a simple load of the .c collection 

7410 when the annotated construct was created (see d3621ae961a), in modern 

7411 SQLAlchemy versions this can be expensive for statements constructed 

7412 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7413 it, which works just as well. 

7414 

7415 Two different use cases seem to require the collection either copied 

7416 from the underlying one, or unique to this AnnotatedFromClause. 

7417 

7418 See test_selectable->test_annotated_corresponding_column 

7419 

7420 """ 

7421 ee = self._Annotated__element # type: ignore 

7422 return ee.c # type: ignore