查询语法querystatement:queryexprqueryexpr:〔WITH〔RECURSIVE〕{nonrecursivecterecursivecte}〔,。。。〕〕{select(queryexpr)setoperation}〔ORDERBYexpression〔{ASCDESC}〕〔,。。。〕〕〔LIMITcount〔OFFSETskiprows〕〕select:SELECT〔{ALLDISTINCT}〕〔AS{STRUCTVALUE}〕selectlist〔FROMfromclause〔,。。。〕〕〔WHEREboolexpression〕〔GROUPBY{expression〔,。。。〕ROLLUP(expression〔,。。。〕)}〕〔HAVINGboolexpression〕〔QUALIFYboolexpression〕〔WINDOWwindowclause〕 表示法规则方括号〔〕表示可选子句。圆括号()表示文本括号。竖线表示逻辑OR。大括号{}括起一组可选项。方括号内后跟省略号的逗号〔,。。。〕表示可以在逗号分隔列表中重复其前面的项。 WITHPlayerStatsAS(SELECTAdamsasLastName,51asOpponentID,3asPointsScoredUNIONALLSELECTBuchanan,77,0UNIONALLSELECTCoolidge,77,1UNIONALLSELECTAdams,52,4UNIONALLSELECTBuchanan,50,13)SELECTFROMPlayerStatsSELECT语句SELECT〔{ALLDISTINCT}〕〔AS{STRUCTVALUE}〕selectlistselectlist:{selectallselectexpression}〔,。。。〕selectall:〔expression。〕〔EXCEPT(columnname〔,。。。〕)〕〔REPLACE(expression〔AS〕columnname〔,。。。〕)〕selectexpression:expression〔〔AS〕alias〕SELECT SELECT通常称为查询星号,会对执行完整查询后可见的每个列生成一个输出列。SELECTFROM(SELECTappleASfruit,carrotASvegetable);fruitvegetableapplecarrotSELECTexpression。 SELECT列表中的项也可以采用expression。的形式。这会为每个列或expression的顶级字段生成一个输出列。表达式必须是表别名或者其计算结果是带有字段的数据类型(如STRUCT)的单个值。WITHlocationsAS(SELECTSTRUCT(SeattleAScity,WashingtonASstate)ASlocationUNIONALLSELECTSTRUCT(PhoenixAScity,ArizonaASstate)ASlocation)SELECTl。location。FROMlocationsl;citystateSeattleWashingtonPhoenixArizonaWITHlocationsAS(SELECTARRAYSTRUCTcitySTRING,stateSTRING〔(Seattle,Washington),(Phoenix,Arizona)〕ASlocation)SELECTl。LOCATION〔offset(0)〕。FROMlocationsl;citystateSeattleWashingtonSELECTEXCEPT SELECTEXCEPT语句指定要从结果中排除的一个或多个列的名称。输出中将忽略所有匹配的列名称。WITHordersAS(SELECT5asorderid,sprocketasitemname,200asquantity)SELECTEXCEPT(orderid)FROMorders;itemnamequantitysprocket200SELECTREPLACEWITHordersAS(SELECT5asorderid,sprocketasitemname,200asquantity)SELECTREPLACE(widgetASitemname)FROMorders;orderiditemnamequantity5widget200WITHordersAS(SELECT5asorderid,sprocketasitemname,200asquantity)SELECTREPLACE(quantity2ASquantity)FROMorders;orderiditemnamequantity5sprocket100SELECTASSTRUCTSELECTASSTRUCTexpr〔〔AS〕structfieldname1〕〔,。。。〕 此语法会生成一个行类型为STRUCT的值表,其中STRUCT字段名称和类型与SELECT列表中生成的列名称和类型相匹配。SELECTARRAY(SELECTASSTRUCT1a,2b)SELECTASVALUE SELECTASVALUE从任何只生成一列的SELECT列表生成一个值表。输出将是一个值表,而不是生成具有一列的输出表(可能具有名称),其中行类型只是在一个SELECT列中生成的值类型。该列所具有的任何别名都将在值表中被舍弃。SELECTASVALUESTRUCT(1ASa,2ASb)xyzFROM子句FROMfromclause〔,。。。〕fromclause:fromitem〔{pivotoperatorunpivotoperator}〕〔tablesampleoperator〕fromitem:{tablename〔asalias〕〔FORSYSTEMTIMEASOFtimestampexpression〕{joinoperation(joinoperation)}(queryexpr)〔asalias〕fieldpathunnestoperatorctename〔asalias〕}asalias:〔AS〕aliasFORSYSTEMTIMEASOF返回表在过去一个小时内的历史版本SELECTFROMtFORSYSTEMTIMEASOFTIMESTAMPSUB(CURRENTTIMESTAMP(),INTERVAL1HOUR);返回表在一个绝对时间点的历史版本SELECTFROMtFORSYSTEMTIMEASOF2017010110:00:0007:00;返回错误,因为timestampexpression包含对所包含查询中的列的相关引用SELECTFROMt1WHEREt1。aIN(SELECTt2。aFROMt2FORSYSTEMTIMEASOFt1。timestampcolumn);如何访问在替换表之前表的历史版本DECLAREbeforereplacetimestampTIMESTAMP;Createtablebooks。CREATETABLEbooksASSELECTHamlettitle,WilliamShakespeareauthor;Getcurrenttimestampbeforetablereplacement。SETbeforereplacetimestampCURRENTTIMESTAMP();Replacetablewithdifferentschema(titleandreleasedate)。CREATEORREPLACETABLEbooksASSELECTHamlettitle,DATE16030101releasedate;ThisqueryreturnsHamlet,WilliamShakespeareasresult。SELECTFROMbooksFORSYSTEMTIMEASOFbeforereplacetimestamp;如何访问DML作业之前表的历史版本DECLAREJOBSTARTTIMESTAMPTIMESTAMP;Createtablebooks。CREATEORREPLACETABLEbooksASSELECTHamlettitle,WilliamShakespeareauthor;Inserttworowsintothebooks。INSERTbooks(title,author)VALUES(TheGreatGatsby,F。ScottFizgerald),(WarandPeace,LeoTolstoy);SELECTFROMbooks;SETJOBSTARTTIMESTAMP(SELECTstarttimeFROMregionus。INFORMATIONSCHEMA。JOBSBYUSERWHEREjobtypeQUERYANDstatementtypeINSERTORDERBYstarttimeDESCLIMIT1);ThisqueryonlyreturnsHamlet,WilliamShakespeareasresult。SELECTFROMbooksFORSYSTEMTIMEASOFJOBSTARTTIMESTAMP;查询返回错误,因为DML对表的当前版本以及一天前的表的历史版本进行操作INSERTINTOt1SELECTFROMt1FORSYSTEMTIMEASOFTIMESTAMPSUB(CURRENTTIMESTAMP(),INTERVAL1DAY);UNNEST运算符 UNNEST运算符接受数组,并返回一个表,数组中的每个元素占一行。您还可以在FROM子句外部将UNNEST与IN运算符搭配使用。unnestoperator:{UNNEST(arrayexpression)UNNEST(arraypath)arraypath}〔asalias〕〔WITHOFFSET〔asalias〕〕asalias:〔AS〕aliasUNNEST和结构体 对于结构体的输入数组,UNNEST会为每个结构体返回一行,并在结构体中为每个字段返回单独的列。每列的别名是相应结构体字段的名称。SELECTFROMUNNEST(ARRAYSTRUCTxINT64,ySTRING,zSTRUCT〔(1,foo,(10,11)),(3,bar,(20,21))〕);xyz1foo{10,11}3bar{20,21}SELECT,structvalueFROMUNNEST(ARRAYSTRUCTxINT64,ySTRING〔(1,foo),(3,bar)〕)ASstructvalue;xystructvalue3bar{3,bar}1foo{1,foo}显式和隐式UNNEST显式解除嵌套中,arrayexpression必须返回一个数组值,但不需要解析为数组,并且UNNEST关键字是必需的。SELECTFROMUNNEST(〔1,2,3〕);隐式解除嵌套中,arraypath必须解析为数组,而UNNEST关键字是可选的。SELECTxFROMmytableASt,t。structtypedcolumn。arraytypedfield1ASx;UNNEST和NULLULL和空数组会生成零行。包含NULL的数组会生成包含NULL值的行。UNNEST和WITHOFFSET 可选的WITHOFFSET子句会返回一个包含偏移量值的单独列,其中UNNEST运算生成的每一行会从零开始计数。该列具有一个可选的别名;如果未使用可选别名,则默认列名称为offset。SELECTFROMUNNEST(〔10,20,30〕)asnumbersWITHOFFSET;numbersoffset100201302PIVOT运算符FROMfromitem〔,。。。〕pivotoperatorpivotoperator:PIVOT(aggregatefunctioncall〔asalias〕〔,。。。〕FORinputcolumnIN(pivotcolumn〔asalias〕〔,。。。〕))〔ASalias〕asalias:〔AS〕alias PIVOT运算符通过聚合将行旋转为列。PIVOT是FROM子句的一部分。PIVOT可用于修改任何表表达式。不允许将PIVOT与FORSYSTEMTIMEASOF结合使用,但用户可以将PIVOT与本身使用FORSYSTEMTIMEASOF的子查询输入结合使用。WITHOFFSET子句不允许出现在PIVOT运算符之前。BeforePIVOTisusedtorotatesalesandquarterintoQ1,Q2,Q3,Q4columns:productsalesquarteryearKale51Q12020Kale23Q22020Kale45Q32020Kale3Q42020Kale70Q12021Kale85Q22021Apple77Q12020Apple0Q22020Apple1Q12021AfterPIVOTisusedtorotatesalesandquarterintoQ1,Q2,Q3,Q4columns:productyearQ1Q2Q3Q4Apple2020770NULLNULLApple20211NULLNULLNULLKale20205123453Kale20217085NULLNULL聚合函数SUM按除了pivotcolumn以外的所有未聚合列(product和year)进行隐式分组。SELECTFROMProducePIVOT(SUM(sales)FORquarterIN(Q1,Q2,Q3,Q4))productyearQ1Q2Q3Q4Apple2020770NULLNULLApple20211NULLNULLNULLKale20205123453Kale20217085NULLNULL如果您未添加year,则SUM只会按product进行分组。SELECTFROM(SELECTproduct,sales,quarterFROMProduce)PIVOT(SUM(sales)FORquarterIN(Q1,Q2,Q3,Q4))productQ1Q2Q3Q4Apple780NULLNULLKale121108453SELECTFROM(SELECTproduct,sales,quarterFROMProduce)PIVOT(SUM(sales)FORquarterIN(Q1,Q2,Q3))productQ1Q2Q3Apple780NULLKale12110845SELECTFROM(SELECTproduct,sales,quarterFROMProduce)PIVOT(SUM(sales)FORquarterIN(Q1,Q2,Q3))productQ1Q2Q3Apple780NULLKale12110845UNPIVOT运算符FROMfromitem〔,。。。〕unpivotoperatorunpivotoperator:UNPIVOT〔{INCLUDENULLSEXCLUDENULLS}〕({singlecolumnunpivotmulticolumnunpivot})〔unpivotalias〕singlecolumnunpivot:valuescolumnFORnamecolumnIN(columnstounpivot)multicolumnunpivot:valuescolumnsetFORnamecolumnIN(columnsetstounpivot)valuescolumnset:(valuescolumn〔,。。。〕)columnstounpivot:unpivotcolumn〔rowvaluealias〕〔,。。。〕columnsetstounpivot:(unpivotcolumn〔rowvaluealias〕〔,。。。〕)unpivotaliasandrowvaluealias:〔AS〕alias UNPIVOT运算符将列旋转为行。UNPIVOT是FROM子句的一部分。UNPIVOT可用于修改任何表表达式。不允许将UNPIVOT与FORSYSTEMTIMEASOF结合使用,但用户可以将UNPIVOT与本身使用FORSYSTEMTIMEASOF的子查询输入结合使用。WITHOFFSET子句不允许出现在UNPIVOT运算符之前。PIVOT聚合不能通过UNPIVOT撤消。BeforeUNPIVOTisusedtorotateQ1,Q2,Q3,Q4intosalesandquartercolumns:productQ1Q2Q3Q4Kale5123453Apple770252AfterUNPIVOTisusedtorotateQ1,Q2,Q3,Q4intosalesandquartercolumns:productsalesquarterKale51Q1Kale23Q2Kale45Q3Kale3Q4Apple77Q1Apple0Q2Apple25Q3Apple2Q4Produce表WITHProduceAS(SELECTKaleasproduct,51asQ1,23asQ2,45asQ3,3asQ4UNIONALLSELECTApple,77,0,25,2)SELECTFROMProduceproductQ1Q2Q3Q4Kale5123453Apple770252使用UNPIVOT运算符,Q1、Q2、Q3和Q4列将被旋转。现在,这些列的值会填充名为Sales的新列,这些列的名称会填充名为Quarter的新列。这是一个单列列转行操作。SELECTFROMProduceUNPIVOT(salesFORquarterIN(Q1,Q2,Q3,Q4))productsalesquarterKale51Q1Kale23Q2Kale45Q3Kale3Q4Apple77Q1Apple0Q2Apple25Q3Apple2Q4我们对四个季度执行UNPIVOT操作,使其合并为两个半年。这是一个多列列转行操作。SELECTFROMProduceUNPIVOT((firsthalfsales,secondhalfsales)FORsemestersIN((Q1,Q2)ASsemester1,(Q3,Q4)ASsemester2))productfirsthalfsalessecondhalfsalessemestersKale5123semester1Kale453semester2Apple770semester1Apple252semester2TABLESAMPLE运算符选择表中约10的数据SELECTFROMdataset。mytableTABLESAMPLESYSTEM(10PERCENT)JOIN操作joinoperation:{crossjoinoperationconditionjoinoperation}crossjoinoperation:fromitemcrossjoinoperatorfromitemconditionjoinoperation:fromitemconditionjoinoperatorfromitemjoinconditioncrossjoinoperator:{CROSSJOIN,}conditionjoinoperator:{〔INNER〕JOINFULL〔OUTER〕JOINLEFT〔OUTER〕JOINRIGHT〔OUTER〕JOIN}joincondition:{onclauseusingclause}onclause:ONboolexpressionusingclause:USING(joincolumn〔,。。。〕)〔INNER〕JOINFROMAINNERJOINBONA。wB。y FROMAINNERJOINBUSING(x) SELECTRoster。LastName,TeamMascot。MascotFROMRosterJOINTeamMascotONRoster。SchoolIDTeamMascot。SchoolID;LastNameMascotAdamsJaguarsBuchananLakersCoolidgeLakersDavisKnightsCROSSJOINFROMACROSSJOINB SELECTRoster。LastName,TeamMascot。MascotFROMRosterCROSSJOINTeamMascot;LastNameMascotAdamsJaguarsAdamsKnightsAdamsLakersAdamsMustangsBuchananJaguarsBuchananKnightsBuchananLakersBuchananMustangs。。。逗号交叉联接(,)FROMA,B SELECTRoster。LastName,TeamMascot。MascotFROMRoster,TeamMascot;LastNameMascotAdamsJaguarsAdamsKnightsAdamsLakersAdamsMustangsBuchananJaguarsBuchananKnightsBuchananLakersBuchananMustangs。。。FULL〔OUTER〕JOINFROMAFULLOUTERJOINBONA。wB。y FROMAFULLOUTERJOINBUSING(x) SELECTRoster。LastName,TeamMascot。MascotFROMRosterFULLJOINTeamMascotONRoster。SchoolIDTeamMascot。SchoolID;LastNameMascotAdamsJaguarsBuchananLakersCoolidgeLakersDavisKnightsEisenhowerNULLNULLMustangsLEFT〔OUTER〕JOINFROMALEFTOUTERJOINBONA。wB。y FROMALEFTOUTERJOINBUSING(x) SELECTRoster。LastName,TeamMascot。MascotFROMRosterLEFTJOINTeamMascotONRoster。SchoolIDTeamMascot。SchoolID;LastNameMascotAdamsJaguarsBuchananLakersCoolidgeLakersDavisKnightsEisenhowerNULLRIGHT〔OUTER〕JOINFROMARIGHTOUTERJOINBONA。wB。y FROMARIGHTOUTERJOINBUSING(x) SELECTRoster。LastName,TeamMascot。MascotFROMRosterRIGHTJOINTeamMascotONRoster。SchoolIDTeamMascot。SchoolID;LastNameMascotAdamsJaguarsBuchananLakersCoolidgeLakersDavisKnightsNULLMustangsON子句FROMAJOINBONA。xB。x SELECTRoster。LastName,TeamMascot。MascotFROMRosterJOINTeamMascotONRoster。SchoolIDTeamMascot。SchoolID;LastNameMascotAdamsJaguarsBuchananLakersCoolidgeLakersDavisKnightsUSING子句FROMAJOINBUSING(x) SELECTFROMRosterINNERJOINTeamMascotUSING(SchoolID);SchoolIDLastNameMascot50AdamsJaguars52BuchananLakers52CoolidgeLakers51DavisKnightsON和USING等效项ON和USING关键字并不等效,但它们是类似的。ON返回多列,USING返回一列。FROMAJOINBONA。xB。xFROMAJOINBUSING(x) 虽然ON和USING不等效,但如果您指定要返回的列,它们可以返回相同的结果。SELECTxFROMAJOINBUSING(x);SELECTA。xFROMAJOINBONA。xB。x; 序列中的联接操作FROM子句可以在一个序列中包含多个JOIN运算。JOIN按从左到右的顺序绑定。FROMAJOINBUSING(x)JOINCUSING(x)AJOINBUSING(x)result1result1JOINCUSING(x)result2result2returnvalue插入括号来对JOIN分组FROM((AJOINBUSING(x))JOINCUSING(x))AJOINBUSING(x)result1result1JOINCUSING(x)result2result2returnvalue通过括号,您可以将JOIN分组,从而使它们按不同的顺序绑定:FROM(AJOIN(BJOINCUSING(x))USING(x))BJOINCUSING(x)result1AJOINresult1result2result2returnvalueFROM子句可以有多个联接。如果FROM子句中没有逗号交叉联接,则联接不需要括号,但括号可增强可读性:FROMAJOINBJOINCJOINDUSING(w)ONB。xC。yONA。zB。x如果子句包含逗号交叉联接,则必须使用括号:FROMA,BJOIN(CJOINDONC。xD。y)ONB。zC。xVALID当逗号交叉联接出现在具有一系列JOIN的查询中时,它们会像其他JOIN类型一样按从左到右的顺序进行分组:FROMAJOINBUSING(x)JOINCUSING(x),DAJOINBUSING(x)result1result1JOINCUSING(x)result2result2CROSSJOINDreturnvalue除非逗号交叉联接带括号,否则它后面不能有RIGHTJOIN或FULLJOINFROMA,BJOINCONTRUEVALIDFROMA,(BRIGHTJOINCONTRUE)VALIDFROMA,(BFULLJOINCONTRUE)VALID相互关联的联接操作FROMAJOINUNNEST(ARRAY(SELECTASSTRUCTFROMBWHEREA。IDB。ID))ASC SELECTFROMRosterJOINUNNEST(ARRAY(SELECTASSTRUCTFROMPlayerStatsWHEREPlayerStats。OpponentIDRoster。SchoolID))ASPlayerMatchesONPlayerMatches。LastNameBuchananLastNameSchoolIDLastNameOpponentIDPointsScoredAdams50Buchanan5013Eisenhower77Buchanan770相关LEFTJOIN的常见模式是在右侧执行UNNEST运算,并引用左侧输入引入的某个列的数组。对于该数组为空或NULL的行,UNNEST运算在右侧的输入上不生成行。在这种情况下,系统会创建右侧输入对应列中具有NULL条目的行,以便与左侧输入中的行进行联接。SELECTA。name,item,ARRAYLENGTH(A。items)itemcountfornameFROMUNNEST(〔STRUCT(firstASname,〔1,2,3,4〕ASitems),STRUCT(secondASname,〔〕ASitems)〕)ASALEFTJOINA。itemsASitem;nameitemitemcountfornamefirst14first24first34first44secondNULL0对于相关CROSSJOIN,当右侧的输入对于左侧的某个行为空时,则从结果中删除最后一行SELECTA。name,itemFROMUNNEST(〔STRUCT(firstASname,〔1,2,3,4〕ASitems),STRUCT(secondASname,〔〕ASitems)〕)ASACROSSJOINA。itemsASitem;nameitemfirst1first2first3first4WHERE子句WHEREboolexpressionboolexpression可以包含多个子条件SELECTFROMRosterWHERESTARTSWITH(LastName,Mc)ORSTARTSWITH(LastName,Mac);GROUPBY子句GROUPBY{expression〔,。。。〕ROLLUP(expression〔,。。。〕)}SELECTSUM(PointsScored),LastName,FirstNameFROMPlayerStatsGROUPBYLastName,FirstName;SELECTSUM(PointsScored),LastName,FirstNameFROMPlayerStatsGROUPBY2,FirstName;SELECTSUM(PointsScored),LastNameaslastnameFROMPlayerStatsGROUPBYlastname;SELECTa,b,SUM(c)FROMInputGROUPBYROLLUP(a,b);使用汇总列表(a,b)。结果将包括对分组集(a,b)、(a)和包括所有行的()进行GROUPBY操作的结果。SELECTNULL,NULL,SUM(c)FROMInputUNIONALLSELECTa,NULL,SUM(c)FROMInputGROUPBYaUNIONALLSELECTa,b,SUM(c)FROMInputGROUPBYa,b;WITHSalesAS(SELECT123ASsku,1ASday,9。99ASpriceUNIONALLSELECT123,1,8。99UNIONALLSELECT456,1,4。56UNIONALLSELECT123,2,9。99UNIONALLSELECT789,3,1。00UNIONALLSELECT456,3,4。25UNIONALLSELECT789,3,0。99)SELECTday,SUM(price)AStotalFROMSalesGROUPBYROLLUP(day); WITHSalesAS(SELECT123ASsku,1ASday,9。99ASpriceUNIONALLSELECT123,1,8。99UNIONALLSELECT456,1,4。56UNIONALLSELECT123,2,9。99UNIONALLSELECT789,3,1。00UNIONALLSELECT456,3,4。25UNIONALLSELECT789,3,0。99)SELECTsku,day,SUM(price)AStotalFROMSalesGROUPBYROLLUP(sku,day)ORDERBYsku,day; HAVING子句HAVINGboolexpressionSELECT列表中的聚合函数SELECTLastName,SUM(PointsScored)AStotalFROMPlayerStatsGROUPBYLastNameHAVINGtotal15;HAVING子句中的聚合函数SELECTLastNameFROMPlayerStatsGROUPBYLastNameHAVINGSUM(PointsScored)15;SELECTLastName,COUNT()FROMPlayerStatsGROUPBYLastNameHAVINGSUM(PointsScored)15;ORDERBY子句ORDERBYexpression〔{ASCDESC}〕〔{NULLSFIRSTNULLSLAST}〕〔,。。。〕NULLSFIRSTNULLSLAST:NULLSFIRST:在非null值之前对null值进行排序。NULLSLAST:在非null值之后对null值进行排序。ASCDESC:按expression值的升序或降序顺序对结果进行排序。ASC为默认值。如果未使用NULLSFIRST或NULLSLAST指定null排序,则:如果排序顺序为升序,系统会默认应用NULLSFIRST。如果排序顺序为降序,系统会默认应用NULLSLAST。使用默认排序顺序(升序)SELECTx,yFROM(SELECT1ASx,trueASyUNIONALLSELECT9,trueUNIONALLSELECTNULL,false)ORDERBYx;xyNULLfalse1true9true使用默认排序顺序(升序),但最后返回null值。SELECTx,yFROM(SELECT1ASx,trueASyUNIONALLSELECT9,trueUNIONALLSELECTNULL,false)ORDERBYxNULLSLAST;xy1true9trueNULLfalseQUALIFY子句 QUALIFY子句过滤窗口函数的结果。QUALIFY子句或SELECT列表中必须存在窗口函数。QUALIFYboolexpressionSELECTitem,RANK()OVER(PARTITIONBYcategoryORDERBYpurchasesDESC)asrankFROMProduceWHEREProduce。categoryvegetableQUALIFYrank3itemrankkale1lettuce2cabbage3SELECTitemFROMProduceWHEREProduce。categoryvegetableQUALIFYRANK()OVER(PARTITIONBYcategoryORDERBYpurchasesDESC)3itemkalelettucecabbageWINDOW子句 WINDOW子句定义了一系列命名窗口。命名窗口表示表中要使用窗口函数的一组行。命名窗口可通过窗口规范进行定义,也可以引用其他命名窗口。如果引用了另一命名窗口,则引用窗口的定义必须在引用窗口之前定义。WINDOWnamedwindowexpression〔,。。。〕namedwindowexpression:namedwindowAS{namedwindow(〔windowspecification〕)}SELECTitem,purchases,category,LASTVALUE(item)OVER(itemwindow)ASmostpopularFROMProduceWINDOWitemwindowAS(PARTITIONBYcategoryORDERBYpurchasesROWSBETWEEN2PRECEDINGAND2FOLLOWING)SELECTitem,purchases,category,LASTVALUE(item)OVER(d)ASmostpopularFROMProduceWINDOWaAS(PARTITIONBYcategory),bAS(aORDERBYpurchases),cAS(bROWSBETWEEN2PRECEDINGAND2FOLLOWING),dAS(c)SELECTitem,purchases,category,LASTVALUE(item)OVER(cROWSBETWEEN2PRECEDINGAND2FOLLOWING)ASmostpopularFROMProduceWINDOWaAS(PARTITIONBYcategory),bAS(aORDERBYpurchases),cASb集合运算符setoperation:queryexprsetoperatorqueryexprsetoperator:UNION{ALLDISTINCT}INTERSECTDISTINCTEXCEPTDISTINCT对于UNIONALL,R将在结果中正好出现mn次。对于UNIONDISTINCT,先计算UNION,再计算DISTINCT,因此R恰好出现一次。对于INTERSECTDISTINCT,先计算上述结果,再计算DISTINCT。对于EXCEPTDISTINCT,如果m0且n0,则行R在输出中出现一次。如果输入查询超过两个,则上述运算会进行泛化,并且输出结果与输入从左到右递增组合的情形相同。query1UNIONALL(query2UNIONDISTINCTquery3)query1UNIONALLquery2UNIONALLquery3 》》》UNION UNION运算符将每个查询的结果集中的列进行配对并以垂直方式连接这些列,以此来合并两个或更多输入查询的结果集。 》》》INTERSECT INTERSECT运算符返回在左侧和右侧输入查询的结果集中都能找到的行。与EXCEPT不同,输入查询的定位(INTERSECT运算符的左侧和右侧)无关紧要。 》》》EXCEPT EXCEPT运算符返回左侧输入查询中不存在于右侧输入查询中的行。SELECTFROMUNNEST(ARRAYint64〔1,2,3〕)ASnumberEXCEPTDISTINCTSELECT1;number23LIMIT和OFFSET子句LIMIT指定INT64类型的非负count,返回的行数不会超过count。LIMIT0返回0行。 如果存在集合运算,则将在集合运算求值后应用LIMIT。 OFFSET指定在应用LIMIT之前要跳过的非负行数。skiprows的类型为INT64。LIMITcount〔OFFSETskiprows〕SELECTFROMUNNEST(ARRAYSTRING〔a,b,c,d,e〕)ASletterORDERBYletterASCLIMIT2letterabSELECTFROMUNNEST(ARRAYSTRING〔a,b,c,d,e〕)ASletterORDERBYletterASCLIMIT3OFFSET1letterbcdWITH子句 WITH子句包含一个或多个常用的表表达式(CTE)。CTE充当临时表,您可以在单个查询表达式中引用该表。WITH〔RECURSIVE〕{nonrecursivecterecursivecte}〔,。。。〕RECURSIVE关键字在WITH子句中启用递归。如果此关键字不存在,则只能包含非递归通用表表达式(CTE)。如果存在此关键字,则您可以同时使用递归和非递归CTE。在WITH子句中更改CTE可见性。如果此关键字不存在,则CTE只会向WITH子句中定义在它后面的CTE显示。如果此关键字存在,则CTE会向定义了它的WITH子句中的所有CTE显示。非递归CTE非递归CTE不能引用自身。非递归CTE可以通过包含WITH子句的查询表达式进行引用,但会应用规则。nonrecursivecte:ctenameAS(queryexpr)WITHsubQ1AS(SELECTSchoolIDFROMRoster),subQ2AS(SELECTOpponentIDFROMPlayerStats)SELECTFROMsubQ1UNIONALLSELECTFROMsubQ2WITHq1AS(myquery)SELECTFROM(WITHq2AS(SELECTFROMq1)SELECTFROMq2)WITHq1AS(myquery)SELECTFROM(WITHq2AS(SELECTFROMq1),q1resolvestomyqueryq3AS(SELECTFROMq1),q1resolvestomyqueryq1AS(SELECTFROMq1),q1(inthequery)resolvestomyqueryq4AS(SELECTFROMq1)q1resolvestotheWITHsubqueryonthepreviousline。SELECTFROMq1)q1resolvestothethirdinnerWITHsubquery。递归CTE递归CTE会引用其自身。递归CTE可在包含WITH子句的查询表达式中进行引用,但会应用规则。在WITH子句中定义递归CTE时,必须存在RECURSIVE关键字。baseterm:运行递归联合操作的第一次迭代。此术语必须遵循基本术语规则。unionoperator:UNION运算符返回来自基本术语和递归术语的并集的行。借助UNIONALL,迭代N中生成的每一行都会成为最终CTE结果和迭代N1的输入的一部分。如果迭代没有生成要进入下一次迭代的行,则迭代会停止。recursiveterm:运行其余迭代。它必须包含对递归CTE的一个自引用(递归引用)。只有该术语可以包含自引用。该术语必须遵循递归术语规则。recursivecte:ctenameAS(recursiveunionoperation)recursiveunionoperation:basetermunionoperatorrecursivetermbaseterm:queryexprrecursiveterm:queryexprunionoperator:UNIONALLWITHRECURSIVET1AS((SELECT1ASn)UNIONALL(SELECTn1ASnFROMT1WHEREn3))SELECTnFROMT1n213WITHRECURSIVET1AS((SELECT1ASn)UNIONALL(SELECTn2FROMT1WHEREn4))SELECTFROMT1ORDERBYnn135只要每个递归的周期长度为1,同一递归CTE中有多个子查询则可以接受。递归条目也可以依赖于非递归条目,反之亦然。WITHRECURSIVET0AS(SELECT1ASn),T1AS((SELECTFROMT0)UNIONALL(SELECTn1FROMT1WHEREn4)),T2AS((SELECT1ASn)UNIONALL(SELECTn1FROMT2WHEREn4)),T3AS(SELECTFROMT1INNERJOINT2USING(n))SELECTFROMT3ORDERBYnn1234只要聚合函数未在所定义的表中聚合,便可以在子查询中进行调用:WITHRECURSIVET0AS(SELECTFROMUNNEST(〔60,20,30〕)),T1AS((SELECT1ASn)UNIONALL(SELECTn(SELECTCOUNT()FROMT0)FROMT1WHEREn4))SELECTFROMT1ORDERBYnn14 CTE规则和限制条件 CTE可见性