12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887 |
- # sql/selectable.py
- # Copyright (C) 2005-2022 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.
- """
- import collections
- import itertools
- from operator import attrgetter
- from . import coercions
- from . import operators
- from . import roles
- from . import traversals
- from . import type_api
- from . import visitors
- 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 _expand_cloned
- from .base import _from_objects
- from .base import _generative
- 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 Executable
- from .base import Generative
- from .base import HasCompileState
- from .base import HasMemoized
- from .base import Immutable
- from .base import prefix_anon_map
- from .coercions import _document_text_coercion
- from .elements import _anonymous_label
- from .elements import and_
- from .elements import BindParameter
- from .elements import BooleanClauseList
- from .elements import ClauseElement
- from .elements import ClauseList
- from .elements import ColumnClause
- from .elements import GroupedElement
- from .elements import Grouping
- from .elements import literal_column
- from .elements import TableValuedColumn
- from .elements import UnaryExpression
- from .visitors import InternalTraversal
- from .. import exc
- from .. import util
- from ..inspection import inspect
- class _OffsetLimitParam(BindParameter):
- inherit_cache = True
- @property
- def _limit_offset_value(self):
- return self.effective_value
- @util.deprecated(
- "1.4",
- "The standalone :func:`.subquery` function is deprecated "
- "and will be removed in a future release. Use select().subquery().",
- )
- def subquery(alias, *args, **kwargs):
- r"""Return an :class:`.Subquery` object derived
- from a :class:`_expression.Select`.
- :param alias: the alias name for the subquery
- :param \*args, \**kwargs: all other arguments are passed through to the
- :func:`_expression.select` function.
- """
- return Select.create_legacy_select(*args, **kwargs).subquery(alias)
- class ReturnsRows(roles.ReturnsRowsRole, ClauseElement):
- """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_statement = False
- _is_lateral = False
- @property
- def selectable(self):
- return self
- @property
- def _all_selected_columns(self):
- """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()
- @property
- def exported_columns(self):
- """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 Selectable(ReturnsRows):
- """Mark a class as being selectable."""
- __visit_name__ = "selectable"
- is_selectable = True
- def _refresh_for_new_column(self, column):
- raise NotImplementedError()
- def lateral(self, name=None):
- """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.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- return Lateral._construct(self, 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, alias):
- """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, require_embedded=False):
- """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(object):
- _prefixes = ()
- _has_prefixes_traverse_internals = [
- ("_prefixes", InternalTraversal.dp_prefix_sequence)
- ]
- @_generative
- @_document_text_coercion(
- "expr",
- ":meth:`_expression.HasPrefixes.prefix_with`",
- ":paramref:`.HasPrefixes.prefix_with.*expr`",
- )
- def prefix_with(self, *expr, **kw):
- 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 \*expr: textual or :class:`_expression.ClauseElement`
- construct which
- will be rendered following the INSERT, UPDATE, or DELETE
- keyword.
- :param \**kw: A single keyword 'dialect' is accepted. This is an
- optional string dialect name which will
- limit rendering of this prefix to only that dialect.
- """
- dialect = kw.pop("dialect", None)
- if kw:
- raise exc.ArgumentError(
- "Unsupported argument(s): %s" % ",".join(kw)
- )
- self._setup_prefixes(expr, dialect)
- def _setup_prefixes(self, prefixes, dialect=None):
- self._prefixes = self._prefixes + tuple(
- [
- (coercions.expect(roles.StatementOptionRole, p), dialect)
- for p in prefixes
- ]
- )
- class HasSuffixes(object):
- _suffixes = ()
- _has_suffixes_traverse_internals = [
- ("_suffixes", InternalTraversal.dp_prefix_sequence)
- ]
- @_generative
- @_document_text_coercion(
- "expr",
- ":meth:`_expression.HasSuffixes.suffix_with`",
- ":paramref:`.HasSuffixes.suffix_with.*expr`",
- )
- def suffix_with(self, *expr, **kw):
- 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 \*expr: textual or :class:`_expression.ClauseElement`
- construct which
- will be rendered following the target clause.
- :param \**kw: A single keyword 'dialect' is accepted. This is an
- optional string dialect name which will
- limit rendering of this suffix to only that dialect.
- """
- dialect = kw.pop("dialect", None)
- if kw:
- raise exc.ArgumentError(
- "Unsupported argument(s): %s" % ",".join(kw)
- )
- self._setup_suffixes(expr, dialect)
- def _setup_suffixes(self, suffixes, dialect=None):
- self._suffixes = self._suffixes + tuple(
- [
- (coercions.expect(roles.StatementOptionRole, p), dialect)
- for p in suffixes
- ]
- )
- class HasHints(object):
- _hints = util.immutabledict()
- _statement_hints = ()
- _has_hints_traverse_internals = [
- ("_statement_hints", InternalTraversal.dp_statement_hint_list),
- ("_hints", InternalTraversal.dp_table_hint_list),
- ]
- def with_statement_hint(self, text, dialect_name="*"):
- """Add a statement hint to this :class:`_expression.Select` or
- other selectable object.
- 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.
- .. versionadded:: 1.0.0
- .. 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 optimizer hints
- """
- return self.with_hint(None, text, dialect_name)
- @_generative
- def with_hint(self, selectable, text, dialect_name="*"):
- r"""Add an indexing or other executional context hint for the given
- selectable to this :class:`_expression.Select` or other selectable
- object.
- 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, the
- following::
- select(mytable).\
- with_hint(mytable, "index(%(name)s ix_mytable)")
- Would render SQL as::
- 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
- and Sybase simultaneously::
- select(mytable).\
- with_hint(mytable, "index(%(name)s ix_mytable)", 'oracle').\
- with_hint(mytable, "WITH INDEX ix_mytable", 'sybase')
- .. seealso::
- :meth:`_expression.Select.with_statement_hint`
- """
- if selectable is None:
- self._statement_hints += ((dialect_name, text),)
- else:
- self._hints = self._hints.union(
- {
- (
- coercions.expect(roles.FromClauseRole, selectable),
- dialect_name,
- ): text
- }
- )
- 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
- _hide_froms = []
- schema = 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
- @util.deprecated_params(
- whereclause=(
- "2.0",
- "The :paramref:`_sql.FromClause.select().whereclause` parameter "
- "is deprecated and will be removed in version 2.0. "
- "Please make use of "
- "the :meth:`.Select.where` "
- "method to add WHERE criteria to the SELECT statement.",
- ),
- kwargs=(
- "2.0",
- "The :meth:`_sql.FromClause.select` method will no longer accept "
- "keyword arguments in version 2.0. Please use generative methods "
- "from the "
- ":class:`_sql.Select` construct in order to apply additional "
- "modifications.",
- ),
- )
- def select(self, whereclause=None, **kwargs):
- r"""Return a SELECT of this :class:`_expression.FromClause`.
- e.g.::
- stmt = some_table.select().where(some_table.c.id == 5)
- :param whereclause: a WHERE clause, equivalent to calling the
- :meth:`_sql.Select.where` method.
- :param \**kwargs: additional keyword arguments are passed to the
- legacy constructor for :class:`_sql.Select` described at
- :meth:`_sql.Select.create_legacy_select`.
- .. seealso::
- :func:`_expression.select` - general purpose
- method which allows for arbitrary column lists.
- """
- if whereclause is not None:
- kwargs["whereclause"] = whereclause
- return Select._create_select_from_fromclause(self, [self], **kwargs)
- def join(self, right, onclause=None, isouter=False, full=False):
- """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::
- 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`.
- .. versionadded:: 1.1
- .. 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, onclause=None, full=False):
- """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.
- .. versionadded:: 1.1
- .. seealso::
- :meth:`_expression.FromClause.join`
- :class:`_expression.Join`
- """
- return Join(self, right, onclause, True, full)
- def alias(self, name=None, flat=False):
- """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:`core_tutorial_aliases`
- :func:`_expression.alias`
- """
- return Alias._construct(self, name)
- @util.preload_module("sqlalchemy.sql.sqltypes")
- def table_valued(self):
- """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 and SQL Server.
- E.g.::
- >>> 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)
- 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)
- def tablesample(self, sampling, name=None, seed=None):
- """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.
- .. versionadded:: 1.1
- .. seealso::
- :func:`_expression.tablesample` - usage guidelines and parameters
- """
- return TableSample._construct(self, sampling, name, seed)
- def is_derived_from(self, fromclause):
- """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):
- """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 self._cloned_set.intersection(other._cloned_set)
- @property
- def description(self):
- """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._populate_separate_keys(
- col._make_proxy(fromclause) for col in self.c
- )
- @property
- def exported_columns(self):
- """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.columns
- @util.memoized_property
- def columns(self):
- """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.
- """
- if "_columns" not in self.__dict__:
- self._init_collections()
- self._populate_column_collection()
- return self._columns.as_immutable()
- @property
- def entity_namespace(self):
- """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.columns
- @util.memoized_property
- def primary_key(self):
- """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._init_collections()
- self._populate_column_collection()
- return self.primary_key
- @util.memoized_property
- def foreign_keys(self):
- """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._init_collections()
- self._populate_column_collection()
- return self.foreign_keys
- def _reset_column_collection(self):
- """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", "primary_key", "foreign_keys"]:
- self.__dict__.pop(key, None)
- c = property(
- attrgetter("columns"),
- doc="""
- A named-based collection of :class:`_expression.ColumnElement`
- objects maintained by this :class:`_expression.FromClause`.
- The :attr:`_sql.FromClause.c` attribute is an alias for the
- :attr:`_sql.FromClause.columns` attribute.
- :return: a :class:`.ColumnCollection`
- """,
- )
- _select_iterable = property(attrgetter("columns"))
- def _init_collections(self):
- assert "_columns" not in self.__dict__
- assert "primary_key" not in self.__dict__
- assert "foreign_keys" not in self.__dict__
- self._columns = ColumnCollection()
- self.primary_key = ColumnSet()
- self.foreign_keys = set()
- @property
- def _cols_populated(self):
- return "_columns" in self.__dict__
- def _populate_column_collection(self):
- """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):
- """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=None, flat=False):
- return self.alias(name=name)
- LABEL_STYLE_NONE = util.symbol(
- "LABEL_STYLE_NONE",
- """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::
- >>> 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))
- 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 = util.symbol(
- "LABEL_STYLE_TABLENAME_PLUS_COL",
- """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`::
- >>> 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))
- 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 = util.symbol(
- "LABEL_STYLE_DISAMBIGUATE_ONLY",
- """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``::
- >>> 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))
- 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
- """
- 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 = [
- ("left", InternalTraversal.dp_clauseelement),
- ("right", InternalTraversal.dp_clauseelement),
- ("onclause", InternalTraversal.dp_clauseelement),
- ("isouter", InternalTraversal.dp_boolean),
- ("full", InternalTraversal.dp_boolean),
- ]
- _is_join = True
- def __init__(self, left, right, onclause=None, isouter=False, full=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.
- """
- self.left = coercions.expect(
- roles.FromClauseRole, left, deannotate=True
- )
- self.right = coercions.expect(
- roles.FromClauseRole, right, deannotate=True
- ).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
- @classmethod
- def _create_outerjoin(cls, left, right, onclause=None, full=False):
- """Return an ``OUTER JOIN`` clause element.
- The returned object is an instance of :class:`_expression.Join`.
- Similar functionality is also available via the
- :meth:`_expression.FromClause.outerjoin` method on any
- :class:`_expression.FromClause`.
- :param left: The left side of the join.
- :param right: The right side of the join.
- :param onclause: Optional criterion for the ``ON`` clause, is
- derived from foreign key relationships established between
- left and right otherwise.
- To chain joins together, use the :meth:`_expression.FromClause.join`
- or
- :meth:`_expression.FromClause.outerjoin` methods on the resulting
- :class:`_expression.Join` object.
- """
- return cls(left, right, onclause, isouter=True, full=full)
- @classmethod
- def _create_join(
- cls, left, right, onclause=None, isouter=False, full=False
- ):
- """Produce a :class:`_expression.Join` object, given two
- :class:`_expression.FromClause`
- expressions.
- E.g.::
- j = join(user_table, 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::
- SELECT user.id, user.name FROM user
- JOIN address ON user.id = address.user_id
- Similar functionality is available given any
- :class:`_expression.FromClause` object (e.g. such as a
- :class:`_schema.Table`) using
- the :meth:`_expression.FromClause.join` method.
- :param left: The left side of the join.
- :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 JOIN.
- .. versionadded:: 1.1
- .. seealso::
- :meth:`_expression.FromClause.join` - method form,
- based on a given left side.
- :class:`_expression.Join` - the type of object produced.
- """
- return cls(left, right, onclause, isouter, full)
- @property
- def description(self):
- 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):
- 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=None):
- return FromGrouping(self)
- @util.preload_module("sqlalchemy.sql.util")
- def _populate_column_collection(self):
- sqlutil = util.preloaded.sql_util
- columns = [c for c in self.left.columns] + [
- c for c in self.right.columns
- ]
- self.primary_key.extend(
- sqlutil.reduce_columns(
- (c for c in columns if c.primary_key), self.onclause
- )
- )
- self._columns._populate_separate_keys(
- (col._tq_key_label, col) for col in columns
- )
- self.foreign_keys.update(
- itertools.chain(*[col.foreign_keys for col in columns])
- )
- def _copy_internals(self, clone=_clone, **kw):
- # 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, **kw):
- if isinstance(obj, ColumnClause) and obj.table in new_froms:
- newelem = new_froms[obj.table].corresponding_column(obj)
- return newelem
- kw["replace"] = replace
- # run normal _copy_internals. the clones for
- # left and right will come from the clone function's
- # cache
- super(Join, self)._copy_internals(clone=clone, **kw)
- self._reset_memoizations()
- def _refresh_for_new_column(self, column):
- super(Join, self)._refresh_for_new_column(column)
- self.left._refresh_for_new_column(column)
- self.right._refresh_for_new_column(column)
- def _match_primaries(self, left, right):
- 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, b, a_subset=None, consider_as_foreign_keys=None
- ):
- """Create a join condition between two tables or selectables.
- e.g.::
- join_condition(tablea, tableb)
- would produce an expression along the lines of::
- tablea.c.id==tableb.c.tablea_id
- The join is determined based on the foreign key relationships
- between the two selectables. If there are multiple ways
- to join, or no way to join, an error is raised.
- :param a_subset: An optional expression that is a sub-component
- of ``a``. An attempt will be made to join to just this sub-component
- first before looking at the full ``a`` construct, and if found
- will be successful even if there are other ways to join to ``a``.
- This allows the "right side" of a join to be passed thereby
- providing a "natural join".
- """
- 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, right, consider_as_foreign_keys=None):
- 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, a_subset, b, consider_as_foreign_keys
- ):
- sql_util = util.preloaded.sql_util
- a = coercions.expect(roles.FromClauseRole, a)
- b = coercions.expect(roles.FromClauseRole, b)
- constraints = 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, b, constraints, consider_as_foreign_keys
- ):
- # 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 set(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 = set(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)
- )
- @util.deprecated_params(
- whereclause=(
- "2.0",
- "The :paramref:`_sql.Join.select().whereclause` parameter "
- "is deprecated and will be removed in version 2.0. "
- "Please make use of "
- "the :meth:`.Select.where` "
- "method to add WHERE criteria to the SELECT statement.",
- ),
- kwargs=(
- "2.0",
- "The :meth:`_sql.Join.select` method will no longer accept "
- "keyword arguments in version 2.0. Please use generative "
- "methods from the "
- ":class:`_sql.Select` construct in order to apply additional "
- "modifications.",
- ),
- )
- def select(self, whereclause=None, **kwargs):
- 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::
- 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
- :param whereclause: WHERE criteria, same as calling
- :meth:`_sql.Select.where` on the resulting statement
- :param \**kwargs: additional keyword arguments are passed to the
- legacy constructor for :class:`_sql.Select` described at
- :meth:`_sql.Select.create_legacy_select`.
- """
- collist = [self.left, self.right]
- if whereclause is not None:
- kwargs["whereclause"] = whereclause
- return Select._create_select_from_fromclause(
- self, collist, **kwargs
- ).select_from(self)
- @property
- @util.deprecated_20(
- ":attr:`.Executable.bind`",
- alternative="Bound metadata is being removed as of SQLAlchemy 2.0.",
- enable_warnings=False,
- )
- def bind(self):
- """Return the bound engine associated with either the left or right
- side of this :class:`_sql.Join`.
- """
- return self.left.bind or self.right.bind
- @util.preload_module("sqlalchemy.sql.util")
- def _anonymous_fromclause(self, name=None, flat=False):
- sqlutil = util.preloaded.sql_util
- if flat:
- if name is not None:
- raise exc.ArgumentError("Can't send name argument with flat")
- left_a, right_a = (
- self.left._anonymous_fromclause(flat=True),
- self.right._anonymous_fromclause(flat=True),
- )
- 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.deprecated_20(
- ":meth:`_sql.Join.alias`",
- alternative="Create a select + subquery, or alias the "
- "individual tables inside the join, instead.",
- )
- def alias(self, name=None, flat=False):
- r"""Return an alias of this :class:`_expression.Join`.
- The default behavior here is to first produce a SELECT
- construct from this :class:`_expression.Join`, then to produce an
- :class:`_expression.Alias` from that. So given a join of the form::
- j = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
- The JOIN by itself would look like::
- table_a JOIN table_b ON table_a.id = table_b.a_id
- Whereas the alias of the above, ``j.alias()``, would in a
- SELECT context look like::
- (SELECT table_a.id AS table_a_id, table_b.id AS table_b_id,
- table_b.a_id AS table_b_a_id
- FROM table_a
- JOIN table_b ON table_a.id = table_b.a_id) AS anon_1
- The equivalent long-hand form, given a :class:`_expression.Join`
- object ``j``, is::
- from sqlalchemy import select, alias
- j = alias(
- select(j.left, j.right).\
- select_from(j).\
- set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL).\
- correlate(False),
- name=name
- )
- The selectable produced by :meth:`_expression.Join.alias`
- features the same
- columns as that of the two individual selectables presented under
- a single name - the individual columns are "auto-labeled", meaning
- the ``.c.`` collection of the resulting :class:`_expression.Alias`
- represents
- the names of the individual columns using a
- ``<tablename>_<columname>`` scheme::
- j.c.table_a_id
- j.c.table_b_a_id
- :meth:`_expression.Join.alias` also features an alternate
- option for aliasing joins which produces no enclosing SELECT and
- does not normally apply labels to the column names. The
- ``flat=True`` option will call :meth:`_expression.FromClause.alias`
- against the left and right sides individually.
- Using this option, no new ``SELECT`` is produced;
- we instead, from a construct as below::
- j = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
- j = j.alias(flat=True)
- we get a result like this::
- table_a AS table_a_1 JOIN table_b AS table_b_1 ON
- table_a_1.id = table_b_1.a_id
- The ``flat=True`` argument is also propagated to the contained
- selectables, so that a composite join such as::
- j = table_a.join(
- table_b.join(table_c,
- table_b.c.id == table_c.c.b_id),
- table_b.c.a_id == table_a.c.id
- ).alias(flat=True)
- Will produce an expression like::
- table_a AS table_a_1 JOIN (
- table_b AS table_b_1 JOIN table_c AS table_c_1
- ON table_b_1.id = table_c_1.b_id
- ) ON table_a_1.id = table_b_1.a_id
- The standalone :func:`_expression.alias` function as well as the
- base :meth:`_expression.FromClause.alias`
- method also support the ``flat=True``
- argument as a no-op, so that the argument can be passed to the
- ``alias()`` method of any selectable.
- :param name: name given to the alias.
- :param flat: if True, produce an alias of the left and right
- sides of this :class:`_expression.Join` and return the join of those
- two selectables. This produces join expression that does not
- include an enclosing SELECT.
- .. seealso::
- :ref:`core_tutorial_aliases`
- :func:`_expression.alias`
- """
- return self._anonymous_fromclause(flat=flat, name=name)
- @property
- def _hide_froms(self):
- return itertools.chain(
- *[_from_objects(x.left, x.right) for x in self._cloned_set]
- )
- @property
- def _from_objects(self):
- return [self] + self.left._from_objects + self.right._from_objects
- class NoInit(object):
- def __init__(self, *arg, **kw):
- 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(),
- )
- )
- # 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, FromClause):
- """Base class of aliases against tables, subqueries, and other
- selectables."""
- _is_from_container = True
- named_with_column = True
- _supports_derived_columns = False
- _traverse_internals = [
- ("element", InternalTraversal.dp_clauseelement),
- ("name", InternalTraversal.dp_anon_name),
- ]
- @classmethod
- def _construct(cls, *arg, **kw):
- obj = cls.__new__(cls)
- obj._init(*arg, **kw)
- return obj
- @classmethod
- def _factory(cls, returnsrows, name=None):
- """Base factory method. Subclasses need to provide this."""
- raise NotImplementedError()
- def _init(self, selectable, name=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):
- super(AliasedReturnsRows, self)._refresh_for_new_column(column)
- self.element._refresh_for_new_column(column)
- @property
- def description(self):
- name = self.name
- if isinstance(name, _anonymous_label):
- name = "anon_1"
- if util.py3k:
- return name
- else:
- return name.encode("ascii", "backslashreplace")
- @property
- def original(self):
- """Legacy for dialects that are referring to Alias.original."""
- return self.element
- def is_derived_from(self, fromclause):
- if fromclause in self._cloned_set:
- return True
- return self.element.is_derived_from(fromclause)
- def _populate_column_collection(self):
- self.element._generate_fromclause_column_proxies(self)
- def _copy_internals(self, clone=_clone, **kw):
- existing_element = self.element
- super(AliasedReturnsRows, self)._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):
- return [self]
- @property
- def bind(self):
- return self.element.bind
- class Alias(roles.DMLTableRole, AliasedReturnsRows):
- """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).
- 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
- @classmethod
- def _factory(cls, selectable, name=None, flat=False):
- """Return an :class:`_expression.Alias` object.
- An :class:`_expression.Alias` represents any
- :class:`_expression.FromClause`
- with an alternate name assigned within SQL, typically using the ``AS``
- clause when generated, e.g. ``SELECT * FROM table AS aliasname``.
- Similar functionality is available via the
- :meth:`_expression.FromClause.alias`
- method available on all :class:`_expression.FromClause` subclasses.
- In terms of
- a SELECT object as generated from the :func:`_expression.select`
- function, the :meth:`_expression.SelectBase.alias` method returns an
- :class:`_expression.Alias` or similar object which represents a named,
- parenthesized subquery.
- When an :class:`_expression.Alias` is created from a
- :class:`_schema.Table` object,
- this has the effect of the table being rendered
- as ``tablename AS aliasname`` in a SELECT statement.
- For :func:`_expression.select` objects, the effect is that of
- creating a named subquery, i.e. ``(select ...) AS aliasname``.
- The ``name`` parameter is optional, and provides the name
- to use in the rendered SQL. If blank, an "anonymous" name
- will be deterministically generated at compile time.
- Deterministic means the name is guaranteed to be unique against
- other constructs used in the same statement, and will also be the
- same name for each successive compilation of the same statement
- object.
- :param selectable: any :class:`_expression.FromClause` subclass,
- such as a table, select statement, etc.
- :param name: string name to be assigned as the alias.
- If ``None``, a name will be deterministically generated
- at compile time.
- :param flat: Will be passed through to if the given selectable
- is an instance of :class:`_expression.Join` - see
- :meth:`_expression.Join.alias`
- for details.
- """
- return coercions.expect(
- roles.FromClauseRole, selectable, allow_select=True
- ).alias(name=name, flat=flat)
- class TableValuedAlias(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.::
- >>> from sqlalchemy import select, func
- >>> fn = func.json_array_elements_text('["one", "two", "three"]').table_valued("value")
- >>> print(select(fn.c.value))
- 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
- _traverse_internals = [
- ("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, name=None, table_value_type=None):
- super(TableValuedAlias, self)._init(selectable, name=name)
- self._tableval_type = (
- type_api.TABLEVALUE
- if table_value_type is None
- else table_value_type
- )
- @HasMemoized.memoized_attribute
- def column(self):
- """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.::
- >>> print(select(func.some_func().table_valued("value").column))
- 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=None):
- """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._construct(self, name=name)
- if self._render_derived:
- tva._render_derived = True
- tva._render_derived_w_types = self._render_derived_w_types
- return tva
- def lateral(self, name=None):
- """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=None, with_types=False):
- """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.::
- >>> print(
- ... select(
- ... func.unnest(array(["one", "two", "three"])).
- table_valued("x", with_ordinality="o").render_derived()
- ... )
- ... )
- 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)::
- >>> 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)
- ... )
- ... )
- 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)
- new_alias = TableValuedAlias._construct(self, name=name)
- new_alias._render_derived = True
- new_alias._render_derived_w_types = with_types
- return new_alias
- class Lateral(AliasedReturnsRows):
- """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.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- __visit_name__ = "lateral"
- _is_lateral = True
- inherit_cache = True
- @classmethod
- def _factory(cls, selectable, name=None):
- """Return a :class:`_expression.Lateral` object.
- :class:`_expression.Lateral` is an :class:`_expression.Alias`
- subclass that represents
- a subquery with the LATERAL keyword applied to it.
- The special behavior of a LATERAL subquery is that it appears in the
- FROM clause of an enclosing SELECT, but may correlate to other
- FROM clauses of that SELECT. It is a special case of subquery
- only supported by a small number of backends, currently more recent
- PostgreSQL versions.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- return coercions.expect(
- roles.FromClauseRole, selectable, explicit_subquery=True
- ).lateral(name=name)
- class TableSample(AliasedReturnsRows):
- """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.
- .. versionadded:: 1.1
- .. seealso::
- :func:`_expression.tablesample`
- """
- __visit_name__ = "tablesample"
- _traverse_internals = AliasedReturnsRows._traverse_internals + [
- ("sampling", InternalTraversal.dp_clauseelement),
- ("seed", InternalTraversal.dp_clauseelement),
- ]
- @classmethod
- def _factory(cls, selectable, sampling, name=None, seed=None):
- """Return a :class:`_expression.TableSample` object.
- :class:`_expression.TableSample` is an :class:`_expression.Alias`
- subclass that represents
- a table with the TABLESAMPLE clause applied to it.
- :func:`_expression.tablesample`
- is also available from the :class:`_expression.FromClause`
- class via the
- :meth:`_expression.FromClause.tablesample` method.
- The TABLESAMPLE clause allows selecting a randomly selected approximate
- percentage of rows from a table. It supports multiple sampling methods,
- most commonly BERNOULLI and SYSTEM.
- e.g.::
- from sqlalchemy import func
- selectable = people.tablesample(
- func.bernoulli(1),
- name='alias',
- seed=func.random())
- stmt = select(selectable.c.people_id)
- Assuming ``people`` with a column ``people_id``, the above
- statement would render as::
- SELECT alias.people_id FROM
- people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
- REPEATABLE (random())
- .. versionadded:: 1.1
- :param sampling: a ``float`` percentage between 0 and 100 or
- :class:`_functions.Function`.
- :param name: optional alias name
- :param seed: any real-valued SQL expression. When specified, the
- REPEATABLE sub-clause is also rendered.
- """
- return coercions.expect(roles.FromClauseRole, selectable).tablesample(
- sampling, name=name, seed=seed
- )
- @util.preload_module("sqlalchemy.sql.functions")
- def _init(self, selectable, sampling, name=None, seed=None):
- functions = util.preloaded.sql_functions
- if not isinstance(sampling, functions.Function):
- sampling = functions.func.system(sampling)
- self.sampling = sampling
- self.seed = seed
- super(TableSample, self)._init(selectable, name=name)
- def _get_method(self):
- 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 = (
- 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
- )
- @classmethod
- def _factory(cls, selectable, name=None, recursive=False):
- 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,
- name=None,
- recursive=False,
- nesting=False,
- _cte_alias=None,
- _restates=None,
- _prefixes=None,
- _suffixes=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(CTE, self)._init(selectable, name=name)
- def _populate_column_collection(self):
- if self._cte_alias is not None:
- self._cte_alias._generate_fromclause_column_proxies(self)
- else:
- self.element._generate_fromclause_column_proxies(self)
- def alias(self, name=None, flat=False):
- """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:`core_tutorial_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):
- 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
- """
- 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):
- 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
- """
- 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):
- """
- 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 HasCTE(roles.HasCTERole):
- """Mixin that declares a class to include CTE support.
- .. versionadded:: 1.1
- """
- _has_ctes_traverse_internals = [
- ("_independent_ctes", InternalTraversal.dp_clauseelement_list),
- ]
- _independent_ctes = ()
- @_generative
- def add_cte(self, cte):
- """Add a :class:`_sql.CTE` to this statement object that will be
- independently rendered even if not referenced in the statement
- otherwise.
- This feature is useful for 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; while PostgreSQL is known
- to support this usage, it may not be supported by other backends.
- 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::
- 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 referred towards 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::
- 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
- """
- cte = coercions.expect(roles.IsCTERole, cte)
- self._independent_ctes += (cte,)
- def cte(self, name=None, recursive=False, nesting=False):
- 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.
- .. versionchanged:: 1.1 Added support for UPDATE/INSERT/DELETE as
- CTE, CTEs added to UPDATE/INSERT/DELETE.
- 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
- actual statement.
- .. versionadded:: 1.4.24
- 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::
- 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
- 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::
- 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`.
- """
- 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
- @classmethod
- def _factory(cls, selectable, name=None):
- """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):
- return self.element.set_label_style(LABEL_STYLE_NONE).scalar_subquery()
- def _execute_on_connection(
- self,
- connection,
- multiparams,
- params,
- execution_options,
- ):
- util.warn_deprecated(
- "Executing a subquery object is deprecated and will raise "
- "ObjectNotExecutableError in an upcoming release. Please "
- "execute the underlying select() statement directly.",
- "1.4",
- )
- return self.element._execute_on_connection(
- connection, multiparams, params, execution_options, _force=True
- )
- class FromGrouping(GroupedElement, FromClause):
- """Represent a grouping of a FROM clause"""
- _traverse_internals = [("element", InternalTraversal.dp_clauseelement)]
- def __init__(self, element):
- self.element = coercions.expect(roles.FromClauseRole, element)
- def _init_collections(self):
- pass
- @property
- def columns(self):
- return self.element.columns
- @property
- def primary_key(self):
- return self.element.primary_key
- @property
- def foreign_keys(self):
- return self.element.foreign_keys
- def is_derived_from(self, element):
- return self.element.is_derived_from(element)
- def alias(self, **kw):
- return FromGrouping(self.element.alias(**kw))
- def _anonymous_fromclause(self, **kw):
- return FromGrouping(self.element._anonymous_fromclause(**kw))
- @property
- def _hide_froms(self):
- return self.element._hide_froms
- @property
- def _from_objects(self):
- return self.element._from_objects
- def __getstate__(self):
- return {"element": self.element}
- def __setstate__(self, state):
- self.element = state["element"]
- class TableClause(roles.DMLTableRole, Immutable, FromClause):
- """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 = [
- (
- "columns",
- InternalTraversal.dp_fromclause_canonical_column_collection,
- ),
- ("name", InternalTraversal.dp_string),
- ]
- named_with_column = True
- implicit_returning = False
- """:class:`_expression.TableClause`
- doesn't support having a primary key or column
- -level defaults, so implicit returning doesn't apply."""
- _autoincrement_column = None
- """No PK or default support so no autoincrement column."""
- def __init__(self, name, *columns, **kw):
- """Produce a new :class:`_expression.TableClause`.
- The object returned is an instance of
- :class:`_expression.TableClause`, which
- represents the "syntactical" portion of the schema-level
- :class:`_schema.Table` object.
- It may be used to construct lightweight table constructs.
- .. versionchanged:: 1.0.0 :func:`_expression.table` can now
- be imported from the plain ``sqlalchemy`` namespace like any
- other SQL element.
- :param name: Name of the table.
- :param columns: A collection of :func:`_expression.column` constructs.
- :param schema: The schema name for this table.
- .. versionadded:: 1.3.18 :func:`_expression.table` can now
- accept a ``schema`` argument.
- """
- super(TableClause, self).__init__()
- self.name = name
- self._columns = DedupeColumnCollection()
- self.primary_key = ColumnSet()
- self.foreign_keys = set()
- 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))
- def __str__(self):
- if self.schema is not None:
- return self.schema + "." + self.name
- else:
- return self.name
- def _refresh_for_new_column(self, column):
- pass
- def _init_collections(self):
- pass
- @util.memoized_property
- def description(self):
- if util.py3k:
- return self.name
- else:
- return self.name.encode("ascii", "backslashreplace")
- def append_column(self, c, **kw):
- 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, values=None, inline=False, **kwargs):
- """Generate an :func:`_expression.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, values=values, inline=inline, **kwargs
- )
- @util.preload_module("sqlalchemy.sql.dml")
- def update(self, whereclause=None, values=None, inline=False, **kwargs):
- """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,
- whereclause=whereclause,
- values=values,
- inline=inline,
- **kwargs
- )
- @util.preload_module("sqlalchemy.sql.dml")
- def delete(self, whereclause=None, **kwargs):
- """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, whereclause, **kwargs)
- @property
- def _from_objects(self):
- return [self]
- class ForUpdateArg(ClauseElement):
- _traverse_internals = [
- ("of", InternalTraversal.dp_clauseelement_list),
- ("nowait", InternalTraversal.dp_boolean),
- ("read", InternalTraversal.dp_boolean),
- ("skip_locked", InternalTraversal.dp_boolean),
- ]
- @classmethod
- def _from_argument(cls, with_for_update):
- 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(**with_for_update)
- def __eq__(self, other):
- 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):
- return not self.__eq__(other)
- def __hash__(self):
- return id(self)
- def __init__(
- self,
- nowait=False,
- read=False,
- of=None,
- skip_locked=False,
- key_share=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(Generative, FromClause):
- """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
- """
- named_with_column = True
- __visit_name__ = "values"
- _data = ()
- _traverse_internals = [
- ("_column_args", InternalTraversal.dp_clauseelement_list),
- ("_data", InternalTraversal.dp_dml_multi_values),
- ("name", InternalTraversal.dp_string),
- ("literal_binds", InternalTraversal.dp_boolean),
- ]
- def __init__(self, *columns, **kw):
- r"""Construct a :class:`_expression.Values` construct.
- The column expressions and the actual data for
- :class:`_expression.Values` are given in two separate steps. The
- constructor receives the column expressions typically as
- :func:`_expression.column` constructs,
- and the data is then passed via the
- :meth:`_expression.Values.data` method as a list,
- which can be called multiple
- times to add more data, e.g.::
- from sqlalchemy import column
- from sqlalchemy import values
- value_expr = values(
- column('id', Integer),
- column('name', String),
- name="my_values"
- ).data(
- [(1, 'name1'), (2, 'name2'), (3, 'name3')]
- )
- :param \*columns: column expressions, typically composed using
- :func:`_expression.column` objects.
- :param name: the name for this VALUES construct. If omitted, the
- VALUES construct will be unnamed in a SQL expression. Different
- backends may have different requirements here.
- :param literal_binds: Defaults to False. Whether or not to render
- the data values inline in the SQL output, rather than using bound
- parameters.
- """
- super(Values, self).__init__()
- self._column_args = columns
- self.name = kw.pop("name", None)
- self.literal_binds = kw.pop("literal_binds", False)
- self.named_with_column = self.name is not None
- @property
- def _column_types(self):
- return [col.type for col in self._column_args]
- @_generative
- def alias(self, name, **kw):
- """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:`core_tutorial_aliases`
- :func:`_expression.alias`
- """
- self.name = name
- self.named_with_column = self.name is not None
- @_generative
- def lateral(self, name=None):
- """Return a new :class:`_expression.Values` with the lateral flag set,
- so that
- it renders as LATERAL.
- .. seealso::
- :func:`_expression.lateral`
- """
- self._is_lateral = True
- if name is not None:
- self.name = name
- @_generative
- def data(self, values):
- """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,)
- def _populate_column_collection(self):
- for c in self._column_args:
- self._columns.add(c)
- c.table = self
- @property
- def _from_objects(self):
- return [self]
- class SelectBase(
- roles.SelectStatementRole,
- roles.DMLSelectRole,
- roles.CompoundElementRole,
- roles.InElementRole,
- HasCTE,
- Executable,
- SupportsCloneAnnotations,
- Selectable,
- ):
- """Base class for SELECT statements.
- This includes :class:`_expression.Select`,
- :class:`_expression.CompoundSelect` and
- :class:`_expression.TextualSelect`.
- """
- _is_select_statement = True
- is_select = True
- def _generate_fromclause_column_proxies(self, fromclause):
- raise NotImplementedError()
- def _refresh_for_new_column(self, column):
- self._reset_memoizations()
- @property
- def selected_columns(self):
- """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()
- @property
- def _all_selected_columns(self):
- """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):
- """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
- @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):
- return self._implicit_subquery.columns
- @property
- def columns(self):
- return self.c
- @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, **kw):
- return self._implicit_subquery.select(*arg, **kw)
- @HasMemoized.memoized_attribute
- def _implicit_subquery(self):
- return self.subquery()
- @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):
- return self.scalar_subquery()
- def exists(self):
- """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):
- """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
- :ref:`scalar_selects` - in the 1.x 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):
- """Return a 'scalar' representation of this selectable, embedded as a
- subquery with a label.
- .. seealso::
- :meth:`_expression.SelectBase.as_scalar`.
- """
- return self.scalar_subquery().label(name)
- def lateral(self, name=None):
- """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.
- .. versionadded:: 1.1
- .. seealso::
- :ref:`lateral_selects` - overview of usage.
- """
- return Lateral._factory(self, name)
- @property
- def _from_objects(self):
- return [self]
- def subquery(self, name=None):
- """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::
- 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::
- 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)
- def _ensure_disambiguated_names(self):
- """Ensure that the names generated by this selectbase will be
- disambiguated in some way, if possible.
- """
- raise NotImplementedError()
- def alias(self, name=None, flat=False):
- """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)
- class SelectStatementGrouping(GroupedElement, SelectBase):
- """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 = [("element", InternalTraversal.dp_clauseelement)]
- _is_select_container = True
- def __init__(self, element):
- self.element = coercions.expect(roles.SelectStatementRole, element)
- def _ensure_disambiguated_names(self):
- 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):
- return self._label_style
- def set_label_style(self, label_style):
- return SelectStatementGrouping(
- self.element.set_label_style(label_style)
- )
- @property
- def _label_style(self):
- return self.element._label_style
- @property
- def select_statement(self):
- return self.element
- def self_group(self, against=None):
- return self
- def _generate_columns_plus_names(self, anon_for_dupe_key):
- return self.element._generate_columns_plus_names(anon_for_dupe_key)
- def _generate_fromclause_column_proxies(self, subquery):
- self.element._generate_fromclause_column_proxies(subquery)
- def _generate_proxy_for_new_column(self, column, subquery):
- return self.element._generate_proxy_for_new_column(subquery)
- @property
- def _all_selected_columns(self):
- return self.element._all_selected_columns
- @property
- def selected_columns(self):
- """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
- @property
- def _from_objects(self):
- return self.element._from_objects
- class DeprecatedSelectBaseGenerations(object):
- """A collection of methods available on :class:`_sql.Select` and
- :class:`_sql.CompoundSelect`, these are all **deprecated** methods as they
- modify the object in-place.
- """
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.GenerativeSelect.append_order_by` "
- "method is deprecated "
- "and will be removed in a future release. Use the generative method "
- ":meth:`_expression.GenerativeSelect.order_by`.",
- )
- def append_order_by(self, *clauses):
- """Append the given ORDER BY criterion applied to this selectable.
- The criterion will be appended to any pre-existing ORDER BY criterion.
- This is an **in-place** mutation method; the
- :meth:`_expression.GenerativeSelect.order_by` method is preferred,
- as it
- provides standard :term:`method chaining`.
- .. seealso::
- :meth:`_expression.GenerativeSelect.order_by`
- """
- self.order_by.non_generative(self, *clauses)
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.GenerativeSelect.append_group_by` "
- "method is deprecated "
- "and will be removed in a future release. Use the generative method "
- ":meth:`_expression.GenerativeSelect.group_by`.",
- )
- def append_group_by(self, *clauses):
- """Append the given GROUP BY criterion applied to this selectable.
- The criterion will be appended to any pre-existing GROUP BY criterion.
- This is an **in-place** mutation method; the
- :meth:`_expression.GenerativeSelect.group_by` method is preferred,
- as it
- provides standard :term:`method chaining`.
- """
- self.group_by.non_generative(self, *clauses)
- class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase):
- """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 = ()
- _group_by_clauses = ()
- _limit_clause = None
- _offset_clause = None
- _fetch_clause = None
- _fetch_clause_options = None
- _for_update_arg = None
- @util.deprecated_params(
- bind=(
- "2.0",
- "The :paramref:`_sql.select.bind` argument is deprecated and "
- "will be removed in SQLAlchemy 2.0.",
- ),
- )
- def __init__(
- self,
- _label_style=LABEL_STYLE_DEFAULT,
- use_labels=False,
- limit=None,
- offset=None,
- order_by=None,
- group_by=None,
- bind=None,
- ):
- if use_labels:
- if util.SQLALCHEMY_WARN_20:
- util.warn_deprecated_20(
- "The use_labels=True keyword argument to GenerativeSelect "
- "is deprecated and will be removed in version 2.0. Please "
- "use "
- "select.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) "
- "if you need to replicate this legacy behavior.",
- stacklevel=4,
- )
- _label_style = LABEL_STYLE_TABLENAME_PLUS_COL
- self._label_style = _label_style
- if limit is not None:
- self.limit.non_generative(self, limit)
- if offset is not None:
- self.offset.non_generative(self, offset)
- if order_by is not None:
- self.order_by.non_generative(self, *util.to_list(order_by))
- if group_by is not None:
- self.group_by.non_generative(self, *util.to_list(group_by))
- self._bind = bind
- @_generative
- def with_for_update(
- self,
- nowait=False,
- read=False,
- of=None,
- skip_locked=False,
- key_share=False,
- ):
- """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, the above would render a
- statement like::
- SELECT table.a, table.b FROM table FOR UPDATE NOWAIT
- on other backends, the ``nowait`` option is ignored and instead
- would produce::
- 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
- 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) which
- will render into a ``FOR UPDATE OF`` clause; supported by PostgreSQL
- and Oracle. May render as a table or as a column depending on
- backend.
- :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED``
- on Oracle 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,
- )
- def get_label_style(self):
- """
- Retrieve the current label style.
- .. versionadded:: 1.4
- """
- return self._label_style
- def set_label_style(self, style):
- """Return a new selectable with the specified label style.
- There are three "label styles" available,
- :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`,
- :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`, and
- :data:`_sql.LABEL_STYLE_NONE`. The default style is
- :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`.
- 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
- @util.deprecated_20(
- ":meth:`_sql.GenerativeSelect.apply_labels`",
- alternative="Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) "
- "instead.",
- )
- def apply_labels(self):
- return self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
- @property
- def _group_by_clause(self):
- """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 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, name=None, type_=None):
- """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_
- )
- def _offset_or_limit_clause_asint(self, clause, attrname):
- """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:
- util.raise_(
- exc.CompileError(
- "This SELECT structure does not use a simple "
- "integer value for %s" % attrname
- ),
- replace_context=err,
- )
- else:
- return util.asint(value)
- @property
- def _limit(self):
- """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):
- """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):
- """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):
- 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):
- """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`.
- .. versionchanged:: 1.0.0 - :meth:`_expression.Select.limit` can now
- accept arbitrary SQL expressions as well as integer values.
- :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)
- @_generative
- def fetch(self, count, with_ties=False, percent=False):
- """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, 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``
- .. seealso::
- :meth:`_sql.GenerativeSelect.limit`
- :meth:`_sql.GenerativeSelect.offset`
- """
- 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,
- }
- @_generative
- def offset(self, offset):
- """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.
- .. versionchanged:: 1.0.0 - :meth:`_expression.Select.offset` can now
- accept arbitrary SQL expressions as well as integer values.
- :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)
- @_generative
- @util.preload_module("sqlalchemy.sql.util")
- def slice(self, start, stop):
- """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
- )
- @_generative
- def order_by(self, *clauses):
- 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)
- All existing ORDER BY criteria may be cancelled by passing
- ``None`` by itself. New ORDER BY criteria may then be added by
- invoking :meth:`_sql.Select.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 len(clauses) == 1 and clauses[0] is None:
- self._order_by_clauses = ()
- else:
- self._order_by_clauses += tuple(
- coercions.expect(roles.OrderByRole, clause)
- for clause in clauses
- )
- @_generative
- def group_by(self, *clauses):
- 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`
- """
- if len(clauses) == 1 and clauses[0] is None:
- self._group_by_clauses = ()
- else:
- self._group_by_clauses += tuple(
- coercions.expect(roles.GroupByRole, clause)
- for clause in clauses
- )
- @CompileState.plugin_for("default", "compound_select")
- class CompoundSelectState(CompileState):
- @util.memoized_property
- def _label_resolve_dict(self):
- # TODO: this is hacky and slow
- hacky_subquery = self.statement.subquery()
- hacky_subquery.named_with_column = False
- d = dict((c.key, c) for c in hacky_subquery.c)
- return d, d, d
- class CompoundSelect(HasCompileState, GenerativeSelect):
- """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 = [
- ("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
- UNION = util.symbol("UNION")
- UNION_ALL = util.symbol("UNION ALL")
- EXCEPT = util.symbol("EXCEPT")
- EXCEPT_ALL = util.symbol("EXCEPT ALL")
- INTERSECT = util.symbol("INTERSECT")
- INTERSECT_ALL = util.symbol("INTERSECT ALL")
- _is_from_container = True
- def __init__(self, keyword, *selects, **kwargs):
- self._auto_correlate = kwargs.pop("correlate", False)
- self.keyword = keyword
- self.selects = [
- coercions.expect(roles.CompoundElementRole, s).self_group(
- against=self
- )
- for s in selects
- ]
- if kwargs and util.SQLALCHEMY_WARN_20:
- util.warn_deprecated_20(
- "Set functions such as union(), union_all(), extract(), etc. "
- "in SQLAlchemy 2.0 will accept a "
- "series of SELECT statements only. "
- "Please use generative methods such as order_by() for "
- "additional modifications to this CompoundSelect.",
- stacklevel=4,
- )
- GenerativeSelect.__init__(self, **kwargs)
- @classmethod
- def _create_union(cls, *selects, **kwargs):
- r"""Return a ``UNION`` of multiple selectables.
- The returned object is an instance of
- :class:`_expression.CompoundSelect`.
- A similar :func:`union()` method is available on all
- :class:`_expression.FromClause` subclasses.
- :param \*selects:
- a list of :class:`_expression.Select` instances.
- :param \**kwargs:
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.UNION, *selects, **kwargs)
- @classmethod
- def _create_union_all(cls, *selects, **kwargs):
- r"""Return a ``UNION ALL`` of multiple selectables.
- The returned object is an instance of
- :class:`_expression.CompoundSelect`.
- A similar :func:`union_all()` method is available on all
- :class:`_expression.FromClause` subclasses.
- :param \*selects:
- a list of :class:`_expression.Select` instances.
- :param \**kwargs:
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.UNION_ALL, *selects, **kwargs)
- @classmethod
- def _create_except(cls, *selects, **kwargs):
- r"""Return an ``EXCEPT`` of multiple selectables.
- The returned object is an instance of
- :class:`_expression.CompoundSelect`.
- :param \*selects:
- a list of :class:`_expression.Select` instances.
- :param \**kwargs:
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.EXCEPT, *selects, **kwargs)
- @classmethod
- def _create_except_all(cls, *selects, **kwargs):
- r"""Return an ``EXCEPT ALL`` of multiple selectables.
- The returned object is an instance of
- :class:`_expression.CompoundSelect`.
- :param \*selects:
- a list of :class:`_expression.Select` instances.
- :param \**kwargs:
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.EXCEPT_ALL, *selects, **kwargs)
- @classmethod
- def _create_intersect(cls, *selects, **kwargs):
- r"""Return an ``INTERSECT`` of multiple selectables.
- The returned object is an instance of
- :class:`_expression.CompoundSelect`.
- :param \*selects:
- a list of :class:`_expression.Select` instances.
- :param \**kwargs:
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.INTERSECT, *selects, **kwargs)
- @classmethod
- def _create_intersect_all(cls, *selects, **kwargs):
- r"""Return an ``INTERSECT ALL`` of multiple selectables.
- The returned object is an instance of
- :class:`_expression.CompoundSelect`.
- :param \*selects:
- a list of :class:`_expression.Select` instances.
- :param \**kwargs:
- available keyword arguments are the same as those of
- :func:`select`.
- """
- return CompoundSelect(CompoundSelect.INTERSECT_ALL, *selects, **kwargs)
- def _scalar_type(self):
- return self.selects[0]._scalar_type()
- def self_group(self, against=None):
- return SelectStatementGrouping(self)
- def is_derived_from(self, fromclause):
- for s in self.selects:
- if s.is_derived_from(fromclause):
- return True
- return False
- def _set_label_style(self, style):
- 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):
- 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):
- # 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. We may want to improve upon this, such as
- # perhaps _make_proxy can accept a list of other columns
- # that are "shared" - schema.column can then copy all the
- # ForeignKeys in. this would allow the union() to have all
- # those fks too.
- select_0 = self.selects[0]
- if self._label_style is not LABEL_STYLE_DEFAULT:
- select_0 = select_0.set_label_style(self._label_style)
- select_0._generate_fromclause_column_proxies(subquery)
- # 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
- for subq_col, select_cols in zip(
- subquery.c._all_columns,
- zip(*[s.selected_columns for s in self.selects]),
- ):
- subq_col._proxies = [
- c._annotate({"weight": i + 1})
- for (i, c) in enumerate(select_cols)
- ]
- def _refresh_for_new_column(self, column):
- super(CompoundSelect, self)._refresh_for_new_column(column)
- for select in self.selects:
- select._refresh_for_new_column(column)
- @property
- def _all_selected_columns(self):
- return self.selects[0]._all_selected_columns
- @property
- def selected_columns(self):
- """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
- @property
- @util.deprecated_20(
- ":attr:`.Executable.bind`",
- alternative="Bound metadata is being removed as of SQLAlchemy 2.0.",
- enable_warnings=False,
- )
- def bind(self):
- """Returns the :class:`_engine.Engine` or :class:`_engine.Connection`
- to which this :class:`.Executable` is bound, or None if none found.
- """
- if self._bind:
- return self._bind
- for s in self.selects:
- e = s.bind
- if e:
- return e
- else:
- return None
- @bind.setter
- def bind(self, bind):
- self._bind = bind
- class DeprecatedSelectGenerations(object):
- """A collection of methods available on :class:`_sql.Select`, these
- are all **deprecated** methods as they modify the :class:`_sql.Select`
- object in -place.
- """
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.append_correlation` "
- "method is deprecated "
- "and will be removed in a future release. Use the generative "
- "method :meth:`_expression.Select.correlate`.",
- )
- def append_correlation(self, fromclause):
- """Append the given correlation expression to this select()
- construct.
- This is an **in-place** mutation method; the
- :meth:`_expression.Select.correlate` method is preferred,
- as it provides
- standard :term:`method chaining`.
- """
- self.correlate.non_generative(self, fromclause)
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.append_column` method is deprecated "
- "and will be removed in a future release. Use the generative "
- "method :meth:`_expression.Select.add_columns`.",
- )
- def append_column(self, column):
- """Append the given column expression to the columns clause of this
- select() construct.
- E.g.::
- my_select.append_column(some_table.c.new_column)
- This is an **in-place** mutation method; the
- :meth:`_expression.Select.add_columns` method is preferred,
- as it provides standard
- :term:`method chaining`.
- """
- self.add_columns.non_generative(self, column)
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.append_prefix` method is deprecated "
- "and will be removed in a future release. Use the generative "
- "method :meth:`_expression.Select.prefix_with`.",
- )
- def append_prefix(self, clause):
- """Append the given columns clause prefix expression to this select()
- construct.
- This is an **in-place** mutation method; the
- :meth:`_expression.Select.prefix_with` method is preferred,
- as it provides
- standard :term:`method chaining`.
- """
- self.prefix_with.non_generative(self, clause)
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.append_whereclause` "
- "method is deprecated "
- "and will be removed in a future release. Use the generative "
- "method :meth:`_expression.Select.where`.",
- )
- def append_whereclause(self, whereclause):
- """Append the given expression to this select() construct's WHERE
- criterion.
- The expression will be joined to existing WHERE criterion via AND.
- This is an **in-place** mutation method; the
- :meth:`_expression.Select.where` method is preferred,
- as it provides standard
- :term:`method chaining`.
- """
- self.where.non_generative(self, whereclause)
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.append_having` method is deprecated "
- "and will be removed in a future release. Use the generative "
- "method :meth:`_expression.Select.having`.",
- )
- def append_having(self, having):
- """Append the given expression to this select() construct's HAVING
- criterion.
- The expression will be joined to existing HAVING criterion via AND.
- This is an **in-place** mutation method; the
- :meth:`_expression.Select.having` method is preferred,
- as it provides standard
- :term:`method chaining`.
- """
- self.having.non_generative(self, having)
- @util.deprecated(
- "1.4",
- "The :meth:`_expression.Select.append_from` method is deprecated "
- "and will be removed in a future release. Use the generative "
- "method :meth:`_expression.Select.select_from`.",
- )
- def append_from(self, fromclause):
- """Append the given :class:`_expression.FromClause` expression
- to this select() construct's FROM clause.
- This is an **in-place** mutation method; the
- :meth:`_expression.Select.select_from` method is preferred,
- as it provides
- standard :term:`method chaining`.
- """
- self.select_from.non_generative(self, fromclause)
- @CompileState.plugin_for("default", "select")
- class SelectState(util.MemoizedSlots, CompileState):
- __slots__ = (
- "from_clauses",
- "froms",
- "columns_plus_names",
- "_label_resolve_dict",
- )
- class default_select_compile_options(CacheableOptions):
- _cache_key_traversal = []
- def __init__(self, statement, compiler, **kw):
- 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):
- raise NotImplementedError(
- "The default SELECT construct without plugins does not "
- "implement this method."
- )
- @classmethod
- def get_column_descriptions(cls, statement):
- cls._plugin_not_implemented()
- @classmethod
- def from_statement(cls, statement, from_statement):
- cls._plugin_not_implemented()
- @classmethod
- def get_columns_clause_froms(cls, statement):
- 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):
- 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, col_name=None):
- if c._is_text_clause:
- return None
- elif 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):
- return self._normalize_froms(
- itertools.chain(
- 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
- ]
- ),
- self.from_clauses,
- ),
- check_statement=statement,
- )
- @classmethod
- def _normalize_froms(cls, iterable_of_froms, check_statement=None):
- """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()
- froms = []
- for item in iterable_of_froms:
- if item._is_subquery 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]
- return froms
- def _get_display_froms(
- self, explicit_correlate_froms=None, implicit_correlate_froms=None
- ):
- """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):
- with_cols = dict(
- (c._tq_label or c.key, c)
- for c in self.statement._all_selected_columns
- if c._allow_label_resolve
- )
- only_froms = dict(
- (c.key, c)
- for c in _select_iterables(self.froms)
- if c._allow_label_resolve
- )
- only_cols = 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):
- if stmt._setup_joins:
- return stmt._setup_joins[-1][0]
- else:
- return None
- @classmethod
- def all_selected_columns(cls, statement):
- return [c for c in _select_iterables(statement._raw_columns)]
- def _setup_joins(self, args, raw_columns):
- for (right, onclause, left, flags) in args:
- 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
- )
- 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:
- 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, left, right, onclause
- ):
- """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 = None
- from_clauses = self.from_clauses
- if from_clauses:
- indexes = 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):
- replace_from_obj_index = None
- sql_util = util.preloaded.sql_util
- from_clauses = list(self.statement._iterate_from_elements())
- if from_clauses:
- indexes = 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(object):
- def _iterate_from_elements(self):
- # note this does not include elements
- # in _setup_joins or _legacy_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(
- traversals.HasCacheKey, traversals.HasCopyInternals, visitors.Traversible
- ):
- __visit_name__ = "memoized_select_entities"
- _traverse_internals = [
- ("_raw_columns", InternalTraversal.dp_clauseelement_list),
- ("_setup_joins", InternalTraversal.dp_setup_join_tuple),
- ("_legacy_setup_joins", InternalTraversal.dp_setup_join_tuple),
- ("_with_options", InternalTraversal.dp_executable_options),
- ]
- _annotations = util.EMPTY_DICT
- def _clone(self, **kw):
- c = self.__class__.__new__(self.__class__)
- c.__dict__ = {k: v for k, v in self.__dict__.items()}
- c._is_clone_of = self
- return c
- @classmethod
- def _generate_for_statement(cls, select_stmt):
- if (
- select_stmt._setup_joins
- or select_stmt._legacy_setup_joins
- or select_stmt._with_options
- ):
- self = _MemoizedSelectEntities()
- self._raw_columns = select_stmt._raw_columns
- self._setup_joins = select_stmt._setup_joins
- self._legacy_setup_joins = select_stmt._legacy_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._legacy_setup_joins
- ) = select_stmt._with_options = ()
- class Select(
- HasPrefixes,
- HasSuffixes,
- HasHints,
- HasCompileState,
- DeprecatedSelectGenerations,
- _SelectFromElements,
- GenerativeSelect,
- ):
- """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:`coretutorial_selecting` - in the 1.x tutorial
- :ref:`tutorial_selecting_data` - in the 2.0 tutorial
- """
- __visit_name__ = "select"
- _setup_joins = ()
- _legacy_setup_joins = ()
- _memoized_select_entities = ()
- _distinct = False
- _distinct_on = ()
- _correlate = ()
- _correlate_except = None
- _where_criteria = ()
- _having_criteria = ()
- _from_obj = ()
- _auto_correlate = True
- _compile_options = SelectState.default_select_compile_options
- _traverse_internals = (
- [
- ("_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),
- ("_legacy_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
- )
- _cache_key_traversal = _traverse_internals + [
- ("_compile_options", InternalTraversal.dp_has_cache_key)
- ]
- @classmethod
- def _create_select_from_fromclause(cls, target, entities, *arg, **kw):
- if arg or kw:
- return Select.create_legacy_select(entities, *arg, **kw)
- else:
- return Select._create_select(*entities)
- @classmethod
- @util.deprecated(
- "2.0",
- "The legacy calling style of :func:`_sql.select` is deprecated and "
- "will be removed in SQLAlchemy 2.0. Please use the new calling "
- "style described at :func:`_sql.select`.",
- )
- def create_legacy_select(
- cls,
- columns=None,
- whereclause=None,
- from_obj=None,
- distinct=False,
- having=None,
- correlate=True,
- prefixes=None,
- suffixes=None,
- **kwargs
- ):
- """Construct a new :class:`_expression.Select` using the 1.x style API.
- This method is called implicitly when the :func:`_expression.select`
- construct is used and the first argument is a Python list or other
- plain sequence object, which is taken to refer to the columns
- collection.
- .. versionchanged:: 1.4 Added the :meth:`.Select.create_legacy_select`
- constructor which documents the calling style in use when the
- :func:`.select` construct is invoked using 1.x-style arguments.
- Similar functionality is also available via the
- :meth:`_expression.FromClause.select` method on any
- :class:`_expression.FromClause`.
- All arguments which accept :class:`_expression.ClauseElement` arguments
- also accept string arguments, which will be converted as appropriate
- into either :func:`_expression.text()` or
- :func:`_expression.literal_column()` constructs.
- .. seealso::
- :ref:`coretutorial_selecting` - Core Tutorial description of
- :func:`_expression.select`.
- :param columns:
- A list of :class:`_expression.ColumnElement` or
- :class:`_expression.FromClause`
- objects which will form the columns clause of the resulting
- statement. For those objects that are instances of
- :class:`_expression.FromClause` (typically :class:`_schema.Table`
- or :class:`_expression.Alias`
- objects), the :attr:`_expression.FromClause.c`
- collection is extracted
- to form a collection of :class:`_expression.ColumnElement` objects.
- This parameter will also accept :class:`_expression.TextClause`
- constructs as
- given, as well as ORM-mapped classes.
- .. note::
- The :paramref:`_expression.select.columns`
- parameter is not available
- in the method form of :func:`_expression.select`, e.g.
- :meth:`_expression.FromClause.select`.
- .. seealso::
- :meth:`_expression.Select.column`
- :meth:`_expression.Select.with_only_columns`
- :param whereclause:
- A :class:`_expression.ClauseElement`
- expression which will be used to form the
- ``WHERE`` clause. It is typically preferable to add WHERE
- criterion to an existing :class:`_expression.Select`
- using method chaining
- with :meth:`_expression.Select.where`.
- .. seealso::
- :meth:`_expression.Select.where`
- :param from_obj:
- A list of :class:`_expression.ClauseElement`
- objects which will be added to the
- ``FROM`` clause of the resulting statement. This is equivalent
- to calling :meth:`_expression.Select.select_from`
- using method chaining on
- an existing :class:`_expression.Select` object.
- .. seealso::
- :meth:`_expression.Select.select_from`
- - full description of explicit
- FROM clause specification.
- :param bind=None:
- an :class:`_engine.Engine` or :class:`_engine.Connection` instance
- to which the
- resulting :class:`_expression.Select` object will be bound. The
- :class:`_expression.Select`
- object will otherwise automatically bind to
- whatever :class:`~.base.Connectable` instances can be located within
- its contained :class:`_expression.ClauseElement` members.
- :param correlate=True:
- indicates that this :class:`_expression.Select`
- object should have its
- contained :class:`_expression.FromClause`
- elements "correlated" to an enclosing
- :class:`_expression.Select` object.
- It is typically preferable to specify
- correlations on an existing :class:`_expression.Select`
- construct using
- :meth:`_expression.Select.correlate`.
- .. seealso::
- :meth:`_expression.Select.correlate`
- - full description of correlation.
- :param distinct=False:
- when ``True``, applies a ``DISTINCT`` qualifier to the columns
- clause of the resulting statement.
- The boolean argument may also be a column expression or list
- of column expressions - this is a special calling form which
- is understood by the PostgreSQL dialect to render the
- ``DISTINCT ON (<columns>)`` syntax.
- ``distinct`` is also available on an existing
- :class:`_expression.Select`
- object via the :meth:`_expression.Select.distinct` method.
- .. seealso::
- :meth:`_expression.Select.distinct`
- :param group_by:
- a list of :class:`_expression.ClauseElement`
- objects which will comprise the
- ``GROUP BY`` clause of the resulting select. This parameter
- is typically specified more naturally using the
- :meth:`_expression.Select.group_by` method on an existing
- :class:`_expression.Select`.
- .. seealso::
- :meth:`_expression.Select.group_by`
- :param having:
- a :class:`_expression.ClauseElement`
- that will comprise the ``HAVING`` clause
- of the resulting select when ``GROUP BY`` is used. This parameter
- is typically specified more naturally using the
- :meth:`_expression.Select.having` method on an existing
- :class:`_expression.Select`.
- .. seealso::
- :meth:`_expression.Select.having`
- :param limit=None:
- 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. This parameter is typically specified more
- naturally using the :meth:`_expression.Select.limit`
- method on an existing
- :class:`_expression.Select`.
- .. seealso::
- :meth:`_expression.Select.limit`
- :param offset=None:
- 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. This parameter is typically specified more naturally
- using the :meth:`_expression.Select.offset` method on an existing
- :class:`_expression.Select`.
- .. seealso::
- :meth:`_expression.Select.offset`
- :param order_by:
- a scalar or list of :class:`_expression.ClauseElement`
- objects which will
- comprise the ``ORDER BY`` clause of the resulting select.
- This parameter is typically specified more naturally using the
- :meth:`_expression.Select.order_by` method on an existing
- :class:`_expression.Select`.
- .. seealso::
- :meth:`_expression.Select.order_by`
- :param use_labels=False:
- when ``True``, the statement will be generated using labels
- for each column in the columns clause, which qualify each
- column with its parent table's (or aliases) name so that name
- conflicts between columns in different tables don't occur.
- The format of the label is ``<tablename>_<column>``. The "c"
- collection of a :class:`_expression.Subquery` created
- against this :class:`_expression.Select`
- object, as well as the :attr:`_expression.Select.selected_columns`
- collection of the :class:`_expression.Select` itself, will use these
- names for targeting column members.
- This parameter can also be specified on an existing
- :class:`_expression.Select` object using the
- :meth:`_expression.Select.set_label_style`
- method.
- .. seealso::
- :meth:`_expression.Select.set_label_style`
- """
- self = cls.__new__(cls)
- self._auto_correlate = correlate
- if distinct is not False:
- if distinct is True:
- self.distinct.non_generative(self)
- else:
- self.distinct.non_generative(self, *util.to_list(distinct))
- if from_obj is not None:
- self.select_from.non_generative(self, *util.to_list(from_obj))
- try:
- cols_present = bool(columns)
- except TypeError as err:
- util.raise_(
- exc.ArgumentError(
- "select() construct created in legacy mode, i.e. with "
- "keyword arguments, must provide the columns argument as "
- "a Python list or other iterable.",
- code="c9ae",
- ),
- from_=err,
- )
- if cols_present:
- self._raw_columns = [
- coercions.expect(
- roles.ColumnsClauseRole, c, apply_propagate_attrs=self
- )
- for c in columns
- ]
- else:
- self._raw_columns = []
- if whereclause is not None:
- self.where.non_generative(self, whereclause)
- if having is not None:
- self.having.non_generative(self, having)
- if prefixes:
- self._setup_prefixes(prefixes)
- if suffixes:
- self._setup_suffixes(suffixes)
- GenerativeSelect.__init__(self, **kwargs)
- return self
- @classmethod
- def _create_future_select(cls, *entities):
- r"""Construct a new :class:`_expression.Select` using the 2.
- x style API.
- .. versionadded:: 1.4 - The :func:`_sql.select` function now accepts
- column arguments positionally. The top-level :func:`_sql.select`
- function will automatically use the 1.x or 2.x style API based on
- the incoming arguments; using :func:`_future.select` from the
- ``sqlalchemy.future`` module will enforce that only the 2.x style
- constructor is used.
- Similar functionality is also available via the
- :meth:`_expression.FromClause.select` method on any
- :class:`_expression.FromClause`.
- .. seealso::
- :ref:`coretutorial_selecting` - Core Tutorial description of
- :func:`_expression.select`.
- :param \*entities:
- Entities to SELECT from. For Core usage, this is typically a series
- of :class:`_expression.ColumnElement` and / or
- :class:`_expression.FromClause`
- objects which will form the columns clause of the resulting
- statement. For those objects that are instances of
- :class:`_expression.FromClause` (typically :class:`_schema.Table`
- or :class:`_expression.Alias`
- objects), the :attr:`_expression.FromClause.c`
- collection is extracted
- to form a collection of :class:`_expression.ColumnElement` objects.
- This parameter will also accept :class:`_expression.TextClause`
- constructs as
- given, as well as ORM-mapped classes.
- """
- self = cls.__new__(cls)
- self._raw_columns = [
- coercions.expect(
- roles.ColumnsClauseRole, ent, apply_propagate_attrs=self
- )
- for ent in entities
- ]
- GenerativeSelect.__init__(self)
- return self
- _create_select = _create_future_select
- @classmethod
- def _create_raw_select(cls, **kw):
- """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
- @classmethod
- def _create(cls, *args, **kw):
- r"""Create a :class:`.Select` using either the 1.x or 2.0 constructor
- style.
- For the legacy calling style, see :meth:`.Select.create_legacy_select`.
- If the first argument passed is a Python sequence or if keyword
- arguments are present, this style is used.
- .. versionadded:: 2.0 - the :func:`_future.select` construct is
- the same construct as the one returned by
- :func:`_expression.select`, except that the function only
- accepts the "columns clause" entities up front; the rest of the
- state of the SELECT should be built up using generative methods.
- Similar functionality is also available via the
- :meth:`_expression.FromClause.select` method on any
- :class:`_expression.FromClause`.
- .. seealso::
- :ref:`coretutorial_selecting` - Core Tutorial description of
- :func:`_expression.select`.
- :param \*entities:
- Entities to SELECT from. For Core usage, this is typically a series
- of :class:`_expression.ColumnElement` and / or
- :class:`_expression.FromClause`
- objects which will form the columns clause of the resulting
- statement. For those objects that are instances of
- :class:`_expression.FromClause` (typically :class:`_schema.Table`
- or :class:`_expression.Alias`
- objects), the :attr:`_expression.FromClause.c`
- collection is extracted
- to form a collection of :class:`_expression.ColumnElement` objects.
- This parameter will also accept :class:`_expression.TextClause`
- constructs as given, as well as ORM-mapped classes.
- """
- if (
- args
- and (
- isinstance(args[0], list)
- or (
- hasattr(args[0], "__iter__")
- and not isinstance(
- args[0], util.string_types + (ClauseElement,)
- )
- and inspect(args[0], raiseerr=False) is None
- and not hasattr(args[0], "__clause_element__")
- )
- )
- ) or kw:
- return cls.create_legacy_select(*args, **kw)
- else:
- return cls._create_future_select(*args)
- def __init__(self):
- raise NotImplementedError()
- def _scalar_type(self):
- elem = self._raw_columns[0]
- cols = list(elem._select_iterable)
- return cols[0].type
- def filter(self, *criteria):
- """A synonym for the :meth:`_future.Select.where` method."""
- return self.where(*criteria)
- def _filter_by_zero(self):
- 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]
- def filter_by(self, **kwargs):
- 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):
- """Return a 'column descriptions' structure which may be
- :term:`plugin-specific`.
- """
- meth = SelectState.get_plugin_class(self).get_column_descriptions
- return meth(self)
- def from_statement(self, statement):
- """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, onclause=None, isouter=False, full=False):
- 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::
- 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
- target = coercions.expect(
- roles.JoinTargetRole, target, apply_propagate_attrs=self
- )
- if onclause is not None:
- onclause = coercions.expect(roles.OnClauseRole, onclause)
- self._setup_joins += (
- (target, onclause, None, {"isouter": isouter, "full": full}),
- )
- def outerjoin_from(self, from_, target, onclause=None, full=False):
- 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_, target, onclause=None, isouter=False, full=False
- ):
- 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::
- 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
- )
- target = coercions.expect(
- roles.JoinTargetRole, target, apply_propagate_attrs=self
- )
- if onclause is not None:
- onclause = coercions.expect(roles.OnClauseRole, onclause)
- self._setup_joins += (
- (target, onclause, from_, {"isouter": isouter, "full": full}),
- )
- def outerjoin(self, target, onclause=None, full=False):
- """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):
- """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`
- """
- return self._compile_state_factory(self, None)._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):
- """Return the displayed list of :class:`_expression.FromClause`
- elements.
- """
- return self.get_final_froms()
- @property
- def columns_clause_froms(self):
- """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):
- """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):
- if 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=_clone, **kw):
- # 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 = (
- set(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, **kw):
- if isinstance(obj, ColumnClause) and obj.table in new_froms:
- newelem = new_froms[obj.table].corresponding_column(obj)
- return newelem
- 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(Select, self)._copy_internals(
- clone=clone, omit_attrs=("_from_obj",), **kw
- )
- self._reset_memoizations()
- def get_children(self, **kwargs):
- return itertools.chain(
- super(Select, self).get_children(
- omit_attrs=["_from_obj", "_correlate", "_correlate_except"]
- ),
- self._iterate_from_elements(),
- )
- @_generative
- def add_columns(self, *columns):
- """Return a new :func:`_expression.select` construct with
- the given column expressions added to its columns clause.
- E.g.::
- my_select = my_select.add_columns(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.
- """
- self._reset_memoizations()
- self._raw_columns = self._raw_columns + [
- coercions.expect(
- roles.ColumnsClauseRole, column, apply_propagate_attrs=self
- )
- for column in columns
- ]
- def _set_entities(self, entities):
- 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):
- """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=True):
- """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.
- """
- return self.with_only_columns(
- *util.preloaded.sql_util.reduce_columns(
- self._all_selected_columns,
- only_synonyms=only_synonyms,
- *(self._where_criteria + self._from_obj)
- )
- )
- @_generative
- def with_only_columns(self, *columns, **kw):
- r"""Return a new :func:`_expression.select` construct with its columns
- clause replaced with the given columns.
- By default, this method is exactly equivalent to as if the original
- :func:`_expression.select` had been called with the given columns
- clause. 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 \*columns: column expressions to be used.
- .. versionchanged:: 1.4 the :meth:`_sql.Select.with_only_columns`
- method accepts the list of column expressions positionally;
- passing the expressions as a list is deprecated.
- :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
- # memoizations should be cleared here as of
- # I95c560ffcbfa30b26644999412fb6a385125f663 , asserting this
- # is the case for now.
- self._assert_no_memoizations()
- maintain_column_froms = kw.pop("maintain_column_froms", False)
- if kw:
- raise TypeError("unknown parameters: %s" % (", ".join(kw),))
- if maintain_column_froms:
- self.select_from.non_generative(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(
- "columns", "Select.with_only_columns", columns
- )
- ]
- @property
- def whereclause(self):
- """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):
- """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 = coercions.expect(roles.WhereHavingRole, criterion)
- self._where_criteria += (where_criteria,)
- @_generative
- def having(self, having):
- """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.
- """
- self._having_criteria += (
- coercions.expect(roles.WhereHavingRole, having),
- )
- @_generative
- def distinct(self, *expr):
- r"""Return a new :func:`_expression.select` construct which
- will apply DISTINCT to its columns clause.
- :param \*expr: optional column expressions. When present,
- the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>>)``
- construct.
- .. 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) for e in expr
- )
- else:
- self._distinct = True
- @_generative
- def select_from(self, *froms):
- 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
- )
- @_generative
- def correlate(self, *fromclauses):
- 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: 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.Select.correlate_except`
- :ref:`correlated_subqueries`
- """
- self._auto_correlate = False
- if fromclauses and fromclauses[0] in {None, False}:
- self._correlate = ()
- else:
- self._correlate = self._correlate + tuple(
- coercions.expect(roles.FromClauseRole, f) for f in fromclauses
- )
- @_generative
- def correlate_except(self, *fromclauses):
- 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, 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:`correlated_subqueries`
- """
- self._auto_correlate = False
- if fromclauses and fromclauses[0] in {None, False}:
- self._correlate_except = ()
- else:
- self._correlate_except = (self._correlate_except or ()) + tuple(
- coercions.expect(roles.FromClauseRole, f) for f in fromclauses
- )
- @HasMemoized.memoized_attribute
- def selected_columns(self):
- """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.
- .. 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 = SelectState._column_naming_convention(self._label_style)
- return ColumnCollection(
- [
- (conv(c), c)
- for c in self._all_selected_columns
- if not c._is_text_clause
- ]
- ).as_immutable()
- @HasMemoized.memoized_attribute
- def _all_selected_columns(self):
- meth = SelectState.get_plugin_class(self).all_selected_columns
- return list(meth(self))
- def _ensure_disambiguated_names(self):
- if self._label_style is LABEL_STYLE_NONE:
- self = self.set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY)
- return self
- def _generate_columns_plus_names(self, anon_for_dupe_key):
- """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.
- """
- cols = self._all_selected_columns
- key_naming_convention = SelectState._column_naming_convention(
- self._label_style
- )
- names = {}
- result = []
- 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:
- effective_name = required_label_name = None
- fallback_label_name = c._non_anon_label or c._anon_name_label
- else:
- 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 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(
- (
- # string label name, if non-None, must be rendered as a
- # label, i.e. "AS <name>"
- required_label_name,
- # 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
- key_naming_convention(c),
- # 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
- fallback_label_name,
- # the ColumnElement itself
- c,
- # True if this is a duplicate of a previous column
- # in the list of columns
- repeated,
- )
- )
- return result
- def _generate_fromclause_column_proxies(self, subquery):
- """Generate column proxies to place in the exported ``.c``
- collection of a subquery."""
- prox = [
- c._make_proxy(
- subquery,
- key=proxy_key,
- name=required_label_name,
- name_is_truncatable=True,
- )
- for (
- required_label_name,
- proxy_key,
- fallback_label_name,
- c,
- repeated,
- ) in (self._generate_columns_plus_names(False))
- if not c._is_text_clause
- ]
- subquery._columns._populate_separate_keys(prox)
- def _needs_parens_for_grouping(self):
- return self._has_row_limiting_clause or bool(
- self._order_by_clause.clauses
- )
- def self_group(self, against=None):
- """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, **kwargs):
- 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, **kwargs)
- def union_all(self, *other, **kwargs):
- 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, **kwargs)
- def except_(self, *other, **kwargs):
- 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.
- :param \**kwargs: keyword arguments are forwarded to the constructor
- for the newly created :class:`_sql.CompoundSelect` object.
- """
- return CompoundSelect._create_except(self, *other, **kwargs)
- def except_all(self, *other, **kwargs):
- 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.
- :param \**kwargs: keyword arguments are forwarded to the constructor
- for the newly created :class:`_sql.CompoundSelect` object.
- """
- return CompoundSelect._create_except_all(self, *other, **kwargs)
- def intersect(self, *other, **kwargs):
- 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, **kwargs)
- def intersect_all(self, *other, **kwargs):
- 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, **kwargs)
- @property
- @util.deprecated_20(
- ":attr:`.Executable.bind`",
- alternative="Bound metadata is being removed as of SQLAlchemy 2.0.",
- enable_warnings=False,
- )
- def bind(self):
- """Returns the :class:`_engine.Engine` or :class:`_engine.Connection`
- to which this :class:`.Executable` is bound, or None if none found.
- """
- if self._bind:
- return self._bind
- for item in self._iterate_from_elements():
- if item._is_subquery and item.element is self:
- raise exc.InvalidRequestError(
- "select() construct refers to itself as a FROM"
- )
- e = item.bind
- if e:
- self._bind = e
- return e
- else:
- break
- for c in self._raw_columns:
- e = c.bind
- if e:
- self._bind = e
- return e
- @bind.setter
- def bind(self, bind):
- self._bind = bind
- class ScalarSelect(roles.InElementRole, Generative, Grouping):
- """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
- :ref:`scalar_selects` - in the 1.x tutorial
- """
- _from_objects = []
- _is_from_container = True
- _is_implicitly_boolean = False
- inherit_cache = True
- def __init__(self, element):
- self.element = element
- self.type = element._scalar_type()
- @property
- def columns(self):
- 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):
- """Apply a WHERE clause to the SELECT statement referred to
- by this :class:`_expression.ScalarSelect`.
- """
- self.element = self.element.where(crit)
- def self_group(self, **kwargs):
- return self
- @_generative
- def correlate(self, *fromclauses):
- 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
- :ref:`correlated_subqueries` - in the 1.x tutorial
- """
- self.element = self.element.correlate(*fromclauses)
- @_generative
- def correlate_except(self, *fromclauses):
- 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
- :ref:`correlated_subqueries` - in the 1.x tutorial
- """
- self.element = self.element.correlate_except(*fromclauses)
- class Exists(UnaryExpression):
- """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`.
- """
- _from_objects = []
- inherit_cache = True
- def __init__(self, *args, **kwargs):
- """Construct a new :class:`_expression.Exists` construct.
- The :func:`_sql.exists` can be invoked by itself to produce an
- :class:`_sql.Exists` construct, which will accept simple WHERE
- criteria::
- exists_criteria = exists().where(table1.c.col1 == table2.c.col2)
- However, for greater flexibility in constructing the SELECT, an
- existing :class:`_sql.Select` construct may be converted to an
- :class:`_sql.Exists`, most conveniently by making use of the
- :meth:`_sql.SelectBase.exists` method::
- exists_criteria = (
- select(table2.c.col2).
- where(table1.c.col1 == table2.c.col2).
- exists()
- )
- The EXISTS criteria is then used inside of an enclosing SELECT::
- stmt = select(table1.c.col1).where(exists_criteria)
- The above statement will then be of the form::
- SELECT col1 FROM table1 WHERE EXISTS
- (SELECT table2.col2 FROM table2 WHERE table2.col2 = table1.col1)
- .. seealso::
- :ref:`tutorial_exists` - in the :term:`2.0 style` tutorial.
- :meth:`_sql.SelectBase.exists` - method to transform a ``SELECT`` to an
- ``EXISTS`` clause.
- """ # noqa E501
- if args and isinstance(args[0], (SelectBase, ScalarSelect)):
- s = args[0]
- else:
- if not args:
- args = (literal_column("*"),)
- s = Select._create(*args, **kwargs).scalar_subquery()
- UnaryExpression.__init__(
- self,
- s,
- operator=operators.exists,
- type_=type_api.BOOLEANTYPE,
- wraps_column_expression=True,
- )
- def _regroup(self, fn):
- element = self.element._ungroup()
- element = fn(element)
- return element.self_group(against=operators.exists)
- @util.deprecated_params(
- whereclause=(
- "2.0",
- "The :paramref:`_sql.Exists.select().whereclause` parameter "
- "is deprecated and will be removed in version 2.0. "
- "Please make use "
- "of the :meth:`.Select.where` "
- "method to add WHERE criteria to the SELECT statement.",
- ),
- kwargs=(
- "2.0",
- "The :meth:`_sql.Exists.select` method will no longer accept "
- "keyword arguments in version 2.0. "
- "Please use generative methods from the "
- ":class:`_sql.Select` construct in order to apply additional "
- "modifications.",
- ),
- )
- def select(self, whereclause=None, **kwargs):
- 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::
- SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1
- :param whereclause: a WHERE clause, equivalent to calling the
- :meth:`_sql.Select.where` method.
- :param **kwargs: additional keyword arguments are passed to the
- legacy constructor for :class:`_sql.Select` described at
- :meth:`_sql.Select.create_legacy_select`.
- .. seealso::
- :func:`_expression.select` - general purpose
- method which allows for arbitrary column lists.
- """ # noqa
- if whereclause is not None:
- kwargs["whereclause"] = whereclause
- return Select._create_select_from_fromclause(self, [self], **kwargs)
- def correlate(self, *fromclause):
- """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(*fromclause)
- )
- return e
- def correlate_except(self, *fromclause):
- """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(*fromclause)
- )
- return e
- def select_from(self, *froms):
- """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):
- """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):
- """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 = [
- ("element", InternalTraversal.dp_clauseelement),
- ("column_args", InternalTraversal.dp_clauseelement_list),
- ] + SupportsCloneAnnotations._clone_annotations_traverse_internals
- _is_textual = True
- is_text = True
- is_select = True
- def __init__(self, text, columns, positional=False):
- self.element = text
- # convert for ORM attributes->columns, etc
- self.column_args = [
- coercions.expect(roles.ColumnsClauseRole, c) for c in columns
- ]
- self.positional = positional
- @HasMemoized.memoized_attribute
- def selected_columns(self):
- """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_immutable()
- @property
- def _all_selected_columns(self):
- return self.column_args
- def _set_label_style(self, style):
- return self
- def _ensure_disambiguated_names(self):
- return self
- @property
- def _bind(self):
- return self.element._bind
- @_generative
- def bindparams(self, *binds, **bind_as_values):
- self.element = self.element.bindparams(*binds, **bind_as_values)
- def _generate_fromclause_column_proxies(self, fromclause):
- fromclause._columns._populate_separate_keys(
- c._make_proxy(fromclause) for c in self.column_args
- )
- def _scalar_type(self):
- return self.column_args[0].type
- TextAsFrom = TextualSelect
- """Backwards compatibility with the previous name"""
- class AnnotatedFromClause(Annotated):
- def __init__(self, element, values):
- # force FromClause to generate their internal
- # collections into __dict__
- element.c
- Annotated.__init__(self, element, values)
|