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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1744 statements  

1# sql/selectable.py 

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

3# <see AUTHORS file> 

4# 

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

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

7 

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

9representing 

10SQL tables and derived rowsets. 

11 

12""" 

13 

14from __future__ import annotations 

15 

16import collections 

17from enum import Enum 

18import itertools 

19from typing import AbstractSet 

20from typing import Any as TODO_Any 

21from typing import Any 

22from typing import Callable 

23from typing import cast 

24from typing import Dict 

25from typing import Generic 

26from typing import Iterable 

27from typing import Iterator 

28from typing import List 

29from typing import NamedTuple 

30from typing import NoReturn 

31from typing import Optional 

32from typing import overload 

33from typing import Protocol 

34from typing import Sequence 

35from typing import Set 

36from typing import Tuple 

37from typing import Type 

38from typing import TYPE_CHECKING 

39from typing import TypeVar 

40from typing import Union 

41 

42from . import cache_key 

43from . import coercions 

44from . import operators 

45from . import roles 

46from . import traversals 

47from . import type_api 

48from . import visitors 

49from ._typing import _ColumnsClauseArgument 

50from ._typing import _no_kw 

51from ._typing import is_column_element 

52from ._typing import is_select_statement 

53from ._typing import is_subquery 

54from ._typing import is_table 

55from ._typing import is_text_clause 

56from .annotation import Annotated 

57from .annotation import SupportsCloneAnnotations 

58from .base import _clone 

59from .base import _cloned_difference 

60from .base import _cloned_intersection 

61from .base import _entity_namespace_key 

62from .base import _EntityNamespace 

63from .base import _expand_cloned 

64from .base import _from_objects 

65from .base import _generative 

66from .base import _never_select_column 

67from .base import _NoArg 

68from .base import _select_iterables 

69from .base import CacheableOptions 

70from .base import ColumnCollection 

71from .base import ColumnSet 

72from .base import CompileState 

73from .base import DedupeColumnCollection 

74from .base import Executable 

75from .base import Generative 

76from .base import HasCompileState 

77from .base import HasMemoized 

78from .base import Immutable 

79from .coercions import _document_text_coercion 

80from .elements import _anonymous_label 

81from .elements import BindParameter 

82from .elements import BooleanClauseList 

83from .elements import ClauseElement 

84from .elements import ClauseList 

85from .elements import ColumnClause 

86from .elements import ColumnElement 

87from .elements import DQLDMLClauseElement 

88from .elements import GroupedElement 

89from .elements import literal_column 

90from .elements import TableValuedColumn 

91from .elements import UnaryExpression 

92from .operators import OperatorType 

93from .sqltypes import NULLTYPE 

94from .visitors import _TraverseInternalsType 

95from .visitors import InternalTraversal 

96from .visitors import prefix_anon_map 

97from .. import exc 

98from .. import util 

99from ..util import HasMemoized_ro_memoized_attribute 

100from ..util.typing import Literal 

101from ..util.typing import Self 

102from ..util.typing import TupleAny 

103from ..util.typing import TypeVarTuple 

104from ..util.typing import Unpack 

105 

106 

107and_ = BooleanClauseList.and_ 

108 

109_T = TypeVar("_T", bound=Any) 

110_Ts = TypeVarTuple("_Ts") 

111 

112 

113if TYPE_CHECKING: 

114 from ._typing import _ColumnExpressionArgument 

115 from ._typing import _ColumnExpressionOrStrLabelArgument 

116 from ._typing import _FromClauseArgument 

117 from ._typing import _JoinTargetArgument 

118 from ._typing import _LimitOffsetType 

119 from ._typing import _MAYBE_ENTITY 

120 from ._typing import _NOT_ENTITY 

121 from ._typing import _OnClauseArgument 

122 from ._typing import _SelectStatementForCompoundArgument 

123 from ._typing import _T0 

124 from ._typing import _T1 

125 from ._typing import _T2 

126 from ._typing import _T3 

127 from ._typing import _T4 

128 from ._typing import _T5 

129 from ._typing import _T6 

130 from ._typing import _T7 

131 from ._typing import _TextCoercedExpressionArgument 

132 from ._typing import _TypedColumnClauseArgument as _TCCA 

133 from ._typing import _TypeEngineArgument 

134 from .base import _AmbiguousTableNameMap 

135 from .base import ExecutableOption 

136 from .base import ReadOnlyColumnCollection 

137 from .cache_key import _CacheKeyTraversalType 

138 from .compiler import SQLCompiler 

139 from .dml import Delete 

140 from .dml import Update 

141 from .elements import BinaryExpression 

142 from .elements import KeyedColumnElement 

143 from .elements import Label 

144 from .elements import NamedColumn 

145 from .elements import TextClause 

146 from .functions import Function 

147 from .schema import ForeignKey 

148 from .schema import ForeignKeyConstraint 

149 from .sqltypes import TableValueType 

150 from .type_api import TypeEngine 

151 from .visitors import _CloneCallableType 

152 

153 

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

155_LabelConventionCallable = Callable[ 

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

157] 

158 

159 

160class _JoinTargetProtocol(Protocol): 

161 @util.ro_non_memoized_property 

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

163 

164 @util.ro_non_memoized_property 

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

166 

167 

168_JoinTargetElement = Union["FromClause", _JoinTargetProtocol] 

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

170 

171_ForUpdateOfArgument = Union[ 

172 # single column, Table, ORM Entity 

173 Union[ 

174 "_ColumnExpressionArgument[Any]", 

175 "_FromClauseArgument", 

176 ], 

177 # or sequence of single column elements 

178 Sequence["_ColumnExpressionArgument[Any]"], 

179] 

180 

181 

182_SetupJoinsElement = Tuple[ 

183 _JoinTargetElement, 

184 Optional[_OnClauseElement], 

185 Optional["FromClause"], 

186 Dict[str, Any], 

187] 

188 

189 

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

191 

192 

193class _OffsetLimitParam(BindParameter[int]): 

194 inherit_cache = True 

195 

196 @property 

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

198 return self.effective_value 

199 

200 

201class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement): 

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

203 columns that can represent rows. 

204 

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

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

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

208 PostgreSQL has functions that return rows also. 

209 

210 .. versionadded:: 1.4 

211 

212 """ 

213 

214 _is_returns_rows = True 

215 

216 # sub-elements of returns_rows 

217 _is_from_clause = False 

218 _is_select_base = False 

219 _is_select_statement = False 

220 _is_lateral = False 

221 

222 @property 

223 def selectable(self) -> ReturnsRows: 

224 return self 

225 

226 @util.ro_non_memoized_property 

227 def _all_selected_columns(self) -> _SelectIterable: 

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

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

230 

231 This is typically equivalent to .exported_columns except it is 

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

233 :class:`_expression.ColumnCollection`. 

234 

235 """ 

236 raise NotImplementedError() 

237 

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

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

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

241 

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

243 

244 """ 

245 raise NotImplementedError() 

246 

247 def _generate_fromclause_column_proxies( 

248 self, fromclause: FromClause 

249 ) -> None: 

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

251 

252 raise NotImplementedError() 

253 

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

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

256 raise NotImplementedError() 

257 

258 @property 

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

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

261 that represents the "exported" 

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

263 

264 The "exported" columns represent the collection of 

265 :class:`_expression.ColumnElement` 

266 expressions that are rendered by this SQL 

267 construct. There are primary varieties which are the 

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

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

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

271 columns in a DML statement.. 

272 

273 .. versionadded:: 1.4 

274 

275 .. seealso:: 

276 

277 :attr:`_expression.FromClause.exported_columns` 

278 

279 :attr:`_expression.SelectBase.exported_columns` 

280 """ 

281 

282 raise NotImplementedError() 

283 

284 

285class ExecutableReturnsRows(Executable, ReturnsRows): 

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

287 

288 

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

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

291 

292 

293class Selectable(ReturnsRows): 

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

295 

296 __visit_name__ = "selectable" 

297 

298 is_selectable = True 

299 

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

301 raise NotImplementedError() 

302 

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

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

305 

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

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

308 

309 .. seealso:: 

310 

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

312 

313 """ 

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

315 

316 @util.deprecated( 

317 "1.4", 

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

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

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

321 ) 

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

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

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

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

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

327 

328 """ 

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

330 

331 def corresponding_column( 

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

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

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

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

336 :attr:`_expression.Selectable.exported_columns` 

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

338 which corresponds to that 

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

340 column. 

341 

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

343 to be matched. 

344 

345 :param require_embedded: only return corresponding columns for 

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

347 :class:`_expression.ColumnElement` 

348 is actually present within a sub-element 

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

350 Normally the column will match if 

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

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

353 

354 .. seealso:: 

355 

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

357 :class:`_expression.ColumnCollection` 

358 that is used for the operation. 

359 

360 :meth:`_expression.ColumnCollection.corresponding_column` 

361 - implementation 

362 method. 

363 

364 """ 

365 

366 return self.exported_columns.corresponding_column( 

367 column, require_embedded 

368 ) 

369 

370 

371class HasPrefixes: 

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

373 

374 _has_prefixes_traverse_internals: _TraverseInternalsType = [ 

375 ("_prefixes", InternalTraversal.dp_prefix_sequence) 

376 ] 

377 

378 @_generative 

379 @_document_text_coercion( 

380 "prefixes", 

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

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

383 ) 

384 def prefix_with( 

385 self, 

386 *prefixes: _TextCoercedExpressionArgument[Any], 

387 dialect: str = "*", 

388 ) -> Self: 

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

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

391 

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

393 provided by MySQL. 

394 

395 E.g.:: 

396 

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

398 

399 # MySQL 5.7 optimizer hints 

400 stmt = select(table).prefix_with( 

401 "/*+ BKA(t1) */", dialect="mysql") 

402 

403 Multiple prefixes can be specified by multiple calls 

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

405 

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

407 construct which 

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

409 keyword. 

410 :param dialect: optional string dialect name which will 

411 limit rendering of this prefix to only that dialect. 

412 

413 """ 

414 self._prefixes = self._prefixes + tuple( 

415 [ 

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

417 for p in prefixes 

418 ] 

419 ) 

420 return self 

421 

422 

423class HasSuffixes: 

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

425 

426 _has_suffixes_traverse_internals: _TraverseInternalsType = [ 

427 ("_suffixes", InternalTraversal.dp_prefix_sequence) 

428 ] 

429 

430 @_generative 

431 @_document_text_coercion( 

432 "suffixes", 

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

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

435 ) 

436 def suffix_with( 

437 self, 

438 *suffixes: _TextCoercedExpressionArgument[Any], 

439 dialect: str = "*", 

440 ) -> Self: 

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

442 

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

444 certain constructs. 

445 

446 E.g.:: 

447 

448 stmt = select(col1, col2).cte().suffix_with( 

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

450 

451 Multiple suffixes can be specified by multiple calls 

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

453 

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

455 construct which 

456 will be rendered following the target clause. 

457 :param dialect: Optional string dialect name which will 

458 limit rendering of this suffix to only that dialect. 

459 

460 """ 

461 self._suffixes = self._suffixes + tuple( 

462 [ 

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

464 for p in suffixes 

465 ] 

466 ) 

467 return self 

468 

469 

470class HasHints: 

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

472 util.immutabledict() 

473 ) 

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

475 

476 _has_hints_traverse_internals: _TraverseInternalsType = [ 

477 ("_statement_hints", InternalTraversal.dp_statement_hint_list), 

478 ("_hints", InternalTraversal.dp_table_hint_list), 

479 ] 

480 

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

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

483 other selectable object. 

484 

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

486 except that 

487 it does not require an individual table, and instead applies to the 

488 statement as a whole. 

489 

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

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

492 etc. 

493 

494 .. seealso:: 

495 

496 :meth:`_expression.Select.with_hint` 

497 

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

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

500 MySQL optimizer hints 

501 

502 """ 

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

504 

505 @_generative 

506 def with_hint( 

507 self, 

508 selectable: _FromClauseArgument, 

509 text: str, 

510 dialect_name: str = "*", 

511 ) -> Self: 

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

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

514 object. 

515 

516 The text of the hint is rendered in the appropriate 

517 location for the database backend in use, relative 

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

519 passed as the 

520 ``selectable`` argument. The dialect implementation 

521 typically uses Python string substitution syntax 

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

523 the table or alias. E.g. when using Oracle, the 

524 following:: 

525 

526 select(mytable).\ 

527 with_hint(mytable, "index(%(name)s ix_mytable)") 

528 

529 Would render SQL as:: 

530 

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

532 

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

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

535 and Sybase simultaneously:: 

536 

537 select(mytable).\ 

538 with_hint(mytable, "index(%(name)s ix_mytable)", 'oracle').\ 

539 with_hint(mytable, "WITH INDEX ix_mytable", 'mssql') 

540 

541 .. seealso:: 

542 

543 :meth:`_expression.Select.with_statement_hint` 

544 

545 """ 

546 

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

548 

549 def _with_hint( 

550 self, 

551 selectable: Optional[_FromClauseArgument], 

552 text: str, 

553 dialect_name: str, 

554 ) -> Self: 

555 if selectable is None: 

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

557 else: 

558 self._hints = self._hints.union( 

559 { 

560 ( 

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

562 dialect_name, 

563 ): text 

564 } 

565 ) 

566 return self 

567 

568 

569class FromClause(roles.AnonymizedFromClauseRole, Selectable): 

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

571 clause of a ``SELECT`` statement. 

572 

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

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

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

576 

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

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

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

580 :class:`_expression.ColumnElement` 

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

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

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

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

585 :meth:`_expression.FromClause.select`. 

586 

587 

588 """ 

589 

590 __visit_name__ = "fromclause" 

591 named_with_column = False 

592 

593 @util.ro_non_memoized_property 

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

595 return () 

596 

597 _is_clone_of: Optional[FromClause] 

598 

599 _columns: ColumnCollection[Any, Any] 

600 

601 schema: Optional[str] = None 

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

603 

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

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

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

607 

608 """ 

609 

610 is_selectable = True 

611 _is_from_clause = True 

612 _is_join = False 

613 

614 _use_schema_map = False 

615 

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

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

618 

619 

620 e.g.:: 

621 

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

623 

624 .. seealso:: 

625 

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

627 method which allows for arbitrary column lists. 

628 

629 """ 

630 return Select(self) 

631 

632 def join( 

633 self, 

634 right: _FromClauseArgument, 

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

636 isouter: bool = False, 

637 full: bool = False, 

638 ) -> Join: 

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

640 :class:`_expression.FromClause` 

641 to another :class:`FromClause`. 

642 

643 E.g.:: 

644 

645 from sqlalchemy import join 

646 

647 j = user_table.join(address_table, 

648 user_table.c.id == address_table.c.user_id) 

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

650 

651 would emit SQL along the lines of:: 

652 

653 SELECT user.id, user.name FROM user 

654 JOIN address ON user.id = address.user_id 

655 

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

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

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

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

660 class. 

661 

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

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

664 will attempt to 

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

666 

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

668 

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

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

671 

672 .. seealso:: 

673 

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

675 

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

677 

678 """ 

679 

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

681 

682 def outerjoin( 

683 self, 

684 right: _FromClauseArgument, 

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

686 full: bool = False, 

687 ) -> Join: 

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

689 :class:`_expression.FromClause` 

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

691 True. 

692 

693 E.g.:: 

694 

695 from sqlalchemy import outerjoin 

696 

697 j = user_table.outerjoin(address_table, 

698 user_table.c.id == address_table.c.user_id) 

699 

700 The above is equivalent to:: 

701 

702 j = user_table.join( 

703 address_table, 

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

705 isouter=True) 

706 

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

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

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

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

711 class. 

712 

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

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

715 will attempt to 

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

717 

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

719 LEFT OUTER JOIN. 

720 

721 .. seealso:: 

722 

723 :meth:`_expression.FromClause.join` 

724 

725 :class:`_expression.Join` 

726 

727 """ 

728 

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

730 

731 def alias( 

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

733 ) -> NamedFromClause: 

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

735 

736 E.g.:: 

737 

738 a2 = some_table.alias('a2') 

739 

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

741 object which can be used 

742 as a FROM clause in any SELECT statement. 

743 

744 .. seealso:: 

745 

746 :ref:`tutorial_using_aliases` 

747 

748 :func:`_expression.alias` 

749 

750 """ 

751 

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

753 

754 def tablesample( 

755 self, 

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

757 name: Optional[str] = None, 

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

759 ) -> TableSample: 

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

761 

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

763 construct also 

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

765 

766 .. seealso:: 

767 

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

769 

770 """ 

771 return TableSample._construct( 

772 self, sampling=sampling, name=name, seed=seed 

773 ) 

774 

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

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

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

778 

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

780 

781 """ 

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

783 # Other constructs override this to traverse through 

784 # contained elements. 

785 return fromclause in self._cloned_set 

786 

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

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

789 the other represent the same lexical identity. 

790 

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

792 if they are the same via annotation identity. 

793 

794 """ 

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

796 

797 @util.ro_non_memoized_property 

798 def description(self) -> str: 

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

800 

801 Used primarily for error message formatting. 

802 

803 """ 

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

805 

806 def _generate_fromclause_column_proxies( 

807 self, fromclause: FromClause 

808 ) -> None: 

809 fromclause._columns._populate_separate_keys( 

810 col._make_proxy(fromclause) for col in self.c 

811 ) 

812 

813 @util.ro_non_memoized_property 

814 def exported_columns( 

815 self, 

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

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

818 that represents the "exported" 

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

820 

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

822 object are synonymous 

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

824 

825 .. versionadded:: 1.4 

826 

827 .. seealso:: 

828 

829 :attr:`_expression.Selectable.exported_columns` 

830 

831 :attr:`_expression.SelectBase.exported_columns` 

832 

833 

834 """ 

835 return self.c 

836 

837 @util.ro_non_memoized_property 

838 def columns( 

839 self, 

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

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

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

843 

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

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

846 other selectable-bound columns:: 

847 

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

849 

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

851 

852 """ 

853 return self.c 

854 

855 @util.ro_memoized_property 

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

857 """ 

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

859 

860 :return: a :class:`.ColumnCollection` 

861 

862 """ 

863 if "_columns" not in self.__dict__: 

864 self._init_collections() 

865 self._populate_column_collection() 

866 return self._columns.as_readonly() 

867 

868 @util.ro_non_memoized_property 

869 def entity_namespace(self) -> _EntityNamespace: 

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

871 

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

873 expressions, such as:: 

874 

875 stmt.filter_by(address='some address') 

876 

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

878 be overridden using the "entity_namespace" annotation to deliver 

879 alternative results. 

880 

881 """ 

882 return self.c 

883 

884 @util.ro_memoized_property 

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

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

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

888 

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

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

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

892 

893 """ 

894 self._init_collections() 

895 self._populate_column_collection() 

896 return self.primary_key 

897 

898 @util.ro_memoized_property 

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

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

901 which this FromClause references. 

902 

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

904 :class:`_schema.Table`-wide 

905 :class:`_schema.ForeignKeyConstraint`. 

906 

907 .. seealso:: 

908 

909 :attr:`_schema.Table.foreign_key_constraints` 

910 

911 """ 

912 self._init_collections() 

913 self._populate_column_collection() 

914 return self.foreign_keys 

915 

916 def _reset_column_collection(self) -> None: 

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

918 

919 This collection is separate from all the other memoized things 

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

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

922 has already established strong relationships 

923 with the exported columns. 

924 

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

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

927 

928 """ 

929 

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

931 self.__dict__.pop(key, None) 

932 

933 @util.ro_non_memoized_property 

934 def _select_iterable(self) -> _SelectIterable: 

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

936 

937 def _init_collections(self) -> None: 

938 assert "_columns" not in self.__dict__ 

939 assert "primary_key" not in self.__dict__ 

940 assert "foreign_keys" not in self.__dict__ 

941 

942 self._columns = ColumnCollection() 

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

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

945 

946 @property 

947 def _cols_populated(self) -> bool: 

948 return "_columns" in self.__dict__ 

949 

950 def _populate_column_collection(self) -> None: 

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

952 

953 Each implementation has a different way of establishing 

954 this collection. 

955 

956 """ 

957 

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

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

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

961 selectable ultimately should proxy this column. 

962 

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

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

965 Table objects it ultimately derives from. 

966 

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

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

969 but it will return None. 

970 

971 This method is currently used by Declarative to allow Table 

972 columns to be added to a partially constructed inheritance 

973 mapping that may have already produced joins. The method 

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

975 and/or caveats aren't yet clear. 

976 

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

978 default via an event, which would require that 

979 selectables maintain a weak referencing collection of all 

980 derivations. 

981 

982 """ 

983 self._reset_column_collection() 

984 

985 def _anonymous_fromclause( 

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

987 ) -> FromClause: 

988 return self.alias(name=name) 

989 

990 if TYPE_CHECKING: 

991 

992 def self_group( 

993 self, against: Optional[OperatorType] = None 

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

995 

996 

997class NamedFromClause(FromClause): 

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

999 

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

1001 

1002 .. versionadded:: 2.0 

1003 

1004 """ 

1005 

1006 named_with_column = True 

1007 

1008 name: str 

1009 

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

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

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

1013 :class:`_expression.FromClause`. 

1014 

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

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

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

1018 such as PostgreSQL, Oracle and SQL Server. 

1019 

1020 E.g.: 

1021 

1022 .. sourcecode:: pycon+sql 

1023 

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

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

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

1027 >>> print(stmt) 

1028 {printsql}SELECT row_to_json(a) AS row_to_json_1 

1029 FROM a 

1030 

1031 .. versionadded:: 1.4.0b2 

1032 

1033 .. seealso:: 

1034 

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

1036 

1037 """ 

1038 return TableValuedColumn(self, type_api.TABLEVALUE) 

1039 

1040 

1041class SelectLabelStyle(Enum): 

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

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

1044 

1045 LABEL_STYLE_NONE = 0 

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

1047 columns clause of a SELECT statement. 

1048 

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

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

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

1052 

1053 .. sourcecode:: pycon+sql 

1054 

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

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

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

1058 >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_NONE)) 

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

1060 FROM table1 JOIN table2 ON true 

1061 

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

1063 

1064 .. versionadded:: 1.4 

1065 

1066 """ # noqa: E501 

1067 

1068 LABEL_STYLE_TABLENAME_PLUS_COL = 1 

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

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

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

1072 tables, aliases, or subqueries. 

1073 

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

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

1076 ``table2_columna``: 

1077 

1078 .. sourcecode:: pycon+sql 

1079 

1080 >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_TABLENAME_PLUS_COL 

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

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

1083 >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)) 

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

1085 FROM table1 JOIN table2 ON true 

1086 

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

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

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

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

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

1092 

1093 

1094 .. versionadded:: 1.4 

1095 

1096 """ # noqa: E501 

1097 

1098 LABEL_STYLE_DISAMBIGUATE_ONLY = 2 

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

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

1101 when generating the columns clause of a SELECT statement. 

1102 

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

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

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

1106 

1107 .. sourcecode:: pycon+sql 

1108 

1109 >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_DISAMBIGUATE_ONLY 

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

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

1112 >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)) 

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

1114 FROM table1 JOIN table2 ON true 

1115 

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

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

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

1119 

1120 .. versionadded:: 1.4 

1121 

1122 """ # noqa: E501 

1123 

1124 LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1125 """The default label style, refers to 

1126 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

1127 

1128 .. versionadded:: 1.4 

1129 

1130 """ 

1131 

1132 LABEL_STYLE_LEGACY_ORM = 3 

1133 

1134 

1135( 

1136 LABEL_STYLE_NONE, 

1137 LABEL_STYLE_TABLENAME_PLUS_COL, 

1138 LABEL_STYLE_DISAMBIGUATE_ONLY, 

1139 _, 

1140) = list(SelectLabelStyle) 

1141 

1142LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY 

1143 

1144 

1145class Join(roles.DMLTableRole, FromClause): 

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

1147 :class:`_expression.FromClause` 

1148 elements. 

1149 

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

1151 is the module-level 

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

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

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

1155 :class:`_schema.Table`). 

1156 

1157 .. seealso:: 

1158 

1159 :func:`_expression.join` 

1160 

1161 :meth:`_expression.FromClause.join` 

1162 

1163 """ 

1164 

1165 __visit_name__ = "join" 

1166 

1167 _traverse_internals: _TraverseInternalsType = [ 

1168 ("left", InternalTraversal.dp_clauseelement), 

1169 ("right", InternalTraversal.dp_clauseelement), 

1170 ("onclause", InternalTraversal.dp_clauseelement), 

1171 ("isouter", InternalTraversal.dp_boolean), 

1172 ("full", InternalTraversal.dp_boolean), 

1173 ] 

1174 

1175 _is_join = True 

1176 

1177 left: FromClause 

1178 right: FromClause 

1179 onclause: Optional[ColumnElement[bool]] 

1180 isouter: bool 

1181 full: bool 

1182 

1183 def __init__( 

1184 self, 

1185 left: _FromClauseArgument, 

1186 right: _FromClauseArgument, 

1187 onclause: Optional[_OnClauseArgument] = None, 

1188 isouter: bool = False, 

1189 full: bool = False, 

1190 ): 

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

1192 

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

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

1195 :class:`_expression.FromClause` object. 

1196 

1197 """ 

1198 

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

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

1201 # annotated objects. test_orm.py -> test_fetch_results 

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

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

1204 # callcounts for a single compilation in that particular test 

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

1206 # 29200 -> 30373 

1207 

1208 self.left = coercions.expect( 

1209 roles.FromClauseRole, 

1210 left, 

1211 ) 

1212 self.right = coercions.expect( 

1213 roles.FromClauseRole, 

1214 right, 

1215 ).self_group() 

1216 

1217 if onclause is None: 

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

1219 else: 

1220 # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba 

1221 # not merged yet 

1222 self.onclause = coercions.expect( 

1223 roles.OnClauseRole, onclause 

1224 ).self_group(against=operators._asbool) 

1225 

1226 self.isouter = isouter 

1227 self.full = full 

1228 

1229 @util.ro_non_memoized_property 

1230 def description(self) -> str: 

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

1232 self.left.description, 

1233 id(self.left), 

1234 self.right.description, 

1235 id(self.right), 

1236 ) 

1237 

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

1239 return ( 

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

1241 # as well 

1242 hash(fromclause) == hash(self) 

1243 or self.left.is_derived_from(fromclause) 

1244 or self.right.is_derived_from(fromclause) 

1245 ) 

1246 

1247 def self_group( 

1248 self, against: Optional[OperatorType] = None 

1249 ) -> FromGrouping: 

1250 return FromGrouping(self) 

1251 

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

1253 def _populate_column_collection(self) -> None: 

1254 sqlutil = util.preloaded.sql_util 

1255 columns: List[KeyedColumnElement[Any]] = [c for c in self.left.c] + [ 

1256 c for c in self.right.c 

1257 ] 

1258 

1259 self.primary_key.extend( # type: ignore 

1260 sqlutil.reduce_columns( 

1261 (c for c in columns if c.primary_key), self.onclause 

1262 ) 

1263 ) 

1264 self._columns._populate_separate_keys( 

1265 (col._tq_key_label, col) for col in columns 

1266 ) 

1267 self.foreign_keys.update( # type: ignore 

1268 itertools.chain(*[col.foreign_keys for col in columns]) 

1269 ) 

1270 

1271 def _copy_internals( 

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

1273 ) -> None: 

1274 # see Select._copy_internals() for similar concept 

1275 

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

1277 # determine the new FROM clauses 

1278 all_the_froms = set( 

1279 itertools.chain( 

1280 _from_objects(self.left), 

1281 _from_objects(self.right), 

1282 ) 

1283 ) 

1284 

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

1286 # cache used by the clone function 

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

1288 

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

1290 # ColumnClause with parent table referring to those 

1291 # replaced FromClause objects 

1292 def replace( 

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

1294 **kw: Any, 

1295 ) -> Optional[KeyedColumnElement[ColumnElement[Any]]]: 

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

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

1298 return newelem 

1299 return None 

1300 

1301 kw["replace"] = replace 

1302 

1303 # run normal _copy_internals. the clones for 

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

1305 # cache 

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

1307 

1308 self._reset_memoizations() 

1309 

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

1311 super()._refresh_for_new_column(column) 

1312 self.left._refresh_for_new_column(column) 

1313 self.right._refresh_for_new_column(column) 

1314 

1315 def _match_primaries( 

1316 self, 

1317 left: FromClause, 

1318 right: FromClause, 

1319 ) -> ColumnElement[bool]: 

1320 if isinstance(left, Join): 

1321 left_right = left.right 

1322 else: 

1323 left_right = None 

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

1325 

1326 @classmethod 

1327 def _join_condition( 

1328 cls, 

1329 a: FromClause, 

1330 b: FromClause, 

1331 *, 

1332 a_subset: Optional[FromClause] = None, 

1333 consider_as_foreign_keys: Optional[ 

1334 AbstractSet[ColumnClause[Any]] 

1335 ] = None, 

1336 ) -> ColumnElement[bool]: 

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

1338 

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

1340 

1341 """ 

1342 constraints = cls._joincond_scan_left_right( 

1343 a, a_subset, b, consider_as_foreign_keys 

1344 ) 

1345 

1346 if len(constraints) > 1: 

1347 cls._joincond_trim_constraints( 

1348 a, b, constraints, consider_as_foreign_keys 

1349 ) 

1350 

1351 if len(constraints) == 0: 

1352 if isinstance(b, FromGrouping): 

1353 hint = ( 

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

1355 "subquery using alias()?" 

1356 ) 

1357 else: 

1358 hint = "" 

1359 raise exc.NoForeignKeysError( 

1360 "Can't find any foreign key relationships " 

1361 "between '%s' and '%s'.%s" 

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

1363 ) 

1364 

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

1366 if len(crit) == 1: 

1367 return crit[0] 

1368 else: 

1369 return and_(*crit) 

1370 

1371 @classmethod 

1372 def _can_join( 

1373 cls, 

1374 left: FromClause, 

1375 right: FromClause, 

1376 *, 

1377 consider_as_foreign_keys: Optional[ 

1378 AbstractSet[ColumnClause[Any]] 

1379 ] = None, 

1380 ) -> bool: 

1381 if isinstance(left, Join): 

1382 left_right = left.right 

1383 else: 

1384 left_right = None 

1385 

1386 constraints = cls._joincond_scan_left_right( 

1387 a=left, 

1388 b=right, 

1389 a_subset=left_right, 

1390 consider_as_foreign_keys=consider_as_foreign_keys, 

1391 ) 

1392 

1393 return bool(constraints) 

1394 

1395 @classmethod 

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

1397 def _joincond_scan_left_right( 

1398 cls, 

1399 a: FromClause, 

1400 a_subset: Optional[FromClause], 

1401 b: FromClause, 

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

1403 ) -> collections.defaultdict[ 

1404 Optional[ForeignKeyConstraint], 

1405 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1406 ]: 

1407 sql_util = util.preloaded.sql_util 

1408 

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

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

1411 

1412 constraints: collections.defaultdict[ 

1413 Optional[ForeignKeyConstraint], 

1414 List[Tuple[ColumnClause[Any], ColumnClause[Any]]], 

1415 ] = collections.defaultdict(list) 

1416 

1417 for left in (a_subset, a): 

1418 if left is None: 

1419 continue 

1420 for fk in sorted( 

1421 b.foreign_keys, 

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

1423 ): 

1424 if ( 

1425 consider_as_foreign_keys is not None 

1426 and fk.parent not in consider_as_foreign_keys 

1427 ): 

1428 continue 

1429 try: 

1430 col = fk.get_referent(left) 

1431 except exc.NoReferenceError as nrte: 

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

1433 if nrte.table_name in table_names: 

1434 raise 

1435 else: 

1436 continue 

1437 

1438 if col is not None: 

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

1440 if left is not b: 

1441 for fk in sorted( 

1442 left.foreign_keys, 

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

1444 ): 

1445 if ( 

1446 consider_as_foreign_keys is not None 

1447 and fk.parent not in consider_as_foreign_keys 

1448 ): 

1449 continue 

1450 try: 

1451 col = fk.get_referent(b) 

1452 except exc.NoReferenceError as nrte: 

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

1454 if nrte.table_name in table_names: 

1455 raise 

1456 else: 

1457 continue 

1458 

1459 if col is not None: 

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

1461 if constraints: 

1462 break 

1463 return constraints 

1464 

1465 @classmethod 

1466 def _joincond_trim_constraints( 

1467 cls, 

1468 a: FromClause, 

1469 b: FromClause, 

1470 constraints: Dict[Any, Any], 

1471 consider_as_foreign_keys: Optional[Any], 

1472 ) -> None: 

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

1474 # to include just those FKCs that match exactly to 

1475 # "consider_as_foreign_keys". 

1476 if consider_as_foreign_keys: 

1477 for const in list(constraints): 

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

1479 consider_as_foreign_keys 

1480 ): 

1481 del constraints[const] 

1482 

1483 # if still multiple constraints, but 

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

1485 if len(constraints) > 1: 

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

1487 if len(dedupe) == 1: 

1488 key = list(constraints)[0] 

1489 constraints = {key: constraints[key]} 

1490 

1491 if len(constraints) != 1: 

1492 raise exc.AmbiguousForeignKeysError( 

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

1494 "tables have more than one foreign key " 

1495 "constraint relationship between them. " 

1496 "Please specify the 'onclause' of this " 

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

1498 ) 

1499 

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

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

1502 :class:`_expression.Join`. 

1503 

1504 E.g.:: 

1505 

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

1507 

1508 stmt = stmt.select() 

1509 

1510 The above will produce a SQL string resembling:: 

1511 

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

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

1514 

1515 """ 

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

1517 

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

1519 def _anonymous_fromclause( 

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

1521 ) -> TODO_Any: 

1522 sqlutil = util.preloaded.sql_util 

1523 if flat: 

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

1525 left_name = name # will recurse 

1526 else: 

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

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

1529 else: 

1530 left_name = name 

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

1532 right_name = name # will recurse 

1533 else: 

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

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

1536 else: 

1537 right_name = name 

1538 left_a, right_a = ( 

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

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

1541 ) 

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

1543 sqlutil.ClauseAdapter(right_a) 

1544 ) 

1545 

1546 return left_a.join( 

1547 right_a, 

1548 adapter.traverse(self.onclause), 

1549 isouter=self.isouter, 

1550 full=self.full, 

1551 ) 

1552 else: 

1553 return ( 

1554 self.select() 

1555 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1556 .correlate(None) 

1557 .alias(name) 

1558 ) 

1559 

1560 @util.ro_non_memoized_property 

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

1562 return itertools.chain( 

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

1564 ) 

1565 

1566 @util.ro_non_memoized_property 

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

1568 self_list: List[FromClause] = [self] 

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

1570 

1571 

1572class NoInit: 

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

1574 raise NotImplementedError( 

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

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

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

1578 "selectable objects." 

1579 % ( 

1580 self.__class__.__name__, 

1581 self.__class__.__name__.lower(), 

1582 self.__class__.__name__.lower(), 

1583 ) 

1584 ) 

1585 

1586 

1587class LateralFromClause(NamedFromClause): 

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

1589 

1590 

1591# FromClause -> 

1592# AliasedReturnsRows 

1593# -> Alias only for FromClause 

1594# -> Subquery only for SelectBase 

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

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

1597# w/ non-deprecated coercion 

1598# -> TableSample -> only for FromClause 

1599 

1600 

1601class AliasedReturnsRows(NoInit, NamedFromClause): 

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

1603 selectables.""" 

1604 

1605 _is_from_container = True 

1606 

1607 _supports_derived_columns = False 

1608 

1609 element: ReturnsRows 

1610 

1611 _traverse_internals: _TraverseInternalsType = [ 

1612 ("element", InternalTraversal.dp_clauseelement), 

1613 ("name", InternalTraversal.dp_anon_name), 

1614 ] 

1615 

1616 @classmethod 

1617 def _construct( 

1618 cls, 

1619 selectable: Any, 

1620 *, 

1621 name: Optional[str] = None, 

1622 **kw: Any, 

1623 ) -> Self: 

1624 obj = cls.__new__(cls) 

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

1626 return obj 

1627 

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

1629 self.element = coercions.expect( 

1630 roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self 

1631 ) 

1632 self.element = selectable 

1633 self._orig_name = name 

1634 if name is None: 

1635 if ( 

1636 isinstance(selectable, FromClause) 

1637 and selectable.named_with_column 

1638 ): 

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

1640 if isinstance(name, _anonymous_label): 

1641 name = None 

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

1643 self.name = name 

1644 

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

1646 super()._refresh_for_new_column(column) 

1647 self.element._refresh_for_new_column(column) 

1648 

1649 def _populate_column_collection(self) -> None: 

1650 self.element._generate_fromclause_column_proxies(self) 

1651 

1652 @util.ro_non_memoized_property 

1653 def description(self) -> str: 

1654 name = self.name 

1655 if isinstance(name, _anonymous_label): 

1656 name = "anon_1" 

1657 

1658 return name 

1659 

1660 @util.ro_non_memoized_property 

1661 def implicit_returning(self) -> bool: 

1662 return self.element.implicit_returning # type: ignore 

1663 

1664 @property 

1665 def original(self) -> ReturnsRows: 

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

1667 return self.element 

1668 

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

1670 if fromclause in self._cloned_set: 

1671 return True 

1672 return self.element.is_derived_from(fromclause) 

1673 

1674 def _copy_internals( 

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

1676 ) -> None: 

1677 existing_element = self.element 

1678 

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

1680 

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

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

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

1684 # performance. 

1685 if existing_element is not self.element: 

1686 self._reset_column_collection() 

1687 

1688 @property 

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

1690 return [self] 

1691 

1692 

1693class FromClauseAlias(AliasedReturnsRows): 

1694 element: FromClause 

1695 

1696 

1697class Alias(roles.DMLTableRole, FromClauseAlias): 

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

1699 

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

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

1702 without the keyword on certain databases such as Oracle). 

1703 

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

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

1706 method available 

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

1708 

1709 .. seealso:: 

1710 

1711 :meth:`_expression.FromClause.alias` 

1712 

1713 """ 

1714 

1715 __visit_name__ = "alias" 

1716 

1717 inherit_cache = True 

1718 

1719 element: FromClause 

1720 

1721 @classmethod 

1722 def _factory( 

1723 cls, 

1724 selectable: FromClause, 

1725 name: Optional[str] = None, 

1726 flat: bool = False, 

1727 ) -> NamedFromClause: 

1728 return coercions.expect( 

1729 roles.FromClauseRole, selectable, allow_select=True 

1730 ).alias(name=name, flat=flat) 

1731 

1732 

1733class TableValuedAlias(LateralFromClause, Alias): 

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

1735 

1736 This construct provides for a SQL function that returns columns 

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

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

1739 method, e.g.: 

1740 

1741 .. sourcecode:: pycon+sql 

1742 

1743 >>> from sqlalchemy import select, func 

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

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

1746 {printsql}SELECT anon_1.value 

1747 FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1 

1748 

1749 .. versionadded:: 1.4.0b2 

1750 

1751 .. seealso:: 

1752 

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

1754 

1755 """ # noqa: E501 

1756 

1757 __visit_name__ = "table_valued_alias" 

1758 

1759 _supports_derived_columns = True 

1760 _render_derived = False 

1761 _render_derived_w_types = False 

1762 joins_implicitly = False 

1763 

1764 _traverse_internals: _TraverseInternalsType = [ 

1765 ("element", InternalTraversal.dp_clauseelement), 

1766 ("name", InternalTraversal.dp_anon_name), 

1767 ("_tableval_type", InternalTraversal.dp_type), 

1768 ("_render_derived", InternalTraversal.dp_boolean), 

1769 ("_render_derived_w_types", InternalTraversal.dp_boolean), 

1770 ] 

1771 

1772 def _init( 

1773 self, 

1774 selectable: Any, 

1775 *, 

1776 name: Optional[str] = None, 

1777 table_value_type: Optional[TableValueType] = None, 

1778 joins_implicitly: bool = False, 

1779 ) -> None: 

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

1781 

1782 self.joins_implicitly = joins_implicitly 

1783 self._tableval_type = ( 

1784 type_api.TABLEVALUE 

1785 if table_value_type is None 

1786 else table_value_type 

1787 ) 

1788 

1789 @HasMemoized.memoized_attribute 

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

1791 """Return a column expression representing this 

1792 :class:`_sql.TableValuedAlias`. 

1793 

1794 This accessor is used to implement the 

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

1796 method for further details. 

1797 

1798 E.g.: 

1799 

1800 .. sourcecode:: pycon+sql 

1801 

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

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

1804 

1805 .. seealso:: 

1806 

1807 :meth:`_functions.FunctionElement.column_valued` 

1808 

1809 """ 

1810 

1811 return TableValuedColumn(self, self._tableval_type) 

1812 

1813 def alias( 

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

1815 ) -> TableValuedAlias: 

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

1817 

1818 This creates a distinct FROM object that will be distinguished 

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

1820 

1821 """ 

1822 

1823 tva: TableValuedAlias = TableValuedAlias._construct( 

1824 self, 

1825 name=name, 

1826 table_value_type=self._tableval_type, 

1827 joins_implicitly=self.joins_implicitly, 

1828 ) 

1829 

1830 if self._render_derived: 

1831 tva._render_derived = True 

1832 tva._render_derived_w_types = self._render_derived_w_types 

1833 

1834 return tva 

1835 

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

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

1838 set, so that it renders as LATERAL. 

1839 

1840 .. seealso:: 

1841 

1842 :func:`_expression.lateral` 

1843 

1844 """ 

1845 tva = self.alias(name=name) 

1846 tva._is_lateral = True 

1847 return tva 

1848 

1849 def render_derived( 

1850 self, 

1851 name: Optional[str] = None, 

1852 with_types: bool = False, 

1853 ) -> TableValuedAlias: 

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

1855 

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

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

1858 

1859 .. sourcecode:: pycon+sql 

1860 

1861 >>> print( 

1862 ... select( 

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

1864 table_valued("x", with_ordinality="o").render_derived() 

1865 ... ) 

1866 ... ) 

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

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

1869 

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

1871 the alias expression (this syntax currently applies to the 

1872 PostgreSQL database): 

1873 

1874 .. sourcecode:: pycon+sql 

1875 

1876 >>> print( 

1877 ... select( 

1878 ... func.json_to_recordset( 

1879 ... '[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]' 

1880 ... ) 

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

1882 ... .render_derived(with_types=True) 

1883 ... ) 

1884 ... ) 

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

1886 AS anon_1(a INTEGER, b VARCHAR) 

1887 

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

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

1890 

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

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

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

1894 

1895 """ # noqa: E501 

1896 

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

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

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

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

1901 # (just saw it happen on CI) 

1902 

1903 # construct against original to prevent memory growth 

1904 # for repeated generations 

1905 new_alias: TableValuedAlias = TableValuedAlias._construct( 

1906 self.element, 

1907 name=name, 

1908 table_value_type=self._tableval_type, 

1909 joins_implicitly=self.joins_implicitly, 

1910 ) 

1911 new_alias._render_derived = True 

1912 new_alias._render_derived_w_types = with_types 

1913 return new_alias 

1914 

1915 

1916class Lateral(FromClauseAlias, LateralFromClause): 

1917 """Represent a LATERAL subquery. 

1918 

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

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

1921 method available 

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

1923 

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

1925 PostgreSQL versions provide support for this keyword. 

1926 

1927 .. seealso:: 

1928 

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

1930 

1931 """ 

1932 

1933 __visit_name__ = "lateral" 

1934 _is_lateral = True 

1935 

1936 inherit_cache = True 

1937 

1938 @classmethod 

1939 def _factory( 

1940 cls, 

1941 selectable: Union[SelectBase, _FromClauseArgument], 

1942 name: Optional[str] = None, 

1943 ) -> LateralFromClause: 

1944 return coercions.expect( 

1945 roles.FromClauseRole, selectable, explicit_subquery=True 

1946 ).lateral(name=name) 

1947 

1948 

1949class TableSample(FromClauseAlias): 

1950 """Represent a TABLESAMPLE clause. 

1951 

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

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

1954 method 

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

1956 

1957 .. seealso:: 

1958 

1959 :func:`_expression.tablesample` 

1960 

1961 """ 

1962 

1963 __visit_name__ = "tablesample" 

1964 

1965 _traverse_internals: _TraverseInternalsType = ( 

1966 AliasedReturnsRows._traverse_internals 

1967 + [ 

1968 ("sampling", InternalTraversal.dp_clauseelement), 

1969 ("seed", InternalTraversal.dp_clauseelement), 

1970 ] 

1971 ) 

1972 

1973 @classmethod 

1974 def _factory( 

1975 cls, 

1976 selectable: _FromClauseArgument, 

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

1978 name: Optional[str] = None, 

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

1980 ) -> TableSample: 

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

1982 sampling, name=name, seed=seed 

1983 ) 

1984 

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

1986 def _init( # type: ignore[override] 

1987 self, 

1988 selectable: Any, 

1989 *, 

1990 name: Optional[str] = None, 

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

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

1993 ) -> None: 

1994 assert sampling is not None 

1995 functions = util.preloaded.sql_functions 

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

1997 sampling = functions.func.system(sampling) 

1998 

1999 self.sampling: Function[Any] = sampling 

2000 self.seed = seed 

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

2002 

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

2004 return self.sampling 

2005 

2006 

2007class CTE( 

2008 roles.DMLTableRole, 

2009 roles.IsCTERole, 

2010 Generative, 

2011 HasPrefixes, 

2012 HasSuffixes, 

2013 AliasedReturnsRows, 

2014): 

2015 """Represent a Common Table Expression. 

2016 

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

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

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

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

2021 :class:`_sql.Update` and 

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

2023 usage details on CTEs. 

2024 

2025 .. seealso:: 

2026 

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

2028 

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

2030 

2031 """ 

2032 

2033 __visit_name__ = "cte" 

2034 

2035 _traverse_internals: _TraverseInternalsType = ( 

2036 AliasedReturnsRows._traverse_internals 

2037 + [ 

2038 ("_cte_alias", InternalTraversal.dp_clauseelement), 

2039 ("_restates", InternalTraversal.dp_clauseelement), 

2040 ("recursive", InternalTraversal.dp_boolean), 

2041 ("nesting", InternalTraversal.dp_boolean), 

2042 ] 

2043 + HasPrefixes._has_prefixes_traverse_internals 

2044 + HasSuffixes._has_suffixes_traverse_internals 

2045 ) 

2046 

2047 element: HasCTE 

2048 

2049 @classmethod 

2050 def _factory( 

2051 cls, 

2052 selectable: HasCTE, 

2053 name: Optional[str] = None, 

2054 recursive: bool = False, 

2055 ) -> CTE: 

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

2057 or Common Table Expression instance. 

2058 

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

2060 

2061 """ 

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

2063 name=name, recursive=recursive 

2064 ) 

2065 

2066 def _init( 

2067 self, 

2068 selectable: Select[Unpack[TupleAny]], 

2069 *, 

2070 name: Optional[str] = None, 

2071 recursive: bool = False, 

2072 nesting: bool = False, 

2073 _cte_alias: Optional[CTE] = None, 

2074 _restates: Optional[CTE] = None, 

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

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

2077 ) -> None: 

2078 self.recursive = recursive 

2079 self.nesting = nesting 

2080 self._cte_alias = _cte_alias 

2081 # Keep recursivity reference with union/union_all 

2082 self._restates = _restates 

2083 if _prefixes: 

2084 self._prefixes = _prefixes 

2085 if _suffixes: 

2086 self._suffixes = _suffixes 

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

2088 

2089 def _populate_column_collection(self) -> None: 

2090 if self._cte_alias is not None: 

2091 self._cte_alias._generate_fromclause_column_proxies(self) 

2092 else: 

2093 self.element._generate_fromclause_column_proxies(self) 

2094 

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

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

2097 :class:`_expression.CTE`. 

2098 

2099 This method is a CTE-specific specialization of the 

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

2101 

2102 .. seealso:: 

2103 

2104 :ref:`tutorial_using_aliases` 

2105 

2106 :func:`_expression.alias` 

2107 

2108 """ 

2109 return CTE._construct( 

2110 self.element, 

2111 name=name, 

2112 recursive=self.recursive, 

2113 nesting=self.nesting, 

2114 _cte_alias=self, 

2115 _prefixes=self._prefixes, 

2116 _suffixes=self._suffixes, 

2117 ) 

2118 

2119 def union(self, *other: _SelectStatementForCompoundArgument) -> CTE: 

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

2121 of the original CTE against the given selectables provided 

2122 as positional arguments. 

2123 

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

2125 UNION. 

2126 

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

2128 

2129 .. seealso:: 

2130 

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

2132 

2133 """ 

2134 assert is_select_statement( 

2135 self.element 

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

2137 

2138 return CTE._construct( 

2139 self.element.union(*other), 

2140 name=self.name, 

2141 recursive=self.recursive, 

2142 nesting=self.nesting, 

2143 _restates=self, 

2144 _prefixes=self._prefixes, 

2145 _suffixes=self._suffixes, 

2146 ) 

2147 

2148 def union_all(self, *other: _SelectStatementForCompoundArgument) -> CTE: 

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

2150 of the original CTE against the given selectables provided 

2151 as positional arguments. 

2152 

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

2154 UNION. 

2155 

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

2157 

2158 .. seealso:: 

2159 

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

2161 

2162 """ 

2163 

2164 assert is_select_statement( 

2165 self.element 

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

2167 

2168 return CTE._construct( 

2169 self.element.union_all(*other), 

2170 name=self.name, 

2171 recursive=self.recursive, 

2172 nesting=self.nesting, 

2173 _restates=self, 

2174 _prefixes=self._prefixes, 

2175 _suffixes=self._suffixes, 

2176 ) 

2177 

2178 def _get_reference_cte(self) -> CTE: 

2179 """ 

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

2181 Updated CTEs should still refer to the original CTE. 

2182 This function returns this reference identifier. 

2183 """ 

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

2185 

2186 

2187class _CTEOpts(NamedTuple): 

2188 nesting: bool 

2189 

2190 

2191class _ColumnsPlusNames(NamedTuple): 

2192 required_label_name: Optional[str] 

2193 """ 

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

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

2196 """ 

2197 

2198 proxy_key: Optional[str] 

2199 """ 

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

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

2202 select.selected_columns collection 

2203 """ 

2204 

2205 fallback_label_name: Optional[str] 

2206 """ 

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

2208 we have to render a label even though 

2209 required_label_name was not given 

2210 """ 

2211 

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

2213 """ 

2214 the ColumnElement itself 

2215 """ 

2216 

2217 repeated: bool 

2218 """ 

2219 True if this is a duplicate of a previous column 

2220 in the list of columns 

2221 """ 

2222 

2223 

2224class SelectsRows(ReturnsRows): 

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

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

2227 

2228 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

2229 

2230 def _generate_columns_plus_names( 

2231 self, 

2232 anon_for_dupe_key: bool, 

2233 cols: Optional[_SelectIterable] = None, 

2234 ) -> List[_ColumnsPlusNames]: 

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

2236 the compiler. 

2237 

2238 This is distinct from the _column_naming_convention generator that's 

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

2240 different rules. the collection returned here calls upon the 

2241 _column_naming_convention as well. 

2242 

2243 """ 

2244 

2245 if cols is None: 

2246 cols = self._all_selected_columns 

2247 

2248 key_naming_convention = SelectState._column_naming_convention( 

2249 self._label_style 

2250 ) 

2251 

2252 names = {} 

2253 

2254 result: List[_ColumnsPlusNames] = [] 

2255 result_append = result.append 

2256 

2257 table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

2258 label_style_none = self._label_style is LABEL_STYLE_NONE 

2259 

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

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

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

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

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

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

2266 dedupe_hash = 1 

2267 

2268 for c in cols: 

2269 repeated = False 

2270 

2271 if not c._render_label_in_columns_clause: 

2272 effective_name = required_label_name = fallback_label_name = ( 

2273 None 

2274 ) 

2275 elif label_style_none: 

2276 if TYPE_CHECKING: 

2277 assert is_column_element(c) 

2278 

2279 effective_name = required_label_name = None 

2280 fallback_label_name = c._non_anon_label or c._anon_name_label 

2281 else: 

2282 if TYPE_CHECKING: 

2283 assert is_column_element(c) 

2284 

2285 if table_qualified: 

2286 required_label_name = effective_name = ( 

2287 fallback_label_name 

2288 ) = c._tq_label 

2289 else: 

2290 effective_name = fallback_label_name = c._non_anon_label 

2291 required_label_name = None 

2292 

2293 if effective_name is None: 

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

2295 # not need _expression_label but it isn't 

2296 # giving us a clue when to use anon_label instead 

2297 expr_label = c._expression_label 

2298 if expr_label is None: 

2299 repeated = c._anon_name_label in names 

2300 names[c._anon_name_label] = c 

2301 effective_name = required_label_name = None 

2302 

2303 if repeated: 

2304 # here, "required_label_name" is sent as 

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

2306 if table_qualified: 

2307 fallback_label_name = ( 

2308 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2309 ) 

2310 dedupe_hash += 1 

2311 else: 

2312 fallback_label_name = c._dedupe_anon_label_idx( 

2313 dedupe_hash 

2314 ) 

2315 dedupe_hash += 1 

2316 else: 

2317 fallback_label_name = c._anon_name_label 

2318 else: 

2319 required_label_name = effective_name = ( 

2320 fallback_label_name 

2321 ) = expr_label 

2322 

2323 if effective_name is not None: 

2324 if TYPE_CHECKING: 

2325 assert is_column_element(c) 

2326 

2327 if effective_name in names: 

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

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

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

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

2332 # different column under the same name. apply 

2333 # disambiguating label 

2334 if table_qualified: 

2335 required_label_name = fallback_label_name = ( 

2336 c._anon_tq_label 

2337 ) 

2338 else: 

2339 required_label_name = fallback_label_name = ( 

2340 c._anon_name_label 

2341 ) 

2342 

2343 if anon_for_dupe_key and required_label_name in names: 

2344 # here, c._anon_tq_label is definitely unique to 

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

2346 # this should always be true. 

2347 # this is also an infrequent codepath because 

2348 # you need two levels of duplication to be here 

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

2350 

2351 # the column under the disambiguating label is 

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

2353 # subsequent occurrences of the column so that the 

2354 # original stays non-ambiguous 

2355 if table_qualified: 

2356 required_label_name = fallback_label_name = ( 

2357 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2358 ) 

2359 dedupe_hash += 1 

2360 else: 

2361 required_label_name = fallback_label_name = ( 

2362 c._dedupe_anon_label_idx(dedupe_hash) 

2363 ) 

2364 dedupe_hash += 1 

2365 repeated = True 

2366 else: 

2367 names[required_label_name] = c 

2368 elif anon_for_dupe_key: 

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

2370 # label so that the original stays non-ambiguous 

2371 if table_qualified: 

2372 required_label_name = fallback_label_name = ( 

2373 c._dedupe_anon_tq_label_idx(dedupe_hash) 

2374 ) 

2375 dedupe_hash += 1 

2376 else: 

2377 required_label_name = fallback_label_name = ( 

2378 c._dedupe_anon_label_idx(dedupe_hash) 

2379 ) 

2380 dedupe_hash += 1 

2381 repeated = True 

2382 else: 

2383 names[effective_name] = c 

2384 

2385 result_append( 

2386 _ColumnsPlusNames( 

2387 required_label_name, 

2388 key_naming_convention(c), 

2389 fallback_label_name, 

2390 c, 

2391 repeated, 

2392 ) 

2393 ) 

2394 

2395 return result 

2396 

2397 

2398class HasCTE(roles.HasCTERole, SelectsRows): 

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

2400 

2401 _has_ctes_traverse_internals: _TraverseInternalsType = [ 

2402 ("_independent_ctes", InternalTraversal.dp_clauseelement_list), 

2403 ("_independent_ctes_opts", InternalTraversal.dp_plain_obj), 

2404 ] 

2405 

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

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

2408 

2409 @_generative 

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

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

2412 

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

2414 the parent statement such that they will each be unconditionally 

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

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

2417 

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

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

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

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

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

2423 statement. 

2424 

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

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

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

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

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

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

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

2432 larger statement. 

2433 

2434 E.g.:: 

2435 

2436 from sqlalchemy import table, column, select 

2437 t = table('t', column('c1'), column('c2')) 

2438 

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

2440 

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

2442 

2443 Would render:: 

2444 

2445 WITH anon_1 AS 

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

2447 SELECT t.c1, t.c2 

2448 FROM t 

2449 

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

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

2452 statement. 

2453 

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

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

2456 

2457 from sqlalchemy import table, column 

2458 from sqlalchemy.dialects.postgresql import insert 

2459 

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

2461 

2462 delete_statement_cte = ( 

2463 t.delete().where(t.c.c1 < 1).cte("deletions") 

2464 ) 

2465 

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

2467 update_statement = insert_stmt.on_conflict_do_update( 

2468 index_elements=[t.c.c1], 

2469 set_={ 

2470 "c1": insert_stmt.excluded.c1, 

2471 "c2": insert_stmt.excluded.c2, 

2472 }, 

2473 ).add_cte(delete_statement_cte) 

2474 

2475 print(update_statement) 

2476 

2477 The above statement renders as:: 

2478 

2479 WITH deletions AS 

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

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

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

2483 

2484 .. versionadded:: 1.4.21 

2485 

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

2487 

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

2489 

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

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

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

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

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

2495 this statement when this flag is given. 

2496 

2497 .. versionadded:: 2.0 

2498 

2499 .. seealso:: 

2500 

2501 :paramref:`.HasCTE.cte.nesting` 

2502 

2503 

2504 """ 

2505 opt = _CTEOpts( 

2506 nest_here, 

2507 ) 

2508 for cte in ctes: 

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

2510 self._independent_ctes += (cte,) 

2511 self._independent_ctes_opts += (opt,) 

2512 return self 

2513 

2514 def cte( 

2515 self, 

2516 name: Optional[str] = None, 

2517 recursive: bool = False, 

2518 nesting: bool = False, 

2519 ) -> CTE: 

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

2521 or Common Table Expression instance. 

2522 

2523 Common table expressions are a SQL standard whereby SELECT 

2524 statements can draw upon secondary statements specified along 

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

2526 Special semantics regarding UNION can also be employed to 

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

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

2529 

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

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

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

2533 CTE rows. 

2534 

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

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

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

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

2539 

2540 For special prefixes such as PostgreSQL "MATERIALIZED" and 

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

2542 method may be 

2543 used to establish these. 

2544 

2545 .. versionchanged:: 1.3.13 Added support for prefixes. 

2546 In particular - MATERIALIZED and NOT MATERIALIZED. 

2547 

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

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

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

2551 compile time. 

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

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

2554 conjunction with UNION ALL in order to derive rows 

2555 from those already selected. 

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

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

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

2559 :paramref:`.HasCTE.add_cte.nest_here` 

2560 parameter may also be used to more carefully 

2561 control the exact placement of a particular CTE. 

2562 

2563 .. versionadded:: 1.4.24 

2564 

2565 .. seealso:: 

2566 

2567 :meth:`.HasCTE.add_cte` 

2568 

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

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

2571 as well as additional examples. 

2572 

2573 Example 1, non recursive:: 

2574 

2575 from sqlalchemy import (Table, Column, String, Integer, 

2576 MetaData, select, func) 

2577 

2578 metadata = MetaData() 

2579 

2580 orders = Table('orders', metadata, 

2581 Column('region', String), 

2582 Column('amount', Integer), 

2583 Column('product', String), 

2584 Column('quantity', Integer) 

2585 ) 

2586 

2587 regional_sales = select( 

2588 orders.c.region, 

2589 func.sum(orders.c.amount).label('total_sales') 

2590 ).group_by(orders.c.region).cte("regional_sales") 

2591 

2592 

2593 top_regions = select(regional_sales.c.region).\ 

2594 where( 

2595 regional_sales.c.total_sales > 

2596 select( 

2597 func.sum(regional_sales.c.total_sales) / 10 

2598 ) 

2599 ).cte("top_regions") 

2600 

2601 statement = select( 

2602 orders.c.region, 

2603 orders.c.product, 

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

2605 func.sum(orders.c.amount).label("product_sales") 

2606 ).where(orders.c.region.in_( 

2607 select(top_regions.c.region) 

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

2609 

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

2611 

2612 Example 2, WITH RECURSIVE:: 

2613 

2614 from sqlalchemy import (Table, Column, String, Integer, 

2615 MetaData, select, func) 

2616 

2617 metadata = MetaData() 

2618 

2619 parts = Table('parts', metadata, 

2620 Column('part', String), 

2621 Column('sub_part', String), 

2622 Column('quantity', Integer), 

2623 ) 

2624 

2625 included_parts = select(\ 

2626 parts.c.sub_part, parts.c.part, parts.c.quantity\ 

2627 ).\ 

2628 where(parts.c.part=='our part').\ 

2629 cte(recursive=True) 

2630 

2631 

2632 incl_alias = included_parts.alias() 

2633 parts_alias = parts.alias() 

2634 included_parts = included_parts.union_all( 

2635 select( 

2636 parts_alias.c.sub_part, 

2637 parts_alias.c.part, 

2638 parts_alias.c.quantity 

2639 ).\ 

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

2641 ) 

2642 

2643 statement = select( 

2644 included_parts.c.sub_part, 

2645 func.sum(included_parts.c.quantity). 

2646 label('total_quantity') 

2647 ).\ 

2648 group_by(included_parts.c.sub_part) 

2649 

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

2651 

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

2653 

2654 from datetime import date 

2655 from sqlalchemy import (MetaData, Table, Column, Integer, 

2656 Date, select, literal, and_, exists) 

2657 

2658 metadata = MetaData() 

2659 

2660 visitors = Table('visitors', metadata, 

2661 Column('product_id', Integer, primary_key=True), 

2662 Column('date', Date, primary_key=True), 

2663 Column('count', Integer), 

2664 ) 

2665 

2666 # add 5 visitors for the product_id == 1 

2667 product_id = 1 

2668 day = date.today() 

2669 count = 5 

2670 

2671 update_cte = ( 

2672 visitors.update() 

2673 .where(and_(visitors.c.product_id == product_id, 

2674 visitors.c.date == day)) 

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

2676 .returning(literal(1)) 

2677 .cte('update_cte') 

2678 ) 

2679 

2680 upsert = visitors.insert().from_select( 

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

2682 select(literal(product_id), literal(day), literal(count)) 

2683 .where(~exists(update_cte.select())) 

2684 ) 

2685 

2686 connection.execute(upsert) 

2687 

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

2689 

2690 value_a = select( 

2691 literal("root").label("n") 

2692 ).cte("value_a") 

2693 

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

2695 value_a_nested = select( 

2696 literal("nesting").label("n") 

2697 ).cte("value_a", nesting=True) 

2698 

2699 # Nesting CTEs takes ascendency locally 

2700 # over the CTEs at a higher level 

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

2702 

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

2704 

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

2706 shown with inline parameters below as:: 

2707 

2708 WITH 

2709 value_a AS 

2710 (SELECT 'root' AS n), 

2711 value_b AS 

2712 (WITH value_a AS 

2713 (SELECT 'nesting' AS n) 

2714 SELECT value_a.n AS n FROM value_a) 

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

2716 FROM value_a, value_b 

2717 

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

2719 as follows (SQLAlchemy 2.0 and above):: 

2720 

2721 value_a = select( 

2722 literal("root").label("n") 

2723 ).cte("value_a") 

2724 

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

2726 value_a_nested = select( 

2727 literal("nesting").label("n") 

2728 ).cte("value_a") 

2729 

2730 # Nesting CTEs takes ascendency locally 

2731 # over the CTEs at a higher level 

2732 value_b = ( 

2733 select(value_a_nested.c.n). 

2734 add_cte(value_a_nested, nest_here=True). 

2735 cte("value_b") 

2736 ) 

2737 

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

2739 

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

2741 

2742 edge = Table( 

2743 "edge", 

2744 metadata, 

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

2746 Column("left", Integer), 

2747 Column("right", Integer), 

2748 ) 

2749 

2750 root_node = select(literal(1).label("node")).cte( 

2751 "nodes", recursive=True 

2752 ) 

2753 

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

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

2756 ) 

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

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

2759 ) 

2760 

2761 subgraph_cte = root_node.union(left_edge, right_edge) 

2762 

2763 subgraph = select(subgraph_cte) 

2764 

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

2766 

2767 WITH RECURSIVE nodes(node) AS ( 

2768 SELECT 1 AS node 

2769 UNION 

2770 SELECT edge."left" AS "left" 

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

2772 UNION 

2773 SELECT edge."right" AS "right" 

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

2775 ) 

2776 SELECT nodes.node FROM nodes 

2777 

2778 .. seealso:: 

2779 

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

2781 :meth:`_expression.HasCTE.cte`. 

2782 

2783 """ 

2784 return CTE._construct( 

2785 self, name=name, recursive=recursive, nesting=nesting 

2786 ) 

2787 

2788 

2789class Subquery(AliasedReturnsRows): 

2790 """Represent a subquery of a SELECT. 

2791 

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

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

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

2795 :class:`_expression.SelectBase` subclass 

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

2797 :class:`_expression.CompoundSelect`, and 

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

2799 it represents the 

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

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

2802 

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

2804 :class:`_expression.Alias` 

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

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

2807 :class:`_expression.Alias` always 

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

2809 :class:`.Subquery` 

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

2811 

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

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

2814 statement. 

2815 

2816 """ 

2817 

2818 __visit_name__ = "subquery" 

2819 

2820 _is_subquery = True 

2821 

2822 inherit_cache = True 

2823 

2824 element: SelectBase 

2825 

2826 @classmethod 

2827 def _factory( 

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

2829 ) -> Subquery: 

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

2831 

2832 return coercions.expect( 

2833 roles.SelectStatementRole, selectable 

2834 ).subquery(name=name) 

2835 

2836 @util.deprecated( 

2837 "1.4", 

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

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

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

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

2842 ":func:`_expression.select` " 

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

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

2845 ) 

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

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

2848 

2849 

2850class FromGrouping(GroupedElement, FromClause): 

2851 """Represent a grouping of a FROM clause""" 

2852 

2853 _traverse_internals: _TraverseInternalsType = [ 

2854 ("element", InternalTraversal.dp_clauseelement) 

2855 ] 

2856 

2857 element: FromClause 

2858 

2859 def __init__(self, element: FromClause): 

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

2861 

2862 def _init_collections(self) -> None: 

2863 pass 

2864 

2865 @util.ro_non_memoized_property 

2866 def columns( 

2867 self, 

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

2869 return self.element.columns 

2870 

2871 @util.ro_non_memoized_property 

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

2873 return self.element.columns 

2874 

2875 @property 

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

2877 return self.element.primary_key 

2878 

2879 @property 

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

2881 return self.element.foreign_keys 

2882 

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

2884 return self.element.is_derived_from(fromclause) 

2885 

2886 def alias( 

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

2888 ) -> NamedFromGrouping: 

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

2890 

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

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

2893 

2894 @util.ro_non_memoized_property 

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

2896 return self.element._hide_froms 

2897 

2898 @util.ro_non_memoized_property 

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

2900 return self.element._from_objects 

2901 

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

2903 return {"element": self.element} 

2904 

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

2906 self.element = state["element"] 

2907 

2908 if TYPE_CHECKING: 

2909 

2910 def self_group( 

2911 self, against: Optional[OperatorType] = None 

2912 ) -> Self: ... 

2913 

2914 

2915class NamedFromGrouping(FromGrouping, NamedFromClause): 

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

2917 

2918 .. versionadded:: 2.0 

2919 

2920 """ 

2921 

2922 inherit_cache = True 

2923 

2924 if TYPE_CHECKING: 

2925 

2926 def self_group( 

2927 self, against: Optional[OperatorType] = None 

2928 ) -> Self: ... 

2929 

2930 

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

2932 """Represents a minimal "table" construct. 

2933 

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

2935 collection of columns, which are typically produced 

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

2937 

2938 from sqlalchemy import table, column 

2939 

2940 user = table("user", 

2941 column("id"), 

2942 column("name"), 

2943 column("description"), 

2944 ) 

2945 

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

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

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

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

2950 

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

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

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

2954 It's useful 

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

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

2957 is not on hand. 

2958 

2959 """ 

2960 

2961 __visit_name__ = "table" 

2962 

2963 _traverse_internals: _TraverseInternalsType = [ 

2964 ( 

2965 "columns", 

2966 InternalTraversal.dp_fromclause_canonical_column_collection, 

2967 ), 

2968 ("name", InternalTraversal.dp_string), 

2969 ("schema", InternalTraversal.dp_string), 

2970 ] 

2971 

2972 _is_table = True 

2973 

2974 fullname: str 

2975 

2976 implicit_returning = False 

2977 """:class:`_expression.TableClause` 

2978 doesn't support having a primary key or column 

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

2980 

2981 @util.ro_memoized_property 

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

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

2984 return None 

2985 

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

2987 super().__init__() 

2988 self.name = name 

2989 self._columns = DedupeColumnCollection() 

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

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

2992 for c in columns: 

2993 self.append_column(c) 

2994 

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

2996 if schema is not None: 

2997 self.schema = schema 

2998 if self.schema is not None: 

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

3000 else: 

3001 self.fullname = self.name 

3002 if kw: 

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

3004 

3005 if TYPE_CHECKING: 

3006 

3007 @util.ro_non_memoized_property 

3008 def columns( 

3009 self, 

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

3011 

3012 @util.ro_non_memoized_property 

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

3014 

3015 def __str__(self) -> str: 

3016 if self.schema is not None: 

3017 return self.schema + "." + self.name 

3018 else: 

3019 return self.name 

3020 

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

3022 pass 

3023 

3024 def _init_collections(self) -> None: 

3025 pass 

3026 

3027 @util.ro_memoized_property 

3028 def description(self) -> str: 

3029 return self.name 

3030 

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

3032 existing = c.table 

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

3034 raise exc.ArgumentError( 

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

3036 % (c.key, existing) 

3037 ) 

3038 

3039 self._columns.add(c) 

3040 c.table = self 

3041 

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

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

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

3045 :class:`_expression.TableClause`. 

3046 

3047 E.g.:: 

3048 

3049 table.insert().values(name='foo') 

3050 

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

3052 

3053 """ 

3054 

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

3056 

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

3058 def update(self) -> Update: 

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

3060 :class:`_expression.TableClause`. 

3061 

3062 E.g.:: 

3063 

3064 table.update().where(table.c.id==7).values(name='foo') 

3065 

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

3067 

3068 """ 

3069 return util.preloaded.sql_dml.Update( 

3070 self, 

3071 ) 

3072 

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

3074 def delete(self) -> Delete: 

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

3076 :class:`_expression.TableClause`. 

3077 

3078 E.g.:: 

3079 

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

3081 

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

3083 

3084 """ 

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

3086 

3087 @util.ro_non_memoized_property 

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

3089 return [self] 

3090 

3091 

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

3093 

3094 

3095class ForUpdateArg(ClauseElement): 

3096 _traverse_internals: _TraverseInternalsType = [ 

3097 ("of", InternalTraversal.dp_clauseelement_list), 

3098 ("nowait", InternalTraversal.dp_boolean), 

3099 ("read", InternalTraversal.dp_boolean), 

3100 ("skip_locked", InternalTraversal.dp_boolean), 

3101 ("key_share", InternalTraversal.dp_boolean), 

3102 ] 

3103 

3104 of: Optional[Sequence[ClauseElement]] 

3105 nowait: bool 

3106 read: bool 

3107 skip_locked: bool 

3108 

3109 @classmethod 

3110 def _from_argument( 

3111 cls, with_for_update: ForUpdateParameter 

3112 ) -> Optional[ForUpdateArg]: 

3113 if isinstance(with_for_update, ForUpdateArg): 

3114 return with_for_update 

3115 elif with_for_update in (None, False): 

3116 return None 

3117 elif with_for_update is True: 

3118 return ForUpdateArg() 

3119 else: 

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

3121 

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

3123 return ( 

3124 isinstance(other, ForUpdateArg) 

3125 and other.nowait == self.nowait 

3126 and other.read == self.read 

3127 and other.skip_locked == self.skip_locked 

3128 and other.key_share == self.key_share 

3129 and other.of is self.of 

3130 ) 

3131 

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

3133 return not self.__eq__(other) 

3134 

3135 def __hash__(self) -> int: 

3136 return id(self) 

3137 

3138 def __init__( 

3139 self, 

3140 *, 

3141 nowait: bool = False, 

3142 read: bool = False, 

3143 of: Optional[_ForUpdateOfArgument] = None, 

3144 skip_locked: bool = False, 

3145 key_share: bool = False, 

3146 ): 

3147 """Represents arguments specified to 

3148 :meth:`_expression.Select.for_update`. 

3149 

3150 """ 

3151 

3152 self.nowait = nowait 

3153 self.read = read 

3154 self.skip_locked = skip_locked 

3155 self.key_share = key_share 

3156 if of is not None: 

3157 self.of = [ 

3158 coercions.expect(roles.ColumnsClauseRole, elem) 

3159 for elem in util.to_list(of) 

3160 ] 

3161 else: 

3162 self.of = None 

3163 

3164 

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

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

3167 in a statement. 

3168 

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

3170 :func:`_expression.values` function. 

3171 

3172 .. versionadded:: 1.4 

3173 

3174 """ 

3175 

3176 __visit_name__ = "values" 

3177 

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

3179 

3180 _unnamed: bool 

3181 _traverse_internals: _TraverseInternalsType = [ 

3182 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3183 ("_data", InternalTraversal.dp_dml_multi_values), 

3184 ("name", InternalTraversal.dp_string), 

3185 ("literal_binds", InternalTraversal.dp_boolean), 

3186 ] 

3187 

3188 def __init__( 

3189 self, 

3190 *columns: ColumnClause[Any], 

3191 name: Optional[str] = None, 

3192 literal_binds: bool = False, 

3193 ): 

3194 super().__init__() 

3195 self._column_args = columns 

3196 

3197 if name is None: 

3198 self._unnamed = True 

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

3200 else: 

3201 self._unnamed = False 

3202 self.name = name 

3203 self.literal_binds = literal_binds 

3204 self.named_with_column = not self._unnamed 

3205 

3206 @property 

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

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

3209 

3210 @_generative 

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

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

3213 construct that is a copy of this 

3214 one with the given name. 

3215 

3216 This method is a VALUES-specific specialization of the 

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

3218 

3219 .. seealso:: 

3220 

3221 :ref:`tutorial_using_aliases` 

3222 

3223 :func:`_expression.alias` 

3224 

3225 """ 

3226 non_none_name: str 

3227 

3228 if name is None: 

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

3230 else: 

3231 non_none_name = name 

3232 

3233 self.name = non_none_name 

3234 self.named_with_column = True 

3235 self._unnamed = False 

3236 return self 

3237 

3238 @_generative 

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

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

3241 so that 

3242 it renders as LATERAL. 

3243 

3244 .. seealso:: 

3245 

3246 :func:`_expression.lateral` 

3247 

3248 """ 

3249 non_none_name: str 

3250 

3251 if name is None: 

3252 non_none_name = self.name 

3253 else: 

3254 non_none_name = name 

3255 

3256 self._is_lateral = True 

3257 self.name = non_none_name 

3258 self._unnamed = False 

3259 return self 

3260 

3261 @_generative 

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

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

3264 adding the given data to the data list. 

3265 

3266 E.g.:: 

3267 

3268 my_values = my_values.data([(1, 'value 1'), (2, 'value2')]) 

3269 

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

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

3272 constructor. 

3273 

3274 """ 

3275 

3276 self._data += (values,) 

3277 return self 

3278 

3279 def scalar_values(self) -> ScalarValues: 

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

3281 COLUMN element in a statement. 

3282 

3283 .. versionadded:: 2.0.0b4 

3284 

3285 """ 

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

3287 

3288 def _populate_column_collection(self) -> None: 

3289 for c in self._column_args: 

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

3291 _, c = c._make_proxy(self) 

3292 else: 

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

3294 # no memoizations of other FROM clauses. 

3295 # see test_values.py -> test_auto_proxy_select_direct_col 

3296 c._reset_memoizations() 

3297 self._columns.add(c) 

3298 c.table = self 

3299 

3300 @util.ro_non_memoized_property 

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

3302 return [self] 

3303 

3304 

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

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

3307 COLUMN element in a statement. 

3308 

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

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

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

3312 an ``IN`` or ``NOT IN`` condition. 

3313 

3314 .. versionadded:: 2.0.0b4 

3315 

3316 """ 

3317 

3318 __visit_name__ = "scalar_values" 

3319 

3320 _traverse_internals: _TraverseInternalsType = [ 

3321 ("_column_args", InternalTraversal.dp_clauseelement_list), 

3322 ("_data", InternalTraversal.dp_dml_multi_values), 

3323 ("literal_binds", InternalTraversal.dp_boolean), 

3324 ] 

3325 

3326 def __init__( 

3327 self, 

3328 columns: Sequence[ColumnClause[Any]], 

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

3330 literal_binds: bool, 

3331 ): 

3332 super().__init__() 

3333 self._column_args = columns 

3334 self._data = data 

3335 self.literal_binds = literal_binds 

3336 

3337 @property 

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

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

3340 

3341 def __clause_element__(self) -> ScalarValues: 

3342 return self 

3343 

3344 if TYPE_CHECKING: 

3345 

3346 def self_group( 

3347 self, against: Optional[OperatorType] = None 

3348 ) -> Self: ... 

3349 

3350 

3351class SelectBase( 

3352 roles.SelectStatementRole, 

3353 roles.DMLSelectRole, 

3354 roles.CompoundElementRole, 

3355 roles.InElementRole, 

3356 HasCTE, 

3357 SupportsCloneAnnotations, 

3358 Selectable, 

3359): 

3360 """Base class for SELECT statements. 

3361 

3362 

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

3364 :class:`_expression.CompoundSelect` and 

3365 :class:`_expression.TextualSelect`. 

3366 

3367 

3368 """ 

3369 

3370 _is_select_base = True 

3371 is_select = True 

3372 

3373 _label_style: SelectLabelStyle = LABEL_STYLE_NONE 

3374 

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

3376 self._reset_memoizations() 

3377 

3378 @util.ro_non_memoized_property 

3379 def selected_columns( 

3380 self, 

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

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

3383 representing the columns that 

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

3385 

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

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

3388 within this collection cannot be directly nested inside another SELECT 

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

3390 necessary parenthesization required by SQL. 

3391 

3392 .. note:: 

3393 

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

3395 include expressions established in the columns clause using the 

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

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

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

3399 construct. 

3400 

3401 .. seealso:: 

3402 

3403 :attr:`_sql.Select.selected_columns` 

3404 

3405 .. versionadded:: 1.4 

3406 

3407 """ 

3408 raise NotImplementedError() 

3409 

3410 def _generate_fromclause_column_proxies( 

3411 self, 

3412 subquery: FromClause, 

3413 *, 

3414 proxy_compound_columns: Optional[ 

3415 Iterable[Sequence[ColumnElement[Any]]] 

3416 ] = None, 

3417 ) -> None: 

3418 raise NotImplementedError() 

3419 

3420 @util.ro_non_memoized_property 

3421 def _all_selected_columns(self) -> _SelectIterable: 

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

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

3424 constructs. 

3425 

3426 .. versionadded:: 1.4.12 

3427 

3428 .. seealso:: 

3429 

3430 :attr:`_sql.SelectBase.exported_columns` 

3431 

3432 """ 

3433 raise NotImplementedError() 

3434 

3435 @property 

3436 def exported_columns( 

3437 self, 

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

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

3440 that represents the "exported" 

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

3442 :class:`_sql.TextClause` constructs. 

3443 

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

3445 object are synonymous 

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

3447 

3448 .. versionadded:: 1.4 

3449 

3450 .. seealso:: 

3451 

3452 :attr:`_expression.Select.exported_columns` 

3453 

3454 :attr:`_expression.Selectable.exported_columns` 

3455 

3456 :attr:`_expression.FromClause.exported_columns` 

3457 

3458 

3459 """ 

3460 return self.selected_columns.as_readonly() 

3461 

3462 @property 

3463 @util.deprecated( 

3464 "1.4", 

3465 "The :attr:`_expression.SelectBase.c` and " 

3466 ":attr:`_expression.SelectBase.columns` attributes " 

3467 "are deprecated and will be removed in a future release; these " 

3468 "attributes implicitly create a subquery that should be explicit. " 

3469 "Please call :meth:`_expression.SelectBase.subquery` " 

3470 "first in order to create " 

3471 "a subquery, which then contains this attribute. To access the " 

3472 "columns that this SELECT object SELECTs " 

3473 "from, use the :attr:`_expression.SelectBase.selected_columns` " 

3474 "attribute.", 

3475 ) 

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

3477 return self._implicit_subquery.columns 

3478 

3479 @property 

3480 def columns( 

3481 self, 

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

3483 return self.c 

3484 

3485 def get_label_style(self) -> SelectLabelStyle: 

3486 """ 

3487 Retrieve the current label style. 

3488 

3489 Implemented by subclasses. 

3490 

3491 """ 

3492 raise NotImplementedError() 

3493 

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

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

3496 

3497 Implemented by subclasses. 

3498 

3499 """ 

3500 

3501 raise NotImplementedError() 

3502 

3503 @util.deprecated( 

3504 "1.4", 

3505 "The :meth:`_expression.SelectBase.select` method is deprecated " 

3506 "and will be removed in a future release; this method implicitly " 

3507 "creates a subquery that should be explicit. " 

3508 "Please call :meth:`_expression.SelectBase.subquery` " 

3509 "first in order to create " 

3510 "a subquery, which then can be selected.", 

3511 ) 

3512 def select(self, *arg: Any, **kw: Any) -> Select[Unpack[TupleAny]]: 

3513 return self._implicit_subquery.select(*arg, **kw) 

3514 

3515 @HasMemoized.memoized_attribute 

3516 def _implicit_subquery(self) -> Subquery: 

3517 return self.subquery() 

3518 

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

3520 raise NotImplementedError() 

3521 

3522 @util.deprecated( 

3523 "1.4", 

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

3525 "method is deprecated and will be " 

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

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

3528 ) 

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

3530 return self.scalar_subquery() 

3531 

3532 def exists(self) -> Exists: 

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

3534 which can be used as a column expression. 

3535 

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

3537 

3538 .. seealso:: 

3539 

3540 :func:`_sql.exists` 

3541 

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

3543 

3544 .. versionadded:: 1.4 

3545 

3546 """ 

3547 return Exists(self) 

3548 

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

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

3551 used as a column expression. 

3552 

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

3554 

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

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

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

3558 an enclosing SELECT. 

3559 

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

3561 subquery that can be produced using the 

3562 :meth:`_expression.SelectBase.subquery` 

3563 method. 

3564 

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

3566 :meth:`_expression.SelectBase.scalar_subquery`. 

3567 

3568 .. seealso:: 

3569 

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

3571 

3572 """ 

3573 if self._label_style is not LABEL_STYLE_NONE: 

3574 self = self.set_label_style(LABEL_STYLE_NONE) 

3575 

3576 return ScalarSelect(self) 

3577 

3578 def label(self, name: Optional[str]) -> Label[Any]: 

3579 """Return a 'scalar' representation of this selectable, embedded as a 

3580 subquery with a label. 

3581 

3582 .. seealso:: 

3583 

3584 :meth:`_expression.SelectBase.scalar_subquery`. 

3585 

3586 """ 

3587 return self.scalar_subquery().label(name) 

3588 

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

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

3591 

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

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

3594 

3595 .. seealso:: 

3596 

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

3598 

3599 """ 

3600 return Lateral._factory(self, name) 

3601 

3602 def subquery(self, name: Optional[str] = None) -> Subquery: 

3603 """Return a subquery of this :class:`_expression.SelectBase`. 

3604 

3605 A subquery is from a SQL perspective a parenthesized, named 

3606 construct that can be placed in the FROM clause of another 

3607 SELECT statement. 

3608 

3609 Given a SELECT statement such as:: 

3610 

3611 stmt = select(table.c.id, table.c.name) 

3612 

3613 The above statement might look like:: 

3614 

3615 SELECT table.id, table.name FROM table 

3616 

3617 The subquery form by itself renders the same way, however when 

3618 embedded into the FROM clause of another SELECT statement, it becomes 

3619 a named sub-element:: 

3620 

3621 subq = stmt.subquery() 

3622 new_stmt = select(subq) 

3623 

3624 The above renders as:: 

3625 

3626 SELECT anon_1.id, anon_1.name 

3627 FROM (SELECT table.id, table.name FROM table) AS anon_1 

3628 

3629 Historically, :meth:`_expression.SelectBase.subquery` 

3630 is equivalent to calling 

3631 the :meth:`_expression.FromClause.alias` 

3632 method on a FROM object; however, 

3633 as a :class:`_expression.SelectBase` 

3634 object is not directly FROM object, 

3635 the :meth:`_expression.SelectBase.subquery` 

3636 method provides clearer semantics. 

3637 

3638 .. versionadded:: 1.4 

3639 

3640 """ 

3641 

3642 return Subquery._construct( 

3643 self._ensure_disambiguated_names(), name=name 

3644 ) 

3645 

3646 def _ensure_disambiguated_names(self) -> Self: 

3647 """Ensure that the names generated by this selectbase will be 

3648 disambiguated in some way, if possible. 

3649 

3650 """ 

3651 

3652 raise NotImplementedError() 

3653 

3654 def alias( 

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

3656 ) -> Subquery: 

3657 """Return a named subquery against this 

3658 :class:`_expression.SelectBase`. 

3659 

3660 For a :class:`_expression.SelectBase` (as opposed to a 

3661 :class:`_expression.FromClause`), 

3662 this returns a :class:`.Subquery` object which behaves mostly the 

3663 same as the :class:`_expression.Alias` object that is used with a 

3664 :class:`_expression.FromClause`. 

3665 

3666 .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias` 

3667 method is now 

3668 a synonym for the :meth:`_expression.SelectBase.subquery` method. 

3669 

3670 """ 

3671 return self.subquery(name=name) 

3672 

3673 

3674_SB = TypeVar("_SB", bound=SelectBase) 

3675 

3676 

3677class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]): 

3678 """Represent a grouping of a :class:`_expression.SelectBase`. 

3679 

3680 This differs from :class:`.Subquery` in that we are still 

3681 an "inner" SELECT statement, this is strictly for grouping inside of 

3682 compound selects. 

3683 

3684 """ 

3685 

3686 __visit_name__ = "select_statement_grouping" 

3687 _traverse_internals: _TraverseInternalsType = [ 

3688 ("element", InternalTraversal.dp_clauseelement) 

3689 ] 

3690 

3691 _is_select_container = True 

3692 

3693 element: _SB 

3694 

3695 def __init__(self, element: _SB) -> None: 

3696 self.element = cast( 

3697 _SB, coercions.expect(roles.SelectStatementRole, element) 

3698 ) 

3699 

3700 def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]: 

3701 new_element = self.element._ensure_disambiguated_names() 

3702 if new_element is not self.element: 

3703 return SelectStatementGrouping(new_element) 

3704 else: 

3705 return self 

3706 

3707 def get_label_style(self) -> SelectLabelStyle: 

3708 return self.element.get_label_style() 

3709 

3710 def set_label_style( 

3711 self, label_style: SelectLabelStyle 

3712 ) -> SelectStatementGrouping[_SB]: 

3713 return SelectStatementGrouping( 

3714 self.element.set_label_style(label_style) 

3715 ) 

3716 

3717 @property 

3718 def select_statement(self) -> _SB: 

3719 return self.element 

3720 

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

3722 return self 

3723 

3724 if TYPE_CHECKING: 

3725 

3726 def _ungroup(self) -> _SB: ... 

3727 

3728 # def _generate_columns_plus_names( 

3729 # self, anon_for_dupe_key: bool 

3730 # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]: 

3731 # return self.element._generate_columns_plus_names(anon_for_dupe_key) 

3732 

3733 def _generate_fromclause_column_proxies( 

3734 self, 

3735 subquery: FromClause, 

3736 *, 

3737 proxy_compound_columns: Optional[ 

3738 Iterable[Sequence[ColumnElement[Any]]] 

3739 ] = None, 

3740 ) -> None: 

3741 self.element._generate_fromclause_column_proxies( 

3742 subquery, proxy_compound_columns=proxy_compound_columns 

3743 ) 

3744 

3745 @util.ro_non_memoized_property 

3746 def _all_selected_columns(self) -> _SelectIterable: 

3747 return self.element._all_selected_columns 

3748 

3749 @util.ro_non_memoized_property 

3750 def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]: 

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

3752 representing the columns that 

3753 the embedded SELECT statement returns in its result set, not including 

3754 :class:`_sql.TextClause` constructs. 

3755 

3756 .. versionadded:: 1.4 

3757 

3758 .. seealso:: 

3759 

3760 :attr:`_sql.Select.selected_columns` 

3761 

3762 """ 

3763 return self.element.selected_columns 

3764 

3765 @util.ro_non_memoized_property 

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

3767 return self.element._from_objects 

3768 

3769 

3770class GenerativeSelect(SelectBase, Generative): 

3771 """Base class for SELECT statements where additional elements can be 

3772 added. 

3773 

3774 This serves as the base for :class:`_expression.Select` and 

3775 :class:`_expression.CompoundSelect` 

3776 where elements such as ORDER BY, GROUP BY can be added and column 

3777 rendering can be controlled. Compare to 

3778 :class:`_expression.TextualSelect`, which, 

3779 while it subclasses :class:`_expression.SelectBase` 

3780 and is also a SELECT construct, 

3781 represents a fixed textual string which cannot be altered at this level, 

3782 only wrapped as a subquery. 

3783 

3784 """ 

3785 

3786 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3787 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

3788 _limit_clause: Optional[ColumnElement[Any]] = None 

3789 _offset_clause: Optional[ColumnElement[Any]] = None 

3790 _fetch_clause: Optional[ColumnElement[Any]] = None 

3791 _fetch_clause_options: Optional[Dict[str, bool]] = None 

3792 _for_update_arg: Optional[ForUpdateArg] = None 

3793 

3794 def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT): 

3795 self._label_style = _label_style 

3796 

3797 @_generative 

3798 def with_for_update( 

3799 self, 

3800 *, 

3801 nowait: bool = False, 

3802 read: bool = False, 

3803 of: Optional[_ForUpdateOfArgument] = None, 

3804 skip_locked: bool = False, 

3805 key_share: bool = False, 

3806 ) -> Self: 

3807 """Specify a ``FOR UPDATE`` clause for this 

3808 :class:`_expression.GenerativeSelect`. 

3809 

3810 E.g.:: 

3811 

3812 stmt = select(table).with_for_update(nowait=True) 

3813 

3814 On a database like PostgreSQL or Oracle, the above would render a 

3815 statement like:: 

3816 

3817 SELECT table.a, table.b FROM table FOR UPDATE NOWAIT 

3818 

3819 on other backends, the ``nowait`` option is ignored and instead 

3820 would produce:: 

3821 

3822 SELECT table.a, table.b FROM table FOR UPDATE 

3823 

3824 When called with no arguments, the statement will render with 

3825 the suffix ``FOR UPDATE``. Additional arguments can then be 

3826 provided which allow for common database-specific 

3827 variants. 

3828 

3829 :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle 

3830 and PostgreSQL dialects. 

3831 

3832 :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL, 

3833 ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with 

3834 ``nowait``, will render ``FOR SHARE NOWAIT``. 

3835 

3836 :param of: SQL expression or list of SQL expression elements, 

3837 (typically :class:`_schema.Column` objects or a compatible expression, 

3838 for some backends may also be a table expression) which will render 

3839 into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle, some 

3840 MySQL versions and possibly others. May render as a table or as a 

3841 column depending on backend. 

3842 

3843 :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` 

3844 on Oracle and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` if 

3845 ``read=True`` is also specified. 

3846 

3847 :param key_share: boolean, will render ``FOR NO KEY UPDATE``, 

3848 or if combined with ``read=True`` will render ``FOR KEY SHARE``, 

3849 on the PostgreSQL dialect. 

3850 

3851 """ 

3852 self._for_update_arg = ForUpdateArg( 

3853 nowait=nowait, 

3854 read=read, 

3855 of=of, 

3856 skip_locked=skip_locked, 

3857 key_share=key_share, 

3858 ) 

3859 return self 

3860 

3861 def get_label_style(self) -> SelectLabelStyle: 

3862 """ 

3863 Retrieve the current label style. 

3864 

3865 .. versionadded:: 1.4 

3866 

3867 """ 

3868 return self._label_style 

3869 

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

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

3872 

3873 There are three "label styles" available, 

3874 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`, 

3875 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and 

3876 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is 

3877 :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`. 

3878 

3879 In modern SQLAlchemy, there is not generally a need to change the 

3880 labeling style, as per-expression labels are more effectively used by 

3881 making use of the :meth:`_sql.ColumnElement.label` method. In past 

3882 versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to 

3883 disambiguate same-named columns from different tables, aliases, or 

3884 subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now 

3885 applies labels only to names that conflict with an existing name so 

3886 that the impact of this labeling is minimal. 

3887 

3888 The rationale for disambiguation is mostly so that all column 

3889 expressions are available from a given :attr:`_sql.FromClause.c` 

3890 collection when a subquery is created. 

3891 

3892 .. versionadded:: 1.4 - the 

3893 :meth:`_sql.GenerativeSelect.set_label_style` method replaces the 

3894 previous combination of ``.apply_labels()``, ``.with_labels()`` and 

3895 ``use_labels=True`` methods and/or parameters. 

3896 

3897 .. seealso:: 

3898 

3899 :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` 

3900 

3901 :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` 

3902 

3903 :data:`_sql.LABEL_STYLE_NONE` 

3904 

3905 :data:`_sql.LABEL_STYLE_DEFAULT` 

3906 

3907 """ 

3908 if self._label_style is not style: 

3909 self = self._generate() 

3910 self._label_style = style 

3911 return self 

3912 

3913 @property 

3914 def _group_by_clause(self) -> ClauseList: 

3915 """ClauseList access to group_by_clauses for legacy dialects""" 

3916 return ClauseList._construct_raw( 

3917 operators.comma_op, self._group_by_clauses 

3918 ) 

3919 

3920 @property 

3921 def _order_by_clause(self) -> ClauseList: 

3922 """ClauseList access to order_by_clauses for legacy dialects""" 

3923 return ClauseList._construct_raw( 

3924 operators.comma_op, self._order_by_clauses 

3925 ) 

3926 

3927 def _offset_or_limit_clause( 

3928 self, 

3929 element: _LimitOffsetType, 

3930 name: Optional[str] = None, 

3931 type_: Optional[_TypeEngineArgument[int]] = None, 

3932 ) -> ColumnElement[Any]: 

3933 """Convert the given value to an "offset or limit" clause. 

3934 

3935 This handles incoming integers and converts to an expression; if 

3936 an expression is already given, it is passed through. 

3937 

3938 """ 

3939 return coercions.expect( 

3940 roles.LimitOffsetRole, element, name=name, type_=type_ 

3941 ) 

3942 

3943 @overload 

3944 def _offset_or_limit_clause_asint( 

3945 self, clause: ColumnElement[Any], attrname: str 

3946 ) -> NoReturn: ... 

3947 

3948 @overload 

3949 def _offset_or_limit_clause_asint( 

3950 self, clause: Optional[_OffsetLimitParam], attrname: str 

3951 ) -> Optional[int]: ... 

3952 

3953 def _offset_or_limit_clause_asint( 

3954 self, clause: Optional[ColumnElement[Any]], attrname: str 

3955 ) -> Union[NoReturn, Optional[int]]: 

3956 """Convert the "offset or limit" clause of a select construct to an 

3957 integer. 

3958 

3959 This is only possible if the value is stored as a simple bound 

3960 parameter. Otherwise, a compilation error is raised. 

3961 

3962 """ 

3963 if clause is None: 

3964 return None 

3965 try: 

3966 value = clause._limit_offset_value 

3967 except AttributeError as err: 

3968 raise exc.CompileError( 

3969 "This SELECT structure does not use a simple " 

3970 "integer value for %s" % attrname 

3971 ) from err 

3972 else: 

3973 return util.asint(value) 

3974 

3975 @property 

3976 def _limit(self) -> Optional[int]: 

3977 """Get an integer value for the limit. This should only be used 

3978 by code that cannot support a limit as a BindParameter or 

3979 other custom clause as it will throw an exception if the limit 

3980 isn't currently set to an integer. 

3981 

3982 """ 

3983 return self._offset_or_limit_clause_asint(self._limit_clause, "limit") 

3984 

3985 def _simple_int_clause(self, clause: ClauseElement) -> bool: 

3986 """True if the clause is a simple integer, False 

3987 if it is not present or is a SQL expression. 

3988 """ 

3989 return isinstance(clause, _OffsetLimitParam) 

3990 

3991 @property 

3992 def _offset(self) -> Optional[int]: 

3993 """Get an integer value for the offset. This should only be used 

3994 by code that cannot support an offset as a BindParameter or 

3995 other custom clause as it will throw an exception if the 

3996 offset isn't currently set to an integer. 

3997 

3998 """ 

3999 return self._offset_or_limit_clause_asint( 

4000 self._offset_clause, "offset" 

4001 ) 

4002 

4003 @property 

4004 def _has_row_limiting_clause(self) -> bool: 

4005 return ( 

4006 self._limit_clause is not None 

4007 or self._offset_clause is not None 

4008 or self._fetch_clause is not None 

4009 ) 

4010 

4011 @_generative 

4012 def limit(self, limit: _LimitOffsetType) -> Self: 

4013 """Return a new selectable with the given LIMIT criterion 

4014 applied. 

4015 

4016 This is a numerical value which usually renders as a ``LIMIT`` 

4017 expression in the resulting select. Backends that don't 

4018 support ``LIMIT`` will attempt to provide similar 

4019 functionality. 

4020 

4021 .. note:: 

4022 

4023 The :meth:`_sql.GenerativeSelect.limit` method will replace 

4024 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4025 

4026 :param limit: an integer LIMIT parameter, or a SQL expression 

4027 that provides an integer result. Pass ``None`` to reset it. 

4028 

4029 .. seealso:: 

4030 

4031 :meth:`_sql.GenerativeSelect.fetch` 

4032 

4033 :meth:`_sql.GenerativeSelect.offset` 

4034 

4035 """ 

4036 

4037 self._fetch_clause = self._fetch_clause_options = None 

4038 self._limit_clause = self._offset_or_limit_clause(limit) 

4039 return self 

4040 

4041 @_generative 

4042 def fetch( 

4043 self, 

4044 count: _LimitOffsetType, 

4045 with_ties: bool = False, 

4046 percent: bool = False, 

4047 ) -> Self: 

4048 """Return a new selectable with the given FETCH FIRST criterion 

4049 applied. 

4050 

4051 This is a numeric value which usually renders as 

4052 ``FETCH {FIRST | NEXT} [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` 

4053 expression in the resulting select. This functionality is 

4054 is currently implemented for Oracle, PostgreSQL, MSSQL. 

4055 

4056 Use :meth:`_sql.GenerativeSelect.offset` to specify the offset. 

4057 

4058 .. note:: 

4059 

4060 The :meth:`_sql.GenerativeSelect.fetch` method will replace 

4061 any clause applied with :meth:`_sql.GenerativeSelect.limit`. 

4062 

4063 .. versionadded:: 1.4 

4064 

4065 :param count: an integer COUNT parameter, or a SQL expression 

4066 that provides an integer result. When ``percent=True`` this will 

4067 represent the percentage of rows to return, not the absolute value. 

4068 Pass ``None`` to reset it. 

4069 

4070 :param with_ties: When ``True``, the WITH TIES option is used 

4071 to return any additional rows that tie for the last place in the 

4072 result set according to the ``ORDER BY`` clause. The 

4073 ``ORDER BY`` may be mandatory in this case. Defaults to ``False`` 

4074 

4075 :param percent: When ``True``, ``count`` represents the percentage 

4076 of the total number of selected rows to return. Defaults to ``False`` 

4077 

4078 .. seealso:: 

4079 

4080 :meth:`_sql.GenerativeSelect.limit` 

4081 

4082 :meth:`_sql.GenerativeSelect.offset` 

4083 

4084 """ 

4085 

4086 self._limit_clause = None 

4087 if count is None: 

4088 self._fetch_clause = self._fetch_clause_options = None 

4089 else: 

4090 self._fetch_clause = self._offset_or_limit_clause(count) 

4091 self._fetch_clause_options = { 

4092 "with_ties": with_ties, 

4093 "percent": percent, 

4094 } 

4095 return self 

4096 

4097 @_generative 

4098 def offset(self, offset: _LimitOffsetType) -> Self: 

4099 """Return a new selectable with the given OFFSET criterion 

4100 applied. 

4101 

4102 

4103 This is a numeric value which usually renders as an ``OFFSET`` 

4104 expression in the resulting select. Backends that don't 

4105 support ``OFFSET`` will attempt to provide similar 

4106 functionality. 

4107 

4108 :param offset: an integer OFFSET parameter, or a SQL expression 

4109 that provides an integer result. Pass ``None`` to reset it. 

4110 

4111 .. seealso:: 

4112 

4113 :meth:`_sql.GenerativeSelect.limit` 

4114 

4115 :meth:`_sql.GenerativeSelect.fetch` 

4116 

4117 """ 

4118 

4119 self._offset_clause = self._offset_or_limit_clause(offset) 

4120 return self 

4121 

4122 @_generative 

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

4124 def slice( 

4125 self, 

4126 start: int, 

4127 stop: int, 

4128 ) -> Self: 

4129 """Apply LIMIT / OFFSET to this statement based on a slice. 

4130 

4131 The start and stop indices behave like the argument to Python's 

4132 built-in :func:`range` function. This method provides an 

4133 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

4134 query. 

4135 

4136 For example, :: 

4137 

4138 stmt = select(User).order_by(User).id.slice(1, 3) 

4139 

4140 renders as 

4141 

4142 .. sourcecode:: sql 

4143 

4144 SELECT users.id AS users_id, 

4145 users.name AS users_name 

4146 FROM users ORDER BY users.id 

4147 LIMIT ? OFFSET ? 

4148 (2, 1) 

4149 

4150 .. note:: 

4151 

4152 The :meth:`_sql.GenerativeSelect.slice` method will replace 

4153 any clause applied with :meth:`_sql.GenerativeSelect.fetch`. 

4154 

4155 .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice` 

4156 method generalized from the ORM. 

4157 

4158 .. seealso:: 

4159 

4160 :meth:`_sql.GenerativeSelect.limit` 

4161 

4162 :meth:`_sql.GenerativeSelect.offset` 

4163 

4164 :meth:`_sql.GenerativeSelect.fetch` 

4165 

4166 """ 

4167 sql_util = util.preloaded.sql_util 

4168 self._fetch_clause = self._fetch_clause_options = None 

4169 self._limit_clause, self._offset_clause = sql_util._make_slice( 

4170 self._limit_clause, self._offset_clause, start, stop 

4171 ) 

4172 return self 

4173 

4174 @_generative 

4175 def order_by( 

4176 self, 

4177 __first: Union[ 

4178 Literal[None, _NoArg.NO_ARG], 

4179 _ColumnExpressionOrStrLabelArgument[Any], 

4180 ] = _NoArg.NO_ARG, 

4181 /, 

4182 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4183 ) -> Self: 

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

4185 criteria applied. 

4186 

4187 e.g.:: 

4188 

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

4190 

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

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

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

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

4195 

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

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

4198 

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

4200 constructs 

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

4202 

4203 .. seealso:: 

4204 

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

4206 

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

4208 

4209 """ 

4210 

4211 if not clauses and __first is None: 

4212 self._order_by_clauses = () 

4213 elif __first is not _NoArg.NO_ARG: 

4214 self._order_by_clauses += tuple( 

4215 coercions.expect( 

4216 roles.OrderByRole, clause, apply_propagate_attrs=self 

4217 ) 

4218 for clause in (__first,) + clauses 

4219 ) 

4220 return self 

4221 

4222 @_generative 

4223 def group_by( 

4224 self, 

4225 __first: Union[ 

4226 Literal[None, _NoArg.NO_ARG], 

4227 _ColumnExpressionOrStrLabelArgument[Any], 

4228 ] = _NoArg.NO_ARG, 

4229 /, 

4230 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

4231 ) -> Self: 

4232 r"""Return a new selectable with the given list of GROUP BY 

4233 criterion applied. 

4234 

4235 All existing GROUP BY settings can be suppressed by passing ``None``. 

4236 

4237 e.g.:: 

4238 

4239 stmt = select(table.c.name, func.max(table.c.stat)).\ 

4240 group_by(table.c.name) 

4241 

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

4243 constructs 

4244 which will be used to generate an GROUP BY clause. 

4245 

4246 .. seealso:: 

4247 

4248 :ref:`tutorial_group_by_w_aggregates` - in the 

4249 :ref:`unified_tutorial` 

4250 

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

4252 

4253 """ 

4254 

4255 if not clauses and __first is None: 

4256 self._group_by_clauses = () 

4257 elif __first is not _NoArg.NO_ARG: 

4258 self._group_by_clauses += tuple( 

4259 coercions.expect( 

4260 roles.GroupByRole, clause, apply_propagate_attrs=self 

4261 ) 

4262 for clause in (__first,) + clauses 

4263 ) 

4264 return self 

4265 

4266 

4267@CompileState.plugin_for("default", "compound_select") 

4268class CompoundSelectState(CompileState): 

4269 @util.memoized_property 

4270 def _label_resolve_dict( 

4271 self, 

4272 ) -> Tuple[ 

4273 Dict[str, ColumnElement[Any]], 

4274 Dict[str, ColumnElement[Any]], 

4275 Dict[str, ColumnElement[Any]], 

4276 ]: 

4277 # TODO: this is hacky and slow 

4278 hacky_subquery = self.statement.subquery() 

4279 hacky_subquery.named_with_column = False 

4280 d = {c.key: c for c in hacky_subquery.c} 

4281 return d, d, d 

4282 

4283 

4284class _CompoundSelectKeyword(Enum): 

4285 UNION = "UNION" 

4286 UNION_ALL = "UNION ALL" 

4287 EXCEPT = "EXCEPT" 

4288 EXCEPT_ALL = "EXCEPT ALL" 

4289 INTERSECT = "INTERSECT" 

4290 INTERSECT_ALL = "INTERSECT ALL" 

4291 

4292 

4293class CompoundSelect(HasCompileState, GenerativeSelect, ExecutableReturnsRows): 

4294 """Forms the basis of ``UNION``, ``UNION ALL``, and other 

4295 SELECT-based set operations. 

4296 

4297 

4298 .. seealso:: 

4299 

4300 :func:`_expression.union` 

4301 

4302 :func:`_expression.union_all` 

4303 

4304 :func:`_expression.intersect` 

4305 

4306 :func:`_expression.intersect_all` 

4307 

4308 :func:`_expression.except` 

4309 

4310 :func:`_expression.except_all` 

4311 

4312 """ 

4313 

4314 __visit_name__ = "compound_select" 

4315 

4316 _traverse_internals: _TraverseInternalsType = [ 

4317 ("selects", InternalTraversal.dp_clauseelement_list), 

4318 ("_limit_clause", InternalTraversal.dp_clauseelement), 

4319 ("_offset_clause", InternalTraversal.dp_clauseelement), 

4320 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

4321 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

4322 ("_order_by_clauses", InternalTraversal.dp_clauseelement_list), 

4323 ("_group_by_clauses", InternalTraversal.dp_clauseelement_list), 

4324 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

4325 ("keyword", InternalTraversal.dp_string), 

4326 ] + SupportsCloneAnnotations._clone_annotations_traverse_internals 

4327 

4328 selects: List[SelectBase] 

4329 

4330 _is_from_container = True 

4331 _auto_correlate = False 

4332 

4333 def __init__( 

4334 self, 

4335 keyword: _CompoundSelectKeyword, 

4336 *selects: _SelectStatementForCompoundArgument, 

4337 ): 

4338 self.keyword = keyword 

4339 self.selects = [ 

4340 coercions.expect( 

4341 roles.CompoundElementRole, s, apply_propagate_attrs=self 

4342 ).self_group(against=self) 

4343 for s in selects 

4344 ] 

4345 

4346 GenerativeSelect.__init__(self) 

4347 

4348 @classmethod 

4349 def _create_union( 

4350 cls, *selects: _SelectStatementForCompoundArgument 

4351 ) -> CompoundSelect: 

4352 return CompoundSelect(_CompoundSelectKeyword.UNION, *selects) 

4353 

4354 @classmethod 

4355 def _create_union_all( 

4356 cls, *selects: _SelectStatementForCompoundArgument 

4357 ) -> CompoundSelect: 

4358 return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects) 

4359 

4360 @classmethod 

4361 def _create_except( 

4362 cls, *selects: _SelectStatementForCompoundArgument 

4363 ) -> CompoundSelect: 

4364 return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects) 

4365 

4366 @classmethod 

4367 def _create_except_all( 

4368 cls, *selects: _SelectStatementForCompoundArgument 

4369 ) -> CompoundSelect: 

4370 return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects) 

4371 

4372 @classmethod 

4373 def _create_intersect( 

4374 cls, *selects: _SelectStatementForCompoundArgument 

4375 ) -> CompoundSelect: 

4376 return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects) 

4377 

4378 @classmethod 

4379 def _create_intersect_all( 

4380 cls, *selects: _SelectStatementForCompoundArgument 

4381 ) -> CompoundSelect: 

4382 return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects) 

4383 

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

4385 return self.selects[0]._scalar_type() 

4386 

4387 def self_group( 

4388 self, against: Optional[OperatorType] = None 

4389 ) -> GroupedElement: 

4390 return SelectStatementGrouping(self) 

4391 

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

4393 for s in self.selects: 

4394 if s.is_derived_from(fromclause): 

4395 return True 

4396 return False 

4397 

4398 def set_label_style(self, style: SelectLabelStyle) -> CompoundSelect: 

4399 if self._label_style is not style: 

4400 self = self._generate() 

4401 select_0 = self.selects[0].set_label_style(style) 

4402 self.selects = [select_0] + self.selects[1:] 

4403 

4404 return self 

4405 

4406 def _ensure_disambiguated_names(self) -> CompoundSelect: 

4407 new_select = self.selects[0]._ensure_disambiguated_names() 

4408 if new_select is not self.selects[0]: 

4409 self = self._generate() 

4410 self.selects = [new_select] + self.selects[1:] 

4411 

4412 return self 

4413 

4414 def _generate_fromclause_column_proxies( 

4415 self, 

4416 subquery: FromClause, 

4417 *, 

4418 proxy_compound_columns: Optional[ 

4419 Iterable[Sequence[ColumnElement[Any]]] 

4420 ] = None, 

4421 ) -> None: 

4422 # this is a slightly hacky thing - the union exports a 

4423 # column that resembles just that of the *first* selectable. 

4424 # to get at a "composite" column, particularly foreign keys, 

4425 # you have to dig through the proxies collection which we 

4426 # generate below. 

4427 select_0 = self.selects[0] 

4428 

4429 if self._label_style is not LABEL_STYLE_DEFAULT: 

4430 select_0 = select_0.set_label_style(self._label_style) 

4431 

4432 # hand-construct the "_proxies" collection to include all 

4433 # derived columns place a 'weight' annotation corresponding 

4434 # to how low in the list of select()s the column occurs, so 

4435 # that the corresponding_column() operation can resolve 

4436 # conflicts 

4437 extra_col_iterator = zip( 

4438 *[ 

4439 [ 

4440 c._annotate(dd) 

4441 for c in stmt._all_selected_columns 

4442 if is_column_element(c) 

4443 ] 

4444 for dd, stmt in [ 

4445 ({"weight": i + 1}, stmt) 

4446 for i, stmt in enumerate(self.selects) 

4447 ] 

4448 ] 

4449 ) 

4450 

4451 # the incoming proxy_compound_columns can be present also if this is 

4452 # a compound embedded in a compound. it's probably more appropriate 

4453 # that we generate new weights local to this nested compound, though 

4454 # i haven't tried to think what it means for compound nested in 

4455 # compound 

4456 select_0._generate_fromclause_column_proxies( 

4457 subquery, proxy_compound_columns=extra_col_iterator 

4458 ) 

4459 

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

4461 super()._refresh_for_new_column(column) 

4462 for select in self.selects: 

4463 select._refresh_for_new_column(column) 

4464 

4465 @util.ro_non_memoized_property 

4466 def _all_selected_columns(self) -> _SelectIterable: 

4467 return self.selects[0]._all_selected_columns 

4468 

4469 @util.ro_non_memoized_property 

4470 def selected_columns( 

4471 self, 

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

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

4474 representing the columns that 

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

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

4477 

4478 For a :class:`_expression.CompoundSelect`, the 

4479 :attr:`_expression.CompoundSelect.selected_columns` 

4480 attribute returns the selected 

4481 columns of the first SELECT statement contained within the series of 

4482 statements within the set operation. 

4483 

4484 .. seealso:: 

4485 

4486 :attr:`_sql.Select.selected_columns` 

4487 

4488 .. versionadded:: 1.4 

4489 

4490 """ 

4491 return self.selects[0].selected_columns 

4492 

4493 

4494# backwards compat 

4495for elem in _CompoundSelectKeyword: 

4496 setattr(CompoundSelect, elem.name, elem) 

4497 

4498 

4499@CompileState.plugin_for("default", "select") 

4500class SelectState(util.MemoizedSlots, CompileState): 

4501 __slots__ = ( 

4502 "from_clauses", 

4503 "froms", 

4504 "columns_plus_names", 

4505 "_label_resolve_dict", 

4506 ) 

4507 

4508 if TYPE_CHECKING: 

4509 default_select_compile_options: CacheableOptions 

4510 else: 

4511 

4512 class default_select_compile_options(CacheableOptions): 

4513 _cache_key_traversal = [] 

4514 

4515 if TYPE_CHECKING: 

4516 

4517 @classmethod 

4518 def get_plugin_class( 

4519 cls, statement: Executable 

4520 ) -> Type[SelectState]: ... 

4521 

4522 def __init__( 

4523 self, 

4524 statement: Select[Unpack[TupleAny]], 

4525 compiler: Optional[SQLCompiler], 

4526 **kw: Any, 

4527 ): 

4528 self.statement = statement 

4529 self.from_clauses = statement._from_obj 

4530 

4531 for memoized_entities in statement._memoized_select_entities: 

4532 self._setup_joins( 

4533 memoized_entities._setup_joins, memoized_entities._raw_columns 

4534 ) 

4535 

4536 if statement._setup_joins: 

4537 self._setup_joins(statement._setup_joins, statement._raw_columns) 

4538 

4539 self.froms = self._get_froms(statement) 

4540 

4541 self.columns_plus_names = statement._generate_columns_plus_names(True) 

4542 

4543 @classmethod 

4544 def _plugin_not_implemented(cls) -> NoReturn: 

4545 raise NotImplementedError( 

4546 "The default SELECT construct without plugins does not " 

4547 "implement this method." 

4548 ) 

4549 

4550 @classmethod 

4551 def get_column_descriptions( 

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

4553 ) -> List[Dict[str, Any]]: 

4554 return [ 

4555 { 

4556 "name": name, 

4557 "type": element.type, 

4558 "expr": element, 

4559 } 

4560 for _, name, _, element, _ in ( 

4561 statement._generate_columns_plus_names(False) 

4562 ) 

4563 ] 

4564 

4565 @classmethod 

4566 def from_statement( 

4567 cls, 

4568 statement: Select[Unpack[TupleAny]], 

4569 from_statement: roles.ReturnsRowsRole, 

4570 ) -> ExecutableReturnsRows: 

4571 cls._plugin_not_implemented() 

4572 

4573 @classmethod 

4574 def get_columns_clause_froms( 

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

4576 ) -> List[FromClause]: 

4577 return cls._normalize_froms( 

4578 itertools.chain.from_iterable( 

4579 element._from_objects for element in statement._raw_columns 

4580 ) 

4581 ) 

4582 

4583 @classmethod 

4584 def _column_naming_convention( 

4585 cls, label_style: SelectLabelStyle 

4586 ) -> _LabelConventionCallable: 

4587 table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL 

4588 

4589 dedupe = label_style is not LABEL_STYLE_NONE 

4590 

4591 pa = prefix_anon_map() 

4592 names = set() 

4593 

4594 def go( 

4595 c: Union[ColumnElement[Any], TextClause], 

4596 col_name: Optional[str] = None, 

4597 ) -> Optional[str]: 

4598 if is_text_clause(c): 

4599 return None 

4600 elif TYPE_CHECKING: 

4601 assert is_column_element(c) 

4602 

4603 if not dedupe: 

4604 name = c._proxy_key 

4605 if name is None: 

4606 name = "_no_label" 

4607 return name 

4608 

4609 name = c._tq_key_label if table_qualified else c._proxy_key 

4610 

4611 if name is None: 

4612 name = "_no_label" 

4613 if name in names: 

4614 return c._anon_label(name) % pa 

4615 else: 

4616 names.add(name) 

4617 return name 

4618 

4619 elif name in names: 

4620 return ( 

4621 c._anon_tq_key_label % pa 

4622 if table_qualified 

4623 else c._anon_key_label % pa 

4624 ) 

4625 else: 

4626 names.add(name) 

4627 return name 

4628 

4629 return go 

4630 

4631 def _get_froms( 

4632 self, statement: Select[Unpack[TupleAny]] 

4633 ) -> List[FromClause]: 

4634 ambiguous_table_name_map: _AmbiguousTableNameMap 

4635 self._ambiguous_table_name_map = ambiguous_table_name_map = {} 

4636 

4637 return self._normalize_froms( 

4638 itertools.chain( 

4639 self.from_clauses, 

4640 itertools.chain.from_iterable( 

4641 [ 

4642 element._from_objects 

4643 for element in statement._raw_columns 

4644 ] 

4645 ), 

4646 itertools.chain.from_iterable( 

4647 [ 

4648 element._from_objects 

4649 for element in statement._where_criteria 

4650 ] 

4651 ), 

4652 ), 

4653 check_statement=statement, 

4654 ambiguous_table_name_map=ambiguous_table_name_map, 

4655 ) 

4656 

4657 @classmethod 

4658 def _normalize_froms( 

4659 cls, 

4660 iterable_of_froms: Iterable[FromClause], 

4661 check_statement: Optional[Select[Unpack[TupleAny]]] = None, 

4662 ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None, 

4663 ) -> List[FromClause]: 

4664 """given an iterable of things to select FROM, reduce them to what 

4665 would actually render in the FROM clause of a SELECT. 

4666 

4667 This does the job of checking for JOINs, tables, etc. that are in fact 

4668 overlapping due to cloning, adaption, present in overlapping joins, 

4669 etc. 

4670 

4671 """ 

4672 seen: Set[FromClause] = set() 

4673 froms: List[FromClause] = [] 

4674 

4675 for item in iterable_of_froms: 

4676 if is_subquery(item) and item.element is check_statement: 

4677 raise exc.InvalidRequestError( 

4678 "select() construct refers to itself as a FROM" 

4679 ) 

4680 

4681 if not seen.intersection(item._cloned_set): 

4682 froms.append(item) 

4683 seen.update(item._cloned_set) 

4684 

4685 if froms: 

4686 toremove = set( 

4687 itertools.chain.from_iterable( 

4688 [_expand_cloned(f._hide_froms) for f in froms] 

4689 ) 

4690 ) 

4691 if toremove: 

4692 # filter out to FROM clauses not in the list, 

4693 # using a list to maintain ordering 

4694 froms = [f for f in froms if f not in toremove] 

4695 

4696 if ambiguous_table_name_map is not None: 

4697 ambiguous_table_name_map.update( 

4698 ( 

4699 fr.name, 

4700 _anonymous_label.safe_construct( 

4701 hash(fr.name), fr.name 

4702 ), 

4703 ) 

4704 for item in froms 

4705 for fr in item._from_objects 

4706 if is_table(fr) 

4707 and fr.schema 

4708 and fr.name not in ambiguous_table_name_map 

4709 ) 

4710 

4711 return froms 

4712 

4713 def _get_display_froms( 

4714 self, 

4715 explicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4716 implicit_correlate_froms: Optional[Sequence[FromClause]] = None, 

4717 ) -> List[FromClause]: 

4718 """Return the full list of 'from' clauses to be displayed. 

4719 

4720 Takes into account a set of existing froms which may be 

4721 rendered in the FROM clause of enclosing selects; this Select 

4722 may want to leave those absent if it is automatically 

4723 correlating. 

4724 

4725 """ 

4726 

4727 froms = self.froms 

4728 

4729 if self.statement._correlate: 

4730 to_correlate = self.statement._correlate 

4731 if to_correlate: 

4732 froms = [ 

4733 f 

4734 for f in froms 

4735 if f 

4736 not in _cloned_intersection( 

4737 _cloned_intersection( 

4738 froms, explicit_correlate_froms or () 

4739 ), 

4740 to_correlate, 

4741 ) 

4742 ] 

4743 

4744 if self.statement._correlate_except is not None: 

4745 froms = [ 

4746 f 

4747 for f in froms 

4748 if f 

4749 not in _cloned_difference( 

4750 _cloned_intersection( 

4751 froms, explicit_correlate_froms or () 

4752 ), 

4753 self.statement._correlate_except, 

4754 ) 

4755 ] 

4756 

4757 if ( 

4758 self.statement._auto_correlate 

4759 and implicit_correlate_froms 

4760 and len(froms) > 1 

4761 ): 

4762 froms = [ 

4763 f 

4764 for f in froms 

4765 if f 

4766 not in _cloned_intersection(froms, implicit_correlate_froms) 

4767 ] 

4768 

4769 if not len(froms): 

4770 raise exc.InvalidRequestError( 

4771 "Select statement '%r" 

4772 "' returned no FROM clauses " 

4773 "due to auto-correlation; " 

4774 "specify correlate(<tables>) " 

4775 "to control correlation " 

4776 "manually." % self.statement 

4777 ) 

4778 

4779 return froms 

4780 

4781 def _memoized_attr__label_resolve_dict( 

4782 self, 

4783 ) -> Tuple[ 

4784 Dict[str, ColumnElement[Any]], 

4785 Dict[str, ColumnElement[Any]], 

4786 Dict[str, ColumnElement[Any]], 

4787 ]: 

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

4789 c._tq_label or c.key: c 

4790 for c in self.statement._all_selected_columns 

4791 if c._allow_label_resolve 

4792 } 

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

4794 c.key: c # type: ignore 

4795 for c in _select_iterables(self.froms) 

4796 if c._allow_label_resolve 

4797 } 

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

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

4800 with_cols.setdefault(key, value) 

4801 

4802 return with_cols, only_froms, only_cols 

4803 

4804 @classmethod 

4805 def determine_last_joined_entity( 

4806 cls, stmt: Select[Unpack[TupleAny]] 

4807 ) -> Optional[_JoinTargetElement]: 

4808 if stmt._setup_joins: 

4809 return stmt._setup_joins[-1][0] 

4810 else: 

4811 return None 

4812 

4813 @classmethod 

4814 def all_selected_columns( 

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

4816 ) -> _SelectIterable: 

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

4818 

4819 def _setup_joins( 

4820 self, 

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

4822 raw_columns: List[_ColumnsClauseElement], 

4823 ) -> None: 

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

4825 if TYPE_CHECKING: 

4826 if onclause is not None: 

4827 assert isinstance(onclause, ColumnElement) 

4828 

4829 isouter = flags["isouter"] 

4830 full = flags["full"] 

4831 

4832 if left is None: 

4833 ( 

4834 left, 

4835 replace_from_obj_index, 

4836 ) = self._join_determine_implicit_left_side( 

4837 raw_columns, left, right, onclause 

4838 ) 

4839 else: 

4840 (replace_from_obj_index) = self._join_place_explicit_left_side( 

4841 left 

4842 ) 

4843 

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

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

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

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

4848 # used instead. 

4849 if TYPE_CHECKING: 

4850 assert isinstance(right, FromClause) 

4851 if onclause is not None: 

4852 assert isinstance(onclause, ColumnElement) 

4853 

4854 if replace_from_obj_index is not None: 

4855 # splice into an existing element in the 

4856 # self._from_obj list 

4857 left_clause = self.from_clauses[replace_from_obj_index] 

4858 

4859 self.from_clauses = ( 

4860 self.from_clauses[:replace_from_obj_index] 

4861 + ( 

4862 Join( 

4863 left_clause, 

4864 right, 

4865 onclause, 

4866 isouter=isouter, 

4867 full=full, 

4868 ), 

4869 ) 

4870 + self.from_clauses[replace_from_obj_index + 1 :] 

4871 ) 

4872 else: 

4873 assert left is not None 

4874 self.from_clauses = self.from_clauses + ( 

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

4876 ) 

4877 

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

4879 def _join_determine_implicit_left_side( 

4880 self, 

4881 raw_columns: List[_ColumnsClauseElement], 

4882 left: Optional[FromClause], 

4883 right: _JoinTargetElement, 

4884 onclause: Optional[ColumnElement[Any]], 

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

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

4887 determine if an existing FROM or entity in this query 

4888 can serve as the left hand side. 

4889 

4890 """ 

4891 

4892 sql_util = util.preloaded.sql_util 

4893 

4894 replace_from_obj_index: Optional[int] = None 

4895 

4896 from_clauses = self.from_clauses 

4897 

4898 if from_clauses: 

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

4900 from_clauses, right, onclause 

4901 ) 

4902 

4903 if len(indexes) == 1: 

4904 replace_from_obj_index = indexes[0] 

4905 left = from_clauses[replace_from_obj_index] 

4906 else: 

4907 potential = {} 

4908 statement = self.statement 

4909 

4910 for from_clause in itertools.chain( 

4911 itertools.chain.from_iterable( 

4912 [element._from_objects for element in raw_columns] 

4913 ), 

4914 itertools.chain.from_iterable( 

4915 [ 

4916 element._from_objects 

4917 for element in statement._where_criteria 

4918 ] 

4919 ), 

4920 ): 

4921 potential[from_clause] = () 

4922 

4923 all_clauses = list(potential.keys()) 

4924 indexes = sql_util.find_left_clause_to_join_from( 

4925 all_clauses, right, onclause 

4926 ) 

4927 

4928 if len(indexes) == 1: 

4929 left = all_clauses[indexes[0]] 

4930 

4931 if len(indexes) > 1: 

4932 raise exc.InvalidRequestError( 

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

4934 "from, there are multiple FROMS which can " 

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

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

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

4938 "help resolve the ambiguity." 

4939 ) 

4940 elif not indexes: 

4941 raise exc.InvalidRequestError( 

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

4943 "Please use the .select_from() " 

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

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

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

4947 ) 

4948 return left, replace_from_obj_index 

4949 

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

4951 def _join_place_explicit_left_side( 

4952 self, left: FromClause 

4953 ) -> Optional[int]: 

4954 replace_from_obj_index: Optional[int] = None 

4955 

4956 sql_util = util.preloaded.sql_util 

4957 

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

4959 

4960 if from_clauses: 

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

4962 self.from_clauses, left 

4963 ) 

4964 else: 

4965 indexes = [] 

4966 

4967 if len(indexes) > 1: 

4968 raise exc.InvalidRequestError( 

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

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

4971 "ON clause." 

4972 ) 

4973 

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

4975 # an existing FROM in the self._from_obj tuple 

4976 if indexes: 

4977 replace_from_obj_index = indexes[0] 

4978 

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

4980 # self._from_obj tuple 

4981 

4982 return replace_from_obj_index 

4983 

4984 

4985class _SelectFromElements: 

4986 __slots__ = () 

4987 

4988 _raw_columns: List[_ColumnsClauseElement] 

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

4990 _from_obj: Tuple[FromClause, ...] 

4991 

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

4993 # note this does not include elements 

4994 # in _setup_joins 

4995 

4996 seen = set() 

4997 for element in self._raw_columns: 

4998 for fr in element._from_objects: 

4999 if fr in seen: 

5000 continue 

5001 seen.add(fr) 

5002 yield fr 

5003 for element in self._where_criteria: 

5004 for fr in element._from_objects: 

5005 if fr in seen: 

5006 continue 

5007 seen.add(fr) 

5008 yield fr 

5009 for element in self._from_obj: 

5010 if element in seen: 

5011 continue 

5012 seen.add(element) 

5013 yield element 

5014 

5015 

5016class _MemoizedSelectEntities( 

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

5018): 

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

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

5021 statement will be SELECTing from. This object represents 

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

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

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

5025 

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

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

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

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

5030 SQL compiler when needed. But as of 

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

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

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

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

5035 

5036 

5037 """ 

5038 

5039 __visit_name__ = "memoized_select_entities" 

5040 

5041 _traverse_internals: _TraverseInternalsType = [ 

5042 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5043 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5044 ("_with_options", InternalTraversal.dp_executable_options), 

5045 ] 

5046 

5047 _is_clone_of: Optional[ClauseElement] 

5048 _raw_columns: List[_ColumnsClauseElement] 

5049 _setup_joins: Tuple[_SetupJoinsElement, ...] 

5050 _with_options: Tuple[ExecutableOption, ...] 

5051 

5052 _annotations = util.EMPTY_DICT 

5053 

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

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

5056 c.__dict__ = {k: v for k, v in self.__dict__.items()} 

5057 

5058 c._is_clone_of = self.__dict__.get("_is_clone_of", self) 

5059 return c 

5060 

5061 @classmethod 

5062 def _generate_for_statement( 

5063 cls, select_stmt: Select[Unpack[TupleAny]] 

5064 ) -> None: 

5065 if select_stmt._setup_joins or select_stmt._with_options: 

5066 self = _MemoizedSelectEntities() 

5067 self._raw_columns = select_stmt._raw_columns 

5068 self._setup_joins = select_stmt._setup_joins 

5069 self._with_options = select_stmt._with_options 

5070 

5071 select_stmt._memoized_select_entities += (self,) 

5072 select_stmt._raw_columns = [] 

5073 select_stmt._setup_joins = select_stmt._with_options = () 

5074 

5075 

5076class Select( 

5077 HasPrefixes, 

5078 HasSuffixes, 

5079 HasHints, 

5080 HasCompileState, 

5081 _SelectFromElements, 

5082 GenerativeSelect, 

5083 TypedReturnsRows[Unpack[_Ts]], 

5084): 

5085 """Represents a ``SELECT`` statement. 

5086 

5087 The :class:`_sql.Select` object is normally constructed using the 

5088 :func:`_sql.select` function. See that function for details. 

5089 

5090 .. seealso:: 

5091 

5092 :func:`_sql.select` 

5093 

5094 :ref:`tutorial_selecting_data` - in the 2.0 tutorial 

5095 

5096 """ 

5097 

5098 __visit_name__ = "select" 

5099 

5100 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

5101 _memoized_select_entities: Tuple[TODO_Any, ...] = () 

5102 

5103 _raw_columns: List[_ColumnsClauseElement] 

5104 

5105 _distinct: bool = False 

5106 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

5107 _correlate: Tuple[FromClause, ...] = () 

5108 _correlate_except: Optional[Tuple[FromClause, ...]] = None 

5109 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

5110 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

5111 _from_obj: Tuple[FromClause, ...] = () 

5112 _auto_correlate = True 

5113 _is_select_statement = True 

5114 _compile_options: CacheableOptions = ( 

5115 SelectState.default_select_compile_options 

5116 ) 

5117 

5118 _traverse_internals: _TraverseInternalsType = ( 

5119 [ 

5120 ("_raw_columns", InternalTraversal.dp_clauseelement_list), 

5121 ( 

5122 "_memoized_select_entities", 

5123 InternalTraversal.dp_memoized_select_entities, 

5124 ), 

5125 ("_from_obj", InternalTraversal.dp_clauseelement_list), 

5126 ("_where_criteria", InternalTraversal.dp_clauseelement_tuple), 

5127 ("_having_criteria", InternalTraversal.dp_clauseelement_tuple), 

5128 ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5129 ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple), 

5130 ("_setup_joins", InternalTraversal.dp_setup_join_tuple), 

5131 ("_correlate", InternalTraversal.dp_clauseelement_tuple), 

5132 ("_correlate_except", InternalTraversal.dp_clauseelement_tuple), 

5133 ("_limit_clause", InternalTraversal.dp_clauseelement), 

5134 ("_offset_clause", InternalTraversal.dp_clauseelement), 

5135 ("_fetch_clause", InternalTraversal.dp_clauseelement), 

5136 ("_fetch_clause_options", InternalTraversal.dp_plain_dict), 

5137 ("_for_update_arg", InternalTraversal.dp_clauseelement), 

5138 ("_distinct", InternalTraversal.dp_boolean), 

5139 ("_distinct_on", InternalTraversal.dp_clauseelement_tuple), 

5140 ("_label_style", InternalTraversal.dp_plain_obj), 

5141 ] 

5142 + HasCTE._has_ctes_traverse_internals 

5143 + HasPrefixes._has_prefixes_traverse_internals 

5144 + HasSuffixes._has_suffixes_traverse_internals 

5145 + HasHints._has_hints_traverse_internals 

5146 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

5147 + Executable._executable_traverse_internals 

5148 ) 

5149 

5150 _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [ 

5151 ("_compile_options", InternalTraversal.dp_has_cache_key) 

5152 ] 

5153 

5154 _compile_state_factory: Type[SelectState] 

5155 

5156 @classmethod 

5157 def _create_raw_select(cls, **kw: Any) -> Select[Unpack[TupleAny]]: 

5158 """Create a :class:`.Select` using raw ``__new__`` with no coercions. 

5159 

5160 Used internally to build up :class:`.Select` constructs with 

5161 pre-established state. 

5162 

5163 """ 

5164 

5165 stmt = Select.__new__(Select) 

5166 stmt.__dict__.update(kw) 

5167 return stmt 

5168 

5169 def __init__(self, *entities: _ColumnsClauseArgument[Any]): 

5170 r"""Construct a new :class:`_expression.Select`. 

5171 

5172 The public constructor for :class:`_expression.Select` is the 

5173 :func:`_sql.select` function. 

5174 

5175 """ 

5176 self._raw_columns = [ 

5177 coercions.expect( 

5178 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5179 ) 

5180 for ent in entities 

5181 ] 

5182 

5183 GenerativeSelect.__init__(self) 

5184 

5185 def _scalar_type(self) -> TypeEngine[Any]: 

5186 if not self._raw_columns: 

5187 return NULLTYPE 

5188 elem = self._raw_columns[0] 

5189 cols = list(elem._select_iterable) 

5190 return cols[0].type 

5191 

5192 def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self: 

5193 """A synonym for the :meth:`_sql.Select.where` method.""" 

5194 

5195 return self.where(*criteria) 

5196 

5197 def _filter_by_zero( 

5198 self, 

5199 ) -> Union[ 

5200 FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause 

5201 ]: 

5202 if self._setup_joins: 

5203 meth = SelectState.get_plugin_class( 

5204 self 

5205 ).determine_last_joined_entity 

5206 _last_joined_entity = meth(self) 

5207 if _last_joined_entity is not None: 

5208 return _last_joined_entity 

5209 

5210 if self._from_obj: 

5211 return self._from_obj[0] 

5212 

5213 return self._raw_columns[0] 

5214 

5215 if TYPE_CHECKING: 

5216 

5217 @overload 

5218 def scalar_subquery( 

5219 self: Select[_MAYBE_ENTITY], 

5220 ) -> ScalarSelect[Any]: ... 

5221 

5222 @overload 

5223 def scalar_subquery( 

5224 self: Select[_NOT_ENTITY], 

5225 ) -> ScalarSelect[_NOT_ENTITY]: ... 

5226 

5227 @overload 

5228 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5229 

5230 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

5231 

5232 def filter_by(self, **kwargs: Any) -> Self: 

5233 r"""apply the given filtering criterion as a WHERE clause 

5234 to this select. 

5235 

5236 """ 

5237 from_entity = self._filter_by_zero() 

5238 

5239 clauses = [ 

5240 _entity_namespace_key(from_entity, key) == value 

5241 for key, value in kwargs.items() 

5242 ] 

5243 return self.filter(*clauses) 

5244 

5245 @property 

5246 def column_descriptions(self) -> Any: 

5247 """Return a :term:`plugin-enabled` 'column descriptions' structure 

5248 referring to the columns which are SELECTed by this statement. 

5249 

5250 This attribute is generally useful when using the ORM, as an 

5251 extended structure which includes information about mapped 

5252 entities is returned. The section :ref:`queryguide_inspection` 

5253 contains more background. 

5254 

5255 For a Core-only statement, the structure returned by this accessor 

5256 is derived from the same objects that are returned by the 

5257 :attr:`.Select.selected_columns` accessor, formatted as a list of 

5258 dictionaries which contain the keys ``name``, ``type`` and ``expr``, 

5259 which indicate the column expressions to be selected:: 

5260 

5261 >>> stmt = select(user_table) 

5262 >>> stmt.column_descriptions 

5263 [ 

5264 { 

5265 'name': 'id', 

5266 'type': Integer(), 

5267 'expr': Column('id', Integer(), ...)}, 

5268 { 

5269 'name': 'name', 

5270 'type': String(length=30), 

5271 'expr': Column('name', String(length=30), ...)} 

5272 ] 

5273 

5274 .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions` 

5275 attribute returns a structure for a Core-only set of entities, 

5276 not just ORM-only entities. 

5277 

5278 .. seealso:: 

5279 

5280 :attr:`.UpdateBase.entity_description` - entity information for 

5281 an :func:`.insert`, :func:`.update`, or :func:`.delete` 

5282 

5283 :ref:`queryguide_inspection` - ORM background 

5284 

5285 """ 

5286 meth = SelectState.get_plugin_class(self).get_column_descriptions 

5287 return meth(self) 

5288 

5289 def from_statement( 

5290 self, statement: roles.ReturnsRowsRole 

5291 ) -> ExecutableReturnsRows: 

5292 """Apply the columns which this :class:`.Select` would select 

5293 onto another statement. 

5294 

5295 This operation is :term:`plugin-specific` and will raise a not 

5296 supported exception if this :class:`_sql.Select` does not select from 

5297 plugin-enabled entities. 

5298 

5299 

5300 The statement is typically either a :func:`_expression.text` or 

5301 :func:`_expression.select` construct, and should return the set of 

5302 columns appropriate to the entities represented by this 

5303 :class:`.Select`. 

5304 

5305 .. seealso:: 

5306 

5307 :ref:`orm_queryguide_selecting_text` - usage examples in the 

5308 ORM Querying Guide 

5309 

5310 """ 

5311 meth = SelectState.get_plugin_class(self).from_statement 

5312 return meth(self, statement) 

5313 

5314 @_generative 

5315 def join( 

5316 self, 

5317 target: _JoinTargetArgument, 

5318 onclause: Optional[_OnClauseArgument] = None, 

5319 *, 

5320 isouter: bool = False, 

5321 full: bool = False, 

5322 ) -> Self: 

5323 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5324 object's criterion 

5325 and apply generatively, returning the newly resulting 

5326 :class:`_expression.Select`. 

5327 

5328 E.g.:: 

5329 

5330 stmt = select(user_table).join(address_table, user_table.c.id == address_table.c.user_id) 

5331 

5332 The above statement generates SQL similar to:: 

5333 

5334 SELECT user.id, user.name FROM user JOIN address ON user.id = address.user_id 

5335 

5336 .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates 

5337 a :class:`_sql.Join` object between a :class:`_sql.FromClause` 

5338 source that is within the FROM clause of the existing SELECT, 

5339 and a given target :class:`_sql.FromClause`, and then adds 

5340 this :class:`_sql.Join` to the FROM clause of the newly generated 

5341 SELECT statement. This is completely reworked from the behavior 

5342 in 1.3, which would instead create a subquery of the entire 

5343 :class:`_expression.Select` and then join that subquery to the 

5344 target. 

5345 

5346 This is a **backwards incompatible change** as the previous behavior 

5347 was mostly useless, producing an unnamed subquery rejected by 

5348 most databases in any case. The new behavior is modeled after 

5349 that of the very successful :meth:`_orm.Query.join` method in the 

5350 ORM, in order to support the functionality of :class:`_orm.Query` 

5351 being available by using a :class:`_sql.Select` object with an 

5352 :class:`_orm.Session`. 

5353 

5354 See the notes for this change at :ref:`change_select_join`. 

5355 

5356 

5357 :param target: target table to join towards 

5358 

5359 :param onclause: ON clause of the join. If omitted, an ON clause 

5360 is generated automatically based on the :class:`_schema.ForeignKey` 

5361 linkages between the two tables, if one can be unambiguously 

5362 determined, otherwise an error is raised. 

5363 

5364 :param isouter: if True, generate LEFT OUTER join. Same as 

5365 :meth:`_expression.Select.outerjoin`. 

5366 

5367 :param full: if True, generate FULL OUTER join. 

5368 

5369 .. seealso:: 

5370 

5371 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5372 

5373 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5374 

5375 :meth:`_expression.Select.join_from` 

5376 

5377 :meth:`_expression.Select.outerjoin` 

5378 

5379 """ # noqa: E501 

5380 join_target = coercions.expect( 

5381 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5382 ) 

5383 if onclause is not None: 

5384 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5385 else: 

5386 onclause_element = None 

5387 

5388 self._setup_joins += ( 

5389 ( 

5390 join_target, 

5391 onclause_element, 

5392 None, 

5393 {"isouter": isouter, "full": full}, 

5394 ), 

5395 ) 

5396 return self 

5397 

5398 def outerjoin_from( 

5399 self, 

5400 from_: _FromClauseArgument, 

5401 target: _JoinTargetArgument, 

5402 onclause: Optional[_OnClauseArgument] = None, 

5403 *, 

5404 full: bool = False, 

5405 ) -> Self: 

5406 r"""Create a SQL LEFT OUTER JOIN against this 

5407 :class:`_expression.Select` object's criterion and apply generatively, 

5408 returning the newly resulting :class:`_expression.Select`. 

5409 

5410 Usage is the same as that of :meth:`_selectable.Select.join_from`. 

5411 

5412 """ 

5413 return self.join_from( 

5414 from_, target, onclause=onclause, isouter=True, full=full 

5415 ) 

5416 

5417 @_generative 

5418 def join_from( 

5419 self, 

5420 from_: _FromClauseArgument, 

5421 target: _JoinTargetArgument, 

5422 onclause: Optional[_OnClauseArgument] = None, 

5423 *, 

5424 isouter: bool = False, 

5425 full: bool = False, 

5426 ) -> Self: 

5427 r"""Create a SQL JOIN against this :class:`_expression.Select` 

5428 object's criterion 

5429 and apply generatively, returning the newly resulting 

5430 :class:`_expression.Select`. 

5431 

5432 E.g.:: 

5433 

5434 stmt = select(user_table, address_table).join_from( 

5435 user_table, address_table, user_table.c.id == address_table.c.user_id 

5436 ) 

5437 

5438 The above statement generates SQL similar to:: 

5439 

5440 SELECT user.id, user.name, address.id, address.email, address.user_id 

5441 FROM user JOIN address ON user.id = address.user_id 

5442 

5443 .. versionadded:: 1.4 

5444 

5445 :param from\_: the left side of the join, will be rendered in the 

5446 FROM clause and is roughly equivalent to using the 

5447 :meth:`.Select.select_from` method. 

5448 

5449 :param target: target table to join towards 

5450 

5451 :param onclause: ON clause of the join. 

5452 

5453 :param isouter: if True, generate LEFT OUTER join. Same as 

5454 :meth:`_expression.Select.outerjoin`. 

5455 

5456 :param full: if True, generate FULL OUTER join. 

5457 

5458 .. seealso:: 

5459 

5460 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5461 

5462 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5463 

5464 :meth:`_expression.Select.join` 

5465 

5466 """ # noqa: E501 

5467 

5468 # note the order of parsing from vs. target is important here, as we 

5469 # are also deriving the source of the plugin (i.e. the subject mapper 

5470 # in an ORM query) which should favor the "from_" over the "target" 

5471 

5472 from_ = coercions.expect( 

5473 roles.FromClauseRole, from_, apply_propagate_attrs=self 

5474 ) 

5475 join_target = coercions.expect( 

5476 roles.JoinTargetRole, target, apply_propagate_attrs=self 

5477 ) 

5478 if onclause is not None: 

5479 onclause_element = coercions.expect(roles.OnClauseRole, onclause) 

5480 else: 

5481 onclause_element = None 

5482 

5483 self._setup_joins += ( 

5484 ( 

5485 join_target, 

5486 onclause_element, 

5487 from_, 

5488 {"isouter": isouter, "full": full}, 

5489 ), 

5490 ) 

5491 return self 

5492 

5493 def outerjoin( 

5494 self, 

5495 target: _JoinTargetArgument, 

5496 onclause: Optional[_OnClauseArgument] = None, 

5497 *, 

5498 full: bool = False, 

5499 ) -> Self: 

5500 """Create a left outer join. 

5501 

5502 Parameters are the same as that of :meth:`_expression.Select.join`. 

5503 

5504 .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now 

5505 creates a :class:`_sql.Join` object between a 

5506 :class:`_sql.FromClause` source that is within the FROM clause of 

5507 the existing SELECT, and a given target :class:`_sql.FromClause`, 

5508 and then adds this :class:`_sql.Join` to the FROM clause of the 

5509 newly generated SELECT statement. This is completely reworked 

5510 from the behavior in 1.3, which would instead create a subquery of 

5511 the entire 

5512 :class:`_expression.Select` and then join that subquery to the 

5513 target. 

5514 

5515 This is a **backwards incompatible change** as the previous behavior 

5516 was mostly useless, producing an unnamed subquery rejected by 

5517 most databases in any case. The new behavior is modeled after 

5518 that of the very successful :meth:`_orm.Query.join` method in the 

5519 ORM, in order to support the functionality of :class:`_orm.Query` 

5520 being available by using a :class:`_sql.Select` object with an 

5521 :class:`_orm.Session`. 

5522 

5523 See the notes for this change at :ref:`change_select_join`. 

5524 

5525 .. seealso:: 

5526 

5527 :ref:`tutorial_select_join` - in the :doc:`/tutorial/index` 

5528 

5529 :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel` 

5530 

5531 :meth:`_expression.Select.join` 

5532 

5533 """ 

5534 return self.join(target, onclause=onclause, isouter=True, full=full) 

5535 

5536 def get_final_froms(self) -> Sequence[FromClause]: 

5537 """Compute the final displayed list of :class:`_expression.FromClause` 

5538 elements. 

5539 

5540 This method will run through the full computation required to 

5541 determine what FROM elements will be displayed in the resulting 

5542 SELECT statement, including shadowing individual tables with 

5543 JOIN objects, as well as full computation for ORM use cases including 

5544 eager loading clauses. 

5545 

5546 For ORM use, this accessor returns the **post compilation** 

5547 list of FROM objects; this collection will include elements such as 

5548 eagerly loaded tables and joins. The objects will **not** be 

5549 ORM enabled and not work as a replacement for the 

5550 :meth:`_sql.Select.select_froms` collection; additionally, the 

5551 method is not well performing for an ORM enabled statement as it 

5552 will incur the full ORM construction process. 

5553 

5554 To retrieve the FROM list that's implied by the "columns" collection 

5555 passed to the :class:`_sql.Select` originally, use the 

5556 :attr:`_sql.Select.columns_clause_froms` accessor. 

5557 

5558 To select from an alternative set of columns while maintaining the 

5559 FROM list, use the :meth:`_sql.Select.with_only_columns` method and 

5560 pass the 

5561 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5562 parameter. 

5563 

5564 .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms` 

5565 method replaces the previous :attr:`_sql.Select.froms` accessor, 

5566 which is deprecated. 

5567 

5568 .. seealso:: 

5569 

5570 :attr:`_sql.Select.columns_clause_froms` 

5571 

5572 """ 

5573 

5574 return self._compile_state_factory(self, None)._get_display_froms() 

5575 

5576 @property 

5577 @util.deprecated( 

5578 "1.4.23", 

5579 "The :attr:`_expression.Select.froms` attribute is moved to " 

5580 "the :meth:`_expression.Select.get_final_froms` method.", 

5581 ) 

5582 def froms(self) -> Sequence[FromClause]: 

5583 """Return the displayed list of :class:`_expression.FromClause` 

5584 elements. 

5585 

5586 

5587 """ 

5588 return self.get_final_froms() 

5589 

5590 @property 

5591 def columns_clause_froms(self) -> List[FromClause]: 

5592 """Return the set of :class:`_expression.FromClause` objects implied 

5593 by the columns clause of this SELECT statement. 

5594 

5595 .. versionadded:: 1.4.23 

5596 

5597 .. seealso:: 

5598 

5599 :attr:`_sql.Select.froms` - "final" FROM list taking the full 

5600 statement into account 

5601 

5602 :meth:`_sql.Select.with_only_columns` - makes use of this 

5603 collection to set up a new FROM list 

5604 

5605 """ 

5606 

5607 return SelectState.get_plugin_class(self).get_columns_clause_froms( 

5608 self 

5609 ) 

5610 

5611 @property 

5612 def inner_columns(self) -> _SelectIterable: 

5613 """An iterator of all :class:`_expression.ColumnElement` 

5614 expressions which would 

5615 be rendered into the columns clause of the resulting SELECT statement. 

5616 

5617 This method is legacy as of 1.4 and is superseded by the 

5618 :attr:`_expression.Select.exported_columns` collection. 

5619 

5620 """ 

5621 

5622 return iter(self._all_selected_columns) 

5623 

5624 def is_derived_from(self, fromclause: Optional[FromClause]) -> bool: 

5625 if fromclause is not None and self in fromclause._cloned_set: 

5626 return True 

5627 

5628 for f in self._iterate_from_elements(): 

5629 if f.is_derived_from(fromclause): 

5630 return True 

5631 return False 

5632 

5633 def _copy_internals( 

5634 self, clone: _CloneCallableType = _clone, **kw: Any 

5635 ) -> None: 

5636 # Select() object has been cloned and probably adapted by the 

5637 # given clone function. Apply the cloning function to internal 

5638 # objects 

5639 

5640 # 1. keep a dictionary of the froms we've cloned, and what 

5641 # they've become. This allows us to ensure the same cloned from 

5642 # is used when other items such as columns are "cloned" 

5643 

5644 all_the_froms = set( 

5645 itertools.chain( 

5646 _from_objects(*self._raw_columns), 

5647 _from_objects(*self._where_criteria), 

5648 _from_objects(*[elem[0] for elem in self._setup_joins]), 

5649 ) 

5650 ) 

5651 

5652 # do a clone for the froms we've gathered. what is important here 

5653 # is if any of the things we are selecting from, like tables, 

5654 # were converted into Join objects. if so, these need to be 

5655 # added to _from_obj explicitly, because otherwise they won't be 

5656 # part of the new state, as they don't associate themselves with 

5657 # their columns. 

5658 new_froms = {f: clone(f, **kw) for f in all_the_froms} 

5659 

5660 # 2. copy FROM collections, adding in joins that we've created. 

5661 existing_from_obj = [clone(f, **kw) for f in self._from_obj] 

5662 add_froms = ( 

5663 {f for f in new_froms.values() if isinstance(f, Join)} 

5664 .difference(all_the_froms) 

5665 .difference(existing_from_obj) 

5666 ) 

5667 

5668 self._from_obj = tuple(existing_from_obj) + tuple(add_froms) 

5669 

5670 # 3. clone everything else, making sure we use columns 

5671 # corresponding to the froms we just made. 

5672 def replace( 

5673 obj: Union[BinaryExpression[Any], ColumnClause[Any]], 

5674 **kw: Any, 

5675 ) -> Optional[KeyedColumnElement[ColumnElement[Any]]]: 

5676 if isinstance(obj, ColumnClause) and obj.table in new_froms: 

5677 newelem = new_froms[obj.table].corresponding_column(obj) 

5678 return newelem 

5679 return None 

5680 

5681 kw["replace"] = replace 

5682 

5683 # copy everything else. for table-ish things like correlate, 

5684 # correlate_except, setup_joins, these clone normally. For 

5685 # column-expression oriented things like raw_columns, where_criteria, 

5686 # order by, we get this from the new froms. 

5687 super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw) 

5688 

5689 self._reset_memoizations() 

5690 

5691 def get_children(self, **kw: Any) -> Iterable[ClauseElement]: 

5692 return itertools.chain( 

5693 super().get_children( 

5694 omit_attrs=("_from_obj", "_correlate", "_correlate_except"), 

5695 **kw, 

5696 ), 

5697 self._iterate_from_elements(), 

5698 ) 

5699 

5700 @_generative 

5701 def add_columns( 

5702 self, *entities: _ColumnsClauseArgument[Any] 

5703 ) -> Select[Unpack[TupleAny]]: 

5704 r"""Return a new :func:`_expression.select` construct with 

5705 the given entities appended to its columns clause. 

5706 

5707 E.g.:: 

5708 

5709 my_select = my_select.add_columns(table.c.new_column) 

5710 

5711 The original expressions in the columns clause remain in place. 

5712 To replace the original expressions with new ones, see the method 

5713 :meth:`_expression.Select.with_only_columns`. 

5714 

5715 :param \*entities: column, table, or other entity expressions to be 

5716 added to the columns clause 

5717 

5718 .. seealso:: 

5719 

5720 :meth:`_expression.Select.with_only_columns` - replaces existing 

5721 expressions rather than appending. 

5722 

5723 :ref:`orm_queryguide_select_multiple_entities` - ORM-centric 

5724 example 

5725 

5726 """ 

5727 self._reset_memoizations() 

5728 

5729 self._raw_columns = self._raw_columns + [ 

5730 coercions.expect( 

5731 roles.ColumnsClauseRole, column, apply_propagate_attrs=self 

5732 ) 

5733 for column in entities 

5734 ] 

5735 return self 

5736 

5737 def _set_entities( 

5738 self, entities: Iterable[_ColumnsClauseArgument[Any]] 

5739 ) -> None: 

5740 self._raw_columns = [ 

5741 coercions.expect( 

5742 roles.ColumnsClauseRole, ent, apply_propagate_attrs=self 

5743 ) 

5744 for ent in util.to_list(entities) 

5745 ] 

5746 

5747 @util.deprecated( 

5748 "1.4", 

5749 "The :meth:`_expression.Select.column` method is deprecated and will " 

5750 "be removed in a future release. Please use " 

5751 ":meth:`_expression.Select.add_columns`", 

5752 ) 

5753 def column( 

5754 self, column: _ColumnsClauseArgument[Any] 

5755 ) -> Select[Unpack[TupleAny]]: 

5756 """Return a new :func:`_expression.select` construct with 

5757 the given column expression added to its columns clause. 

5758 

5759 E.g.:: 

5760 

5761 my_select = my_select.column(table.c.new_column) 

5762 

5763 See the documentation for 

5764 :meth:`_expression.Select.with_only_columns` 

5765 for guidelines on adding /replacing the columns of a 

5766 :class:`_expression.Select` object. 

5767 

5768 """ 

5769 return self.add_columns(column) 

5770 

5771 @util.preload_module("sqlalchemy.sql.util") 

5772 def reduce_columns( 

5773 self, only_synonyms: bool = True 

5774 ) -> Select[Unpack[TupleAny]]: 

5775 """Return a new :func:`_expression.select` construct with redundantly 

5776 named, equivalently-valued columns removed from the columns clause. 

5777 

5778 "Redundant" here means two columns where one refers to the 

5779 other either based on foreign key, or via a simple equality 

5780 comparison in the WHERE clause of the statement. The primary purpose 

5781 of this method is to automatically construct a select statement 

5782 with all uniquely-named columns, without the need to use 

5783 table-qualified labels as 

5784 :meth:`_expression.Select.set_label_style` 

5785 does. 

5786 

5787 When columns are omitted based on foreign key, the referred-to 

5788 column is the one that's kept. When columns are omitted based on 

5789 WHERE equivalence, the first column in the columns clause is the 

5790 one that's kept. 

5791 

5792 :param only_synonyms: when True, limit the removal of columns 

5793 to those which have the same name as the equivalent. Otherwise, 

5794 all columns that are equivalent to another are removed. 

5795 

5796 """ 

5797 woc: Select[Unpack[TupleAny]] 

5798 woc = self.with_only_columns( 

5799 *util.preloaded.sql_util.reduce_columns( 

5800 self._all_selected_columns, 

5801 only_synonyms=only_synonyms, 

5802 *(self._where_criteria + self._from_obj), 

5803 ) 

5804 ) 

5805 return woc 

5806 

5807 # START OVERLOADED FUNCTIONS self.with_only_columns Select 8 

5808 

5809 # code within this block is **programmatically, 

5810 # statically generated** by tools/generate_sel_v1_overloads.py 

5811 

5812 @overload 

5813 def with_only_columns(self, __ent0: _TCCA[_T0]) -> Select[_T0]: ... 

5814 

5815 @overload 

5816 def with_only_columns( 

5817 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1] 

5818 ) -> Select[_T0, _T1]: ... 

5819 

5820 @overload 

5821 def with_only_columns( 

5822 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2] 

5823 ) -> Select[_T0, _T1, _T2]: ... 

5824 

5825 @overload 

5826 def with_only_columns( 

5827 self, 

5828 __ent0: _TCCA[_T0], 

5829 __ent1: _TCCA[_T1], 

5830 __ent2: _TCCA[_T2], 

5831 __ent3: _TCCA[_T3], 

5832 ) -> Select[_T0, _T1, _T2, _T3]: ... 

5833 

5834 @overload 

5835 def with_only_columns( 

5836 self, 

5837 __ent0: _TCCA[_T0], 

5838 __ent1: _TCCA[_T1], 

5839 __ent2: _TCCA[_T2], 

5840 __ent3: _TCCA[_T3], 

5841 __ent4: _TCCA[_T4], 

5842 ) -> Select[_T0, _T1, _T2, _T3, _T4]: ... 

5843 

5844 @overload 

5845 def with_only_columns( 

5846 self, 

5847 __ent0: _TCCA[_T0], 

5848 __ent1: _TCCA[_T1], 

5849 __ent2: _TCCA[_T2], 

5850 __ent3: _TCCA[_T3], 

5851 __ent4: _TCCA[_T4], 

5852 __ent5: _TCCA[_T5], 

5853 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

5854 

5855 @overload 

5856 def with_only_columns( 

5857 self, 

5858 __ent0: _TCCA[_T0], 

5859 __ent1: _TCCA[_T1], 

5860 __ent2: _TCCA[_T2], 

5861 __ent3: _TCCA[_T3], 

5862 __ent4: _TCCA[_T4], 

5863 __ent5: _TCCA[_T5], 

5864 __ent6: _TCCA[_T6], 

5865 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

5866 

5867 @overload 

5868 def with_only_columns( 

5869 self, 

5870 __ent0: _TCCA[_T0], 

5871 __ent1: _TCCA[_T1], 

5872 __ent2: _TCCA[_T2], 

5873 __ent3: _TCCA[_T3], 

5874 __ent4: _TCCA[_T4], 

5875 __ent5: _TCCA[_T5], 

5876 __ent6: _TCCA[_T6], 

5877 __ent7: _TCCA[_T7], 

5878 ) -> Select[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]: ... 

5879 

5880 # END OVERLOADED FUNCTIONS self.with_only_columns 

5881 

5882 @overload 

5883 def with_only_columns( 

5884 self, 

5885 *entities: _ColumnsClauseArgument[Any], 

5886 maintain_column_froms: bool = False, 

5887 **__kw: Any, 

5888 ) -> Select[Unpack[TupleAny]]: ... 

5889 

5890 @_generative 

5891 def with_only_columns( 

5892 self, 

5893 *entities: _ColumnsClauseArgument[Any], 

5894 maintain_column_froms: bool = False, 

5895 **__kw: Any, 

5896 ) -> Select[Unpack[TupleAny]]: 

5897 r"""Return a new :func:`_expression.select` construct with its columns 

5898 clause replaced with the given entities. 

5899 

5900 By default, this method is exactly equivalent to as if the original 

5901 :func:`_expression.select` had been called with the given entities. 

5902 E.g. a statement:: 

5903 

5904 s = select(table1.c.a, table1.c.b) 

5905 s = s.with_only_columns(table1.c.b) 

5906 

5907 should be exactly equivalent to:: 

5908 

5909 s = select(table1.c.b) 

5910 

5911 In this mode of operation, :meth:`_sql.Select.with_only_columns` 

5912 will also dynamically alter the FROM clause of the 

5913 statement if it is not explicitly stated. 

5914 To maintain the existing set of FROMs including those implied by the 

5915 current columns clause, add the 

5916 :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5917 parameter:: 

5918 

5919 s = select(table1.c.a, table2.c.b) 

5920 s = s.with_only_columns(table1.c.a, maintain_column_froms=True) 

5921 

5922 The above parameter performs a transfer of the effective FROMs 

5923 in the columns collection to the :meth:`_sql.Select.select_from` 

5924 method, as though the following were invoked:: 

5925 

5926 s = select(table1.c.a, table2.c.b) 

5927 s = s.select_from(table1, table2).with_only_columns(table1.c.a) 

5928 

5929 The :paramref:`_sql.Select.with_only_columns.maintain_column_froms` 

5930 parameter makes use of the :attr:`_sql.Select.columns_clause_froms` 

5931 collection and performs an operation equivalent to the following:: 

5932 

5933 s = select(table1.c.a, table2.c.b) 

5934 s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a) 

5935 

5936 :param \*entities: column expressions to be used. 

5937 

5938 :param maintain_column_froms: boolean parameter that will ensure the 

5939 FROM list implied from the current columns clause will be transferred 

5940 to the :meth:`_sql.Select.select_from` method first. 

5941 

5942 .. versionadded:: 1.4.23 

5943 

5944 """ # noqa: E501 

5945 

5946 if __kw: 

5947 raise _no_kw() 

5948 

5949 # memoizations should be cleared here as of 

5950 # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this 

5951 # is the case for now. 

5952 self._assert_no_memoizations() 

5953 

5954 if maintain_column_froms: 

5955 self.select_from.non_generative( # type: ignore 

5956 self, *self.columns_clause_froms 

5957 ) 

5958 

5959 # then memoize the FROMs etc. 

5960 _MemoizedSelectEntities._generate_for_statement(self) 

5961 

5962 self._raw_columns = [ 

5963 coercions.expect(roles.ColumnsClauseRole, c) 

5964 for c in coercions._expression_collection_was_a_list( 

5965 "entities", "Select.with_only_columns", entities 

5966 ) 

5967 ] 

5968 return self 

5969 

5970 @property 

5971 def whereclause(self) -> Optional[ColumnElement[Any]]: 

5972 """Return the completed WHERE clause for this 

5973 :class:`_expression.Select` statement. 

5974 

5975 This assembles the current collection of WHERE criteria 

5976 into a single :class:`_expression.BooleanClauseList` construct. 

5977 

5978 

5979 .. versionadded:: 1.4 

5980 

5981 """ 

5982 

5983 return BooleanClauseList._construct_for_whereclause( 

5984 self._where_criteria 

5985 ) 

5986 

5987 _whereclause = whereclause 

5988 

5989 @_generative 

5990 def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self: 

5991 """Return a new :func:`_expression.select` construct with 

5992 the given expression added to 

5993 its WHERE clause, joined to the existing clause via AND, if any. 

5994 

5995 """ 

5996 

5997 assert isinstance(self._where_criteria, tuple) 

5998 

5999 for criterion in whereclause: 

6000 where_criteria: ColumnElement[Any] = coercions.expect( 

6001 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6002 ) 

6003 self._where_criteria += (where_criteria,) 

6004 return self 

6005 

6006 @_generative 

6007 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

6008 """Return a new :func:`_expression.select` construct with 

6009 the given expression added to 

6010 its HAVING clause, joined to the existing clause via AND, if any. 

6011 

6012 """ 

6013 

6014 for criterion in having: 

6015 having_criteria = coercions.expect( 

6016 roles.WhereHavingRole, criterion, apply_propagate_attrs=self 

6017 ) 

6018 self._having_criteria += (having_criteria,) 

6019 return self 

6020 

6021 @_generative 

6022 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

6023 r"""Return a new :func:`_expression.select` construct which 

6024 will apply DISTINCT to the SELECT statement overall. 

6025 

6026 E.g.:: 

6027 

6028 from sqlalchemy import select 

6029 stmt = select(users_table.c.id, users_table.c.name).distinct() 

6030 

6031 The above would produce an statement resembling:: 

6032 

6033 SELECT DISTINCT user.id, user.name FROM user 

6034 

6035 The method also accepts an ``*expr`` parameter which produces the 

6036 PostgreSQL dialect-specific ``DISTINCT ON`` expression. Using this 

6037 parameter on other backends which don't support this syntax will 

6038 raise an error. 

6039 

6040 :param \*expr: optional column expressions. When present, 

6041 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

6042 construct. A deprecation warning and/or :class:`_exc.CompileError` 

6043 will be raised on other backends. 

6044 

6045 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

6046 and will raise :class:`_exc.CompileError` in a future version. 

6047 

6048 """ 

6049 if expr: 

6050 self._distinct = True 

6051 self._distinct_on = self._distinct_on + tuple( 

6052 coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self) 

6053 for e in expr 

6054 ) 

6055 else: 

6056 self._distinct = True 

6057 return self 

6058 

6059 @_generative 

6060 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6061 r"""Return a new :func:`_expression.select` construct with the 

6062 given FROM expression(s) 

6063 merged into its list of FROM objects. 

6064 

6065 E.g.:: 

6066 

6067 table1 = table('t1', column('a')) 

6068 table2 = table('t2', column('b')) 

6069 s = select(table1.c.a).\ 

6070 select_from( 

6071 table1.join(table2, table1.c.a==table2.c.b) 

6072 ) 

6073 

6074 The "from" list is a unique set on the identity of each element, 

6075 so adding an already present :class:`_schema.Table` 

6076 or other selectable 

6077 will have no effect. Passing a :class:`_expression.Join` that refers 

6078 to an already present :class:`_schema.Table` 

6079 or other selectable will have 

6080 the effect of concealing the presence of that selectable as 

6081 an individual element in the rendered FROM list, instead 

6082 rendering it into a JOIN clause. 

6083 

6084 While the typical purpose of :meth:`_expression.Select.select_from` 

6085 is to 

6086 replace the default, derived FROM clause with a join, it can 

6087 also be called with individual table elements, multiple times 

6088 if desired, in the case that the FROM clause cannot be fully 

6089 derived from the columns clause:: 

6090 

6091 select(func.count('*')).select_from(table1) 

6092 

6093 """ 

6094 

6095 self._from_obj += tuple( 

6096 coercions.expect( 

6097 roles.FromClauseRole, fromclause, apply_propagate_attrs=self 

6098 ) 

6099 for fromclause in froms 

6100 ) 

6101 return self 

6102 

6103 @_generative 

6104 def correlate( 

6105 self, 

6106 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6107 ) -> Self: 

6108 r"""Return a new :class:`_expression.Select` 

6109 which will correlate the given FROM 

6110 clauses to that of an enclosing :class:`_expression.Select`. 

6111 

6112 Calling this method turns off the :class:`_expression.Select` object's 

6113 default behavior of "auto-correlation". Normally, FROM elements 

6114 which appear in a :class:`_expression.Select` 

6115 that encloses this one via 

6116 its :term:`WHERE clause`, ORDER BY, HAVING or 

6117 :term:`columns clause` will be omitted from this 

6118 :class:`_expression.Select` 

6119 object's :term:`FROM clause`. 

6120 Setting an explicit correlation collection using the 

6121 :meth:`_expression.Select.correlate` 

6122 method provides a fixed list of FROM objects 

6123 that can potentially take place in this process. 

6124 

6125 When :meth:`_expression.Select.correlate` 

6126 is used to apply specific FROM clauses 

6127 for correlation, the FROM elements become candidates for 

6128 correlation regardless of how deeply nested this 

6129 :class:`_expression.Select` 

6130 object is, relative to an enclosing :class:`_expression.Select` 

6131 which refers to 

6132 the same FROM object. This is in contrast to the behavior of 

6133 "auto-correlation" which only correlates to an immediate enclosing 

6134 :class:`_expression.Select`. 

6135 Multi-level correlation ensures that the link 

6136 between enclosed and enclosing :class:`_expression.Select` 

6137 is always via 

6138 at least one WHERE/ORDER BY/HAVING/columns clause in order for 

6139 correlation to take place. 

6140 

6141 If ``None`` is passed, the :class:`_expression.Select` 

6142 object will correlate 

6143 none of its FROM entries, and all will render unconditionally 

6144 in the local FROM clause. 

6145 

6146 :param \*fromclauses: one or more :class:`.FromClause` or other 

6147 FROM-compatible construct such as an ORM mapped entity to become part 

6148 of the correlate collection; alternatively pass a single value 

6149 ``None`` to remove all existing correlations. 

6150 

6151 .. seealso:: 

6152 

6153 :meth:`_expression.Select.correlate_except` 

6154 

6155 :ref:`tutorial_scalar_subquery` 

6156 

6157 """ 

6158 

6159 # tests failing when we try to change how these 

6160 # arguments are passed 

6161 

6162 self._auto_correlate = False 

6163 if not fromclauses or fromclauses[0] in {None, False}: 

6164 if len(fromclauses) > 1: 

6165 raise exc.ArgumentError( 

6166 "additional FROM objects not accepted when " 

6167 "passing None/False to correlate()" 

6168 ) 

6169 self._correlate = () 

6170 else: 

6171 self._correlate = self._correlate + tuple( 

6172 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6173 ) 

6174 return self 

6175 

6176 @_generative 

6177 def correlate_except( 

6178 self, 

6179 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6180 ) -> Self: 

6181 r"""Return a new :class:`_expression.Select` 

6182 which will omit the given FROM 

6183 clauses from the auto-correlation process. 

6184 

6185 Calling :meth:`_expression.Select.correlate_except` turns off the 

6186 :class:`_expression.Select` object's default behavior of 

6187 "auto-correlation" for the given FROM elements. An element 

6188 specified here will unconditionally appear in the FROM list, while 

6189 all other FROM elements remain subject to normal auto-correlation 

6190 behaviors. 

6191 

6192 If ``None`` is passed, or no arguments are passed, 

6193 the :class:`_expression.Select` object will correlate all of its 

6194 FROM entries. 

6195 

6196 :param \*fromclauses: a list of one or more 

6197 :class:`_expression.FromClause` 

6198 constructs, or other compatible constructs (i.e. ORM-mapped 

6199 classes) to become part of the correlate-exception collection. 

6200 

6201 .. seealso:: 

6202 

6203 :meth:`_expression.Select.correlate` 

6204 

6205 :ref:`tutorial_scalar_subquery` 

6206 

6207 """ 

6208 

6209 self._auto_correlate = False 

6210 if not fromclauses or fromclauses[0] in {None, False}: 

6211 if len(fromclauses) > 1: 

6212 raise exc.ArgumentError( 

6213 "additional FROM objects not accepted when " 

6214 "passing None/False to correlate_except()" 

6215 ) 

6216 self._correlate_except = () 

6217 else: 

6218 self._correlate_except = (self._correlate_except or ()) + tuple( 

6219 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

6220 ) 

6221 

6222 return self 

6223 

6224 @HasMemoized_ro_memoized_attribute 

6225 def selected_columns( 

6226 self, 

6227 ) -> ColumnCollection[str, ColumnElement[Any]]: 

6228 """A :class:`_expression.ColumnCollection` 

6229 representing the columns that 

6230 this SELECT statement or similar construct returns in its result set, 

6231 not including :class:`_sql.TextClause` constructs. 

6232 

6233 This collection differs from the :attr:`_expression.FromClause.columns` 

6234 collection of a :class:`_expression.FromClause` in that the columns 

6235 within this collection cannot be directly nested inside another SELECT 

6236 statement; a subquery must be applied first which provides for the 

6237 necessary parenthesization required by SQL. 

6238 

6239 For a :func:`_expression.select` construct, the collection here is 

6240 exactly what would be rendered inside the "SELECT" statement, and the 

6241 :class:`_expression.ColumnElement` objects are directly present as they 

6242 were given, e.g.:: 

6243 

6244 col1 = column('q', Integer) 

6245 col2 = column('p', Integer) 

6246 stmt = select(col1, col2) 

6247 

6248 Above, ``stmt.selected_columns`` would be a collection that contains 

6249 the ``col1`` and ``col2`` objects directly. For a statement that is 

6250 against a :class:`_schema.Table` or other 

6251 :class:`_expression.FromClause`, the collection will use the 

6252 :class:`_expression.ColumnElement` objects that are in the 

6253 :attr:`_expression.FromClause.c` collection of the from element. 

6254 

6255 A use case for the :attr:`_sql.Select.selected_columns` collection is 

6256 to allow the existing columns to be referenced when adding additional 

6257 criteria, e.g.:: 

6258 

6259 def filter_on_id(my_select, id): 

6260 return my_select.where(my_select.selected_columns['id'] == id) 

6261 

6262 stmt = select(MyModel) 

6263 

6264 # adds "WHERE id=:param" to the statement 

6265 stmt = filter_on_id(stmt, 42) 

6266 

6267 .. note:: 

6268 

6269 The :attr:`_sql.Select.selected_columns` collection does not 

6270 include expressions established in the columns clause using the 

6271 :func:`_sql.text` construct; these are silently omitted from the 

6272 collection. To use plain textual column expressions inside of a 

6273 :class:`_sql.Select` construct, use the :func:`_sql.literal_column` 

6274 construct. 

6275 

6276 

6277 .. versionadded:: 1.4 

6278 

6279 """ 

6280 

6281 # compare to SelectState._generate_columns_plus_names, which 

6282 # generates the actual names used in the SELECT string. that 

6283 # method is more complex because it also renders columns that are 

6284 # fully ambiguous, e.g. same column more than once. 

6285 conv = cast( 

6286 "Callable[[Any], str]", 

6287 SelectState._column_naming_convention(self._label_style), 

6288 ) 

6289 

6290 cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection( 

6291 [ 

6292 (conv(c), c) 

6293 for c in self._all_selected_columns 

6294 if is_column_element(c) 

6295 ] 

6296 ) 

6297 return cc.as_readonly() 

6298 

6299 @HasMemoized_ro_memoized_attribute 

6300 def _all_selected_columns(self) -> _SelectIterable: 

6301 meth = SelectState.get_plugin_class(self).all_selected_columns 

6302 return list(meth(self)) 

6303 

6304 def _ensure_disambiguated_names(self) -> Select[Unpack[TupleAny]]: 

6305 if self._label_style is LABEL_STYLE_NONE: 

6306 self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY) 

6307 return self 

6308 

6309 def _generate_fromclause_column_proxies( 

6310 self, 

6311 subquery: FromClause, 

6312 *, 

6313 proxy_compound_columns: Optional[ 

6314 Iterable[Sequence[ColumnElement[Any]]] 

6315 ] = None, 

6316 ) -> None: 

6317 """Generate column proxies to place in the exported ``.c`` 

6318 collection of a subquery.""" 

6319 

6320 if proxy_compound_columns: 

6321 extra_col_iterator = proxy_compound_columns 

6322 prox = [ 

6323 c._make_proxy( 

6324 subquery, 

6325 key=proxy_key, 

6326 name=required_label_name, 

6327 name_is_truncatable=True, 

6328 compound_select_cols=extra_cols, 

6329 ) 

6330 for ( 

6331 ( 

6332 required_label_name, 

6333 proxy_key, 

6334 fallback_label_name, 

6335 c, 

6336 repeated, 

6337 ), 

6338 extra_cols, 

6339 ) in ( 

6340 zip( 

6341 self._generate_columns_plus_names(False), 

6342 extra_col_iterator, 

6343 ) 

6344 ) 

6345 if is_column_element(c) 

6346 ] 

6347 else: 

6348 prox = [ 

6349 c._make_proxy( 

6350 subquery, 

6351 key=proxy_key, 

6352 name=required_label_name, 

6353 name_is_truncatable=True, 

6354 ) 

6355 for ( 

6356 required_label_name, 

6357 proxy_key, 

6358 fallback_label_name, 

6359 c, 

6360 repeated, 

6361 ) in (self._generate_columns_plus_names(False)) 

6362 if is_column_element(c) 

6363 ] 

6364 

6365 subquery._columns._populate_separate_keys(prox) 

6366 

6367 def _needs_parens_for_grouping(self) -> bool: 

6368 return self._has_row_limiting_clause or bool( 

6369 self._order_by_clause.clauses 

6370 ) 

6371 

6372 def self_group( 

6373 self, against: Optional[OperatorType] = None 

6374 ) -> Union[SelectStatementGrouping[Self], Self]: 

6375 """Return a 'grouping' construct as per the 

6376 :class:`_expression.ClauseElement` specification. 

6377 

6378 This produces an element that can be embedded in an expression. Note 

6379 that this method is called automatically as needed when constructing 

6380 expressions and should not require explicit use. 

6381 

6382 """ 

6383 if ( 

6384 isinstance(against, CompoundSelect) 

6385 and not self._needs_parens_for_grouping() 

6386 ): 

6387 return self 

6388 else: 

6389 return SelectStatementGrouping(self) 

6390 

6391 def union( 

6392 self, *other: _SelectStatementForCompoundArgument 

6393 ) -> CompoundSelect: 

6394 r"""Return a SQL ``UNION`` of this select() construct against 

6395 the given selectables provided as positional arguments. 

6396 

6397 :param \*other: one or more elements with which to create a 

6398 UNION. 

6399 

6400 .. versionchanged:: 1.4.28 

6401 

6402 multiple elements are now accepted. 

6403 

6404 :param \**kwargs: keyword arguments are forwarded to the constructor 

6405 for the newly created :class:`_sql.CompoundSelect` object. 

6406 

6407 """ 

6408 return CompoundSelect._create_union(self, *other) 

6409 

6410 def union_all( 

6411 self, *other: _SelectStatementForCompoundArgument 

6412 ) -> CompoundSelect: 

6413 r"""Return a SQL ``UNION ALL`` of this select() construct against 

6414 the given selectables provided as positional arguments. 

6415 

6416 :param \*other: one or more elements with which to create a 

6417 UNION. 

6418 

6419 .. versionchanged:: 1.4.28 

6420 

6421 multiple elements are now accepted. 

6422 

6423 :param \**kwargs: keyword arguments are forwarded to the constructor 

6424 for the newly created :class:`_sql.CompoundSelect` object. 

6425 

6426 """ 

6427 return CompoundSelect._create_union_all(self, *other) 

6428 

6429 def except_( 

6430 self, *other: _SelectStatementForCompoundArgument 

6431 ) -> CompoundSelect: 

6432 r"""Return a SQL ``EXCEPT`` of this select() construct against 

6433 the given selectable provided as positional arguments. 

6434 

6435 :param \*other: one or more elements with which to create a 

6436 UNION. 

6437 

6438 .. versionchanged:: 1.4.28 

6439 

6440 multiple elements are now accepted. 

6441 

6442 """ 

6443 return CompoundSelect._create_except(self, *other) 

6444 

6445 def except_all( 

6446 self, *other: _SelectStatementForCompoundArgument 

6447 ) -> CompoundSelect: 

6448 r"""Return a SQL ``EXCEPT ALL`` of this select() construct against 

6449 the given selectables provided as positional arguments. 

6450 

6451 :param \*other: one or more elements with which to create a 

6452 UNION. 

6453 

6454 .. versionchanged:: 1.4.28 

6455 

6456 multiple elements are now accepted. 

6457 

6458 """ 

6459 return CompoundSelect._create_except_all(self, *other) 

6460 

6461 def intersect( 

6462 self, *other: _SelectStatementForCompoundArgument 

6463 ) -> CompoundSelect: 

6464 r"""Return a SQL ``INTERSECT`` of this select() construct against 

6465 the given selectables provided as positional arguments. 

6466 

6467 :param \*other: one or more elements with which to create a 

6468 UNION. 

6469 

6470 .. versionchanged:: 1.4.28 

6471 

6472 multiple elements are now accepted. 

6473 

6474 :param \**kwargs: keyword arguments are forwarded to the constructor 

6475 for the newly created :class:`_sql.CompoundSelect` object. 

6476 

6477 """ 

6478 return CompoundSelect._create_intersect(self, *other) 

6479 

6480 def intersect_all( 

6481 self, *other: _SelectStatementForCompoundArgument 

6482 ) -> CompoundSelect: 

6483 r"""Return a SQL ``INTERSECT ALL`` of this select() construct 

6484 against the given selectables provided as positional arguments. 

6485 

6486 :param \*other: one or more elements with which to create a 

6487 UNION. 

6488 

6489 .. versionchanged:: 1.4.28 

6490 

6491 multiple elements are now accepted. 

6492 

6493 :param \**kwargs: keyword arguments are forwarded to the constructor 

6494 for the newly created :class:`_sql.CompoundSelect` object. 

6495 

6496 """ 

6497 return CompoundSelect._create_intersect_all(self, *other) 

6498 

6499 

6500class ScalarSelect( 

6501 roles.InElementRole, Generative, GroupedElement, ColumnElement[_T] 

6502): 

6503 """Represent a scalar subquery. 

6504 

6505 

6506 A :class:`_sql.ScalarSelect` is created by invoking the 

6507 :meth:`_sql.SelectBase.scalar_subquery` method. The object 

6508 then participates in other SQL expressions as a SQL column expression 

6509 within the :class:`_sql.ColumnElement` hierarchy. 

6510 

6511 .. seealso:: 

6512 

6513 :meth:`_sql.SelectBase.scalar_subquery` 

6514 

6515 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6516 

6517 """ 

6518 

6519 _traverse_internals: _TraverseInternalsType = [ 

6520 ("element", InternalTraversal.dp_clauseelement), 

6521 ("type", InternalTraversal.dp_type), 

6522 ] 

6523 

6524 _from_objects: List[FromClause] = [] 

6525 _is_from_container = True 

6526 if not TYPE_CHECKING: 

6527 _is_implicitly_boolean = False 

6528 inherit_cache = True 

6529 

6530 element: SelectBase 

6531 

6532 def __init__(self, element: SelectBase) -> None: 

6533 self.element = element 

6534 self.type = element._scalar_type() 

6535 self._propagate_attrs = element._propagate_attrs 

6536 

6537 def __getattr__(self, attr: str) -> Any: 

6538 return getattr(self.element, attr) 

6539 

6540 def __getstate__(self) -> Dict[str, Any]: 

6541 return {"element": self.element, "type": self.type} 

6542 

6543 def __setstate__(self, state: Dict[str, Any]) -> None: 

6544 self.element = state["element"] 

6545 self.type = state["type"] 

6546 

6547 @property 

6548 def columns(self) -> NoReturn: 

6549 raise exc.InvalidRequestError( 

6550 "Scalar Select expression has no " 

6551 "columns; use this object directly " 

6552 "within a column-level expression." 

6553 ) 

6554 

6555 c = columns 

6556 

6557 @_generative 

6558 def where(self, crit: _ColumnExpressionArgument[bool]) -> Self: 

6559 """Apply a WHERE clause to the SELECT statement referred to 

6560 by this :class:`_expression.ScalarSelect`. 

6561 

6562 """ 

6563 self.element = cast("Select[Unpack[TupleAny]]", self.element).where( 

6564 crit 

6565 ) 

6566 return self 

6567 

6568 def self_group(self, against: Optional[OperatorType] = None) -> Self: 

6569 return self 

6570 

6571 if TYPE_CHECKING: 

6572 

6573 def _ungroup(self) -> Select[Unpack[TupleAny]]: ... 

6574 

6575 @_generative 

6576 def correlate( 

6577 self, 

6578 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6579 ) -> Self: 

6580 r"""Return a new :class:`_expression.ScalarSelect` 

6581 which will correlate the given FROM 

6582 clauses to that of an enclosing :class:`_expression.Select`. 

6583 

6584 This method is mirrored from the :meth:`_sql.Select.correlate` method 

6585 of the underlying :class:`_sql.Select`. The method applies the 

6586 :meth:_sql.Select.correlate` method, then returns a new 

6587 :class:`_sql.ScalarSelect` against that statement. 

6588 

6589 .. versionadded:: 1.4 Previously, the 

6590 :meth:`_sql.ScalarSelect.correlate` 

6591 method was only available from :class:`_sql.Select`. 

6592 

6593 :param \*fromclauses: a list of one or more 

6594 :class:`_expression.FromClause` 

6595 constructs, or other compatible constructs (i.e. ORM-mapped 

6596 classes) to become part of the correlate collection. 

6597 

6598 .. seealso:: 

6599 

6600 :meth:`_expression.ScalarSelect.correlate_except` 

6601 

6602 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6603 

6604 

6605 """ 

6606 self.element = cast( 

6607 "Select[Unpack[TupleAny]]", self.element 

6608 ).correlate(*fromclauses) 

6609 return self 

6610 

6611 @_generative 

6612 def correlate_except( 

6613 self, 

6614 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6615 ) -> Self: 

6616 r"""Return a new :class:`_expression.ScalarSelect` 

6617 which will omit the given FROM 

6618 clauses from the auto-correlation process. 

6619 

6620 This method is mirrored from the 

6621 :meth:`_sql.Select.correlate_except` method of the underlying 

6622 :class:`_sql.Select`. The method applies the 

6623 :meth:_sql.Select.correlate_except` method, then returns a new 

6624 :class:`_sql.ScalarSelect` against that statement. 

6625 

6626 .. versionadded:: 1.4 Previously, the 

6627 :meth:`_sql.ScalarSelect.correlate_except` 

6628 method was only available from :class:`_sql.Select`. 

6629 

6630 :param \*fromclauses: a list of one or more 

6631 :class:`_expression.FromClause` 

6632 constructs, or other compatible constructs (i.e. ORM-mapped 

6633 classes) to become part of the correlate-exception collection. 

6634 

6635 .. seealso:: 

6636 

6637 :meth:`_expression.ScalarSelect.correlate` 

6638 

6639 :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial 

6640 

6641 

6642 """ 

6643 

6644 self.element = cast( 

6645 "Select[Unpack[TupleAny]]", self.element 

6646 ).correlate_except(*fromclauses) 

6647 return self 

6648 

6649 

6650class Exists(UnaryExpression[bool]): 

6651 """Represent an ``EXISTS`` clause. 

6652 

6653 See :func:`_sql.exists` for a description of usage. 

6654 

6655 An ``EXISTS`` clause can also be constructed from a :func:`_sql.select` 

6656 instance by calling :meth:`_sql.SelectBase.exists`. 

6657 

6658 """ 

6659 

6660 inherit_cache = True 

6661 element: Union[ 

6662 SelectStatementGrouping[Select[Unpack[TupleAny]]], 

6663 ScalarSelect[Any], 

6664 ] 

6665 

6666 def __init__( 

6667 self, 

6668 __argument: Optional[ 

6669 Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]] 

6670 ] = None, 

6671 /, 

6672 ): 

6673 s: ScalarSelect[Any] 

6674 

6675 # TODO: this seems like we should be using coercions for this 

6676 if __argument is None: 

6677 s = Select(literal_column("*")).scalar_subquery() 

6678 elif isinstance(__argument, SelectBase): 

6679 s = __argument.scalar_subquery() 

6680 s._propagate_attrs = __argument._propagate_attrs 

6681 elif isinstance(__argument, ScalarSelect): 

6682 s = __argument 

6683 else: 

6684 s = Select(__argument).scalar_subquery() 

6685 

6686 UnaryExpression.__init__( 

6687 self, 

6688 s, 

6689 operator=operators.exists, 

6690 type_=type_api.BOOLEANTYPE, 

6691 wraps_column_expression=True, 

6692 ) 

6693 

6694 @util.ro_non_memoized_property 

6695 def _from_objects(self) -> List[FromClause]: 

6696 return [] 

6697 

6698 def _regroup( 

6699 self, 

6700 fn: Callable[[Select[Unpack[TupleAny]]], Select[Unpack[TupleAny]]], 

6701 ) -> SelectStatementGrouping[Select[Unpack[TupleAny]]]: 

6702 element = self.element._ungroup() 

6703 new_element = fn(element) 

6704 

6705 return_value = new_element.self_group(against=operators.exists) 

6706 assert isinstance(return_value, SelectStatementGrouping) 

6707 return return_value 

6708 

6709 def select(self) -> Select[bool]: 

6710 r"""Return a SELECT of this :class:`_expression.Exists`. 

6711 

6712 e.g.:: 

6713 

6714 stmt = exists(some_table.c.id).where(some_table.c.id == 5).select() 

6715 

6716 This will produce a statement resembling:: 

6717 

6718 SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1 

6719 

6720 .. seealso:: 

6721 

6722 :func:`_expression.select` - general purpose 

6723 method which allows for arbitrary column lists. 

6724 

6725 """ # noqa 

6726 

6727 return Select(self) 

6728 

6729 def correlate( 

6730 self, 

6731 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6732 ) -> Self: 

6733 """Apply correlation to the subquery noted by this 

6734 :class:`_sql.Exists`. 

6735 

6736 .. seealso:: 

6737 

6738 :meth:`_sql.ScalarSelect.correlate` 

6739 

6740 """ 

6741 e = self._clone() 

6742 e.element = self._regroup( 

6743 lambda element: element.correlate(*fromclauses) 

6744 ) 

6745 return e 

6746 

6747 def correlate_except( 

6748 self, 

6749 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

6750 ) -> Self: 

6751 """Apply correlation to the subquery noted by this 

6752 :class:`_sql.Exists`. 

6753 

6754 .. seealso:: 

6755 

6756 :meth:`_sql.ScalarSelect.correlate_except` 

6757 

6758 """ 

6759 

6760 e = self._clone() 

6761 e.element = self._regroup( 

6762 lambda element: element.correlate_except(*fromclauses) 

6763 ) 

6764 return e 

6765 

6766 def select_from(self, *froms: _FromClauseArgument) -> Self: 

6767 """Return a new :class:`_expression.Exists` construct, 

6768 applying the given 

6769 expression to the :meth:`_expression.Select.select_from` 

6770 method of the select 

6771 statement contained. 

6772 

6773 .. note:: it is typically preferable to build a :class:`_sql.Select` 

6774 statement first, including the desired WHERE clause, then use the 

6775 :meth:`_sql.SelectBase.exists` method to produce an 

6776 :class:`_sql.Exists` object at once. 

6777 

6778 """ 

6779 e = self._clone() 

6780 e.element = self._regroup(lambda element: element.select_from(*froms)) 

6781 return e 

6782 

6783 def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self: 

6784 """Return a new :func:`_expression.exists` construct with the 

6785 given expression added to 

6786 its WHERE clause, joined to the existing clause via AND, if any. 

6787 

6788 

6789 .. note:: it is typically preferable to build a :class:`_sql.Select` 

6790 statement first, including the desired WHERE clause, then use the 

6791 :meth:`_sql.SelectBase.exists` method to produce an 

6792 :class:`_sql.Exists` object at once. 

6793 

6794 """ 

6795 e = self._clone() 

6796 e.element = self._regroup(lambda element: element.where(*clause)) 

6797 return e 

6798 

6799 

6800class TextualSelect(SelectBase, ExecutableReturnsRows, Generative): 

6801 """Wrap a :class:`_expression.TextClause` construct within a 

6802 :class:`_expression.SelectBase` 

6803 interface. 

6804 

6805 This allows the :class:`_expression.TextClause` object to gain a 

6806 ``.c`` collection 

6807 and other FROM-like capabilities such as 

6808 :meth:`_expression.FromClause.alias`, 

6809 :meth:`_expression.SelectBase.cte`, etc. 

6810 

6811 The :class:`_expression.TextualSelect` construct is produced via the 

6812 :meth:`_expression.TextClause.columns` 

6813 method - see that method for details. 

6814 

6815 .. versionchanged:: 1.4 the :class:`_expression.TextualSelect` 

6816 class was renamed 

6817 from ``TextAsFrom``, to more correctly suit its role as a 

6818 SELECT-oriented object and not a FROM clause. 

6819 

6820 .. seealso:: 

6821 

6822 :func:`_expression.text` 

6823 

6824 :meth:`_expression.TextClause.columns` - primary creation interface. 

6825 

6826 """ 

6827 

6828 __visit_name__ = "textual_select" 

6829 

6830 _label_style = LABEL_STYLE_NONE 

6831 

6832 _traverse_internals: _TraverseInternalsType = ( 

6833 [ 

6834 ("element", InternalTraversal.dp_clauseelement), 

6835 ("column_args", InternalTraversal.dp_clauseelement_list), 

6836 ] 

6837 + SupportsCloneAnnotations._clone_annotations_traverse_internals 

6838 + HasCTE._has_ctes_traverse_internals 

6839 ) 

6840 

6841 _is_textual = True 

6842 

6843 is_text = True 

6844 is_select = True 

6845 

6846 def __init__( 

6847 self, 

6848 text: TextClause, 

6849 columns: List[_ColumnExpressionArgument[Any]], 

6850 positional: bool = False, 

6851 ) -> None: 

6852 self._init( 

6853 text, 

6854 # convert for ORM attributes->columns, etc 

6855 [ 

6856 coercions.expect(roles.LabeledColumnExprRole, c) 

6857 for c in columns 

6858 ], 

6859 positional, 

6860 ) 

6861 

6862 def _init( 

6863 self, 

6864 text: TextClause, 

6865 columns: List[NamedColumn[Any]], 

6866 positional: bool = False, 

6867 ) -> None: 

6868 self.element = text 

6869 self.column_args = columns 

6870 self.positional = positional 

6871 

6872 @HasMemoized_ro_memoized_attribute 

6873 def selected_columns( 

6874 self, 

6875 ) -> ColumnCollection[str, KeyedColumnElement[Any]]: 

6876 """A :class:`_expression.ColumnCollection` 

6877 representing the columns that 

6878 this SELECT statement or similar construct returns in its result set, 

6879 not including :class:`_sql.TextClause` constructs. 

6880 

6881 This collection differs from the :attr:`_expression.FromClause.columns` 

6882 collection of a :class:`_expression.FromClause` in that the columns 

6883 within this collection cannot be directly nested inside another SELECT 

6884 statement; a subquery must be applied first which provides for the 

6885 necessary parenthesization required by SQL. 

6886 

6887 For a :class:`_expression.TextualSelect` construct, the collection 

6888 contains the :class:`_expression.ColumnElement` objects that were 

6889 passed to the constructor, typically via the 

6890 :meth:`_expression.TextClause.columns` method. 

6891 

6892 

6893 .. versionadded:: 1.4 

6894 

6895 """ 

6896 return ColumnCollection( 

6897 (c.key, c) for c in self.column_args 

6898 ).as_readonly() 

6899 

6900 @util.ro_non_memoized_property 

6901 def _all_selected_columns(self) -> _SelectIterable: 

6902 return self.column_args 

6903 

6904 def set_label_style(self, style: SelectLabelStyle) -> TextualSelect: 

6905 return self 

6906 

6907 def _ensure_disambiguated_names(self) -> TextualSelect: 

6908 return self 

6909 

6910 @_generative 

6911 def bindparams( 

6912 self, 

6913 *binds: BindParameter[Any], 

6914 **bind_as_values: Any, 

6915 ) -> Self: 

6916 self.element = self.element.bindparams(*binds, **bind_as_values) 

6917 return self 

6918 

6919 def _generate_fromclause_column_proxies( 

6920 self, 

6921 fromclause: FromClause, 

6922 *, 

6923 proxy_compound_columns: Optional[ 

6924 Iterable[Sequence[ColumnElement[Any]]] 

6925 ] = None, 

6926 ) -> None: 

6927 if TYPE_CHECKING: 

6928 assert isinstance(fromclause, Subquery) 

6929 

6930 if proxy_compound_columns: 

6931 fromclause._columns._populate_separate_keys( 

6932 c._make_proxy(fromclause, compound_select_cols=extra_cols) 

6933 for c, extra_cols in zip( 

6934 self.column_args, proxy_compound_columns 

6935 ) 

6936 ) 

6937 else: 

6938 fromclause._columns._populate_separate_keys( 

6939 c._make_proxy(fromclause) for c in self.column_args 

6940 ) 

6941 

6942 def _scalar_type(self) -> Union[TypeEngine[Any], Any]: 

6943 return self.column_args[0].type 

6944 

6945 

6946TextAsFrom = TextualSelect 

6947"""Backwards compatibility with the previous name""" 

6948 

6949 

6950class AnnotatedFromClause(Annotated): 

6951 def _copy_internals(self, **kw: Any) -> None: 

6952 super()._copy_internals(**kw) 

6953 if kw.get("ind_cols_on_fromclause", False): 

6954 ee = self._Annotated__element # type: ignore 

6955 

6956 self.c = ee.__class__.c.fget(self) # type: ignore 

6957 

6958 @util.ro_memoized_property 

6959 def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]: 

6960 """proxy the .c collection of the underlying FromClause. 

6961 

6962 Originally implemented in 2008 as a simple load of the .c collection 

6963 when the annotated construct was created (see d3621ae961a), in modern 

6964 SQLAlchemy versions this can be expensive for statements constructed 

6965 with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy 

6966 it, which works just as well. 

6967 

6968 Two different use cases seem to require the collection either copied 

6969 from the underlying one, or unique to this AnnotatedFromClause. 

6970 

6971 See test_selectable->test_annotated_corresponding_column 

6972 

6973 """ 

6974 ee = self._Annotated__element # type: ignore 

6975 return ee.c # type: ignore