| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219 |
- # sql/selectable.py
- # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of SQLAlchemy and is released under
- # the MIT License: https://www.opensource.org/licenses/mit-license.php
- """The :class:`_expression.FromClause` class of SQL expression elements,
- representing
- SQL tables and derived rowsets.
- """
- from __future__ import annotations
- import collections
- from enum import Enum
- import itertools
- from typing import AbstractSet
- from typing import Any as TODO_Any
- from typing import Any
- from typing import Callable
- from typing import cast
- from typing import Dict
- from typing import Generic
- from typing import Iterable
- from typing import Iterator
- from typing import List
- from typing import NamedTuple
- from typing import NoReturn
- from typing import Optional
- from typing import overload
- from typing import Sequence
- from typing import Set
- from typing import Tuple
- from typing import Type
- from typing import TYPE_CHECKING
- from typing import TypeVar
- from typing import Union
- from . import cache_key
- from . import coercions
- from . import operators
- from . import roles
- from . import traversals
- from . import type_api
- from . import visitors
- from ._typing import _ColumnsClauseArgument
- from ._typing import _no_kw
- from ._typing import _T
- from ._typing import _TP
- from ._typing import is_column_element
- from ._typing import is_select_statement
- from ._typing import is_subquery
- from ._typing import is_table
- from ._typing import is_text_clause
- from .annotation import Annotated
- from .annotation import SupportsCloneAnnotations
- from .base import _clone
- from .base import _cloned_difference
- from .base import _cloned_intersection
- from .base import _entity_namespace_key
- from .base import _EntityNamespace
- from .base import _expand_cloned
- from .base import _from_objects
- from .base import _generative
- from .base import _never_select_column
- from .base import _NoArg
- from .base import _select_iterables
- from .base import CacheableOptions
- from .base import ColumnCollection
- from .base import ColumnSet
- from .base import CompileState
- from .base import DedupeColumnCollection
- from .base import DialectKWArgs
- from .base import Executable
- from .base import Generative
- from .base import HasCompileState
- from .base import HasMemoized
- from .base import Immutable
- from .coercions import _document_text_coercion
- from .elements import _anonymous_label
- from .elements import BindParameter
- from .elements import BooleanClauseList
- from .elements import ClauseElement
- from .elements import ClauseList
- from .elements import ColumnClause
- from .elements import ColumnElement
- from .elements import DQLDMLClauseElement
- from .elements import GroupedElement
- from .elements import literal_column
- from .elements import TableValuedColumn
- from .elements import UnaryExpression
- from .operators import OperatorType
- from .sqltypes import NULLTYPE
- from .visitors import _TraverseInternalsType
- from .visitors import InternalTraversal
- from .visitors import prefix_anon_map
- from .. import exc
- from .. import util
- from ..util import HasMemoized_ro_memoized_attribute
- from ..util.typing import Literal
- from ..util.typing import Protocol
- from ..util.typing import Self
- and_ = BooleanClauseList.and_
- if TYPE_CHECKING:
- from ._typing import _ColumnExpressionArgument
- from ._typing import _ColumnExpressionOrStrLabelArgument
- from ._typing import _FromClauseArgument
- from ._typing import _JoinTargetArgument
- from ._typing import _LimitOffsetType
- from ._typing import _MAYBE_ENTITY
- from ._typing import _NOT_ENTITY
- from ._typing import _OnClauseArgument
- from ._typing import _SelectStatementForCompoundArgument
- from ._typing import _T0
- from ._typing import _T1
- from ._typing import _T2
- from ._typing import _T3
- from ._typing import _T4
- from ._typing import _T5
- from ._typing import _T6
- from ._typing import _T7
- from ._typing import _TextCoercedExpressionArgument
- from ._typing import _TypedColumnClauseArgument as _TCCA
- from ._typing import _TypeEngineArgument
- from .base import _AmbiguousTableNameMap
- from .base import ExecutableOption
- from .base import ReadOnlyColumnCollection
- from .cache_key import _CacheKeyTraversalType
- from .compiler import SQLCompiler
- from .dml import Delete
- from .dml import Update
- from .elements import BinaryExpression
- from .elements import KeyedColumnElement
- from .elements import Label
- from .elements import NamedColumn
- from .elements import TextClause
- from .functions import Function
- from .schema import ForeignKey
- from .schema import ForeignKeyConstraint
- from .sqltypes import TableValueType
- from .type_api import TypeEngine
- from .visitors import _CloneCallableType
- _ColumnsClauseElement = Union["FromClause", ColumnElement[Any], "TextClause"]
- _LabelConventionCallable = Callable[
- [Union["ColumnElement[Any]", "TextClause"]], Optional[str]
- ]
- class _JoinTargetProtocol(Protocol):
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]: ...
- @util.ro_non_memoized_property
- def entity_namespace(self) -> _EntityNamespace: ...
- _JoinTargetElement = Union["FromClause", _JoinTargetProtocol]
- _OnClauseElement = Union["ColumnElement[bool]", _JoinTargetProtocol]
- _ForUpdateOfArgument = Union[
- # single column, Table, ORM Entity
- Union[
- "_ColumnExpressionArgument[Any]",
- "_FromClauseArgument",
- ],
- # or sequence of single column elements
- Sequence["_ColumnExpressionArgument[Any]"],
- ]
- _SetupJoinsElement = Tuple[
- _JoinTargetElement,
- Optional[_OnClauseElement],
- Optional["FromClause"],
- Dict[str, Any],
- ]
- _SelectIterable = Iterable[Union["ColumnElement[Any]", "TextClause"]]
- class _OffsetLimitParam(BindParameter[int]):
- inherit_cache = True
- @property
- def _limit_offset_value(self) -> Optional[int]:
- return self.effective_value
- class ReturnsRows(roles.ReturnsRowsRole, DQLDMLClauseElement):
- """The base-most class for Core constructs that have some concept of
- columns that can represent rows.
- While the SELECT statement and TABLE are the primary things we think
- of in this category, DML like INSERT, UPDATE and DELETE can also specify
- RETURNING which means they can be used in CTEs and other forms, and
- PostgreSQL has functions that return rows also.
- .. versionadded:: 1.4
- """
- _is_returns_rows = True
- # sub-elements of returns_rows
- _is_from_clause = False
- _is_select_base = False
- _is_select_statement = False
- _is_lateral = False
- @property
- def selectable(self) -> ReturnsRows:
- return self
- @util.ro_non_memoized_property
- def _all_selected_columns(self) -> _SelectIterable:
- """A sequence of column expression objects that represents the
- "selected" columns of this :class:`_expression.ReturnsRows`.
- This is typically equivalent to .exported_columns except it is
- delivered in the form of a straight sequence and not keyed
- :class:`_expression.ColumnCollection`.
- """
- raise NotImplementedError()
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- """Return ``True`` if this :class:`.ReturnsRows` is
- 'derived' from the given :class:`.FromClause`.
- An example would be an Alias of a Table is derived from that Table.
- """
- raise NotImplementedError()
- def _generate_fromclause_column_proxies(
- self,
- fromclause: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- """Populate columns into an :class:`.AliasedReturnsRows` object."""
- raise NotImplementedError()
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- """reset internal collections for an incoming column being added."""
- raise NotImplementedError()
- @property
- def exported_columns(self) -> ReadOnlyColumnCollection[Any, Any]:
- """A :class:`_expression.ColumnCollection`
- that represents the "exported"
- columns of this :class:`_expression.ReturnsRows`.
- The "exported" columns represent the collection of
- :class:`_expression.ColumnElement`
- expressions that are rendered by this SQL
- construct. There are primary varieties which are the
- "FROM clause columns" of a FROM clause, such as a table, join,
- or subquery, the "SELECTed columns", which are the columns in
- the "columns clause" of a SELECT statement, and the RETURNING
- columns in a DML statement..
- .. versionadded:: 1.4
- .. seealso::
- :attr:`_expression.FromClause.exported_columns`
- :attr:`_expression.SelectBase.exported_columns`
- """
- raise NotImplementedError()
- class ExecutableReturnsRows(Executable, ReturnsRows):
- """base for executable statements that return rows."""
- class TypedReturnsRows(ExecutableReturnsRows, Generic[_TP]):
- """base for a typed executable statements that return rows."""
- class Selectable(ReturnsRows):
- """Mark a class as being selectable."""
- __visit_name__ = "selectable"
- is_selectable = True
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- raise NotImplementedError()
- def lateral(self, name: Optional[str] = None) -> LateralFromClause:
- """Return a LATERAL alias of this :class:`_expression.Selectable`.
- The return value is the :class:`_expression.Lateral` construct also
- provided by the top-level :func:`_expression.lateral` function.
- .. seealso::
- :ref:`tutorial_lateral_correlation` - overview of usage.
- """
- return Lateral._construct(self, name=name)
- @util.deprecated(
- "1.4",
- message="The :meth:`.Selectable.replace_selectable` method is "
- "deprecated, and will be removed in a future release. Similar "
- "functionality is available via the sqlalchemy.sql.visitors module.",
- )
- @util.preload_module("sqlalchemy.sql.util")
- def replace_selectable(self, old: FromClause, alias: Alias) -> Self:
- """Replace all occurrences of :class:`_expression.FromClause`
- 'old' with the given :class:`_expression.Alias`
- object, returning a copy of this :class:`_expression.FromClause`.
- """
- return util.preloaded.sql_util.ClauseAdapter(alias).traverse(self)
- def corresponding_column(
- self, column: KeyedColumnElement[Any], require_embedded: bool = False
- ) -> Optional[KeyedColumnElement[Any]]:
- """Given a :class:`_expression.ColumnElement`, return the exported
- :class:`_expression.ColumnElement` object from the
- :attr:`_expression.Selectable.exported_columns`
- collection of this :class:`_expression.Selectable`
- which corresponds to that
- original :class:`_expression.ColumnElement` via a common ancestor
- column.
- :param column: the target :class:`_expression.ColumnElement`
- to be matched.
- :param require_embedded: only return corresponding columns for
- the given :class:`_expression.ColumnElement`, if the given
- :class:`_expression.ColumnElement`
- is actually present within a sub-element
- of this :class:`_expression.Selectable`.
- Normally the column will match if
- it merely shares a common ancestor with one of the exported
- columns of this :class:`_expression.Selectable`.
- .. seealso::
- :attr:`_expression.Selectable.exported_columns` - the
- :class:`_expression.ColumnCollection`
- that is used for the operation.
- :meth:`_expression.ColumnCollection.corresponding_column`
- - implementation
- method.
- """
- return self.exported_columns.corresponding_column(
- column, require_embedded
- )
- class HasPrefixes:
- _prefixes: Tuple[Tuple[DQLDMLClauseElement, str], ...] = ()
- _has_prefixes_traverse_internals: _TraverseInternalsType = [
- ("_prefixes", InternalTraversal.dp_prefix_sequence)
- ]
- @_generative
- @_document_text_coercion(
- "prefixes",
- ":meth:`_expression.HasPrefixes.prefix_with`",
- ":paramref:`.HasPrefixes.prefix_with.*prefixes`",
- )
- def prefix_with(
- self,
- *prefixes: _TextCoercedExpressionArgument[Any],
- dialect: str = "*",
- ) -> Self:
- r"""Add one or more expressions following the statement keyword, i.e.
- SELECT, INSERT, UPDATE, or DELETE. Generative.
- This is used to support backend-specific prefix keywords such as those
- provided by MySQL.
- E.g.::
- stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")
- # MySQL 5.7 optimizer hints
- stmt = select(table).prefix_with("/*+ BKA(t1) */", dialect="mysql")
- Multiple prefixes can be specified by multiple calls
- to :meth:`_expression.HasPrefixes.prefix_with`.
- :param \*prefixes: textual or :class:`_expression.ClauseElement`
- construct which
- will be rendered following the INSERT, UPDATE, or DELETE
- keyword.
- :param dialect: optional string dialect name which will
- limit rendering of this prefix to only that dialect.
- """
- self._prefixes = self._prefixes + tuple(
- [
- (coercions.expect(roles.StatementOptionRole, p), dialect)
- for p in prefixes
- ]
- )
- return self
- class HasSuffixes:
- _suffixes: Tuple[Tuple[DQLDMLClauseElement, str], ...] = ()
- _has_suffixes_traverse_internals: _TraverseInternalsType = [
- ("_suffixes", InternalTraversal.dp_prefix_sequence)
- ]
- @_generative
- @_document_text_coercion(
- "suffixes",
- ":meth:`_expression.HasSuffixes.suffix_with`",
- ":paramref:`.HasSuffixes.suffix_with.*suffixes`",
- )
- def suffix_with(
- self,
- *suffixes: _TextCoercedExpressionArgument[Any],
- dialect: str = "*",
- ) -> Self:
- r"""Add one or more expressions following the statement as a whole.
- This is used to support backend-specific suffix keywords on
- certain constructs.
- E.g.::
- stmt = (
- select(col1, col2)
- .cte()
- .suffix_with(
- "cycle empno set y_cycle to 1 default 0", dialect="oracle"
- )
- )
- Multiple suffixes can be specified by multiple calls
- to :meth:`_expression.HasSuffixes.suffix_with`.
- :param \*suffixes: textual or :class:`_expression.ClauseElement`
- construct which
- will be rendered following the target clause.
- :param dialect: Optional string dialect name which will
- limit rendering of this suffix to only that dialect.
- """
- self._suffixes = self._suffixes + tuple(
- [
- (coercions.expect(roles.StatementOptionRole, p), dialect)
- for p in suffixes
- ]
- )
- return self
- class HasHints:
- _hints: util.immutabledict[Tuple[FromClause, str], str] = (
- util.immutabledict()
- )
- _statement_hints: Tuple[Tuple[str, str], ...] = ()
- _has_hints_traverse_internals: _TraverseInternalsType = [
- ("_statement_hints", InternalTraversal.dp_statement_hint_list),
- ("_hints", InternalTraversal.dp_table_hint_list),
- ]
- @_generative
- def with_statement_hint(self, text: str, dialect_name: str = "*") -> Self:
- """Add a statement hint to this :class:`_expression.Select` or
- other selectable object.
- .. tip::
- :meth:`_expression.Select.with_statement_hint` generally adds hints
- **at the trailing end** of a SELECT statement. To place
- dialect-specific hints such as optimizer hints at the **front** of
- the SELECT statement after the SELECT keyword, use the
- :meth:`_expression.Select.prefix_with` method for an open-ended
- space, or for table-specific hints the
- :meth:`_expression.Select.with_hint` may be used, which places
- hints in a dialect-specific location.
- This method is similar to :meth:`_expression.Select.with_hint` except
- that it does not require an individual table, and instead applies to
- the statement as a whole.
- Hints here are specific to the backend database and may include
- directives such as isolation levels, file directives, fetch directives,
- etc.
- .. seealso::
- :meth:`_expression.Select.with_hint`
- :meth:`_expression.Select.prefix_with` - generic SELECT prefixing
- which also can suit some database-specific HINT syntaxes such as
- MySQL or Oracle Database optimizer hints
- """
- return self._with_hint(None, text, dialect_name)
- @_generative
- def with_hint(
- self,
- selectable: _FromClauseArgument,
- text: str,
- dialect_name: str = "*",
- ) -> Self:
- r"""Add an indexing or other executional context hint for the given
- selectable to this :class:`_expression.Select` or other selectable
- object.
- .. tip::
- The :meth:`_expression.Select.with_hint` method adds hints that are
- **specific to a single table** to a statement, in a location that
- is **dialect-specific**. To add generic optimizer hints to the
- **beginning** of a statement ahead of the SELECT keyword such as
- for MySQL or Oracle Database, use the
- :meth:`_expression.Select.prefix_with` method. To add optimizer
- hints to the **end** of a statement such as for PostgreSQL, use the
- :meth:`_expression.Select.with_statement_hint` method.
- The text of the hint is rendered in the appropriate
- location for the database backend in use, relative
- to the given :class:`_schema.Table` or :class:`_expression.Alias`
- passed as the
- ``selectable`` argument. The dialect implementation
- typically uses Python string substitution syntax
- with the token ``%(name)s`` to render the name of
- the table or alias. E.g. when using Oracle Database, the
- following::
- select(mytable).with_hint(mytable, "index(%(name)s ix_mytable)")
- Would render SQL as:
- .. sourcecode:: sql
- select /*+ index(mytable ix_mytable) */ ... from mytable
- The ``dialect_name`` option will limit the rendering of a particular
- hint to a particular backend. Such as, to add hints for both Oracle
- Database and MSSql simultaneously::
- select(mytable).with_hint(
- mytable, "index(%(name)s ix_mytable)", "oracle"
- ).with_hint(mytable, "WITH INDEX ix_mytable", "mssql")
- .. seealso::
- :meth:`_expression.Select.with_statement_hint`
- :meth:`_expression.Select.prefix_with` - generic SELECT prefixing
- which also can suit some database-specific HINT syntaxes such as
- MySQL or Oracle Database optimizer hints
- """
- return self._with_hint(selectable, text, dialect_name)
- def _with_hint(
- self,
- selectable: Optional[_FromClauseArgument],
- text: str,
- dialect_name: str,
- ) -> Self:
- if selectable is None:
- self._statement_hints += ((dialect_name, text),)
- else:
- self._hints = self._hints.union(
- {
- (
- coercions.expect(roles.FromClauseRole, selectable),
- dialect_name,
- ): text
- }
- )
- return self
- class FromClause(roles.AnonymizedFromClauseRole, Selectable):
- """Represent an element that can be used within the ``FROM``
- clause of a ``SELECT`` statement.
- The most common forms of :class:`_expression.FromClause` are the
- :class:`_schema.Table` and the :func:`_expression.select` constructs. Key
- features common to all :class:`_expression.FromClause` objects include:
- * a :attr:`.c` collection, which provides per-name access to a collection
- of :class:`_expression.ColumnElement` objects.
- * a :attr:`.primary_key` attribute, which is a collection of all those
- :class:`_expression.ColumnElement`
- objects that indicate the ``primary_key`` flag.
- * Methods to generate various derivations of a "from" clause, including
- :meth:`_expression.FromClause.alias`,
- :meth:`_expression.FromClause.join`,
- :meth:`_expression.FromClause.select`.
- """
- __visit_name__ = "fromclause"
- named_with_column = False
- @util.ro_non_memoized_property
- def _hide_froms(self) -> Iterable[FromClause]:
- return ()
- _is_clone_of: Optional[FromClause]
- _columns: ColumnCollection[Any, Any]
- schema: Optional[str] = None
- """Define the 'schema' attribute for this :class:`_expression.FromClause`.
- This is typically ``None`` for most objects except that of
- :class:`_schema.Table`, where it is taken as the value of the
- :paramref:`_schema.Table.schema` argument.
- """
- is_selectable = True
- _is_from_clause = True
- _is_join = False
- _use_schema_map = False
- def select(self) -> Select[Any]:
- r"""Return a SELECT of this :class:`_expression.FromClause`.
- e.g.::
- stmt = some_table.select().where(some_table.c.id == 5)
- .. seealso::
- :func:`_expression.select` - general purpose
- method which allows for arbitrary column lists.
- """
- return Select(self)
- def join(
- self,
- right: _FromClauseArgument,
- onclause: Optional[_ColumnExpressionArgument[bool]] = None,
- isouter: bool = False,
- full: bool = False,
- ) -> Join:
- """Return a :class:`_expression.Join` from this
- :class:`_expression.FromClause`
- to another :class:`FromClause`.
- E.g.::
- from sqlalchemy import join
- j = user_table.join(
- address_table, user_table.c.id == address_table.c.user_id
- )
- stmt = select(user_table).select_from(j)
- would emit SQL along the lines of:
- .. sourcecode:: sql
- SELECT user.id, user.name FROM user
- JOIN address ON user.id = address.user_id
- :param right: the right side of the join; this is any
- :class:`_expression.FromClause` object such as a
- :class:`_schema.Table` object, and
- may also be a selectable-compatible object such as an ORM-mapped
- class.
- :param onclause: a SQL expression representing the ON clause of the
- join. If left at ``None``, :meth:`_expression.FromClause.join`
- will attempt to
- join the two tables based on a foreign key relationship.
- :param isouter: if True, render a LEFT OUTER JOIN, instead of JOIN.
- :param full: if True, render a FULL OUTER JOIN, instead of LEFT OUTER
- JOIN. Implies :paramref:`.FromClause.join.isouter`.
- .. seealso::
- :func:`_expression.join` - standalone function
- :class:`_expression.Join` - the type of object produced
- """
- return Join(self, right, onclause, isouter, full)
- def outerjoin(
- self,
- right: _FromClauseArgument,
- onclause: Optional[_ColumnExpressionArgument[bool]] = None,
- full: bool = False,
- ) -> Join:
- """Return a :class:`_expression.Join` from this
- :class:`_expression.FromClause`
- to another :class:`FromClause`, with the "isouter" flag set to
- True.
- E.g.::
- from sqlalchemy import outerjoin
- j = user_table.outerjoin(
- address_table, user_table.c.id == address_table.c.user_id
- )
- The above is equivalent to::
- j = user_table.join(
- address_table, user_table.c.id == address_table.c.user_id, isouter=True
- )
- :param right: the right side of the join; this is any
- :class:`_expression.FromClause` object such as a
- :class:`_schema.Table` object, and
- may also be a selectable-compatible object such as an ORM-mapped
- class.
- :param onclause: a SQL expression representing the ON clause of the
- join. If left at ``None``, :meth:`_expression.FromClause.join`
- will attempt to
- join the two tables based on a foreign key relationship.
- :param full: if True, render a FULL OUTER JOIN, instead of
- LEFT OUTER JOIN.
- .. seealso::
- :meth:`_expression.FromClause.join`
- :class:`_expression.Join`
- """ # noqa: E501
- return Join(self, right, onclause, True, full)
- def alias(
- self, name: Optional[str] = None, flat: bool = False
- ) -> NamedFromClause:
- """Return an alias of this :class:`_expression.FromClause`.
- E.g.::
- a2 = some_table.alias("a2")
- The above code creates an :class:`_expression.Alias`
- object which can be used
- as a FROM clause in any SELECT statement.
- .. seealso::
- :ref:`tutorial_using_aliases`
- :func:`_expression.alias`
- """
- return Alias._construct(self, name=name)
- def tablesample(
- self,
- sampling: Union[float, Function[Any]],
- name: Optional[str] = None,
- seed: Optional[roles.ExpressionElementRole[Any]] = None,
- ) -> TableSample:
- """Return a TABLESAMPLE alias of this :class:`_expression.FromClause`.
- The return value is the :class:`_expression.TableSample`
- construct also
- provided by the top-level :func:`_expression.tablesample` function.
- .. seealso::
- :func:`_expression.tablesample` - usage guidelines and parameters
- """
- return TableSample._construct(
- self, sampling=sampling, name=name, seed=seed
- )
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- """Return ``True`` if this :class:`_expression.FromClause` is
- 'derived' from the given ``FromClause``.
- An example would be an Alias of a Table is derived from that Table.
- """
- # this is essentially an "identity" check in the base class.
- # Other constructs override this to traverse through
- # contained elements.
- return fromclause in self._cloned_set
- def _is_lexical_equivalent(self, other: FromClause) -> bool:
- """Return ``True`` if this :class:`_expression.FromClause` and
- the other represent the same lexical identity.
- This tests if either one is a copy of the other, or
- if they are the same via annotation identity.
- """
- return bool(self._cloned_set.intersection(other._cloned_set))
- @util.ro_non_memoized_property
- def description(self) -> str:
- """A brief description of this :class:`_expression.FromClause`.
- Used primarily for error message formatting.
- """
- return getattr(self, "name", self.__class__.__name__ + " object")
- def _generate_fromclause_column_proxies(
- self,
- fromclause: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- columns._populate_separate_keys(
- col._make_proxy(
- fromclause, primary_key=primary_key, foreign_keys=foreign_keys
- )
- for col in self.c
- )
- @util.ro_non_memoized_property
- def exported_columns(
- self,
- ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- that represents the "exported"
- columns of this :class:`_expression.Selectable`.
- The "exported" columns for a :class:`_expression.FromClause`
- object are synonymous
- with the :attr:`_expression.FromClause.columns` collection.
- .. versionadded:: 1.4
- .. seealso::
- :attr:`_expression.Selectable.exported_columns`
- :attr:`_expression.SelectBase.exported_columns`
- """
- return self.c
- @util.ro_non_memoized_property
- def columns(
- self,
- ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- """A named-based collection of :class:`_expression.ColumnElement`
- objects maintained by this :class:`_expression.FromClause`.
- The :attr:`.columns`, or :attr:`.c` collection, is the gateway
- to the construction of SQL expressions using table-bound or
- other selectable-bound columns::
- select(mytable).where(mytable.c.somecolumn == 5)
- :return: a :class:`.ColumnCollection` object.
- """
- return self.c
- @util.ro_memoized_property
- def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- """
- A synonym for :attr:`.FromClause.columns`
- :return: a :class:`.ColumnCollection`
- """
- if "_columns" not in self.__dict__:
- self._setup_collections()
- return self._columns.as_readonly()
- def _setup_collections(self) -> None:
- assert "_columns" not in self.__dict__
- assert "primary_key" not in self.__dict__
- assert "foreign_keys" not in self.__dict__
- _columns: ColumnCollection[Any, Any] = ColumnCollection()
- primary_key = ColumnSet()
- foreign_keys: Set[KeyedColumnElement[Any]] = set()
- self._populate_column_collection(
- columns=_columns,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- # assigning these three collections separately is not itself atomic,
- # but greatly reduces the surface for problems
- self._columns = _columns
- self.primary_key = primary_key # type: ignore
- self.foreign_keys = foreign_keys # type: ignore
- @util.ro_non_memoized_property
- def entity_namespace(self) -> _EntityNamespace:
- """Return a namespace used for name-based access in SQL expressions.
- This is the namespace that is used to resolve "filter_by()" type
- expressions, such as::
- stmt.filter_by(address="some address")
- It defaults to the ``.c`` collection, however internally it can
- be overridden using the "entity_namespace" annotation to deliver
- alternative results.
- """
- return self.c
- @util.ro_memoized_property
- def primary_key(self) -> Iterable[NamedColumn[Any]]:
- """Return the iterable collection of :class:`_schema.Column` objects
- which comprise the primary key of this :class:`_selectable.FromClause`.
- For a :class:`_schema.Table` object, this collection is represented
- by the :class:`_schema.PrimaryKeyConstraint` which itself is an
- iterable collection of :class:`_schema.Column` objects.
- """
- self._setup_collections()
- return self.primary_key
- @util.ro_memoized_property
- def foreign_keys(self) -> Iterable[ForeignKey]:
- """Return the collection of :class:`_schema.ForeignKey` marker objects
- which this FromClause references.
- Each :class:`_schema.ForeignKey` is a member of a
- :class:`_schema.Table`-wide
- :class:`_schema.ForeignKeyConstraint`.
- .. seealso::
- :attr:`_schema.Table.foreign_key_constraints`
- """
- self._setup_collections()
- return self.foreign_keys
- def _reset_column_collection(self) -> None:
- """Reset the attributes linked to the ``FromClause.c`` attribute.
- This collection is separate from all the other memoized things
- as it has shown to be sensitive to being cleared out in situations
- where enclosing code, typically in a replacement traversal scenario,
- has already established strong relationships
- with the exported columns.
- The collection is cleared for the case where a table is having a
- column added to it as well as within a Join during copy internals.
- """
- for key in ["_columns", "columns", "c", "primary_key", "foreign_keys"]:
- self.__dict__.pop(key, None)
- @util.ro_non_memoized_property
- def _select_iterable(self) -> _SelectIterable:
- return (c for c in self.c if not _never_select_column(c))
- @property
- def _cols_populated(self) -> bool:
- return "_columns" in self.__dict__
- def _populate_column_collection(
- self,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- """Called on subclasses to establish the .c collection.
- Each implementation has a different way of establishing
- this collection.
- """
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- """Given a column added to the .c collection of an underlying
- selectable, produce the local version of that column, assuming this
- selectable ultimately should proxy this column.
- this is used to "ping" a derived selectable to add a new column
- to its .c. collection when a Column has been added to one of the
- Table objects it ultimately derives from.
- If the given selectable hasn't populated its .c. collection yet,
- it should at least pass on the message to the contained selectables,
- but it will return None.
- This method is currently used by Declarative to allow Table
- columns to be added to a partially constructed inheritance
- mapping that may have already produced joins. The method
- isn't public right now, as the full span of implications
- and/or caveats aren't yet clear.
- It's also possible that this functionality could be invoked by
- default via an event, which would require that
- selectables maintain a weak referencing collection of all
- derivations.
- """
- self._reset_column_collection()
- def _anonymous_fromclause(
- self, *, name: Optional[str] = None, flat: bool = False
- ) -> FromClause:
- return self.alias(name=name)
- if TYPE_CHECKING:
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> Union[FromGrouping, Self]: ...
- class NamedFromClause(FromClause):
- """A :class:`.FromClause` that has a name.
- Examples include tables, subqueries, CTEs, aliased tables.
- .. versionadded:: 2.0
- """
- named_with_column = True
- name: str
- @util.preload_module("sqlalchemy.sql.sqltypes")
- def table_valued(self) -> TableValuedColumn[Any]:
- """Return a :class:`_sql.TableValuedColumn` object for this
- :class:`_expression.FromClause`.
- A :class:`_sql.TableValuedColumn` is a :class:`_sql.ColumnElement` that
- represents a complete row in a table. Support for this construct is
- backend dependent, and is supported in various forms by backends
- such as PostgreSQL, Oracle Database and SQL Server.
- E.g.:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import select, column, func, table
- >>> a = table("a", column("id"), column("x"), column("y"))
- >>> stmt = select(func.row_to_json(a.table_valued()))
- >>> print(stmt)
- {printsql}SELECT row_to_json(a) AS row_to_json_1
- FROM a
- .. versionadded:: 1.4.0b2
- .. seealso::
- :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
- """
- return TableValuedColumn(self, type_api.TABLEVALUE)
- class SelectLabelStyle(Enum):
- """Label style constants that may be passed to
- :meth:`_sql.Select.set_label_style`."""
- LABEL_STYLE_NONE = 0
- """Label style indicating no automatic labeling should be applied to the
- columns clause of a SELECT statement.
- Below, the columns named ``columna`` are both rendered as is, meaning that
- the name ``columna`` can only refer to the first occurrence of this name
- within a result set, as well as if the statement were used as a subquery:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_NONE
- >>> table1 = table("table1", column("columna"), column("columnb"))
- >>> table2 = table("table2", column("columna"), column("columnc"))
- >>> print(
- ... select(table1, table2)
- ... .join(table2, true())
- ... .set_label_style(LABEL_STYLE_NONE)
- ... )
- {printsql}SELECT table1.columna, table1.columnb, table2.columna, table2.columnc
- FROM table1 JOIN table2 ON true
- Used with the :meth:`_sql.Select.set_label_style` method.
- .. versionadded:: 1.4
- """ # noqa: E501
- LABEL_STYLE_TABLENAME_PLUS_COL = 1
- """Label style indicating all columns should be labeled as
- ``<tablename>_<columnname>`` when generating the columns clause of a SELECT
- statement, to disambiguate same-named columns referenced from different
- tables, aliases, or subqueries.
- Below, all column names are given a label so that the two same-named
- columns ``columna`` are disambiguated as ``table1_columna`` and
- ``table2_columna``:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import (
- ... table,
- ... column,
- ... select,
- ... true,
- ... LABEL_STYLE_TABLENAME_PLUS_COL,
- ... )
- >>> table1 = table("table1", column("columna"), column("columnb"))
- >>> table2 = table("table2", column("columna"), column("columnc"))
- >>> print(
- ... select(table1, table2)
- ... .join(table2, true())
- ... .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
- ... )
- {printsql}SELECT table1.columna AS table1_columna, table1.columnb AS table1_columnb, table2.columna AS table2_columna, table2.columnc AS table2_columnc
- FROM table1 JOIN table2 ON true
- Used with the :meth:`_sql.GenerativeSelect.set_label_style` method.
- Equivalent to the legacy method ``Select.apply_labels()``;
- :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` is SQLAlchemy's legacy
- auto-labeling style. :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` provides a
- less intrusive approach to disambiguation of same-named column expressions.
- .. versionadded:: 1.4
- """ # noqa: E501
- LABEL_STYLE_DISAMBIGUATE_ONLY = 2
- """Label style indicating that columns with a name that conflicts with
- an existing name should be labeled with a semi-anonymizing label
- when generating the columns clause of a SELECT statement.
- Below, most column names are left unaffected, except for the second
- occurrence of the name ``columna``, which is labeled using the
- label ``columna_1`` to disambiguate it from that of ``tablea.columna``:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import (
- ... table,
- ... column,
- ... select,
- ... true,
- ... LABEL_STYLE_DISAMBIGUATE_ONLY,
- ... )
- >>> table1 = table("table1", column("columna"), column("columnb"))
- >>> table2 = table("table2", column("columna"), column("columnc"))
- >>> print(
- ... select(table1, table2)
- ... .join(table2, true())
- ... .set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
- ... )
- {printsql}SELECT table1.columna, table1.columnb, table2.columna AS columna_1, table2.columnc
- FROM table1 JOIN table2 ON true
- Used with the :meth:`_sql.GenerativeSelect.set_label_style` method,
- :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` is the default labeling style
- for all SELECT statements outside of :term:`1.x style` ORM queries.
- .. versionadded:: 1.4
- """ # noqa: E501
- LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY
- """The default label style, refers to
- :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`.
- .. versionadded:: 1.4
- """
- LABEL_STYLE_LEGACY_ORM = 3
- (
- LABEL_STYLE_NONE,
- LABEL_STYLE_TABLENAME_PLUS_COL,
- LABEL_STYLE_DISAMBIGUATE_ONLY,
- _,
- ) = list(SelectLabelStyle)
- LABEL_STYLE_DEFAULT = LABEL_STYLE_DISAMBIGUATE_ONLY
- class Join(roles.DMLTableRole, FromClause):
- """Represent a ``JOIN`` construct between two
- :class:`_expression.FromClause`
- elements.
- The public constructor function for :class:`_expression.Join`
- is the module-level
- :func:`_expression.join()` function, as well as the
- :meth:`_expression.FromClause.join` method
- of any :class:`_expression.FromClause` (e.g. such as
- :class:`_schema.Table`).
- .. seealso::
- :func:`_expression.join`
- :meth:`_expression.FromClause.join`
- """
- __visit_name__ = "join"
- _traverse_internals: _TraverseInternalsType = [
- ("left", InternalTraversal.dp_clauseelement),
- ("right", InternalTraversal.dp_clauseelement),
- ("onclause", InternalTraversal.dp_clauseelement),
- ("isouter", InternalTraversal.dp_boolean),
- ("full", InternalTraversal.dp_boolean),
- ]
- _is_join = True
- left: FromClause
- right: FromClause
- onclause: Optional[ColumnElement[bool]]
- isouter: bool
- full: bool
- def __init__(
- self,
- left: _FromClauseArgument,
- right: _FromClauseArgument,
- onclause: Optional[_OnClauseArgument] = None,
- isouter: bool = False,
- full: bool = False,
- ):
- """Construct a new :class:`_expression.Join`.
- The usual entrypoint here is the :func:`_expression.join`
- function or the :meth:`_expression.FromClause.join` method of any
- :class:`_expression.FromClause` object.
- """
- # when deannotate was removed here, callcounts went up for ORM
- # compilation of eager joins, since there were more comparisons of
- # annotated objects. test_orm.py -> test_fetch_results
- # was therefore changed to show a more real-world use case, where the
- # compilation is cached; there's no change in post-cache callcounts.
- # callcounts for a single compilation in that particular test
- # that includes about eight joins about 1100 extra fn calls, from
- # 29200 -> 30373
- self.left = coercions.expect(
- roles.FromClauseRole,
- left,
- )
- self.right = coercions.expect(
- roles.FromClauseRole,
- right,
- ).self_group()
- if onclause is None:
- self.onclause = self._match_primaries(self.left, self.right)
- else:
- # note: taken from If91f61527236fd4d7ae3cad1f24c38be921c90ba
- # not merged yet
- self.onclause = coercions.expect(
- roles.OnClauseRole, onclause
- ).self_group(against=operators._asbool)
- self.isouter = isouter
- self.full = full
- @util.ro_non_memoized_property
- def description(self) -> str:
- return "Join object on %s(%d) and %s(%d)" % (
- self.left.description,
- id(self.left),
- self.right.description,
- id(self.right),
- )
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- return (
- # use hash() to ensure direct comparison to annotated works
- # as well
- hash(fromclause) == hash(self)
- or self.left.is_derived_from(fromclause)
- or self.right.is_derived_from(fromclause)
- )
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> FromGrouping:
- return FromGrouping(self)
- @util.preload_module("sqlalchemy.sql.util")
- def _populate_column_collection(
- self,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- sqlutil = util.preloaded.sql_util
- _columns: List[KeyedColumnElement[Any]] = [c for c in self.left.c] + [
- c for c in self.right.c
- ]
- primary_key.extend(
- sqlutil.reduce_columns(
- (c for c in _columns if c.primary_key), self.onclause
- )
- )
- columns._populate_separate_keys(
- (col._tq_key_label, col) for col in _columns # type: ignore
- )
- foreign_keys.update(
- itertools.chain(*[col.foreign_keys for col in _columns]) # type: ignore # noqa: E501
- )
- def _copy_internals(
- self, clone: _CloneCallableType = _clone, **kw: Any
- ) -> None:
- # see Select._copy_internals() for similar concept
- # here we pre-clone "left" and "right" so that we can
- # determine the new FROM clauses
- all_the_froms = set(
- itertools.chain(
- _from_objects(self.left),
- _from_objects(self.right),
- )
- )
- # run the clone on those. these will be placed in the
- # cache used by the clone function
- new_froms = {f: clone(f, **kw) for f in all_the_froms}
- # set up a special replace function that will replace for
- # ColumnClause with parent table referring to those
- # replaced FromClause objects
- def replace(
- obj: Union[BinaryExpression[Any], ColumnClause[Any]],
- **kw: Any,
- ) -> Optional[KeyedColumnElement[Any]]:
- if isinstance(obj, ColumnClause) and obj.table in new_froms:
- newelem = new_froms[obj.table].corresponding_column(obj)
- return newelem
- return None
- kw["replace"] = replace
- # run normal _copy_internals. the clones for
- # left and right will come from the clone function's
- # cache
- super()._copy_internals(clone=clone, **kw)
- self._reset_memoizations()
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- super()._refresh_for_new_column(column)
- self.left._refresh_for_new_column(column)
- self.right._refresh_for_new_column(column)
- def _match_primaries(
- self,
- left: FromClause,
- right: FromClause,
- ) -> ColumnElement[bool]:
- if isinstance(left, Join):
- left_right = left.right
- else:
- left_right = None
- return self._join_condition(left, right, a_subset=left_right)
- @classmethod
- def _join_condition(
- cls,
- a: FromClause,
- b: FromClause,
- *,
- a_subset: Optional[FromClause] = None,
- consider_as_foreign_keys: Optional[
- AbstractSet[ColumnClause[Any]]
- ] = None,
- ) -> ColumnElement[bool]:
- """Create a join condition between two tables or selectables.
- See sqlalchemy.sql.util.join_condition() for full docs.
- """
- constraints = cls._joincond_scan_left_right(
- a, a_subset, b, consider_as_foreign_keys
- )
- if len(constraints) > 1:
- cls._joincond_trim_constraints(
- a, b, constraints, consider_as_foreign_keys
- )
- if len(constraints) == 0:
- if isinstance(b, FromGrouping):
- hint = (
- " Perhaps you meant to convert the right side to a "
- "subquery using alias()?"
- )
- else:
- hint = ""
- raise exc.NoForeignKeysError(
- "Can't find any foreign key relationships "
- "between '%s' and '%s'.%s"
- % (a.description, b.description, hint)
- )
- crit = [(x == y) for x, y in list(constraints.values())[0]]
- if len(crit) == 1:
- return crit[0]
- else:
- return and_(*crit)
- @classmethod
- def _can_join(
- cls,
- left: FromClause,
- right: FromClause,
- *,
- consider_as_foreign_keys: Optional[
- AbstractSet[ColumnClause[Any]]
- ] = None,
- ) -> bool:
- if isinstance(left, Join):
- left_right = left.right
- else:
- left_right = None
- constraints = cls._joincond_scan_left_right(
- a=left,
- b=right,
- a_subset=left_right,
- consider_as_foreign_keys=consider_as_foreign_keys,
- )
- return bool(constraints)
- @classmethod
- @util.preload_module("sqlalchemy.sql.util")
- def _joincond_scan_left_right(
- cls,
- a: FromClause,
- a_subset: Optional[FromClause],
- b: FromClause,
- consider_as_foreign_keys: Optional[AbstractSet[ColumnClause[Any]]],
- ) -> collections.defaultdict[
- Optional[ForeignKeyConstraint],
- List[Tuple[ColumnClause[Any], ColumnClause[Any]]],
- ]:
- sql_util = util.preloaded.sql_util
- a = coercions.expect(roles.FromClauseRole, a)
- b = coercions.expect(roles.FromClauseRole, b)
- constraints: collections.defaultdict[
- Optional[ForeignKeyConstraint],
- List[Tuple[ColumnClause[Any], ColumnClause[Any]]],
- ] = collections.defaultdict(list)
- for left in (a_subset, a):
- if left is None:
- continue
- for fk in sorted(
- b.foreign_keys,
- key=lambda fk: fk.parent._creation_order,
- ):
- if (
- consider_as_foreign_keys is not None
- and fk.parent not in consider_as_foreign_keys
- ):
- continue
- try:
- col = fk.get_referent(left)
- except exc.NoReferenceError as nrte:
- table_names = {t.name for t in sql_util.find_tables(left)}
- if nrte.table_name in table_names:
- raise
- else:
- continue
- if col is not None:
- constraints[fk.constraint].append((col, fk.parent))
- if left is not b:
- for fk in sorted(
- left.foreign_keys,
- key=lambda fk: fk.parent._creation_order,
- ):
- if (
- consider_as_foreign_keys is not None
- and fk.parent not in consider_as_foreign_keys
- ):
- continue
- try:
- col = fk.get_referent(b)
- except exc.NoReferenceError as nrte:
- table_names = {t.name for t in sql_util.find_tables(b)}
- if nrte.table_name in table_names:
- raise
- else:
- continue
- if col is not None:
- constraints[fk.constraint].append((col, fk.parent))
- if constraints:
- break
- return constraints
- @classmethod
- def _joincond_trim_constraints(
- cls,
- a: FromClause,
- b: FromClause,
- constraints: Dict[Any, Any],
- consider_as_foreign_keys: Optional[Any],
- ) -> None:
- # more than one constraint matched. narrow down the list
- # to include just those FKCs that match exactly to
- # "consider_as_foreign_keys".
- if consider_as_foreign_keys:
- for const in list(constraints):
- if {f.parent for f in const.elements} != set(
- consider_as_foreign_keys
- ):
- del constraints[const]
- # if still multiple constraints, but
- # they all refer to the exact same end result, use it.
- if len(constraints) > 1:
- dedupe = {tuple(crit) for crit in constraints.values()}
- if len(dedupe) == 1:
- key = list(constraints)[0]
- constraints = {key: constraints[key]}
- if len(constraints) != 1:
- raise exc.AmbiguousForeignKeysError(
- "Can't determine join between '%s' and '%s'; "
- "tables have more than one foreign key "
- "constraint relationship between them. "
- "Please specify the 'onclause' of this "
- "join explicitly." % (a.description, b.description)
- )
- def select(self) -> Select[Any]:
- r"""Create a :class:`_expression.Select` from this
- :class:`_expression.Join`.
- E.g.::
- stmt = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
- stmt = stmt.select()
- The above will produce a SQL string resembling:
- .. sourcecode:: sql
- SELECT table_a.id, table_a.col, table_b.id, table_b.a_id
- FROM table_a JOIN table_b ON table_a.id = table_b.a_id
- """
- return Select(self.left, self.right).select_from(self)
- @util.preload_module("sqlalchemy.sql.util")
- def _anonymous_fromclause(
- self, name: Optional[str] = None, flat: bool = False
- ) -> TODO_Any:
- sqlutil = util.preloaded.sql_util
- if flat:
- if isinstance(self.left, (FromGrouping, Join)):
- left_name = name # will recurse
- else:
- if name and isinstance(self.left, NamedFromClause):
- left_name = f"{name}_{self.left.name}"
- else:
- left_name = name
- if isinstance(self.right, (FromGrouping, Join)):
- right_name = name # will recurse
- else:
- if name and isinstance(self.right, NamedFromClause):
- right_name = f"{name}_{self.right.name}"
- else:
- right_name = name
- left_a, right_a = (
- self.left._anonymous_fromclause(name=left_name, flat=flat),
- self.right._anonymous_fromclause(name=right_name, flat=flat),
- )
- adapter = sqlutil.ClauseAdapter(left_a).chain(
- sqlutil.ClauseAdapter(right_a)
- )
- return left_a.join(
- right_a,
- adapter.traverse(self.onclause),
- isouter=self.isouter,
- full=self.full,
- )
- else:
- return (
- self.select()
- .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
- .correlate(None)
- .alias(name)
- )
- @util.ro_non_memoized_property
- def _hide_froms(self) -> Iterable[FromClause]:
- return itertools.chain(
- *[_from_objects(x.left, x.right) for x in self._cloned_set]
- )
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]:
- self_list: List[FromClause] = [self]
- return self_list + self.left._from_objects + self.right._from_objects
- class NoInit:
- def __init__(self, *arg: Any, **kw: Any):
- raise NotImplementedError(
- "The %s class is not intended to be constructed "
- "directly. Please use the %s() standalone "
- "function or the %s() method available from appropriate "
- "selectable objects."
- % (
- self.__class__.__name__,
- self.__class__.__name__.lower(),
- self.__class__.__name__.lower(),
- )
- )
- class LateralFromClause(NamedFromClause):
- """mark a FROM clause as being able to render directly as LATERAL"""
- # FromClause ->
- # AliasedReturnsRows
- # -> Alias only for FromClause
- # -> Subquery only for SelectBase
- # -> CTE only for HasCTE -> SelectBase, DML
- # -> Lateral -> FromClause, but we accept SelectBase
- # w/ non-deprecated coercion
- # -> TableSample -> only for FromClause
- class AliasedReturnsRows(NoInit, NamedFromClause):
- """Base class of aliases against tables, subqueries, and other
- selectables."""
- _is_from_container = True
- _supports_derived_columns = False
- element: ReturnsRows
- _traverse_internals: _TraverseInternalsType = [
- ("element", InternalTraversal.dp_clauseelement),
- ("name", InternalTraversal.dp_anon_name),
- ]
- @classmethod
- def _construct(
- cls,
- selectable: Any,
- *,
- name: Optional[str] = None,
- **kw: Any,
- ) -> Self:
- obj = cls.__new__(cls)
- obj._init(selectable, name=name, **kw)
- return obj
- def _init(self, selectable: Any, *, name: Optional[str] = None) -> None:
- self.element = coercions.expect(
- roles.ReturnsRowsRole, selectable, apply_propagate_attrs=self
- )
- self.element = selectable
- self._orig_name = name
- if name is None:
- if (
- isinstance(selectable, FromClause)
- and selectable.named_with_column
- ):
- name = getattr(selectable, "name", None)
- if isinstance(name, _anonymous_label):
- name = None
- name = _anonymous_label.safe_construct(id(self), name or "anon")
- self.name = name
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- super()._refresh_for_new_column(column)
- self.element._refresh_for_new_column(column)
- def _populate_column_collection(
- self,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- self.element._generate_fromclause_column_proxies(
- self, columns, primary_key=primary_key, foreign_keys=foreign_keys
- )
- @util.ro_non_memoized_property
- def description(self) -> str:
- name = self.name
- if isinstance(name, _anonymous_label):
- return "anon_1"
- return name
- @util.ro_non_memoized_property
- def implicit_returning(self) -> bool:
- return self.element.implicit_returning # type: ignore
- @property
- def original(self) -> ReturnsRows:
- """Legacy for dialects that are referring to Alias.original."""
- return self.element
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- if fromclause in self._cloned_set:
- return True
- return self.element.is_derived_from(fromclause)
- def _copy_internals(
- self, clone: _CloneCallableType = _clone, **kw: Any
- ) -> None:
- existing_element = self.element
- super()._copy_internals(clone=clone, **kw)
- # the element clone is usually against a Table that returns the
- # same object. don't reset exported .c. collections and other
- # memoized details if it was not changed. this saves a lot on
- # performance.
- if existing_element is not self.element:
- self._reset_column_collection()
- @property
- def _from_objects(self) -> List[FromClause]:
- return [self]
- class FromClauseAlias(AliasedReturnsRows):
- element: FromClause
- @util.ro_non_memoized_property
- def description(self) -> str:
- name = self.name
- if isinstance(name, _anonymous_label):
- return f"Anonymous alias of {self.element.description}"
- return name
- class Alias(roles.DMLTableRole, FromClauseAlias):
- """Represents an table or selectable alias (AS).
- Represents an alias, as typically applied to any table or
- sub-select within a SQL statement using the ``AS`` keyword (or
- without the keyword on certain databases such as Oracle Database).
- This object is constructed from the :func:`_expression.alias` module
- level function as well as the :meth:`_expression.FromClause.alias`
- method available
- on all :class:`_expression.FromClause` subclasses.
- .. seealso::
- :meth:`_expression.FromClause.alias`
- """
- __visit_name__ = "alias"
- inherit_cache = True
- element: FromClause
- @classmethod
- def _factory(
- cls,
- selectable: FromClause,
- name: Optional[str] = None,
- flat: bool = False,
- ) -> NamedFromClause:
- return coercions.expect(
- roles.FromClauseRole, selectable, allow_select=True
- ).alias(name=name, flat=flat)
- class TableValuedAlias(LateralFromClause, Alias):
- """An alias against a "table valued" SQL function.
- This construct provides for a SQL function that returns columns
- to be used in the FROM clause of a SELECT statement. The
- object is generated using the :meth:`_functions.FunctionElement.table_valued`
- method, e.g.:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import select, func
- >>> fn = func.json_array_elements_text('["one", "two", "three"]').table_valued(
- ... "value"
- ... )
- >>> print(select(fn.c.value))
- {printsql}SELECT anon_1.value
- FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1
- .. versionadded:: 1.4.0b2
- .. seealso::
- :ref:`tutorial_functions_table_valued` - in the :ref:`unified_tutorial`
- """ # noqa: E501
- __visit_name__ = "table_valued_alias"
- _supports_derived_columns = True
- _render_derived = False
- _render_derived_w_types = False
- joins_implicitly = False
- _traverse_internals: _TraverseInternalsType = [
- ("element", InternalTraversal.dp_clauseelement),
- ("name", InternalTraversal.dp_anon_name),
- ("_tableval_type", InternalTraversal.dp_type),
- ("_render_derived", InternalTraversal.dp_boolean),
- ("_render_derived_w_types", InternalTraversal.dp_boolean),
- ]
- def _init(
- self,
- selectable: Any,
- *,
- name: Optional[str] = None,
- table_value_type: Optional[TableValueType] = None,
- joins_implicitly: bool = False,
- ) -> None:
- super()._init(selectable, name=name)
- self.joins_implicitly = joins_implicitly
- self._tableval_type = (
- type_api.TABLEVALUE
- if table_value_type is None
- else table_value_type
- )
- @HasMemoized.memoized_attribute
- def column(self) -> TableValuedColumn[Any]:
- """Return a column expression representing this
- :class:`_sql.TableValuedAlias`.
- This accessor is used to implement the
- :meth:`_functions.FunctionElement.column_valued` method. See that
- method for further details.
- E.g.:
- .. sourcecode:: pycon+sql
- >>> print(select(func.some_func().table_valued("value").column))
- {printsql}SELECT anon_1 FROM some_func() AS anon_1
- .. seealso::
- :meth:`_functions.FunctionElement.column_valued`
- """
- return TableValuedColumn(self, self._tableval_type)
- def alias(
- self, name: Optional[str] = None, flat: bool = False
- ) -> TableValuedAlias:
- """Return a new alias of this :class:`_sql.TableValuedAlias`.
- This creates a distinct FROM object that will be distinguished
- from the original one when used in a SQL statement.
- """
- tva: TableValuedAlias = TableValuedAlias._construct(
- self,
- name=name,
- table_value_type=self._tableval_type,
- joins_implicitly=self.joins_implicitly,
- )
- if self._render_derived:
- tva._render_derived = True
- tva._render_derived_w_types = self._render_derived_w_types
- return tva
- def lateral(self, name: Optional[str] = None) -> LateralFromClause:
- """Return a new :class:`_sql.TableValuedAlias` with the lateral flag
- set, so that it renders as LATERAL.
- .. seealso::
- :func:`_expression.lateral`
- """
- tva = self.alias(name=name)
- tva._is_lateral = True
- return tva
- def render_derived(
- self,
- name: Optional[str] = None,
- with_types: bool = False,
- ) -> TableValuedAlias:
- """Apply "render derived" to this :class:`_sql.TableValuedAlias`.
- This has the effect of the individual column names listed out
- after the alias name in the "AS" sequence, e.g.:
- .. sourcecode:: pycon+sql
- >>> print(
- ... select(
- ... func.unnest(array(["one", "two", "three"]))
- ... .table_valued("x", with_ordinality="o")
- ... .render_derived()
- ... )
- ... )
- {printsql}SELECT anon_1.x, anon_1.o
- FROM unnest(ARRAY[%(param_1)s, %(param_2)s, %(param_3)s]) WITH ORDINALITY AS anon_1(x, o)
- The ``with_types`` keyword will render column types inline within
- the alias expression (this syntax currently applies to the
- PostgreSQL database):
- .. sourcecode:: pycon+sql
- >>> print(
- ... select(
- ... func.json_to_recordset('[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]')
- ... .table_valued(column("a", Integer), column("b", String))
- ... .render_derived(with_types=True)
- ... )
- ... )
- {printsql}SELECT anon_1.a, anon_1.b FROM json_to_recordset(:json_to_recordset_1)
- AS anon_1(a INTEGER, b VARCHAR)
- :param name: optional string name that will be applied to the alias
- generated. If left as None, a unique anonymizing name will be used.
- :param with_types: if True, the derived columns will include the
- datatype specification with each column. This is a special syntax
- currently known to be required by PostgreSQL for some SQL functions.
- """ # noqa: E501
- # note: don't use the @_generative system here, keep a reference
- # to the original object. otherwise you can have re-use of the
- # python id() of the original which can cause name conflicts if
- # a new anon-name grabs the same identifier as the local anon-name
- # (just saw it happen on CI)
- # construct against original to prevent memory growth
- # for repeated generations
- new_alias: TableValuedAlias = TableValuedAlias._construct(
- self.element,
- name=name,
- table_value_type=self._tableval_type,
- joins_implicitly=self.joins_implicitly,
- )
- new_alias._render_derived = True
- new_alias._render_derived_w_types = with_types
- return new_alias
- class Lateral(FromClauseAlias, LateralFromClause):
- """Represent a LATERAL subquery.
- This object is constructed from the :func:`_expression.lateral` module
- level function as well as the :meth:`_expression.FromClause.lateral`
- method available
- on all :class:`_expression.FromClause` subclasses.
- While LATERAL is part of the SQL standard, currently only more recent
- PostgreSQL versions provide support for this keyword.
- .. seealso::
- :ref:`tutorial_lateral_correlation` - overview of usage.
- """
- __visit_name__ = "lateral"
- _is_lateral = True
- inherit_cache = True
- @classmethod
- def _factory(
- cls,
- selectable: Union[SelectBase, _FromClauseArgument],
- name: Optional[str] = None,
- ) -> LateralFromClause:
- return coercions.expect(
- roles.FromClauseRole, selectable, explicit_subquery=True
- ).lateral(name=name)
- class TableSample(FromClauseAlias):
- """Represent a TABLESAMPLE clause.
- This object is constructed from the :func:`_expression.tablesample` module
- level function as well as the :meth:`_expression.FromClause.tablesample`
- method
- available on all :class:`_expression.FromClause` subclasses.
- .. seealso::
- :func:`_expression.tablesample`
- """
- __visit_name__ = "tablesample"
- _traverse_internals: _TraverseInternalsType = (
- AliasedReturnsRows._traverse_internals
- + [
- ("sampling", InternalTraversal.dp_clauseelement),
- ("seed", InternalTraversal.dp_clauseelement),
- ]
- )
- @classmethod
- def _factory(
- cls,
- selectable: _FromClauseArgument,
- sampling: Union[float, Function[Any]],
- name: Optional[str] = None,
- seed: Optional[roles.ExpressionElementRole[Any]] = None,
- ) -> TableSample:
- return coercions.expect(roles.FromClauseRole, selectable).tablesample(
- sampling, name=name, seed=seed
- )
- @util.preload_module("sqlalchemy.sql.functions")
- def _init( # type: ignore[override]
- self,
- selectable: Any,
- *,
- name: Optional[str] = None,
- sampling: Union[float, Function[Any]],
- seed: Optional[roles.ExpressionElementRole[Any]] = None,
- ) -> None:
- assert sampling is not None
- functions = util.preloaded.sql_functions
- if not isinstance(sampling, functions.Function):
- sampling = functions.func.system(sampling)
- self.sampling: Function[Any] = sampling
- self.seed = seed
- super()._init(selectable, name=name)
- def _get_method(self) -> Function[Any]:
- return self.sampling
- class CTE(
- roles.DMLTableRole,
- roles.IsCTERole,
- Generative,
- HasPrefixes,
- HasSuffixes,
- AliasedReturnsRows,
- ):
- """Represent a Common Table Expression.
- The :class:`_expression.CTE` object is obtained using the
- :meth:`_sql.SelectBase.cte` method from any SELECT statement. A less often
- available syntax also allows use of the :meth:`_sql.HasCTE.cte` method
- present on :term:`DML` constructs such as :class:`_sql.Insert`,
- :class:`_sql.Update` and
- :class:`_sql.Delete`. See the :meth:`_sql.HasCTE.cte` method for
- usage details on CTEs.
- .. seealso::
- :ref:`tutorial_subqueries_ctes` - in the 2.0 tutorial
- :meth:`_sql.HasCTE.cte` - examples of calling styles
- """
- __visit_name__ = "cte"
- _traverse_internals: _TraverseInternalsType = (
- AliasedReturnsRows._traverse_internals
- + [
- ("_cte_alias", InternalTraversal.dp_clauseelement),
- ("_restates", InternalTraversal.dp_clauseelement),
- ("recursive", InternalTraversal.dp_boolean),
- ("nesting", InternalTraversal.dp_boolean),
- ]
- + HasPrefixes._has_prefixes_traverse_internals
- + HasSuffixes._has_suffixes_traverse_internals
- )
- element: HasCTE
- @classmethod
- def _factory(
- cls,
- selectable: HasCTE,
- name: Optional[str] = None,
- recursive: bool = False,
- ) -> CTE:
- r"""Return a new :class:`_expression.CTE`,
- or Common Table Expression instance.
- Please see :meth:`_expression.HasCTE.cte` for detail on CTE usage.
- """
- return coercions.expect(roles.HasCTERole, selectable).cte(
- name=name, recursive=recursive
- )
- def _init(
- self,
- selectable: Select[Any],
- *,
- name: Optional[str] = None,
- recursive: bool = False,
- nesting: bool = False,
- _cte_alias: Optional[CTE] = None,
- _restates: Optional[CTE] = None,
- _prefixes: Optional[Tuple[()]] = None,
- _suffixes: Optional[Tuple[()]] = None,
- ) -> None:
- self.recursive = recursive
- self.nesting = nesting
- self._cte_alias = _cte_alias
- # Keep recursivity reference with union/union_all
- self._restates = _restates
- if _prefixes:
- self._prefixes = _prefixes
- if _suffixes:
- self._suffixes = _suffixes
- super()._init(selectable, name=name)
- def _populate_column_collection(
- self,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- if self._cte_alias is not None:
- self._cte_alias._generate_fromclause_column_proxies(
- self,
- columns,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- else:
- self.element._generate_fromclause_column_proxies(
- self,
- columns,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- def alias(self, name: Optional[str] = None, flat: bool = False) -> CTE:
- """Return an :class:`_expression.Alias` of this
- :class:`_expression.CTE`.
- This method is a CTE-specific specialization of the
- :meth:`_expression.FromClause.alias` method.
- .. seealso::
- :ref:`tutorial_using_aliases`
- :func:`_expression.alias`
- """
- return CTE._construct(
- self.element,
- name=name,
- recursive=self.recursive,
- nesting=self.nesting,
- _cte_alias=self,
- _prefixes=self._prefixes,
- _suffixes=self._suffixes,
- )
- def union(self, *other: _SelectStatementForCompoundArgument[Any]) -> CTE:
- r"""Return a new :class:`_expression.CTE` with a SQL ``UNION``
- of the original CTE against the given selectables provided
- as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28 multiple elements are now accepted.
- .. seealso::
- :meth:`_sql.HasCTE.cte` - examples of calling styles
- """
- assert is_select_statement(
- self.element
- ), f"CTE element f{self.element} does not support union()"
- return CTE._construct(
- self.element.union(*other),
- name=self.name,
- recursive=self.recursive,
- nesting=self.nesting,
- _restates=self,
- _prefixes=self._prefixes,
- _suffixes=self._suffixes,
- )
- def union_all(
- self, *other: _SelectStatementForCompoundArgument[Any]
- ) -> CTE:
- r"""Return a new :class:`_expression.CTE` with a SQL ``UNION ALL``
- of the original CTE against the given selectables provided
- as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28 multiple elements are now accepted.
- .. seealso::
- :meth:`_sql.HasCTE.cte` - examples of calling styles
- """
- assert is_select_statement(
- self.element
- ), f"CTE element f{self.element} does not support union_all()"
- return CTE._construct(
- self.element.union_all(*other),
- name=self.name,
- recursive=self.recursive,
- nesting=self.nesting,
- _restates=self,
- _prefixes=self._prefixes,
- _suffixes=self._suffixes,
- )
- def _get_reference_cte(self) -> CTE:
- """
- A recursive CTE is updated to attach the recursive part.
- Updated CTEs should still refer to the original CTE.
- This function returns this reference identifier.
- """
- return self._restates if self._restates is not None else self
- class _CTEOpts(NamedTuple):
- nesting: bool
- class _ColumnsPlusNames(NamedTuple):
- required_label_name: Optional[str]
- """
- string label name, if non-None, must be rendered as a
- label, i.e. "AS <name>"
- """
- proxy_key: Optional[str]
- """
- proxy_key that is to be part of the result map for this
- col. this is also the key in a fromclause.c or
- select.selected_columns collection
- """
- fallback_label_name: Optional[str]
- """
- name that can be used to render an "AS <name>" when
- we have to render a label even though
- required_label_name was not given
- """
- column: Union[ColumnElement[Any], TextClause]
- """
- the ColumnElement itself
- """
- repeated: bool
- """
- True if this is a duplicate of a previous column
- in the list of columns
- """
- class SelectsRows(ReturnsRows):
- """Sub-base of ReturnsRows for elements that deliver rows
- directly, namely SELECT and INSERT/UPDATE/DELETE..RETURNING"""
- _label_style: SelectLabelStyle = LABEL_STYLE_NONE
- def _generate_columns_plus_names(
- self,
- anon_for_dupe_key: bool,
- cols: Optional[_SelectIterable] = None,
- ) -> List[_ColumnsPlusNames]:
- """Generate column names as rendered in a SELECT statement by
- the compiler.
- This is distinct from the _column_naming_convention generator that's
- intended for population of .c collections and similar, which has
- different rules. the collection returned here calls upon the
- _column_naming_convention as well.
- """
- if cols is None:
- cols = self._all_selected_columns
- key_naming_convention = SelectState._column_naming_convention(
- self._label_style
- )
- names = {}
- result: List[_ColumnsPlusNames] = []
- result_append = result.append
- table_qualified = self._label_style is LABEL_STYLE_TABLENAME_PLUS_COL
- label_style_none = self._label_style is LABEL_STYLE_NONE
- # a counter used for "dedupe" labels, which have double underscores
- # in them and are never referred by name; they only act
- # as positional placeholders. they need only be unique within
- # the single columns clause they're rendered within (required by
- # some dbs such as mysql). So their anon identity is tracked against
- # a fixed counter rather than hash() identity.
- dedupe_hash = 1
- for c in cols:
- repeated = False
- if not c._render_label_in_columns_clause:
- effective_name = required_label_name = fallback_label_name = (
- None
- )
- elif label_style_none:
- if TYPE_CHECKING:
- assert is_column_element(c)
- effective_name = required_label_name = None
- fallback_label_name = c._non_anon_label or c._anon_name_label
- else:
- if TYPE_CHECKING:
- assert is_column_element(c)
- if table_qualified:
- required_label_name = effective_name = (
- fallback_label_name
- ) = c._tq_label
- else:
- effective_name = fallback_label_name = c._non_anon_label
- required_label_name = None
- if effective_name is None:
- # it seems like this could be _proxy_key and we would
- # not need _expression_label but it isn't
- # giving us a clue when to use anon_label instead
- expr_label = c._expression_label
- if expr_label is None:
- repeated = c._anon_name_label in names
- names[c._anon_name_label] = c
- effective_name = required_label_name = None
- if repeated:
- # here, "required_label_name" is sent as
- # "None" and "fallback_label_name" is sent.
- if table_qualified:
- fallback_label_name = (
- c._dedupe_anon_tq_label_idx(dedupe_hash)
- )
- dedupe_hash += 1
- else:
- fallback_label_name = c._dedupe_anon_label_idx(
- dedupe_hash
- )
- dedupe_hash += 1
- else:
- fallback_label_name = c._anon_name_label
- else:
- required_label_name = effective_name = (
- fallback_label_name
- ) = expr_label
- if effective_name is not None:
- if TYPE_CHECKING:
- assert is_column_element(c)
- if effective_name in names:
- # when looking to see if names[name] is the same column as
- # c, use hash(), so that an annotated version of the column
- # is seen as the same as the non-annotated
- if hash(names[effective_name]) != hash(c):
- # different column under the same name. apply
- # disambiguating label
- if table_qualified:
- required_label_name = fallback_label_name = (
- c._anon_tq_label
- )
- else:
- required_label_name = fallback_label_name = (
- c._anon_name_label
- )
- if anon_for_dupe_key and required_label_name in names:
- # here, c._anon_tq_label is definitely unique to
- # that column identity (or annotated version), so
- # this should always be true.
- # this is also an infrequent codepath because
- # you need two levels of duplication to be here
- assert hash(names[required_label_name]) == hash(c)
- # the column under the disambiguating label is
- # already present. apply the "dedupe" label to
- # subsequent occurrences of the column so that the
- # original stays non-ambiguous
- if table_qualified:
- required_label_name = fallback_label_name = (
- c._dedupe_anon_tq_label_idx(dedupe_hash)
- )
- dedupe_hash += 1
- else:
- required_label_name = fallback_label_name = (
- c._dedupe_anon_label_idx(dedupe_hash)
- )
- dedupe_hash += 1
- repeated = True
- else:
- names[required_label_name] = c
- elif anon_for_dupe_key:
- # same column under the same name. apply the "dedupe"
- # label so that the original stays non-ambiguous
- if table_qualified:
- required_label_name = fallback_label_name = (
- c._dedupe_anon_tq_label_idx(dedupe_hash)
- )
- dedupe_hash += 1
- else:
- required_label_name = fallback_label_name = (
- c._dedupe_anon_label_idx(dedupe_hash)
- )
- dedupe_hash += 1
- repeated = True
- else:
- names[effective_name] = c
- result_append(
- _ColumnsPlusNames(
- required_label_name,
- key_naming_convention(c),
- fallback_label_name,
- c,
- repeated,
- )
- )
- return result
- class HasCTE(roles.HasCTERole, SelectsRows):
- """Mixin that declares a class to include CTE support."""
- _has_ctes_traverse_internals: _TraverseInternalsType = [
- ("_independent_ctes", InternalTraversal.dp_clauseelement_list),
- ("_independent_ctes_opts", InternalTraversal.dp_plain_obj),
- ]
- _independent_ctes: Tuple[CTE, ...] = ()
- _independent_ctes_opts: Tuple[_CTEOpts, ...] = ()
- name_cte_columns: bool = False
- """indicates if this HasCTE as contained within a CTE should compel the CTE
- to render the column names of this object in the WITH clause.
- .. versionadded:: 2.0.42
- """
- @_generative
- def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self:
- r"""Add one or more :class:`_sql.CTE` constructs to this statement.
- This method will associate the given :class:`_sql.CTE` constructs with
- the parent statement such that they will each be unconditionally
- rendered in the WITH clause of the final statement, even if not
- referenced elsewhere within the statement or any sub-selects.
- The optional :paramref:`.HasCTE.add_cte.nest_here` parameter when set
- to True will have the effect that each given :class:`_sql.CTE` will
- render in a WITH clause rendered directly along with this statement,
- rather than being moved to the top of the ultimate rendered statement,
- even if this statement is rendered as a subquery within a larger
- statement.
- This method has two general uses. One is to embed CTE statements that
- serve some purpose without being referenced explicitly, such as the use
- case of embedding a DML statement such as an INSERT or UPDATE as a CTE
- inline with a primary statement that may draw from its results
- indirectly. The other is to provide control over the exact placement
- of a particular series of CTE constructs that should remain rendered
- directly in terms of a particular statement that may be nested in a
- larger statement.
- E.g.::
- from sqlalchemy import table, column, select
- t = table("t", column("c1"), column("c2"))
- ins = t.insert().values({"c1": "x", "c2": "y"}).cte()
- stmt = select(t).add_cte(ins)
- Would render:
- .. sourcecode:: sql
- WITH anon_1 AS (
- INSERT INTO t (c1, c2) VALUES (:param_1, :param_2)
- )
- SELECT t.c1, t.c2
- FROM t
- Above, the "anon_1" CTE is not referenced in the SELECT
- statement, however still accomplishes the task of running an INSERT
- statement.
- Similarly in a DML-related context, using the PostgreSQL
- :class:`_postgresql.Insert` construct to generate an "upsert"::
- from sqlalchemy import table, column
- from sqlalchemy.dialects.postgresql import insert
- t = table("t", column("c1"), column("c2"))
- delete_statement_cte = t.delete().where(t.c.c1 < 1).cte("deletions")
- insert_stmt = insert(t).values({"c1": 1, "c2": 2})
- update_statement = insert_stmt.on_conflict_do_update(
- index_elements=[t.c.c1],
- set_={
- "c1": insert_stmt.excluded.c1,
- "c2": insert_stmt.excluded.c2,
- },
- ).add_cte(delete_statement_cte)
- print(update_statement)
- The above statement renders as:
- .. sourcecode:: sql
- WITH deletions AS (
- DELETE FROM t WHERE t.c1 < %(c1_1)s
- )
- INSERT INTO t (c1, c2) VALUES (%(c1)s, %(c2)s)
- ON CONFLICT (c1) DO UPDATE SET c1 = excluded.c1, c2 = excluded.c2
- .. versionadded:: 1.4.21
- :param \*ctes: zero or more :class:`.CTE` constructs.
- .. versionchanged:: 2.0 Multiple CTE instances are accepted
- :param nest_here: if True, the given CTE or CTEs will be rendered
- as though they specified the :paramref:`.HasCTE.cte.nesting` flag
- to ``True`` when they were added to this :class:`.HasCTE`.
- Assuming the given CTEs are not referenced in an outer-enclosing
- statement as well, the CTEs given should render at the level of
- this statement when this flag is given.
- .. versionadded:: 2.0
- .. seealso::
- :paramref:`.HasCTE.cte.nesting`
- """ # noqa: E501
- opt = _CTEOpts(nest_here)
- for cte in ctes:
- cte = coercions.expect(roles.IsCTERole, cte)
- self._independent_ctes += (cte,)
- self._independent_ctes_opts += (opt,)
- return self
- def cte(
- self,
- name: Optional[str] = None,
- recursive: bool = False,
- nesting: bool = False,
- ) -> CTE:
- r"""Return a new :class:`_expression.CTE`,
- or Common Table Expression instance.
- Common table expressions are a SQL standard whereby SELECT
- statements can draw upon secondary statements specified along
- with the primary statement, using a clause called "WITH".
- Special semantics regarding UNION can also be employed to
- allow "recursive" queries, where a SELECT statement can draw
- upon the set of rows that have previously been selected.
- CTEs can also be applied to DML constructs UPDATE, INSERT
- and DELETE on some databases, both as a source of CTE rows
- when combined with RETURNING, as well as a consumer of
- CTE rows.
- SQLAlchemy detects :class:`_expression.CTE` objects, which are treated
- similarly to :class:`_expression.Alias` objects, as special elements
- to be delivered to the FROM clause of the statement as well
- as to a WITH clause at the top of the statement.
- For special prefixes such as PostgreSQL "MATERIALIZED" and
- "NOT MATERIALIZED", the :meth:`_expression.CTE.prefix_with`
- method may be
- used to establish these.
- .. versionchanged:: 1.3.13 Added support for prefixes.
- In particular - MATERIALIZED and NOT MATERIALIZED.
- :param name: name given to the common table expression. Like
- :meth:`_expression.FromClause.alias`, the name can be left as
- ``None`` in which case an anonymous symbol will be used at query
- compile time.
- :param recursive: if ``True``, will render ``WITH RECURSIVE``.
- A recursive common table expression is intended to be used in
- conjunction with UNION ALL in order to derive rows
- from those already selected.
- :param nesting: if ``True``, will render the CTE locally to the
- statement in which it is referenced. For more complex scenarios,
- the :meth:`.HasCTE.add_cte` method using the
- :paramref:`.HasCTE.add_cte.nest_here`
- parameter may also be used to more carefully
- control the exact placement of a particular CTE.
- .. versionadded:: 1.4.24
- .. seealso::
- :meth:`.HasCTE.add_cte`
- The following examples include two from PostgreSQL's documentation at
- https://www.postgresql.org/docs/current/static/queries-with.html,
- as well as additional examples.
- Example 1, non recursive::
- from sqlalchemy import (
- Table,
- Column,
- String,
- Integer,
- MetaData,
- select,
- func,
- )
- metadata = MetaData()
- orders = Table(
- "orders",
- metadata,
- Column("region", String),
- Column("amount", Integer),
- Column("product", String),
- Column("quantity", Integer),
- )
- regional_sales = (
- select(orders.c.region, func.sum(orders.c.amount).label("total_sales"))
- .group_by(orders.c.region)
- .cte("regional_sales")
- )
- top_regions = (
- select(regional_sales.c.region)
- .where(
- regional_sales.c.total_sales
- > select(func.sum(regional_sales.c.total_sales) / 10)
- )
- .cte("top_regions")
- )
- statement = (
- select(
- orders.c.region,
- orders.c.product,
- func.sum(orders.c.quantity).label("product_units"),
- func.sum(orders.c.amount).label("product_sales"),
- )
- .where(orders.c.region.in_(select(top_regions.c.region)))
- .group_by(orders.c.region, orders.c.product)
- )
- result = conn.execute(statement).fetchall()
- Example 2, WITH RECURSIVE::
- from sqlalchemy import (
- Table,
- Column,
- String,
- Integer,
- MetaData,
- select,
- func,
- )
- metadata = MetaData()
- parts = Table(
- "parts",
- metadata,
- Column("part", String),
- Column("sub_part", String),
- Column("quantity", Integer),
- )
- included_parts = (
- select(parts.c.sub_part, parts.c.part, parts.c.quantity)
- .where(parts.c.part == "our part")
- .cte(recursive=True)
- )
- incl_alias = included_parts.alias()
- parts_alias = parts.alias()
- included_parts = included_parts.union_all(
- select(
- parts_alias.c.sub_part, parts_alias.c.part, parts_alias.c.quantity
- ).where(parts_alias.c.part == incl_alias.c.sub_part)
- )
- statement = select(
- included_parts.c.sub_part,
- func.sum(included_parts.c.quantity).label("total_quantity"),
- ).group_by(included_parts.c.sub_part)
- result = conn.execute(statement).fetchall()
- Example 3, an upsert using UPDATE and INSERT with CTEs::
- from datetime import date
- from sqlalchemy import (
- MetaData,
- Table,
- Column,
- Integer,
- Date,
- select,
- literal,
- and_,
- exists,
- )
- metadata = MetaData()
- visitors = Table(
- "visitors",
- metadata,
- Column("product_id", Integer, primary_key=True),
- Column("date", Date, primary_key=True),
- Column("count", Integer),
- )
- # add 5 visitors for the product_id == 1
- product_id = 1
- day = date.today()
- count = 5
- update_cte = (
- visitors.update()
- .where(
- and_(visitors.c.product_id == product_id, visitors.c.date == day)
- )
- .values(count=visitors.c.count + count)
- .returning(literal(1))
- .cte("update_cte")
- )
- upsert = visitors.insert().from_select(
- [visitors.c.product_id, visitors.c.date, visitors.c.count],
- select(literal(product_id), literal(day), literal(count)).where(
- ~exists(update_cte.select())
- ),
- )
- connection.execute(upsert)
- Example 4, Nesting CTE (SQLAlchemy 1.4.24 and above)::
- value_a = select(literal("root").label("n")).cte("value_a")
- # A nested CTE with the same name as the root one
- value_a_nested = select(literal("nesting").label("n")).cte(
- "value_a", nesting=True
- )
- # Nesting CTEs takes ascendency locally
- # over the CTEs at a higher level
- value_b = select(value_a_nested.c.n).cte("value_b")
- value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b"))
- The above query will render the second CTE nested inside the first,
- shown with inline parameters below as:
- .. sourcecode:: sql
- WITH
- value_a AS
- (SELECT 'root' AS n),
- value_b AS
- (WITH value_a AS
- (SELECT 'nesting' AS n)
- SELECT value_a.n AS n FROM value_a)
- SELECT value_a.n AS a, value_b.n AS b
- FROM value_a, value_b
- The same CTE can be set up using the :meth:`.HasCTE.add_cte` method
- as follows (SQLAlchemy 2.0 and above)::
- value_a = select(literal("root").label("n")).cte("value_a")
- # A nested CTE with the same name as the root one
- value_a_nested = select(literal("nesting").label("n")).cte("value_a")
- # Nesting CTEs takes ascendency locally
- # over the CTEs at a higher level
- value_b = (
- select(value_a_nested.c.n)
- .add_cte(value_a_nested, nest_here=True)
- .cte("value_b")
- )
- value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b"))
- Example 5, Non-Linear CTE (SQLAlchemy 1.4.28 and above)::
- edge = Table(
- "edge",
- metadata,
- Column("id", Integer, primary_key=True),
- Column("left", Integer),
- Column("right", Integer),
- )
- root_node = select(literal(1).label("node")).cte("nodes", recursive=True)
- left_edge = select(edge.c.left).join(
- root_node, edge.c.right == root_node.c.node
- )
- right_edge = select(edge.c.right).join(
- root_node, edge.c.left == root_node.c.node
- )
- subgraph_cte = root_node.union(left_edge, right_edge)
- subgraph = select(subgraph_cte)
- The above query will render 2 UNIONs inside the recursive CTE:
- .. sourcecode:: sql
- WITH RECURSIVE nodes(node) AS (
- SELECT 1 AS node
- UNION
- SELECT edge."left" AS "left"
- FROM edge JOIN nodes ON edge."right" = nodes.node
- UNION
- SELECT edge."right" AS "right"
- FROM edge JOIN nodes ON edge."left" = nodes.node
- )
- SELECT nodes.node FROM nodes
- .. seealso::
- :meth:`_orm.Query.cte` - ORM version of
- :meth:`_expression.HasCTE.cte`.
- """ # noqa: E501
- return CTE._construct(
- self, name=name, recursive=recursive, nesting=nesting
- )
- class Subquery(AliasedReturnsRows):
- """Represent a subquery of a SELECT.
- A :class:`.Subquery` is created by invoking the
- :meth:`_expression.SelectBase.subquery` method, or for convenience the
- :meth:`_expression.SelectBase.alias` method, on any
- :class:`_expression.SelectBase` subclass
- which includes :class:`_expression.Select`,
- :class:`_expression.CompoundSelect`, and
- :class:`_expression.TextualSelect`. As rendered in a FROM clause,
- it represents the
- body of the SELECT statement inside of parenthesis, followed by the usual
- "AS <somename>" that defines all "alias" objects.
- The :class:`.Subquery` object is very similar to the
- :class:`_expression.Alias`
- object and can be used in an equivalent way. The difference between
- :class:`_expression.Alias` and :class:`.Subquery` is that
- :class:`_expression.Alias` always
- contains a :class:`_expression.FromClause` object whereas
- :class:`.Subquery`
- always contains a :class:`_expression.SelectBase` object.
- .. versionadded:: 1.4 The :class:`.Subquery` class was added which now
- serves the purpose of providing an aliased version of a SELECT
- statement.
- """
- __visit_name__ = "subquery"
- _is_subquery = True
- inherit_cache = True
- element: SelectBase
- @classmethod
- def _factory(
- cls, selectable: SelectBase, name: Optional[str] = None
- ) -> Subquery:
- """Return a :class:`.Subquery` object."""
- return coercions.expect(
- roles.SelectStatementRole, selectable
- ).subquery(name=name)
- @util.deprecated(
- "1.4",
- "The :meth:`.Subquery.as_scalar` method, which was previously "
- "``Alias.as_scalar()`` prior to version 1.4, is deprecated and "
- "will be removed in a future release; Please use the "
- ":meth:`_expression.Select.scalar_subquery` method of the "
- ":func:`_expression.select` "
- "construct before constructing a subquery object, or with the ORM "
- "use the :meth:`_query.Query.scalar_subquery` method.",
- )
- def as_scalar(self) -> ScalarSelect[Any]:
- return self.element.set_label_style(LABEL_STYLE_NONE).scalar_subquery()
- class FromGrouping(GroupedElement, FromClause):
- """Represent a grouping of a FROM clause"""
- _traverse_internals: _TraverseInternalsType = [
- ("element", InternalTraversal.dp_clauseelement)
- ]
- element: FromClause
- def __init__(self, element: FromClause):
- self.element = coercions.expect(roles.FromClauseRole, element)
- @util.ro_non_memoized_property
- def columns(
- self,
- ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- return self.element.columns
- @util.ro_non_memoized_property
- def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- return self.element.columns
- @property
- def primary_key(self) -> Iterable[NamedColumn[Any]]:
- return self.element.primary_key
- @property
- def foreign_keys(self) -> Iterable[ForeignKey]:
- return self.element.foreign_keys
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- return self.element.is_derived_from(fromclause)
- def alias(
- self, name: Optional[str] = None, flat: bool = False
- ) -> NamedFromGrouping:
- return NamedFromGrouping(self.element.alias(name=name, flat=flat))
- def _anonymous_fromclause(self, **kw: Any) -> FromGrouping:
- return FromGrouping(self.element._anonymous_fromclause(**kw))
- @util.ro_non_memoized_property
- def _hide_froms(self) -> Iterable[FromClause]:
- return self.element._hide_froms
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]:
- return self.element._from_objects
- def __getstate__(self) -> Dict[str, FromClause]:
- return {"element": self.element}
- def __setstate__(self, state: Dict[str, FromClause]) -> None:
- self.element = state["element"]
- if TYPE_CHECKING:
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> Self: ...
- class NamedFromGrouping(FromGrouping, NamedFromClause):
- """represent a grouping of a named FROM clause
- .. versionadded:: 2.0
- """
- inherit_cache = True
- if TYPE_CHECKING:
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> Self: ...
- class TableClause(roles.DMLTableRole, Immutable, NamedFromClause):
- """Represents a minimal "table" construct.
- This is a lightweight table object that has only a name, a
- collection of columns, which are typically produced
- by the :func:`_expression.column` function, and a schema::
- from sqlalchemy import table, column
- user = table(
- "user",
- column("id"),
- column("name"),
- column("description"),
- )
- The :class:`_expression.TableClause` construct serves as the base for
- the more commonly used :class:`_schema.Table` object, providing
- the usual set of :class:`_expression.FromClause` services including
- the ``.c.`` collection and statement generation methods.
- It does **not** provide all the additional schema-level services
- of :class:`_schema.Table`, including constraints, references to other
- tables, or support for :class:`_schema.MetaData`-level services.
- It's useful
- on its own as an ad-hoc construct used to generate quick SQL
- statements when a more fully fledged :class:`_schema.Table`
- is not on hand.
- """
- __visit_name__ = "table"
- _traverse_internals: _TraverseInternalsType = [
- (
- "columns",
- InternalTraversal.dp_fromclause_canonical_column_collection,
- ),
- ("name", InternalTraversal.dp_string),
- ("schema", InternalTraversal.dp_string),
- ]
- _is_table = True
- fullname: str
- implicit_returning = False
- """:class:`_expression.TableClause`
- doesn't support having a primary key or column
- -level defaults, so implicit returning doesn't apply."""
- @util.ro_memoized_property
- def _autoincrement_column(self) -> Optional[ColumnClause[Any]]:
- """No PK or default support so no autoincrement column."""
- return None
- def __init__(self, name: str, *columns: ColumnClause[Any], **kw: Any):
- super().__init__()
- self.name = name
- self._columns = DedupeColumnCollection()
- self.primary_key = ColumnSet() # type: ignore
- self.foreign_keys = set() # type: ignore
- for c in columns:
- self.append_column(c)
- schema = kw.pop("schema", None)
- if schema is not None:
- self.schema = schema
- if self.schema is not None:
- self.fullname = "%s.%s" % (self.schema, self.name)
- else:
- self.fullname = self.name
- if kw:
- raise exc.ArgumentError("Unsupported argument(s): %s" % list(kw))
- if TYPE_CHECKING:
- @util.ro_non_memoized_property
- def columns(
- self,
- ) -> ReadOnlyColumnCollection[str, ColumnClause[Any]]: ...
- @util.ro_non_memoized_property
- def c(self) -> ReadOnlyColumnCollection[str, ColumnClause[Any]]: ...
- def __str__(self) -> str:
- if self.schema is not None:
- return self.schema + "." + self.name
- else:
- return self.name
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- pass
- @util.ro_memoized_property
- def description(self) -> str:
- return self.name
- def append_column(self, c: ColumnClause[Any]) -> None:
- existing = c.table
- if existing is not None and existing is not self:
- raise exc.ArgumentError(
- "column object '%s' already assigned to table '%s'"
- % (c.key, existing)
- )
- self._columns.add(c)
- c.table = self
- @util.preload_module("sqlalchemy.sql.dml")
- def insert(self) -> util.preloaded.sql_dml.Insert:
- """Generate an :class:`_sql.Insert` construct against this
- :class:`_expression.TableClause`.
- E.g.::
- table.insert().values(name="foo")
- See :func:`_expression.insert` for argument and usage information.
- """
- return util.preloaded.sql_dml.Insert(self)
- @util.preload_module("sqlalchemy.sql.dml")
- def update(self) -> Update:
- """Generate an :func:`_expression.update` construct against this
- :class:`_expression.TableClause`.
- E.g.::
- table.update().where(table.c.id == 7).values(name="foo")
- See :func:`_expression.update` for argument and usage information.
- """
- return util.preloaded.sql_dml.Update(
- self,
- )
- @util.preload_module("sqlalchemy.sql.dml")
- def delete(self) -> Delete:
- """Generate a :func:`_expression.delete` construct against this
- :class:`_expression.TableClause`.
- E.g.::
- table.delete().where(table.c.id == 7)
- See :func:`_expression.delete` for argument and usage information.
- """
- return util.preloaded.sql_dml.Delete(self)
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]:
- return [self]
- ForUpdateParameter = Union["ForUpdateArg", None, bool, Dict[str, Any]]
- class ForUpdateArg(ClauseElement):
- _traverse_internals: _TraverseInternalsType = [
- ("of", InternalTraversal.dp_clauseelement_list),
- ("nowait", InternalTraversal.dp_boolean),
- ("read", InternalTraversal.dp_boolean),
- ("skip_locked", InternalTraversal.dp_boolean),
- ("key_share", InternalTraversal.dp_boolean),
- ]
- of: Optional[Sequence[ClauseElement]]
- nowait: bool
- read: bool
- skip_locked: bool
- @classmethod
- def _from_argument(
- cls, with_for_update: ForUpdateParameter
- ) -> Optional[ForUpdateArg]:
- if isinstance(with_for_update, ForUpdateArg):
- return with_for_update
- elif with_for_update in (None, False):
- return None
- elif with_for_update is True:
- return ForUpdateArg()
- else:
- return ForUpdateArg(**cast("Dict[str, Any]", with_for_update))
- def __eq__(self, other: Any) -> bool:
- return (
- isinstance(other, ForUpdateArg)
- and other.nowait == self.nowait
- and other.read == self.read
- and other.skip_locked == self.skip_locked
- and other.key_share == self.key_share
- and other.of is self.of
- )
- def __ne__(self, other: Any) -> bool:
- return not self.__eq__(other)
- def __hash__(self) -> int:
- return id(self)
- def __init__(
- self,
- *,
- nowait: bool = False,
- read: bool = False,
- of: Optional[_ForUpdateOfArgument] = None,
- skip_locked: bool = False,
- key_share: bool = False,
- ):
- """Represents arguments specified to
- :meth:`_expression.Select.for_update`.
- """
- self.nowait = nowait
- self.read = read
- self.skip_locked = skip_locked
- self.key_share = key_share
- if of is not None:
- self.of = [
- coercions.expect(roles.ColumnsClauseRole, elem)
- for elem in util.to_list(of)
- ]
- else:
- self.of = None
- class Values(roles.InElementRole, HasCTE, Generative, LateralFromClause):
- """Represent a ``VALUES`` construct that can be used as a FROM element
- in a statement.
- The :class:`_expression.Values` object is created from the
- :func:`_expression.values` function.
- .. versionadded:: 1.4
- """
- __visit_name__ = "values"
- _data: Tuple[Sequence[Tuple[Any, ...]], ...] = ()
- _unnamed: bool
- _traverse_internals: _TraverseInternalsType = [
- ("_column_args", InternalTraversal.dp_clauseelement_list),
- ("_data", InternalTraversal.dp_dml_multi_values),
- ("name", InternalTraversal.dp_string),
- ("literal_binds", InternalTraversal.dp_boolean),
- ] + HasCTE._has_ctes_traverse_internals
- name_cte_columns = True
- def __init__(
- self,
- *columns: ColumnClause[Any],
- name: Optional[str] = None,
- literal_binds: bool = False,
- ):
- super().__init__()
- self._column_args = columns
- if name is None:
- self._unnamed = True
- self.name = _anonymous_label.safe_construct(id(self), "anon")
- else:
- self._unnamed = False
- self.name = name
- self.literal_binds = literal_binds
- self.named_with_column = not self._unnamed
- @property
- def _column_types(self) -> List[TypeEngine[Any]]:
- return [col.type for col in self._column_args]
- @util.ro_non_memoized_property
- def _all_selected_columns(self) -> _SelectIterable:
- return self._column_args
- @_generative
- def alias(self, name: Optional[str] = None, flat: bool = False) -> Self:
- """Return a new :class:`_expression.Values`
- construct that is a copy of this
- one with the given name.
- This method is a VALUES-specific specialization of the
- :meth:`_expression.FromClause.alias` method.
- .. seealso::
- :ref:`tutorial_using_aliases`
- :func:`_expression.alias`
- """
- non_none_name: str
- if name is None:
- non_none_name = _anonymous_label.safe_construct(id(self), "anon")
- else:
- non_none_name = name
- self.name = non_none_name
- self.named_with_column = True
- self._unnamed = False
- return self
- @_generative
- def lateral(self, name: Optional[str] = None) -> Self:
- """Return a new :class:`_expression.Values` with the lateral flag set,
- so that
- it renders as LATERAL.
- .. seealso::
- :func:`_expression.lateral`
- """
- non_none_name: str
- if name is None:
- non_none_name = self.name
- else:
- non_none_name = name
- self._is_lateral = True
- self.name = non_none_name
- self._unnamed = False
- return self
- @_generative
- def data(self, values: Sequence[Tuple[Any, ...]]) -> Self:
- """Return a new :class:`_expression.Values` construct,
- adding the given data to the data list.
- E.g.::
- my_values = my_values.data([(1, "value 1"), (2, "value2")])
- :param values: a sequence (i.e. list) of tuples that map to the
- column expressions given in the :class:`_expression.Values`
- constructor.
- """
- self._data += (values,)
- return self
- def scalar_values(self) -> ScalarValues:
- """Returns a scalar ``VALUES`` construct that can be used as a
- COLUMN element in a statement.
- .. versionadded:: 2.0.0b4
- """
- return ScalarValues(self._column_args, self._data, self.literal_binds)
- def _populate_column_collection(
- self,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- ) -> None:
- for c in self._column_args:
- if c.table is not None and c.table is not self:
- _, c = c._make_proxy(
- self, primary_key=primary_key, foreign_keys=foreign_keys
- )
- else:
- # if the column was used in other contexts, ensure
- # no memoizations of other FROM clauses.
- # see test_values.py -> test_auto_proxy_select_direct_col
- c._reset_memoizations()
- columns.add(c)
- c.table = self
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]:
- return [self]
- class ScalarValues(roles.InElementRole, GroupedElement, ColumnElement[Any]):
- """Represent a scalar ``VALUES`` construct that can be used as a
- COLUMN element in a statement.
- The :class:`_expression.ScalarValues` object is created from the
- :meth:`_expression.Values.scalar_values` method. It's also
- automatically generated when a :class:`_expression.Values` is used in
- an ``IN`` or ``NOT IN`` condition.
- .. versionadded:: 2.0.0b4
- """
- __visit_name__ = "scalar_values"
- _traverse_internals: _TraverseInternalsType = [
- ("_column_args", InternalTraversal.dp_clauseelement_list),
- ("_data", InternalTraversal.dp_dml_multi_values),
- ("literal_binds", InternalTraversal.dp_boolean),
- ]
- def __init__(
- self,
- columns: Sequence[ColumnClause[Any]],
- data: Tuple[Sequence[Tuple[Any, ...]], ...],
- literal_binds: bool,
- ):
- super().__init__()
- self._column_args = columns
- self._data = data
- self.literal_binds = literal_binds
- @property
- def _column_types(self) -> List[TypeEngine[Any]]:
- return [col.type for col in self._column_args]
- def __clause_element__(self) -> ScalarValues:
- return self
- if TYPE_CHECKING:
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> Self: ...
- def _ungroup(self) -> ColumnElement[Any]: ...
- class SelectBase(
- roles.SelectStatementRole,
- roles.DMLSelectRole,
- roles.CompoundElementRole,
- roles.InElementRole,
- HasCTE,
- SupportsCloneAnnotations,
- Selectable,
- ):
- """Base class for SELECT statements.
- This includes :class:`_expression.Select`,
- :class:`_expression.CompoundSelect` and
- :class:`_expression.TextualSelect`.
- """
- _is_select_base = True
- is_select = True
- _label_style: SelectLabelStyle = LABEL_STYLE_NONE
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- self._reset_memoizations()
- @util.ro_non_memoized_property
- def selected_columns(
- self,
- ) -> ColumnCollection[str, ColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- representing the columns that
- this SELECT statement or similar construct returns in its result set.
- This collection differs from the :attr:`_expression.FromClause.columns`
- collection of a :class:`_expression.FromClause` in that the columns
- within this collection cannot be directly nested inside another SELECT
- statement; a subquery must be applied first which provides for the
- necessary parenthesization required by SQL.
- .. note::
- The :attr:`_sql.SelectBase.selected_columns` collection does not
- include expressions established in the columns clause using the
- :func:`_sql.text` construct; these are silently omitted from the
- collection. To use plain textual column expressions inside of a
- :class:`_sql.Select` construct, use the :func:`_sql.literal_column`
- construct.
- .. seealso::
- :attr:`_sql.Select.selected_columns`
- .. versionadded:: 1.4
- """
- raise NotImplementedError()
- def _generate_fromclause_column_proxies(
- self,
- subquery: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- *,
- proxy_compound_columns: Optional[
- Iterable[Sequence[ColumnElement[Any]]]
- ] = None,
- ) -> None:
- raise NotImplementedError()
- @util.ro_non_memoized_property
- def _all_selected_columns(self) -> _SelectIterable:
- """A sequence of expressions that correspond to what is rendered
- in the columns clause, including :class:`_sql.TextClause`
- constructs.
- .. versionadded:: 1.4.12
- .. seealso::
- :attr:`_sql.SelectBase.exported_columns`
- """
- raise NotImplementedError()
- @property
- def exported_columns(
- self,
- ) -> ReadOnlyColumnCollection[str, ColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- that represents the "exported"
- columns of this :class:`_expression.Selectable`, not including
- :class:`_sql.TextClause` constructs.
- The "exported" columns for a :class:`_expression.SelectBase`
- object are synonymous
- with the :attr:`_expression.SelectBase.selected_columns` collection.
- .. versionadded:: 1.4
- .. seealso::
- :attr:`_expression.Select.exported_columns`
- :attr:`_expression.Selectable.exported_columns`
- :attr:`_expression.FromClause.exported_columns`
- """
- return self.selected_columns.as_readonly()
- @property
- @util.deprecated(
- "1.4",
- "The :attr:`_expression.SelectBase.c` and "
- ":attr:`_expression.SelectBase.columns` attributes "
- "are deprecated and will be removed in a future release; these "
- "attributes implicitly create a subquery that should be explicit. "
- "Please call :meth:`_expression.SelectBase.subquery` "
- "first in order to create "
- "a subquery, which then contains this attribute. To access the "
- "columns that this SELECT object SELECTs "
- "from, use the :attr:`_expression.SelectBase.selected_columns` "
- "attribute.",
- )
- def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- return self._implicit_subquery.columns
- @property
- def columns(
- self,
- ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- return self.c
- def get_label_style(self) -> SelectLabelStyle:
- """
- Retrieve the current label style.
- Implemented by subclasses.
- """
- raise NotImplementedError()
- def set_label_style(self, style: SelectLabelStyle) -> Self:
- """Return a new selectable with the specified label style.
- Implemented by subclasses.
- """
- raise NotImplementedError()
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.SelectBase.select` method is deprecated "
- "and will be removed in a future release; this method implicitly "
- "creates a subquery that should be explicit. "
- "Please call :meth:`_expression.SelectBase.subquery` "
- "first in order to create "
- "a subquery, which then can be selected.",
- )
- def select(self, *arg: Any, **kw: Any) -> Select[Any]:
- return self._implicit_subquery.select(*arg, **kw)
- @HasMemoized.memoized_attribute
- def _implicit_subquery(self) -> Subquery:
- return self.subquery()
- def _scalar_type(self) -> TypeEngine[Any]:
- raise NotImplementedError()
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.SelectBase.as_scalar` "
- "method is deprecated and will be "
- "removed in a future release. Please refer to "
- ":meth:`_expression.SelectBase.scalar_subquery`.",
- )
- def as_scalar(self) -> ScalarSelect[Any]:
- return self.scalar_subquery()
- def exists(self) -> Exists:
- """Return an :class:`_sql.Exists` representation of this selectable,
- which can be used as a column expression.
- The returned object is an instance of :class:`_sql.Exists`.
- .. seealso::
- :func:`_sql.exists`
- :ref:`tutorial_exists` - in the :term:`2.0 style` tutorial.
- .. versionadded:: 1.4
- """
- return Exists(self)
- def scalar_subquery(self) -> ScalarSelect[Any]:
- """Return a 'scalar' representation of this selectable, which can be
- used as a column expression.
- The returned object is an instance of :class:`_sql.ScalarSelect`.
- Typically, a select statement which has only one column in its columns
- clause is eligible to be used as a scalar expression. The scalar
- subquery can then be used in the WHERE clause or columns clause of
- an enclosing SELECT.
- Note that the scalar subquery differentiates from the FROM-level
- subquery that can be produced using the
- :meth:`_expression.SelectBase.subquery`
- method.
- .. versionchanged: 1.4 - the ``.as_scalar()`` method was renamed to
- :meth:`_expression.SelectBase.scalar_subquery`.
- .. seealso::
- :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
- """
- if self._label_style is not LABEL_STYLE_NONE:
- self = self.set_label_style(LABEL_STYLE_NONE)
- return ScalarSelect(self)
- def label(self, name: Optional[str]) -> Label[Any]:
- """Return a 'scalar' representation of this selectable, embedded as a
- subquery with a label.
- .. seealso::
- :meth:`_expression.SelectBase.scalar_subquery`.
- """
- return self.scalar_subquery().label(name)
- def lateral(self, name: Optional[str] = None) -> LateralFromClause:
- """Return a LATERAL alias of this :class:`_expression.Selectable`.
- The return value is the :class:`_expression.Lateral` construct also
- provided by the top-level :func:`_expression.lateral` function.
- .. seealso::
- :ref:`tutorial_lateral_correlation` - overview of usage.
- """
- return Lateral._factory(self, name)
- def subquery(self, name: Optional[str] = None) -> Subquery:
- """Return a subquery of this :class:`_expression.SelectBase`.
- A subquery is from a SQL perspective a parenthesized, named
- construct that can be placed in the FROM clause of another
- SELECT statement.
- Given a SELECT statement such as::
- stmt = select(table.c.id, table.c.name)
- The above statement might look like:
- .. sourcecode:: sql
- SELECT table.id, table.name FROM table
- The subquery form by itself renders the same way, however when
- embedded into the FROM clause of another SELECT statement, it becomes
- a named sub-element::
- subq = stmt.subquery()
- new_stmt = select(subq)
- The above renders as:
- .. sourcecode:: sql
- SELECT anon_1.id, anon_1.name
- FROM (SELECT table.id, table.name FROM table) AS anon_1
- Historically, :meth:`_expression.SelectBase.subquery`
- is equivalent to calling
- the :meth:`_expression.FromClause.alias`
- method on a FROM object; however,
- as a :class:`_expression.SelectBase`
- object is not directly FROM object,
- the :meth:`_expression.SelectBase.subquery`
- method provides clearer semantics.
- .. versionadded:: 1.4
- """
- return Subquery._construct(
- self._ensure_disambiguated_names(), name=name
- )
- def _ensure_disambiguated_names(self) -> Self:
- """Ensure that the names generated by this selectbase will be
- disambiguated in some way, if possible.
- """
- raise NotImplementedError()
- def alias(
- self, name: Optional[str] = None, flat: bool = False
- ) -> Subquery:
- """Return a named subquery against this
- :class:`_expression.SelectBase`.
- For a :class:`_expression.SelectBase` (as opposed to a
- :class:`_expression.FromClause`),
- this returns a :class:`.Subquery` object which behaves mostly the
- same as the :class:`_expression.Alias` object that is used with a
- :class:`_expression.FromClause`.
- .. versionchanged:: 1.4 The :meth:`_expression.SelectBase.alias`
- method is now
- a synonym for the :meth:`_expression.SelectBase.subquery` method.
- """
- return self.subquery(name=name)
- _SB = TypeVar("_SB", bound=SelectBase)
- class SelectStatementGrouping(GroupedElement, SelectBase, Generic[_SB]):
- """Represent a grouping of a :class:`_expression.SelectBase`.
- This differs from :class:`.Subquery` in that we are still
- an "inner" SELECT statement, this is strictly for grouping inside of
- compound selects.
- """
- __visit_name__ = "select_statement_grouping"
- _traverse_internals: _TraverseInternalsType = [
- ("element", InternalTraversal.dp_clauseelement)
- ] + SupportsCloneAnnotations._clone_annotations_traverse_internals
- _is_select_container = True
- element: _SB
- def __init__(self, element: _SB) -> None:
- self.element = cast(
- _SB, coercions.expect(roles.SelectStatementRole, element)
- )
- def _ensure_disambiguated_names(self) -> SelectStatementGrouping[_SB]:
- new_element = self.element._ensure_disambiguated_names()
- if new_element is not self.element:
- return SelectStatementGrouping(new_element)
- else:
- return self
- def get_label_style(self) -> SelectLabelStyle:
- return self.element.get_label_style()
- def set_label_style(
- self, label_style: SelectLabelStyle
- ) -> SelectStatementGrouping[_SB]:
- return SelectStatementGrouping(
- self.element.set_label_style(label_style)
- )
- @property
- def select_statement(self) -> _SB:
- return self.element
- def self_group(self, against: Optional[OperatorType] = None) -> Self:
- return self
- if TYPE_CHECKING:
- def _ungroup(self) -> _SB: ...
- # def _generate_columns_plus_names(
- # self, anon_for_dupe_key: bool
- # ) -> List[Tuple[str, str, str, ColumnElement[Any], bool]]:
- # return self.element._generate_columns_plus_names(anon_for_dupe_key)
- def _generate_fromclause_column_proxies(
- self,
- subquery: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- *,
- proxy_compound_columns: Optional[
- Iterable[Sequence[ColumnElement[Any]]]
- ] = None,
- ) -> None:
- self.element._generate_fromclause_column_proxies(
- subquery,
- columns,
- proxy_compound_columns=proxy_compound_columns,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- @util.ro_non_memoized_property
- def _all_selected_columns(self) -> _SelectIterable:
- return self.element._all_selected_columns
- @util.ro_non_memoized_property
- def selected_columns(self) -> ColumnCollection[str, ColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- representing the columns that
- the embedded SELECT statement returns in its result set, not including
- :class:`_sql.TextClause` constructs.
- .. versionadded:: 1.4
- .. seealso::
- :attr:`_sql.Select.selected_columns`
- """
- return self.element.selected_columns
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]:
- return self.element._from_objects
- def add_cte(self, *ctes: CTE, nest_here: bool = False) -> Self:
- # SelectStatementGrouping not generative: has no attribute '_generate'
- raise NotImplementedError
- class GenerativeSelect(DialectKWArgs, SelectBase, Generative):
- """Base class for SELECT statements where additional elements can be
- added.
- This serves as the base for :class:`_expression.Select` and
- :class:`_expression.CompoundSelect`
- where elements such as ORDER BY, GROUP BY can be added and column
- rendering can be controlled. Compare to
- :class:`_expression.TextualSelect`, which,
- while it subclasses :class:`_expression.SelectBase`
- and is also a SELECT construct,
- represents a fixed textual string which cannot be altered at this level,
- only wrapped as a subquery.
- """
- _order_by_clauses: Tuple[ColumnElement[Any], ...] = ()
- _group_by_clauses: Tuple[ColumnElement[Any], ...] = ()
- _limit_clause: Optional[ColumnElement[Any]] = None
- _offset_clause: Optional[ColumnElement[Any]] = None
- _fetch_clause: Optional[ColumnElement[Any]] = None
- _fetch_clause_options: Optional[Dict[str, bool]] = None
- _for_update_arg: Optional[ForUpdateArg] = None
- def __init__(self, _label_style: SelectLabelStyle = LABEL_STYLE_DEFAULT):
- self._label_style = _label_style
- @_generative
- def with_for_update(
- self,
- *,
- nowait: bool = False,
- read: bool = False,
- of: Optional[_ForUpdateOfArgument] = None,
- skip_locked: bool = False,
- key_share: bool = False,
- ) -> Self:
- """Specify a ``FOR UPDATE`` clause for this
- :class:`_expression.GenerativeSelect`.
- E.g.::
- stmt = select(table).with_for_update(nowait=True)
- On a database like PostgreSQL or Oracle Database, the above would
- render a statement like:
- .. sourcecode:: sql
- SELECT table.a, table.b FROM table FOR UPDATE NOWAIT
- on other backends, the ``nowait`` option is ignored and instead
- would produce:
- .. sourcecode:: sql
- SELECT table.a, table.b FROM table FOR UPDATE
- When called with no arguments, the statement will render with
- the suffix ``FOR UPDATE``. Additional arguments can then be
- provided which allow for common database-specific
- variants.
- :param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle
- Database and PostgreSQL dialects.
- :param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL,
- ``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with
- ``nowait``, will render ``FOR SHARE NOWAIT``.
- :param of: SQL expression or list of SQL expression elements,
- (typically :class:`_schema.Column` objects or a compatible expression,
- for some backends may also be a table expression) which will render
- into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle
- Database, some MySQL versions and possibly others. May render as a
- table or as a column depending on backend.
- :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on
- Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED``
- if ``read=True`` is also specified.
- :param key_share: boolean, will render ``FOR NO KEY UPDATE``,
- or if combined with ``read=True`` will render ``FOR KEY SHARE``,
- on the PostgreSQL dialect.
- """
- self._for_update_arg = ForUpdateArg(
- nowait=nowait,
- read=read,
- of=of,
- skip_locked=skip_locked,
- key_share=key_share,
- )
- return self
- def get_label_style(self) -> SelectLabelStyle:
- """
- Retrieve the current label style.
- .. versionadded:: 1.4
- """
- return self._label_style
- def set_label_style(self, style: SelectLabelStyle) -> Self:
- """Return a new selectable with the specified label style.
- There are three "label styles" available,
- :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`,
- :attr:`_sql.SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL`, and
- :attr:`_sql.SelectLabelStyle.LABEL_STYLE_NONE`. The default style is
- :attr:`_sql.SelectLabelStyle.LABEL_STYLE_DISAMBIGUATE_ONLY`.
- In modern SQLAlchemy, there is not generally a need to change the
- labeling style, as per-expression labels are more effectively used by
- making use of the :meth:`_sql.ColumnElement.label` method. In past
- versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to
- disambiguate same-named columns from different tables, aliases, or
- subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now
- applies labels only to names that conflict with an existing name so
- that the impact of this labeling is minimal.
- The rationale for disambiguation is mostly so that all column
- expressions are available from a given :attr:`_sql.FromClause.c`
- collection when a subquery is created.
- .. versionadded:: 1.4 - the
- :meth:`_sql.GenerativeSelect.set_label_style` method replaces the
- previous combination of ``.apply_labels()``, ``.with_labels()`` and
- ``use_labels=True`` methods and/or parameters.
- .. seealso::
- :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`
- :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`
- :data:`_sql.LABEL_STYLE_NONE`
- :data:`_sql.LABEL_STYLE_DEFAULT`
- """
- if self._label_style is not style:
- self = self._generate()
- self._label_style = style
- return self
- @property
- def _group_by_clause(self) -> ClauseList:
- """ClauseList access to group_by_clauses for legacy dialects"""
- return ClauseList._construct_raw(
- operators.comma_op, self._group_by_clauses
- )
- @property
- def _order_by_clause(self) -> ClauseList:
- """ClauseList access to order_by_clauses for legacy dialects"""
- return ClauseList._construct_raw(
- operators.comma_op, self._order_by_clauses
- )
- def _offset_or_limit_clause(
- self,
- element: _LimitOffsetType,
- name: Optional[str] = None,
- type_: Optional[_TypeEngineArgument[int]] = None,
- ) -> ColumnElement[Any]:
- """Convert the given value to an "offset or limit" clause.
- This handles incoming integers and converts to an expression; if
- an expression is already given, it is passed through.
- """
- return coercions.expect(
- roles.LimitOffsetRole, element, name=name, type_=type_
- )
- @overload
- def _offset_or_limit_clause_asint(
- self, clause: ColumnElement[Any], attrname: str
- ) -> NoReturn: ...
- @overload
- def _offset_or_limit_clause_asint(
- self, clause: Optional[_OffsetLimitParam], attrname: str
- ) -> Optional[int]: ...
- def _offset_or_limit_clause_asint(
- self, clause: Optional[ColumnElement[Any]], attrname: str
- ) -> Union[NoReturn, Optional[int]]:
- """Convert the "offset or limit" clause of a select construct to an
- integer.
- This is only possible if the value is stored as a simple bound
- parameter. Otherwise, a compilation error is raised.
- """
- if clause is None:
- return None
- try:
- value = clause._limit_offset_value
- except AttributeError as err:
- raise exc.CompileError(
- "This SELECT structure does not use a simple "
- "integer value for %s" % attrname
- ) from err
- else:
- return util.asint(value)
- @property
- def _limit(self) -> Optional[int]:
- """Get an integer value for the limit. This should only be used
- by code that cannot support a limit as a BindParameter or
- other custom clause as it will throw an exception if the limit
- isn't currently set to an integer.
- """
- return self._offset_or_limit_clause_asint(self._limit_clause, "limit")
- def _simple_int_clause(self, clause: ClauseElement) -> bool:
- """True if the clause is a simple integer, False
- if it is not present or is a SQL expression.
- """
- return isinstance(clause, _OffsetLimitParam)
- @property
- def _offset(self) -> Optional[int]:
- """Get an integer value for the offset. This should only be used
- by code that cannot support an offset as a BindParameter or
- other custom clause as it will throw an exception if the
- offset isn't currently set to an integer.
- """
- return self._offset_or_limit_clause_asint(
- self._offset_clause, "offset"
- )
- @property
- def _has_row_limiting_clause(self) -> bool:
- return (
- self._limit_clause is not None
- or self._offset_clause is not None
- or self._fetch_clause is not None
- )
- @_generative
- def limit(self, limit: _LimitOffsetType) -> Self:
- """Return a new selectable with the given LIMIT criterion
- applied.
- This is a numerical value which usually renders as a ``LIMIT``
- expression in the resulting select. Backends that don't
- support ``LIMIT`` will attempt to provide similar
- functionality.
- .. note::
- The :meth:`_sql.GenerativeSelect.limit` method will replace
- any clause applied with :meth:`_sql.GenerativeSelect.fetch`.
- :param limit: an integer LIMIT parameter, or a SQL expression
- that provides an integer result. Pass ``None`` to reset it.
- .. seealso::
- :meth:`_sql.GenerativeSelect.fetch`
- :meth:`_sql.GenerativeSelect.offset`
- """
- self._fetch_clause = self._fetch_clause_options = None
- self._limit_clause = self._offset_or_limit_clause(limit)
- return self
- @_generative
- def fetch(
- self,
- count: _LimitOffsetType,
- with_ties: bool = False,
- percent: bool = False,
- **dialect_kw: Any,
- ) -> Self:
- r"""Return a new selectable with the given FETCH FIRST criterion
- applied.
- This is a numeric value which usually renders as ``FETCH {FIRST | NEXT}
- [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting
- select. This functionality is is currently implemented for Oracle
- Database, PostgreSQL, MSSQL.
- Use :meth:`_sql.GenerativeSelect.offset` to specify the offset.
- .. note::
- The :meth:`_sql.GenerativeSelect.fetch` method will replace
- any clause applied with :meth:`_sql.GenerativeSelect.limit`.
- .. versionadded:: 1.4
- :param count: an integer COUNT parameter, or a SQL expression
- that provides an integer result. When ``percent=True`` this will
- represent the percentage of rows to return, not the absolute value.
- Pass ``None`` to reset it.
- :param with_ties: When ``True``, the WITH TIES option is used
- to return any additional rows that tie for the last place in the
- result set according to the ``ORDER BY`` clause. The
- ``ORDER BY`` may be mandatory in this case. Defaults to ``False``
- :param percent: When ``True``, ``count`` represents the percentage
- of the total number of selected rows to return. Defaults to ``False``
- :param \**dialect_kw: Additional dialect-specific keyword arguments
- may be accepted by dialects.
- .. versionadded:: 2.0.41
- .. seealso::
- :meth:`_sql.GenerativeSelect.limit`
- :meth:`_sql.GenerativeSelect.offset`
- """
- self._validate_dialect_kwargs(dialect_kw)
- self._limit_clause = None
- if count is None:
- self._fetch_clause = self._fetch_clause_options = None
- else:
- self._fetch_clause = self._offset_or_limit_clause(count)
- self._fetch_clause_options = {
- "with_ties": with_ties,
- "percent": percent,
- }
- return self
- @_generative
- def offset(self, offset: _LimitOffsetType) -> Self:
- """Return a new selectable with the given OFFSET criterion
- applied.
- This is a numeric value which usually renders as an ``OFFSET``
- expression in the resulting select. Backends that don't
- support ``OFFSET`` will attempt to provide similar
- functionality.
- :param offset: an integer OFFSET parameter, or a SQL expression
- that provides an integer result. Pass ``None`` to reset it.
- .. seealso::
- :meth:`_sql.GenerativeSelect.limit`
- :meth:`_sql.GenerativeSelect.fetch`
- """
- self._offset_clause = self._offset_or_limit_clause(offset)
- return self
- @_generative
- @util.preload_module("sqlalchemy.sql.util")
- def slice(
- self,
- start: int,
- stop: int,
- ) -> Self:
- """Apply LIMIT / OFFSET to this statement based on a slice.
- The start and stop indices behave like the argument to Python's
- built-in :func:`range` function. This method provides an
- alternative to using ``LIMIT``/``OFFSET`` to get a slice of the
- query.
- For example, ::
- stmt = select(User).order_by(User.id).slice(1, 3)
- renders as
- .. sourcecode:: sql
- SELECT users.id AS users_id,
- users.name AS users_name
- FROM users ORDER BY users.id
- LIMIT ? OFFSET ?
- (2, 1)
- .. note::
- The :meth:`_sql.GenerativeSelect.slice` method will replace
- any clause applied with :meth:`_sql.GenerativeSelect.fetch`.
- .. versionadded:: 1.4 Added the :meth:`_sql.GenerativeSelect.slice`
- method generalized from the ORM.
- .. seealso::
- :meth:`_sql.GenerativeSelect.limit`
- :meth:`_sql.GenerativeSelect.offset`
- :meth:`_sql.GenerativeSelect.fetch`
- """
- sql_util = util.preloaded.sql_util
- self._fetch_clause = self._fetch_clause_options = None
- self._limit_clause, self._offset_clause = sql_util._make_slice(
- self._limit_clause, self._offset_clause, start, stop
- )
- return self
- @_generative
- def order_by(
- self,
- __first: Union[
- Literal[None, _NoArg.NO_ARG],
- _ColumnExpressionOrStrLabelArgument[Any],
- ] = _NoArg.NO_ARG,
- *clauses: _ColumnExpressionOrStrLabelArgument[Any],
- ) -> Self:
- r"""Return a new selectable with the given list of ORDER BY
- criteria applied.
- e.g.::
- stmt = select(table).order_by(table.c.id, table.c.name)
- Calling this method multiple times is equivalent to calling it once
- with all the clauses concatenated. All existing ORDER BY criteria may
- be cancelled by passing ``None`` by itself. New ORDER BY criteria may
- then be added by invoking :meth:`_orm.Query.order_by` again, e.g.::
- # will erase all ORDER BY and ORDER BY new_col alone
- stmt = stmt.order_by(None).order_by(new_col)
- :param \*clauses: a series of :class:`_expression.ColumnElement`
- constructs
- which will be used to generate an ORDER BY clause.
- .. seealso::
- :ref:`tutorial_order_by` - in the :ref:`unified_tutorial`
- :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial`
- """
- if not clauses and __first is None:
- self._order_by_clauses = ()
- elif __first is not _NoArg.NO_ARG:
- self._order_by_clauses += tuple(
- coercions.expect(
- roles.OrderByRole, clause, apply_propagate_attrs=self
- )
- for clause in (__first,) + clauses
- )
- return self
- @_generative
- def group_by(
- self,
- __first: Union[
- Literal[None, _NoArg.NO_ARG],
- _ColumnExpressionOrStrLabelArgument[Any],
- ] = _NoArg.NO_ARG,
- *clauses: _ColumnExpressionOrStrLabelArgument[Any],
- ) -> Self:
- r"""Return a new selectable with the given list of GROUP BY
- criterion applied.
- All existing GROUP BY settings can be suppressed by passing ``None``.
- e.g.::
- stmt = select(table.c.name, func.max(table.c.stat)).group_by(table.c.name)
- :param \*clauses: a series of :class:`_expression.ColumnElement`
- constructs
- which will be used to generate an GROUP BY clause.
- .. seealso::
- :ref:`tutorial_group_by_w_aggregates` - in the
- :ref:`unified_tutorial`
- :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial`
- """ # noqa: E501
- if not clauses and __first is None:
- self._group_by_clauses = ()
- elif __first is not _NoArg.NO_ARG:
- self._group_by_clauses += tuple(
- coercions.expect(
- roles.GroupByRole, clause, apply_propagate_attrs=self
- )
- for clause in (__first,) + clauses
- )
- return self
- @CompileState.plugin_for("default", "compound_select")
- class CompoundSelectState(CompileState):
- @util.memoized_property
- def _label_resolve_dict(
- self,
- ) -> Tuple[
- Dict[str, ColumnElement[Any]],
- Dict[str, ColumnElement[Any]],
- Dict[str, ColumnElement[Any]],
- ]:
- # TODO: this is hacky and slow
- hacky_subquery = self.statement.subquery()
- hacky_subquery.named_with_column = False
- d = {c.key: c for c in hacky_subquery.c}
- return d, d, d
- class _CompoundSelectKeyword(Enum):
- UNION = "UNION"
- UNION_ALL = "UNION ALL"
- EXCEPT = "EXCEPT"
- EXCEPT_ALL = "EXCEPT ALL"
- INTERSECT = "INTERSECT"
- INTERSECT_ALL = "INTERSECT ALL"
- class CompoundSelect(HasCompileState, GenerativeSelect, TypedReturnsRows[_TP]):
- """Forms the basis of ``UNION``, ``UNION ALL``, and other
- SELECT-based set operations.
- .. seealso::
- :func:`_expression.union`
- :func:`_expression.union_all`
- :func:`_expression.intersect`
- :func:`_expression.intersect_all`
- :func:`_expression.except`
- :func:`_expression.except_all`
- """
- __visit_name__ = "compound_select"
- _traverse_internals: _TraverseInternalsType = (
- [
- ("selects", InternalTraversal.dp_clauseelement_list),
- ("_limit_clause", InternalTraversal.dp_clauseelement),
- ("_offset_clause", InternalTraversal.dp_clauseelement),
- ("_fetch_clause", InternalTraversal.dp_clauseelement),
- ("_fetch_clause_options", InternalTraversal.dp_plain_dict),
- ("_order_by_clauses", InternalTraversal.dp_clauseelement_list),
- ("_group_by_clauses", InternalTraversal.dp_clauseelement_list),
- ("_for_update_arg", InternalTraversal.dp_clauseelement),
- ("keyword", InternalTraversal.dp_string),
- ]
- + SupportsCloneAnnotations._clone_annotations_traverse_internals
- + HasCTE._has_ctes_traverse_internals
- + DialectKWArgs._dialect_kwargs_traverse_internals
- )
- selects: List[SelectBase]
- _is_from_container = True
- _auto_correlate = False
- def __init__(
- self,
- keyword: _CompoundSelectKeyword,
- *selects: _SelectStatementForCompoundArgument[_TP],
- ):
- self.keyword = keyword
- self.selects = [
- coercions.expect(
- roles.CompoundElementRole, s, apply_propagate_attrs=self
- ).self_group(against=self)
- for s in selects
- ]
- GenerativeSelect.__init__(self)
- @classmethod
- def _create_union(
- cls, *selects: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- return CompoundSelect(_CompoundSelectKeyword.UNION, *selects)
- @classmethod
- def _create_union_all(
- cls, *selects: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- return CompoundSelect(_CompoundSelectKeyword.UNION_ALL, *selects)
- @classmethod
- def _create_except(
- cls, *selects: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- return CompoundSelect(_CompoundSelectKeyword.EXCEPT, *selects)
- @classmethod
- def _create_except_all(
- cls, *selects: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- return CompoundSelect(_CompoundSelectKeyword.EXCEPT_ALL, *selects)
- @classmethod
- def _create_intersect(
- cls, *selects: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- return CompoundSelect(_CompoundSelectKeyword.INTERSECT, *selects)
- @classmethod
- def _create_intersect_all(
- cls, *selects: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- return CompoundSelect(_CompoundSelectKeyword.INTERSECT_ALL, *selects)
- def _scalar_type(self) -> TypeEngine[Any]:
- return self.selects[0]._scalar_type()
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> GroupedElement:
- return SelectStatementGrouping(self)
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- for s in self.selects:
- if s.is_derived_from(fromclause):
- return True
- return False
- def set_label_style(self, style: SelectLabelStyle) -> Self:
- if self._label_style is not style:
- self = self._generate()
- select_0 = self.selects[0].set_label_style(style)
- self.selects = [select_0] + self.selects[1:]
- return self
- def _ensure_disambiguated_names(self) -> Self:
- new_select = self.selects[0]._ensure_disambiguated_names()
- if new_select is not self.selects[0]:
- self = self._generate()
- self.selects = [new_select] + self.selects[1:]
- return self
- def _generate_fromclause_column_proxies(
- self,
- subquery: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- *,
- proxy_compound_columns: Optional[
- Iterable[Sequence[ColumnElement[Any]]]
- ] = None,
- ) -> None:
- # this is a slightly hacky thing - the union exports a
- # column that resembles just that of the *first* selectable.
- # to get at a "composite" column, particularly foreign keys,
- # you have to dig through the proxies collection which we
- # generate below.
- select_0 = self.selects[0]
- if self._label_style is not LABEL_STYLE_DEFAULT:
- select_0 = select_0.set_label_style(self._label_style)
- # hand-construct the "_proxies" collection to include all
- # derived columns place a 'weight' annotation corresponding
- # to how low in the list of select()s the column occurs, so
- # that the corresponding_column() operation can resolve
- # conflicts
- extra_col_iterator = zip(
- *[
- [
- c._annotate(dd)
- for c in stmt._all_selected_columns
- if is_column_element(c)
- ]
- for dd, stmt in [
- ({"weight": i + 1}, stmt)
- for i, stmt in enumerate(self.selects)
- ]
- ]
- )
- # the incoming proxy_compound_columns can be present also if this is
- # a compound embedded in a compound. it's probably more appropriate
- # that we generate new weights local to this nested compound, though
- # i haven't tried to think what it means for compound nested in
- # compound
- select_0._generate_fromclause_column_proxies(
- subquery,
- columns,
- proxy_compound_columns=extra_col_iterator,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- def _refresh_for_new_column(self, column: ColumnElement[Any]) -> None:
- super()._refresh_for_new_column(column)
- for select in self.selects:
- select._refresh_for_new_column(column)
- @util.ro_non_memoized_property
- def _all_selected_columns(self) -> _SelectIterable:
- return self.selects[0]._all_selected_columns
- @util.ro_non_memoized_property
- def selected_columns(
- self,
- ) -> ColumnCollection[str, ColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- representing the columns that
- this SELECT statement or similar construct returns in its result set,
- not including :class:`_sql.TextClause` constructs.
- For a :class:`_expression.CompoundSelect`, the
- :attr:`_expression.CompoundSelect.selected_columns`
- attribute returns the selected
- columns of the first SELECT statement contained within the series of
- statements within the set operation.
- .. seealso::
- :attr:`_sql.Select.selected_columns`
- .. versionadded:: 1.4
- """
- return self.selects[0].selected_columns
- # backwards compat
- for elem in _CompoundSelectKeyword:
- setattr(CompoundSelect, elem.name, elem)
- @CompileState.plugin_for("default", "select")
- class SelectState(util.MemoizedSlots, CompileState):
- __slots__ = (
- "from_clauses",
- "froms",
- "columns_plus_names",
- "_label_resolve_dict",
- )
- if TYPE_CHECKING:
- default_select_compile_options: CacheableOptions
- else:
- class default_select_compile_options(CacheableOptions):
- _cache_key_traversal = []
- if TYPE_CHECKING:
- @classmethod
- def get_plugin_class(
- cls, statement: Executable
- ) -> Type[SelectState]: ...
- def __init__(
- self,
- statement: Select[Any],
- compiler: SQLCompiler,
- **kw: Any,
- ):
- self.statement = statement
- self.from_clauses = statement._from_obj
- for memoized_entities in statement._memoized_select_entities:
- self._setup_joins(
- memoized_entities._setup_joins, memoized_entities._raw_columns
- )
- if statement._setup_joins:
- self._setup_joins(statement._setup_joins, statement._raw_columns)
- self.froms = self._get_froms(statement)
- self.columns_plus_names = statement._generate_columns_plus_names(True)
- @classmethod
- def _plugin_not_implemented(cls) -> NoReturn:
- raise NotImplementedError(
- "The default SELECT construct without plugins does not "
- "implement this method."
- )
- @classmethod
- def get_column_descriptions(
- cls, statement: Select[Any]
- ) -> List[Dict[str, Any]]:
- return [
- {
- "name": name,
- "type": element.type,
- "expr": element,
- }
- for _, name, _, element, _ in (
- statement._generate_columns_plus_names(False)
- )
- ]
- @classmethod
- def from_statement(
- cls, statement: Select[Any], from_statement: roles.ReturnsRowsRole
- ) -> ExecutableReturnsRows:
- cls._plugin_not_implemented()
- @classmethod
- def get_columns_clause_froms(
- cls, statement: Select[Any]
- ) -> List[FromClause]:
- return cls._normalize_froms(
- itertools.chain.from_iterable(
- element._from_objects for element in statement._raw_columns
- )
- )
- @classmethod
- def _column_naming_convention(
- cls, label_style: SelectLabelStyle
- ) -> _LabelConventionCallable:
- table_qualified = label_style is LABEL_STYLE_TABLENAME_PLUS_COL
- dedupe = label_style is not LABEL_STYLE_NONE
- pa = prefix_anon_map()
- names = set()
- def go(
- c: Union[ColumnElement[Any], TextClause],
- col_name: Optional[str] = None,
- ) -> Optional[str]:
- if is_text_clause(c):
- return None
- elif TYPE_CHECKING:
- assert is_column_element(c)
- if not dedupe:
- name = c._proxy_key
- if name is None:
- name = "_no_label"
- return name
- name = c._tq_key_label if table_qualified else c._proxy_key
- if name is None:
- name = "_no_label"
- if name in names:
- return c._anon_label(name) % pa
- else:
- names.add(name)
- return name
- elif name in names:
- return (
- c._anon_tq_key_label % pa
- if table_qualified
- else c._anon_key_label % pa
- )
- else:
- names.add(name)
- return name
- return go
- def _get_froms(self, statement: Select[Any]) -> List[FromClause]:
- ambiguous_table_name_map: _AmbiguousTableNameMap
- self._ambiguous_table_name_map = ambiguous_table_name_map = {}
- return self._normalize_froms(
- itertools.chain(
- self.from_clauses,
- itertools.chain.from_iterable(
- [
- element._from_objects
- for element in statement._raw_columns
- ]
- ),
- itertools.chain.from_iterable(
- [
- element._from_objects
- for element in statement._where_criteria
- ]
- ),
- ),
- check_statement=statement,
- ambiguous_table_name_map=ambiguous_table_name_map,
- )
- @classmethod
- def _normalize_froms(
- cls,
- iterable_of_froms: Iterable[FromClause],
- check_statement: Optional[Select[Any]] = None,
- ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None,
- ) -> List[FromClause]:
- """given an iterable of things to select FROM, reduce them to what
- would actually render in the FROM clause of a SELECT.
- This does the job of checking for JOINs, tables, etc. that are in fact
- overlapping due to cloning, adaption, present in overlapping joins,
- etc.
- """
- seen: Set[FromClause] = set()
- froms: List[FromClause] = []
- for item in iterable_of_froms:
- if is_subquery(item) and item.element is check_statement:
- raise exc.InvalidRequestError(
- "select() construct refers to itself as a FROM"
- )
- if not seen.intersection(item._cloned_set):
- froms.append(item)
- seen.update(item._cloned_set)
- if froms:
- toremove = set(
- itertools.chain.from_iterable(
- [_expand_cloned(f._hide_froms) for f in froms]
- )
- )
- if toremove:
- # filter out to FROM clauses not in the list,
- # using a list to maintain ordering
- froms = [f for f in froms if f not in toremove]
- if ambiguous_table_name_map is not None:
- ambiguous_table_name_map.update(
- (
- fr.name,
- _anonymous_label.safe_construct(
- hash(fr.name), fr.name
- ),
- )
- for item in froms
- for fr in item._from_objects
- if is_table(fr)
- and fr.schema
- and fr.name not in ambiguous_table_name_map
- )
- return froms
- def _get_display_froms(
- self,
- explicit_correlate_froms: Optional[Sequence[FromClause]] = None,
- implicit_correlate_froms: Optional[Sequence[FromClause]] = None,
- ) -> List[FromClause]:
- """Return the full list of 'from' clauses to be displayed.
- Takes into account a set of existing froms which may be
- rendered in the FROM clause of enclosing selects; this Select
- may want to leave those absent if it is automatically
- correlating.
- """
- froms = self.froms
- if self.statement._correlate:
- to_correlate = self.statement._correlate
- if to_correlate:
- froms = [
- f
- for f in froms
- if f
- not in _cloned_intersection(
- _cloned_intersection(
- froms, explicit_correlate_froms or ()
- ),
- to_correlate,
- )
- ]
- if self.statement._correlate_except is not None:
- froms = [
- f
- for f in froms
- if f
- not in _cloned_difference(
- _cloned_intersection(
- froms, explicit_correlate_froms or ()
- ),
- self.statement._correlate_except,
- )
- ]
- if (
- self.statement._auto_correlate
- and implicit_correlate_froms
- and len(froms) > 1
- ):
- froms = [
- f
- for f in froms
- if f
- not in _cloned_intersection(froms, implicit_correlate_froms)
- ]
- if not len(froms):
- raise exc.InvalidRequestError(
- "Select statement '%r"
- "' returned no FROM clauses "
- "due to auto-correlation; "
- "specify correlate(<tables>) "
- "to control correlation "
- "manually." % self.statement
- )
- return froms
- def _memoized_attr__label_resolve_dict(
- self,
- ) -> Tuple[
- Dict[str, ColumnElement[Any]],
- Dict[str, ColumnElement[Any]],
- Dict[str, ColumnElement[Any]],
- ]:
- with_cols: Dict[str, ColumnElement[Any]] = {
- c._tq_label or c.key: c
- for c in self.statement._all_selected_columns
- if c._allow_label_resolve
- }
- only_froms: Dict[str, ColumnElement[Any]] = {
- c.key: c # type: ignore
- for c in _select_iterables(self.froms)
- if c._allow_label_resolve
- }
- only_cols: Dict[str, ColumnElement[Any]] = with_cols.copy()
- for key, value in only_froms.items():
- with_cols.setdefault(key, value)
- return with_cols, only_froms, only_cols
- @classmethod
- def determine_last_joined_entity(
- cls, stmt: Select[Any]
- ) -> Optional[_JoinTargetElement]:
- if stmt._setup_joins:
- return stmt._setup_joins[-1][0]
- else:
- return None
- @classmethod
- def all_selected_columns(cls, statement: Select[Any]) -> _SelectIterable:
- return [c for c in _select_iterables(statement._raw_columns)]
- def _setup_joins(
- self,
- args: Tuple[_SetupJoinsElement, ...],
- raw_columns: List[_ColumnsClauseElement],
- ) -> None:
- for right, onclause, left, flags in args:
- if TYPE_CHECKING:
- if onclause is not None:
- assert isinstance(onclause, ColumnElement)
- isouter = flags["isouter"]
- full = flags["full"]
- if left is None:
- (
- left,
- replace_from_obj_index,
- ) = self._join_determine_implicit_left_side(
- raw_columns, left, right, onclause
- )
- else:
- (replace_from_obj_index) = self._join_place_explicit_left_side(
- left
- )
- # these assertions can be made here, as if the right/onclause
- # contained ORM elements, the select() statement would have been
- # upgraded to an ORM select, and this method would not be called;
- # orm.context.ORMSelectCompileState._join() would be
- # used instead.
- if TYPE_CHECKING:
- assert isinstance(right, FromClause)
- if onclause is not None:
- assert isinstance(onclause, ColumnElement)
- if replace_from_obj_index is not None:
- # splice into an existing element in the
- # self._from_obj list
- left_clause = self.from_clauses[replace_from_obj_index]
- self.from_clauses = (
- self.from_clauses[:replace_from_obj_index]
- + (
- Join(
- left_clause,
- right,
- onclause,
- isouter=isouter,
- full=full,
- ),
- )
- + self.from_clauses[replace_from_obj_index + 1 :]
- )
- else:
- assert left is not None
- self.from_clauses = self.from_clauses + (
- Join(left, right, onclause, isouter=isouter, full=full),
- )
- @util.preload_module("sqlalchemy.sql.util")
- def _join_determine_implicit_left_side(
- self,
- raw_columns: List[_ColumnsClauseElement],
- left: Optional[FromClause],
- right: _JoinTargetElement,
- onclause: Optional[ColumnElement[Any]],
- ) -> Tuple[Optional[FromClause], Optional[int]]:
- """When join conditions don't express the left side explicitly,
- determine if an existing FROM or entity in this query
- can serve as the left hand side.
- """
- sql_util = util.preloaded.sql_util
- replace_from_obj_index: Optional[int] = None
- from_clauses = self.from_clauses
- if from_clauses:
- indexes: List[int] = sql_util.find_left_clause_to_join_from(
- from_clauses, right, onclause
- )
- if len(indexes) == 1:
- replace_from_obj_index = indexes[0]
- left = from_clauses[replace_from_obj_index]
- else:
- potential = {}
- statement = self.statement
- for from_clause in itertools.chain(
- itertools.chain.from_iterable(
- [element._from_objects for element in raw_columns]
- ),
- itertools.chain.from_iterable(
- [
- element._from_objects
- for element in statement._where_criteria
- ]
- ),
- ):
- potential[from_clause] = ()
- all_clauses = list(potential.keys())
- indexes = sql_util.find_left_clause_to_join_from(
- all_clauses, right, onclause
- )
- if len(indexes) == 1:
- left = all_clauses[indexes[0]]
- if len(indexes) > 1:
- raise exc.InvalidRequestError(
- "Can't determine which FROM clause to join "
- "from, there are multiple FROMS which can "
- "join to this entity. Please use the .select_from() "
- "method to establish an explicit left side, as well as "
- "providing an explicit ON clause if not present already to "
- "help resolve the ambiguity."
- )
- elif not indexes:
- raise exc.InvalidRequestError(
- "Don't know how to join to %r. "
- "Please use the .select_from() "
- "method to establish an explicit left side, as well as "
- "providing an explicit ON clause if not present already to "
- "help resolve the ambiguity." % (right,)
- )
- return left, replace_from_obj_index
- @util.preload_module("sqlalchemy.sql.util")
- def _join_place_explicit_left_side(
- self, left: FromClause
- ) -> Optional[int]:
- replace_from_obj_index: Optional[int] = None
- sql_util = util.preloaded.sql_util
- from_clauses = list(self.statement._iterate_from_elements())
- if from_clauses:
- indexes: List[int] = sql_util.find_left_clause_that_matches_given(
- self.from_clauses, left
- )
- else:
- indexes = []
- if len(indexes) > 1:
- raise exc.InvalidRequestError(
- "Can't identify which entity in which to assign the "
- "left side of this join. Please use a more specific "
- "ON clause."
- )
- # have an index, means the left side is already present in
- # an existing FROM in the self._from_obj tuple
- if indexes:
- replace_from_obj_index = indexes[0]
- # no index, means we need to add a new element to the
- # self._from_obj tuple
- return replace_from_obj_index
- class _SelectFromElements:
- __slots__ = ()
- _raw_columns: List[_ColumnsClauseElement]
- _where_criteria: Tuple[ColumnElement[Any], ...]
- _from_obj: Tuple[FromClause, ...]
- def _iterate_from_elements(self) -> Iterator[FromClause]:
- # note this does not include elements
- # in _setup_joins
- seen = set()
- for element in self._raw_columns:
- for fr in element._from_objects:
- if fr in seen:
- continue
- seen.add(fr)
- yield fr
- for element in self._where_criteria:
- for fr in element._from_objects:
- if fr in seen:
- continue
- seen.add(fr)
- yield fr
- for element in self._from_obj:
- if element in seen:
- continue
- seen.add(element)
- yield element
- class _MemoizedSelectEntities(
- cache_key.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible
- ):
- """represents partial state from a Select object, for the case
- where Select.columns() has redefined the set of columns/entities the
- statement will be SELECTing from. This object represents
- the entities from the SELECT before that transformation was applied,
- so that transformations that were made in terms of the SELECT at that
- time, such as join() as well as options(), can access the correct context.
- In previous SQLAlchemy versions, this wasn't needed because these
- constructs calculated everything up front, like when you called join()
- or options(), it did everything to figure out how that would translate
- into specific SQL constructs that would be ready to send directly to the
- SQL compiler when needed. But as of
- 1.4, all of that stuff is done in the compilation phase, during the
- "compile state" portion of the process, so that the work can all be
- cached. So it needs to be able to resolve joins/options2 based on what
- the list of entities was when those methods were called.
- """
- __visit_name__ = "memoized_select_entities"
- _traverse_internals: _TraverseInternalsType = [
- ("_raw_columns", InternalTraversal.dp_clauseelement_list),
- ("_setup_joins", InternalTraversal.dp_setup_join_tuple),
- ("_with_options", InternalTraversal.dp_executable_options),
- ]
- _is_clone_of: Optional[ClauseElement]
- _raw_columns: List[_ColumnsClauseElement]
- _setup_joins: Tuple[_SetupJoinsElement, ...]
- _with_options: Tuple[ExecutableOption, ...]
- _annotations = util.EMPTY_DICT
- def _clone(self, **kw: Any) -> Self:
- c = self.__class__.__new__(self.__class__)
- c.__dict__ = {k: v for k, v in self.__dict__.items()}
- c._is_clone_of = self.__dict__.get("_is_clone_of", self)
- return c
- @classmethod
- def _generate_for_statement(cls, select_stmt: Select[Any]) -> None:
- if select_stmt._setup_joins or select_stmt._with_options:
- self = _MemoizedSelectEntities()
- self._raw_columns = select_stmt._raw_columns
- self._setup_joins = select_stmt._setup_joins
- self._with_options = select_stmt._with_options
- select_stmt._memoized_select_entities += (self,)
- select_stmt._raw_columns = []
- select_stmt._setup_joins = select_stmt._with_options = ()
- class Select(
- HasPrefixes,
- HasSuffixes,
- HasHints,
- HasCompileState,
- _SelectFromElements,
- GenerativeSelect,
- TypedReturnsRows[_TP],
- ):
- """Represents a ``SELECT`` statement.
- The :class:`_sql.Select` object is normally constructed using the
- :func:`_sql.select` function. See that function for details.
- .. seealso::
- :func:`_sql.select`
- :ref:`tutorial_selecting_data` - in the 2.0 tutorial
- """
- __visit_name__ = "select"
- _setup_joins: Tuple[_SetupJoinsElement, ...] = ()
- _memoized_select_entities: Tuple[TODO_Any, ...] = ()
- _raw_columns: List[_ColumnsClauseElement]
- _distinct: bool = False
- _distinct_on: Tuple[ColumnElement[Any], ...] = ()
- _correlate: Tuple[FromClause, ...] = ()
- _correlate_except: Optional[Tuple[FromClause, ...]] = None
- _where_criteria: Tuple[ColumnElement[Any], ...] = ()
- _having_criteria: Tuple[ColumnElement[Any], ...] = ()
- _from_obj: Tuple[FromClause, ...] = ()
- _auto_correlate = True
- _is_select_statement = True
- _compile_options: CacheableOptions = (
- SelectState.default_select_compile_options
- )
- _traverse_internals: _TraverseInternalsType = (
- [
- ("_raw_columns", InternalTraversal.dp_clauseelement_list),
- (
- "_memoized_select_entities",
- InternalTraversal.dp_memoized_select_entities,
- ),
- ("_from_obj", InternalTraversal.dp_clauseelement_list),
- ("_where_criteria", InternalTraversal.dp_clauseelement_tuple),
- ("_having_criteria", InternalTraversal.dp_clauseelement_tuple),
- ("_order_by_clauses", InternalTraversal.dp_clauseelement_tuple),
- ("_group_by_clauses", InternalTraversal.dp_clauseelement_tuple),
- ("_setup_joins", InternalTraversal.dp_setup_join_tuple),
- ("_correlate", InternalTraversal.dp_clauseelement_tuple),
- ("_correlate_except", InternalTraversal.dp_clauseelement_tuple),
- ("_limit_clause", InternalTraversal.dp_clauseelement),
- ("_offset_clause", InternalTraversal.dp_clauseelement),
- ("_fetch_clause", InternalTraversal.dp_clauseelement),
- ("_fetch_clause_options", InternalTraversal.dp_plain_dict),
- ("_for_update_arg", InternalTraversal.dp_clauseelement),
- ("_distinct", InternalTraversal.dp_boolean),
- ("_distinct_on", InternalTraversal.dp_clauseelement_tuple),
- ("_label_style", InternalTraversal.dp_plain_obj),
- ]
- + HasCTE._has_ctes_traverse_internals
- + HasPrefixes._has_prefixes_traverse_internals
- + HasSuffixes._has_suffixes_traverse_internals
- + HasHints._has_hints_traverse_internals
- + SupportsCloneAnnotations._clone_annotations_traverse_internals
- + Executable._executable_traverse_internals
- + DialectKWArgs._dialect_kwargs_traverse_internals
- )
- _cache_key_traversal: _CacheKeyTraversalType = _traverse_internals + [
- ("_compile_options", InternalTraversal.dp_has_cache_key)
- ]
- _compile_state_factory: Type[SelectState]
- @classmethod
- def _create_raw_select(cls, **kw: Any) -> Select[Any]:
- """Create a :class:`.Select` using raw ``__new__`` with no coercions.
- Used internally to build up :class:`.Select` constructs with
- pre-established state.
- """
- stmt = Select.__new__(Select)
- stmt.__dict__.update(kw)
- return stmt
- def __init__(
- self, *entities: _ColumnsClauseArgument[Any], **dialect_kw: Any
- ):
- r"""Construct a new :class:`_expression.Select`.
- The public constructor for :class:`_expression.Select` is the
- :func:`_sql.select` function.
- """
- self._raw_columns = [
- coercions.expect(
- roles.ColumnsClauseRole, ent, apply_propagate_attrs=self
- )
- for ent in entities
- ]
- GenerativeSelect.__init__(self)
- def _scalar_type(self) -> TypeEngine[Any]:
- if not self._raw_columns:
- return NULLTYPE
- elem = self._raw_columns[0]
- cols = list(elem._select_iterable)
- return cols[0].type
- def filter(self, *criteria: _ColumnExpressionArgument[bool]) -> Self:
- """A synonym for the :meth:`_sql.Select.where` method."""
- return self.where(*criteria)
- def _filter_by_zero(
- self,
- ) -> Union[
- FromClause, _JoinTargetProtocol, ColumnElement[Any], TextClause
- ]:
- if self._setup_joins:
- meth = SelectState.get_plugin_class(
- self
- ).determine_last_joined_entity
- _last_joined_entity = meth(self)
- if _last_joined_entity is not None:
- return _last_joined_entity
- if self._from_obj:
- return self._from_obj[0]
- return self._raw_columns[0]
- if TYPE_CHECKING:
- @overload
- def scalar_subquery(
- self: Select[Tuple[_MAYBE_ENTITY]],
- ) -> ScalarSelect[Any]: ...
- @overload
- def scalar_subquery(
- self: Select[Tuple[_NOT_ENTITY]],
- ) -> ScalarSelect[_NOT_ENTITY]: ...
- @overload
- def scalar_subquery(self) -> ScalarSelect[Any]: ...
- def scalar_subquery(self) -> ScalarSelect[Any]: ...
- def filter_by(self, **kwargs: Any) -> Self:
- r"""apply the given filtering criterion as a WHERE clause
- to this select.
- """
- from_entity = self._filter_by_zero()
- clauses = [
- _entity_namespace_key(from_entity, key) == value
- for key, value in kwargs.items()
- ]
- return self.filter(*clauses)
- @property
- def column_descriptions(self) -> Any:
- """Return a :term:`plugin-enabled` 'column descriptions' structure
- referring to the columns which are SELECTed by this statement.
- This attribute is generally useful when using the ORM, as an
- extended structure which includes information about mapped
- entities is returned. The section :ref:`queryguide_inspection`
- contains more background.
- For a Core-only statement, the structure returned by this accessor
- is derived from the same objects that are returned by the
- :attr:`.Select.selected_columns` accessor, formatted as a list of
- dictionaries which contain the keys ``name``, ``type`` and ``expr``,
- which indicate the column expressions to be selected::
- >>> stmt = select(user_table)
- >>> stmt.column_descriptions
- [
- {
- 'name': 'id',
- 'type': Integer(),
- 'expr': Column('id', Integer(), ...)},
- {
- 'name': 'name',
- 'type': String(length=30),
- 'expr': Column('name', String(length=30), ...)}
- ]
- .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions`
- attribute returns a structure for a Core-only set of entities,
- not just ORM-only entities.
- .. seealso::
- :attr:`.UpdateBase.entity_description` - entity information for
- an :func:`.insert`, :func:`.update`, or :func:`.delete`
- :ref:`queryguide_inspection` - ORM background
- """
- meth = SelectState.get_plugin_class(self).get_column_descriptions
- return meth(self)
- def from_statement(
- self, statement: roles.ReturnsRowsRole
- ) -> ExecutableReturnsRows:
- """Apply the columns which this :class:`.Select` would select
- onto another statement.
- This operation is :term:`plugin-specific` and will raise a not
- supported exception if this :class:`_sql.Select` does not select from
- plugin-enabled entities.
- The statement is typically either a :func:`_expression.text` or
- :func:`_expression.select` construct, and should return the set of
- columns appropriate to the entities represented by this
- :class:`.Select`.
- .. seealso::
- :ref:`orm_queryguide_selecting_text` - usage examples in the
- ORM Querying Guide
- """
- meth = SelectState.get_plugin_class(self).from_statement
- return meth(self, statement)
- @_generative
- def join(
- self,
- target: _JoinTargetArgument,
- onclause: Optional[_OnClauseArgument] = None,
- *,
- isouter: bool = False,
- full: bool = False,
- ) -> Self:
- r"""Create a SQL JOIN against this :class:`_expression.Select`
- object's criterion
- and apply generatively, returning the newly resulting
- :class:`_expression.Select`.
- E.g.::
- stmt = select(user_table).join(
- address_table, user_table.c.id == address_table.c.user_id
- )
- The above statement generates SQL similar to:
- .. sourcecode:: sql
- SELECT user.id, user.name
- FROM user
- JOIN address ON user.id = address.user_id
- .. versionchanged:: 1.4 :meth:`_expression.Select.join` now creates
- a :class:`_sql.Join` object between a :class:`_sql.FromClause`
- source that is within the FROM clause of the existing SELECT,
- and a given target :class:`_sql.FromClause`, and then adds
- this :class:`_sql.Join` to the FROM clause of the newly generated
- SELECT statement. This is completely reworked from the behavior
- in 1.3, which would instead create a subquery of the entire
- :class:`_expression.Select` and then join that subquery to the
- target.
- This is a **backwards incompatible change** as the previous behavior
- was mostly useless, producing an unnamed subquery rejected by
- most databases in any case. The new behavior is modeled after
- that of the very successful :meth:`_orm.Query.join` method in the
- ORM, in order to support the functionality of :class:`_orm.Query`
- being available by using a :class:`_sql.Select` object with an
- :class:`_orm.Session`.
- See the notes for this change at :ref:`change_select_join`.
- :param target: target table to join towards
- :param onclause: ON clause of the join. If omitted, an ON clause
- is generated automatically based on the :class:`_schema.ForeignKey`
- linkages between the two tables, if one can be unambiguously
- determined, otherwise an error is raised.
- :param isouter: if True, generate LEFT OUTER join. Same as
- :meth:`_expression.Select.outerjoin`.
- :param full: if True, generate FULL OUTER join.
- .. seealso::
- :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
- :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
- :meth:`_expression.Select.join_from`
- :meth:`_expression.Select.outerjoin`
- """ # noqa: E501
- join_target = coercions.expect(
- roles.JoinTargetRole, target, apply_propagate_attrs=self
- )
- if onclause is not None:
- onclause_element = coercions.expect(roles.OnClauseRole, onclause)
- else:
- onclause_element = None
- self._setup_joins += (
- (
- join_target,
- onclause_element,
- None,
- {"isouter": isouter, "full": full},
- ),
- )
- return self
- def outerjoin_from(
- self,
- from_: _FromClauseArgument,
- target: _JoinTargetArgument,
- onclause: Optional[_OnClauseArgument] = None,
- *,
- full: bool = False,
- ) -> Self:
- r"""Create a SQL LEFT OUTER JOIN against this
- :class:`_expression.Select` object's criterion and apply generatively,
- returning the newly resulting :class:`_expression.Select`.
- Usage is the same as that of :meth:`_selectable.Select.join_from`.
- """
- return self.join_from(
- from_, target, onclause=onclause, isouter=True, full=full
- )
- @_generative
- def join_from(
- self,
- from_: _FromClauseArgument,
- target: _JoinTargetArgument,
- onclause: Optional[_OnClauseArgument] = None,
- *,
- isouter: bool = False,
- full: bool = False,
- ) -> Self:
- r"""Create a SQL JOIN against this :class:`_expression.Select`
- object's criterion
- and apply generatively, returning the newly resulting
- :class:`_expression.Select`.
- E.g.::
- stmt = select(user_table, address_table).join_from(
- user_table, address_table, user_table.c.id == address_table.c.user_id
- )
- The above statement generates SQL similar to:
- .. sourcecode:: sql
- SELECT user.id, user.name, address.id, address.email, address.user_id
- FROM user JOIN address ON user.id = address.user_id
- .. versionadded:: 1.4
- :param from\_: the left side of the join, will be rendered in the
- FROM clause and is roughly equivalent to using the
- :meth:`.Select.select_from` method.
- :param target: target table to join towards
- :param onclause: ON clause of the join.
- :param isouter: if True, generate LEFT OUTER join. Same as
- :meth:`_expression.Select.outerjoin`.
- :param full: if True, generate FULL OUTER join.
- .. seealso::
- :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
- :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
- :meth:`_expression.Select.join`
- """ # noqa: E501
- # note the order of parsing from vs. target is important here, as we
- # are also deriving the source of the plugin (i.e. the subject mapper
- # in an ORM query) which should favor the "from_" over the "target"
- from_ = coercions.expect(
- roles.FromClauseRole, from_, apply_propagate_attrs=self
- )
- join_target = coercions.expect(
- roles.JoinTargetRole, target, apply_propagate_attrs=self
- )
- if onclause is not None:
- onclause_element = coercions.expect(roles.OnClauseRole, onclause)
- else:
- onclause_element = None
- self._setup_joins += (
- (
- join_target,
- onclause_element,
- from_,
- {"isouter": isouter, "full": full},
- ),
- )
- return self
- def outerjoin(
- self,
- target: _JoinTargetArgument,
- onclause: Optional[_OnClauseArgument] = None,
- *,
- full: bool = False,
- ) -> Self:
- """Create a left outer join.
- Parameters are the same as that of :meth:`_expression.Select.join`.
- .. versionchanged:: 1.4 :meth:`_expression.Select.outerjoin` now
- creates a :class:`_sql.Join` object between a
- :class:`_sql.FromClause` source that is within the FROM clause of
- the existing SELECT, and a given target :class:`_sql.FromClause`,
- and then adds this :class:`_sql.Join` to the FROM clause of the
- newly generated SELECT statement. This is completely reworked
- from the behavior in 1.3, which would instead create a subquery of
- the entire
- :class:`_expression.Select` and then join that subquery to the
- target.
- This is a **backwards incompatible change** as the previous behavior
- was mostly useless, producing an unnamed subquery rejected by
- most databases in any case. The new behavior is modeled after
- that of the very successful :meth:`_orm.Query.join` method in the
- ORM, in order to support the functionality of :class:`_orm.Query`
- being available by using a :class:`_sql.Select` object with an
- :class:`_orm.Session`.
- See the notes for this change at :ref:`change_select_join`.
- .. seealso::
- :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
- :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
- :meth:`_expression.Select.join`
- """
- return self.join(target, onclause=onclause, isouter=True, full=full)
- def get_final_froms(self) -> Sequence[FromClause]:
- """Compute the final displayed list of :class:`_expression.FromClause`
- elements.
- This method will run through the full computation required to
- determine what FROM elements will be displayed in the resulting
- SELECT statement, including shadowing individual tables with
- JOIN objects, as well as full computation for ORM use cases including
- eager loading clauses.
- For ORM use, this accessor returns the **post compilation**
- list of FROM objects; this collection will include elements such as
- eagerly loaded tables and joins. The objects will **not** be
- ORM enabled and not work as a replacement for the
- :meth:`_sql.Select.select_froms` collection; additionally, the
- method is not well performing for an ORM enabled statement as it
- will incur the full ORM construction process.
- To retrieve the FROM list that's implied by the "columns" collection
- passed to the :class:`_sql.Select` originally, use the
- :attr:`_sql.Select.columns_clause_froms` accessor.
- To select from an alternative set of columns while maintaining the
- FROM list, use the :meth:`_sql.Select.with_only_columns` method and
- pass the
- :paramref:`_sql.Select.with_only_columns.maintain_column_froms`
- parameter.
- .. versionadded:: 1.4.23 - the :meth:`_sql.Select.get_final_froms`
- method replaces the previous :attr:`_sql.Select.froms` accessor,
- which is deprecated.
- .. seealso::
- :attr:`_sql.Select.columns_clause_froms`
- """
- compiler = self._default_compiler()
- return self._compile_state_factory(self, compiler)._get_display_froms()
- @property
- @util.deprecated(
- "1.4.23",
- "The :attr:`_expression.Select.froms` attribute is moved to "
- "the :meth:`_expression.Select.get_final_froms` method.",
- )
- def froms(self) -> Sequence[FromClause]:
- """Return the displayed list of :class:`_expression.FromClause`
- elements.
- """
- return self.get_final_froms()
- @property
- def columns_clause_froms(self) -> List[FromClause]:
- """Return the set of :class:`_expression.FromClause` objects implied
- by the columns clause of this SELECT statement.
- .. versionadded:: 1.4.23
- .. seealso::
- :attr:`_sql.Select.froms` - "final" FROM list taking the full
- statement into account
- :meth:`_sql.Select.with_only_columns` - makes use of this
- collection to set up a new FROM list
- """
- return SelectState.get_plugin_class(self).get_columns_clause_froms(
- self
- )
- @property
- def inner_columns(self) -> _SelectIterable:
- """An iterator of all :class:`_expression.ColumnElement`
- expressions which would
- be rendered into the columns clause of the resulting SELECT statement.
- This method is legacy as of 1.4 and is superseded by the
- :attr:`_expression.Select.exported_columns` collection.
- """
- return iter(self._all_selected_columns)
- def is_derived_from(self, fromclause: Optional[FromClause]) -> bool:
- if fromclause is not None and self in fromclause._cloned_set:
- return True
- for f in self._iterate_from_elements():
- if f.is_derived_from(fromclause):
- return True
- return False
- def _copy_internals(
- self, clone: _CloneCallableType = _clone, **kw: Any
- ) -> None:
- # Select() object has been cloned and probably adapted by the
- # given clone function. Apply the cloning function to internal
- # objects
- # 1. keep a dictionary of the froms we've cloned, and what
- # they've become. This allows us to ensure the same cloned from
- # is used when other items such as columns are "cloned"
- all_the_froms = set(
- itertools.chain(
- _from_objects(*self._raw_columns),
- _from_objects(*self._where_criteria),
- _from_objects(*[elem[0] for elem in self._setup_joins]),
- )
- )
- # do a clone for the froms we've gathered. what is important here
- # is if any of the things we are selecting from, like tables,
- # were converted into Join objects. if so, these need to be
- # added to _from_obj explicitly, because otherwise they won't be
- # part of the new state, as they don't associate themselves with
- # their columns.
- new_froms = {f: clone(f, **kw) for f in all_the_froms}
- # 2. copy FROM collections, adding in joins that we've created.
- existing_from_obj = [clone(f, **kw) for f in self._from_obj]
- add_froms = (
- {f for f in new_froms.values() if isinstance(f, Join)}
- .difference(all_the_froms)
- .difference(existing_from_obj)
- )
- self._from_obj = tuple(existing_from_obj) + tuple(add_froms)
- # 3. clone everything else, making sure we use columns
- # corresponding to the froms we just made.
- def replace(
- obj: Union[BinaryExpression[Any], ColumnClause[Any]],
- **kw: Any,
- ) -> Optional[KeyedColumnElement[Any]]:
- if isinstance(obj, ColumnClause) and obj.table in new_froms:
- newelem = new_froms[obj.table].corresponding_column(obj)
- return newelem
- return None
- kw["replace"] = replace
- # copy everything else. for table-ish things like correlate,
- # correlate_except, setup_joins, these clone normally. For
- # column-expression oriented things like raw_columns, where_criteria,
- # order by, we get this from the new froms.
- super()._copy_internals(clone=clone, omit_attrs=("_from_obj",), **kw)
- self._reset_memoizations()
- def get_children(self, **kw: Any) -> Iterable[ClauseElement]:
- return itertools.chain(
- super().get_children(
- omit_attrs=("_from_obj", "_correlate", "_correlate_except"),
- **kw,
- ),
- self._iterate_from_elements(),
- )
- @_generative
- def add_columns(
- self, *entities: _ColumnsClauseArgument[Any]
- ) -> Select[Any]:
- r"""Return a new :func:`_expression.select` construct with
- the given entities appended to its columns clause.
- E.g.::
- my_select = my_select.add_columns(table.c.new_column)
- The original expressions in the columns clause remain in place.
- To replace the original expressions with new ones, see the method
- :meth:`_expression.Select.with_only_columns`.
- :param \*entities: column, table, or other entity expressions to be
- added to the columns clause
- .. seealso::
- :meth:`_expression.Select.with_only_columns` - replaces existing
- expressions rather than appending.
- :ref:`orm_queryguide_select_multiple_entities` - ORM-centric
- example
- """
- self._reset_memoizations()
- self._raw_columns = self._raw_columns + [
- coercions.expect(
- roles.ColumnsClauseRole, column, apply_propagate_attrs=self
- )
- for column in entities
- ]
- return self
- def _set_entities(
- self, entities: Iterable[_ColumnsClauseArgument[Any]]
- ) -> None:
- self._raw_columns = [
- coercions.expect(
- roles.ColumnsClauseRole, ent, apply_propagate_attrs=self
- )
- for ent in util.to_list(entities)
- ]
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.column` method is deprecated and will "
- "be removed in a future release. Please use "
- ":meth:`_expression.Select.add_columns`",
- )
- def column(self, column: _ColumnsClauseArgument[Any]) -> Select[Any]:
- """Return a new :func:`_expression.select` construct with
- the given column expression added to its columns clause.
- E.g.::
- my_select = my_select.column(table.c.new_column)
- See the documentation for
- :meth:`_expression.Select.with_only_columns`
- for guidelines on adding /replacing the columns of a
- :class:`_expression.Select` object.
- """
- return self.add_columns(column)
- @util.preload_module("sqlalchemy.sql.util")
- def reduce_columns(self, only_synonyms: bool = True) -> Select[Any]:
- """Return a new :func:`_expression.select` construct with redundantly
- named, equivalently-valued columns removed from the columns clause.
- "Redundant" here means two columns where one refers to the
- other either based on foreign key, or via a simple equality
- comparison in the WHERE clause of the statement. The primary purpose
- of this method is to automatically construct a select statement
- with all uniquely-named columns, without the need to use
- table-qualified labels as
- :meth:`_expression.Select.set_label_style`
- does.
- When columns are omitted based on foreign key, the referred-to
- column is the one that's kept. When columns are omitted based on
- WHERE equivalence, the first column in the columns clause is the
- one that's kept.
- :param only_synonyms: when True, limit the removal of columns
- to those which have the same name as the equivalent. Otherwise,
- all columns that are equivalent to another are removed.
- """
- woc: Select[Any]
- woc = self.with_only_columns(
- *util.preloaded.sql_util.reduce_columns(
- self._all_selected_columns,
- only_synonyms=only_synonyms,
- *(self._where_criteria + self._from_obj),
- )
- )
- return woc
- # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501
- # code within this block is **programmatically,
- # statically generated** by tools/generate_tuple_map_overloads.py
- @overload
- def with_only_columns(
- self, __ent0: _TCCA[_T0], *, maintain_column_froms: bool = ...
- ) -> Select[Tuple[_T0]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1, _T2]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1, _T2, _T3]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- __ent5: _TCCA[_T5],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- __ent5: _TCCA[_T5],
- __ent6: _TCCA[_T6],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
- @overload
- def with_only_columns(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- __ent5: _TCCA[_T5],
- __ent6: _TCCA[_T6],
- __ent7: _TCCA[_T7],
- *,
- maintain_column_froms: bool = ...,
- ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ...
- # END OVERLOADED FUNCTIONS self.with_only_columns
- @overload
- def with_only_columns(
- self,
- *entities: _ColumnsClauseArgument[Any],
- maintain_column_froms: bool = False,
- **__kw: Any,
- ) -> Select[Any]: ...
- @_generative
- def with_only_columns(
- self,
- *entities: _ColumnsClauseArgument[Any],
- maintain_column_froms: bool = False,
- **__kw: Any,
- ) -> Select[Any]:
- r"""Return a new :func:`_expression.select` construct with its columns
- clause replaced with the given entities.
- By default, this method is exactly equivalent to as if the original
- :func:`_expression.select` had been called with the given entities.
- E.g. a statement::
- s = select(table1.c.a, table1.c.b)
- s = s.with_only_columns(table1.c.b)
- should be exactly equivalent to::
- s = select(table1.c.b)
- In this mode of operation, :meth:`_sql.Select.with_only_columns`
- will also dynamically alter the FROM clause of the
- statement if it is not explicitly stated.
- To maintain the existing set of FROMs including those implied by the
- current columns clause, add the
- :paramref:`_sql.Select.with_only_columns.maintain_column_froms`
- parameter::
- s = select(table1.c.a, table2.c.b)
- s = s.with_only_columns(table1.c.a, maintain_column_froms=True)
- The above parameter performs a transfer of the effective FROMs
- in the columns collection to the :meth:`_sql.Select.select_from`
- method, as though the following were invoked::
- s = select(table1.c.a, table2.c.b)
- s = s.select_from(table1, table2).with_only_columns(table1.c.a)
- The :paramref:`_sql.Select.with_only_columns.maintain_column_froms`
- parameter makes use of the :attr:`_sql.Select.columns_clause_froms`
- collection and performs an operation equivalent to the following::
- s = select(table1.c.a, table2.c.b)
- s = s.select_from(*s.columns_clause_froms).with_only_columns(table1.c.a)
- :param \*entities: column expressions to be used.
- :param maintain_column_froms: boolean parameter that will ensure the
- FROM list implied from the current columns clause will be transferred
- to the :meth:`_sql.Select.select_from` method first.
- .. versionadded:: 1.4.23
- """ # noqa: E501
- if __kw:
- raise _no_kw()
- # memoizations should be cleared here as of
- # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this
- # is the case for now.
- self._assert_no_memoizations()
- if maintain_column_froms:
- self.select_from.non_generative( # type: ignore
- self, *self.columns_clause_froms
- )
- # then memoize the FROMs etc.
- _MemoizedSelectEntities._generate_for_statement(self)
- self._raw_columns = [
- coercions.expect(roles.ColumnsClauseRole, c)
- for c in coercions._expression_collection_was_a_list(
- "entities", "Select.with_only_columns", entities
- )
- ]
- return self
- @property
- def whereclause(self) -> Optional[ColumnElement[Any]]:
- """Return the completed WHERE clause for this
- :class:`_expression.Select` statement.
- This assembles the current collection of WHERE criteria
- into a single :class:`_expression.BooleanClauseList` construct.
- .. versionadded:: 1.4
- """
- return BooleanClauseList._construct_for_whereclause(
- self._where_criteria
- )
- _whereclause = whereclause
- @_generative
- def where(self, *whereclause: _ColumnExpressionArgument[bool]) -> Self:
- """Return a new :func:`_expression.select` construct with
- the given expression added to
- its WHERE clause, joined to the existing clause via AND, if any.
- """
- assert isinstance(self._where_criteria, tuple)
- for criterion in whereclause:
- where_criteria: ColumnElement[Any] = coercions.expect(
- roles.WhereHavingRole, criterion, apply_propagate_attrs=self
- )
- self._where_criteria += (where_criteria,)
- return self
- @_generative
- def having(self, *having: _ColumnExpressionArgument[bool]) -> Self:
- """Return a new :func:`_expression.select` construct with
- the given expression added to
- its HAVING clause, joined to the existing clause via AND, if any.
- """
- for criterion in having:
- having_criteria = coercions.expect(
- roles.WhereHavingRole, criterion, apply_propagate_attrs=self
- )
- self._having_criteria += (having_criteria,)
- return self
- @_generative
- def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self:
- r"""Return a new :func:`_expression.select` construct which
- will apply DISTINCT to the SELECT statement overall.
- E.g.::
- from sqlalchemy import select
- stmt = select(users_table.c.id, users_table.c.name).distinct()
- The above would produce an statement resembling:
- .. sourcecode:: sql
- SELECT DISTINCT user.id, user.name FROM user
- The method also accepts an ``*expr`` parameter which produces the
- PostgreSQL dialect-specific ``DISTINCT ON`` expression. Using this
- parameter on other backends which don't support this syntax will
- raise an error.
- :param \*expr: optional column expressions. When present,
- the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)``
- construct. A deprecation warning and/or :class:`_exc.CompileError`
- will be raised on other backends.
- .. deprecated:: 1.4 Using \*expr in other dialects is deprecated
- and will raise :class:`_exc.CompileError` in a future version.
- """
- if expr:
- self._distinct = True
- self._distinct_on = self._distinct_on + tuple(
- coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self)
- for e in expr
- )
- else:
- self._distinct = True
- return self
- @_generative
- def select_from(self, *froms: _FromClauseArgument) -> Self:
- r"""Return a new :func:`_expression.select` construct with the
- given FROM expression(s)
- merged into its list of FROM objects.
- E.g.::
- table1 = table("t1", column("a"))
- table2 = table("t2", column("b"))
- s = select(table1.c.a).select_from(
- table1.join(table2, table1.c.a == table2.c.b)
- )
- The "from" list is a unique set on the identity of each element,
- so adding an already present :class:`_schema.Table`
- or other selectable
- will have no effect. Passing a :class:`_expression.Join` that refers
- to an already present :class:`_schema.Table`
- or other selectable will have
- the effect of concealing the presence of that selectable as
- an individual element in the rendered FROM list, instead
- rendering it into a JOIN clause.
- While the typical purpose of :meth:`_expression.Select.select_from`
- is to
- replace the default, derived FROM clause with a join, it can
- also be called with individual table elements, multiple times
- if desired, in the case that the FROM clause cannot be fully
- derived from the columns clause::
- select(func.count("*")).select_from(table1)
- """
- self._from_obj += tuple(
- coercions.expect(
- roles.FromClauseRole, fromclause, apply_propagate_attrs=self
- )
- for fromclause in froms
- )
- return self
- @_generative
- def correlate(
- self,
- *fromclauses: Union[Literal[None, False], _FromClauseArgument],
- ) -> Self:
- r"""Return a new :class:`_expression.Select`
- which will correlate the given FROM
- clauses to that of an enclosing :class:`_expression.Select`.
- Calling this method turns off the :class:`_expression.Select` object's
- default behavior of "auto-correlation". Normally, FROM elements
- which appear in a :class:`_expression.Select`
- that encloses this one via
- its :term:`WHERE clause`, ORDER BY, HAVING or
- :term:`columns clause` will be omitted from this
- :class:`_expression.Select`
- object's :term:`FROM clause`.
- Setting an explicit correlation collection using the
- :meth:`_expression.Select.correlate`
- method provides a fixed list of FROM objects
- that can potentially take place in this process.
- When :meth:`_expression.Select.correlate`
- is used to apply specific FROM clauses
- for correlation, the FROM elements become candidates for
- correlation regardless of how deeply nested this
- :class:`_expression.Select`
- object is, relative to an enclosing :class:`_expression.Select`
- which refers to
- the same FROM object. This is in contrast to the behavior of
- "auto-correlation" which only correlates to an immediate enclosing
- :class:`_expression.Select`.
- Multi-level correlation ensures that the link
- between enclosed and enclosing :class:`_expression.Select`
- is always via
- at least one WHERE/ORDER BY/HAVING/columns clause in order for
- correlation to take place.
- If ``None`` is passed, the :class:`_expression.Select`
- object will correlate
- none of its FROM entries, and all will render unconditionally
- in the local FROM clause.
- :param \*fromclauses: one or more :class:`.FromClause` or other
- FROM-compatible construct such as an ORM mapped entity to become part
- of the correlate collection; alternatively pass a single value
- ``None`` to remove all existing correlations.
- .. seealso::
- :meth:`_expression.Select.correlate_except`
- :ref:`tutorial_scalar_subquery`
- """
- # tests failing when we try to change how these
- # arguments are passed
- self._auto_correlate = False
- if not fromclauses or fromclauses[0] in {None, False}:
- if len(fromclauses) > 1:
- raise exc.ArgumentError(
- "additional FROM objects not accepted when "
- "passing None/False to correlate()"
- )
- self._correlate = ()
- else:
- self._correlate = self._correlate + tuple(
- coercions.expect(roles.FromClauseRole, f) for f in fromclauses
- )
- return self
- @_generative
- def correlate_except(
- self,
- *fromclauses: Union[Literal[None, False], _FromClauseArgument],
- ) -> Self:
- r"""Return a new :class:`_expression.Select`
- which will omit the given FROM
- clauses from the auto-correlation process.
- Calling :meth:`_expression.Select.correlate_except` turns off the
- :class:`_expression.Select` object's default behavior of
- "auto-correlation" for the given FROM elements. An element
- specified here will unconditionally appear in the FROM list, while
- all other FROM elements remain subject to normal auto-correlation
- behaviors.
- If ``None`` is passed, or no arguments are passed,
- the :class:`_expression.Select` object will correlate all of its
- FROM entries.
- :param \*fromclauses: a list of one or more
- :class:`_expression.FromClause`
- constructs, or other compatible constructs (i.e. ORM-mapped
- classes) to become part of the correlate-exception collection.
- .. seealso::
- :meth:`_expression.Select.correlate`
- :ref:`tutorial_scalar_subquery`
- """
- self._auto_correlate = False
- if not fromclauses or fromclauses[0] in {None, False}:
- if len(fromclauses) > 1:
- raise exc.ArgumentError(
- "additional FROM objects not accepted when "
- "passing None/False to correlate_except()"
- )
- self._correlate_except = ()
- else:
- self._correlate_except = (self._correlate_except or ()) + tuple(
- coercions.expect(roles.FromClauseRole, f) for f in fromclauses
- )
- return self
- @HasMemoized_ro_memoized_attribute
- def selected_columns(
- self,
- ) -> ColumnCollection[str, ColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- representing the columns that
- this SELECT statement or similar construct returns in its result set,
- not including :class:`_sql.TextClause` constructs.
- This collection differs from the :attr:`_expression.FromClause.columns`
- collection of a :class:`_expression.FromClause` in that the columns
- within this collection cannot be directly nested inside another SELECT
- statement; a subquery must be applied first which provides for the
- necessary parenthesization required by SQL.
- For a :func:`_expression.select` construct, the collection here is
- exactly what would be rendered inside the "SELECT" statement, and the
- :class:`_expression.ColumnElement` objects are directly present as they
- were given, e.g.::
- col1 = column("q", Integer)
- col2 = column("p", Integer)
- stmt = select(col1, col2)
- Above, ``stmt.selected_columns`` would be a collection that contains
- the ``col1`` and ``col2`` objects directly. For a statement that is
- against a :class:`_schema.Table` or other
- :class:`_expression.FromClause`, the collection will use the
- :class:`_expression.ColumnElement` objects that are in the
- :attr:`_expression.FromClause.c` collection of the from element.
- A use case for the :attr:`_sql.Select.selected_columns` collection is
- to allow the existing columns to be referenced when adding additional
- criteria, e.g.::
- def filter_on_id(my_select, id):
- return my_select.where(my_select.selected_columns["id"] == id)
- stmt = select(MyModel)
- # adds "WHERE id=:param" to the statement
- stmt = filter_on_id(stmt, 42)
- .. note::
- The :attr:`_sql.Select.selected_columns` collection does not
- include expressions established in the columns clause using the
- :func:`_sql.text` construct; these are silently omitted from the
- collection. To use plain textual column expressions inside of a
- :class:`_sql.Select` construct, use the :func:`_sql.literal_column`
- construct.
- .. versionadded:: 1.4
- """
- # compare to SelectState._generate_columns_plus_names, which
- # generates the actual names used in the SELECT string. that
- # method is more complex because it also renders columns that are
- # fully ambiguous, e.g. same column more than once.
- conv = cast(
- "Callable[[Any], str]",
- SelectState._column_naming_convention(self._label_style),
- )
- cc: ColumnCollection[str, ColumnElement[Any]] = ColumnCollection(
- [
- (conv(c), c)
- for c in self._all_selected_columns
- if is_column_element(c)
- ]
- )
- return cc.as_readonly()
- @HasMemoized_ro_memoized_attribute
- def _all_selected_columns(self) -> _SelectIterable:
- meth = SelectState.get_plugin_class(self).all_selected_columns
- return list(meth(self))
- def _ensure_disambiguated_names(self) -> Select[Any]:
- if self._label_style is LABEL_STYLE_NONE:
- self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
- return self
- def _generate_fromclause_column_proxies(
- self,
- subquery: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- *,
- proxy_compound_columns: Optional[
- Iterable[Sequence[ColumnElement[Any]]]
- ] = None,
- ) -> None:
- """Generate column proxies to place in the exported ``.c``
- collection of a subquery."""
- if proxy_compound_columns:
- extra_col_iterator = proxy_compound_columns
- prox = [
- c._make_proxy(
- subquery,
- key=proxy_key,
- name=required_label_name,
- name_is_truncatable=True,
- compound_select_cols=extra_cols,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- for (
- (
- required_label_name,
- proxy_key,
- fallback_label_name,
- c,
- repeated,
- ),
- extra_cols,
- ) in (
- zip(
- self._generate_columns_plus_names(False),
- extra_col_iterator,
- )
- )
- if is_column_element(c)
- ]
- else:
- prox = [
- c._make_proxy(
- subquery,
- key=proxy_key,
- name=required_label_name,
- name_is_truncatable=True,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- for (
- required_label_name,
- proxy_key,
- fallback_label_name,
- c,
- repeated,
- ) in (self._generate_columns_plus_names(False))
- if is_column_element(c)
- ]
- columns._populate_separate_keys(prox)
- def _needs_parens_for_grouping(self) -> bool:
- return self._has_row_limiting_clause or bool(
- self._order_by_clause.clauses
- )
- def self_group(
- self, against: Optional[OperatorType] = None
- ) -> Union[SelectStatementGrouping[Self], Self]:
- """Return a 'grouping' construct as per the
- :class:`_expression.ClauseElement` specification.
- This produces an element that can be embedded in an expression. Note
- that this method is called automatically as needed when constructing
- expressions and should not require explicit use.
- """
- if (
- isinstance(against, CompoundSelect)
- and not self._needs_parens_for_grouping()
- ):
- return self
- else:
- return SelectStatementGrouping(self)
- def union(
- self, *other: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- r"""Return a SQL ``UNION`` of this select() construct against
- the given selectables provided as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28
- multiple elements are now accepted.
- :param \**kwargs: keyword arguments are forwarded to the constructor
- for the newly created :class:`_sql.CompoundSelect` object.
- """
- return CompoundSelect._create_union(self, *other)
- def union_all(
- self, *other: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- r"""Return a SQL ``UNION ALL`` of this select() construct against
- the given selectables provided as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28
- multiple elements are now accepted.
- :param \**kwargs: keyword arguments are forwarded to the constructor
- for the newly created :class:`_sql.CompoundSelect` object.
- """
- return CompoundSelect._create_union_all(self, *other)
- def except_(
- self, *other: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- r"""Return a SQL ``EXCEPT`` of this select() construct against
- the given selectable provided as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28
- multiple elements are now accepted.
- """
- return CompoundSelect._create_except(self, *other)
- def except_all(
- self, *other: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- r"""Return a SQL ``EXCEPT ALL`` of this select() construct against
- the given selectables provided as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28
- multiple elements are now accepted.
- """
- return CompoundSelect._create_except_all(self, *other)
- def intersect(
- self, *other: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- r"""Return a SQL ``INTERSECT`` of this select() construct against
- the given selectables provided as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28
- multiple elements are now accepted.
- :param \**kwargs: keyword arguments are forwarded to the constructor
- for the newly created :class:`_sql.CompoundSelect` object.
- """
- return CompoundSelect._create_intersect(self, *other)
- def intersect_all(
- self, *other: _SelectStatementForCompoundArgument[_TP]
- ) -> CompoundSelect[_TP]:
- r"""Return a SQL ``INTERSECT ALL`` of this select() construct
- against the given selectables provided as positional arguments.
- :param \*other: one or more elements with which to create a
- UNION.
- .. versionchanged:: 1.4.28
- multiple elements are now accepted.
- :param \**kwargs: keyword arguments are forwarded to the constructor
- for the newly created :class:`_sql.CompoundSelect` object.
- """
- return CompoundSelect._create_intersect_all(self, *other)
- class ScalarSelect(
- roles.InElementRole, Generative, GroupedElement, ColumnElement[_T]
- ):
- """Represent a scalar subquery.
- A :class:`_sql.ScalarSelect` is created by invoking the
- :meth:`_sql.SelectBase.scalar_subquery` method. The object
- then participates in other SQL expressions as a SQL column expression
- within the :class:`_sql.ColumnElement` hierarchy.
- .. seealso::
- :meth:`_sql.SelectBase.scalar_subquery`
- :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
- """
- _traverse_internals: _TraverseInternalsType = [
- ("element", InternalTraversal.dp_clauseelement),
- ("type", InternalTraversal.dp_type),
- ]
- _from_objects: List[FromClause] = []
- _is_from_container = True
- if not TYPE_CHECKING:
- _is_implicitly_boolean = False
- inherit_cache = True
- element: SelectBase
- def __init__(self, element: SelectBase) -> None:
- self.element = element
- self.type = element._scalar_type()
- self._propagate_attrs = element._propagate_attrs
- def __getattr__(self, attr: str) -> Any:
- return getattr(self.element, attr)
- def __getstate__(self) -> Dict[str, Any]:
- return {"element": self.element, "type": self.type}
- def __setstate__(self, state: Dict[str, Any]) -> None:
- self.element = state["element"]
- self.type = state["type"]
- @property
- def columns(self) -> NoReturn:
- raise exc.InvalidRequestError(
- "Scalar Select expression has no "
- "columns; use this object directly "
- "within a column-level expression."
- )
- c = columns
- @_generative
- def where(self, crit: _ColumnExpressionArgument[bool]) -> Self:
- """Apply a WHERE clause to the SELECT statement referred to
- by this :class:`_expression.ScalarSelect`.
- """
- self.element = cast("Select[Any]", self.element).where(crit)
- return self
- def self_group(self, against: Optional[OperatorType] = None) -> Self:
- return self
- def _ungroup(self) -> Self:
- return self
- @_generative
- def correlate(
- self,
- *fromclauses: Union[Literal[None, False], _FromClauseArgument],
- ) -> Self:
- r"""Return a new :class:`_expression.ScalarSelect`
- which will correlate the given FROM
- clauses to that of an enclosing :class:`_expression.Select`.
- This method is mirrored from the :meth:`_sql.Select.correlate` method
- of the underlying :class:`_sql.Select`. The method applies the
- :meth:_sql.Select.correlate` method, then returns a new
- :class:`_sql.ScalarSelect` against that statement.
- .. versionadded:: 1.4 Previously, the
- :meth:`_sql.ScalarSelect.correlate`
- method was only available from :class:`_sql.Select`.
- :param \*fromclauses: a list of one or more
- :class:`_expression.FromClause`
- constructs, or other compatible constructs (i.e. ORM-mapped
- classes) to become part of the correlate collection.
- .. seealso::
- :meth:`_expression.ScalarSelect.correlate_except`
- :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
- """
- self.element = cast("Select[Any]", self.element).correlate(
- *fromclauses
- )
- return self
- @_generative
- def correlate_except(
- self,
- *fromclauses: Union[Literal[None, False], _FromClauseArgument],
- ) -> Self:
- r"""Return a new :class:`_expression.ScalarSelect`
- which will omit the given FROM
- clauses from the auto-correlation process.
- This method is mirrored from the
- :meth:`_sql.Select.correlate_except` method of the underlying
- :class:`_sql.Select`. The method applies the
- :meth:_sql.Select.correlate_except` method, then returns a new
- :class:`_sql.ScalarSelect` against that statement.
- .. versionadded:: 1.4 Previously, the
- :meth:`_sql.ScalarSelect.correlate_except`
- method was only available from :class:`_sql.Select`.
- :param \*fromclauses: a list of one or more
- :class:`_expression.FromClause`
- constructs, or other compatible constructs (i.e. ORM-mapped
- classes) to become part of the correlate-exception collection.
- .. seealso::
- :meth:`_expression.ScalarSelect.correlate`
- :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
- """
- self.element = cast("Select[Any]", self.element).correlate_except(
- *fromclauses
- )
- return self
- class Exists(UnaryExpression[bool]):
- """Represent an ``EXISTS`` clause.
- See :func:`_sql.exists` for a description of usage.
- An ``EXISTS`` clause can also be constructed from a :func:`_sql.select`
- instance by calling :meth:`_sql.SelectBase.exists`.
- """
- inherit_cache = True
- def __init__(
- self,
- __argument: Optional[
- Union[_ColumnsClauseArgument[Any], SelectBase, ScalarSelect[Any]]
- ] = None,
- ):
- s: ScalarSelect[Any]
- # TODO: this seems like we should be using coercions for this
- if __argument is None:
- s = Select(literal_column("*")).scalar_subquery()
- elif isinstance(__argument, SelectBase):
- s = __argument.scalar_subquery()
- s._propagate_attrs = __argument._propagate_attrs
- elif isinstance(__argument, ScalarSelect):
- s = __argument
- else:
- s = Select(__argument).scalar_subquery()
- UnaryExpression.__init__(
- self,
- s,
- operator=operators.exists,
- type_=type_api.BOOLEANTYPE,
- )
- @util.ro_non_memoized_property
- def _from_objects(self) -> List[FromClause]:
- return []
- def _regroup(
- self,
- fn: Callable[[Select[Any]], Select[Any]],
- ) -> ScalarSelect[Any]:
- assert isinstance(self.element, ScalarSelect)
- element = self.element.element
- if not isinstance(element, Select):
- raise exc.InvalidRequestError(
- "Can only apply this operation to a plain SELECT construct"
- )
- new_element = fn(element)
- return_value = new_element.scalar_subquery()
- return return_value
- def select(self) -> Select[Tuple[bool]]:
- r"""Return a SELECT of this :class:`_expression.Exists`.
- e.g.::
- stmt = exists(some_table.c.id).where(some_table.c.id == 5).select()
- This will produce a statement resembling:
- .. sourcecode:: sql
- SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1
- .. seealso::
- :func:`_expression.select` - general purpose
- method which allows for arbitrary column lists.
- """ # noqa
- return Select(self)
- def correlate(
- self,
- *fromclauses: Union[Literal[None, False], _FromClauseArgument],
- ) -> Self:
- """Apply correlation to the subquery noted by this
- :class:`_sql.Exists`.
- .. seealso::
- :meth:`_sql.ScalarSelect.correlate`
- """
- e = self._clone()
- e.element = self._regroup(
- lambda element: element.correlate(*fromclauses)
- )
- return e
- def correlate_except(
- self,
- *fromclauses: Union[Literal[None, False], _FromClauseArgument],
- ) -> Self:
- """Apply correlation to the subquery noted by this
- :class:`_sql.Exists`.
- .. seealso::
- :meth:`_sql.ScalarSelect.correlate_except`
- """
- e = self._clone()
- e.element = self._regroup(
- lambda element: element.correlate_except(*fromclauses)
- )
- return e
- def select_from(self, *froms: _FromClauseArgument) -> Self:
- """Return a new :class:`_expression.Exists` construct,
- applying the given
- expression to the :meth:`_expression.Select.select_from`
- method of the select
- statement contained.
- .. note:: it is typically preferable to build a :class:`_sql.Select`
- statement first, including the desired WHERE clause, then use the
- :meth:`_sql.SelectBase.exists` method to produce an
- :class:`_sql.Exists` object at once.
- """
- e = self._clone()
- e.element = self._regroup(lambda element: element.select_from(*froms))
- return e
- def where(self, *clause: _ColumnExpressionArgument[bool]) -> Self:
- """Return a new :func:`_expression.exists` construct with the
- given expression added to
- its WHERE clause, joined to the existing clause via AND, if any.
- .. note:: it is typically preferable to build a :class:`_sql.Select`
- statement first, including the desired WHERE clause, then use the
- :meth:`_sql.SelectBase.exists` method to produce an
- :class:`_sql.Exists` object at once.
- """
- e = self._clone()
- e.element = self._regroup(lambda element: element.where(*clause))
- return e
- class TextualSelect(SelectBase, ExecutableReturnsRows, Generative):
- """Wrap a :class:`_expression.TextClause` construct within a
- :class:`_expression.SelectBase`
- interface.
- This allows the :class:`_expression.TextClause` object to gain a
- ``.c`` collection
- and other FROM-like capabilities such as
- :meth:`_expression.FromClause.alias`,
- :meth:`_expression.SelectBase.cte`, etc.
- The :class:`_expression.TextualSelect` construct is produced via the
- :meth:`_expression.TextClause.columns`
- method - see that method for details.
- .. versionchanged:: 1.4 the :class:`_expression.TextualSelect`
- class was renamed
- from ``TextAsFrom``, to more correctly suit its role as a
- SELECT-oriented object and not a FROM clause.
- .. seealso::
- :func:`_expression.text`
- :meth:`_expression.TextClause.columns` - primary creation interface.
- """
- __visit_name__ = "textual_select"
- _label_style = LABEL_STYLE_NONE
- _traverse_internals: _TraverseInternalsType = (
- [
- ("element", InternalTraversal.dp_clauseelement),
- ("column_args", InternalTraversal.dp_clauseelement_list),
- ]
- + SupportsCloneAnnotations._clone_annotations_traverse_internals
- + HasCTE._has_ctes_traverse_internals
- )
- _is_textual = True
- is_text = True
- is_select = True
- def __init__(
- self,
- text: TextClause,
- columns: List[_ColumnExpressionArgument[Any]],
- positional: bool = False,
- ) -> None:
- self._init(
- text,
- # convert for ORM attributes->columns, etc
- [
- coercions.expect(roles.LabeledColumnExprRole, c)
- for c in columns
- ],
- positional,
- )
- def _init(
- self,
- text: TextClause,
- columns: List[NamedColumn[Any]],
- positional: bool = False,
- ) -> None:
- self.element = text
- self.column_args = columns
- self.positional = positional
- @HasMemoized_ro_memoized_attribute
- def selected_columns(
- self,
- ) -> ColumnCollection[str, KeyedColumnElement[Any]]:
- """A :class:`_expression.ColumnCollection`
- representing the columns that
- this SELECT statement or similar construct returns in its result set,
- not including :class:`_sql.TextClause` constructs.
- This collection differs from the :attr:`_expression.FromClause.columns`
- collection of a :class:`_expression.FromClause` in that the columns
- within this collection cannot be directly nested inside another SELECT
- statement; a subquery must be applied first which provides for the
- necessary parenthesization required by SQL.
- For a :class:`_expression.TextualSelect` construct, the collection
- contains the :class:`_expression.ColumnElement` objects that were
- passed to the constructor, typically via the
- :meth:`_expression.TextClause.columns` method.
- .. versionadded:: 1.4
- """
- return ColumnCollection(
- (c.key, c) for c in self.column_args
- ).as_readonly()
- @util.ro_non_memoized_property
- def _all_selected_columns(self) -> _SelectIterable:
- return self.column_args
- def set_label_style(self, style: SelectLabelStyle) -> TextualSelect:
- return self
- def _ensure_disambiguated_names(self) -> TextualSelect:
- return self
- @_generative
- def bindparams(
- self,
- *binds: BindParameter[Any],
- **bind_as_values: Any,
- ) -> Self:
- self.element = self.element.bindparams(*binds, **bind_as_values)
- return self
- def _generate_fromclause_column_proxies(
- self,
- fromclause: FromClause,
- columns: ColumnCollection[str, KeyedColumnElement[Any]],
- primary_key: ColumnSet,
- foreign_keys: Set[KeyedColumnElement[Any]],
- *,
- proxy_compound_columns: Optional[
- Iterable[Sequence[ColumnElement[Any]]]
- ] = None,
- ) -> None:
- if TYPE_CHECKING:
- assert isinstance(fromclause, Subquery)
- if proxy_compound_columns:
- columns._populate_separate_keys(
- c._make_proxy(
- fromclause,
- compound_select_cols=extra_cols,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- for c, extra_cols in zip(
- self.column_args, proxy_compound_columns
- )
- )
- else:
- columns._populate_separate_keys(
- c._make_proxy(
- fromclause,
- primary_key=primary_key,
- foreign_keys=foreign_keys,
- )
- for c in self.column_args
- )
- def _scalar_type(self) -> Union[TypeEngine[Any], Any]:
- return self.column_args[0].type
- TextAsFrom = TextualSelect
- """Backwards compatibility with the previous name"""
- class AnnotatedFromClause(Annotated):
- def _copy_internals(self, **kw: Any) -> None:
- super()._copy_internals(**kw)
- if kw.get("ind_cols_on_fromclause", False):
- ee = self._Annotated__element # type: ignore
- self.c = ee.__class__.c.fget(self) # type: ignore
- @util.ro_memoized_property
- def c(self) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
- """proxy the .c collection of the underlying FromClause.
- Originally implemented in 2008 as a simple load of the .c collection
- when the annotated construct was created (see d3621ae961a), in modern
- SQLAlchemy versions this can be expensive for statements constructed
- with ORM aliases. So for #8796 SQLAlchemy 2.0 we instead proxy
- it, which works just as well.
- Two different use cases seem to require the collection either copied
- from the underlying one, or unique to this AnnotatedFromClause.
- See test_selectable->test_annotated_corresponding_column
- """
- ee = self._Annotated__element # type: ignore
- return ee.c # type: ignore
|