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

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

1828 statements  

1# sql/selectable.py 

2# Copyright (C) 2005-2026 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 

19import os 

20from typing import AbstractSet 

21from typing import Any as TODO_Any 

22from typing import Any 

23from typing import Callable 

24from typing import cast 

25from typing import Collection 

26from typing import Dict 

27from typing import Generic 

28from typing import Iterable 

29from typing import Iterator 

30from typing import List 

31from typing import Literal 

32from typing import NamedTuple 

33from typing import NoReturn 

34from typing import Optional 

35from typing import overload 

36from typing import Protocol 

37from typing import Sequence 

38from typing import Set 

39from typing import Tuple 

40from typing import Type 

41from typing import TYPE_CHECKING 

42from typing import TypeVar 

43from typing import Union 

44 

45from . import cache_key 

46from . import coercions 

47from . import operators 

48from . import roles 

49from . import traversals 

50from . import type_api 

51from . import visitors 

52from ._annotated_cols import _ColClauseCC_co 

53from ._annotated_cols import _KeyColCC_co 

54from ._annotated_cols import _TC_co 

55from ._annotated_cols import HasRowPos 

56from ._typing import _ColumnsClauseArgument 

57from ._typing import _no_kw 

58from ._typing import _T 

59from ._typing import _Ts 

60from ._typing import is_column_element 

61from ._typing import is_select_statement 

62from ._typing import is_subquery 

63from ._typing import is_table 

64from ._typing import is_text_clause 

65from .annotation import Annotated 

66from .annotation import SupportsCloneAnnotations 

67from .base import _clone 

68from .base import _cloned_difference 

69from .base import _cloned_intersection 

70from .base import _entity_namespace_key_search_all 

71from .base import _EntityNamespace 

72from .base import _expand_cloned 

73from .base import _from_objects 

74from .base import _generative 

75from .base import _never_select_column 

76from .base import _NoArg 

77from .base import _select_iterables 

78from .base import CacheableOptions 

79from .base import ColumnCollection 

80from .base import ColumnSet 

81from .base import CompileState 

82from .base import DedupeColumnCollection 

83from .base import DialectKWArgs 

84from .base import Executable 

85from .base import ExecutableStatement 

86from .base import Generative 

87from .base import HasCompileState 

88from .base import HasMemoized 

89from .base import HasSyntaxExtensions 

90from .base import Immutable 

91from .base import SyntaxExtension 

92from .base import WriteableColumnCollection 

93from .coercions import _document_text_coercion 

94from .elements import _anonymous_label 

95from .elements import BindParameter 

96from .elements import BooleanClauseList 

97from .elements import ClauseElement 

98from .elements import ClauseList 

99from .elements import ColumnClause 

100from .elements import ColumnElement 

101from .elements import DQLDMLClauseElement 

102from .elements import GroupedElement 

103from .elements import literal_column 

104from .elements import TableValuedColumn 

105from .elements import TextClause 

106from .elements import UnaryExpression 

107from .operators import OperatorType 

108from .sqltypes import NULLTYPE 

109from .visitors import _TraverseInternalsType 

110from .visitors import InternalTraversal 

111from .visitors import prefix_anon_map 

112from .. import exc 

113from .. import util 

114from ..util import HasMemoized_ro_memoized_attribute 

115from ..util import warn_deprecated 

116from ..util.typing import Self 

117from ..util.typing import TupleAny 

118from ..util.typing import Unpack 

119 

120and_ = BooleanClauseList.and_ 

121 

122 

123if TYPE_CHECKING: 

124 from ._typing import _ColumnExpressionArgument 

125 from ._typing import _ColumnExpressionOrStrLabelArgument 

126 from ._typing import _FromClauseArgument 

127 from ._typing import _JoinTargetArgument 

128 from ._typing import _LimitOffsetType 

129 from ._typing import _MAYBE_ENTITY 

130 from ._typing import _NOT_ENTITY 

131 from ._typing import _OnClauseArgument 

132 from ._typing import _OnlyColumnArgument 

133 from ._typing import _SelectStatementForCompoundArgument 

134 from ._typing import _T0 

135 from ._typing import _T1 

136 from ._typing import _T2 

137 from ._typing import _T3 

138 from ._typing import _T4 

139 from ._typing import _T5 

140 from ._typing import _T6 

141 from ._typing import _T7 

142 from ._typing import _TextCoercedExpressionArgument 

143 from ._typing import _TypedColumnClauseArgument as _TCCA 

144 from ._typing import _TypeEngineArgument 

145 from .base import _AmbiguousTableNameMap 

146 from .base import ExecutableOption 

147 from .base import ReadOnlyColumnCollection 

148 from .cache_key import _CacheKeyTraversalType 

149 from .compiler import SQLCompiler 

150 from .ddl import CreateTableAs 

151 from .dml import Delete 

152 from .dml import Update 

153 from .elements import AbstractTextClause 

154 from .elements import BinaryExpression 

155 from .elements import KeyedColumnElement 

156 from .elements import Label 

157 from .elements import NamedColumn 

158 from .functions import Function 

159 from .schema import ForeignKey 

160 from .schema import ForeignKeyConstraint 

161 from .schema import MetaData 

162 from .sqltypes import TableValueType 

163 from .type_api import TypeEngine 

164 from .visitors import _CloneCallableType 

165 

166 

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

168_LabelConventionCallable = Callable[ 

169 [Union["ColumnElement[Any]", "AbstractTextClause"]], Optional[str] 

170] 

171 

172 

173class _JoinTargetProtocol(Protocol): 

174 @util.ro_non_memoized_property 

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

176 

177 @util.ro_non_memoized_property 

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

179 

180 

181_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

183 

184_ForUpdateOfArgument = Union[ 

185 # single column, Table, ORM entity 

186 Union[ 

187 "_ColumnExpressionArgument[Any]", 

188 "_FromClauseArgument", 

189 ], 

190 # or sequence of column, Table, ORM entity 

191 Sequence[ 

192 Union[ 

193 "_ColumnExpressionArgument[Any]", 

194 "_FromClauseArgument", 

195 ] 

196 ], 

197] 

198 

199 

200_SetupJoinsElement = Tuple[ 

201 _JoinTargetElement, 

202 Optional[_OnClauseElement], 

203 Optional["FromClause"], 

204 Dict[str, Any], 

205] 

206 

207 

208_SelectIterable = Iterable[Union["ColumnElement[Any]", "AbstractTextClause"]] 

209 

210 

211class _OffsetLimitParam(BindParameter[int]): 

212 inherit_cache = True 

213 

214 @property 

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

216 return self.effective_value 

217 

218 

219class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

221 columns that can represent rows. 

222 

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

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

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

226 PostgreSQL has functions that return rows also. 

227 

228 .. versionadded:: 1.4 

229 

230 """ 

231 

232 _is_returns_rows = True 

233 

234 # sub-elements of returns_rows 

235 _is_from_clause = False 

236 _is_select_base = False 

237 _is_select_statement = False 

238 _is_lateral = False 

239 

240 @property 

241 def selectable(self) -> ReturnsRows: 

242 return self 

243 

244 @util.ro_non_memoized_property 

245 def _all_selected_columns(self) -> _SelectIterable: 

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

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

248 

249 This is typically equivalent to .exported_columns except it is 

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

251 :class:`_expression.ColumnCollection`. 

252 

253 """ 

254 raise NotImplementedError() 

255 

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

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

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

259 

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

261 

262 """ 

263 raise NotImplementedError() 

264 

265 def _generate_fromclause_column_proxies( 

266 self, 

267 fromclause: FromClause, 

268 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

269 primary_key: ColumnSet, 

270 foreign_keys: Set[KeyedColumnElement[Any]], 

271 ) -> None: 

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

273 

274 raise NotImplementedError() 

275 

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

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

278 raise NotImplementedError() 

279 

280 @property 

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

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

283 that represents the "exported" 

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

285 

286 The "exported" columns represent the collection of 

287 :class:`_expression.ColumnElement` 

288 expressions that are rendered by this SQL 

289 construct. There are primary varieties which are the 

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

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

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

293 columns in a DML statement.. 

294 

295 .. versionadded:: 1.4 

296 

297 .. seealso:: 

298 

299 :attr:`_expression.FromClause.exported_columns` 

300 

301 :attr:`_expression.SelectBase.exported_columns` 

302 """ 

303 

304 raise NotImplementedError() 

305 

306 

307class ExecutableReturnsRows(ExecutableStatement, ReturnsRows): 

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

309 

310 

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

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

313 

314 

315class Selectable(ReturnsRows): 

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

317 

318 __visit_name__ = "selectable" 

319 

320 is_selectable = True 

321 

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

323 raise NotImplementedError() 

324 

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

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

327 

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

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

330 

331 .. seealso:: 

332 

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

334 

335 """ 

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

337 

338 @util.deprecated( 

339 "1.4", 

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

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

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

343 ) 

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

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

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

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

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

349 

350 """ 

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

352 

353 def corresponding_column( 

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

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

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

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

358 :attr:`_expression.Selectable.exported_columns` 

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

360 which corresponds to that 

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

362 column. 

363 

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

365 to be matched. 

366 

367 :param require_embedded: only return corresponding columns for 

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

369 :class:`_expression.ColumnElement` 

370 is actually present within a sub-element 

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

372 Normally the column will match if 

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

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

375 

376 .. seealso:: 

377 

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

379 :class:`_expression.ColumnCollection` 

380 that is used for the operation. 

381 

382 :meth:`_expression.ColumnCollection.corresponding_column` 

383 - implementation 

384 method. 

385 

386 """ 

387 

388 return self.exported_columns.corresponding_column( 

389 column, require_embedded 

390 ) 

391 

392 

393class HasPrefixes: 

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

395 

396 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

397 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

398 ] 

399 

400 @_generative 

401 @_document_text_coercion( 

402 "prefixes", 

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

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

405 ) 

406 def prefix_with( 

407 self, 

408 *prefixes: _TextCoercedExpressionArgument[Any], 

409 dialect: str = "*", 

410 ) -> Self: 

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

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

413 

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

415 provided by MySQL. 

416 

417 E.g.:: 

418 

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

420 

421 # MySQL 5.7 optimizer hints 

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

423 

424 Multiple prefixes can be specified by multiple calls 

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

426 

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

428 construct which 

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

430 keyword. 

431 :param dialect: optional string dialect name which will 

432 limit rendering of this prefix to only that dialect. 

433 

434 """ 

435 self._prefixes = self._prefixes + tuple( 

436 [ 

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

438 for p in prefixes 

439 ] 

440 ) 

441 return self 

442 

443 

444class HasSuffixes: 

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

446 

447 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

448 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

449 ] 

450 

451 @_generative 

452 @_document_text_coercion( 

453 "suffixes", 

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

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

456 ) 

457 def suffix_with( 

458 self, 

459 *suffixes: _TextCoercedExpressionArgument[Any], 

460 dialect: str = "*", 

461 ) -> Self: 

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

463 

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

465 certain constructs. 

466 

467 E.g.:: 

468 

469 stmt = ( 

470 select(col1, col2) 

471 .cte() 

472 .suffix_with( 

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

474 ) 

475 ) 

476 

477 Multiple suffixes can be specified by multiple calls 

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

479 

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

481 construct which 

482 will be rendered following the target clause. 

483 :param dialect: Optional string dialect name which will 

484 limit rendering of this suffix to only that dialect. 

485 

486 """ 

487 self._suffixes = self._suffixes + tuple( 

488 [ 

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

490 for p in suffixes 

491 ] 

492 ) 

493 return self 

494 

495 

496class HasHints: 

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

498 util.immutabledict() 

499 ) 

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

501 

502 _has_hints_traverse_internals: _TraverseInternalsType = [ 

503 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

504 ("_hints", InternalTraversal.dp_table_hint_list), 

505 ] 

506 

507 @_generative 

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

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

510 other selectable object. 

511 

512 .. tip:: 

513 

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

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

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

517 the SELECT statement after the SELECT keyword, use the 

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

519 space, or for table-specific hints the 

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

521 hints in a dialect-specific location. 

522 

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

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

525 the statement as a whole. 

526 

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

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

529 etc. 

530 

531 .. seealso:: 

532 

533 :meth:`_expression.Select.with_hint` 

534 

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

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

537 MySQL or Oracle Database optimizer hints 

538 

539 """ 

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

541 

542 @_generative 

543 def with_hint( 

544 self, 

545 selectable: _FromClauseArgument, 

546 text: str, 

547 dialect_name: str = "*", 

548 ) -> Self: 

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

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

551 object. 

552 

553 .. tip:: 

554 

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

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

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

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

559 for MySQL or Oracle Database, use the 

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

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

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

563 

564 The text of the hint is rendered in the appropriate 

565 location for the database backend in use, relative 

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

567 passed as the 

568 ``selectable`` argument. The dialect implementation 

569 typically uses Python string substitution syntax 

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

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

572 following:: 

573 

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

575 

576 Would render SQL as: 

577 

578 .. sourcecode:: sql 

579 

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

581 

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

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

584 Database and MSSql simultaneously:: 

585 

586 select(mytable).with_hint( 

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

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

589 

590 .. seealso:: 

591 

592 :meth:`_expression.Select.with_statement_hint` 

593 

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

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

596 MySQL or Oracle Database optimizer hints 

597 

598 """ 

599 

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

601 

602 def _with_hint( 

603 self, 

604 selectable: Optional[_FromClauseArgument], 

605 text: str, 

606 dialect_name: str, 

607 ) -> Self: 

608 if selectable is None: 

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

610 else: 

611 self._hints = self._hints.union( 

612 { 

613 ( 

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

615 dialect_name, 

616 ): text 

617 } 

618 ) 

619 return self 

620 

621 

622class FromClause( 

623 roles.AnonymizedFromClauseRole, Generic[_KeyColCC_co], Selectable 

624): 

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

626 clause of a ``SELECT`` statement. 

627 

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

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

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

631 

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

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

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

635 :class:`_expression.ColumnElement` 

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

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

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

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

640 :meth:`_expression.FromClause.select`. 

641 

642 

643 """ 

644 

645 __visit_name__ = "fromclause" 

646 named_with_column = False 

647 

648 @util.ro_non_memoized_property 

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

650 return () 

651 

652 _is_clone_of: Optional[FromClause[_KeyColCC_co]] 

653 

654 _columns: WriteableColumnCollection[Any, Any] 

655 

656 schema: Optional[str] = None 

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

658 

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

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

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

662 

663 """ 

664 

665 is_selectable = True 

666 _is_from_clause = True 

667 _is_join = False 

668 

669 _use_schema_map = False 

670 

671 def with_cols(self, type_: Type[_TC_co]) -> FromClause[_TC_co]: 

672 """Cast this :class:`.FromClause` to be generic on a specific a 

673 :class:`_schema.TypedColumns` subclass. 

674 

675 At runtime returns self unchanged, without performing any validation. 

676 """ 

677 return self # type: ignore[return-value] 

678 

679 @overload 

680 def select( 

681 self: FromClause[HasRowPos[Unpack[_Ts]]], # type: ignore[type-var] 

682 ) -> Select[Unpack[_Ts]]: ... 

683 @overload 

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

685 

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

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

688 

689 

690 e.g.:: 

691 

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

693 

694 .. seealso:: 

695 

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

697 method which allows for arbitrary column lists. 

698 

699 """ 

700 return Select(self) 

701 

702 def join( 

703 self, 

704 right: _FromClauseArgument, 

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

706 isouter: bool = False, 

707 full: bool = False, 

708 ) -> Join: 

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

710 :class:`_expression.FromClause` 

711 to another :class:`FromClause`. 

712 

713 E.g.:: 

714 

715 from sqlalchemy import join 

716 

717 j = user_table.join( 

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

719 ) 

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

721 

722 would emit SQL along the lines of: 

723 

724 .. sourcecode:: sql 

725 

726 SELECT user.id, user.name FROM user 

727 JOIN address ON user.id = address.user_id 

728 

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

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

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

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

733 class. 

734 

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

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

737 will attempt to 

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

739 

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

741 

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

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

744 

745 .. seealso:: 

746 

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

748 

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

750 

751 """ 

752 

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

754 

755 def outerjoin( 

756 self, 

757 right: _FromClauseArgument, 

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

759 full: bool = False, 

760 ) -> Join: 

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

762 :class:`_expression.FromClause` 

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

764 True. 

765 

766 E.g.:: 

767 

768 from sqlalchemy import outerjoin 

769 

770 j = user_table.outerjoin( 

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

772 ) 

773 

774 The above is equivalent to:: 

775 

776 j = user_table.join( 

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

778 ) 

779 

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

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

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

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

784 class. 

785 

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

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

788 will attempt to 

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

790 

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

792 LEFT OUTER JOIN. 

793 

794 .. seealso:: 

795 

796 :meth:`_expression.FromClause.join` 

797 

798 :class:`_expression.Join` 

799 

800 """ # noqa: E501 

801 

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

803 

804 def alias( 

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

806 ) -> NamedFromClause[_KeyColCC_co]: 

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

808 

809 E.g.:: 

810 

811 a2 = some_table.alias("a2") 

812 

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

814 object which can be used 

815 as a FROM clause in any SELECT statement. 

816 

817 .. seealso:: 

818 

819 :ref:`tutorial_using_aliases` 

820 

821 :func:`_expression.alias` 

822 

823 """ 

824 

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

826 

827 def tablesample( 

828 self, 

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

830 name: Optional[str] = None, 

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

832 ) -> TableSample: 

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

834 

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

836 construct also 

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

838 

839 .. seealso:: 

840 

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

842 

843 """ 

844 return TableSample._construct( 

845 self, sampling=sampling, name=name, seed=seed 

846 ) 

847 

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

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

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

851 

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

853 

854 """ 

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

856 # Other constructs override this to traverse through 

857 # contained elements. 

858 return fromclause in self._cloned_set 

859 

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

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

862 the other represent the same lexical identity. 

863 

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

865 if they are the same via annotation identity. 

866 

867 """ 

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

869 

870 @util.ro_non_memoized_property 

871 def description(self) -> str: 

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

873 

874 Used primarily for error message formatting. 

875 

876 """ 

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

878 

879 def _generate_fromclause_column_proxies( 

880 self, 

881 fromclause: FromClause, 

882 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

883 primary_key: ColumnSet, 

884 foreign_keys: Set[KeyedColumnElement[Any]], 

885 ) -> None: 

886 columns._populate_separate_keys( 

887 col._make_proxy( 

888 fromclause, primary_key=primary_key, foreign_keys=foreign_keys 

889 ) 

890 for col in self.c 

891 ) 

892 

893 @util.ro_non_memoized_property 

894 def exported_columns(self) -> _KeyColCC_co: 

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

896 that represents the "exported" 

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

898 

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

900 object are synonymous 

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

902 

903 .. versionadded:: 1.4 

904 

905 .. seealso:: 

906 

907 :attr:`_expression.Selectable.exported_columns` 

908 

909 :attr:`_expression.SelectBase.exported_columns` 

910 

911 

912 """ 

913 return self.c 

914 

915 @util.ro_non_memoized_property 

916 def columns(self) -> _KeyColCC_co: 

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

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

919 

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

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

922 other selectable-bound columns:: 

923 

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

925 

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

927 

928 """ 

929 return self.c 

930 

931 @util.ro_memoized_property 

932 def c(self) -> _KeyColCC_co: 

933 """ 

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

935 

936 :return: a :class:`.ColumnCollection` 

937 

938 """ 

939 if "_columns" not in self.__dict__: 

940 self._setup_collections() 

941 return self._columns.as_readonly() # type: ignore[return-value] 

942 

943 def _setup_collections(self) -> None: 

944 with util.mini_gil: 

945 # detect another thread that raced ahead 

946 if "_columns" in self.__dict__: 

947 assert "primary_key" in self.__dict__ 

948 assert "foreign_keys" in self.__dict__ 

949 return 

950 

951 _columns: WriteableColumnCollection[Any, Any] = ( 

952 WriteableColumnCollection() 

953 ) 

954 primary_key = ColumnSet() 

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

956 

957 self._populate_column_collection( 

958 columns=_columns, 

959 primary_key=primary_key, 

960 foreign_keys=foreign_keys, 

961 ) 

962 

963 # assigning these three collections separately is not itself 

964 # atomic, but greatly reduces the surface for problems. 

965 # _columns is assigned last, as its presence is what signals 

966 # to other threads that all three collections are present 

967 self.primary_key = primary_key # type: ignore[misc] 

968 self.foreign_keys = foreign_keys # type: ignore[assignment, misc] 

969 self._columns = _columns 

970 

971 @util.ro_non_memoized_property 

972 def entity_namespace(self) -> _EntityNamespace: 

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

974 

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

976 expressions, such as:: 

977 

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

979 

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

981 be overridden using the "entity_namespace" annotation to deliver 

982 alternative results. 

983 

984 """ 

985 return self.c 

986 

987 @util.ro_memoized_property 

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

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

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

991 

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

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

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

995 

996 """ 

997 self._setup_collections() 

998 return self.primary_key 

999 

1000 @util.ro_memoized_property 

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

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

1003 which this FromClause references. 

1004 

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

1006 :class:`_schema.Table`-wide 

1007 :class:`_schema.ForeignKeyConstraint`. 

1008 

1009 .. seealso:: 

1010 

1011 :attr:`_schema.Table.foreign_key_constraints` 

1012 

1013 """ 

1014 self._setup_collections() 

1015 return self.foreign_keys 

1016 

1017 def _reset_column_collection(self) -> None: 

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

1019 

1020 This collection is separate from all the other memoized things 

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

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

1023 has already established strong relationships 

1024 with the exported columns. 

1025 

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

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

1028 

1029 """ 

1030 

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

1032 self.__dict__.pop(key, None) 

1033 

1034 @util.ro_non_memoized_property 

1035 def _select_iterable(self) -> _SelectIterable: 

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

1037 

1038 @property 

1039 def _cols_populated(self) -> bool: 

1040 return "_columns" in self.__dict__ 

1041 

1042 def _populate_column_collection( 

1043 self, 

1044 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

1045 primary_key: ColumnSet, 

1046 foreign_keys: Set[KeyedColumnElement[Any]], 

1047 ) -> None: 

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

1049 

1050 Each implementation has a different way of establishing 

1051 this collection. 

1052 

1053 """ 

1054 

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

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

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

1058 selectable ultimately should proxy this column. 

1059 

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

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

1062 Table objects it ultimately derives from. 

1063 

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

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

1066 but it will return None. 

1067 

1068 This method is currently used by Declarative to allow Table 

1069 columns to be added to a partially constructed inheritance 

1070 mapping that may have already produced joins. The method 

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

1072 and/or caveats aren't yet clear. 

1073 

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

1075 default via an event, which would require that 

1076 selectables maintain a weak referencing collection of all 

1077 derivations. 

1078 

1079 """ 

1080 self._reset_column_collection() 

1081 

1082 def _anonymous_fromclause( 

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

1084 ) -> FromClause: 

1085 return self.alias(name=name) 

1086 

1087 if TYPE_CHECKING: 

1088 

1089 def self_group( 

1090 self, against: Optional[OperatorType] = None 

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

1092 

1093 

1094class NamedFromClause(FromClause[_KeyColCC_co]): 

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

1096 

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

1098 

1099 .. versionadded:: 2.0 

1100 

1101 """ 

1102 

1103 named_with_column = True 

1104 

1105 name: str 

1106 

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

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

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

1110 :class:`_expression.FromClause`. 

1111 

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

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

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

1115 such as PostgreSQL, Oracle Database and SQL Server. 

1116 

1117 E.g.: 

1118 

1119 .. sourcecode:: pycon+sql 

1120 

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

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

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

1124 >>> print(stmt) 

1125 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1126 FROM a 

1127 

1128 .. versionadded:: 1.4.0b2 

1129 

1130 .. seealso:: 

1131 

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

1133 

1134 """ 

1135 return TableValuedColumn(self, type_api.TABLEVALUE) 

1136 

1137 if TYPE_CHECKING: 

1138 

1139 def with_cols( 

1140 self, type_: type[_TC_co] 

1141 ) -> NamedFromClause[_TC_co]: ... 

1142 

1143 

1144class SelectLabelStyle(Enum): 

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

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

1147 

1148 LABEL_STYLE_NONE = 0 

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

1150 columns clause of a SELECT statement. 

1151 

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

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

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

1155 

1156 .. sourcecode:: pycon+sql 

1157 

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

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

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

1161 >>> print( 

1162 ... select(table1, table2) 

1163 ... .join(table2, true()) 

1164 ... .set_label_style(LABEL_STYLE_NONE) 

1165 ... ) 

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

1167 FROM table1 JOIN table2 ON true 

1168 

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

1170 

1171 .. versionadded:: 1.4 

1172 

1173 """ # noqa: E501 

1174 

1175 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1179 tables, aliases, or subqueries. 

1180 

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

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

1183 ``table2_columna``: 

1184 

1185 .. sourcecode:: pycon+sql 

1186 

1187 >>> from sqlalchemy import ( 

1188 ... table, 

1189 ... column, 

1190 ... select, 

1191 ... true, 

1192 ... LABEL_STYLE_TABLENAME_PLUS_COL, 

1193 ... ) 

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

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

1196 >>> print( 

1197 ... select(table1, table2) 

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

1199 ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1200 ... ) 

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

1202 FROM table1 JOIN table2 ON true 

1203 

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

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

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

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

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

1209 

1210 

1211 .. versionadded:: 1.4 

1212 

1213 """ # noqa: E501 

1214 

1215 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1218 when generating the columns clause of a SELECT statement. 

1219 

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

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

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

1223 

1224 .. sourcecode:: pycon+sql 

1225 

1226 >>> from sqlalchemy import ( 

1227 ... table, 

1228 ... column, 

1229 ... select, 

1230 ... true, 

1231 ... LABEL_STYLE_DISAMBIGUATE_ONLY, 

1232 ... ) 

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

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

1235 >>> print( 

1236 ... select(table1, table2) 

1237 ... .join(table2, true()) 

1238 ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

1239 ... ) 

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

1241 FROM table1 JOIN table2 ON true 

1242 

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

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

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

1246 

1247 .. versionadded:: 1.4 

1248 

1249 """ # noqa: E501 

1250 

1251 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1252 """The default label style, refers to 

1253 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1254 

1255 .. versionadded:: 1.4 

1256 

1257 """ 

1258 

1259 LABEL_STYLE_LEGACY_ORM = 3 

1260 

1261 

1262( 

1263 LABEL_STYLE_NONE, 

1264 LABEL_STYLE_TABLENAME_PLUS_COL, 

1265 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1266 _, 

1267) = list(SelectLabelStyle) 

1268 

1269LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1270 

1271 

1272class Join(roles.DMLTableRole, FromClause[_KeyColCC_co]): 

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

1274 :class:`_expression.FromClause` 

1275 elements. 

1276 

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

1278 is the module-level 

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

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

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

1282 :class:`_schema.Table`). 

1283 

1284 .. seealso:: 

1285 

1286 :func:`_expression.join` 

1287 

1288 :meth:`_expression.FromClause.join` 

1289 

1290 """ 

1291 

1292 __visit_name__ = "join" 

1293 

1294 _traverse_internals: _TraverseInternalsType = [ 

1295 ("left", InternalTraversal.dp_clauseelement), 

1296 ("right", InternalTraversal.dp_clauseelement), 

1297 ("onclause", InternalTraversal.dp_clauseelement), 

1298 ("isouter", InternalTraversal.dp_boolean), 

1299 ("full", InternalTraversal.dp_boolean), 

1300 ] 

1301 

1302 _is_join = True 

1303 

1304 left: FromClause 

1305 right: FromClause 

1306 onclause: Optional[ColumnElement[bool]] 

1307 isouter: bool 

1308 full: bool 

1309 

1310 def __init__( 

1311 self, 

1312 left: _FromClauseArgument, 

1313 right: _FromClauseArgument, 

1314 onclause: Optional[_OnClauseArgument] = None, 

1315 isouter: bool = False, 

1316 full: bool = False, 

1317 ): 

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

1319 

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

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

1322 :class:`_expression.FromClause` object. 

1323 

1324 """ 

1325 

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

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

1328 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1331 # callcounts for a single compilation in that particular test 

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

1333 # 29200 -> 30373 

1334 

1335 self.left = coercions.expect( 

1336 roles.FromClauseRole, 

1337 left, 

1338 ) 

1339 self.right = coercions.expect( 

1340 roles.FromClauseRole, 

1341 right, 

1342 ).self_group() 

1343 

1344 if onclause is None: 

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

1346 else: 

1347 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1348 # not merged yet 

1349 self.onclause = coercions.expect( 

1350 roles.OnClauseRole, onclause 

1351 ).self_group(against=operators._asbool) 

1352 

1353 self.isouter = isouter 

1354 self.full = full 

1355 

1356 @util.ro_non_memoized_property 

1357 def description(self) -> str: 

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

1359 self.left.description, 

1360 id(self.left), 

1361 self.right.description, 

1362 id(self.right), 

1363 ) 

1364 

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

1366 return ( 

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

1368 # as well 

1369 hash(fromclause) == hash(self) 

1370 or self.left.is_derived_from(fromclause) 

1371 or self.right.is_derived_from(fromclause) 

1372 ) 

1373 

1374 def self_group( 

1375 self, against: Optional[OperatorType] = None 

1376 ) -> FromGrouping: 

1377 return FromGrouping(self) 

1378 

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

1380 def _populate_column_collection( 

1381 self, 

1382 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

1383 primary_key: ColumnSet, 

1384 foreign_keys: Set[KeyedColumnElement[Any]], 

1385 ) -> None: 

1386 sqlutil = util.preloaded.sql_util 

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

1388 c for c in self.right.c 

1389 ] 

1390 

1391 primary_key.extend( 

1392 sqlutil.reduce_columns( 

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

1394 ) 

1395 ) 

1396 columns._populate_separate_keys( 

1397 (col._tq_key_label, col) for col in _columns # type: ignore[misc] 

1398 ) 

1399 foreign_keys.update( 

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

1401 ) 

1402 

1403 def _copy_internals( 

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

1405 ) -> None: 

1406 # see Select._copy_internals() for similar concept 

1407 

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

1409 # determine the new FROM clauses 

1410 all_the_froms = set( 

1411 itertools.chain( 

1412 _from_objects(self.left), 

1413 _from_objects(self.right), 

1414 ) 

1415 ) 

1416 

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

1418 # cache used by the clone function 

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

1420 

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

1422 # ColumnClause with parent table referring to those 

1423 # replaced FromClause objects 

1424 def replace( 

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

1426 **kw: Any, 

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

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

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

1430 return newelem 

1431 return None 

1432 

1433 kw["replace"] = replace 

1434 

1435 # run normal _copy_internals. the clones for 

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

1437 # cache 

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

1439 

1440 self._reset_memoizations() 

1441 

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

1443 super()._refresh_for_new_column(column) 

1444 self.left._refresh_for_new_column(column) 

1445 self.right._refresh_for_new_column(column) 

1446 

1447 def _match_primaries( 

1448 self, 

1449 left: FromClause, 

1450 right: FromClause, 

1451 ) -> ColumnElement[bool]: 

1452 if isinstance(left, Join): 

1453 left_right = left.right 

1454 else: 

1455 left_right = None 

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

1457 

1458 @classmethod 

1459 def _join_condition( 

1460 cls, 

1461 a: FromClause, 

1462 b: FromClause, 

1463 *, 

1464 a_subset: Optional[FromClause] = None, 

1465 consider_as_foreign_keys: Optional[ 

1466 AbstractSet[ColumnClause[Any]] 

1467 ] = None, 

1468 ) -> ColumnElement[bool]: 

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

1470 

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

1472 

1473 """ 

1474 constraints = cls._joincond_scan_left_right( 

1475 a, a_subset, b, consider_as_foreign_keys 

1476 ) 

1477 

1478 if len(constraints) > 1: 

1479 cls._joincond_trim_constraints( 

1480 a, b, constraints, consider_as_foreign_keys 

1481 ) 

1482 

1483 if len(constraints) == 0: 

1484 if isinstance(b, FromGrouping): 

1485 hint = ( 

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

1487 "subquery using alias()?" 

1488 ) 

1489 else: 

1490 hint = "" 

1491 raise exc.NoForeignKeysError( 

1492 "Can't find any foreign key relationships " 

1493 "between '%s' and '%s'.%s" 

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

1495 ) 

1496 

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

1498 if len(crit) == 1: 

1499 return crit[0] 

1500 else: 

1501 return and_(*crit) 

1502 

1503 @classmethod 

1504 def _can_join( 

1505 cls, 

1506 left: FromClause, 

1507 right: FromClause, 

1508 *, 

1509 consider_as_foreign_keys: Optional[ 

1510 AbstractSet[ColumnClause[Any]] 

1511 ] = None, 

1512 ) -> bool: 

1513 if isinstance(left, Join): 

1514 left_right = left.right 

1515 else: 

1516 left_right = None 

1517 

1518 constraints = cls._joincond_scan_left_right( 

1519 a=left, 

1520 b=right, 

1521 a_subset=left_right, 

1522 consider_as_foreign_keys=consider_as_foreign_keys, 

1523 ) 

1524 

1525 return bool(constraints) 

1526 

1527 @classmethod 

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

1529 def _joincond_scan_left_right( 

1530 cls, 

1531 a: FromClause, 

1532 a_subset: Optional[FromClause], 

1533 b: FromClause, 

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

1535 ) -> collections.defaultdict[ 

1536 Optional[ForeignKeyConstraint], 

1537 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1538 ]: 

1539 sql_util = util.preloaded.sql_util 

1540 

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

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

1543 

1544 constraints: collections.defaultdict[ 

1545 Optional[ForeignKeyConstraint], 

1546 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1547 ] = collections.defaultdict(list) 

1548 

1549 for left in (a_subset, a): 

1550 if left is None: 

1551 continue 

1552 for fk in sorted( 

1553 b.foreign_keys, 

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

1555 ): 

1556 if ( 

1557 consider_as_foreign_keys is not None 

1558 and fk.parent not in consider_as_foreign_keys 

1559 ): 

1560 continue 

1561 try: 

1562 col = fk.get_referent(left) 

1563 except exc.NoReferenceError as nrte: 

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

1565 if nrte.table_name in table_names: 

1566 raise 

1567 else: 

1568 continue 

1569 

1570 if col is not None: 

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

1572 if left is not b: 

1573 for fk in sorted( 

1574 left.foreign_keys, 

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

1576 ): 

1577 if ( 

1578 consider_as_foreign_keys is not None 

1579 and fk.parent not in consider_as_foreign_keys 

1580 ): 

1581 continue 

1582 try: 

1583 col = fk.get_referent(b) 

1584 except exc.NoReferenceError as nrte: 

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

1586 if nrte.table_name in table_names: 

1587 raise 

1588 else: 

1589 continue 

1590 

1591 if col is not None: 

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

1593 if constraints: 

1594 break 

1595 return constraints 

1596 

1597 @classmethod 

1598 def _joincond_trim_constraints( 

1599 cls, 

1600 a: FromClause, 

1601 b: FromClause, 

1602 constraints: Dict[Any, Any], 

1603 consider_as_foreign_keys: Optional[Any], 

1604 ) -> None: 

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

1606 # to include just those FKCs that match exactly to 

1607 # "consider_as_foreign_keys". 

1608 if consider_as_foreign_keys: 

1609 for const in list(constraints): 

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

1611 consider_as_foreign_keys 

1612 ): 

1613 del constraints[const] 

1614 

1615 # if still multiple constraints, but 

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

1617 if len(constraints) > 1: 

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

1619 if len(dedupe) == 1: 

1620 key = list(constraints)[0] 

1621 constraints = {key: constraints[key]} 

1622 

1623 if len(constraints) != 1: 

1624 raise exc.AmbiguousForeignKeysError( 

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

1626 "tables have more than one foreign key " 

1627 "constraint relationship between them. " 

1628 "Please specify the 'onclause' of this " 

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

1630 ) 

1631 

1632 @overload 

1633 def select( 

1634 self: Join[HasRowPos[Unpack[_Ts]]], # type: ignore[type-var] 

1635 ) -> Select[Unpack[_Ts]]: ... 

1636 @overload 

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

1638 

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

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

1641 :class:`_expression.Join`. 

1642 

1643 E.g.:: 

1644 

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

1646 

1647 stmt = stmt.select() 

1648 

1649 The above will produce a SQL string resembling: 

1650 

1651 .. sourcecode:: sql 

1652 

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

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

1655 

1656 """ 

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

1658 

1659 @staticmethod 

1660 def _flat_element_name( 

1661 name: Optional[str], element: FromClause 

1662 ) -> Optional[str]: 

1663 if name and isinstance(element, NamedFromClause): 

1664 if isinstance(element.name, _anonymous_label): 

1665 # an anonymous name can't be embedded within a new name; 

1666 # alias the element anonymously, #13583 

1667 return None 

1668 return f"{name}_{element.name}" 

1669 else: 

1670 return name 

1671 

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

1673 def _anonymous_fromclause( 

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

1675 ) -> TODO_Any: 

1676 sqlutil = util.preloaded.sql_util 

1677 if flat: 

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

1679 left_name = name # will recurse 

1680 else: 

1681 left_name = self._flat_element_name(name, self.left) 

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

1683 right_name = name # will recurse 

1684 else: 

1685 right_name = self._flat_element_name(name, self.right) 

1686 left_a, right_a = ( 

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

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

1689 ) 

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

1691 sqlutil.ClauseAdapter(right_a) 

1692 ) 

1693 

1694 return left_a.join( 

1695 right_a, 

1696 adapter.traverse(self.onclause), 

1697 isouter=self.isouter, 

1698 full=self.full, 

1699 ) 

1700 else: 

1701 return ( 

1702 self.select() 

1703 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1704 .correlate(None) 

1705 .alias(name) 

1706 ) 

1707 

1708 @util.ro_non_memoized_property 

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

1710 return itertools.chain( 

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

1712 ) 

1713 

1714 @util.ro_non_memoized_property 

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

1716 self_list: List[FromClause] = [self] 

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

1718 

1719 if TYPE_CHECKING: 

1720 

1721 def with_cols(self, type_: type[_TC_co]) -> Join[_TC_co]: ... 

1722 

1723 

1724class NoInit: 

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

1726 raise NotImplementedError( 

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

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

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

1730 "selectable objects." 

1731 % ( 

1732 self.__class__.__name__, 

1733 self.__class__.__name__.lower(), 

1734 self.__class__.__name__.lower(), 

1735 ) 

1736 ) 

1737 

1738 

1739class LateralFromClause(NamedFromClause): 

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

1741 

1742 

1743# FromClause -> 

1744# AliasedReturnsRows 

1745# -> Alias only for FromClause 

1746# -> Subquery only for SelectBase 

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

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

1749# w/ non-deprecated coercion 

1750# -> TableSample -> only for FromClause 

1751 

1752 

1753class AliasedReturnsRows(NoInit, NamedFromClause[_KeyColCC_co]): 

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

1755 selectables.""" 

1756 

1757 _is_from_container = True 

1758 

1759 _supports_derived_columns = False 

1760 

1761 element: ReturnsRows 

1762 

1763 _traverse_internals: _TraverseInternalsType = [ 

1764 ("element", InternalTraversal.dp_clauseelement), 

1765 ("name", InternalTraversal.dp_anon_name), 

1766 ] 

1767 

1768 @classmethod 

1769 def _construct( 

1770 cls, 

1771 selectable: Any, 

1772 *, 

1773 name: Optional[str] = None, 

1774 **kw: Any, 

1775 ) -> Self: 

1776 obj = cls.__new__(cls) 

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

1778 return obj 

1779 

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

1781 self.element = coercions.expect( 

1782 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1783 ) 

1784 self.element = selectable 

1785 self._orig_name = name 

1786 if name is None: 

1787 if ( 

1788 isinstance(selectable, FromClause) 

1789 and selectable.named_with_column 

1790 ): 

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

1792 if isinstance(name, _anonymous_label): 

1793 name = None 

1794 name = _anonymous_label.safe_construct( 

1795 os.urandom(10).hex(), name or "anon" 

1796 ) 

1797 self.name = name 

1798 

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

1800 super()._refresh_for_new_column(column) 

1801 self.element._refresh_for_new_column(column) 

1802 

1803 def _populate_column_collection( 

1804 self, 

1805 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

1806 primary_key: ColumnSet, 

1807 foreign_keys: Set[KeyedColumnElement[Any]], 

1808 ) -> None: 

1809 self.element._generate_fromclause_column_proxies( 

1810 self, columns, primary_key=primary_key, foreign_keys=foreign_keys 

1811 ) 

1812 

1813 @util.ro_non_memoized_property 

1814 def description(self) -> str: 

1815 name = self.name 

1816 if isinstance(name, _anonymous_label): 

1817 return "anon_1" 

1818 

1819 return name 

1820 

1821 @util.ro_non_memoized_property 

1822 def implicit_returning(self) -> bool: 

1823 return self.element.implicit_returning # type: ignore[attr-defined, no-any-return] # noqa: E501 

1824 

1825 @property 

1826 def original(self) -> ReturnsRows: 

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

1828 return self.element 

1829 

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

1831 if fromclause in self._cloned_set: 

1832 return True 

1833 return self.element.is_derived_from(fromclause) 

1834 

1835 def _copy_internals( 

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

1837 ) -> None: 

1838 existing_element = self.element 

1839 

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

1841 

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

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

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

1845 # performance. 

1846 if existing_element is not self.element: 

1847 self._reset_column_collection() 

1848 

1849 @property 

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

1851 return [self] 

1852 

1853 

1854class FromClauseAlias(AliasedReturnsRows[_KeyColCC_co]): 

1855 element: FromClause[_KeyColCC_co] 

1856 

1857 @util.ro_non_memoized_property 

1858 def description(self) -> str: 

1859 name = self.name 

1860 if isinstance(name, _anonymous_label): 

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

1862 

1863 return name 

1864 

1865 

1866class Alias(roles.DMLTableRole, FromClauseAlias[_KeyColCC_co]): 

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

1868 

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

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

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

1872 

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

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

1875 method available 

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

1877 

1878 .. seealso:: 

1879 

1880 :meth:`_expression.FromClause.alias` 

1881 

1882 """ 

1883 

1884 __visit_name__ = "alias" 

1885 

1886 inherit_cache = True 

1887 

1888 element: FromClause[_KeyColCC_co] 

1889 

1890 @classmethod 

1891 def _factory( 

1892 cls, 

1893 selectable: FromClause[_KeyColCC_co], 

1894 name: Optional[str] = None, 

1895 flat: bool = False, 

1896 ) -> NamedFromClause[_KeyColCC_co]: 

1897 # mypy refuses to see the overload that has this returning 

1898 # NamedFromClause[Any]. Pylance sees it just fine. 

1899 return coercions.expect(roles.FromClauseRole, selectable).alias( # type: ignore[no-any-return] # noqa: E501 

1900 name=name, flat=flat 

1901 ) 

1902 

1903 

1904class TableValuedAlias(LateralFromClause, Alias): 

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

1906 

1907 This construct provides for a SQL function that returns columns 

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

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

1910 method, e.g.: 

1911 

1912 .. sourcecode:: pycon+sql 

1913 

1914 >>> from sqlalchemy import select, func 

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

1916 ... "value" 

1917 ... ) 

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

1919 {printsql}SELECT anon_1.value 

1920 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1921 

1922 .. versionadded:: 1.4.0b2 

1923 

1924 .. seealso:: 

1925 

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

1927 

1928 """ # noqa: E501 

1929 

1930 __visit_name__ = "table_valued_alias" 

1931 

1932 _supports_derived_columns = True 

1933 _render_derived = False 

1934 _render_derived_w_types = False 

1935 joins_implicitly = False 

1936 

1937 _traverse_internals: _TraverseInternalsType = [ 

1938 ("element", InternalTraversal.dp_clauseelement), 

1939 ("name", InternalTraversal.dp_anon_name), 

1940 ("_tableval_type", InternalTraversal.dp_type), 

1941 ("_render_derived", InternalTraversal.dp_boolean), 

1942 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1943 ] 

1944 

1945 def _init( 

1946 self, 

1947 selectable: Any, 

1948 *, 

1949 name: Optional[str] = None, 

1950 table_value_type: Optional[TableValueType] = None, 

1951 joins_implicitly: bool = False, 

1952 ) -> None: 

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

1954 

1955 self.joins_implicitly = joins_implicitly 

1956 self._tableval_type = ( 

1957 type_api.TABLEVALUE 

1958 if table_value_type is None 

1959 else table_value_type 

1960 ) 

1961 

1962 @HasMemoized.memoized_attribute 

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

1964 """Return a column expression representing this 

1965 :class:`_sql.TableValuedAlias`. 

1966 

1967 This accessor is used to implement the 

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

1969 method for further details. 

1970 

1971 E.g.: 

1972 

1973 .. sourcecode:: pycon+sql 

1974 

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

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

1977 

1978 .. seealso:: 

1979 

1980 :meth:`_functions.FunctionElement.column_valued` 

1981 

1982 """ 

1983 

1984 return TableValuedColumn(self, self._tableval_type) 

1985 

1986 def alias( 

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

1988 ) -> TableValuedAlias: 

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

1990 

1991 This creates a distinct FROM object that will be distinguished 

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

1993 

1994 """ 

1995 

1996 tva: TableValuedAlias = TableValuedAlias._construct( 

1997 self, 

1998 name=name, 

1999 table_value_type=self._tableval_type, 

2000 joins_implicitly=self.joins_implicitly, 

2001 ) 

2002 

2003 if self._render_derived: 

2004 tva._render_derived = True 

2005 tva._render_derived_w_types = self._render_derived_w_types 

2006 

2007 return tva 

2008 

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

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

2011 set, so that it renders as LATERAL. 

2012 

2013 .. seealso:: 

2014 

2015 :func:`_expression.lateral` 

2016 

2017 """ 

2018 tva = self.alias(name=name) 

2019 tva._is_lateral = True 

2020 return tva 

2021 

2022 def render_derived( 

2023 self, 

2024 name: Optional[str] = None, 

2025 with_types: bool = False, 

2026 ) -> TableValuedAlias: 

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

2028 

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

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

2031 

2032 .. sourcecode:: pycon+sql 

2033 

2034 >>> print( 

2035 ... select( 

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

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

2038 ... .render_derived() 

2039 ... ) 

2040 ... ) 

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

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

2043 

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

2045 the alias expression (this syntax currently applies to the 

2046 PostgreSQL database): 

2047 

2048 .. sourcecode:: pycon+sql 

2049 

2050 >>> print( 

2051 ... select( 

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

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

2054 ... .render_derived(with_types=True) 

2055 ... ) 

2056 ... ) 

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

2058 AS anon_1(a INTEGER, b VARCHAR) 

2059 

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

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

2062 

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

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

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

2066 

2067 """ # noqa: E501 

2068 

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

2070 # to the original object. otherwise you can have reuse of the 

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

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

2073 # (just saw it happen on CI) 

2074 

2075 # construct against original to prevent memory growth 

2076 # for repeated generations 

2077 new_alias: TableValuedAlias = TableValuedAlias._construct( 

2078 self.element, 

2079 name=name, 

2080 table_value_type=self._tableval_type, 

2081 joins_implicitly=self.joins_implicitly, 

2082 ) 

2083 new_alias._render_derived = True 

2084 new_alias._render_derived_w_types = with_types 

2085 return new_alias 

2086 

2087 

2088class Lateral(FromClauseAlias, LateralFromClause): 

2089 """Represent a LATERAL subquery. 

2090 

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

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

2093 method available 

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

2095 

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

2097 PostgreSQL versions provide support for this keyword. 

2098 

2099 .. seealso:: 

2100 

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

2102 

2103 """ 

2104 

2105 __visit_name__ = "lateral" 

2106 _is_lateral = True 

2107 

2108 inherit_cache = True 

2109 

2110 @classmethod 

2111 def _factory( 

2112 cls, 

2113 selectable: Union[SelectBase, _FromClauseArgument], 

2114 name: Optional[str] = None, 

2115 ) -> LateralFromClause: 

2116 return coercions.expect( 

2117 roles.FromClauseRole, selectable, explicit_subquery=True 

2118 ).lateral(name=name) 

2119 

2120 

2121class TableSample(FromClauseAlias): 

2122 """Represent a TABLESAMPLE clause. 

2123 

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

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

2126 method 

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

2128 

2129 .. seealso:: 

2130 

2131 :func:`_expression.tablesample` 

2132 

2133 """ 

2134 

2135 __visit_name__ = "tablesample" 

2136 

2137 _traverse_internals: _TraverseInternalsType = ( 

2138 AliasedReturnsRows._traverse_internals 

2139 + [ 

2140 ("sampling", InternalTraversal.dp_clauseelement), 

2141 ("seed", InternalTraversal.dp_clauseelement), 

2142 ] 

2143 ) 

2144 

2145 @classmethod 

2146 def _factory( 

2147 cls, 

2148 selectable: _FromClauseArgument, 

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

2150 name: Optional[str] = None, 

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

2152 ) -> TableSample: 

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

2154 sampling, name=name, seed=seed 

2155 ) 

2156 

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

2158 def _init( # type: ignore[override] 

2159 self, 

2160 selectable: Any, 

2161 *, 

2162 name: Optional[str] = None, 

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

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

2165 ) -> None: 

2166 assert sampling is not None 

2167 functions = util.preloaded.sql_functions 

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

2169 sampling = functions.func.system(sampling) 

2170 

2171 self.sampling: Function[Any] = sampling 

2172 self.seed = seed 

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

2174 

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

2176 return self.sampling 

2177 

2178 

2179class CTE( 

2180 roles.DMLTableRole, 

2181 roles.IsCTERole, 

2182 Generative, 

2183 HasPrefixes, 

2184 HasSuffixes, 

2185 AliasedReturnsRows[_KeyColCC_co], 

2186): 

2187 """Represent a Common Table Expression. 

2188 

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

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

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

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

2193 :class:`_sql.Update` and 

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

2195 usage details on CTEs. 

2196 

2197 .. seealso:: 

2198 

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

2200 

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

2202 

2203 """ 

2204 

2205 __visit_name__ = "cte" 

2206 

2207 _traverse_internals: _TraverseInternalsType = ( 

2208 AliasedReturnsRows._traverse_internals 

2209 + [ 

2210 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2211 ("_restates", InternalTraversal.dp_clauseelement), 

2212 ("recursive", InternalTraversal.dp_boolean), 

2213 ("nesting", InternalTraversal.dp_boolean), 

2214 ] 

2215 + HasPrefixes._has_prefixes_traverse_internals 

2216 + HasSuffixes._has_suffixes_traverse_internals 

2217 ) 

2218 

2219 element: HasCTE 

2220 

2221 @classmethod 

2222 def _factory( 

2223 cls, 

2224 selectable: HasCTE, 

2225 name: Optional[str] = None, 

2226 recursive: bool = False, 

2227 ) -> CTE: 

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

2229 or Common Table Expression instance. 

2230 

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

2232 

2233 """ 

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

2235 name=name, recursive=recursive 

2236 ) 

2237 

2238 def _init( 

2239 self, 

2240 selectable: HasCTE, 

2241 *, 

2242 name: Optional[str] = None, 

2243 recursive: bool = False, 

2244 nesting: bool = False, 

2245 _cte_alias: Optional[CTE[_KeyColCC_co]] = None, 

2246 _restates: Optional[CTE[_KeyColCC_co]] = None, 

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

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

2249 ) -> None: 

2250 self.recursive = recursive 

2251 self.nesting = nesting 

2252 self._cte_alias = _cte_alias 

2253 # Keep recursivity reference with union/union_all 

2254 self._restates = _restates 

2255 if _prefixes: 

2256 self._prefixes = _prefixes 

2257 if _suffixes: 

2258 self._suffixes = _suffixes 

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

2260 

2261 def _populate_column_collection( 

2262 self, 

2263 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

2264 primary_key: ColumnSet, 

2265 foreign_keys: Set[KeyedColumnElement[Any]], 

2266 ) -> None: 

2267 if self._cte_alias is not None: 

2268 self._cte_alias._generate_fromclause_column_proxies( 

2269 self, 

2270 columns, 

2271 primary_key=primary_key, 

2272 foreign_keys=foreign_keys, 

2273 ) 

2274 else: 

2275 self.element._generate_fromclause_column_proxies( 

2276 self, 

2277 columns, 

2278 primary_key=primary_key, 

2279 foreign_keys=foreign_keys, 

2280 ) 

2281 

2282 def alias( 

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

2284 ) -> CTE[_KeyColCC_co]: 

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

2286 :class:`_expression.CTE`. 

2287 

2288 This method is a CTE-specific specialization of the 

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

2290 

2291 .. seealso:: 

2292 

2293 :ref:`tutorial_using_aliases` 

2294 

2295 :func:`_expression.alias` 

2296 

2297 """ 

2298 return CTE._construct( 

2299 self.element, 

2300 name=name, 

2301 recursive=self.recursive, 

2302 nesting=self.nesting, 

2303 # an alias of an alias refers to the original CTE, #13583 

2304 _cte_alias=( 

2305 self._cte_alias if self._cte_alias is not None else self 

2306 ), 

2307 _prefixes=self._prefixes, 

2308 _suffixes=self._suffixes, 

2309 ) 

2310 

2311 def union( 

2312 self, *other: _SelectStatementForCompoundArgument[Any] 

2313 ) -> CTE[_KeyColCC_co]: 

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

2315 of the original CTE against the given selectables provided 

2316 as positional arguments. 

2317 

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

2319 UNION. 

2320 

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

2322 

2323 .. seealso:: 

2324 

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

2326 

2327 """ 

2328 assert is_select_statement( 

2329 self.element 

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

2331 

2332 return CTE._construct( 

2333 self.element.union(*other), 

2334 name=self.name, 

2335 recursive=self.recursive, 

2336 nesting=self.nesting, 

2337 _restates=self, 

2338 _prefixes=self._prefixes, 

2339 _suffixes=self._suffixes, 

2340 ) 

2341 

2342 def union_all( 

2343 self, *other: _SelectStatementForCompoundArgument[Any] 

2344 ) -> CTE[_KeyColCC_co]: 

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

2346 of the original CTE against the given selectables provided 

2347 as positional arguments. 

2348 

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

2350 UNION. 

2351 

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

2353 

2354 .. seealso:: 

2355 

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

2357 

2358 """ 

2359 

2360 assert is_select_statement( 

2361 self.element 

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

2363 

2364 return CTE._construct( 

2365 self.element.union_all(*other), 

2366 name=self.name, 

2367 recursive=self.recursive, 

2368 nesting=self.nesting, 

2369 _restates=self, 

2370 _prefixes=self._prefixes, 

2371 _suffixes=self._suffixes, 

2372 ) 

2373 

2374 def _get_reference_cte(self) -> CTE[_KeyColCC_co]: 

2375 """ 

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

2377 Updated CTEs should still refer to the original CTE. 

2378 This function returns this reference identifier. 

2379 """ 

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

2381 

2382 if TYPE_CHECKING: 

2383 

2384 def with_cols(self, type_: type[_TC_co]) -> CTE[_TC_co]: ... 

2385 

2386 

2387class _CTEOpts(NamedTuple): 

2388 nesting: bool 

2389 

2390 

2391class _ColumnsPlusNames(NamedTuple): 

2392 required_label_name: Optional[str] 

2393 """ 

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

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

2396 """ 

2397 

2398 proxy_key: Optional[str] 

2399 """ 

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

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

2402 select.selected_columns collection 

2403 """ 

2404 

2405 fallback_label_name: Optional[str] 

2406 """ 

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

2408 we have to render a label even though 

2409 required_label_name was not given 

2410 """ 

2411 

2412 column: Union[ColumnElement[Any], AbstractTextClause] 

2413 """ 

2414 the ColumnElement itself 

2415 """ 

2416 

2417 repeated: bool 

2418 """ 

2419 True if this is a duplicate of a previous column 

2420 in the list of columns 

2421 """ 

2422 

2423 

2424class SelectsRows(ReturnsRows): 

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

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

2427 

2428 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2429 

2430 def _generate_columns_plus_names( 

2431 self, 

2432 anon_for_dupe_key: bool, 

2433 cols: Optional[_SelectIterable] = None, 

2434 ) -> List[_ColumnsPlusNames]: 

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

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

2437 on a :class:`.FromClause`. 

2438 

2439 This is distinct from the _column_naming_convention generator that's 

2440 intended for population of the Select.selected_columns collection, 

2441 different rules. the collection returned here calls upon the 

2442 _column_naming_convention as well. 

2443 

2444 """ 

2445 

2446 if cols is None: 

2447 cols = self._all_selected_columns 

2448 

2449 key_naming_convention = SelectState._column_naming_convention( 

2450 self._label_style 

2451 ) 

2452 

2453 names = {} 

2454 

2455 result: List[_ColumnsPlusNames] = [] 

2456 result_append = result.append 

2457 

2458 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2459 label_style_none = self._label_style is LABEL_STYLE_NONE 

2460 

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

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

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

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

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

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

2467 dedupe_hash = 1 

2468 

2469 for c in cols: 

2470 repeated = False 

2471 

2472 if not c._render_label_in_columns_clause: 

2473 effective_name = required_label_name = fallback_label_name = ( 

2474 None 

2475 ) 

2476 elif label_style_none: 

2477 if TYPE_CHECKING: 

2478 assert is_column_element(c) 

2479 

2480 effective_name = required_label_name = None 

2481 fallback_label_name = c._non_anon_label or c._anon_name_label 

2482 else: 

2483 if TYPE_CHECKING: 

2484 assert is_column_element(c) 

2485 

2486 if table_qualified: 

2487 required_label_name = effective_name = ( 

2488 fallback_label_name 

2489 ) = c._tq_label 

2490 else: 

2491 effective_name = fallback_label_name = c._non_anon_label 

2492 required_label_name = None 

2493 

2494 if effective_name is None: 

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

2496 # not need _expression_label but it isn't 

2497 # giving us a clue when to use anon_label instead 

2498 expr_label = c._expression_label 

2499 if expr_label is None: 

2500 repeated = c._anon_name_label in names 

2501 names[c._anon_name_label] = c 

2502 effective_name = required_label_name = None 

2503 

2504 if repeated: 

2505 # here, "required_label_name" is sent as 

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

2507 if table_qualified: 

2508 fallback_label_name = ( 

2509 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2510 ) 

2511 dedupe_hash += 1 

2512 else: 

2513 fallback_label_name = c._dedupe_anon_label_idx( 

2514 dedupe_hash 

2515 ) 

2516 dedupe_hash += 1 

2517 else: 

2518 fallback_label_name = c._anon_name_label 

2519 else: 

2520 required_label_name = effective_name = ( 

2521 fallback_label_name 

2522 ) = expr_label 

2523 

2524 if effective_name is not None: 

2525 if TYPE_CHECKING: 

2526 assert is_column_element(c) 

2527 

2528 if effective_name in names: 

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

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

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

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

2533 # different column under the same name. apply 

2534 # disambiguating label 

2535 if table_qualified: 

2536 required_label_name = fallback_label_name = ( 

2537 c._anon_tq_label 

2538 ) 

2539 else: 

2540 required_label_name = fallback_label_name = ( 

2541 c._anon_name_label 

2542 ) 

2543 

2544 if anon_for_dupe_key and required_label_name in names: 

2545 # here, c._anon_tq_label is definitely unique to 

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

2547 # this should always be true. 

2548 # this is also an infrequent codepath because 

2549 # you need two levels of duplication to be here 

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

2551 

2552 # the column under the disambiguating label is 

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

2554 # subsequent occurrences of the column so that the 

2555 # original stays non-ambiguous 

2556 if table_qualified: 

2557 required_label_name = fallback_label_name = ( 

2558 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2559 ) 

2560 dedupe_hash += 1 

2561 else: 

2562 required_label_name = fallback_label_name = ( 

2563 c._dedupe_anon_label_idx(dedupe_hash) 

2564 ) 

2565 dedupe_hash += 1 

2566 repeated = True 

2567 else: 

2568 names[required_label_name] = c 

2569 elif anon_for_dupe_key: 

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

2571 # label so that the original stays non-ambiguous 

2572 if table_qualified: 

2573 required_label_name = fallback_label_name = ( 

2574 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2575 ) 

2576 dedupe_hash += 1 

2577 else: 

2578 required_label_name = fallback_label_name = ( 

2579 c._dedupe_anon_label_idx(dedupe_hash) 

2580 ) 

2581 dedupe_hash += 1 

2582 repeated = True 

2583 else: 

2584 names[effective_name] = c 

2585 

2586 result_append( 

2587 _ColumnsPlusNames( 

2588 required_label_name, 

2589 key_naming_convention(c), 

2590 fallback_label_name, 

2591 c, 

2592 repeated, 

2593 ) 

2594 ) 

2595 

2596 return result 

2597 

2598 

2599class HasCTE(roles.HasCTERole, SelectsRows): 

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

2601 

2602 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2603 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2604 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2605 ] 

2606 

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

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

2609 

2610 name_cte_columns: bool = False 

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

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

2613 

2614 .. versionadded:: 2.0.42 

2615 

2616 """ 

2617 

2618 @_generative 

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

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

2621 

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

2623 the parent statement such that they will each be unconditionally 

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

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

2626 

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

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

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

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

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

2632 statement. 

2633 

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

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

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

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

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

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

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

2641 larger statement. 

2642 

2643 E.g.:: 

2644 

2645 from sqlalchemy import table, column, select 

2646 

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

2648 

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

2650 

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

2652 

2653 Would render: 

2654 

2655 .. sourcecode:: sql 

2656 

2657 WITH anon_1 AS ( 

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

2659 ) 

2660 SELECT t.c1, t.c2 

2661 FROM t 

2662 

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

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

2665 statement. 

2666 

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

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

2669 

2670 from sqlalchemy import table, column 

2671 from sqlalchemy.dialects.postgresql import insert 

2672 

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

2674 

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

2676 

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

2678 update_statement = insert_stmt.on_conflict_do_update( 

2679 index_elements=[t.c.c1], 

2680 set_={ 

2681 "c1": insert_stmt.excluded.c1, 

2682 "c2": insert_stmt.excluded.c2, 

2683 }, 

2684 ).add_cte(delete_statement_cte) 

2685 

2686 print(update_statement) 

2687 

2688 The above statement renders as: 

2689 

2690 .. sourcecode:: sql 

2691 

2692 WITH deletions AS ( 

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

2694 ) 

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

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

2697 

2698 .. versionadded:: 1.4.21 

2699 

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

2701 

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

2703 

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

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

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

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

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

2709 this statement when this flag is given. 

2710 

2711 .. versionadded:: 2.0 

2712 

2713 .. seealso:: 

2714 

2715 :paramref:`.HasCTE.cte.nesting` 

2716 

2717 

2718 """ # noqa: E501 

2719 opt = _CTEOpts(nest_here) 

2720 for cte in ctes: 

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

2722 self._independent_ctes += (cte,) 

2723 self._independent_ctes_opts += (opt,) 

2724 return self 

2725 

2726 def cte( 

2727 self, 

2728 name: Optional[str] = None, 

2729 recursive: bool = False, 

2730 nesting: bool = False, 

2731 ) -> CTE: 

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

2733 or Common Table Expression instance. 

2734 

2735 Common table expressions are a SQL standard whereby SELECT 

2736 statements can draw upon secondary statements specified along 

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

2738 Special semantics regarding UNION can also be employed to 

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

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

2741 

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

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

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

2745 CTE rows. 

2746 

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

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

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

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

2751 

2752 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2754 method may be 

2755 used to establish these. 

2756 

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

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

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

2760 compile time. 

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

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

2763 conjunction with UNION ALL in order to derive rows 

2764 from those already selected. 

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

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

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

2768 :paramref:`.HasCTE.add_cte.nest_here` 

2769 parameter may also be used to more carefully 

2770 control the exact placement of a particular CTE. 

2771 

2772 .. versionadded:: 1.4.24 

2773 

2774 .. seealso:: 

2775 

2776 :meth:`.HasCTE.add_cte` 

2777 

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

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

2780 as well as additional examples. 

2781 

2782 Example 1, non recursive:: 

2783 

2784 from sqlalchemy import ( 

2785 Table, 

2786 Column, 

2787 String, 

2788 Integer, 

2789 MetaData, 

2790 select, 

2791 func, 

2792 ) 

2793 

2794 metadata = MetaData() 

2795 

2796 orders = Table( 

2797 "orders", 

2798 metadata, 

2799 Column("region", String), 

2800 Column("amount", Integer), 

2801 Column("product", String), 

2802 Column("quantity", Integer), 

2803 ) 

2804 

2805 regional_sales = ( 

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

2807 .group_by(orders.c.region) 

2808 .cte("regional_sales") 

2809 ) 

2810 

2811 

2812 top_regions = ( 

2813 select(regional_sales.c.region) 

2814 .where( 

2815 regional_sales.c.total_sales 

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

2817 ) 

2818 .cte("top_regions") 

2819 ) 

2820 

2821 statement = ( 

2822 select( 

2823 orders.c.region, 

2824 orders.c.product, 

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

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

2827 ) 

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

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

2830 ) 

2831 

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

2833 

2834 Example 2, WITH RECURSIVE:: 

2835 

2836 from sqlalchemy import ( 

2837 Table, 

2838 Column, 

2839 String, 

2840 Integer, 

2841 MetaData, 

2842 select, 

2843 func, 

2844 ) 

2845 

2846 metadata = MetaData() 

2847 

2848 parts = Table( 

2849 "parts", 

2850 metadata, 

2851 Column("part", String), 

2852 Column("sub_part", String), 

2853 Column("quantity", Integer), 

2854 ) 

2855 

2856 included_parts = ( 

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

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

2859 .cte(recursive=True) 

2860 ) 

2861 

2862 

2863 incl_alias = included_parts.alias() 

2864 parts_alias = parts.alias() 

2865 included_parts = included_parts.union_all( 

2866 select( 

2867 parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity 

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

2869 ) 

2870 

2871 statement = select( 

2872 included_parts.c.sub_part, 

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

2874 ).group_by(included_parts.c.sub_part) 

2875 

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

2877 

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

2879 

2880 from datetime import date 

2881 from sqlalchemy import ( 

2882 MetaData, 

2883 Table, 

2884 Column, 

2885 Integer, 

2886 Date, 

2887 select, 

2888 literal, 

2889 and_, 

2890 exists, 

2891 ) 

2892 

2893 metadata = MetaData() 

2894 

2895 visitors = Table( 

2896 "visitors", 

2897 metadata, 

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

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

2900 Column("count", Integer), 

2901 ) 

2902 

2903 # add 5 visitors for the product_id == 1 

2904 product_id = 1 

2905 day = date.today() 

2906 count = 5 

2907 

2908 update_cte = ( 

2909 visitors.update() 

2910 .where( 

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

2912 ) 

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

2914 .returning(literal(1)) 

2915 .cte("update_cte") 

2916 ) 

2917 

2918 upsert = visitors.insert().from_select( 

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

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

2921 ~exists(update_cte.select()) 

2922 ), 

2923 ) 

2924 

2925 connection.execute(upsert) 

2926 

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

2928 

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

2930 

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

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

2933 "value_a", nesting=True 

2934 ) 

2935 

2936 # Nesting CTEs takes ascendency locally 

2937 # over the CTEs at a higher level 

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

2939 

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

2941 

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

2943 shown with inline parameters below as: 

2944 

2945 .. sourcecode:: sql 

2946 

2947 WITH 

2948 value_a AS 

2949 (SELECT 'root' AS n), 

2950 value_b AS 

2951 (WITH value_a AS 

2952 (SELECT 'nesting' AS n) 

2953 SELECT value_a.n AS n FROM value_a) 

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

2955 FROM value_a, value_b 

2956 

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

2958 as follows (SQLAlchemy 2.0 and above):: 

2959 

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

2961 

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

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

2964 

2965 # Nesting CTEs takes ascendency locally 

2966 # over the CTEs at a higher level 

2967 value_b = ( 

2968 select(value_a_nested.c.n) 

2969 .add_cte(value_a_nested, nest_here=True) 

2970 .cte("value_b") 

2971 ) 

2972 

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

2974 

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

2976 

2977 edge = Table( 

2978 "edge", 

2979 metadata, 

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

2981 Column("left", Integer), 

2982 Column("right", Integer), 

2983 ) 

2984 

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

2986 

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

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

2989 ) 

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

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

2992 ) 

2993 

2994 subgraph_cte = root_node.union(left_edge, right_edge) 

2995 

2996 subgraph = select(subgraph_cte) 

2997 

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

2999 

3000 .. sourcecode:: sql 

3001 

3002 WITH RECURSIVE nodes(node) AS ( 

3003 SELECT 1 AS node 

3004 UNION 

3005 SELECT edge."left" AS "left" 

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

3007 UNION 

3008 SELECT edge."right" AS "right" 

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

3010 ) 

3011 SELECT nodes.node FROM nodes 

3012 

3013 .. seealso:: 

3014 

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

3016 :meth:`_expression.HasCTE.cte`. 

3017 

3018 """ # noqa: E501 

3019 return CTE._construct( 

3020 self, name=name, recursive=recursive, nesting=nesting 

3021 ) 

3022 

3023 

3024class Subquery(AliasedReturnsRows[_KeyColCC_co]): 

3025 """Represent a subquery of a SELECT. 

3026 

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

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

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

3030 :class:`_expression.SelectBase` subclass 

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

3032 :class:`_expression.CompoundSelect`, and 

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

3034 it represents the 

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

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

3037 

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

3039 :class:`_expression.Alias` 

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

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

3042 :class:`_expression.Alias` always 

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

3044 :class:`.Subquery` 

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

3046 

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

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

3049 statement. 

3050 

3051 """ 

3052 

3053 __visit_name__ = "subquery" 

3054 

3055 _is_subquery = True 

3056 

3057 inherit_cache = True 

3058 

3059 element: SelectBase 

3060 

3061 @classmethod 

3062 def _factory( 

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

3064 ) -> Subquery: 

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

3066 

3067 return coercions.expect( 

3068 roles.SelectStatementRole, selectable 

3069 ).subquery(name=name) 

3070 

3071 @util.deprecated( 

3072 "1.4", 

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

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

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

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

3077 ":func:`_expression.select` " 

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

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

3080 ) 

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

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

3083 

3084 

3085class FromGrouping(GroupedElement, FromClause[_KeyColCC_co]): 

3086 """Represent a grouping of a FROM clause""" 

3087 

3088 _traverse_internals: _TraverseInternalsType = [ 

3089 ("element", InternalTraversal.dp_clauseelement) 

3090 ] 

3091 

3092 element: FromClause[_KeyColCC_co] 

3093 

3094 def __init__(self, element: FromClause[_KeyColCC_co]): 

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

3096 

3097 @util.ro_non_memoized_property 

3098 def columns(self) -> _KeyColCC_co: 

3099 return self.element.columns 

3100 

3101 @util.ro_non_memoized_property 

3102 def c(self) -> _KeyColCC_co: 

3103 return self.element.columns 

3104 

3105 @property 

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

3107 return self.element.primary_key 

3108 

3109 @property 

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

3111 return self.element.foreign_keys 

3112 

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

3114 return self.element.is_derived_from(fromclause) 

3115 

3116 def alias( 

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

3118 ) -> NamedFromGrouping[_KeyColCC_co]: 

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

3120 

3121 def _anonymous_fromclause( 

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

3123 ) -> FromGrouping: 

3124 return FromGrouping( 

3125 self.element._anonymous_fromclause(name=name, flat=flat) 

3126 ) 

3127 

3128 @util.ro_non_memoized_property 

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

3130 return self.element._hide_froms 

3131 

3132 @util.ro_non_memoized_property 

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

3134 return self.element._from_objects 

3135 

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

3137 return {"element": self.element} 

3138 

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

3140 self.element = state["element"] 

3141 

3142 if TYPE_CHECKING: 

3143 

3144 def self_group( 

3145 self, against: Optional[OperatorType] = None 

3146 ) -> Self: ... 

3147 

3148 

3149class NamedFromGrouping( 

3150 FromGrouping[_KeyColCC_co], NamedFromClause[_KeyColCC_co] 

3151): 

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

3153 

3154 .. versionadded:: 2.0 

3155 

3156 """ 

3157 

3158 inherit_cache = True 

3159 

3160 if TYPE_CHECKING: 

3161 

3162 def self_group( 

3163 self, against: Optional[OperatorType] = None 

3164 ) -> Self: ... 

3165 

3166 

3167class TableClause( 

3168 roles.DMLTableRole, Immutable, NamedFromClause[_ColClauseCC_co] 

3169): 

3170 """Represents a minimal "table" construct. 

3171 

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

3173 collection of columns, which are typically produced 

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

3175 

3176 from sqlalchemy import table, column 

3177 

3178 user = table( 

3179 "user", 

3180 column("id"), 

3181 column("name"), 

3182 column("description"), 

3183 ) 

3184 

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

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

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

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

3189 

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

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

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

3193 It's useful 

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

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

3196 is not on hand. 

3197 

3198 """ 

3199 

3200 __visit_name__ = "table" 

3201 

3202 _traverse_internals: _TraverseInternalsType = [ 

3203 ( 

3204 "columns", 

3205 InternalTraversal.dp_fromclause_canonical_column_collection, 

3206 ), 

3207 ("name", InternalTraversal.dp_string), 

3208 ("schema", InternalTraversal.dp_string), 

3209 ] 

3210 

3211 _is_table = True 

3212 

3213 fullname: str 

3214 

3215 implicit_returning = False 

3216 """:class:`_expression.TableClause` 

3217 doesn't support having a primary key or column 

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

3219 

3220 _columns: DedupeColumnCollection[ColumnClause[Any]] 

3221 

3222 @util.ro_memoized_property 

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

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

3225 return None 

3226 

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

3228 super().__init__() 

3229 self.name = name 

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

3231 self.primary_key = ColumnSet() # type: ignore[misc] 

3232 self.foreign_keys = set() # type: ignore[misc] 

3233 for c in columns: 

3234 self.append_column(c) 

3235 

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

3237 if schema is not None: 

3238 self.schema = schema 

3239 if self.schema is not None: 

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

3241 else: 

3242 self.fullname = self.name 

3243 if kw: 

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

3245 

3246 if TYPE_CHECKING: 

3247 

3248 def with_cols(self, type_: type[_TC_co]) -> TableClause[_TC_co]: ... 

3249 

3250 def __str__(self) -> str: 

3251 if self.schema is not None: 

3252 return self.schema + "." + self.name 

3253 else: 

3254 return self.name 

3255 

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

3257 pass 

3258 

3259 @util.ro_memoized_property 

3260 def description(self) -> str: 

3261 return self.name 

3262 

3263 def _insert_col_impl( 

3264 self, 

3265 c: ColumnClause[Any], 

3266 *, 

3267 index: Optional[int] = None, 

3268 ) -> None: 

3269 existing = c.table 

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

3271 raise exc.ArgumentError( 

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

3273 % (c.key, existing) 

3274 ) 

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

3276 c.table = self 

3277 

3278 def append_column(self, column: ColumnClause[Any]) -> None: 

3279 """Append a :class:`.ColumnClause` to this :class:`.TableClause`.""" 

3280 self._insert_col_impl(column) 

3281 

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

3283 """Insert a :class:`.ColumnClause` to this :class:`.TableClause` at 

3284 a specific position. 

3285 

3286 .. versionadded:: 2.1 

3287 

3288 """ 

3289 self._insert_col_impl(column, index=index) 

3290 

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

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

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

3294 :class:`_expression.TableClause`. 

3295 

3296 E.g.:: 

3297 

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

3299 

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

3301 

3302 """ 

3303 

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

3305 

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

3307 def update(self) -> Update: 

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

3309 :class:`_expression.TableClause`. 

3310 

3311 E.g.:: 

3312 

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

3314 

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

3316 

3317 """ 

3318 return util.preloaded.sql_dml.Update( 

3319 self, 

3320 ) 

3321 

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

3323 def delete(self) -> Delete: 

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

3325 :class:`_expression.TableClause`. 

3326 

3327 E.g.:: 

3328 

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

3330 

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

3332 

3333 """ 

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

3335 

3336 @util.ro_non_memoized_property 

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

3338 return [self] 

3339 

3340 

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

3342 

3343 

3344class ForUpdateArg(ClauseElement): 

3345 _traverse_internals: _TraverseInternalsType = [ 

3346 ("of", InternalTraversal.dp_clauseelement_list), 

3347 ("nowait", InternalTraversal.dp_boolean), 

3348 ("read", InternalTraversal.dp_boolean), 

3349 ("skip_locked", InternalTraversal.dp_boolean), 

3350 ("key_share", InternalTraversal.dp_boolean), 

3351 ] 

3352 

3353 of: Optional[Sequence[ClauseElement]] 

3354 nowait: bool 

3355 read: bool 

3356 skip_locked: bool 

3357 

3358 @classmethod 

3359 def _from_argument( 

3360 cls, with_for_update: ForUpdateParameter 

3361 ) -> Optional[ForUpdateArg]: 

3362 if isinstance(with_for_update, ForUpdateArg): 

3363 return with_for_update 

3364 elif with_for_update in (None, False): 

3365 return None 

3366 elif with_for_update is True: 

3367 return ForUpdateArg() 

3368 else: 

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

3370 

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

3372 return ( 

3373 isinstance(other, ForUpdateArg) 

3374 and other.nowait == self.nowait 

3375 and other.read == self.read 

3376 and other.skip_locked == self.skip_locked 

3377 and other.key_share == self.key_share 

3378 and other.of is self.of 

3379 ) 

3380 

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

3382 return not self.__eq__(other) 

3383 

3384 def __hash__(self) -> int: 

3385 return id(self) 

3386 

3387 def __init__( 

3388 self, 

3389 *, 

3390 nowait: bool = False, 

3391 read: bool = False, 

3392 of: Optional[_ForUpdateOfArgument] = None, 

3393 skip_locked: bool = False, 

3394 key_share: bool = False, 

3395 ): 

3396 """Represents arguments specified to 

3397 :meth:`_expression.Select.for_update`. 

3398 

3399 """ 

3400 

3401 self.nowait = nowait 

3402 self.read = read 

3403 self.skip_locked = skip_locked 

3404 self.key_share = key_share 

3405 if of is not None: 

3406 self.of = [ 

3407 coercions.expect(roles.ColumnsClauseRole, elem) 

3408 for elem in util.to_list(of) 

3409 ] 

3410 else: 

3411 self.of = None 

3412 

3413 

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

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

3416 in a statement. 

3417 

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

3419 :func:`_expression.values` function. 

3420 

3421 .. versionadded:: 1.4 

3422 

3423 """ 

3424 

3425 __visit_name__ = "values" 

3426 

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

3428 _column_args: Tuple[NamedColumn[Any], ...] 

3429 

3430 _unnamed: bool 

3431 _traverse_internals: _TraverseInternalsType = [ 

3432 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3433 ("_data", InternalTraversal.dp_dml_multi_values), 

3434 ("name", InternalTraversal.dp_string), 

3435 ("literal_binds", InternalTraversal.dp_boolean), 

3436 ] + HasCTE._has_ctes_traverse_internals 

3437 

3438 name_cte_columns = True 

3439 

3440 def __init__( 

3441 self, 

3442 *columns: _OnlyColumnArgument[Any], 

3443 name: Optional[str] = None, 

3444 literal_binds: bool = False, 

3445 ): 

3446 super().__init__() 

3447 self._column_args = tuple( 

3448 coercions.expect(roles.LabeledColumnExprRole, col) 

3449 for col in columns 

3450 ) 

3451 

3452 if name is None: 

3453 self._unnamed = True 

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

3455 else: 

3456 self._unnamed = False 

3457 self.name = name 

3458 self.literal_binds = literal_binds 

3459 self.named_with_column = not self._unnamed 

3460 

3461 @property 

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

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

3464 

3465 @util.ro_non_memoized_property 

3466 def _all_selected_columns(self) -> _SelectIterable: 

3467 return self._column_args 

3468 

3469 @_generative 

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

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

3472 construct that is a copy of this 

3473 one with the given name. 

3474 

3475 This method is a VALUES-specific specialization of the 

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

3477 

3478 .. seealso:: 

3479 

3480 :ref:`tutorial_using_aliases` 

3481 

3482 :func:`_expression.alias` 

3483 

3484 """ 

3485 non_none_name: str 

3486 

3487 if name is None: 

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

3489 else: 

3490 non_none_name = name 

3491 

3492 self.name = non_none_name 

3493 self.named_with_column = True 

3494 self._unnamed = False 

3495 return self 

3496 

3497 @_generative 

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

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

3500 so that 

3501 it renders as LATERAL. 

3502 

3503 .. seealso:: 

3504 

3505 :func:`_expression.lateral` 

3506 

3507 """ 

3508 non_none_name: str 

3509 

3510 if name is None: 

3511 non_none_name = self.name 

3512 else: 

3513 non_none_name = name 

3514 

3515 self._is_lateral = True 

3516 self.name = non_none_name 

3517 self._unnamed = False 

3518 return self 

3519 

3520 @_generative 

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

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

3523 adding the given data to the data list. 

3524 

3525 E.g.:: 

3526 

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

3528 

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

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

3531 constructor. 

3532 

3533 """ 

3534 

3535 self._data += (values,) 

3536 return self 

3537 

3538 def scalar_values(self) -> ScalarValues: 

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

3540 COLUMN element in a statement. 

3541 

3542 .. versionadded:: 2.0.0b4 

3543 

3544 """ 

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

3546 

3547 def _populate_column_collection( 

3548 self, 

3549 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

3550 primary_key: ColumnSet, 

3551 foreign_keys: Set[KeyedColumnElement[Any]], 

3552 ) -> None: 

3553 for c in self._column_args: 

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

3555 _, c = c._make_proxy( 

3556 self, primary_key=primary_key, foreign_keys=foreign_keys 

3557 ) 

3558 else: 

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

3560 # no memoizations of other FROM clauses. 

3561 # see test_values.py -> test_auto_proxy_select_direct_col 

3562 c._reset_memoizations() 

3563 columns.add(c) 

3564 c.table = self 

3565 

3566 @util.ro_non_memoized_property 

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

3568 return [self] 

3569 

3570 

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

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

3573 COLUMN element in a statement. 

3574 

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

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

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

3578 an ``IN`` or ``NOT IN`` condition. 

3579 

3580 .. versionadded:: 2.0.0b4 

3581 

3582 """ 

3583 

3584 __visit_name__ = "scalar_values" 

3585 

3586 _traverse_internals: _TraverseInternalsType = [ 

3587 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3588 ("_data", InternalTraversal.dp_dml_multi_values), 

3589 ("literal_binds", InternalTraversal.dp_boolean), 

3590 ] 

3591 

3592 def __init__( 

3593 self, 

3594 columns: Sequence[NamedColumn[Any]], 

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

3596 literal_binds: bool, 

3597 ): 

3598 super().__init__() 

3599 self._column_args = columns 

3600 self._data = data 

3601 self.literal_binds = literal_binds 

3602 

3603 @property 

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

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

3606 

3607 def __clause_element__(self) -> ScalarValues: 

3608 return self 

3609 

3610 if TYPE_CHECKING: 

3611 

3612 def self_group( 

3613 self, against: Optional[OperatorType] = None 

3614 ) -> Self: ... 

3615 

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

3617 

3618 

3619class SelectBase( 

3620 roles.SelectStatementRole, 

3621 roles.DMLSelectRole, 

3622 roles.CompoundElementRole, 

3623 roles.InElementRole, 

3624 HasCTE, 

3625 SupportsCloneAnnotations, 

3626 Selectable, 

3627): 

3628 """Base class for SELECT statements. 

3629 

3630 

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

3632 :class:`_expression.CompoundSelect` and 

3633 :class:`_expression.TextualSelect`. 

3634 

3635 

3636 """ 

3637 

3638 _is_select_base = True 

3639 is_select = True 

3640 

3641 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3642 

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

3644 self._reset_memoizations() 

3645 

3646 @util.ro_non_memoized_property 

3647 def selected_columns( 

3648 self, 

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

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

3651 representing the columns that 

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

3653 

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

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

3656 within this collection cannot be directly nested inside another SELECT 

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

3658 necessary parenthesization required by SQL. 

3659 

3660 .. note:: 

3661 

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

3663 include expressions established in the columns clause using the 

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

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

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

3667 construct. 

3668 

3669 .. seealso:: 

3670 

3671 :attr:`_sql.Select.selected_columns` 

3672 

3673 .. versionadded:: 1.4 

3674 

3675 """ 

3676 raise NotImplementedError() 

3677 

3678 def _generate_fromclause_column_proxies( 

3679 self, 

3680 subquery: FromClause, 

3681 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

3682 primary_key: ColumnSet, 

3683 foreign_keys: Set[KeyedColumnElement[Any]], 

3684 *, 

3685 proxy_compound_columns: Optional[ 

3686 Iterable[Sequence[ColumnElement[Any]]] 

3687 ] = None, 

3688 ) -> None: 

3689 raise NotImplementedError() 

3690 

3691 @util.ro_non_memoized_property 

3692 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3695 constructs. 

3696 

3697 .. versionadded:: 1.4.12 

3698 

3699 .. seealso:: 

3700 

3701 :attr:`_sql.SelectBase.exported_columns` 

3702 

3703 """ 

3704 raise NotImplementedError() 

3705 

3706 @property 

3707 def exported_columns( 

3708 self, 

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

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

3711 that represents the "exported" 

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

3713 :class:`_sql.TextClause` constructs. 

3714 

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

3716 object are synonymous 

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

3718 

3719 .. versionadded:: 1.4 

3720 

3721 .. seealso:: 

3722 

3723 :attr:`_expression.Select.exported_columns` 

3724 

3725 :attr:`_expression.Selectable.exported_columns` 

3726 

3727 :attr:`_expression.FromClause.exported_columns` 

3728 

3729 

3730 """ 

3731 return self.selected_columns._as_readonly() 

3732 

3733 def get_label_style(self) -> SelectLabelStyle: 

3734 """ 

3735 Retrieve the current label style. 

3736 

3737 Implemented by subclasses. 

3738 

3739 """ 

3740 raise NotImplementedError() 

3741 

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

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

3744 

3745 Implemented by subclasses. 

3746 

3747 """ 

3748 

3749 raise NotImplementedError() 

3750 

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

3752 raise NotImplementedError() 

3753 

3754 @util.deprecated( 

3755 "1.4", 

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

3757 "method is deprecated and will be " 

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

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

3760 ) 

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

3762 return self.scalar_subquery() 

3763 

3764 def exists(self) -> Exists: 

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

3766 which can be used as a column expression. 

3767 

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

3769 

3770 .. seealso:: 

3771 

3772 :func:`_sql.exists` 

3773 

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

3775 

3776 .. versionadded:: 1.4 

3777 

3778 """ 

3779 return Exists(self) 

3780 

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

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

3783 used as a column expression. 

3784 

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

3786 

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

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

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

3790 an enclosing SELECT. 

3791 

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

3793 subquery that can be produced using the 

3794 :meth:`_expression.SelectBase.subquery` 

3795 method. 

3796 

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

3798 :meth:`_expression.SelectBase.scalar_subquery`. 

3799 

3800 .. seealso:: 

3801 

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

3803 

3804 """ 

3805 if self._label_style is not LABEL_STYLE_NONE: 

3806 self = self.set_label_style(LABEL_STYLE_NONE) 

3807 

3808 return ScalarSelect(self) 

3809 

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

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

3812 subquery with a label. 

3813 

3814 .. seealso:: 

3815 

3816 :meth:`_expression.SelectBase.scalar_subquery`. 

3817 

3818 """ 

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

3820 

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

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

3823 

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

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

3826 

3827 .. seealso:: 

3828 

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

3830 

3831 """ 

3832 return Lateral._factory(self, name) 

3833 

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

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

3836 

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

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

3839 SELECT statement. 

3840 

3841 Given a SELECT statement such as:: 

3842 

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

3844 

3845 The above statement might look like: 

3846 

3847 .. sourcecode:: sql 

3848 

3849 SELECT table.id, table.name FROM table 

3850 

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

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

3853 a named sub-element:: 

3854 

3855 subq = stmt.subquery() 

3856 new_stmt = select(subq) 

3857 

3858 The above renders as: 

3859 

3860 .. sourcecode:: sql 

3861 

3862 SELECT anon_1.id, anon_1.name 

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

3864 

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

3866 is equivalent to calling 

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

3868 method on a FROM object; however, 

3869 as a :class:`_expression.SelectBase` 

3870 object is not directly FROM object, 

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

3872 method provides clearer semantics. 

3873 

3874 .. versionadded:: 1.4 

3875 

3876 """ 

3877 

3878 return Subquery._construct( 

3879 self._ensure_disambiguated_names(), name=name 

3880 ) 

3881 

3882 @util.preload_module("sqlalchemy.sql.ddl") 

3883 def into( 

3884 self, 

3885 target: str, 

3886 *, 

3887 metadata: Optional["MetaData"] = None, 

3888 schema: Optional[str] = None, 

3889 temporary: bool = False, 

3890 if_not_exists: bool = False, 

3891 ) -> CreateTableAs: 

3892 """Create a :class:`_schema.CreateTableAs` construct from this SELECT. 

3893 

3894 This method provides a convenient way to create a ``CREATE TABLE ... 

3895 AS`` statement from a SELECT, as well as compound SELECTs like UNION. 

3896 The new table will be created with columns matching the SELECT list. 

3897 

3898 Supported on all included backends, the construct emits 

3899 ``CREATE TABLE...AS`` for all backends except SQL Server, which instead 

3900 emits a ``SELECT..INTO`` statement. 

3901 

3902 e.g.:: 

3903 

3904 from sqlalchemy import select 

3905 

3906 # Create a new table from a SELECT 

3907 stmt = ( 

3908 select(users.c.id, users.c.name) 

3909 .where(users.c.status == "active") 

3910 .into("active_users") 

3911 ) 

3912 

3913 with engine.begin() as conn: 

3914 conn.execute(stmt) 

3915 

3916 # With optional flags 

3917 stmt = ( 

3918 select(users.c.id) 

3919 .where(users.c.status == "inactive") 

3920 .into("inactive_users", schema="analytics", if_not_exists=True) 

3921 ) 

3922 

3923 .. versionadded:: 2.1 

3924 

3925 :param target: Name of the table to create as a string. Must be 

3926 unqualified; use the ``schema`` parameter for qualification. 

3927 

3928 :param metadata: :class:`_schema.MetaData`, optional 

3929 If provided, the :class:`_schema.Table` object available via the 

3930 :attr:`.CreateTableAs.table` attribute will be associated with this 

3931 :class:`.MetaData`. Otherwise, a new, empty :class:`.MetaData` 

3932 is created. 

3933 

3934 :param schema: Optional schema name for the new table. 

3935 

3936 :param temporary: If True, create a temporary table where supported 

3937 

3938 :param if_not_exists: If True, add IF NOT EXISTS clause where supported 

3939 

3940 :return: A :class:`_schema.CreateTableAs` construct. 

3941 

3942 .. seealso:: 

3943 

3944 :ref:`metadata_create_table_as` - in :ref:`metadata_toplevel` 

3945 

3946 :class:`_schema.CreateTableAs` 

3947 

3948 """ 

3949 sql_ddl = util.preloaded.sql_ddl 

3950 

3951 return sql_ddl.CreateTableAs( 

3952 self, 

3953 target, 

3954 metadata=metadata, 

3955 schema=schema, 

3956 temporary=temporary, 

3957 if_not_exists=if_not_exists, 

3958 ) 

3959 

3960 def _ensure_disambiguated_names(self) -> Self: 

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

3962 disambiguated in some way, if possible. 

3963 

3964 """ 

3965 

3966 raise NotImplementedError() 

3967 

3968 def alias( 

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

3970 ) -> Subquery: 

3971 """Return a named subquery against this 

3972 :class:`_expression.SelectBase`. 

3973 

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

3975 :class:`_expression.FromClause`), 

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

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

3978 :class:`_expression.FromClause`. 

3979 

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

3981 method is now 

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

3983 

3984 """ 

3985 return self.subquery(name=name) 

3986 

3987 

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

3989 

3990 

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

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

3993 

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

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

3996 compound selects. 

3997 

3998 """ 

3999 

4000 __visit_name__ = "select_statement_grouping" 

4001 _traverse_internals: _TraverseInternalsType = [ 

4002 ("element", InternalTraversal.dp_clauseelement) 

4003 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4004 

4005 _is_select_container = True 

4006 

4007 element: _SB 

4008 

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

4010 self.element = cast( 

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

4012 ) 

4013 

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

4015 new_element = self.element._ensure_disambiguated_names() 

4016 if new_element is not self.element: 

4017 return SelectStatementGrouping(new_element) 

4018 else: 

4019 return self 

4020 

4021 def get_label_style(self) -> SelectLabelStyle: 

4022 return self.element.get_label_style() 

4023 

4024 def set_label_style( 

4025 self, label_style: SelectLabelStyle 

4026 ) -> SelectStatementGrouping[_SB]: 

4027 return SelectStatementGrouping( 

4028 self.element.set_label_style(label_style) 

4029 ) 

4030 

4031 @property 

4032 def select_statement(self) -> _SB: 

4033 return self.element 

4034 

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

4036 return self 

4037 

4038 if TYPE_CHECKING: 

4039 

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

4041 

4042 # def _generate_columns_plus_names( 

4043 # self, anon_for_dupe_key: bool 

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

4045 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

4046 

4047 def _generate_fromclause_column_proxies( 

4048 self, 

4049 subquery: FromClause, 

4050 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

4051 primary_key: ColumnSet, 

4052 foreign_keys: Set[KeyedColumnElement[Any]], 

4053 *, 

4054 proxy_compound_columns: Optional[ 

4055 Iterable[Sequence[ColumnElement[Any]]] 

4056 ] = None, 

4057 ) -> None: 

4058 self.element._generate_fromclause_column_proxies( 

4059 subquery, 

4060 columns, 

4061 proxy_compound_columns=proxy_compound_columns, 

4062 primary_key=primary_key, 

4063 foreign_keys=foreign_keys, 

4064 ) 

4065 

4066 @util.ro_non_memoized_property 

4067 def _all_selected_columns(self) -> _SelectIterable: 

4068 return self.element._all_selected_columns 

4069 

4070 @util.ro_non_memoized_property 

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

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

4073 representing the columns that 

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

4075 :class:`_sql.TextClause` constructs. 

4076 

4077 .. versionadded:: 1.4 

4078 

4079 .. seealso:: 

4080 

4081 :attr:`_sql.Select.selected_columns` 

4082 

4083 """ 

4084 return self.element.selected_columns 

4085 

4086 @util.ro_non_memoized_property 

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

4088 return self.element._from_objects 

4089 

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

4091 return self.element._scalar_type() 

4092 

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

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

4095 raise NotImplementedError 

4096 

4097 

4098class GenerativeSelect(DialectKWArgs, SelectBase, Generative): 

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

4100 added. 

4101 

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

4103 :class:`_expression.CompoundSelect` 

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

4105 rendering can be controlled. Compare to 

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

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

4108 and is also a SELECT construct, 

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

4110 only wrapped as a subquery. 

4111 

4112 """ 

4113 

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

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

4116 _limit_clause: Optional[ColumnElement[Any]] = None 

4117 _offset_clause: Optional[ColumnElement[Any]] = None 

4118 _fetch_clause: Optional[ColumnElement[Any]] = None 

4119 _fetch_clause_options: Optional[Dict[str, bool]] = None 

4120 _for_update_arg: Optional[ForUpdateArg] = None 

4121 

4122 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

4123 self._label_style = _label_style 

4124 

4125 @_generative 

4126 def with_for_update( 

4127 self, 

4128 *, 

4129 nowait: bool = False, 

4130 read: bool = False, 

4131 of: Optional[_ForUpdateOfArgument] = None, 

4132 skip_locked: bool = False, 

4133 key_share: bool = False, 

4134 ) -> Self: 

4135 """Specify a ``FOR UPDATE`` clause for this 

4136 :class:`_expression.GenerativeSelect`. 

4137 

4138 E.g.:: 

4139 

4140 stmt = select(table).with_for_update(nowait=True) 

4141 

4142 On a database like PostgreSQL or Oracle Database, the above would 

4143 render a statement like: 

4144 

4145 .. sourcecode:: sql 

4146 

4147 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

4148 

4149 on other backends, the ``nowait`` option is ignored and instead 

4150 would produce: 

4151 

4152 .. sourcecode:: sql 

4153 

4154 SELECT table.a, table.b FROM table FOR UPDATE 

4155 

4156 When called with no arguments, the statement will render with 

4157 the suffix ``FOR UPDATE``. Additional arguments can then be 

4158 provided which allow for common database-specific 

4159 variants. 

4160 

4161 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

4162 Database and PostgreSQL dialects. 

4163 

4164 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

4165 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

4166 ``nowait``, will render ``FOR SHARE NOWAIT``. 

4167 

4168 :param of: SQL expression or list of SQL expression elements, 

4169 (typically :class:`_schema.Column` objects or a compatible expression, 

4170 for some backends may also be a table expression) which will render 

4171 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle 

4172 Database, some MySQL versions and possibly others. May render as a 

4173 table or as a column depending on backend. 

4174 

4175 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on 

4176 Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` 

4177 if ``read=True`` is also specified. 

4178 

4179 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

4180 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

4181 on the PostgreSQL dialect. 

4182 

4183 """ 

4184 self._for_update_arg = ForUpdateArg( 

4185 nowait=nowait, 

4186 read=read, 

4187 of=of, 

4188 skip_locked=skip_locked, 

4189 key_share=key_share, 

4190 ) 

4191 return self 

4192 

4193 def get_label_style(self) -> SelectLabelStyle: 

4194 """ 

4195 Retrieve the current label style. 

4196 

4197 .. versionadded:: 1.4 

4198 

4199 """ 

4200 return self._label_style 

4201 

4202 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4203 """Return a new selectable with the specified label style. 

4204 

4205 There are three "label styles" available, 

4206 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

4207 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

4208 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

4209 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

4210 

4211 In modern SQLAlchemy, there is not generally a need to change the 

4212 labeling style, as per-expression labels are more effectively used by 

4213 making use of the :meth:`_sql.ColumnElement.label` method. In past 

4214 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

4215 disambiguate same-named columns from different tables, aliases, or 

4216 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

4217 applies labels only to names that conflict with an existing name so 

4218 that the impact of this labeling is minimal. 

4219 

4220 The rationale for disambiguation is mostly so that all column 

4221 expressions are available from a given :attr:`_sql.FromClause.c` 

4222 collection when a subquery is created. 

4223 

4224 .. versionadded:: 1.4 - the 

4225 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

4226 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

4227 ``use_labels=True`` methods and/or parameters. 

4228 

4229 .. seealso:: 

4230 

4231 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY` 

4232 

4233 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL` 

4234 

4235 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE` 

4236 

4237 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DEFAULT` 

4238 

4239 """ 

4240 if self._label_style is not style: 

4241 self = self._generate() 

4242 self._label_style = style 

4243 return self 

4244 

4245 @property 

4246 def _group_by_clause(self) -> ClauseList: 

4247 """ClauseList access to group_by_clauses for legacy dialects""" 

4248 return ClauseList._construct_raw( 

4249 operators.comma_op, self._group_by_clauses 

4250 ) 

4251 

4252 @property 

4253 def _order_by_clause(self) -> ClauseList: 

4254 """ClauseList access to order_by_clauses for legacy dialects""" 

4255 return ClauseList._construct_raw( 

4256 operators.comma_op, self._order_by_clauses 

4257 ) 

4258 

4259 def _offset_or_limit_clause( 

4260 self, 

4261 element: _LimitOffsetType, 

4262 name: Optional[str] = None, 

4263 type_: Optional[_TypeEngineArgument[int]] = None, 

4264 ) -> ColumnElement[Any]: 

4265 """Convert the given value to an "offset or limit" clause. 

4266 

4267 This handles incoming integers and converts to an expression; if 

4268 an expression is already given, it is passed through. 

4269 

4270 """ 

4271 return coercions.expect( 

4272 roles.LimitOffsetRole, element, name=name, type_=type_ 

4273 ) 

4274 

4275 @overload 

4276 def _offset_or_limit_clause_asint( 

4277 self, clause: ColumnElement[Any], attrname: str 

4278 ) -> NoReturn: ... 

4279 

4280 @overload 

4281 def _offset_or_limit_clause_asint( 

4282 self, clause: Optional[_OffsetLimitParam], attrname: str 

4283 ) -> Optional[int]: ... 

4284 

4285 def _offset_or_limit_clause_asint( 

4286 self, clause: Optional[ColumnElement[Any]], attrname: str 

4287 ) -> Union[NoReturn, Optional[int]]: 

4288 """Convert the "offset or limit" clause of a select construct to an 

4289 integer. 

4290 

4291 This is only possible if the value is stored as a simple bound 

4292 parameter. Otherwise, a compilation error is raised. 

4293 

4294 """ 

4295 if clause is None: 

4296 return None 

4297 try: 

4298 value = clause._limit_offset_value 

4299 except AttributeError as err: 

4300 raise exc.CompileError( 

4301 "This SELECT structure does not use a simple " 

4302 "integer value for %s" % attrname 

4303 ) from err 

4304 else: 

4305 return util.asint(value) 

4306 

4307 @property 

4308 def _limit(self) -> Optional[int]: 

4309 """Get an integer value for the limit. This should only be used 

4310 by code that cannot support a limit as a BindParameter or 

4311 other custom clause as it will throw an exception if the limit 

4312 isn't currently set to an integer. 

4313 

4314 """ 

4315 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

4316 

4317 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

4318 """True if the clause is a simple integer, False 

4319 if it is not present or is a SQL expression. 

4320 """ 

4321 return isinstance(clause, _OffsetLimitParam) 

4322 

4323 @property 

4324 def _offset(self) -> Optional[int]: 

4325 """Get an integer value for the offset. This should only be used 

4326 by code that cannot support an offset as a BindParameter or 

4327 other custom clause as it will throw an exception if the 

4328 offset isn't currently set to an integer. 

4329 

4330 """ 

4331 return self._offset_or_limit_clause_asint( 

4332 self._offset_clause, "offset" 

4333 ) 

4334 

4335 @property 

4336 def _has_row_limiting_clause(self) -> bool: 

4337 return ( 

4338 self._limit_clause is not None 

4339 or self._offset_clause is not None 

4340 or self._fetch_clause is not None 

4341 ) 

4342 

4343 @_generative 

4344 def limit(self, limit: _LimitOffsetType) -> Self: 

4345 """Return a new selectable with the given LIMIT criterion 

4346 applied. 

4347 

4348 This is a numerical value which usually renders as a ``LIMIT`` 

4349 expression in the resulting select. Backends that don't 

4350 support ``LIMIT`` will attempt to provide similar 

4351 functionality. 

4352 

4353 .. note:: 

4354 

4355 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4356 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4357 

4358 :param limit: an integer LIMIT parameter, or a SQL expression 

4359 that provides an integer result. Pass ``None`` to reset it. 

4360 

4361 .. seealso:: 

4362 

4363 :meth:`_sql.GenerativeSelect.fetch` 

4364 

4365 :meth:`_sql.GenerativeSelect.offset` 

4366 

4367 """ 

4368 

4369 self._fetch_clause = self._fetch_clause_options = None 

4370 self._limit_clause = self._offset_or_limit_clause(limit) 

4371 return self 

4372 

4373 @_generative 

4374 def fetch( 

4375 self, 

4376 count: _LimitOffsetType, 

4377 with_ties: bool = False, 

4378 percent: bool = False, 

4379 **dialect_kw: Any, 

4380 ) -> Self: 

4381 r"""Return a new selectable with the given FETCH FIRST criterion 

4382 applied. 

4383 

4384 This is a numeric value which usually renders as ``FETCH {FIRST | NEXT} 

4385 [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting 

4386 select. This functionality is is currently implemented for Oracle 

4387 Database, PostgreSQL, MSSQL. 

4388 

4389 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4390 

4391 .. note:: 

4392 

4393 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4394 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4395 

4396 .. versionadded:: 1.4 

4397 

4398 :param count: an integer COUNT parameter, or a SQL expression 

4399 that provides an integer result. When ``percent=True`` this will 

4400 represent the percentage of rows to return, not the absolute value. 

4401 Pass ``None`` to reset it. 

4402 

4403 :param with_ties: When ``True``, the WITH TIES option is used 

4404 to return any additional rows that tie for the last place in the 

4405 result set according to the ``ORDER BY`` clause. The 

4406 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4407 

4408 :param percent: When ``True``, ``count`` represents the percentage 

4409 of the total number of selected rows to return. Defaults to ``False`` 

4410 

4411 :param \**dialect_kw: Additional dialect-specific keyword arguments 

4412 may be accepted by dialects. 

4413 

4414 .. versionadded:: 2.0.41 

4415 

4416 .. seealso:: 

4417 

4418 :meth:`_sql.GenerativeSelect.limit` 

4419 

4420 :meth:`_sql.GenerativeSelect.offset` 

4421 

4422 """ 

4423 self._validate_dialect_kwargs(dialect_kw) 

4424 self._limit_clause = None 

4425 if count is None: 

4426 self._fetch_clause = self._fetch_clause_options = None 

4427 else: 

4428 self._fetch_clause = self._offset_or_limit_clause(count) 

4429 self._fetch_clause_options = { 

4430 "with_ties": with_ties, 

4431 "percent": percent, 

4432 } 

4433 return self 

4434 

4435 @_generative 

4436 def offset(self, offset: _LimitOffsetType) -> Self: 

4437 """Return a new selectable with the given OFFSET criterion 

4438 applied. 

4439 

4440 

4441 This is a numeric value which usually renders as an ``OFFSET`` 

4442 expression in the resulting select. Backends that don't 

4443 support ``OFFSET`` will attempt to provide similar 

4444 functionality. 

4445 

4446 :param offset: an integer OFFSET parameter, or a SQL expression 

4447 that provides an integer result. Pass ``None`` to reset it. 

4448 

4449 .. seealso:: 

4450 

4451 :meth:`_sql.GenerativeSelect.limit` 

4452 

4453 :meth:`_sql.GenerativeSelect.fetch` 

4454 

4455 """ 

4456 

4457 self._offset_clause = self._offset_or_limit_clause(offset) 

4458 return self 

4459 

4460 @_generative 

4461 @util.preload_module("sqlalchemy.sql.util") 

4462 def slice( 

4463 self, 

4464 start: int, 

4465 stop: int, 

4466 ) -> Self: 

4467 """Apply LIMIT / OFFSET to this statement based on a slice. 

4468 

4469 The start and stop indices behave like the argument to Python's 

4470 built-in :func:`range` function. This method provides an 

4471 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4472 query. 

4473 

4474 For example, :: 

4475 

4476 stmt = select(User).order_by(User.id).slice(1, 3) 

4477 

4478 renders as 

4479 

4480 .. sourcecode:: sql 

4481 

4482 SELECT users.id AS users_id, 

4483 users.name AS users_name 

4484 FROM users ORDER BY users.id 

4485 LIMIT ? OFFSET ? 

4486 (2, 1) 

4487 

4488 .. note:: 

4489 

4490 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4491 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4492 

4493 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4494 method generalized from the ORM. 

4495 

4496 .. seealso:: 

4497 

4498 :meth:`_sql.GenerativeSelect.limit` 

4499 

4500 :meth:`_sql.GenerativeSelect.offset` 

4501 

4502 :meth:`_sql.GenerativeSelect.fetch` 

4503 

4504 """ 

4505 sql_util = util.preloaded.sql_util 

4506 self._fetch_clause = self._fetch_clause_options = None 

4507 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4508 self._limit_clause, self._offset_clause, start, stop 

4509 ) 

4510 return self 

4511 

4512 @_generative 

4513 def order_by( 

4514 self, 

4515 __first: Union[ 

4516 Literal[None, _NoArg.NO_ARG], 

4517 _ColumnExpressionOrStrLabelArgument[Any], 

4518 roles.OrderByRole, 

4519 ] = _NoArg.NO_ARG, 

4520 /, 

4521 *clauses: Union[ 

4522 _ColumnExpressionOrStrLabelArgument[Any], roles.OrderByRole 

4523 ], 

4524 ) -> Self: 

4525 r"""Return a new selectable with the given list of ORDER BY 

4526 criteria applied. 

4527 

4528 e.g.:: 

4529 

4530 stmt = select(table).order_by(table.c.id, table.c.name) 

4531 

4532 Calling this method multiple times is equivalent to calling it once 

4533 with all the clauses concatenated. All existing ORDER BY criteria may 

4534 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

4535 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

4536 

4537 # will erase all ORDER BY and ORDER BY new_col alone 

4538 stmt = stmt.order_by(None).order_by(new_col) 

4539 

4540 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4541 constructs which will be used to generate an ORDER BY clause. 

4542 

4543 Alternatively, an individual entry may also be the string name of a 

4544 label located elsewhere in the columns clause of the statement which 

4545 will be matched and rendered in a backend-specific way based on 

4546 context; see :ref:`tutorial_order_by_label` for background on string 

4547 label matching in ORDER BY and GROUP BY expressions. 

4548 

4549 .. seealso:: 

4550 

4551 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

4552 

4553 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4554 

4555 """ 

4556 

4557 if not clauses and __first is None: 

4558 self._order_by_clauses = () 

4559 elif __first is not _NoArg.NO_ARG: 

4560 self._order_by_clauses += tuple( 

4561 coercions.expect( 

4562 roles.OrderByRole, clause, apply_propagate_attrs=self 

4563 ) 

4564 for clause in (__first,) + clauses 

4565 ) 

4566 return self 

4567 

4568 @_generative 

4569 def group_by( 

4570 self, 

4571 __first: Union[ 

4572 Literal[None, _NoArg.NO_ARG], 

4573 _ColumnExpressionOrStrLabelArgument[Any], 

4574 ] = _NoArg.NO_ARG, 

4575 /, 

4576 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4577 ) -> Self: 

4578 r"""Return a new selectable with the given list of GROUP BY 

4579 criterion applied. 

4580 

4581 All existing GROUP BY settings can be suppressed by passing ``None``. 

4582 

4583 e.g.:: 

4584 

4585 stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name) 

4586 

4587 :param \*clauses: a series of :class:`_expression.ColumnElement` 

4588 constructs which will be used to generate an GROUP BY clause. 

4589 

4590 Alternatively, an individual entry may also be the string name of a 

4591 label located elsewhere in the columns clause of the statement which 

4592 will be matched and rendered in a backend-specific way based on 

4593 context; see :ref:`tutorial_order_by_label` for background on string 

4594 label matching in ORDER BY and GROUP BY expressions. 

4595 

4596 .. seealso:: 

4597 

4598 :ref:`tutorial_group_by_w_aggregates` - in the 

4599 :ref:`unified_tutorial` 

4600 

4601 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

4602 

4603 """ # noqa: E501 

4604 

4605 if not clauses and __first is None: 

4606 self._group_by_clauses = () 

4607 elif __first is not _NoArg.NO_ARG: 

4608 self._group_by_clauses += tuple( 

4609 coercions.expect( 

4610 roles.GroupByRole, clause, apply_propagate_attrs=self 

4611 ) 

4612 for clause in (__first,) + clauses 

4613 ) 

4614 return self 

4615 

4616 

4617@CompileState.plugin_for("default", "compound_select") 

4618class CompoundSelectState(CompileState): 

4619 @util.memoized_property 

4620 def _label_resolve_dict( 

4621 self, 

4622 ) -> Tuple[ 

4623 Dict[str, ColumnElement[Any]], 

4624 Dict[str, ColumnElement[Any]], 

4625 Dict[str, ColumnElement[Any]], 

4626 ]: 

4627 # TODO: this is hacky and slow 

4628 hacky_subquery = self.statement.subquery() 

4629 hacky_subquery.named_with_column = False 

4630 d = {c.key: c for c in hacky_subquery.c} 

4631 return d, d, d 

4632 

4633 

4634class _CompoundSelectKeyword(Enum): 

4635 UNION = "UNION" 

4636 UNION_ALL = "UNION ALL" 

4637 EXCEPT = "EXCEPT" 

4638 EXCEPT_ALL = "EXCEPT ALL" 

4639 INTERSECT = "INTERSECT" 

4640 INTERSECT_ALL = "INTERSECT ALL" 

4641 

4642 

4643class CompoundSelect( 

4644 HasCompileState, GenerativeSelect, TypedReturnsRows[Unpack[_Ts]] 

4645): 

4646 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4647 SELECT-based set operations. 

4648 

4649 

4650 .. seealso:: 

4651 

4652 :func:`_expression.union` 

4653 

4654 :func:`_expression.union_all` 

4655 

4656 :func:`_expression.intersect` 

4657 

4658 :func:`_expression.intersect_all` 

4659 

4660 :func:`_expression.except` 

4661 

4662 :func:`_expression.except_all` 

4663 

4664 """ 

4665 

4666 __visit_name__ = "compound_select" 

4667 

4668 _traverse_internals: _TraverseInternalsType = ( 

4669 [ 

4670 ("selects", InternalTraversal.dp_clauseelement_list), 

4671 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4672 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4673 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4674 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4675 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4676 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4677 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4678 ("keyword", InternalTraversal.dp_string), 

4679 ] 

4680 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4681 + HasCTE._has_ctes_traverse_internals 

4682 + DialectKWArgs._dialect_kwargs_traverse_internals 

4683 + ExecutableStatement._executable_traverse_internals 

4684 ) 

4685 

4686 selects: List[SelectBase] 

4687 

4688 _is_from_container = True 

4689 _auto_correlate = False 

4690 

4691 def __init__( 

4692 self, 

4693 keyword: _CompoundSelectKeyword, 

4694 *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]], 

4695 ): 

4696 self.keyword = keyword 

4697 self.selects = [ 

4698 coercions.expect( 

4699 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4700 ).self_group(against=self) 

4701 for s in selects 

4702 ] 

4703 

4704 GenerativeSelect.__init__(self) 

4705 

4706 @classmethod 

4707 def _create_union( 

4708 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4709 ) -> CompoundSelect[Unpack[_Ts]]: 

4710 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4711 

4712 @classmethod 

4713 def _create_union_all( 

4714 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4715 ) -> CompoundSelect[Unpack[_Ts]]: 

4716 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4717 

4718 @classmethod 

4719 def _create_except( 

4720 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4721 ) -> CompoundSelect[Unpack[_Ts]]: 

4722 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4723 

4724 @classmethod 

4725 def _create_except_all( 

4726 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4727 ) -> CompoundSelect[Unpack[_Ts]]: 

4728 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4729 

4730 @classmethod 

4731 def _create_intersect( 

4732 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4733 ) -> CompoundSelect[Unpack[_Ts]]: 

4734 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4735 

4736 @classmethod 

4737 def _create_intersect_all( 

4738 cls, *selects: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

4739 ) -> CompoundSelect[Unpack[_Ts]]: 

4740 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4741 

4742 def _scalar_type(self) -> TypeEngine[Any]: 

4743 return self.selects[0]._scalar_type() 

4744 

4745 def self_group( 

4746 self, against: Optional[OperatorType] = None 

4747 ) -> GroupedElement: 

4748 return SelectStatementGrouping(self) 

4749 

4750 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

4751 for s in self.selects: 

4752 if s.is_derived_from(fromclause): 

4753 return True 

4754 return False 

4755 

4756 def set_label_style(self, style: SelectLabelStyle) -> Self: 

4757 if self._label_style is not style: 

4758 self = self._generate() 

4759 select_0 = self.selects[0].set_label_style(style) 

4760 self.selects = [select_0] + self.selects[1:] 

4761 

4762 return self 

4763 

4764 def _ensure_disambiguated_names(self) -> Self: 

4765 new_select = self.selects[0]._ensure_disambiguated_names() 

4766 if new_select is not self.selects[0]: 

4767 self = self._generate() 

4768 self.selects = [new_select] + self.selects[1:] 

4769 

4770 return self 

4771 

4772 def _generate_fromclause_column_proxies( 

4773 self, 

4774 subquery: FromClause, 

4775 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

4776 primary_key: ColumnSet, 

4777 foreign_keys: Set[KeyedColumnElement[Any]], 

4778 *, 

4779 proxy_compound_columns: Optional[ 

4780 Iterable[Sequence[ColumnElement[Any]]] 

4781 ] = None, 

4782 ) -> None: 

4783 # this is a slightly hacky thing - the union exports a 

4784 # column that resembles just that of the *first* selectable. 

4785 # to get at a "composite" column, particularly foreign keys, 

4786 # you have to dig through the proxies collection which we 

4787 # generate below. 

4788 select_0 = self.selects[0] 

4789 

4790 if self._label_style is not LABEL_STYLE_DEFAULT: 

4791 select_0 = select_0.set_label_style(self._label_style) 

4792 

4793 # hand-construct the "_proxies" collection to include all 

4794 # derived columns place a 'weight' annotation corresponding 

4795 # to how low in the list of select()s the column occurs, so 

4796 # that the corresponding_column() operation can resolve 

4797 # conflicts 

4798 extra_col_iterator = zip( 

4799 *[ 

4800 [ 

4801 c._annotate(dd) 

4802 for c in stmt._all_selected_columns 

4803 if is_column_element(c) 

4804 ] 

4805 for dd, stmt in [ 

4806 ({"weight": i + 1}, stmt) 

4807 for i, stmt in enumerate(self.selects) 

4808 ] 

4809 ] 

4810 ) 

4811 

4812 # the incoming proxy_compound_columns can be present also if this is 

4813 # a compound embedded in a compound. it's probably more appropriate 

4814 # that we generate new weights local to this nested compound, though 

4815 # i haven't tried to think what it means for compound nested in 

4816 # compound 

4817 select_0._generate_fromclause_column_proxies( 

4818 subquery, 

4819 columns, 

4820 proxy_compound_columns=extra_col_iterator, 

4821 primary_key=primary_key, 

4822 foreign_keys=foreign_keys, 

4823 ) 

4824 

4825 def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None: 

4826 super()._refresh_for_new_column(column) 

4827 for select in self.selects: 

4828 select._refresh_for_new_column(column) 

4829 

4830 @util.ro_non_memoized_property 

4831 def _all_selected_columns(self) -> _SelectIterable: 

4832 return self.selects[0]._all_selected_columns 

4833 

4834 @util.ro_non_memoized_property 

4835 def selected_columns( 

4836 self, 

4837 ) -> ColumnCollection[str, ColumnElement[Any]]: 

4838 """A :class:`_expression.ColumnCollection` 

4839 representing the columns that 

4840 this SELECT statement or similar construct returns in its result set, 

4841 not including :class:`_sql.TextClause` constructs. 

4842 

4843 For a :class:`_expression.CompoundSelect`, the 

4844 :attr:`_expression.CompoundSelect.selected_columns` 

4845 attribute returns the selected 

4846 columns of the first SELECT statement contained within the series of 

4847 statements within the set operation. 

4848 

4849 .. seealso:: 

4850 

4851 :attr:`_sql.Select.selected_columns` 

4852 

4853 .. versionadded:: 1.4 

4854 

4855 """ 

4856 return self.selects[0].selected_columns 

4857 

4858 

4859# backwards compat 

4860for elem in _CompoundSelectKeyword: 

4861 setattr(CompoundSelect, elem.name, elem) 

4862 

4863 

4864@CompileState.plugin_for("default", "select") 

4865class SelectState(util.MemoizedSlots, CompileState): 

4866 __slots__ = ( 

4867 "from_clauses", 

4868 "froms", 

4869 "columns_plus_names", 

4870 "_label_resolve_dict", 

4871 ) 

4872 

4873 if TYPE_CHECKING: 

4874 default_select_compile_options: CacheableOptions 

4875 else: 

4876 

4877 class default_select_compile_options(CacheableOptions): 

4878 _cache_key_traversal = [] 

4879 

4880 if TYPE_CHECKING: 

4881 

4882 @classmethod 

4883 def get_plugin_class( 

4884 cls, statement: Executable 

4885 ) -> Type[SelectState]: ... 

4886 

4887 def __init__( 

4888 self, 

4889 statement: Select[Unpack[TupleAny]], 

4890 compiler: SQLCompiler, 

4891 **kw: Any, 

4892 ): 

4893 self.statement = statement 

4894 self.from_clauses = statement._from_obj 

4895 

4896 for memoized_entities in statement._memoized_select_entities: 

4897 self._setup_joins( 

4898 memoized_entities._setup_joins, memoized_entities._raw_columns 

4899 ) 

4900 

4901 if statement._setup_joins: 

4902 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4903 

4904 self.froms = self._get_froms(statement) 

4905 

4906 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4907 

4908 @classmethod 

4909 def _plugin_not_implemented(cls) -> NoReturn: 

4910 raise NotImplementedError( 

4911 "The default SELECT construct without plugins does not " 

4912 "implement this method." 

4913 ) 

4914 

4915 @classmethod 

4916 def get_column_descriptions( 

4917 cls, statement: Select[Unpack[TupleAny]] 

4918 ) -> List[Dict[str, Any]]: 

4919 return [ 

4920 { 

4921 "name": name, 

4922 "type": element.type, 

4923 "expr": element, 

4924 } 

4925 for _, name, _, element, _ in ( 

4926 statement._generate_columns_plus_names(False) 

4927 ) 

4928 ] 

4929 

4930 @classmethod 

4931 def from_statement( 

4932 cls, 

4933 statement: Select[Unpack[TupleAny]], 

4934 from_statement: roles.ReturnsRowsRole, 

4935 ) -> ExecutableReturnsRows: 

4936 cls._plugin_not_implemented() 

4937 

4938 @classmethod 

4939 def get_columns_clause_froms( 

4940 cls, statement: Select[Unpack[TupleAny]] 

4941 ) -> List[FromClause]: 

4942 return cls._normalize_froms( 

4943 itertools.chain.from_iterable( 

4944 element._from_objects for element in statement._raw_columns 

4945 ) 

4946 ) 

4947 

4948 @classmethod 

4949 def _column_naming_convention( 

4950 cls, label_style: SelectLabelStyle 

4951 ) -> _LabelConventionCallable: 

4952 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4953 

4954 dedupe = label_style is not LABEL_STYLE_NONE 

4955 

4956 pa = prefix_anon_map() 

4957 names = set() 

4958 

4959 def go( 

4960 c: Union[ColumnElement[Any], AbstractTextClause], 

4961 col_name: Optional[str] = None, 

4962 ) -> Optional[str]: 

4963 if is_text_clause(c): 

4964 return None 

4965 elif TYPE_CHECKING: 

4966 assert is_column_element(c) 

4967 

4968 if not dedupe: 

4969 name = c._proxy_key 

4970 if name is None: 

4971 name = "_no_label" 

4972 return name 

4973 

4974 name = c._tq_key_label if table_qualified else c._proxy_key 

4975 

4976 if name is None: 

4977 name = "_no_label" 

4978 if name in names: 

4979 return c._anon_label(name) % pa 

4980 else: 

4981 names.add(name) 

4982 return name 

4983 

4984 elif name in names: 

4985 return ( 

4986 c._anon_tq_key_label % pa 

4987 if table_qualified 

4988 else c._anon_key_label % pa 

4989 ) 

4990 else: 

4991 names.add(name) 

4992 return name 

4993 

4994 return go 

4995 

4996 def _get_froms( 

4997 self, statement: Select[Unpack[TupleAny]] 

4998 ) -> List[FromClause]: 

4999 ambiguous_table_name_map: _AmbiguousTableNameMap 

5000 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

5001 

5002 return self._normalize_froms( 

5003 itertools.chain( 

5004 self.from_clauses, 

5005 itertools.chain.from_iterable( 

5006 [ 

5007 element._from_objects 

5008 for element in statement._raw_columns 

5009 ] 

5010 ), 

5011 itertools.chain.from_iterable( 

5012 [ 

5013 element._from_objects 

5014 for element in statement._where_criteria 

5015 ] 

5016 ), 

5017 ), 

5018 check_statement=statement, 

5019 ambiguous_table_name_map=ambiguous_table_name_map, 

5020 ) 

5021 

5022 @classmethod 

5023 def _normalize_froms( 

5024 cls, 

5025 iterable_of_froms: Iterable[FromClause], 

5026 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

5027 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

5028 ) -> List[FromClause]: 

5029 """given an iterable of things to select FROM, reduce them to what 

5030 would actually render in the FROM clause of a SELECT. 

5031 

5032 This does the job of checking for JOINs, tables, etc. that are in fact 

5033 overlapping due to cloning, adaption, present in overlapping joins, 

5034 etc. 

5035 

5036 """ 

5037 seen: Set[FromClause] = set() 

5038 froms: List[FromClause] = [] 

5039 

5040 for item in iterable_of_froms: 

5041 if is_subquery(item) and item.element is check_statement: 

5042 raise exc.InvalidRequestError( 

5043 "select() construct refers to itself as a FROM" 

5044 ) 

5045 

5046 if not seen.intersection(item._cloned_set): 

5047 froms.append(item) 

5048 seen.update(item._cloned_set) 

5049 

5050 if froms: 

5051 toremove = set( 

5052 itertools.chain.from_iterable( 

5053 [_expand_cloned(f._hide_froms) for f in froms] 

5054 ) 

5055 ) 

5056 if toremove: 

5057 # filter out to FROM clauses not in the list, 

5058 # using a list to maintain ordering 

5059 froms = [f for f in froms if f not in toremove] 

5060 

5061 if ambiguous_table_name_map is not None: 

5062 ambiguous_table_name_map.update( 

5063 ( 

5064 fr.name, 

5065 _anonymous_label.safe_construct( 

5066 hash(fr.name), fr.name 

5067 ), 

5068 ) 

5069 for item in froms 

5070 for fr in item._from_objects 

5071 if is_table(fr) 

5072 and fr.schema 

5073 and fr.name not in ambiguous_table_name_map 

5074 ) 

5075 

5076 return froms 

5077 

5078 def _get_display_froms( 

5079 self, 

5080 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

5081 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

5082 ) -> List[FromClause]: 

5083 """Return the full list of 'from' clauses to be displayed. 

5084 

5085 Takes into account a set of existing froms which may be 

5086 rendered in the FROM clause of enclosing selects; this Select 

5087 may want to leave those absent if it is automatically 

5088 correlating. 

5089 

5090 """ 

5091 statement = self.statement 

5092 return self._correlate_froms( 

5093 self.froms, 

5094 statement, 

5095 statement._correlate, 

5096 statement._correlate_except, 

5097 statement._auto_correlate, 

5098 explicit_correlate_froms, 

5099 implicit_correlate_froms, 

5100 ) 

5101 

5102 @classmethod 

5103 def _correlate_froms( 

5104 cls, 

5105 froms: List[FromClause], 

5106 statement: Select[Unpack[TupleAny]], 

5107 to_correlate: Optional[Sequence[FromClause]], 

5108 to_correlate_except: Optional[Sequence[FromClause]], 

5109 auto_correlate: bool, 

5110 explicit_correlate_froms: Optional[Sequence[FromClause]], 

5111 implicit_correlate_froms: Optional[Sequence[FromClause]], 

5112 ) -> List[FromClause]: 

5113 """Given a list of FROM clauses and correlation settings, return 

5114 the list of FROM clauses that remain after correlation. 

5115 

5116 This is the implementation for :meth:`.SelectState._get_display_froms` 

5117 that is also used by the ORM, which needs to know which FROM clauses 

5118 will be correlated before it has generated the final statement. 

5119 

5120 For ``explicit_correlate_froms`` and ``implicit_correlate_froms``, 

5121 see :meth:`.SQLCompiler._enclosing_correlate_froms`. 

5122 

5123 """ 

5124 

5125 if to_correlate: 

5126 to_remove = _cloned_intersection( 

5127 _cloned_intersection(froms, explicit_correlate_froms or ()), 

5128 to_correlate, 

5129 ) 

5130 froms = [f for f in froms if f not in to_remove] 

5131 

5132 if to_correlate_except is not None: 

5133 to_remove = _cloned_difference( 

5134 _cloned_intersection(froms, explicit_correlate_froms or ()), 

5135 to_correlate_except, 

5136 ) 

5137 froms = [f for f in froms if f not in to_remove] 

5138 

5139 if auto_correlate and implicit_correlate_froms and len(froms) > 1: 

5140 to_remove = _cloned_intersection(froms, implicit_correlate_froms) 

5141 froms = [f for f in froms if f not in to_remove] 

5142 

5143 if not len(froms): 

5144 raise exc.InvalidRequestError( 

5145 "Select statement '%r" 

5146 "' returned no FROM clauses " 

5147 "due to auto-correlation; " 

5148 "specify correlate(<tables>) " 

5149 "to control correlation " 

5150 "manually." % statement 

5151 ) 

5152 

5153 return froms 

5154 

5155 def _memoized_attr__label_resolve_dict( 

5156 self, 

5157 ) -> Tuple[ 

5158 Dict[str, ColumnElement[Any]], 

5159 Dict[str, ColumnElement[Any]], 

5160 Dict[str, ColumnElement[Any]], 

5161 ]: 

5162 with_cols: Dict[str, ColumnElement[Any]] = { 

5163 c._tq_label or c.key: c 

5164 for c in self.statement._all_selected_columns 

5165 if c._allow_label_resolve 

5166 } 

5167 only_froms: Dict[str, ColumnElement[Any]] = { 

5168 c.key: c # type: ignore[misc] 

5169 for c in _select_iterables(self.froms) 

5170 if c._allow_label_resolve 

5171 } 

5172 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

5173 for key, value in only_froms.items(): 

5174 with_cols.setdefault(key, value) 

5175 

5176 return with_cols, only_froms, only_cols 

5177 

5178 @classmethod 

5179 def _get_filter_by_entities( 

5180 cls, statement: Select[Unpack[TupleAny]] 

5181 ) -> Collection[ 

5182 Union[FromClause, _JoinTargetProtocol, ColumnElement[Any]] 

5183 ]: 

5184 """Return all entities to search for filter_by() attributes. 

5185 

5186 This includes: 

5187 

5188 * All joined entities from _setup_joins 

5189 * Memoized entities from previous operations (e.g., 

5190 before with_only_columns) 

5191 * Explicit FROM objects from _from_obj 

5192 * Entities inferred from _raw_columns 

5193 

5194 .. versionadded:: 2.1 

5195 

5196 """ 

5197 entities: set[ 

5198 Union[FromClause, _JoinTargetProtocol, ColumnElement[Any]] 

5199 ] 

5200 

5201 entities = set( 

5202 join_element[0] for join_element in statement._setup_joins 

5203 ) 

5204 

5205 for memoized in statement._memoized_select_entities: 

5206 entities.update( 

5207 join_element[0] for join_element in memoized._setup_joins 

5208 ) 

5209 

5210 entities.update(statement._from_obj) 

5211 

5212 for col in statement._raw_columns: 

5213 entities.update(col._from_objects) 

5214 

5215 return entities 

5216 

5217 @classmethod 

5218 def all_selected_columns( 

5219 cls, statement: Select[Unpack[TupleAny]] 

5220 ) -> _SelectIterable: 

5221 return [c for c in _select_iterables(statement._raw_columns)] 

5222 

5223 def _setup_joins( 

5224 self, 

5225 args: Tuple[_SetupJoinsElement, ...], 

5226 raw_columns: List[_ColumnsClauseElement], 

5227 ) -> None: 

5228 for right, onclause, left, flags in args: 

5229 if TYPE_CHECKING: 

5230 if onclause is not None: 

5231 assert isinstance(onclause, ColumnElement) 

5232 

5233 explicit_left = left 

5234 isouter = flags["isouter"] 

5235 full = flags["full"] 

5236 

5237 if left is None: 

5238 ( 

5239 left, 

5240 replace_from_obj_index, 

5241 ) = self._join_determine_implicit_left_side( 

5242 raw_columns, left, right, onclause 

5243 ) 

5244 else: 

5245 replace_from_obj_index = self._join_place_explicit_left_side( 

5246 left 

5247 ) 

5248 

5249 # these assertions can be made here, as if the right/onclause 

5250 # contained ORM elements, the select() statement would have been 

5251 # upgraded to an ORM select, and this method would not be called; 

5252 # orm.context.ORMSelectCompileState._join() would be 

5253 # used instead. 

5254 if TYPE_CHECKING: 

5255 assert isinstance(right, FromClause) 

5256 if onclause is not None: 

5257 assert isinstance(onclause, ColumnElement) 

5258 

5259 if replace_from_obj_index is not None: 

5260 # splice into an existing element in the 

5261 # self._from_obj list 

5262 left_clause = self.from_clauses[replace_from_obj_index] 

5263 

5264 if explicit_left is not None and onclause is None: 

5265 onclause = Join._join_condition(explicit_left, right) 

5266 

5267 self.from_clauses = ( 

5268 self.from_clauses[:replace_from_obj_index] 

5269 + ( 

5270 Join( 

5271 left_clause, 

5272 right, 

5273 onclause, 

5274 isouter=isouter, 

5275 full=full, 

5276 ), 

5277 ) 

5278 + self.from_clauses[replace_from_obj_index + 1 :] 

5279 ) 

5280 else: 

5281 assert left is not None 

5282 self.from_clauses = self.from_clauses + ( 

5283 Join(left, right, onclause, isouter=isouter, full=full), 

5284 ) 

5285 

5286 @util.preload_module("sqlalchemy.sql.util") 

5287 def _join_determine_implicit_left_side( 

5288 self, 

5289 raw_columns: List[_ColumnsClauseElement], 

5290 left: Optional[FromClause], 

5291 right: _JoinTargetElement, 

5292 onclause: Optional[ColumnElement[Any]], 

5293 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5294 """When join conditions don't express the left side explicitly, 

5295 determine if an existing FROM or entity in this query 

5296 can serve as the left hand side. 

5297 

5298 """ 

5299 

5300 sql_util = util.preloaded.sql_util 

5301 

5302 replace_from_obj_index: Optional[int] = None 

5303 

5304 from_clauses = self.from_clauses 

5305 

5306 if from_clauses: 

5307 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5308 from_clauses, right, onclause 

5309 ) 

5310 

5311 if len(indexes) == 1: 

5312 replace_from_obj_index = indexes[0] 

5313 left = from_clauses[replace_from_obj_index] 

5314 else: 

5315 potential = {} 

5316 statement = self.statement 

5317 

5318 for from_clause in itertools.chain( 

5319 itertools.chain.from_iterable( 

5320 [element._from_objects for element in raw_columns] 

5321 ), 

5322 itertools.chain.from_iterable( 

5323 [ 

5324 element._from_objects 

5325 for element in statement._where_criteria 

5326 ] 

5327 ), 

5328 ): 

5329 potential[from_clause] = () 

5330 

5331 all_clauses = list(potential.keys()) 

5332 indexes = sql_util.find_left_clause_to_join_from( 

5333 all_clauses, right, onclause 

5334 ) 

5335 

5336 if len(indexes) == 1: 

5337 left = all_clauses[indexes[0]] 

5338 

5339 if len(indexes) > 1: 

5340 raise exc.InvalidRequestError( 

5341 "Can't determine which FROM clause to join " 

5342 "from, there are multiple FROMS which can " 

5343 "join to this entity. Please use the .select_from() " 

5344 "method to establish an explicit left side, as well as " 

5345 "providing an explicit ON clause if not present already to " 

5346 "help resolve the ambiguity." 

5347 ) 

5348 elif not indexes: 

5349 raise exc.InvalidRequestError( 

5350 "Don't know how to join to %r. " 

5351 "Please use the .select_from() " 

5352 "method to establish an explicit left side, as well as " 

5353 "providing an explicit ON clause if not present already to " 

5354 "help resolve the ambiguity." % (right,) 

5355 ) 

5356 return left, replace_from_obj_index 

5357 

5358 @util.preload_module("sqlalchemy.sql.util") 

5359 def _join_place_explicit_left_side( 

5360 self, left: FromClause 

5361 ) -> Optional[int]: 

5362 replace_from_obj_index: Optional[int] = None 

5363 

5364 sql_util = util.preloaded.sql_util 

5365 

5366 from_clauses = list(self.statement._iterate_from_elements()) 

5367 

5368 if from_clauses: 

5369 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5370 self.from_clauses, left 

5371 ) 

5372 else: 

5373 indexes = [] 

5374 

5375 if len(indexes) > 1: 

5376 raise exc.InvalidRequestError( 

5377 "Can't identify which entity in which to assign the " 

5378 "left side of this join. Please use a more specific " 

5379 "ON clause." 

5380 ) 

5381 

5382 # have an index, means the left side is already present in 

5383 # an existing FROM in the self._from_obj tuple 

5384 if indexes: 

5385 replace_from_obj_index = indexes[0] 

5386 

5387 # no index, means we need to add a new element to the 

5388 # self._from_obj tuple 

5389 

5390 return replace_from_obj_index 

5391 

5392 

5393class _SelectFromElements: 

5394 __slots__ = () 

5395 

5396 _raw_columns: List[_ColumnsClauseElement] 

5397 _where_criteria: Tuple[ColumnElement[Any], ...] 

5398 _from_obj: Tuple[FromClause, ...] 

5399 

5400 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5401 # note this does not include elements 

5402 # in _setup_joins 

5403 

5404 seen = set() 

5405 for element in self._raw_columns: 

5406 for fr in element._from_objects: 

5407 if fr in seen: 

5408 continue 

5409 seen.add(fr) 

5410 yield fr 

5411 for element in self._where_criteria: 

5412 for fr in element._from_objects: 

5413 if fr in seen: 

5414 continue 

5415 seen.add(fr) 

5416 yield fr 

5417 for element in self._from_obj: 

5418 if element in seen: 

5419 continue 

5420 seen.add(element) 

5421 yield element 

5422 

5423 

5424class _MemoizedSelectEntities( 

5425 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5426): 

5427 """represents partial state from a Select object, for the case 

5428 where Select.columns() has redefined the set of columns/entities the 

5429 statement will be SELECTing from. This object represents 

5430 the entities from the SELECT before that transformation was applied, 

5431 so that transformations that were made in terms of the SELECT at that 

5432 time, such as join() as well as options(), can access the correct context. 

5433 

5434 In previous SQLAlchemy versions, this wasn't needed because these 

5435 constructs calculated everything up front, like when you called join() 

5436 or options(), it did everything to figure out how that would translate 

5437 into specific SQL constructs that would be ready to send directly to the 

5438 SQL compiler when needed. But as of 

5439 1.4, all of that stuff is done in the compilation phase, during the 

5440 "compile state" portion of the process, so that the work can all be 

5441 cached. So it needs to be able to resolve joins/options2 based on what 

5442 the list of entities was when those methods were called. 

5443 

5444 

5445 """ 

5446 

5447 __visit_name__ = "memoized_select_entities" 

5448 

5449 _traverse_internals: _TraverseInternalsType = [ 

5450 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5451 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5452 ("_with_options", InternalTraversal.dp_executable_options), 

5453 ] 

5454 

5455 _is_clone_of: Optional[ClauseElement] 

5456 _raw_columns: List[_ColumnsClauseElement] 

5457 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5458 _with_options: Tuple[ExecutableOption, ...] 

5459 

5460 _annotations = util.EMPTY_DICT 

5461 

5462 def _clone(self, **kw: Any) -> Self: 

5463 c = self.__class__.__new__(self.__class__) 

5464 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5465 

5466 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5467 return c 

5468 

5469 @classmethod 

5470 def _generate_for_statement( 

5471 cls, select_stmt: Select[Unpack[TupleAny]] 

5472 ) -> None: 

5473 if select_stmt._setup_joins or select_stmt._with_options: 

5474 self = _MemoizedSelectEntities() 

5475 self._raw_columns = select_stmt._raw_columns 

5476 self._setup_joins = select_stmt._setup_joins 

5477 self._with_options = select_stmt._with_options 

5478 

5479 select_stmt._memoized_select_entities += (self,) 

5480 select_stmt._raw_columns = [] 

5481 select_stmt._setup_joins = select_stmt._with_options = () 

5482 

5483 

5484class Select( 

5485 HasPrefixes, 

5486 HasSuffixes, 

5487 HasHints, 

5488 HasCompileState, 

5489 HasSyntaxExtensions[ 

5490 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5491 ], 

5492 _SelectFromElements, 

5493 GenerativeSelect, 

5494 TypedReturnsRows[Unpack[_Ts]], 

5495): 

5496 """Represents a ``SELECT`` statement. 

5497 

5498 The :class:`_sql.Select` object is normally constructed using the 

5499 :func:`_sql.select` function. See that function for details. 

5500 

5501 Available extension points: 

5502 

5503 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5504 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5505 keyword (if any) and the list of columns. 

5506 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5507 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5508 

5509 .. seealso:: 

5510 

5511 :func:`_sql.select` 

5512 

5513 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5514 

5515 """ 

5516 

5517 __visit_name__ = "select" 

5518 

5519 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5520 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5521 

5522 _raw_columns: List[_ColumnsClauseElement] 

5523 

5524 _distinct: bool = False 

5525 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5526 _correlate: Tuple[FromClause, ...] = () 

5527 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5528 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5529 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5530 _from_obj: Tuple[FromClause, ...] = () 

5531 

5532 _position_map = util.immutabledict( 

5533 { 

5534 "post_select": "_post_select_clause", 

5535 "pre_columns": "_pre_columns_clause", 

5536 "post_criteria": "_post_criteria_clause", 

5537 "post_body": "_post_body_clause", 

5538 } 

5539 ) 

5540 

5541 _post_select_clause: Optional[ClauseElement] = None 

5542 """extension point for a ClauseElement that will be compiled directly 

5543 after the SELECT keyword. 

5544 

5545 .. versionadded:: 2.1 

5546 

5547 """ 

5548 

5549 _pre_columns_clause: Optional[ClauseElement] = None 

5550 """extension point for a ClauseElement that will be compiled directly 

5551 before the "columns" clause; after DISTINCT (if present). 

5552 

5553 .. versionadded:: 2.1 

5554 

5555 """ 

5556 

5557 _post_criteria_clause: Optional[ClauseElement] = None 

5558 """extension point for a ClauseElement that will be compiled directly 

5559 after "criteria", following the HAVING clause but before ORDER BY. 

5560 

5561 .. versionadded:: 2.1 

5562 

5563 """ 

5564 

5565 _post_body_clause: Optional[ClauseElement] = None 

5566 """extension point for a ClauseElement that will be compiled directly 

5567 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5568 of the SELECT. 

5569 

5570 .. versionadded:: 2.1 

5571 

5572 """ 

5573 

5574 _auto_correlate = True 

5575 _is_select_statement = True 

5576 _compile_options: CacheableOptions = ( 

5577 SelectState.default_select_compile_options 

5578 ) 

5579 

5580 _traverse_internals: _TraverseInternalsType = ( 

5581 [ 

5582 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5583 ( 

5584 "_memoized_select_entities", 

5585 InternalTraversal.dp_memoized_select_entities, 

5586 ), 

5587 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5588 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5589 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5590 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5591 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5592 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5593 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5594 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5595 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5596 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5597 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5598 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5599 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5600 ("_distinct", InternalTraversal.dp_boolean), 

5601 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5602 ("_label_style", InternalTraversal.dp_plain_obj), 

5603 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5604 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5605 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5606 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5607 ] 

5608 + HasCTE._has_ctes_traverse_internals 

5609 + HasPrefixes._has_prefixes_traverse_internals 

5610 + HasSuffixes._has_suffixes_traverse_internals 

5611 + HasHints._has_hints_traverse_internals 

5612 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5613 + ExecutableStatement._executable_traverse_internals 

5614 + DialectKWArgs._dialect_kwargs_traverse_internals 

5615 ) 

5616 

5617 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5618 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5619 ] 

5620 

5621 _compile_state_factory: Type[SelectState] 

5622 

5623 @classmethod 

5624 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5625 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5626 

5627 Used internally to build up :class:`.Select` constructs with 

5628 pre-established state. 

5629 

5630 """ 

5631 

5632 stmt = Select.__new__(Select) 

5633 stmt.__dict__.update(kw) 

5634 return stmt 

5635 

5636 def __init__( 

5637 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5638 ): 

5639 r"""Construct a new :class:`_expression.Select`. 

5640 

5641 The public constructor for :class:`_expression.Select` is the 

5642 :func:`_sql.select` function. 

5643 

5644 """ 

5645 self._raw_columns = [ 

5646 coercions.expect( 

5647 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5648 ) 

5649 for ent in entities 

5650 ] 

5651 GenerativeSelect.__init__(self) 

5652 

5653 def _apply_syntax_extension_to_self( 

5654 self, extension: SyntaxExtension 

5655 ) -> None: 

5656 extension.apply_to_select(self) 

5657 

5658 def _scalar_type(self) -> TypeEngine[Any]: 

5659 if not self._raw_columns: 

5660 return NULLTYPE 

5661 elem = self._raw_columns[0] 

5662 cols = list(elem._select_iterable) 

5663 return cols[0].type 

5664 

5665 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5666 """A synonym for the :meth:`_sql.Select.where` method.""" 

5667 

5668 return self.where(*criteria) 

5669 

5670 if TYPE_CHECKING: 

5671 

5672 @overload 

5673 def scalar_subquery( 

5674 self: Select[_MAYBE_ENTITY], 

5675 ) -> ScalarSelect[Any]: ... 

5676 

5677 @overload 

5678 def scalar_subquery( 

5679 self: Select[_NOT_ENTITY], 

5680 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5681 

5682 @overload 

5683 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5684 

5685 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5686 

5687 def filter_by(self, **kwargs: Any) -> Self: 

5688 r"""Apply the given filtering criterion as a WHERE clause 

5689 to this select, using keyword expressions. 

5690 

5691 E.g.:: 

5692 

5693 stmt = select(User).filter_by(name="some name") 

5694 

5695 Multiple criteria may be specified as comma separated; the effect 

5696 is that they will be joined together using the :func:`.and_` 

5697 function:: 

5698 

5699 stmt = select(User).filter_by(name="some name", id=5) 

5700 

5701 The keyword expressions are extracted by searching across **all 

5702 entities present in the FROM clause** of the statement. If a 

5703 keyword name is present in more than one entity, 

5704 :class:`_exc.AmbiguousColumnError` is raised. In this case, use 

5705 :meth:`_sql.Select.filter` or :meth:`_sql.Select.where` with 

5706 explicit column references:: 

5707 

5708 # both User and Address have an 'id' attribute 

5709 stmt = select(User).join(Address).filter_by(id=5) 

5710 # raises AmbiguousColumnError 

5711 

5712 # use filter() with explicit qualification instead 

5713 stmt = select(User).join(Address).filter(Address.id == 5) 

5714 

5715 .. versionchanged:: 2.1 

5716 

5717 :meth:`_sql.Select.filter_by` now searches across all FROM clause 

5718 entities rather than only searching the last joined entity or first 

5719 FROM entity. This allows the method to locate attributes 

5720 unambiguously across multiple joined tables. The new 

5721 :class:`_exc.AmbiguousColumnError` is raised when an attribute name 

5722 is present in more than one entity. 

5723 

5724 See :ref:`change_8601` for migration notes. 

5725 

5726 .. seealso:: 

5727 

5728 :ref:`tutorial_selecting_data` - in the :ref:`unified_tutorial` 

5729 

5730 :meth:`_sql.Select.filter` - filter on SQL expressions. 

5731 

5732 :meth:`_sql.Select.where` - filter on SQL expressions. 

5733 

5734 """ 

5735 # Get all entities via plugin system 

5736 all_entities = SelectState.get_plugin_class( 

5737 self 

5738 )._get_filter_by_entities(self) 

5739 

5740 clauses = [ 

5741 _entity_namespace_key_search_all(all_entities, key) == value 

5742 for key, value in kwargs.items() 

5743 ] 

5744 return self.filter(*clauses) 

5745 

5746 @property 

5747 def column_descriptions(self) -> Any: 

5748 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5749 referring to the columns which are SELECTed by this statement. 

5750 

5751 This attribute is generally useful when using the ORM, as an 

5752 extended structure which includes information about mapped 

5753 entities is returned. The section :ref:`queryguide_inspection` 

5754 contains more background. 

5755 

5756 For a Core-only statement, the structure returned by this accessor 

5757 is derived from the same objects that are returned by the 

5758 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5759 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5760 which indicate the column expressions to be selected:: 

5761 

5762 >>> stmt = select(user_table) 

5763 >>> stmt.column_descriptions 

5764 [ 

5765 { 

5766 'name': 'id', 

5767 'type': Integer(), 

5768 'expr': Column('id', Integer(), ...)}, 

5769 { 

5770 'name': 'name', 

5771 'type': String(length=30), 

5772 'expr': Column('name', String(length=30), ...)} 

5773 ] 

5774 

5775 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5776 attribute returns a structure for a Core-only set of entities, 

5777 not just ORM-only entities. 

5778 

5779 .. seealso:: 

5780 

5781 :attr:`.UpdateBase.entity_description` - entity information for 

5782 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5783 

5784 :ref:`queryguide_inspection` - ORM background 

5785 

5786 """ 

5787 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5788 return meth(self) 

5789 

5790 def from_statement( 

5791 self, statement: roles.ReturnsRowsRole 

5792 ) -> ExecutableReturnsRows: 

5793 """Apply the columns which this :class:`.Select` would select 

5794 onto another statement. 

5795 

5796 This operation is :term:`plugin-specific` and will raise a not 

5797 supported exception if this :class:`_sql.Select` does not select from 

5798 plugin-enabled entities. 

5799 

5800 

5801 The statement is typically either a :func:`_expression.text` or 

5802 :func:`_expression.select` construct, and should return the set of 

5803 columns appropriate to the entities represented by this 

5804 :class:`.Select`. 

5805 

5806 .. seealso:: 

5807 

5808 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5809 ORM Querying Guide 

5810 

5811 """ 

5812 meth = SelectState.get_plugin_class(self).from_statement 

5813 return meth(self, statement) 

5814 

5815 @_generative 

5816 def join( 

5817 self, 

5818 target: _JoinTargetArgument, 

5819 onclause: Optional[_OnClauseArgument] = None, 

5820 *, 

5821 isouter: bool = False, 

5822 full: bool = False, 

5823 ) -> Self: 

5824 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5825 object's criterion 

5826 and apply generatively, returning the newly resulting 

5827 :class:`_expression.Select`. 

5828 

5829 E.g.:: 

5830 

5831 stmt = select(user_table).join( 

5832 address_table, user_table.c.id == address_table.c.user_id 

5833 ) 

5834 

5835 The above statement generates SQL similar to: 

5836 

5837 .. sourcecode:: sql 

5838 

5839 SELECT user.id, user.name 

5840 FROM user 

5841 JOIN address ON user.id = address.user_id 

5842 

5843 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5844 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5845 source that is within the FROM clause of the existing SELECT, 

5846 and a given target :class:`_sql.FromClause`, and then adds 

5847 this :class:`_sql.Join` to the FROM clause of the newly generated 

5848 SELECT statement. This is completely reworked from the behavior 

5849 in 1.3, which would instead create a subquery of the entire 

5850 :class:`_expression.Select` and then join that subquery to the 

5851 target. 

5852 

5853 This is a **backwards incompatible change** as the previous behavior 

5854 was mostly useless, producing an unnamed subquery rejected by 

5855 most databases in any case. The new behavior is modeled after 

5856 that of the very successful :meth:`_orm.Query.join` method in the 

5857 ORM, in order to support the functionality of :class:`_orm.Query` 

5858 being available by using a :class:`_sql.Select` object with an 

5859 :class:`_orm.Session`. 

5860 

5861 See the notes for this change at :ref:`change_select_join`. 

5862 

5863 

5864 :param target: target table to join towards 

5865 

5866 :param onclause: ON clause of the join. If omitted, an ON clause 

5867 is generated automatically based on the :class:`_schema.ForeignKey` 

5868 linkages between the two tables, if one can be unambiguously 

5869 determined, otherwise an error is raised. 

5870 

5871 :param isouter: if True, generate LEFT OUTER join. Same as 

5872 :meth:`_expression.Select.outerjoin`. 

5873 

5874 :param full: if True, generate FULL OUTER join. 

5875 

5876 .. seealso:: 

5877 

5878 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5879 

5880 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5881 

5882 :meth:`_expression.Select.join_from` 

5883 

5884 :meth:`_expression.Select.outerjoin` 

5885 

5886 """ # noqa: E501 

5887 join_target = coercions.expect( 

5888 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5889 ) 

5890 if onclause is not None: 

5891 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5892 else: 

5893 onclause_element = None 

5894 

5895 self._setup_joins += ( 

5896 ( 

5897 join_target, 

5898 onclause_element, 

5899 None, 

5900 {"isouter": isouter, "full": full}, 

5901 ), 

5902 ) 

5903 return self 

5904 

5905 def outerjoin_from( 

5906 self, 

5907 from_: _FromClauseArgument, 

5908 target: _JoinTargetArgument, 

5909 onclause: Optional[_OnClauseArgument] = None, 

5910 *, 

5911 full: bool = False, 

5912 ) -> Self: 

5913 r"""Create a SQL LEFT OUTER JOIN against this 

5914 :class:`_expression.Select` object's criterion and apply generatively, 

5915 returning the newly resulting :class:`_expression.Select`. 

5916 

5917 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5918 

5919 """ 

5920 return self.join_from( 

5921 from_, target, onclause=onclause, isouter=True, full=full 

5922 ) 

5923 

5924 @_generative 

5925 def join_from( 

5926 self, 

5927 from_: _FromClauseArgument, 

5928 target: _JoinTargetArgument, 

5929 onclause: Optional[_OnClauseArgument] = None, 

5930 *, 

5931 isouter: bool = False, 

5932 full: bool = False, 

5933 ) -> Self: 

5934 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5935 object's criterion 

5936 and apply generatively, returning the newly resulting 

5937 :class:`_expression.Select`. 

5938 

5939 E.g.:: 

5940 

5941 stmt = select(user_table, address_table).join_from( 

5942 user_table, address_table, user_table.c.id == address_table.c.user_id 

5943 ) 

5944 

5945 The above statement generates SQL similar to: 

5946 

5947 .. sourcecode:: sql 

5948 

5949 SELECT user.id, user.name, address.id, address.email, address.user_id 

5950 FROM user JOIN address ON user.id = address.user_id 

5951 

5952 .. versionadded:: 1.4 

5953 

5954 :param from\_: the left side of the join, will be rendered in the 

5955 FROM clause and is roughly equivalent to using the 

5956 :meth:`.Select.select_from` method. 

5957 

5958 :param target: target table to join towards 

5959 

5960 :param onclause: ON clause of the join. 

5961 

5962 :param isouter: if True, generate LEFT OUTER join. Same as 

5963 :meth:`_expression.Select.outerjoin`. 

5964 

5965 :param full: if True, generate FULL OUTER join. 

5966 

5967 .. seealso:: 

5968 

5969 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5970 

5971 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5972 

5973 :meth:`_expression.Select.join` 

5974 

5975 """ # noqa: E501 

5976 

5977 # note the order of parsing from vs. target is important here, as we 

5978 # are also deriving the source of the plugin (i.e. the subject mapper 

5979 # in an ORM query) which should favor the "from_" over the "target" 

5980 

5981 from_ = coercions.expect( 

5982 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5983 ) 

5984 join_target = coercions.expect( 

5985 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5986 ) 

5987 if onclause is not None: 

5988 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5989 else: 

5990 onclause_element = None 

5991 

5992 self._setup_joins += ( 

5993 ( 

5994 join_target, 

5995 onclause_element, 

5996 from_, 

5997 {"isouter": isouter, "full": full}, 

5998 ), 

5999 ) 

6000 return self 

6001 

6002 def outerjoin( 

6003 self, 

6004 target: _JoinTargetArgument, 

6005 onclause: Optional[_OnClauseArgument] = None, 

6006 *, 

6007 full: bool = False, 

6008 ) -> Self: 

6009 """Create a left outer join. 

6010 

6011 Parameters are the same as that of :meth:`_expression.Select.join`. 

6012 

6013 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

6014 creates a :class:`_sql.Join` object between a 

6015 :class:`_sql.FromClause` source that is within the FROM clause of 

6016 the existing SELECT, and a given target :class:`_sql.FromClause`, 

6017 and then adds this :class:`_sql.Join` to the FROM clause of the 

6018 newly generated SELECT statement. This is completely reworked 

6019 from the behavior in 1.3, which would instead create a subquery of 

6020 the entire 

6021 :class:`_expression.Select` and then join that subquery to the 

6022 target. 

6023 

6024 This is a **backwards incompatible change** as the previous behavior 

6025 was mostly useless, producing an unnamed subquery rejected by 

6026 most databases in any case. The new behavior is modeled after 

6027 that of the very successful :meth:`_orm.Query.join` method in the 

6028 ORM, in order to support the functionality of :class:`_orm.Query` 

6029 being available by using a :class:`_sql.Select` object with an 

6030 :class:`_orm.Session`. 

6031 

6032 See the notes for this change at :ref:`change_select_join`. 

6033 

6034 .. seealso:: 

6035 

6036 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

6037 

6038 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

6039 

6040 :meth:`_expression.Select.join` 

6041 

6042 """ 

6043 return self.join(target, onclause=onclause, isouter=True, full=full) 

6044 

6045 def get_final_froms(self) -> Sequence[FromClause]: 

6046 """Compute the final displayed list of :class:`_expression.FromClause` 

6047 elements. 

6048 

6049 This method will run through the full computation required to 

6050 determine what FROM elements will be displayed in the resulting 

6051 SELECT statement, including shadowing individual tables with 

6052 JOIN objects, as well as full computation for ORM use cases including 

6053 eager loading clauses. 

6054 

6055 For ORM use, this accessor returns the **post compilation** 

6056 list of FROM objects; this collection will include elements such as 

6057 eagerly loaded tables and joins. The objects will **not** be 

6058 ORM enabled and not work as a replacement for the 

6059 :meth:`_sql.Select.select_froms` collection; additionally, the 

6060 method is not well performing for an ORM enabled statement as it 

6061 will incur the full ORM construction process. 

6062 

6063 To retrieve the FROM list that's implied by the "columns" collection 

6064 passed to the :class:`_sql.Select` originally, use the 

6065 :attr:`_sql.Select.columns_clause_froms` accessor. 

6066 

6067 To select from an alternative set of columns while maintaining the 

6068 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

6069 pass the 

6070 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6071 parameter. 

6072 

6073 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

6074 method replaces the previous :attr:`_sql.Select.froms` accessor, 

6075 which is deprecated. 

6076 

6077 .. seealso:: 

6078 

6079 :attr:`_sql.Select.columns_clause_froms` 

6080 

6081 """ 

6082 compiler = self._default_compiler() 

6083 

6084 return self._compile_state_factory(self, compiler)._get_display_froms() 

6085 

6086 @property 

6087 @util.deprecated( 

6088 "1.4.23", 

6089 "The :attr:`_expression.Select.froms` attribute is moved to " 

6090 "the :meth:`_expression.Select.get_final_froms` method.", 

6091 ) 

6092 def froms(self) -> Sequence[FromClause]: 

6093 """Return the displayed list of :class:`_expression.FromClause` 

6094 elements. 

6095 

6096 

6097 """ 

6098 return self.get_final_froms() 

6099 

6100 @property 

6101 def columns_clause_froms(self) -> List[FromClause]: 

6102 """Return the set of :class:`_expression.FromClause` objects implied 

6103 by the columns clause of this SELECT statement. 

6104 

6105 .. versionadded:: 1.4.23 

6106 

6107 .. seealso:: 

6108 

6109 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

6110 statement into account 

6111 

6112 :meth:`_sql.Select.with_only_columns` - makes use of this 

6113 collection to set up a new FROM list 

6114 

6115 """ 

6116 

6117 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

6118 self 

6119 ) 

6120 

6121 @property 

6122 def inner_columns(self) -> _SelectIterable: 

6123 """An iterator of all :class:`_expression.ColumnElement` 

6124 expressions which would 

6125 be rendered into the columns clause of the resulting SELECT statement. 

6126 

6127 This method is legacy as of 1.4 and is superseded by the 

6128 :attr:`_expression.Select.exported_columns` collection. 

6129 

6130 """ 

6131 

6132 return iter(self._all_selected_columns) 

6133 

6134 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

6135 if fromclause is not None and self in fromclause._cloned_set: 

6136 return True 

6137 

6138 for f in self._iterate_from_elements(): 

6139 if f.is_derived_from(fromclause): 

6140 return True 

6141 return False 

6142 

6143 def _copy_internals( 

6144 self, clone: _CloneCallableType = _clone, **kw: Any 

6145 ) -> None: 

6146 # Select() object has been cloned and probably adapted by the 

6147 # given clone function. Apply the cloning function to internal 

6148 # objects 

6149 

6150 # 1. keep a dictionary of the froms we've cloned, and what 

6151 # they've become. This allows us to ensure the same cloned from 

6152 # is used when other items such as columns are "cloned" 

6153 

6154 all_the_froms = set( 

6155 itertools.chain( 

6156 _from_objects(*self._raw_columns), 

6157 _from_objects(*self._where_criteria), 

6158 _from_objects(*[elem[0] for elem in self._setup_joins]), 

6159 ) 

6160 ) 

6161 

6162 # do a clone for the froms we've gathered. what is important here 

6163 # is if any of the things we are selecting from, like tables, 

6164 # were converted into Join objects. if so, these need to be 

6165 # added to _from_obj explicitly, because otherwise they won't be 

6166 # part of the new state, as they don't associate themselves with 

6167 # their columns. 

6168 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

6169 

6170 # 2. copy FROM collections, adding in joins that we've created. 

6171 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

6172 add_froms = ( 

6173 {f for f in new_froms.values() if isinstance(f, Join)} 

6174 .difference(all_the_froms) 

6175 .difference(existing_from_obj) 

6176 ) 

6177 

6178 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

6179 

6180 # 3. clone everything else, making sure we use columns 

6181 # corresponding to the froms we just made. 

6182 def replace( 

6183 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

6184 **kw: Any, 

6185 ) -> Optional[KeyedColumnElement[Any]]: 

6186 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

6187 newelem = new_froms[obj.table].corresponding_column(obj) 

6188 return newelem 

6189 return None 

6190 

6191 kw["replace"] = replace 

6192 

6193 # copy everything else. for table-ish things like correlate, 

6194 # correlate_except, setup_joins, these clone normally. For 

6195 # column-expression oriented things like raw_columns, where_criteria, 

6196 # order by, we get this from the new froms. 

6197 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

6198 

6199 self._reset_memoizations() 

6200 

6201 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

6202 return itertools.chain( 

6203 super().get_children( 

6204 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

6205 **kw, 

6206 ), 

6207 self._iterate_from_elements(), 

6208 ) 

6209 

6210 @_generative 

6211 def add_columns( 

6212 self, *entities: _ColumnsClauseArgument[Any] 

6213 ) -> Select[Unpack[TupleAny]]: 

6214 r"""Return a new :func:`_expression.select` construct with 

6215 the given entities appended to its columns clause. 

6216 

6217 E.g.:: 

6218 

6219 my_select = my_select.add_columns(table.c.new_column) 

6220 

6221 The original expressions in the columns clause remain in place. 

6222 To replace the original expressions with new ones, see the method 

6223 :meth:`_expression.Select.with_only_columns`. 

6224 

6225 :param \*entities: column, table, or other entity expressions to be 

6226 added to the columns clause 

6227 

6228 .. seealso:: 

6229 

6230 :meth:`_expression.Select.with_only_columns` - replaces existing 

6231 expressions rather than appending. 

6232 

6233 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

6234 example 

6235 

6236 """ 

6237 self._reset_memoizations() 

6238 

6239 self._raw_columns = self._raw_columns + [ 

6240 coercions.expect( 

6241 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

6242 ) 

6243 for column in entities 

6244 ] 

6245 return self 

6246 

6247 def _set_entities( 

6248 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

6249 ) -> None: 

6250 self._raw_columns = [ 

6251 coercions.expect( 

6252 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6253 ) 

6254 for ent in util.to_list(entities) 

6255 ] 

6256 

6257 @util.deprecated( 

6258 "1.4", 

6259 "The :meth:`_expression.Select.column` method is deprecated and will " 

6260 "be removed in a future release. Please use " 

6261 ":meth:`_expression.Select.add_columns`", 

6262 ) 

6263 def column( 

6264 self, column: _ColumnsClauseArgument[Any] 

6265 ) -> Select[Unpack[TupleAny]]: 

6266 """Return a new :func:`_expression.select` construct with 

6267 the given column expression added to its columns clause. 

6268 

6269 E.g.:: 

6270 

6271 my_select = my_select.column(table.c.new_column) 

6272 

6273 See the documentation for 

6274 :meth:`_expression.Select.with_only_columns` 

6275 for guidelines on adding /replacing the columns of a 

6276 :class:`_expression.Select` object. 

6277 

6278 """ 

6279 return self.add_columns(column) 

6280 

6281 @util.preload_module("sqlalchemy.sql.util") 

6282 def reduce_columns( 

6283 self, only_synonyms: bool = True 

6284 ) -> Select[Unpack[TupleAny]]: 

6285 """Return a new :func:`_expression.select` construct with redundantly 

6286 named, equivalently-valued columns removed from the columns clause. 

6287 

6288 "Redundant" here means two columns where one refers to the 

6289 other either based on foreign key, or via a simple equality 

6290 comparison in the WHERE clause of the statement. The primary purpose 

6291 of this method is to automatically construct a select statement 

6292 with all uniquely-named columns, without the need to use 

6293 table-qualified labels as 

6294 :meth:`_expression.Select.set_label_style` 

6295 does. 

6296 

6297 When columns are omitted based on foreign key, the referred-to 

6298 column is the one that's kept. When columns are omitted based on 

6299 WHERE equivalence, the first column in the columns clause is the 

6300 one that's kept. 

6301 

6302 :param only_synonyms: when True, limit the removal of columns 

6303 to those which have the same name as the equivalent. Otherwise, 

6304 all columns that are equivalent to another are removed. 

6305 

6306 """ 

6307 woc: Select[Unpack[TupleAny]] 

6308 woc = self.with_only_columns( 

6309 *util.preloaded.sql_util.reduce_columns( 

6310 self._all_selected_columns, 

6311 only_synonyms=only_synonyms, 

6312 *(self._where_criteria + self._from_obj), 

6313 ) 

6314 ) 

6315 return woc 

6316 

6317 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6318 

6319 # code within this block is **programmatically, 

6320 # statically generated** by tools/generate_tuple_map_overloads.py 

6321 

6322 @overload 

6323 def with_only_columns( 

6324 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6325 ) -> Select[_T0]: ... 

6326 

6327 @overload 

6328 def with_only_columns( 

6329 self, 

6330 __ent0: _TCCA[_T0], 

6331 __ent1: _TCCA[_T1], 

6332 /, 

6333 *, 

6334 maintain_column_froms: bool = ..., 

6335 ) -> Select[_T0, _T1]: ... 

6336 

6337 @overload 

6338 def with_only_columns( 

6339 self, 

6340 __ent0: _TCCA[_T0], 

6341 __ent1: _TCCA[_T1], 

6342 __ent2: _TCCA[_T2], 

6343 /, 

6344 *, 

6345 maintain_column_froms: bool = ..., 

6346 ) -> Select[_T0, _T1, _T2]: ... 

6347 

6348 @overload 

6349 def with_only_columns( 

6350 self, 

6351 __ent0: _TCCA[_T0], 

6352 __ent1: _TCCA[_T1], 

6353 __ent2: _TCCA[_T2], 

6354 __ent3: _TCCA[_T3], 

6355 /, 

6356 *, 

6357 maintain_column_froms: bool = ..., 

6358 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6359 

6360 @overload 

6361 def with_only_columns( 

6362 self, 

6363 __ent0: _TCCA[_T0], 

6364 __ent1: _TCCA[_T1], 

6365 __ent2: _TCCA[_T2], 

6366 __ent3: _TCCA[_T3], 

6367 __ent4: _TCCA[_T4], 

6368 /, 

6369 *, 

6370 maintain_column_froms: bool = ..., 

6371 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6372 

6373 @overload 

6374 def with_only_columns( 

6375 self, 

6376 __ent0: _TCCA[_T0], 

6377 __ent1: _TCCA[_T1], 

6378 __ent2: _TCCA[_T2], 

6379 __ent3: _TCCA[_T3], 

6380 __ent4: _TCCA[_T4], 

6381 __ent5: _TCCA[_T5], 

6382 /, 

6383 *, 

6384 maintain_column_froms: bool = ..., 

6385 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6386 

6387 @overload 

6388 def with_only_columns( 

6389 self, 

6390 __ent0: _TCCA[_T0], 

6391 __ent1: _TCCA[_T1], 

6392 __ent2: _TCCA[_T2], 

6393 __ent3: _TCCA[_T3], 

6394 __ent4: _TCCA[_T4], 

6395 __ent5: _TCCA[_T5], 

6396 __ent6: _TCCA[_T6], 

6397 /, 

6398 *, 

6399 maintain_column_froms: bool = ..., 

6400 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6401 

6402 @overload 

6403 def with_only_columns( 

6404 self, 

6405 __ent0: _TCCA[_T0], 

6406 __ent1: _TCCA[_T1], 

6407 __ent2: _TCCA[_T2], 

6408 __ent3: _TCCA[_T3], 

6409 __ent4: _TCCA[_T4], 

6410 __ent5: _TCCA[_T5], 

6411 __ent6: _TCCA[_T6], 

6412 __ent7: _TCCA[_T7], 

6413 /, 

6414 *entities: _ColumnsClauseArgument[Any], 

6415 maintain_column_froms: bool = ..., 

6416 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6417 

6418 # END OVERLOADED FUNCTIONS self.with_only_columns 

6419 

6420 @overload 

6421 def with_only_columns( 

6422 self, 

6423 *entities: _ColumnsClauseArgument[Any], 

6424 maintain_column_froms: bool = False, 

6425 **__kw: Any, 

6426 ) -> Select[Unpack[TupleAny]]: ... 

6427 

6428 @_generative 

6429 def with_only_columns( 

6430 self, 

6431 *entities: _ColumnsClauseArgument[Any], 

6432 maintain_column_froms: bool = False, 

6433 **__kw: Any, 

6434 ) -> Select[Unpack[TupleAny]]: 

6435 r"""Return a new :func:`_expression.select` construct with its columns 

6436 clause replaced with the given entities. 

6437 

6438 By default, this method is exactly equivalent to as if the original 

6439 :func:`_expression.select` had been called with the given entities. 

6440 E.g. a statement:: 

6441 

6442 s = select(table1.c.a, table1.c.b) 

6443 s = s.with_only_columns(table1.c.b) 

6444 

6445 should be exactly equivalent to:: 

6446 

6447 s = select(table1.c.b) 

6448 

6449 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6450 will also dynamically alter the FROM clause of the 

6451 statement if it is not explicitly stated. 

6452 To maintain the existing set of FROMs including those implied by the 

6453 current columns clause, add the 

6454 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6455 parameter:: 

6456 

6457 s = select(table1.c.a, table2.c.b) 

6458 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6459 

6460 The above parameter performs a transfer of the effective FROMs 

6461 in the columns collection to the :meth:`_sql.Select.select_from` 

6462 method, as though the following were invoked:: 

6463 

6464 s = select(table1.c.a, table2.c.b) 

6465 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6466 

6467 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6468 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6469 collection and performs an operation equivalent to the following:: 

6470 

6471 s = select(table1.c.a, table2.c.b) 

6472 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6473 

6474 :param \*entities: column expressions to be used. 

6475 

6476 :param maintain_column_froms: boolean parameter that will ensure the 

6477 FROM list implied from the current columns clause will be transferred 

6478 to the :meth:`_sql.Select.select_from` method first. 

6479 

6480 .. versionadded:: 1.4.23 

6481 

6482 """ # noqa: E501 

6483 

6484 if __kw: 

6485 raise _no_kw() 

6486 

6487 # memoizations should be cleared here as of 

6488 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6489 # is the case for now. 

6490 self._assert_no_memoizations() 

6491 

6492 if maintain_column_froms: 

6493 self.select_from.non_generative( # type: ignore[attr-defined] 

6494 self, *self.columns_clause_froms 

6495 ) 

6496 

6497 # then memoize the FROMs etc. 

6498 _MemoizedSelectEntities._generate_for_statement(self) 

6499 

6500 self._raw_columns = [ 

6501 coercions.expect(roles.ColumnsClauseRole, c) 

6502 for c in coercions._expression_collection_was_a_list( 

6503 "entities", "Select.with_only_columns", entities 

6504 ) 

6505 ] 

6506 return self 

6507 

6508 @property 

6509 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6510 """Return the completed WHERE clause for this 

6511 :class:`_expression.Select` statement. 

6512 

6513 This assembles the current collection of WHERE criteria 

6514 into a single :class:`_expression.BooleanClauseList` construct. 

6515 

6516 

6517 .. versionadded:: 1.4 

6518 

6519 """ 

6520 

6521 return BooleanClauseList._construct_for_whereclause( 

6522 self._where_criteria 

6523 ) 

6524 

6525 _whereclause = whereclause 

6526 

6527 @_generative 

6528 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6529 """Return a new :func:`_expression.select` construct with 

6530 the given expression added to 

6531 its WHERE clause, joined to the existing clause via AND, if any. 

6532 

6533 """ 

6534 

6535 assert isinstance(self._where_criteria, tuple) 

6536 

6537 for criterion in whereclause: 

6538 where_criteria: ColumnElement[Any] = coercions.expect( 

6539 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6540 ) 

6541 self._where_criteria += (where_criteria,) 

6542 return self 

6543 

6544 @_generative 

6545 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6546 """Return a new :func:`_expression.select` construct with 

6547 the given expression added to 

6548 its HAVING clause, joined to the existing clause via AND, if any. 

6549 

6550 """ 

6551 

6552 for criterion in having: 

6553 having_criteria = coercions.expect( 

6554 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6555 ) 

6556 self._having_criteria += (having_criteria,) 

6557 return self 

6558 

6559 @_generative 

6560 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6561 r"""Return a new :func:`_expression.select` construct which 

6562 will apply DISTINCT to the SELECT statement overall. 

6563 

6564 E.g.:: 

6565 

6566 from sqlalchemy import select 

6567 

6568 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6569 

6570 The above would produce an statement resembling: 

6571 

6572 .. sourcecode:: sql 

6573 

6574 SELECT DISTINCT user.id, user.name FROM user 

6575 

6576 The method also historically accepted an ``*expr`` parameter which 

6577 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6578 This is now replaced using the :func:`_postgresql.distinct_on` 

6579 extension:: 

6580 

6581 from sqlalchemy import select 

6582 from sqlalchemy.dialects.postgresql import distinct_on 

6583 

6584 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6585 

6586 Using this parameter on other backends which don't support this 

6587 syntax will raise an error. 

6588 

6589 :param \*expr: optional column expressions. When present, 

6590 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6591 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6592 will be raised on other backends. 

6593 

6594 .. deprecated:: 2.1 Passing expressions to 

6595 :meth:`_sql.Select.distinct` is deprecated, use 

6596 :func:`_postgresql.distinct_on` instead. 

6597 

6598 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6599 and will raise :class:`_exc.CompileError` in a future version. 

6600 

6601 .. seealso:: 

6602 

6603 :func:`_postgresql.distinct_on` 

6604 

6605 :meth:`.ext` 

6606 """ 

6607 self._distinct = True 

6608 if expr: 

6609 warn_deprecated( 

6610 "Passing expression to ``distinct`` to generate a " 

6611 "DISTINCT ON clause is deprecated. Use instead the " 

6612 "``postgresql.distinct_on`` function as an extension.", 

6613 "2.1", 

6614 ) 

6615 self._distinct_on = self._distinct_on + tuple( 

6616 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6617 for e in expr 

6618 ) 

6619 return self 

6620 

6621 @_generative 

6622 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6623 r"""Return a new :func:`_expression.select` construct with the 

6624 given FROM expression(s) 

6625 merged into its list of FROM objects. 

6626 

6627 E.g.:: 

6628 

6629 table1 = table("t1", column("a")) 

6630 table2 = table("t2", column("b")) 

6631 s = select(table1.c.a).select_from( 

6632 table1.join(table2, table1.c.a == table2.c.b) 

6633 ) 

6634 

6635 The "from" list is a unique set on the identity of each element, 

6636 so adding an already present :class:`_schema.Table` 

6637 or other selectable 

6638 will have no effect. Passing a :class:`_expression.Join` that refers 

6639 to an already present :class:`_schema.Table` 

6640 or other selectable will have 

6641 the effect of concealing the presence of that selectable as 

6642 an individual element in the rendered FROM list, instead 

6643 rendering it into a JOIN clause. 

6644 

6645 While the typical purpose of :meth:`_expression.Select.select_from` 

6646 is to 

6647 replace the default, derived FROM clause with a join, it can 

6648 also be called with individual table elements, multiple times 

6649 if desired, in the case that the FROM clause cannot be fully 

6650 derived from the columns clause:: 

6651 

6652 select(func.count("*")).select_from(table1) 

6653 

6654 """ 

6655 

6656 self._from_obj += tuple( 

6657 coercions.expect( 

6658 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6659 ) 

6660 for fromclause in froms 

6661 ) 

6662 return self 

6663 

6664 @_generative 

6665 def correlate( 

6666 self, 

6667 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6668 ) -> Self: 

6669 r"""Return a new :class:`_expression.Select` 

6670 which will correlate the given FROM 

6671 clauses to that of an enclosing :class:`_expression.Select`. 

6672 

6673 Calling this method turns off the :class:`_expression.Select` object's 

6674 default behavior of "auto-correlation". Normally, FROM elements 

6675 which appear in a :class:`_expression.Select` 

6676 that encloses this one via 

6677 its :term:`WHERE clause`, ORDER BY, HAVING or 

6678 :term:`columns clause` will be omitted from this 

6679 :class:`_expression.Select` 

6680 object's :term:`FROM clause`. 

6681 Setting an explicit correlation collection using the 

6682 :meth:`_expression.Select.correlate` 

6683 method provides a fixed list of FROM objects 

6684 that can potentially take place in this process. 

6685 

6686 When :meth:`_expression.Select.correlate` 

6687 is used to apply specific FROM clauses 

6688 for correlation, the FROM elements become candidates for 

6689 correlation regardless of how deeply nested this 

6690 :class:`_expression.Select` 

6691 object is, relative to an enclosing :class:`_expression.Select` 

6692 which refers to 

6693 the same FROM object. This is in contrast to the behavior of 

6694 "auto-correlation" which only correlates to an immediate enclosing 

6695 :class:`_expression.Select`. 

6696 Multi-level correlation ensures that the link 

6697 between enclosed and enclosing :class:`_expression.Select` 

6698 is always via 

6699 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6700 correlation to take place. 

6701 

6702 If ``None`` is passed, the :class:`_expression.Select` 

6703 object will correlate 

6704 none of its FROM entries, and all will render unconditionally 

6705 in the local FROM clause. 

6706 

6707 :param \*fromclauses: one or more :class:`.FromClause` or other 

6708 FROM-compatible construct such as an ORM mapped entity to become part 

6709 of the correlate collection; alternatively pass a single value 

6710 ``None`` to remove all existing correlations. 

6711 

6712 .. seealso:: 

6713 

6714 :meth:`_expression.Select.correlate_except` 

6715 

6716 :ref:`tutorial_scalar_subquery` 

6717 

6718 """ 

6719 

6720 # tests failing when we try to change how these 

6721 # arguments are passed 

6722 

6723 self._auto_correlate = False 

6724 if not fromclauses or fromclauses[0] in {None, False}: 

6725 if len(fromclauses) > 1: 

6726 raise exc.ArgumentError( 

6727 "additional FROM objects not accepted when " 

6728 "passing None/False to correlate()" 

6729 ) 

6730 self._correlate = () 

6731 else: 

6732 self._correlate = self._correlate + tuple( 

6733 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6734 ) 

6735 return self 

6736 

6737 @_generative 

6738 def correlate_except( 

6739 self, 

6740 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6741 ) -> Self: 

6742 r"""Return a new :class:`_expression.Select` 

6743 which will omit the given FROM 

6744 clauses from the auto-correlation process. 

6745 

6746 Calling :meth:`_expression.Select.correlate_except` turns off the 

6747 :class:`_expression.Select` object's default behavior of 

6748 "auto-correlation" for the given FROM elements. An element 

6749 specified here will unconditionally appear in the FROM list, while 

6750 all other FROM elements remain subject to normal auto-correlation 

6751 behaviors. 

6752 

6753 If ``None`` is passed, or no arguments are passed, 

6754 the :class:`_expression.Select` object will correlate all of its 

6755 FROM entries. 

6756 

6757 :param \*fromclauses: a list of one or more 

6758 :class:`_expression.FromClause` 

6759 constructs, or other compatible constructs (i.e. ORM-mapped 

6760 classes) to become part of the correlate-exception collection. 

6761 

6762 .. seealso:: 

6763 

6764 :meth:`_expression.Select.correlate` 

6765 

6766 :ref:`tutorial_scalar_subquery` 

6767 

6768 """ 

6769 

6770 self._auto_correlate = False 

6771 if not fromclauses or fromclauses[0] in {None, False}: 

6772 if len(fromclauses) > 1: 

6773 raise exc.ArgumentError( 

6774 "additional FROM objects not accepted when " 

6775 "passing None/False to correlate_except()" 

6776 ) 

6777 self._correlate_except = () 

6778 else: 

6779 self._correlate_except = (self._correlate_except or ()) + tuple( 

6780 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6781 ) 

6782 

6783 return self 

6784 

6785 @HasMemoized_ro_memoized_attribute 

6786 def selected_columns( 

6787 self, 

6788 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6789 """A :class:`_expression.ColumnCollection` 

6790 representing the columns that 

6791 this SELECT statement or similar construct returns in its result set, 

6792 not including :class:`_sql.TextClause` constructs. 

6793 

6794 This collection differs from the :attr:`_expression.FromClause.columns` 

6795 collection of a :class:`_expression.FromClause` in that the columns 

6796 within this collection cannot be directly nested inside another SELECT 

6797 statement; a subquery must be applied first which provides for the 

6798 necessary parenthesization required by SQL. 

6799 

6800 For a :func:`_expression.select` construct, the collection here is 

6801 exactly what would be rendered inside the "SELECT" statement, and the 

6802 :class:`_expression.ColumnElement` objects are directly present as they 

6803 were given, e.g.:: 

6804 

6805 col1 = column("q", Integer) 

6806 col2 = column("p", Integer) 

6807 stmt = select(col1, col2) 

6808 

6809 Above, ``stmt.selected_columns`` would be a collection that contains 

6810 the ``col1`` and ``col2`` objects directly. For a statement that is 

6811 against a :class:`_schema.Table` or other 

6812 :class:`_expression.FromClause`, the collection will use the 

6813 :class:`_expression.ColumnElement` objects that are in the 

6814 :attr:`_expression.FromClause.c` collection of the from element. 

6815 

6816 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6817 to allow the existing columns to be referenced when adding additional 

6818 criteria, e.g.:: 

6819 

6820 def filter_on_id(my_select, id): 

6821 return my_select.where(my_select.selected_columns["id"] == id) 

6822 

6823 

6824 stmt = select(MyModel) 

6825 

6826 # adds "WHERE id=:param" to the statement 

6827 stmt = filter_on_id(stmt, 42) 

6828 

6829 .. note:: 

6830 

6831 The :attr:`_sql.Select.selected_columns` collection does not 

6832 include expressions established in the columns clause using the 

6833 :func:`_sql.text` construct; these are silently omitted from the 

6834 collection. To use plain textual column expressions inside of a 

6835 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6836 construct. 

6837 

6838 

6839 .. versionadded:: 1.4 

6840 

6841 """ 

6842 

6843 # compare to SelectState._generate_columns_plus_names, which 

6844 # generates the actual names used in the SELECT string. that 

6845 # method is more complex because it also renders columns that are 

6846 # fully ambiguous, e.g. same column more than once. 

6847 conv = cast( 

6848 "Callable[[Any], str]", 

6849 SelectState._column_naming_convention(self._label_style), 

6850 ) 

6851 

6852 cc: WriteableColumnCollection[str, ColumnElement[Any]] = ( 

6853 WriteableColumnCollection( 

6854 [ 

6855 (conv(c), c) 

6856 for c in self._all_selected_columns 

6857 if is_column_element(c) 

6858 ] 

6859 ) 

6860 ) 

6861 return cc.as_readonly() 

6862 

6863 @HasMemoized_ro_memoized_attribute 

6864 def _all_selected_columns(self) -> _SelectIterable: 

6865 meth = SelectState.get_plugin_class(self).all_selected_columns 

6866 return list(meth(self)) 

6867 

6868 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6869 if self._label_style is LABEL_STYLE_NONE: 

6870 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6871 return self 

6872 

6873 def _generate_fromclause_column_proxies( 

6874 self, 

6875 subquery: FromClause, 

6876 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

6877 primary_key: ColumnSet, 

6878 foreign_keys: Set[KeyedColumnElement[Any]], 

6879 *, 

6880 proxy_compound_columns: Optional[ 

6881 Iterable[Sequence[ColumnElement[Any]]] 

6882 ] = None, 

6883 ) -> None: 

6884 """Generate column proxies to place in the exported ``.c`` 

6885 collection of a subquery.""" 

6886 

6887 if proxy_compound_columns: 

6888 extra_col_iterator = proxy_compound_columns 

6889 prox = [ 

6890 c._make_proxy( 

6891 subquery, 

6892 key=proxy_key, 

6893 name=required_label_name, 

6894 name_is_truncatable=True, 

6895 compound_select_cols=extra_cols, 

6896 primary_key=primary_key, 

6897 foreign_keys=foreign_keys, 

6898 ) 

6899 for ( 

6900 ( 

6901 required_label_name, 

6902 proxy_key, 

6903 fallback_label_name, 

6904 c, 

6905 repeated, 

6906 ), 

6907 extra_cols, 

6908 ) in ( 

6909 zip( 

6910 self._generate_columns_plus_names(False), 

6911 extra_col_iterator, 

6912 ) 

6913 ) 

6914 if is_column_element(c) 

6915 ] 

6916 else: 

6917 prox = [ 

6918 c._make_proxy( 

6919 subquery, 

6920 key=proxy_key, 

6921 name=required_label_name, 

6922 name_is_truncatable=True, 

6923 primary_key=primary_key, 

6924 foreign_keys=foreign_keys, 

6925 ) 

6926 for ( 

6927 required_label_name, 

6928 proxy_key, 

6929 fallback_label_name, 

6930 c, 

6931 repeated, 

6932 ) in (self._generate_columns_plus_names(False)) 

6933 if is_column_element(c) 

6934 ] 

6935 

6936 columns._populate_separate_keys(prox) 

6937 

6938 def _needs_parens_for_grouping(self) -> bool: 

6939 return self._has_row_limiting_clause or bool( 

6940 self._order_by_clause.clauses 

6941 ) 

6942 

6943 def self_group( 

6944 self, against: Optional[OperatorType] = None 

6945 ) -> Union[SelectStatementGrouping[Self], Self]: 

6946 """Return a 'grouping' construct as per the 

6947 :class:`_expression.ClauseElement` specification. 

6948 

6949 This produces an element that can be embedded in an expression. Note 

6950 that this method is called automatically as needed when constructing 

6951 expressions and should not require explicit use. 

6952 

6953 """ 

6954 if ( 

6955 isinstance(against, CompoundSelect) 

6956 and not self._needs_parens_for_grouping() 

6957 ): 

6958 return self 

6959 else: 

6960 return SelectStatementGrouping(self) 

6961 

6962 def union( 

6963 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6964 ) -> CompoundSelect[Unpack[_Ts]]: 

6965 r"""Return a SQL ``UNION`` of this select() construct against 

6966 the given selectables provided as positional arguments. 

6967 

6968 :param \*other: one or more elements with which to create a 

6969 UNION. 

6970 

6971 .. versionchanged:: 1.4.28 

6972 

6973 multiple elements are now accepted. 

6974 

6975 :param \**kwargs: keyword arguments are forwarded to the constructor 

6976 for the newly created :class:`_sql.CompoundSelect` object. 

6977 

6978 """ 

6979 return CompoundSelect._create_union(self, *other) 

6980 

6981 def union_all( 

6982 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6983 ) -> CompoundSelect[Unpack[_Ts]]: 

6984 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6985 the given selectables provided as positional arguments. 

6986 

6987 :param \*other: one or more elements with which to create a 

6988 UNION. 

6989 

6990 .. versionchanged:: 1.4.28 

6991 

6992 multiple elements are now accepted. 

6993 

6994 :param \**kwargs: keyword arguments are forwarded to the constructor 

6995 for the newly created :class:`_sql.CompoundSelect` object. 

6996 

6997 """ 

6998 return CompoundSelect._create_union_all(self, *other) 

6999 

7000 def except_( 

7001 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

7002 ) -> CompoundSelect[Unpack[_Ts]]: 

7003 r"""Return a SQL ``EXCEPT`` of this select() construct against 

7004 the given selectable provided as positional arguments. 

7005 

7006 :param \*other: one or more elements with which to create a 

7007 UNION. 

7008 

7009 .. versionchanged:: 1.4.28 

7010 

7011 multiple elements are now accepted. 

7012 

7013 """ 

7014 return CompoundSelect._create_except(self, *other) 

7015 

7016 def except_all( 

7017 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

7018 ) -> CompoundSelect[Unpack[_Ts]]: 

7019 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

7020 the given selectables provided as positional arguments. 

7021 

7022 :param \*other: one or more elements with which to create a 

7023 UNION. 

7024 

7025 .. versionchanged:: 1.4.28 

7026 

7027 multiple elements are now accepted. 

7028 

7029 """ 

7030 return CompoundSelect._create_except_all(self, *other) 

7031 

7032 def intersect( 

7033 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

7034 ) -> CompoundSelect[Unpack[_Ts]]: 

7035 r"""Return a SQL ``INTERSECT`` of this select() construct against 

7036 the given selectables provided as positional arguments. 

7037 

7038 :param \*other: one or more elements with which to create a 

7039 UNION. 

7040 

7041 .. versionchanged:: 1.4.28 

7042 

7043 multiple elements are now accepted. 

7044 

7045 :param \**kwargs: keyword arguments are forwarded to the constructor 

7046 for the newly created :class:`_sql.CompoundSelect` object. 

7047 

7048 """ 

7049 return CompoundSelect._create_intersect(self, *other) 

7050 

7051 def intersect_all( 

7052 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

7053 ) -> CompoundSelect[Unpack[_Ts]]: 

7054 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

7055 against the given selectables provided as positional arguments. 

7056 

7057 :param \*other: one or more elements with which to create a 

7058 UNION. 

7059 

7060 .. versionchanged:: 1.4.28 

7061 

7062 multiple elements are now accepted. 

7063 

7064 :param \**kwargs: keyword arguments are forwarded to the constructor 

7065 for the newly created :class:`_sql.CompoundSelect` object. 

7066 

7067 """ 

7068 return CompoundSelect._create_intersect_all(self, *other) 

7069 

7070 

7071class ScalarSelect( 

7072 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

7073): 

7074 """Represent a scalar subquery. 

7075 

7076 

7077 A :class:`_sql.ScalarSelect` is created by invoking the 

7078 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

7079 then participates in other SQL expressions as a SQL column expression 

7080 within the :class:`_sql.ColumnElement` hierarchy. 

7081 

7082 .. seealso:: 

7083 

7084 :meth:`_sql.SelectBase.scalar_subquery` 

7085 

7086 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7087 

7088 """ 

7089 

7090 _traverse_internals: _TraverseInternalsType = [ 

7091 ("element", InternalTraversal.dp_clauseelement), 

7092 ("type", InternalTraversal.dp_type), 

7093 ] 

7094 

7095 _from_objects: List[FromClause] = [] 

7096 _is_from_container = True 

7097 if not TYPE_CHECKING: 

7098 _is_implicitly_boolean = False 

7099 inherit_cache = True 

7100 

7101 element: SelectBase 

7102 

7103 def __init__(self, element: SelectBase) -> None: 

7104 self.element = element 

7105 self.type = element._scalar_type() 

7106 self._propagate_attrs = element._propagate_attrs 

7107 

7108 def __getattr__(self, attr: str) -> Any: 

7109 return getattr(self.element, attr) 

7110 

7111 def __getstate__(self) -> Dict[str, Any]: 

7112 return {"element": self.element, "type": self.type} 

7113 

7114 def __setstate__(self, state: Dict[str, Any]) -> None: 

7115 self.element = state["element"] 

7116 self.type = state["type"] 

7117 

7118 @property 

7119 def columns(self) -> NoReturn: 

7120 raise exc.InvalidRequestError( 

7121 "Scalar Select expression has no " 

7122 "columns; use this object directly " 

7123 "within a column-level expression." 

7124 ) 

7125 

7126 c = columns 

7127 

7128 @_generative 

7129 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

7130 """Apply a WHERE clause to the SELECT statement referred to 

7131 by this :class:`_expression.ScalarSelect`. 

7132 

7133 """ 

7134 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

7135 crit 

7136 ) 

7137 return self 

7138 

7139 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

7140 return self 

7141 

7142 def _ungroup(self) -> Self: 

7143 return self 

7144 

7145 @_generative 

7146 def correlate( 

7147 self, 

7148 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7149 ) -> Self: 

7150 r"""Return a new :class:`_expression.ScalarSelect` 

7151 which will correlate the given FROM 

7152 clauses to that of an enclosing :class:`_expression.Select`. 

7153 

7154 This method is mirrored from the :meth:`_sql.Select.correlate` method 

7155 of the underlying :class:`_sql.Select`. The method applies the 

7156 :meth:_sql.Select.correlate` method, then returns a new 

7157 :class:`_sql.ScalarSelect` against that statement. 

7158 

7159 .. versionadded:: 1.4 Previously, the 

7160 :meth:`_sql.ScalarSelect.correlate` 

7161 method was only available from :class:`_sql.Select`. 

7162 

7163 :param \*fromclauses: a list of one or more 

7164 :class:`_expression.FromClause` 

7165 constructs, or other compatible constructs (i.e. ORM-mapped 

7166 classes) to become part of the correlate collection. 

7167 

7168 .. seealso:: 

7169 

7170 :meth:`_expression.ScalarSelect.correlate_except` 

7171 

7172 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7173 

7174 

7175 """ 

7176 self.element = cast( 

7177 "Select[Unpack[TupleAny]]", self.element 

7178 ).correlate(*fromclauses) 

7179 return self 

7180 

7181 @_generative 

7182 def correlate_except( 

7183 self, 

7184 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7185 ) -> Self: 

7186 r"""Return a new :class:`_expression.ScalarSelect` 

7187 which will omit the given FROM 

7188 clauses from the auto-correlation process. 

7189 

7190 This method is mirrored from the 

7191 :meth:`_sql.Select.correlate_except` method of the underlying 

7192 :class:`_sql.Select`. The method applies the 

7193 :meth:_sql.Select.correlate_except` method, then returns a new 

7194 :class:`_sql.ScalarSelect` against that statement. 

7195 

7196 .. versionadded:: 1.4 Previously, the 

7197 :meth:`_sql.ScalarSelect.correlate_except` 

7198 method was only available from :class:`_sql.Select`. 

7199 

7200 :param \*fromclauses: a list of one or more 

7201 :class:`_expression.FromClause` 

7202 constructs, or other compatible constructs (i.e. ORM-mapped 

7203 classes) to become part of the correlate-exception collection. 

7204 

7205 .. seealso:: 

7206 

7207 :meth:`_expression.ScalarSelect.correlate` 

7208 

7209 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7210 

7211 

7212 """ 

7213 

7214 self.element = cast( 

7215 "Select[Unpack[TupleAny]]", self.element 

7216 ).correlate_except(*fromclauses) 

7217 return self 

7218 

7219 

7220class Exists(UnaryExpression[bool]): 

7221 """Represent an ``EXISTS`` clause. 

7222 

7223 See :func:`_sql.exists` for a description of usage. 

7224 

7225 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

7226 instance by calling :meth:`_sql.SelectBase.exists`. 

7227 

7228 """ 

7229 

7230 inherit_cache = True 

7231 

7232 def __init__( 

7233 self, 

7234 __argument: Optional[ 

7235 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

7236 ] = None, 

7237 /, 

7238 ): 

7239 s: ScalarSelect[Any] 

7240 

7241 # TODO: this seems like we should be using coercions for this 

7242 if __argument is None: 

7243 s = Select(literal_column("*")).scalar_subquery() 

7244 elif isinstance(__argument, SelectBase): 

7245 s = __argument.scalar_subquery() 

7246 s._propagate_attrs = __argument._propagate_attrs 

7247 elif isinstance(__argument, ScalarSelect): 

7248 s = __argument 

7249 else: 

7250 s = Select(__argument).scalar_subquery() 

7251 

7252 UnaryExpression.__init__( 

7253 self, 

7254 s, 

7255 operator=operators.exists, 

7256 type_=type_api.BOOLEANTYPE, 

7257 ) 

7258 

7259 @util.ro_non_memoized_property 

7260 def _from_objects(self) -> List[FromClause]: 

7261 return [] 

7262 

7263 def _regroup( 

7264 self, 

7265 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7266 ) -> ScalarSelect[Any]: 

7267 

7268 assert isinstance(self.element, ScalarSelect) 

7269 element = self.element.element 

7270 if not isinstance(element, Select): 

7271 raise exc.InvalidRequestError( 

7272 "Can only apply this operation to a plain SELECT construct" 

7273 ) 

7274 new_element = fn(element) 

7275 

7276 return_value = new_element.scalar_subquery() 

7277 return return_value 

7278 

7279 def select(self) -> Select[bool]: 

7280 r"""Return a SELECT of this :class:`_expression.Exists`. 

7281 

7282 e.g.:: 

7283 

7284 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7285 

7286 This will produce a statement resembling: 

7287 

7288 .. sourcecode:: sql 

7289 

7290 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7291 

7292 .. seealso:: 

7293 

7294 :func:`_expression.select` - general purpose 

7295 method which allows for arbitrary column lists. 

7296 

7297 """ # noqa 

7298 

7299 return Select(self) 

7300 

7301 def correlate( 

7302 self, 

7303 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7304 ) -> Self: 

7305 """Apply correlation to the subquery noted by this 

7306 :class:`_sql.Exists`. 

7307 

7308 .. seealso:: 

7309 

7310 :meth:`_sql.ScalarSelect.correlate` 

7311 

7312 """ 

7313 e = self._clone() 

7314 e.element = self._regroup( 

7315 lambda element: element.correlate(*fromclauses) 

7316 ) 

7317 return e 

7318 

7319 def correlate_except( 

7320 self, 

7321 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7322 ) -> Self: 

7323 """Apply correlation to the subquery noted by this 

7324 :class:`_sql.Exists`. 

7325 

7326 .. seealso:: 

7327 

7328 :meth:`_sql.ScalarSelect.correlate_except` 

7329 

7330 """ 

7331 e = self._clone() 

7332 e.element = self._regroup( 

7333 lambda element: element.correlate_except(*fromclauses) 

7334 ) 

7335 return e 

7336 

7337 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7338 """Return a new :class:`_expression.Exists` construct, 

7339 applying the given 

7340 expression to the :meth:`_expression.Select.select_from` 

7341 method of the select 

7342 statement contained. 

7343 

7344 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7345 statement first, including the desired WHERE clause, then use the 

7346 :meth:`_sql.SelectBase.exists` method to produce an 

7347 :class:`_sql.Exists` object at once. 

7348 

7349 """ 

7350 e = self._clone() 

7351 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7352 return e 

7353 

7354 def with_hint( 

7355 self, 

7356 selectable: _FromClauseArgument, 

7357 text: str, 

7358 dialect_name: str = "*", 

7359 ) -> Self: 

7360 r"""Return a new :class:`_expression.Exists` construct, applying 

7361 the given arguments to the 

7362 :meth:`_expression.Select.with_hint` method of the select 

7363 statement contained. 

7364 

7365 The hint is therefore rendered against the SELECT that's enclosed 

7366 by the EXISTS expression. This includes :class:`_expression.Exists` 

7367 objects that were generated by ORM constructs such as 

7368 :meth:`_orm.PropComparator.any` and 

7369 :meth:`_orm.PropComparator.has`:: 

7370 

7371 stmt = select(User).where( 

7372 User.addresses.any().with_hint( 

7373 Address.__table__, "WITH (NOLOCK)", "mssql" 

7374 ) 

7375 ) 

7376 

7377 The above statement renders as: 

7378 

7379 .. sourcecode:: sql 

7380 

7381 SELECT users.id, users.name 

7382 FROM users 

7383 WHERE EXISTS (SELECT 1 

7384 FROM addresses WITH (NOLOCK) 

7385 WHERE users.id = addresses.user_id) 

7386 

7387 .. versionadded:: 2.1 

7388 

7389 .. seealso:: 

7390 

7391 :meth:`_expression.Select.with_hint` 

7392 

7393 :meth:`_expression.Exists.with_statement_hint` 

7394 

7395 """ 

7396 e = self._clone() 

7397 e.element = self._regroup( 

7398 lambda element: element.with_hint(selectable, text, dialect_name) 

7399 ) 

7400 return e 

7401 

7402 def with_statement_hint(self, text: str, dialect_name: str = "*") -> Self: 

7403 r"""Return a new :class:`_expression.Exists` construct, applying 

7404 the given arguments to the 

7405 :meth:`_expression.Select.with_statement_hint` method of the select 

7406 statement contained. 

7407 

7408 The hint is therefore rendered at the trailing end of the SELECT 

7409 that's enclosed by the EXISTS expression, rather than at the end of 

7410 the enclosing statement. As with 

7411 :meth:`_expression.Exists.with_hint`, this includes 

7412 :class:`_expression.Exists` objects that were generated by ORM 

7413 constructs such as :meth:`_orm.PropComparator.any` and 

7414 :meth:`_orm.PropComparator.has`:: 

7415 

7416 has_address = User.addresses.any().with_statement_hint( 

7417 "WITH (NOLOCK)", "mssql" 

7418 ) 

7419 stmt = select(User).where(has_address) 

7420 

7421 The above statement renders as: 

7422 

7423 .. sourcecode:: sql 

7424 

7425 SELECT users.id, users.name 

7426 FROM users 

7427 WHERE EXISTS (SELECT 1 

7428 FROM addresses 

7429 WHERE users.id = addresses.user_id WITH (NOLOCK)) 

7430 

7431 .. versionadded:: 2.1 

7432 

7433 .. seealso:: 

7434 

7435 :meth:`_expression.Select.with_statement_hint` 

7436 

7437 :meth:`_expression.Exists.with_hint` 

7438 

7439 """ 

7440 e = self._clone() 

7441 e.element = self._regroup( 

7442 lambda element: element.with_statement_hint(text, dialect_name) 

7443 ) 

7444 return e 

7445 

7446 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7447 """Return a new :func:`_expression.exists` construct with the 

7448 given expression added to 

7449 its WHERE clause, joined to the existing clause via AND, if any. 

7450 

7451 

7452 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7453 statement first, including the desired WHERE clause, then use the 

7454 :meth:`_sql.SelectBase.exists` method to produce an 

7455 :class:`_sql.Exists` object at once. 

7456 

7457 """ 

7458 e = self._clone() 

7459 e.element = self._regroup(lambda element: element.where(*clause)) 

7460 return e 

7461 

7462 

7463class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7464 """Wrap a :class:`_expression.TextClause` construct within a 

7465 :class:`_expression.SelectBase` 

7466 interface. 

7467 

7468 This allows the :class:`_expression.TextClause` object to gain a 

7469 ``.c`` collection 

7470 and other FROM-like capabilities such as 

7471 :meth:`_expression.FromClause.alias`, 

7472 :meth:`_expression.SelectBase.cte`, etc. 

7473 

7474 The :class:`_expression.TextualSelect` construct is produced via the 

7475 :meth:`_expression.TextClause.columns` 

7476 method - see that method for details. 

7477 

7478 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7479 class was renamed 

7480 from ``TextAsFrom``, to more correctly suit its role as a 

7481 SELECT-oriented object and not a FROM clause. 

7482 

7483 .. seealso:: 

7484 

7485 :func:`_expression.text` 

7486 

7487 :meth:`_expression.TextClause.columns` - primary creation interface. 

7488 

7489 """ 

7490 

7491 __visit_name__ = "textual_select" 

7492 

7493 _label_style = LABEL_STYLE_NONE 

7494 

7495 _traverse_internals: _TraverseInternalsType = ( 

7496 [ 

7497 ("element", InternalTraversal.dp_clauseelement), 

7498 ("column_args", InternalTraversal.dp_clauseelement_list), 

7499 ] 

7500 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7501 + HasCTE._has_ctes_traverse_internals 

7502 + ExecutableStatement._executable_traverse_internals 

7503 ) 

7504 

7505 _is_textual = True 

7506 

7507 is_text = True 

7508 is_select = True 

7509 

7510 def __init__( 

7511 self, 

7512 text: TextClause, 

7513 columns: List[_ColumnExpressionArgument[Any]], 

7514 positional: bool = False, 

7515 ) -> None: 

7516 self._init( 

7517 text, 

7518 # convert for ORM attributes->columns, etc 

7519 [ 

7520 coercions.expect(roles.LabeledColumnExprRole, c) 

7521 for c in columns 

7522 ], 

7523 positional, 

7524 ) 

7525 

7526 def _init( 

7527 self, 

7528 text: AbstractTextClause, 

7529 columns: List[NamedColumn[Any]], 

7530 positional: bool = False, 

7531 ) -> None: 

7532 self.element = text 

7533 self.column_args = columns 

7534 self.positional = positional 

7535 

7536 @HasMemoized_ro_memoized_attribute 

7537 def selected_columns( 

7538 self, 

7539 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

7540 """A :class:`_expression.ColumnCollection` 

7541 representing the columns that 

7542 this SELECT statement or similar construct returns in its result set, 

7543 not including :class:`_sql.TextClause` constructs. 

7544 

7545 This collection differs from the :attr:`_expression.FromClause.columns` 

7546 collection of a :class:`_expression.FromClause` in that the columns 

7547 within this collection cannot be directly nested inside another SELECT 

7548 statement; a subquery must be applied first which provides for the 

7549 necessary parenthesization required by SQL. 

7550 

7551 For a :class:`_expression.TextualSelect` construct, the collection 

7552 contains the :class:`_expression.ColumnElement` objects that were 

7553 passed to the constructor, typically via the 

7554 :meth:`_expression.TextClause.columns` method. 

7555 

7556 

7557 .. versionadded:: 1.4 

7558 

7559 """ 

7560 return WriteableColumnCollection( 

7561 (c.key, c) for c in self.column_args 

7562 ).as_readonly() 

7563 

7564 @util.ro_non_memoized_property 

7565 def _all_selected_columns(self) -> _SelectIterable: 

7566 return self.column_args 

7567 

7568 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7569 return self 

7570 

7571 def _ensure_disambiguated_names(self) -> TextualSelect: 

7572 return self 

7573 

7574 @_generative 

7575 def bindparams( 

7576 self, 

7577 *binds: BindParameter[Any], 

7578 **bind_as_values: Any, 

7579 ) -> Self: 

7580 self.element = self.element.bindparams(*binds, **bind_as_values) 

7581 return self 

7582 

7583 def _generate_fromclause_column_proxies( 

7584 self, 

7585 fromclause: FromClause, 

7586 columns: WriteableColumnCollection[str, KeyedColumnElement[Any]], 

7587 primary_key: ColumnSet, 

7588 foreign_keys: Set[KeyedColumnElement[Any]], 

7589 *, 

7590 proxy_compound_columns: Optional[ 

7591 Iterable[Sequence[ColumnElement[Any]]] 

7592 ] = None, 

7593 ) -> None: 

7594 if TYPE_CHECKING: 

7595 assert isinstance(fromclause, Subquery) 

7596 

7597 if proxy_compound_columns: 

7598 columns._populate_separate_keys( 

7599 c._make_proxy( 

7600 fromclause, 

7601 compound_select_cols=extra_cols, 

7602 primary_key=primary_key, 

7603 foreign_keys=foreign_keys, 

7604 ) 

7605 for c, extra_cols in zip( 

7606 self.column_args, proxy_compound_columns 

7607 ) 

7608 ) 

7609 else: 

7610 columns._populate_separate_keys( 

7611 c._make_proxy( 

7612 fromclause, 

7613 primary_key=primary_key, 

7614 foreign_keys=foreign_keys, 

7615 ) 

7616 for c in self.column_args 

7617 ) 

7618 

7619 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7620 return self.column_args[0].type 

7621 

7622 

7623TextAsFrom = TextualSelect 

7624"""Backwards compatibility with the previous name""" 

7625 

7626 

7627class AnnotatedFromClause(Annotated): 

7628 def _copy_internals( 

7629 self, 

7630 _annotations_traversal: bool = False, 

7631 ind_cols_on_fromclause: bool = False, 

7632 **kw: Any, 

7633 ) -> None: 

7634 super()._copy_internals(**kw) 

7635 

7636 # passed from annotations._shallow_annotate(), _deep_annotate(), etc. 

7637 # the traversals used by annotations for these cases are not currently 

7638 # designed around expecting that inner elements inside of 

7639 # AnnotatedFromClause's element are also deep copied, so skip for these 

7640 # cases. in other cases such as plain visitors.cloned_traverse(), we 

7641 # expect this to happen. see issue #12915 

7642 if not _annotations_traversal: 

7643 ee = self._Annotated__element # type: ignore[attr-defined] 

7644 ee._copy_internals(**kw) 

7645 

7646 if ind_cols_on_fromclause: 

7647 # passed from annotations._deep_annotate(). See that function 

7648 # for notes 

7649 ee = self._Annotated__element # type: ignore[attr-defined] 

7650 self.c = ee.__class__.c.fget(self) # type: ignore[misc] 

7651 

7652 @util.ro_memoized_property 

7653 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

7654 """proxy the .c collection of the underlying FromClause. 

7655 

7656 Originally implemented in 2008 as a simple load of the .c collection 

7657 when the annotated construct was created (see d3621ae961a), in modern 

7658 SQLAlchemy versions this can be expensive for statements constructed 

7659 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7660 it, which works just as well. 

7661 

7662 Two different use cases seem to require the collection either copied 

7663 from the underlying one, or unique to this AnnotatedFromClause. 

7664 

7665 See test_selectable->test_annotated_corresponding_column 

7666 

7667 """ 

7668 ee = self._Annotated__element # type: ignore[attr-defined] 

7669 return ee.c # type: ignore[no-any-return]