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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1827 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 

5092 froms = self.froms 

5093 

5094 if self.statement._correlate: 

5095 to_correlate = self.statement._correlate 

5096 if to_correlate: 

5097 to_remove = _cloned_intersection( 

5098 _cloned_intersection( 

5099 froms, explicit_correlate_froms or () 

5100 ), 

5101 to_correlate, 

5102 ) 

5103 froms = [f for f in froms if f not in to_remove] 

5104 

5105 if self.statement._correlate_except is not None: 

5106 to_remove = _cloned_difference( 

5107 _cloned_intersection(froms, explicit_correlate_froms or ()), 

5108 self.statement._correlate_except, 

5109 ) 

5110 froms = [f for f in froms if f not in to_remove] 

5111 

5112 if ( 

5113 self.statement._auto_correlate 

5114 and implicit_correlate_froms 

5115 and len(froms) > 1 

5116 ): 

5117 to_remove = _cloned_intersection(froms, implicit_correlate_froms) 

5118 froms = [f for f in froms if f not in to_remove] 

5119 

5120 if not len(froms): 

5121 raise exc.InvalidRequestError( 

5122 "Select statement '%r" 

5123 "' returned no FROM clauses " 

5124 "due to auto-correlation; " 

5125 "specify correlate(<tables>) " 

5126 "to control correlation " 

5127 "manually." % self.statement 

5128 ) 

5129 

5130 return froms 

5131 

5132 def _memoized_attr__label_resolve_dict( 

5133 self, 

5134 ) -> Tuple[ 

5135 Dict[str, ColumnElement[Any]], 

5136 Dict[str, ColumnElement[Any]], 

5137 Dict[str, ColumnElement[Any]], 

5138 ]: 

5139 with_cols: Dict[str, ColumnElement[Any]] = { 

5140 c._tq_label or c.key: c 

5141 for c in self.statement._all_selected_columns 

5142 if c._allow_label_resolve 

5143 } 

5144 only_froms: Dict[str, ColumnElement[Any]] = { 

5145 c.key: c # type: ignore[misc] 

5146 for c in _select_iterables(self.froms) 

5147 if c._allow_label_resolve 

5148 } 

5149 only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy() 

5150 for key, value in only_froms.items(): 

5151 with_cols.setdefault(key, value) 

5152 

5153 return with_cols, only_froms, only_cols 

5154 

5155 @classmethod 

5156 def _get_filter_by_entities( 

5157 cls, statement: Select[Unpack[TupleAny]] 

5158 ) -> Collection[ 

5159 Union[FromClause, _JoinTargetProtocol, ColumnElement[Any]] 

5160 ]: 

5161 """Return all entities to search for filter_by() attributes. 

5162 

5163 This includes: 

5164 

5165 * All joined entities from _setup_joins 

5166 * Memoized entities from previous operations (e.g., 

5167 before with_only_columns) 

5168 * Explicit FROM objects from _from_obj 

5169 * Entities inferred from _raw_columns 

5170 

5171 .. versionadded:: 2.1 

5172 

5173 """ 

5174 entities: set[ 

5175 Union[FromClause, _JoinTargetProtocol, ColumnElement[Any]] 

5176 ] 

5177 

5178 entities = set( 

5179 join_element[0] for join_element in statement._setup_joins 

5180 ) 

5181 

5182 for memoized in statement._memoized_select_entities: 

5183 entities.update( 

5184 join_element[0] for join_element in memoized._setup_joins 

5185 ) 

5186 

5187 entities.update(statement._from_obj) 

5188 

5189 for col in statement._raw_columns: 

5190 entities.update(col._from_objects) 

5191 

5192 return entities 

5193 

5194 @classmethod 

5195 def all_selected_columns( 

5196 cls, statement: Select[Unpack[TupleAny]] 

5197 ) -> _SelectIterable: 

5198 return [c for c in _select_iterables(statement._raw_columns)] 

5199 

5200 def _setup_joins( 

5201 self, 

5202 args: Tuple[_SetupJoinsElement, ...], 

5203 raw_columns: List[_ColumnsClauseElement], 

5204 ) -> None: 

5205 for right, onclause, left, flags in args: 

5206 if TYPE_CHECKING: 

5207 if onclause is not None: 

5208 assert isinstance(onclause, ColumnElement) 

5209 

5210 explicit_left = left 

5211 isouter = flags["isouter"] 

5212 full = flags["full"] 

5213 

5214 if left is None: 

5215 ( 

5216 left, 

5217 replace_from_obj_index, 

5218 ) = self._join_determine_implicit_left_side( 

5219 raw_columns, left, right, onclause 

5220 ) 

5221 else: 

5222 replace_from_obj_index = self._join_place_explicit_left_side( 

5223 left 

5224 ) 

5225 

5226 # these assertions can be made here, as if the right/onclause 

5227 # contained ORM elements, the select() statement would have been 

5228 # upgraded to an ORM select, and this method would not be called; 

5229 # orm.context.ORMSelectCompileState._join() would be 

5230 # used instead. 

5231 if TYPE_CHECKING: 

5232 assert isinstance(right, FromClause) 

5233 if onclause is not None: 

5234 assert isinstance(onclause, ColumnElement) 

5235 

5236 if replace_from_obj_index is not None: 

5237 # splice into an existing element in the 

5238 # self._from_obj list 

5239 left_clause = self.from_clauses[replace_from_obj_index] 

5240 

5241 if explicit_left is not None and onclause is None: 

5242 onclause = Join._join_condition(explicit_left, right) 

5243 

5244 self.from_clauses = ( 

5245 self.from_clauses[:replace_from_obj_index] 

5246 + ( 

5247 Join( 

5248 left_clause, 

5249 right, 

5250 onclause, 

5251 isouter=isouter, 

5252 full=full, 

5253 ), 

5254 ) 

5255 + self.from_clauses[replace_from_obj_index + 1 :] 

5256 ) 

5257 else: 

5258 assert left is not None 

5259 self.from_clauses = self.from_clauses + ( 

5260 Join(left, right, onclause, isouter=isouter, full=full), 

5261 ) 

5262 

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

5264 def _join_determine_implicit_left_side( 

5265 self, 

5266 raw_columns: List[_ColumnsClauseElement], 

5267 left: Optional[FromClause], 

5268 right: _JoinTargetElement, 

5269 onclause: Optional[ColumnElement[Any]], 

5270 ) -> Tuple[Optional[FromClause], Optional[int]]: 

5271 """When join conditions don't express the left side explicitly, 

5272 determine if an existing FROM or entity in this query 

5273 can serve as the left hand side. 

5274 

5275 """ 

5276 

5277 sql_util = util.preloaded.sql_util 

5278 

5279 replace_from_obj_index: Optional[int] = None 

5280 

5281 from_clauses = self.from_clauses 

5282 

5283 if from_clauses: 

5284 indexes: List[int] = sql_util.find_left_clause_to_join_from( 

5285 from_clauses, right, onclause 

5286 ) 

5287 

5288 if len(indexes) == 1: 

5289 replace_from_obj_index = indexes[0] 

5290 left = from_clauses[replace_from_obj_index] 

5291 else: 

5292 potential = {} 

5293 statement = self.statement 

5294 

5295 for from_clause in itertools.chain( 

5296 itertools.chain.from_iterable( 

5297 [element._from_objects for element in raw_columns] 

5298 ), 

5299 itertools.chain.from_iterable( 

5300 [ 

5301 element._from_objects 

5302 for element in statement._where_criteria 

5303 ] 

5304 ), 

5305 ): 

5306 potential[from_clause] = () 

5307 

5308 all_clauses = list(potential.keys()) 

5309 indexes = sql_util.find_left_clause_to_join_from( 

5310 all_clauses, right, onclause 

5311 ) 

5312 

5313 if len(indexes) == 1: 

5314 left = all_clauses[indexes[0]] 

5315 

5316 if len(indexes) > 1: 

5317 raise exc.InvalidRequestError( 

5318 "Can't determine which FROM clause to join " 

5319 "from, there are multiple FROMS which can " 

5320 "join to this entity. Please use the .select_from() " 

5321 "method to establish an explicit left side, as well as " 

5322 "providing an explicit ON clause if not present already to " 

5323 "help resolve the ambiguity." 

5324 ) 

5325 elif not indexes: 

5326 raise exc.InvalidRequestError( 

5327 "Don't know how to join to %r. " 

5328 "Please use the .select_from() " 

5329 "method to establish an explicit left side, as well as " 

5330 "providing an explicit ON clause if not present already to " 

5331 "help resolve the ambiguity." % (right,) 

5332 ) 

5333 return left, replace_from_obj_index 

5334 

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

5336 def _join_place_explicit_left_side( 

5337 self, left: FromClause 

5338 ) -> Optional[int]: 

5339 replace_from_obj_index: Optional[int] = None 

5340 

5341 sql_util = util.preloaded.sql_util 

5342 

5343 from_clauses = list(self.statement._iterate_from_elements()) 

5344 

5345 if from_clauses: 

5346 indexes: List[int] = sql_util.find_left_clause_that_matches_given( 

5347 self.from_clauses, left 

5348 ) 

5349 else: 

5350 indexes = [] 

5351 

5352 if len(indexes) > 1: 

5353 raise exc.InvalidRequestError( 

5354 "Can't identify which entity in which to assign the " 

5355 "left side of this join. Please use a more specific " 

5356 "ON clause." 

5357 ) 

5358 

5359 # have an index, means the left side is already present in 

5360 # an existing FROM in the self._from_obj tuple 

5361 if indexes: 

5362 replace_from_obj_index = indexes[0] 

5363 

5364 # no index, means we need to add a new element to the 

5365 # self._from_obj tuple 

5366 

5367 return replace_from_obj_index 

5368 

5369 

5370class _SelectFromElements: 

5371 __slots__ = () 

5372 

5373 _raw_columns: List[_ColumnsClauseElement] 

5374 _where_criteria: Tuple[ColumnElement[Any], ...] 

5375 _from_obj: Tuple[FromClause, ...] 

5376 

5377 def _iterate_from_elements(self) -> Iterator[FromClause]: 

5378 # note this does not include elements 

5379 # in _setup_joins 

5380 

5381 seen = set() 

5382 for element in self._raw_columns: 

5383 for fr in element._from_objects: 

5384 if fr in seen: 

5385 continue 

5386 seen.add(fr) 

5387 yield fr 

5388 for element in self._where_criteria: 

5389 for fr in element._from_objects: 

5390 if fr in seen: 

5391 continue 

5392 seen.add(fr) 

5393 yield fr 

5394 for element in self._from_obj: 

5395 if element in seen: 

5396 continue 

5397 seen.add(element) 

5398 yield element 

5399 

5400 

5401class _MemoizedSelectEntities( 

5402 cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible 

5403): 

5404 """represents partial state from a Select object, for the case 

5405 where Select.columns() has redefined the set of columns/entities the 

5406 statement will be SELECTing from. This object represents 

5407 the entities from the SELECT before that transformation was applied, 

5408 so that transformations that were made in terms of the SELECT at that 

5409 time, such as join() as well as options(), can access the correct context. 

5410 

5411 In previous SQLAlchemy versions, this wasn't needed because these 

5412 constructs calculated everything up front, like when you called join() 

5413 or options(), it did everything to figure out how that would translate 

5414 into specific SQL constructs that would be ready to send directly to the 

5415 SQL compiler when needed. But as of 

5416 1.4, all of that stuff is done in the compilation phase, during the 

5417 "compile state" portion of the process, so that the work can all be 

5418 cached. So it needs to be able to resolve joins/options2 based on what 

5419 the list of entities was when those methods were called. 

5420 

5421 

5422 """ 

5423 

5424 __visit_name__ = "memoized_select_entities" 

5425 

5426 _traverse_internals: _TraverseInternalsType = [ 

5427 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5428 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5429 ("_with_options", InternalTraversal.dp_executable_options), 

5430 ] 

5431 

5432 _is_clone_of: Optional[ClauseElement] 

5433 _raw_columns: List[_ColumnsClauseElement] 

5434 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5435 _with_options: Tuple[ExecutableOption, ...] 

5436 

5437 _annotations = util.EMPTY_DICT 

5438 

5439 def _clone(self, **kw: Any) -> Self: 

5440 c = self.__class__.__new__(self.__class__) 

5441 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5442 

5443 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5444 return c 

5445 

5446 @classmethod 

5447 def _generate_for_statement( 

5448 cls, select_stmt: Select[Unpack[TupleAny]] 

5449 ) -> None: 

5450 if select_stmt._setup_joins or select_stmt._with_options: 

5451 self = _MemoizedSelectEntities() 

5452 self._raw_columns = select_stmt._raw_columns 

5453 self._setup_joins = select_stmt._setup_joins 

5454 self._with_options = select_stmt._with_options 

5455 

5456 select_stmt._memoized_select_entities += (self,) 

5457 select_stmt._raw_columns = [] 

5458 select_stmt._setup_joins = select_stmt._with_options = () 

5459 

5460 

5461class Select( 

5462 HasPrefixes, 

5463 HasSuffixes, 

5464 HasHints, 

5465 HasCompileState, 

5466 HasSyntaxExtensions[ 

5467 Literal["post_select", "pre_columns", "post_criteria", "post_body"] 

5468 ], 

5469 _SelectFromElements, 

5470 GenerativeSelect, 

5471 TypedReturnsRows[Unpack[_Ts]], 

5472): 

5473 """Represents a ``SELECT`` statement. 

5474 

5475 The :class:`_sql.Select` object is normally constructed using the 

5476 :func:`_sql.select` function. See that function for details. 

5477 

5478 Available extension points: 

5479 

5480 * ``post_select``: applies additional logic after the ``SELECT`` keyword. 

5481 * ``pre_columns``: applies additional logic between the ``DISTINCT`` 

5482 keyword (if any) and the list of columns. 

5483 * ``post_criteria``: applies additional logic after the ``HAVING`` clause. 

5484 * ``post_body``: applies additional logic after the ``FOR UPDATE`` clause. 

5485 

5486 .. seealso:: 

5487 

5488 :func:`_sql.select` 

5489 

5490 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5491 

5492 """ 

5493 

5494 __visit_name__ = "select" 

5495 

5496 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5497 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5498 

5499 _raw_columns: List[_ColumnsClauseElement] 

5500 

5501 _distinct: bool = False 

5502 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5503 _correlate: Tuple[FromClause, ...] = () 

5504 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5505 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5506 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5507 _from_obj: Tuple[FromClause, ...] = () 

5508 

5509 _position_map = util.immutabledict( 

5510 { 

5511 "post_select": "_post_select_clause", 

5512 "pre_columns": "_pre_columns_clause", 

5513 "post_criteria": "_post_criteria_clause", 

5514 "post_body": "_post_body_clause", 

5515 } 

5516 ) 

5517 

5518 _post_select_clause: Optional[ClauseElement] = None 

5519 """extension point for a ClauseElement that will be compiled directly 

5520 after the SELECT keyword. 

5521 

5522 .. versionadded:: 2.1 

5523 

5524 """ 

5525 

5526 _pre_columns_clause: Optional[ClauseElement] = None 

5527 """extension point for a ClauseElement that will be compiled directly 

5528 before the "columns" clause; after DISTINCT (if present). 

5529 

5530 .. versionadded:: 2.1 

5531 

5532 """ 

5533 

5534 _post_criteria_clause: Optional[ClauseElement] = None 

5535 """extension point for a ClauseElement that will be compiled directly 

5536 after "criteria", following the HAVING clause but before ORDER BY. 

5537 

5538 .. versionadded:: 2.1 

5539 

5540 """ 

5541 

5542 _post_body_clause: Optional[ClauseElement] = None 

5543 """extension point for a ClauseElement that will be compiled directly 

5544 after the "body", following the ORDER BY, LIMIT, and FOR UPDATE sections 

5545 of the SELECT. 

5546 

5547 .. versionadded:: 2.1 

5548 

5549 """ 

5550 

5551 _auto_correlate = True 

5552 _is_select_statement = True 

5553 _compile_options: CacheableOptions = ( 

5554 SelectState.default_select_compile_options 

5555 ) 

5556 

5557 _traverse_internals: _TraverseInternalsType = ( 

5558 [ 

5559 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5560 ( 

5561 "_memoized_select_entities", 

5562 InternalTraversal.dp_memoized_select_entities, 

5563 ), 

5564 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5565 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5566 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5567 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5568 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5569 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5570 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5571 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5572 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5573 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5574 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5575 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5576 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5577 ("_distinct", InternalTraversal.dp_boolean), 

5578 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5579 ("_label_style", InternalTraversal.dp_plain_obj), 

5580 ("_post_select_clause", InternalTraversal.dp_clauseelement), 

5581 ("_pre_columns_clause", InternalTraversal.dp_clauseelement), 

5582 ("_post_criteria_clause", InternalTraversal.dp_clauseelement), 

5583 ("_post_body_clause", InternalTraversal.dp_clauseelement), 

5584 ] 

5585 + HasCTE._has_ctes_traverse_internals 

5586 + HasPrefixes._has_prefixes_traverse_internals 

5587 + HasSuffixes._has_suffixes_traverse_internals 

5588 + HasHints._has_hints_traverse_internals 

5589 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5590 + ExecutableStatement._executable_traverse_internals 

5591 + DialectKWArgs._dialect_kwargs_traverse_internals 

5592 ) 

5593 

5594 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5595 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5596 ] 

5597 

5598 _compile_state_factory: Type[SelectState] 

5599 

5600 @classmethod 

5601 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5602 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5603 

5604 Used internally to build up :class:`.Select` constructs with 

5605 pre-established state. 

5606 

5607 """ 

5608 

5609 stmt = Select.__new__(Select) 

5610 stmt.__dict__.update(kw) 

5611 return stmt 

5612 

5613 def __init__( 

5614 self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any 

5615 ): 

5616 r"""Construct a new :class:`_expression.Select`. 

5617 

5618 The public constructor for :class:`_expression.Select` is the 

5619 :func:`_sql.select` function. 

5620 

5621 """ 

5622 self._raw_columns = [ 

5623 coercions.expect( 

5624 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5625 ) 

5626 for ent in entities 

5627 ] 

5628 GenerativeSelect.__init__(self) 

5629 

5630 def _apply_syntax_extension_to_self( 

5631 self, extension: SyntaxExtension 

5632 ) -> None: 

5633 extension.apply_to_select(self) 

5634 

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

5636 if not self._raw_columns: 

5637 return NULLTYPE 

5638 elem = self._raw_columns[0] 

5639 cols = list(elem._select_iterable) 

5640 return cols[0].type 

5641 

5642 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5643 """A synonym for the :meth:`_sql.Select.where` method.""" 

5644 

5645 return self.where(*criteria) 

5646 

5647 if TYPE_CHECKING: 

5648 

5649 @overload 

5650 def scalar_subquery( 

5651 self: Select[_MAYBE_ENTITY], 

5652 ) -> ScalarSelect[Any]: ... 

5653 

5654 @overload 

5655 def scalar_subquery( 

5656 self: Select[_NOT_ENTITY], 

5657 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5658 

5659 @overload 

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

5661 

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

5663 

5664 def filter_by(self, **kwargs: Any) -> Self: 

5665 r"""Apply the given filtering criterion as a WHERE clause 

5666 to this select, using keyword expressions. 

5667 

5668 E.g.:: 

5669 

5670 stmt = select(User).filter_by(name="some name") 

5671 

5672 Multiple criteria may be specified as comma separated; the effect 

5673 is that they will be joined together using the :func:`.and_` 

5674 function:: 

5675 

5676 stmt = select(User).filter_by(name="some name", id=5) 

5677 

5678 The keyword expressions are extracted by searching across **all 

5679 entities present in the FROM clause** of the statement. If a 

5680 keyword name is present in more than one entity, 

5681 :class:`_exc.AmbiguousColumnError` is raised. In this case, use 

5682 :meth:`_sql.Select.filter` or :meth:`_sql.Select.where` with 

5683 explicit column references:: 

5684 

5685 # both User and Address have an 'id' attribute 

5686 stmt = select(User).join(Address).filter_by(id=5) 

5687 # raises AmbiguousColumnError 

5688 

5689 # use filter() with explicit qualification instead 

5690 stmt = select(User).join(Address).filter(Address.id == 5) 

5691 

5692 .. versionchanged:: 2.1 

5693 

5694 :meth:`_sql.Select.filter_by` now searches across all FROM clause 

5695 entities rather than only searching the last joined entity or first 

5696 FROM entity. This allows the method to locate attributes 

5697 unambiguously across multiple joined tables. The new 

5698 :class:`_exc.AmbiguousColumnError` is raised when an attribute name 

5699 is present in more than one entity. 

5700 

5701 See :ref:`change_8601` for migration notes. 

5702 

5703 .. seealso:: 

5704 

5705 :ref:`tutorial_selecting_data` - in the :ref:`unified_tutorial` 

5706 

5707 :meth:`_sql.Select.filter` - filter on SQL expressions. 

5708 

5709 :meth:`_sql.Select.where` - filter on SQL expressions. 

5710 

5711 """ 

5712 # Get all entities via plugin system 

5713 all_entities = SelectState.get_plugin_class( 

5714 self 

5715 )._get_filter_by_entities(self) 

5716 

5717 clauses = [ 

5718 _entity_namespace_key_search_all(all_entities, key) == value 

5719 for key, value in kwargs.items() 

5720 ] 

5721 return self.filter(*clauses) 

5722 

5723 @property 

5724 def column_descriptions(self) -> Any: 

5725 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5726 referring to the columns which are SELECTed by this statement. 

5727 

5728 This attribute is generally useful when using the ORM, as an 

5729 extended structure which includes information about mapped 

5730 entities is returned. The section :ref:`queryguide_inspection` 

5731 contains more background. 

5732 

5733 For a Core-only statement, the structure returned by this accessor 

5734 is derived from the same objects that are returned by the 

5735 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5736 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5737 which indicate the column expressions to be selected:: 

5738 

5739 >>> stmt = select(user_table) 

5740 >>> stmt.column_descriptions 

5741 [ 

5742 { 

5743 'name': 'id', 

5744 'type': Integer(), 

5745 'expr': Column('id', Integer(), ...)}, 

5746 { 

5747 'name': 'name', 

5748 'type': String(length=30), 

5749 'expr': Column('name', String(length=30), ...)} 

5750 ] 

5751 

5752 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5753 attribute returns a structure for a Core-only set of entities, 

5754 not just ORM-only entities. 

5755 

5756 .. seealso:: 

5757 

5758 :attr:`.UpdateBase.entity_description` - entity information for 

5759 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5760 

5761 :ref:`queryguide_inspection` - ORM background 

5762 

5763 """ 

5764 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5765 return meth(self) 

5766 

5767 def from_statement( 

5768 self, statement: roles.ReturnsRowsRole 

5769 ) -> ExecutableReturnsRows: 

5770 """Apply the columns which this :class:`.Select` would select 

5771 onto another statement. 

5772 

5773 This operation is :term:`plugin-specific` and will raise a not 

5774 supported exception if this :class:`_sql.Select` does not select from 

5775 plugin-enabled entities. 

5776 

5777 

5778 The statement is typically either a :func:`_expression.text` or 

5779 :func:`_expression.select` construct, and should return the set of 

5780 columns appropriate to the entities represented by this 

5781 :class:`.Select`. 

5782 

5783 .. seealso:: 

5784 

5785 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5786 ORM Querying Guide 

5787 

5788 """ 

5789 meth = SelectState.get_plugin_class(self).from_statement 

5790 return meth(self, statement) 

5791 

5792 @_generative 

5793 def join( 

5794 self, 

5795 target: _JoinTargetArgument, 

5796 onclause: Optional[_OnClauseArgument] = None, 

5797 *, 

5798 isouter: bool = False, 

5799 full: bool = False, 

5800 ) -> Self: 

5801 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5802 object's criterion 

5803 and apply generatively, returning the newly resulting 

5804 :class:`_expression.Select`. 

5805 

5806 E.g.:: 

5807 

5808 stmt = select(user_table).join( 

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

5810 ) 

5811 

5812 The above statement generates SQL similar to: 

5813 

5814 .. sourcecode:: sql 

5815 

5816 SELECT user.id, user.name 

5817 FROM user 

5818 JOIN address ON user.id = address.user_id 

5819 

5820 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5821 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5822 source that is within the FROM clause of the existing SELECT, 

5823 and a given target :class:`_sql.FromClause`, and then adds 

5824 this :class:`_sql.Join` to the FROM clause of the newly generated 

5825 SELECT statement. This is completely reworked from the behavior 

5826 in 1.3, which would instead create a subquery of the entire 

5827 :class:`_expression.Select` and then join that subquery to the 

5828 target. 

5829 

5830 This is a **backwards incompatible change** as the previous behavior 

5831 was mostly useless, producing an unnamed subquery rejected by 

5832 most databases in any case. The new behavior is modeled after 

5833 that of the very successful :meth:`_orm.Query.join` method in the 

5834 ORM, in order to support the functionality of :class:`_orm.Query` 

5835 being available by using a :class:`_sql.Select` object with an 

5836 :class:`_orm.Session`. 

5837 

5838 See the notes for this change at :ref:`change_select_join`. 

5839 

5840 

5841 :param target: target table to join towards 

5842 

5843 :param onclause: ON clause of the join. If omitted, an ON clause 

5844 is generated automatically based on the :class:`_schema.ForeignKey` 

5845 linkages between the two tables, if one can be unambiguously 

5846 determined, otherwise an error is raised. 

5847 

5848 :param isouter: if True, generate LEFT OUTER join. Same as 

5849 :meth:`_expression.Select.outerjoin`. 

5850 

5851 :param full: if True, generate FULL OUTER join. 

5852 

5853 .. seealso:: 

5854 

5855 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5856 

5857 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5858 

5859 :meth:`_expression.Select.join_from` 

5860 

5861 :meth:`_expression.Select.outerjoin` 

5862 

5863 """ # noqa: E501 

5864 join_target = coercions.expect( 

5865 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5866 ) 

5867 if onclause is not None: 

5868 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5869 else: 

5870 onclause_element = None 

5871 

5872 self._setup_joins += ( 

5873 ( 

5874 join_target, 

5875 onclause_element, 

5876 None, 

5877 {"isouter": isouter, "full": full}, 

5878 ), 

5879 ) 

5880 return self 

5881 

5882 def outerjoin_from( 

5883 self, 

5884 from_: _FromClauseArgument, 

5885 target: _JoinTargetArgument, 

5886 onclause: Optional[_OnClauseArgument] = None, 

5887 *, 

5888 full: bool = False, 

5889 ) -> Self: 

5890 r"""Create a SQL LEFT OUTER JOIN against this 

5891 :class:`_expression.Select` object's criterion and apply generatively, 

5892 returning the newly resulting :class:`_expression.Select`. 

5893 

5894 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5895 

5896 """ 

5897 return self.join_from( 

5898 from_, target, onclause=onclause, isouter=True, full=full 

5899 ) 

5900 

5901 @_generative 

5902 def join_from( 

5903 self, 

5904 from_: _FromClauseArgument, 

5905 target: _JoinTargetArgument, 

5906 onclause: Optional[_OnClauseArgument] = None, 

5907 *, 

5908 isouter: bool = False, 

5909 full: bool = False, 

5910 ) -> Self: 

5911 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5912 object's criterion 

5913 and apply generatively, returning the newly resulting 

5914 :class:`_expression.Select`. 

5915 

5916 E.g.:: 

5917 

5918 stmt = select(user_table, address_table).join_from( 

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

5920 ) 

5921 

5922 The above statement generates SQL similar to: 

5923 

5924 .. sourcecode:: sql 

5925 

5926 SELECT user.id, user.name, address.id, address.email, address.user_id 

5927 FROM user JOIN address ON user.id = address.user_id 

5928 

5929 .. versionadded:: 1.4 

5930 

5931 :param from\_: the left side of the join, will be rendered in the 

5932 FROM clause and is roughly equivalent to using the 

5933 :meth:`.Select.select_from` method. 

5934 

5935 :param target: target table to join towards 

5936 

5937 :param onclause: ON clause of the join. 

5938 

5939 :param isouter: if True, generate LEFT OUTER join. Same as 

5940 :meth:`_expression.Select.outerjoin`. 

5941 

5942 :param full: if True, generate FULL OUTER join. 

5943 

5944 .. seealso:: 

5945 

5946 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5947 

5948 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5949 

5950 :meth:`_expression.Select.join` 

5951 

5952 """ # noqa: E501 

5953 

5954 # note the order of parsing from vs. target is important here, as we 

5955 # are also deriving the source of the plugin (i.e. the subject mapper 

5956 # in an ORM query) which should favor the "from_" over the "target" 

5957 

5958 from_ = coercions.expect( 

5959 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5960 ) 

5961 join_target = coercions.expect( 

5962 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5963 ) 

5964 if onclause is not None: 

5965 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5966 else: 

5967 onclause_element = None 

5968 

5969 self._setup_joins += ( 

5970 ( 

5971 join_target, 

5972 onclause_element, 

5973 from_, 

5974 {"isouter": isouter, "full": full}, 

5975 ), 

5976 ) 

5977 return self 

5978 

5979 def outerjoin( 

5980 self, 

5981 target: _JoinTargetArgument, 

5982 onclause: Optional[_OnClauseArgument] = None, 

5983 *, 

5984 full: bool = False, 

5985 ) -> Self: 

5986 """Create a left outer join. 

5987 

5988 Parameters are the same as that of :meth:`_expression.Select.join`. 

5989 

5990 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5991 creates a :class:`_sql.Join` object between a 

5992 :class:`_sql.FromClause` source that is within the FROM clause of 

5993 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5994 and then adds this :class:`_sql.Join` to the FROM clause of the 

5995 newly generated SELECT statement. This is completely reworked 

5996 from the behavior in 1.3, which would instead create a subquery of 

5997 the entire 

5998 :class:`_expression.Select` and then join that subquery to the 

5999 target. 

6000 

6001 This is a **backwards incompatible change** as the previous behavior 

6002 was mostly useless, producing an unnamed subquery rejected by 

6003 most databases in any case. The new behavior is modeled after 

6004 that of the very successful :meth:`_orm.Query.join` method in the 

6005 ORM, in order to support the functionality of :class:`_orm.Query` 

6006 being available by using a :class:`_sql.Select` object with an 

6007 :class:`_orm.Session`. 

6008 

6009 See the notes for this change at :ref:`change_select_join`. 

6010 

6011 .. seealso:: 

6012 

6013 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

6014 

6015 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

6016 

6017 :meth:`_expression.Select.join` 

6018 

6019 """ 

6020 return self.join(target, onclause=onclause, isouter=True, full=full) 

6021 

6022 def get_final_froms(self) -> Sequence[FromClause]: 

6023 """Compute the final displayed list of :class:`_expression.FromClause` 

6024 elements. 

6025 

6026 This method will run through the full computation required to 

6027 determine what FROM elements will be displayed in the resulting 

6028 SELECT statement, including shadowing individual tables with 

6029 JOIN objects, as well as full computation for ORM use cases including 

6030 eager loading clauses. 

6031 

6032 For ORM use, this accessor returns the **post compilation** 

6033 list of FROM objects; this collection will include elements such as 

6034 eagerly loaded tables and joins. The objects will **not** be 

6035 ORM enabled and not work as a replacement for the 

6036 :meth:`_sql.Select.select_froms` collection; additionally, the 

6037 method is not well performing for an ORM enabled statement as it 

6038 will incur the full ORM construction process. 

6039 

6040 To retrieve the FROM list that's implied by the "columns" collection 

6041 passed to the :class:`_sql.Select` originally, use the 

6042 :attr:`_sql.Select.columns_clause_froms` accessor. 

6043 

6044 To select from an alternative set of columns while maintaining the 

6045 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

6046 pass the 

6047 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6048 parameter. 

6049 

6050 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

6051 method replaces the previous :attr:`_sql.Select.froms` accessor, 

6052 which is deprecated. 

6053 

6054 .. seealso:: 

6055 

6056 :attr:`_sql.Select.columns_clause_froms` 

6057 

6058 """ 

6059 compiler = self._default_compiler() 

6060 

6061 return self._compile_state_factory(self, compiler)._get_display_froms() 

6062 

6063 @property 

6064 @util.deprecated( 

6065 "1.4.23", 

6066 "The :attr:`_expression.Select.froms` attribute is moved to " 

6067 "the :meth:`_expression.Select.get_final_froms` method.", 

6068 ) 

6069 def froms(self) -> Sequence[FromClause]: 

6070 """Return the displayed list of :class:`_expression.FromClause` 

6071 elements. 

6072 

6073 

6074 """ 

6075 return self.get_final_froms() 

6076 

6077 @property 

6078 def columns_clause_froms(self) -> List[FromClause]: 

6079 """Return the set of :class:`_expression.FromClause` objects implied 

6080 by the columns clause of this SELECT statement. 

6081 

6082 .. versionadded:: 1.4.23 

6083 

6084 .. seealso:: 

6085 

6086 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

6087 statement into account 

6088 

6089 :meth:`_sql.Select.with_only_columns` - makes use of this 

6090 collection to set up a new FROM list 

6091 

6092 """ 

6093 

6094 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

6095 self 

6096 ) 

6097 

6098 @property 

6099 def inner_columns(self) -> _SelectIterable: 

6100 """An iterator of all :class:`_expression.ColumnElement` 

6101 expressions which would 

6102 be rendered into the columns clause of the resulting SELECT statement. 

6103 

6104 This method is legacy as of 1.4 and is superseded by the 

6105 :attr:`_expression.Select.exported_columns` collection. 

6106 

6107 """ 

6108 

6109 return iter(self._all_selected_columns) 

6110 

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

6112 if fromclause is not None and self in fromclause._cloned_set: 

6113 return True 

6114 

6115 for f in self._iterate_from_elements(): 

6116 if f.is_derived_from(fromclause): 

6117 return True 

6118 return False 

6119 

6120 def _copy_internals( 

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

6122 ) -> None: 

6123 # Select() object has been cloned and probably adapted by the 

6124 # given clone function. Apply the cloning function to internal 

6125 # objects 

6126 

6127 # 1. keep a dictionary of the froms we've cloned, and what 

6128 # they've become. This allows us to ensure the same cloned from 

6129 # is used when other items such as columns are "cloned" 

6130 

6131 all_the_froms = set( 

6132 itertools.chain( 

6133 _from_objects(*self._raw_columns), 

6134 _from_objects(*self._where_criteria), 

6135 _from_objects(*[elem[0] for elem in self._setup_joins]), 

6136 ) 

6137 ) 

6138 

6139 # do a clone for the froms we've gathered. what is important here 

6140 # is if any of the things we are selecting from, like tables, 

6141 # were converted into Join objects. if so, these need to be 

6142 # added to _from_obj explicitly, because otherwise they won't be 

6143 # part of the new state, as they don't associate themselves with 

6144 # their columns. 

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

6146 

6147 # 2. copy FROM collections, adding in joins that we've created. 

6148 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

6149 add_froms = ( 

6150 {f for f in new_froms.values() if isinstance(f, Join)} 

6151 .difference(all_the_froms) 

6152 .difference(existing_from_obj) 

6153 ) 

6154 

6155 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

6156 

6157 # 3. clone everything else, making sure we use columns 

6158 # corresponding to the froms we just made. 

6159 def replace( 

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

6161 **kw: Any, 

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

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

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

6165 return newelem 

6166 return None 

6167 

6168 kw["replace"] = replace 

6169 

6170 # copy everything else. for table-ish things like correlate, 

6171 # correlate_except, setup_joins, these clone normally. For 

6172 # column-expression oriented things like raw_columns, where_criteria, 

6173 # order by, we get this from the new froms. 

6174 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

6175 

6176 self._reset_memoizations() 

6177 

6178 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

6179 return itertools.chain( 

6180 super().get_children( 

6181 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

6182 **kw, 

6183 ), 

6184 self._iterate_from_elements(), 

6185 ) 

6186 

6187 @_generative 

6188 def add_columns( 

6189 self, *entities: _ColumnsClauseArgument[Any] 

6190 ) -> Select[Unpack[TupleAny]]: 

6191 r"""Return a new :func:`_expression.select` construct with 

6192 the given entities appended to its columns clause. 

6193 

6194 E.g.:: 

6195 

6196 my_select = my_select.add_columns(table.c.new_column) 

6197 

6198 The original expressions in the columns clause remain in place. 

6199 To replace the original expressions with new ones, see the method 

6200 :meth:`_expression.Select.with_only_columns`. 

6201 

6202 :param \*entities: column, table, or other entity expressions to be 

6203 added to the columns clause 

6204 

6205 .. seealso:: 

6206 

6207 :meth:`_expression.Select.with_only_columns` - replaces existing 

6208 expressions rather than appending. 

6209 

6210 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

6211 example 

6212 

6213 """ 

6214 self._reset_memoizations() 

6215 

6216 self._raw_columns = self._raw_columns + [ 

6217 coercions.expect( 

6218 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

6219 ) 

6220 for column in entities 

6221 ] 

6222 return self 

6223 

6224 def _set_entities( 

6225 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

6226 ) -> None: 

6227 self._raw_columns = [ 

6228 coercions.expect( 

6229 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

6230 ) 

6231 for ent in util.to_list(entities) 

6232 ] 

6233 

6234 @util.deprecated( 

6235 "1.4", 

6236 "The :meth:`_expression.Select.column` method is deprecated and will " 

6237 "be removed in a future release. Please use " 

6238 ":meth:`_expression.Select.add_columns`", 

6239 ) 

6240 def column( 

6241 self, column: _ColumnsClauseArgument[Any] 

6242 ) -> Select[Unpack[TupleAny]]: 

6243 """Return a new :func:`_expression.select` construct with 

6244 the given column expression added to its columns clause. 

6245 

6246 E.g.:: 

6247 

6248 my_select = my_select.column(table.c.new_column) 

6249 

6250 See the documentation for 

6251 :meth:`_expression.Select.with_only_columns` 

6252 for guidelines on adding /replacing the columns of a 

6253 :class:`_expression.Select` object. 

6254 

6255 """ 

6256 return self.add_columns(column) 

6257 

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

6259 def reduce_columns( 

6260 self, only_synonyms: bool = True 

6261 ) -> Select[Unpack[TupleAny]]: 

6262 """Return a new :func:`_expression.select` construct with redundantly 

6263 named, equivalently-valued columns removed from the columns clause. 

6264 

6265 "Redundant" here means two columns where one refers to the 

6266 other either based on foreign key, or via a simple equality 

6267 comparison in the WHERE clause of the statement. The primary purpose 

6268 of this method is to automatically construct a select statement 

6269 with all uniquely-named columns, without the need to use 

6270 table-qualified labels as 

6271 :meth:`_expression.Select.set_label_style` 

6272 does. 

6273 

6274 When columns are omitted based on foreign key, the referred-to 

6275 column is the one that's kept. When columns are omitted based on 

6276 WHERE equivalence, the first column in the columns clause is the 

6277 one that's kept. 

6278 

6279 :param only_synonyms: when True, limit the removal of columns 

6280 to those which have the same name as the equivalent. Otherwise, 

6281 all columns that are equivalent to another are removed. 

6282 

6283 """ 

6284 woc: Select[Unpack[TupleAny]] 

6285 woc = self.with_only_columns( 

6286 *util.preloaded.sql_util.reduce_columns( 

6287 self._all_selected_columns, 

6288 only_synonyms=only_synonyms, 

6289 *(self._where_criteria + self._from_obj), 

6290 ) 

6291 ) 

6292 return woc 

6293 

6294 # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501 

6295 

6296 # code within this block is **programmatically, 

6297 # statically generated** by tools/generate_tuple_map_overloads.py 

6298 

6299 @overload 

6300 def with_only_columns( 

6301 self, __ent0: _TCCA[_T0], /, *, maintain_column_froms: bool = ... 

6302 ) -> Select[_T0]: ... 

6303 

6304 @overload 

6305 def with_only_columns( 

6306 self, 

6307 __ent0: _TCCA[_T0], 

6308 __ent1: _TCCA[_T1], 

6309 /, 

6310 *, 

6311 maintain_column_froms: bool = ..., 

6312 ) -> Select[_T0, _T1]: ... 

6313 

6314 @overload 

6315 def with_only_columns( 

6316 self, 

6317 __ent0: _TCCA[_T0], 

6318 __ent1: _TCCA[_T1], 

6319 __ent2: _TCCA[_T2], 

6320 /, 

6321 *, 

6322 maintain_column_froms: bool = ..., 

6323 ) -> Select[_T0, _T1, _T2]: ... 

6324 

6325 @overload 

6326 def with_only_columns( 

6327 self, 

6328 __ent0: _TCCA[_T0], 

6329 __ent1: _TCCA[_T1], 

6330 __ent2: _TCCA[_T2], 

6331 __ent3: _TCCA[_T3], 

6332 /, 

6333 *, 

6334 maintain_column_froms: bool = ..., 

6335 ) -> Select[_T0, _T1, _T2, _T3]: ... 

6336 

6337 @overload 

6338 def with_only_columns( 

6339 self, 

6340 __ent0: _TCCA[_T0], 

6341 __ent1: _TCCA[_T1], 

6342 __ent2: _TCCA[_T2], 

6343 __ent3: _TCCA[_T3], 

6344 __ent4: _TCCA[_T4], 

6345 /, 

6346 *, 

6347 maintain_column_froms: bool = ..., 

6348 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

6349 

6350 @overload 

6351 def with_only_columns( 

6352 self, 

6353 __ent0: _TCCA[_T0], 

6354 __ent1: _TCCA[_T1], 

6355 __ent2: _TCCA[_T2], 

6356 __ent3: _TCCA[_T3], 

6357 __ent4: _TCCA[_T4], 

6358 __ent5: _TCCA[_T5], 

6359 /, 

6360 *, 

6361 maintain_column_froms: bool = ..., 

6362 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

6363 

6364 @overload 

6365 def with_only_columns( 

6366 self, 

6367 __ent0: _TCCA[_T0], 

6368 __ent1: _TCCA[_T1], 

6369 __ent2: _TCCA[_T2], 

6370 __ent3: _TCCA[_T3], 

6371 __ent4: _TCCA[_T4], 

6372 __ent5: _TCCA[_T5], 

6373 __ent6: _TCCA[_T6], 

6374 /, 

6375 *, 

6376 maintain_column_froms: bool = ..., 

6377 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

6378 

6379 @overload 

6380 def with_only_columns( 

6381 self, 

6382 __ent0: _TCCA[_T0], 

6383 __ent1: _TCCA[_T1], 

6384 __ent2: _TCCA[_T2], 

6385 __ent3: _TCCA[_T3], 

6386 __ent4: _TCCA[_T4], 

6387 __ent5: _TCCA[_T5], 

6388 __ent6: _TCCA[_T6], 

6389 __ent7: _TCCA[_T7], 

6390 /, 

6391 *entities: _ColumnsClauseArgument[Any], 

6392 maintain_column_froms: bool = ..., 

6393 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]]: ... 

6394 

6395 # END OVERLOADED FUNCTIONS self.with_only_columns 

6396 

6397 @overload 

6398 def with_only_columns( 

6399 self, 

6400 *entities: _ColumnsClauseArgument[Any], 

6401 maintain_column_froms: bool = False, 

6402 **__kw: Any, 

6403 ) -> Select[Unpack[TupleAny]]: ... 

6404 

6405 @_generative 

6406 def with_only_columns( 

6407 self, 

6408 *entities: _ColumnsClauseArgument[Any], 

6409 maintain_column_froms: bool = False, 

6410 **__kw: Any, 

6411 ) -> Select[Unpack[TupleAny]]: 

6412 r"""Return a new :func:`_expression.select` construct with its columns 

6413 clause replaced with the given entities. 

6414 

6415 By default, this method is exactly equivalent to as if the original 

6416 :func:`_expression.select` had been called with the given entities. 

6417 E.g. a statement:: 

6418 

6419 s = select(table1.c.a, table1.c.b) 

6420 s = s.with_only_columns(table1.c.b) 

6421 

6422 should be exactly equivalent to:: 

6423 

6424 s = select(table1.c.b) 

6425 

6426 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

6427 will also dynamically alter the FROM clause of the 

6428 statement if it is not explicitly stated. 

6429 To maintain the existing set of FROMs including those implied by the 

6430 current columns clause, add the 

6431 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6432 parameter:: 

6433 

6434 s = select(table1.c.a, table2.c.b) 

6435 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

6436 

6437 The above parameter performs a transfer of the effective FROMs 

6438 in the columns collection to the :meth:`_sql.Select.select_from` 

6439 method, as though the following were invoked:: 

6440 

6441 s = select(table1.c.a, table2.c.b) 

6442 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

6443 

6444 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

6445 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

6446 collection and performs an operation equivalent to the following:: 

6447 

6448 s = select(table1.c.a, table2.c.b) 

6449 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

6450 

6451 :param \*entities: column expressions to be used. 

6452 

6453 :param maintain_column_froms: boolean parameter that will ensure the 

6454 FROM list implied from the current columns clause will be transferred 

6455 to the :meth:`_sql.Select.select_from` method first. 

6456 

6457 .. versionadded:: 1.4.23 

6458 

6459 """ # noqa: E501 

6460 

6461 if __kw: 

6462 raise _no_kw() 

6463 

6464 # memoizations should be cleared here as of 

6465 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

6466 # is the case for now. 

6467 self._assert_no_memoizations() 

6468 

6469 if maintain_column_froms: 

6470 self.select_from.non_generative( # type: ignore[attr-defined] 

6471 self, *self.columns_clause_froms 

6472 ) 

6473 

6474 # then memoize the FROMs etc. 

6475 _MemoizedSelectEntities._generate_for_statement(self) 

6476 

6477 self._raw_columns = [ 

6478 coercions.expect(roles.ColumnsClauseRole, c) 

6479 for c in coercions._expression_collection_was_a_list( 

6480 "entities", "Select.with_only_columns", entities 

6481 ) 

6482 ] 

6483 return self 

6484 

6485 @property 

6486 def whereclause(self) -> Optional[ColumnElement[Any]]: 

6487 """Return the completed WHERE clause for this 

6488 :class:`_expression.Select` statement. 

6489 

6490 This assembles the current collection of WHERE criteria 

6491 into a single :class:`_expression.BooleanClauseList` construct. 

6492 

6493 

6494 .. versionadded:: 1.4 

6495 

6496 """ 

6497 

6498 return BooleanClauseList._construct_for_whereclause( 

6499 self._where_criteria 

6500 ) 

6501 

6502 _whereclause = whereclause 

6503 

6504 @_generative 

6505 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

6506 """Return a new :func:`_expression.select` construct with 

6507 the given expression added to 

6508 its WHERE clause, joined to the existing clause via AND, if any. 

6509 

6510 """ 

6511 

6512 assert isinstance(self._where_criteria, tuple) 

6513 

6514 for criterion in whereclause: 

6515 where_criteria: ColumnElement[Any] = coercions.expect( 

6516 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6517 ) 

6518 self._where_criteria += (where_criteria,) 

6519 return self 

6520 

6521 @_generative 

6522 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6523 """Return a new :func:`_expression.select` construct with 

6524 the given expression added to 

6525 its HAVING clause, joined to the existing clause via AND, if any. 

6526 

6527 """ 

6528 

6529 for criterion in having: 

6530 having_criteria = coercions.expect( 

6531 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6532 ) 

6533 self._having_criteria += (having_criteria,) 

6534 return self 

6535 

6536 @_generative 

6537 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6538 r"""Return a new :func:`_expression.select` construct which 

6539 will apply DISTINCT to the SELECT statement overall. 

6540 

6541 E.g.:: 

6542 

6543 from sqlalchemy import select 

6544 

6545 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6546 

6547 The above would produce an statement resembling: 

6548 

6549 .. sourcecode:: sql 

6550 

6551 SELECT DISTINCT user.id, user.name FROM user 

6552 

6553 The method also historically accepted an ``*expr`` parameter which 

6554 produced the PostgreSQL dialect-specific ``DISTINCT ON`` expression. 

6555 This is now replaced using the :func:`_postgresql.distinct_on` 

6556 extension:: 

6557 

6558 from sqlalchemy import select 

6559 from sqlalchemy.dialects.postgresql import distinct_on 

6560 

6561 stmt = select(users_table).ext(distinct_on(users_table.c.name)) 

6562 

6563 Using this parameter on other backends which don't support this 

6564 syntax will raise an error. 

6565 

6566 :param \*expr: optional column expressions. When present, 

6567 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6568 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6569 will be raised on other backends. 

6570 

6571 .. deprecated:: 2.1 Passing expressions to 

6572 :meth:`_sql.Select.distinct` is deprecated, use 

6573 :func:`_postgresql.distinct_on` instead. 

6574 

6575 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6576 and will raise :class:`_exc.CompileError` in a future version. 

6577 

6578 .. seealso:: 

6579 

6580 :func:`_postgresql.distinct_on` 

6581 

6582 :meth:`.ext` 

6583 """ 

6584 self._distinct = True 

6585 if expr: 

6586 warn_deprecated( 

6587 "Passing expression to ``distinct`` to generate a " 

6588 "DISTINCT ON clause is deprecated. Use instead the " 

6589 "``postgresql.distinct_on`` function as an extension.", 

6590 "2.1", 

6591 ) 

6592 self._distinct_on = self._distinct_on + tuple( 

6593 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6594 for e in expr 

6595 ) 

6596 return self 

6597 

6598 @_generative 

6599 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6600 r"""Return a new :func:`_expression.select` construct with the 

6601 given FROM expression(s) 

6602 merged into its list of FROM objects. 

6603 

6604 E.g.:: 

6605 

6606 table1 = table("t1", column("a")) 

6607 table2 = table("t2", column("b")) 

6608 s = select(table1.c.a).select_from( 

6609 table1.join(table2, table1.c.a == table2.c.b) 

6610 ) 

6611 

6612 The "from" list is a unique set on the identity of each element, 

6613 so adding an already present :class:`_schema.Table` 

6614 or other selectable 

6615 will have no effect. Passing a :class:`_expression.Join` that refers 

6616 to an already present :class:`_schema.Table` 

6617 or other selectable will have 

6618 the effect of concealing the presence of that selectable as 

6619 an individual element in the rendered FROM list, instead 

6620 rendering it into a JOIN clause. 

6621 

6622 While the typical purpose of :meth:`_expression.Select.select_from` 

6623 is to 

6624 replace the default, derived FROM clause with a join, it can 

6625 also be called with individual table elements, multiple times 

6626 if desired, in the case that the FROM clause cannot be fully 

6627 derived from the columns clause:: 

6628 

6629 select(func.count("*")).select_from(table1) 

6630 

6631 """ 

6632 

6633 self._from_obj += tuple( 

6634 coercions.expect( 

6635 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6636 ) 

6637 for fromclause in froms 

6638 ) 

6639 return self 

6640 

6641 @_generative 

6642 def correlate( 

6643 self, 

6644 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6645 ) -> Self: 

6646 r"""Return a new :class:`_expression.Select` 

6647 which will correlate the given FROM 

6648 clauses to that of an enclosing :class:`_expression.Select`. 

6649 

6650 Calling this method turns off the :class:`_expression.Select` object's 

6651 default behavior of "auto-correlation". Normally, FROM elements 

6652 which appear in a :class:`_expression.Select` 

6653 that encloses this one via 

6654 its :term:`WHERE clause`, ORDER BY, HAVING or 

6655 :term:`columns clause` will be omitted from this 

6656 :class:`_expression.Select` 

6657 object's :term:`FROM clause`. 

6658 Setting an explicit correlation collection using the 

6659 :meth:`_expression.Select.correlate` 

6660 method provides a fixed list of FROM objects 

6661 that can potentially take place in this process. 

6662 

6663 When :meth:`_expression.Select.correlate` 

6664 is used to apply specific FROM clauses 

6665 for correlation, the FROM elements become candidates for 

6666 correlation regardless of how deeply nested this 

6667 :class:`_expression.Select` 

6668 object is, relative to an enclosing :class:`_expression.Select` 

6669 which refers to 

6670 the same FROM object. This is in contrast to the behavior of 

6671 "auto-correlation" which only correlates to an immediate enclosing 

6672 :class:`_expression.Select`. 

6673 Multi-level correlation ensures that the link 

6674 between enclosed and enclosing :class:`_expression.Select` 

6675 is always via 

6676 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6677 correlation to take place. 

6678 

6679 If ``None`` is passed, the :class:`_expression.Select` 

6680 object will correlate 

6681 none of its FROM entries, and all will render unconditionally 

6682 in the local FROM clause. 

6683 

6684 :param \*fromclauses: one or more :class:`.FromClause` or other 

6685 FROM-compatible construct such as an ORM mapped entity to become part 

6686 of the correlate collection; alternatively pass a single value 

6687 ``None`` to remove all existing correlations. 

6688 

6689 .. seealso:: 

6690 

6691 :meth:`_expression.Select.correlate_except` 

6692 

6693 :ref:`tutorial_scalar_subquery` 

6694 

6695 """ 

6696 

6697 # tests failing when we try to change how these 

6698 # arguments are passed 

6699 

6700 self._auto_correlate = False 

6701 if not fromclauses or fromclauses[0] in {None, False}: 

6702 if len(fromclauses) > 1: 

6703 raise exc.ArgumentError( 

6704 "additional FROM objects not accepted when " 

6705 "passing None/False to correlate()" 

6706 ) 

6707 self._correlate = () 

6708 else: 

6709 self._correlate = self._correlate + tuple( 

6710 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6711 ) 

6712 return self 

6713 

6714 @_generative 

6715 def correlate_except( 

6716 self, 

6717 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6718 ) -> Self: 

6719 r"""Return a new :class:`_expression.Select` 

6720 which will omit the given FROM 

6721 clauses from the auto-correlation process. 

6722 

6723 Calling :meth:`_expression.Select.correlate_except` turns off the 

6724 :class:`_expression.Select` object's default behavior of 

6725 "auto-correlation" for the given FROM elements. An element 

6726 specified here will unconditionally appear in the FROM list, while 

6727 all other FROM elements remain subject to normal auto-correlation 

6728 behaviors. 

6729 

6730 If ``None`` is passed, or no arguments are passed, 

6731 the :class:`_expression.Select` object will correlate all of its 

6732 FROM entries. 

6733 

6734 :param \*fromclauses: a list of one or more 

6735 :class:`_expression.FromClause` 

6736 constructs, or other compatible constructs (i.e. ORM-mapped 

6737 classes) to become part of the correlate-exception collection. 

6738 

6739 .. seealso:: 

6740 

6741 :meth:`_expression.Select.correlate` 

6742 

6743 :ref:`tutorial_scalar_subquery` 

6744 

6745 """ 

6746 

6747 self._auto_correlate = False 

6748 if not fromclauses or fromclauses[0] in {None, False}: 

6749 if len(fromclauses) > 1: 

6750 raise exc.ArgumentError( 

6751 "additional FROM objects not accepted when " 

6752 "passing None/False to correlate_except()" 

6753 ) 

6754 self._correlate_except = () 

6755 else: 

6756 self._correlate_except = (self._correlate_except or ()) + tuple( 

6757 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6758 ) 

6759 

6760 return self 

6761 

6762 @HasMemoized_ro_memoized_attribute 

6763 def selected_columns( 

6764 self, 

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

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

6767 representing the columns that 

6768 this SELECT statement or similar construct returns in its result set, 

6769 not including :class:`_sql.TextClause` constructs. 

6770 

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

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

6773 within this collection cannot be directly nested inside another SELECT 

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

6775 necessary parenthesization required by SQL. 

6776 

6777 For a :func:`_expression.select` construct, the collection here is 

6778 exactly what would be rendered inside the "SELECT" statement, and the 

6779 :class:`_expression.ColumnElement` objects are directly present as they 

6780 were given, e.g.:: 

6781 

6782 col1 = column("q", Integer) 

6783 col2 = column("p", Integer) 

6784 stmt = select(col1, col2) 

6785 

6786 Above, ``stmt.selected_columns`` would be a collection that contains 

6787 the ``col1`` and ``col2`` objects directly. For a statement that is 

6788 against a :class:`_schema.Table` or other 

6789 :class:`_expression.FromClause`, the collection will use the 

6790 :class:`_expression.ColumnElement` objects that are in the 

6791 :attr:`_expression.FromClause.c` collection of the from element. 

6792 

6793 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6794 to allow the existing columns to be referenced when adding additional 

6795 criteria, e.g.:: 

6796 

6797 def filter_on_id(my_select, id): 

6798 return my_select.where(my_select.selected_columns["id"] == id) 

6799 

6800 

6801 stmt = select(MyModel) 

6802 

6803 # adds "WHERE id=:param" to the statement 

6804 stmt = filter_on_id(stmt, 42) 

6805 

6806 .. note:: 

6807 

6808 The :attr:`_sql.Select.selected_columns` collection does not 

6809 include expressions established in the columns clause using the 

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

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

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

6813 construct. 

6814 

6815 

6816 .. versionadded:: 1.4 

6817 

6818 """ 

6819 

6820 # compare to SelectState._generate_columns_plus_names, which 

6821 # generates the actual names used in the SELECT string. that 

6822 # method is more complex because it also renders columns that are 

6823 # fully ambiguous, e.g. same column more than once. 

6824 conv = cast( 

6825 "Callable[[Any], str]", 

6826 SelectState._column_naming_convention(self._label_style), 

6827 ) 

6828 

6829 cc: WriteableColumnCollection[str, ColumnElement[Any]] = ( 

6830 WriteableColumnCollection( 

6831 [ 

6832 (conv(c), c) 

6833 for c in self._all_selected_columns 

6834 if is_column_element(c) 

6835 ] 

6836 ) 

6837 ) 

6838 return cc.as_readonly() 

6839 

6840 @HasMemoized_ro_memoized_attribute 

6841 def _all_selected_columns(self) -> _SelectIterable: 

6842 meth = SelectState.get_plugin_class(self).all_selected_columns 

6843 return list(meth(self)) 

6844 

6845 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6846 if self._label_style is LABEL_STYLE_NONE: 

6847 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6848 return self 

6849 

6850 def _generate_fromclause_column_proxies( 

6851 self, 

6852 subquery: FromClause, 

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

6854 primary_key: ColumnSet, 

6855 foreign_keys: Set[KeyedColumnElement[Any]], 

6856 *, 

6857 proxy_compound_columns: Optional[ 

6858 Iterable[Sequence[ColumnElement[Any]]] 

6859 ] = None, 

6860 ) -> None: 

6861 """Generate column proxies to place in the exported ``.c`` 

6862 collection of a subquery.""" 

6863 

6864 if proxy_compound_columns: 

6865 extra_col_iterator = proxy_compound_columns 

6866 prox = [ 

6867 c._make_proxy( 

6868 subquery, 

6869 key=proxy_key, 

6870 name=required_label_name, 

6871 name_is_truncatable=True, 

6872 compound_select_cols=extra_cols, 

6873 primary_key=primary_key, 

6874 foreign_keys=foreign_keys, 

6875 ) 

6876 for ( 

6877 ( 

6878 required_label_name, 

6879 proxy_key, 

6880 fallback_label_name, 

6881 c, 

6882 repeated, 

6883 ), 

6884 extra_cols, 

6885 ) in ( 

6886 zip( 

6887 self._generate_columns_plus_names(False), 

6888 extra_col_iterator, 

6889 ) 

6890 ) 

6891 if is_column_element(c) 

6892 ] 

6893 else: 

6894 prox = [ 

6895 c._make_proxy( 

6896 subquery, 

6897 key=proxy_key, 

6898 name=required_label_name, 

6899 name_is_truncatable=True, 

6900 primary_key=primary_key, 

6901 foreign_keys=foreign_keys, 

6902 ) 

6903 for ( 

6904 required_label_name, 

6905 proxy_key, 

6906 fallback_label_name, 

6907 c, 

6908 repeated, 

6909 ) in (self._generate_columns_plus_names(False)) 

6910 if is_column_element(c) 

6911 ] 

6912 

6913 columns._populate_separate_keys(prox) 

6914 

6915 def _needs_parens_for_grouping(self) -> bool: 

6916 return self._has_row_limiting_clause or bool( 

6917 self._order_by_clause.clauses 

6918 ) 

6919 

6920 def self_group( 

6921 self, against: Optional[OperatorType] = None 

6922 ) -> Union[SelectStatementGrouping[Self], Self]: 

6923 """Return a 'grouping' construct as per the 

6924 :class:`_expression.ClauseElement` specification. 

6925 

6926 This produces an element that can be embedded in an expression. Note 

6927 that this method is called automatically as needed when constructing 

6928 expressions and should not require explicit use. 

6929 

6930 """ 

6931 if ( 

6932 isinstance(against, CompoundSelect) 

6933 and not self._needs_parens_for_grouping() 

6934 ): 

6935 return self 

6936 else: 

6937 return SelectStatementGrouping(self) 

6938 

6939 def union( 

6940 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6941 ) -> CompoundSelect[Unpack[_Ts]]: 

6942 r"""Return a SQL ``UNION`` of this select() construct against 

6943 the given selectables provided as positional arguments. 

6944 

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

6946 UNION. 

6947 

6948 .. versionchanged:: 1.4.28 

6949 

6950 multiple elements are now accepted. 

6951 

6952 :param \**kwargs: keyword arguments are forwarded to the constructor 

6953 for the newly created :class:`_sql.CompoundSelect` object. 

6954 

6955 """ 

6956 return CompoundSelect._create_union(self, *other) 

6957 

6958 def union_all( 

6959 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6960 ) -> CompoundSelect[Unpack[_Ts]]: 

6961 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6962 the given selectables provided as positional arguments. 

6963 

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

6965 UNION. 

6966 

6967 .. versionchanged:: 1.4.28 

6968 

6969 multiple elements are now accepted. 

6970 

6971 :param \**kwargs: keyword arguments are forwarded to the constructor 

6972 for the newly created :class:`_sql.CompoundSelect` object. 

6973 

6974 """ 

6975 return CompoundSelect._create_union_all(self, *other) 

6976 

6977 def except_( 

6978 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6979 ) -> CompoundSelect[Unpack[_Ts]]: 

6980 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6981 the given selectable provided as positional arguments. 

6982 

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

6984 UNION. 

6985 

6986 .. versionchanged:: 1.4.28 

6987 

6988 multiple elements are now accepted. 

6989 

6990 """ 

6991 return CompoundSelect._create_except(self, *other) 

6992 

6993 def except_all( 

6994 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

6995 ) -> CompoundSelect[Unpack[_Ts]]: 

6996 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6997 the given selectables provided as positional arguments. 

6998 

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

7000 UNION. 

7001 

7002 .. versionchanged:: 1.4.28 

7003 

7004 multiple elements are now accepted. 

7005 

7006 """ 

7007 return CompoundSelect._create_except_all(self, *other) 

7008 

7009 def intersect( 

7010 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

7011 ) -> CompoundSelect[Unpack[_Ts]]: 

7012 r"""Return a SQL ``INTERSECT`` of this select() construct against 

7013 the given selectables provided as positional arguments. 

7014 

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

7016 UNION. 

7017 

7018 .. versionchanged:: 1.4.28 

7019 

7020 multiple elements are now accepted. 

7021 

7022 :param \**kwargs: keyword arguments are forwarded to the constructor 

7023 for the newly created :class:`_sql.CompoundSelect` object. 

7024 

7025 """ 

7026 return CompoundSelect._create_intersect(self, *other) 

7027 

7028 def intersect_all( 

7029 self, *other: _SelectStatementForCompoundArgument[Unpack[_Ts]] 

7030 ) -> CompoundSelect[Unpack[_Ts]]: 

7031 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

7032 against the given selectables provided as positional arguments. 

7033 

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

7035 UNION. 

7036 

7037 .. versionchanged:: 1.4.28 

7038 

7039 multiple elements are now accepted. 

7040 

7041 :param \**kwargs: keyword arguments are forwarded to the constructor 

7042 for the newly created :class:`_sql.CompoundSelect` object. 

7043 

7044 """ 

7045 return CompoundSelect._create_intersect_all(self, *other) 

7046 

7047 

7048class ScalarSelect( 

7049 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

7050): 

7051 """Represent a scalar subquery. 

7052 

7053 

7054 A :class:`_sql.ScalarSelect` is created by invoking the 

7055 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

7056 then participates in other SQL expressions as a SQL column expression 

7057 within the :class:`_sql.ColumnElement` hierarchy. 

7058 

7059 .. seealso:: 

7060 

7061 :meth:`_sql.SelectBase.scalar_subquery` 

7062 

7063 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7064 

7065 """ 

7066 

7067 _traverse_internals: _TraverseInternalsType = [ 

7068 ("element", InternalTraversal.dp_clauseelement), 

7069 ("type", InternalTraversal.dp_type), 

7070 ] 

7071 

7072 _from_objects: List[FromClause] = [] 

7073 _is_from_container = True 

7074 if not TYPE_CHECKING: 

7075 _is_implicitly_boolean = False 

7076 inherit_cache = True 

7077 

7078 element: SelectBase 

7079 

7080 def __init__(self, element: SelectBase) -> None: 

7081 self.element = element 

7082 self.type = element._scalar_type() 

7083 self._propagate_attrs = element._propagate_attrs 

7084 

7085 def __getattr__(self, attr: str) -> Any: 

7086 return getattr(self.element, attr) 

7087 

7088 def __getstate__(self) -> Dict[str, Any]: 

7089 return {"element": self.element, "type": self.type} 

7090 

7091 def __setstate__(self, state: Dict[str, Any]) -> None: 

7092 self.element = state["element"] 

7093 self.type = state["type"] 

7094 

7095 @property 

7096 def columns(self) -> NoReturn: 

7097 raise exc.InvalidRequestError( 

7098 "Scalar Select expression has no " 

7099 "columns; use this object directly " 

7100 "within a column-level expression." 

7101 ) 

7102 

7103 c = columns 

7104 

7105 @_generative 

7106 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

7107 """Apply a WHERE clause to the SELECT statement referred to 

7108 by this :class:`_expression.ScalarSelect`. 

7109 

7110 """ 

7111 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

7112 crit 

7113 ) 

7114 return self 

7115 

7116 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

7117 return self 

7118 

7119 def _ungroup(self) -> Self: 

7120 return self 

7121 

7122 @_generative 

7123 def correlate( 

7124 self, 

7125 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7126 ) -> Self: 

7127 r"""Return a new :class:`_expression.ScalarSelect` 

7128 which will correlate the given FROM 

7129 clauses to that of an enclosing :class:`_expression.Select`. 

7130 

7131 This method is mirrored from the :meth:`_sql.Select.correlate` method 

7132 of the underlying :class:`_sql.Select`. The method applies the 

7133 :meth:_sql.Select.correlate` method, then returns a new 

7134 :class:`_sql.ScalarSelect` against that statement. 

7135 

7136 .. versionadded:: 1.4 Previously, the 

7137 :meth:`_sql.ScalarSelect.correlate` 

7138 method was only available from :class:`_sql.Select`. 

7139 

7140 :param \*fromclauses: a list of one or more 

7141 :class:`_expression.FromClause` 

7142 constructs, or other compatible constructs (i.e. ORM-mapped 

7143 classes) to become part of the correlate collection. 

7144 

7145 .. seealso:: 

7146 

7147 :meth:`_expression.ScalarSelect.correlate_except` 

7148 

7149 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7150 

7151 

7152 """ 

7153 self.element = cast( 

7154 "Select[Unpack[TupleAny]]", self.element 

7155 ).correlate(*fromclauses) 

7156 return self 

7157 

7158 @_generative 

7159 def correlate_except( 

7160 self, 

7161 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7162 ) -> Self: 

7163 r"""Return a new :class:`_expression.ScalarSelect` 

7164 which will omit the given FROM 

7165 clauses from the auto-correlation process. 

7166 

7167 This method is mirrored from the 

7168 :meth:`_sql.Select.correlate_except` method of the underlying 

7169 :class:`_sql.Select`. The method applies the 

7170 :meth:_sql.Select.correlate_except` method, then returns a new 

7171 :class:`_sql.ScalarSelect` against that statement. 

7172 

7173 .. versionadded:: 1.4 Previously, the 

7174 :meth:`_sql.ScalarSelect.correlate_except` 

7175 method was only available from :class:`_sql.Select`. 

7176 

7177 :param \*fromclauses: a list of one or more 

7178 :class:`_expression.FromClause` 

7179 constructs, or other compatible constructs (i.e. ORM-mapped 

7180 classes) to become part of the correlate-exception collection. 

7181 

7182 .. seealso:: 

7183 

7184 :meth:`_expression.ScalarSelect.correlate` 

7185 

7186 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

7187 

7188 

7189 """ 

7190 

7191 self.element = cast( 

7192 "Select[Unpack[TupleAny]]", self.element 

7193 ).correlate_except(*fromclauses) 

7194 return self 

7195 

7196 

7197class Exists(UnaryExpression[bool]): 

7198 """Represent an ``EXISTS`` clause. 

7199 

7200 See :func:`_sql.exists` for a description of usage. 

7201 

7202 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

7203 instance by calling :meth:`_sql.SelectBase.exists`. 

7204 

7205 """ 

7206 

7207 inherit_cache = True 

7208 

7209 def __init__( 

7210 self, 

7211 __argument: Optional[ 

7212 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

7213 ] = None, 

7214 /, 

7215 ): 

7216 s: ScalarSelect[Any] 

7217 

7218 # TODO: this seems like we should be using coercions for this 

7219 if __argument is None: 

7220 s = Select(literal_column("*")).scalar_subquery() 

7221 elif isinstance(__argument, SelectBase): 

7222 s = __argument.scalar_subquery() 

7223 s._propagate_attrs = __argument._propagate_attrs 

7224 elif isinstance(__argument, ScalarSelect): 

7225 s = __argument 

7226 else: 

7227 s = Select(__argument).scalar_subquery() 

7228 

7229 UnaryExpression.__init__( 

7230 self, 

7231 s, 

7232 operator=operators.exists, 

7233 type_=type_api.BOOLEANTYPE, 

7234 ) 

7235 

7236 @util.ro_non_memoized_property 

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

7238 return [] 

7239 

7240 def _regroup( 

7241 self, 

7242 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

7243 ) -> ScalarSelect[Any]: 

7244 

7245 assert isinstance(self.element, ScalarSelect) 

7246 element = self.element.element 

7247 if not isinstance(element, Select): 

7248 raise exc.InvalidRequestError( 

7249 "Can only apply this operation to a plain SELECT construct" 

7250 ) 

7251 new_element = fn(element) 

7252 

7253 return_value = new_element.scalar_subquery() 

7254 return return_value 

7255 

7256 def select(self) -> Select[bool]: 

7257 r"""Return a SELECT of this :class:`_expression.Exists`. 

7258 

7259 e.g.:: 

7260 

7261 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

7262 

7263 This will produce a statement resembling: 

7264 

7265 .. sourcecode:: sql 

7266 

7267 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

7268 

7269 .. seealso:: 

7270 

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

7272 method which allows for arbitrary column lists. 

7273 

7274 """ # noqa 

7275 

7276 return Select(self) 

7277 

7278 def correlate( 

7279 self, 

7280 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7281 ) -> Self: 

7282 """Apply correlation to the subquery noted by this 

7283 :class:`_sql.Exists`. 

7284 

7285 .. seealso:: 

7286 

7287 :meth:`_sql.ScalarSelect.correlate` 

7288 

7289 """ 

7290 e = self._clone() 

7291 e.element = self._regroup( 

7292 lambda element: element.correlate(*fromclauses) 

7293 ) 

7294 return e 

7295 

7296 def correlate_except( 

7297 self, 

7298 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

7299 ) -> Self: 

7300 """Apply correlation to the subquery noted by this 

7301 :class:`_sql.Exists`. 

7302 

7303 .. seealso:: 

7304 

7305 :meth:`_sql.ScalarSelect.correlate_except` 

7306 

7307 """ 

7308 e = self._clone() 

7309 e.element = self._regroup( 

7310 lambda element: element.correlate_except(*fromclauses) 

7311 ) 

7312 return e 

7313 

7314 def select_from(self, *froms: _FromClauseArgument) -> Self: 

7315 """Return a new :class:`_expression.Exists` construct, 

7316 applying the given 

7317 expression to the :meth:`_expression.Select.select_from` 

7318 method of the select 

7319 statement contained. 

7320 

7321 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7322 statement first, including the desired WHERE clause, then use the 

7323 :meth:`_sql.SelectBase.exists` method to produce an 

7324 :class:`_sql.Exists` object at once. 

7325 

7326 """ 

7327 e = self._clone() 

7328 e.element = self._regroup(lambda element: element.select_from(*froms)) 

7329 return e 

7330 

7331 def with_hint( 

7332 self, 

7333 selectable: _FromClauseArgument, 

7334 text: str, 

7335 dialect_name: str = "*", 

7336 ) -> Self: 

7337 r"""Return a new :class:`_expression.Exists` construct, applying 

7338 the given arguments to the 

7339 :meth:`_expression.Select.with_hint` method of the select 

7340 statement contained. 

7341 

7342 The hint is therefore rendered against the SELECT that's enclosed 

7343 by the EXISTS expression. This includes :class:`_expression.Exists` 

7344 objects that were generated by ORM constructs such as 

7345 :meth:`_orm.PropComparator.any` and 

7346 :meth:`_orm.PropComparator.has`:: 

7347 

7348 stmt = select(User).where( 

7349 User.addresses.any().with_hint( 

7350 Address.__table__, "WITH (NOLOCK)", "mssql" 

7351 ) 

7352 ) 

7353 

7354 The above statement renders as: 

7355 

7356 .. sourcecode:: sql 

7357 

7358 SELECT users.id, users.name 

7359 FROM users 

7360 WHERE EXISTS (SELECT 1 

7361 FROM addresses WITH (NOLOCK) 

7362 WHERE users.id = addresses.user_id) 

7363 

7364 .. versionadded:: 2.1 

7365 

7366 .. seealso:: 

7367 

7368 :meth:`_expression.Select.with_hint` 

7369 

7370 :meth:`_expression.Exists.with_statement_hint` 

7371 

7372 """ 

7373 e = self._clone() 

7374 e.element = self._regroup( 

7375 lambda element: element.with_hint(selectable, text, dialect_name) 

7376 ) 

7377 return e 

7378 

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

7380 r"""Return a new :class:`_expression.Exists` construct, applying 

7381 the given arguments to the 

7382 :meth:`_expression.Select.with_statement_hint` method of the select 

7383 statement contained. 

7384 

7385 The hint is therefore rendered at the trailing end of the SELECT 

7386 that's enclosed by the EXISTS expression, rather than at the end of 

7387 the enclosing statement. As with 

7388 :meth:`_expression.Exists.with_hint`, this includes 

7389 :class:`_expression.Exists` objects that were generated by ORM 

7390 constructs such as :meth:`_orm.PropComparator.any` and 

7391 :meth:`_orm.PropComparator.has`:: 

7392 

7393 has_address = User.addresses.any().with_statement_hint( 

7394 "WITH (NOLOCK)", "mssql" 

7395 ) 

7396 stmt = select(User).where(has_address) 

7397 

7398 The above statement renders as: 

7399 

7400 .. sourcecode:: sql 

7401 

7402 SELECT users.id, users.name 

7403 FROM users 

7404 WHERE EXISTS (SELECT 1 

7405 FROM addresses 

7406 WHERE users.id = addresses.user_id WITH (NOLOCK)) 

7407 

7408 .. versionadded:: 2.1 

7409 

7410 .. seealso:: 

7411 

7412 :meth:`_expression.Select.with_statement_hint` 

7413 

7414 :meth:`_expression.Exists.with_hint` 

7415 

7416 """ 

7417 e = self._clone() 

7418 e.element = self._regroup( 

7419 lambda element: element.with_statement_hint(text, dialect_name) 

7420 ) 

7421 return e 

7422 

7423 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

7424 """Return a new :func:`_expression.exists` construct with the 

7425 given expression added to 

7426 its WHERE clause, joined to the existing clause via AND, if any. 

7427 

7428 

7429 .. note:: it is typically preferable to build a :class:`_sql.Select` 

7430 statement first, including the desired WHERE clause, then use the 

7431 :meth:`_sql.SelectBase.exists` method to produce an 

7432 :class:`_sql.Exists` object at once. 

7433 

7434 """ 

7435 e = self._clone() 

7436 e.element = self._regroup(lambda element: element.where(*clause)) 

7437 return e 

7438 

7439 

7440class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

7441 """Wrap a :class:`_expression.TextClause` construct within a 

7442 :class:`_expression.SelectBase` 

7443 interface. 

7444 

7445 This allows the :class:`_expression.TextClause` object to gain a 

7446 ``.c`` collection 

7447 and other FROM-like capabilities such as 

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

7449 :meth:`_expression.SelectBase.cte`, etc. 

7450 

7451 The :class:`_expression.TextualSelect` construct is produced via the 

7452 :meth:`_expression.TextClause.columns` 

7453 method - see that method for details. 

7454 

7455 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

7456 class was renamed 

7457 from ``TextAsFrom``, to more correctly suit its role as a 

7458 SELECT-oriented object and not a FROM clause. 

7459 

7460 .. seealso:: 

7461 

7462 :func:`_expression.text` 

7463 

7464 :meth:`_expression.TextClause.columns` - primary creation interface. 

7465 

7466 """ 

7467 

7468 __visit_name__ = "textual_select" 

7469 

7470 _label_style = LABEL_STYLE_NONE 

7471 

7472 _traverse_internals: _TraverseInternalsType = ( 

7473 [ 

7474 ("element", InternalTraversal.dp_clauseelement), 

7475 ("column_args", InternalTraversal.dp_clauseelement_list), 

7476 ] 

7477 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

7478 + HasCTE._has_ctes_traverse_internals 

7479 + ExecutableStatement._executable_traverse_internals 

7480 ) 

7481 

7482 _is_textual = True 

7483 

7484 is_text = True 

7485 is_select = True 

7486 

7487 def __init__( 

7488 self, 

7489 text: TextClause, 

7490 columns: List[_ColumnExpressionArgument[Any]], 

7491 positional: bool = False, 

7492 ) -> None: 

7493 self._init( 

7494 text, 

7495 # convert for ORM attributes->columns, etc 

7496 [ 

7497 coercions.expect(roles.LabeledColumnExprRole, c) 

7498 for c in columns 

7499 ], 

7500 positional, 

7501 ) 

7502 

7503 def _init( 

7504 self, 

7505 text: AbstractTextClause, 

7506 columns: List[NamedColumn[Any]], 

7507 positional: bool = False, 

7508 ) -> None: 

7509 self.element = text 

7510 self.column_args = columns 

7511 self.positional = positional 

7512 

7513 @HasMemoized_ro_memoized_attribute 

7514 def selected_columns( 

7515 self, 

7516 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

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

7518 representing the columns that 

7519 this SELECT statement or similar construct returns in its result set, 

7520 not including :class:`_sql.TextClause` constructs. 

7521 

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

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

7524 within this collection cannot be directly nested inside another SELECT 

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

7526 necessary parenthesization required by SQL. 

7527 

7528 For a :class:`_expression.TextualSelect` construct, the collection 

7529 contains the :class:`_expression.ColumnElement` objects that were 

7530 passed to the constructor, typically via the 

7531 :meth:`_expression.TextClause.columns` method. 

7532 

7533 

7534 .. versionadded:: 1.4 

7535 

7536 """ 

7537 return WriteableColumnCollection( 

7538 (c.key, c) for c in self.column_args 

7539 ).as_readonly() 

7540 

7541 @util.ro_non_memoized_property 

7542 def _all_selected_columns(self) -> _SelectIterable: 

7543 return self.column_args 

7544 

7545 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

7546 return self 

7547 

7548 def _ensure_disambiguated_names(self) -> TextualSelect: 

7549 return self 

7550 

7551 @_generative 

7552 def bindparams( 

7553 self, 

7554 *binds: BindParameter[Any], 

7555 **bind_as_values: Any, 

7556 ) -> Self: 

7557 self.element = self.element.bindparams(*binds, **bind_as_values) 

7558 return self 

7559 

7560 def _generate_fromclause_column_proxies( 

7561 self, 

7562 fromclause: FromClause, 

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

7564 primary_key: ColumnSet, 

7565 foreign_keys: Set[KeyedColumnElement[Any]], 

7566 *, 

7567 proxy_compound_columns: Optional[ 

7568 Iterable[Sequence[ColumnElement[Any]]] 

7569 ] = None, 

7570 ) -> None: 

7571 if TYPE_CHECKING: 

7572 assert isinstance(fromclause, Subquery) 

7573 

7574 if proxy_compound_columns: 

7575 columns._populate_separate_keys( 

7576 c._make_proxy( 

7577 fromclause, 

7578 compound_select_cols=extra_cols, 

7579 primary_key=primary_key, 

7580 foreign_keys=foreign_keys, 

7581 ) 

7582 for c, extra_cols in zip( 

7583 self.column_args, proxy_compound_columns 

7584 ) 

7585 ) 

7586 else: 

7587 columns._populate_separate_keys( 

7588 c._make_proxy( 

7589 fromclause, 

7590 primary_key=primary_key, 

7591 foreign_keys=foreign_keys, 

7592 ) 

7593 for c in self.column_args 

7594 ) 

7595 

7596 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

7597 return self.column_args[0].type 

7598 

7599 

7600TextAsFrom = TextualSelect 

7601"""Backwards compatibility with the previous name""" 

7602 

7603 

7604class AnnotatedFromClause(Annotated): 

7605 def _copy_internals( 

7606 self, 

7607 _annotations_traversal: bool = False, 

7608 ind_cols_on_fromclause: bool = False, 

7609 **kw: Any, 

7610 ) -> None: 

7611 super()._copy_internals(**kw) 

7612 

7613 # passed from annotations._shallow_annotate(), _deep_annotate(), etc. 

7614 # the traversals used by annotations for these cases are not currently 

7615 # designed around expecting that inner elements inside of 

7616 # AnnotatedFromClause's element are also deep copied, so skip for these 

7617 # cases. in other cases such as plain visitors.cloned_traverse(), we 

7618 # expect this to happen. see issue #12915 

7619 if not _annotations_traversal: 

7620 ee = self._Annotated__element # type: ignore[attr-defined] 

7621 ee._copy_internals(**kw) 

7622 

7623 if ind_cols_on_fromclause: 

7624 # passed from annotations._deep_annotate(). See that function 

7625 # for notes 

7626 ee = self._Annotated__element # type: ignore[attr-defined] 

7627 self.c = ee.__class__.c.fget(self) # type: ignore[misc] 

7628 

7629 @util.ro_memoized_property 

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

7631 """proxy the .c collection of the underlying FromClause. 

7632 

7633 Originally implemented in 2008 as a simple load of the .c collection 

7634 when the annotated construct was created (see d3621ae961a), in modern 

7635 SQLAlchemy versions this can be expensive for statements constructed 

7636 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

7637 it, which works just as well. 

7638 

7639 Two different use cases seem to require the collection either copied 

7640 from the underlying one, or unique to this AnnotatedFromClause. 

7641 

7642 See test_selectable->test_annotated_corresponding_column 

7643 

7644 """ 

7645 ee = self._Annotated__element # type: ignore[attr-defined] 

7646 return ee.c # type: ignore[no-any-return]