1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955 |
- # sql/selectable.py
- # Copyright (C) 2005-2024 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:`tutorial_lateral_correlation` - 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:`tutorial_using_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
- joins_implicitly = 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,
- joins_implicitly=False,
- ):
- super(TableValuedAlias, self)._init(selectable, name=name)
- self.joins_implicitly = joins_implicitly
- self._tableval_type = (
- type_api.TABLEVALUE
- if table_value_type is None
- else table_value_type
- )
- @HasMemoized.memoized_attribute
- def column(self):
- """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,
- table_value_type=self._tableval_type,
- joins_implicitly=self.joins_implicitly,
- )
- if self._render_derived:
- tva._render_derived = True
- tva._render_derived_w_types = self._render_derived_w_types
- return tva
- def lateral(self, name=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)
- # construct against original to prevent memory growth
- # for repeated generations
- new_alias = TableValuedAlias._construct(
- self.element,
- name=name,
- table_value_type=self._tableval_type,
- joins_implicitly=self.joins_implicitly,
- )
- new_alias._render_derived = True
- new_alias._render_derived_w_types = with_types
- return new_alias
- class Lateral(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:`tutorial_lateral_correlation` - 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:`tutorial_lateral_correlation` - 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:`tutorial_using_aliases`
- :func:`_expression.alias`
- """
- return CTE._construct(
- self.element,
- name=name,
- recursive=self.recursive,
- nesting=self.nesting,
- _cte_alias=self,
- _prefixes=self._prefixes,
- _suffixes=self._suffixes,
- )
- def union(self, *other):
- 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),
- ("schema", 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),
- ("key_share", 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:`tutorial_using_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
- """
- 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:`tutorial_lateral_correlation` - 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_DISAMBIGUATE_ONLY`.
- In modern SQLAlchemy, there is not generally a need to change the
- labeling style, as per-expression labels are more effectively used by
- making use of the :meth:`_sql.ColumnElement.label` method. In past
- versions, :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL` was used to
- disambiguate same-named columns from different tables, aliases, or
- subqueries; the newer :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY` now
- applies labels only to names that conflict with an existing name so
- that the impact of this labeling is minimal.
- The rationale for disambiguation is mostly so that all column
- expressions are available from a given :attr:`_sql.FromClause.c`
- collection when a subquery is created.
- .. versionadded:: 1.4 - the
- :meth:`_sql.GenerativeSelect.set_label_style` method replaces the
- previous combination of ``.apply_labels()``, ``.with_labels()`` and
- ``use_labels=True`` methods and/or parameters.
- .. seealso::
- :data:`_sql.LABEL_STYLE_DISAMBIGUATE_ONLY`
- :data:`_sql.LABEL_STYLE_TABLENAME_PLUS_COL`
- :data:`_sql.LABEL_STYLE_NONE`
- :data:`_sql.LABEL_STYLE_DEFAULT`
- """
- if self._label_style is not style:
- self = self._generate()
- self._label_style = style
- return self
- @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)
- Calling this method multiple times is equivalent to calling it once
- with all the clauses concatenated. All existing ORDER BY criteria may
- be cancelled by passing ``None`` by itself. New ORDER BY criteria may
- then be added by invoking :meth:`_orm.Query.order_by` again, e.g.::
- # will erase all ORDER BY and ORDER BY new_col alone
- stmt = stmt.order_by(None).order_by(new_col)
- :param \*clauses: a series of :class:`_expression.ColumnElement`
- constructs
- which will be used to generate an ORDER BY clause.
- .. seealso::
- :ref:`tutorial_order_by` - in the :ref:`unified_tutorial`
- :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial`
- """
- if 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):
- return [
- {
- "name": name,
- "type": element.type,
- "expr": element,
- }
- for _, name, _, element, _ in (
- statement._generate_columns_plus_names(False)
- )
- ]
- @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.__dict__.get("_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:`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:`tutorial_selecting_data` - in the :ref:`unified_tutorial`
- :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 :term:`plugin-enabled` 'column descriptions' structure
- referring to the columns which are SELECTed by this statement.
- This attribute is generally useful when using the ORM, as an
- extended structure which includes information about mapped
- entities is returned. The section :ref:`queryguide_inspection`
- contains more background.
- For a Core-only statement, the structure returned by this accessor
- is derived from the same objects that are returned by the
- :attr:`.Select.selected_columns` accessor, formatted as a list of
- dictionaries which contain the keys ``name``, ``type`` and ``expr``,
- which indicate the column expressions to be selected::
- >>> stmt = select(user_table)
- >>> stmt.column_descriptions
- [
- {
- 'name': 'id',
- 'type': Integer(),
- 'expr': Column('id', Integer(), ...)},
- {
- 'name': 'name',
- 'type': String(length=30),
- 'expr': Column('name', String(length=30), ...)}
- ]
- .. versionchanged:: 1.4.33 The :attr:`.Select.column_descriptions`
- attribute returns a structure for a Core-only set of entities,
- not just ORM-only entities.
- .. seealso::
- :attr:`.UpdateBase.entity_description` - entity information for
- an :func:`.insert`, :func:`.update`, or :func:`.delete`
- :ref:`queryguide_inspection` - ORM background
- """
- meth = SelectState.get_plugin_class(self).get_column_descriptions
- return meth(self)
- def from_statement(self, statement):
- """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:`tutorial_scalar_subquery`
- """
- 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:`tutorial_scalar_subquery`
- """
- 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, cols=None):
- """Generate column names as rendered in a SELECT statement by
- the compiler.
- This is distinct from the _column_naming_convention generator that's
- intended for population of .c collections and similar, which has
- different rules. the collection returned here calls upon the
- _column_naming_convention as well.
- """
- if cols is None:
- cols = self._all_selected_columns
- key_naming_convention = SelectState._column_naming_convention(
- self._label_style
- )
- names = {}
- result = []
- 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
- """
- _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
- """
- 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
- """
- 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
- + HasCTE._has_ctes_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)
|