-- MySQL中的語句都能用,不再一一描述,只記錄一些不同 詳情見Inceptor 6.0文檔 3.4.4查詢語句這節 -- 查詢語句 SELECT開頭,可以通過添加多種從句從Inceptor中的表中獲得信息。 -- 最常使用的數據查詢語句的語法如下: SELECT [ALL | DISTINCT] select_expression, select_expression, ... FROM table_reference [WHERE where_condition] [GROUPBY col_list] [CLUSTERBY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list] ] [LIMIT (M,)N | [OFFSET M ROWSFETCHNEXT | FIRST] N ROWSONLY]; -- 如果不指定數據庫,Inceptor默認從default數據庫中尋找用戶指定的查詢來源。要指定數據庫,可以用"."來表示表和數據庫的從屬關系,比如 SELECT * FROM database_name.table_name; -- 或者還可以在查詢前使用USE語句來指定當前數據庫: USE database_name; SELECT query_specifications; USE default; 1、-- 過濾 -- WHERE在SELECT之前過濾,而HAVING在SELECT之后過濾。
2、-- ORDER BY, SORT BY, DISTRIBUTE BY和CLUSTER BY 略 3、-- GROUP BY 3.1 --單列GROUP BY -- 單列GROUP BY就是GROUP BY 子句中只有一列。 --舉例我們可以用對transactions表用GROUP BY查看各個賬戶進行交易的次數: SELECT acc_num, COUNT(trans_id) AS cnt FROM transactions GROUP BY acc_num; --GROUP BY前面的列只能包含聚合函數和被分組列 --注意:一次查詢可以使用多個聚合函數,但是聚合函數的參數中的DISTINCT列必須相同。 3.2 -- GROUP BY (number) SELECT select_expression1, select_expression2, ... GROUP BY groupby_expression [,groupby_expression, ...] -- Inceptor中支持group by 1 (第一列),group by 2(第二列)這類用法,其中數字1是指select_expression的位置。 3.3 --多列GROUP BY -- 多列GROUP BY就是GROUP BY子句中有不止一列。 SELECT acc_num, trans_type, COUNT(trans_id) AS cnt FROM transactions GROUP BY acc_num, trans_type; 3.4 --用表達式GROUP BY -- tdh_todate是Inceptor自帶的函數,可以用來提取trans_time 中的月份: SELECT tdh_todate(trans_time, 'yyyyMMddHHmmss', 'MM') AS date,COUNT(trans_id) AS cnt FROM transactions GROUP BY tdh_todate(trans_time, 'yyyyMMddHHmmss', 'MM'); 3.5 --在GROUP BY子句中過濾:HAVING 子句 -- 如果過濾條件受帶GROUP BY的查詢結果影響,那么就不能用WHERE子句來過濾,而要用HAVING子句 SELECT acc_num, MAX(price*amount) AS max_value FROM transactions WHERE trans_time<'20140630235959' GROUP BY acc_num HAVING MAX(price*amount)>5000; --有兩個過濾條件:WHERE子句中的過濾條件和查詢結果無關,而HAVING子句中的過濾要在查詢結束后才執行。 --注意:在WHERE子句中不能有聚合函數,因為Inceptor在執行GROUP BY子句之前就會執行WHERE子句。HAVING子句中可以含有聚合函數: 3.6 -- SELECT DISTINCT + GROUP BY --當執行形如SELECT DISTINCT <key> + GROUP BY的語句之前必須先打開開關inceptor.select.distinct.group.by.enabled。該開關默認處於關閉狀態,如果不啟動則出現語法報錯。 SET inceptor.select.distinct.group.by.enabled = TRUE; SELECT DISTINCT acc_num, COUNT(1)FROM transactions GROUP BY acc_num; 3.7 -- GROUP BY 擴展:ROLLUP/CUBE/GROUPING SETS -- ROLLUP -- 生成聚合行、超聚合行和總計行。舉例來說,下面的代碼 SELECT a, b, c, SUM(expression) FROM table GROUP BY ROLLUP(a, b, c); -- 會為 (a, b, c)、(a, b) 和 (a) 值的每個唯一組合生成一個帶有小計的行。還將計算一個總計行。 -- 詳細地說,以上代碼會計算以下四條查詢並將結果一並輸出: SELECT a, b, c, sum(expression) FROM table GROUP BY a, b, c; -- (a, b, c)組合小計 SELECT a, b, NULL, sum(expression) FROM table GROUP BY a, b; -- (a, b)組合小計 SELECT a, NULL, NULL, sum(expression) FROM table GROUP BY a; -- (a)組合小計 SELECT NULL, NULL, NULL, sum(expression) FROM table; -- 總計 -- CUBE -- 生成聚合行、超聚合行、交叉表格行和總計行 SELECT a, b, c, SUM (expression) FROM table GROUP BY CUBE (a,b,c); -- 會為 (a, b, c)、(a, b)、(a, c)、(b, c)、(a)、(b) 和 (c) 值的每個唯一組合生成一個帶 有小計的行,還會生成一個總計行。 -- 詳細來說,以上代碼會進行以下八條計算,並將結果一並輸出: SELECT a, b, c, sum(expression) FROM table GROUP BY a, b, c; -- (a, b, c)組合小計 SELECT a, b, NULL, sum(expression) FROM table GROUP BY a, b; -- (a, b)組合小計 SELECT a, NULL, c, sum(expression) FROM table GROUP BY a, c; -- (a, c)組合小計 SELECT NULL, b, c, sum(expression) FROM table GROUP BY b, c; -- (b, c)組合小計 SELECT a, NULL, NULL, sum(expression) FROM table GROUP BY a; -- (a)組合小計 SELECT NULL, b, NULL, sum(expression) FROM table GROUP BY b; -- (b)組合小計 SELECT NULL, NULL, c, sum(expression) FROM table GROUP BY c; -- (c)組合小計 SELECT NULL, NULL, NULL, sum(expression) FROM table; -- 總計 -- GROUPING SETS -- GROUPING SETS生成交叉表格行。 -- 舉例來說, SELECT a, b, c, sum(expression) FROM table GROUP BY GROUPING SETS(a,b,c); -- 會為 (a)、(b) 和 (c) 值的每個唯一組合生成一個帶有小計的行。 -- 詳細地說,以上代碼會進行以下三條計算,並將結果一並輸出: SELECT a, NULL, NULL, sum(expression) FROM table GROUP BY a; -- (a)組合小計 SELECT NULL, b, NULL, sum(expression) FROM table GROUP BY b; -- (b)組合小計 SELECT NULL, NULL, c, sum(expression) FROM table GROUP BY c; -- (c)組合小計 --FUNC(DISTINCT KEY)+GROUP BY 擴展 --支持形如UDAF(DISTINCT)+GROUP BY [ROLLUP|CUBE|GROUPING SET]的語句。 SELECT COUNT(store), COUNT(type), COUNT(DISTINCT grade)FROM inventory GROUP BY ROLLUP(store, type, grade); 4、-- 多表查詢:JOIN 4.1 -- 笛卡爾連接:Cartesian Join SELECT * FROM join_demo1 JOIN join_demo2 ON 1=1; -- 這樣的表連接會產生大量的數據,而且並不經常具有意義,所以很少出現在實際應用中。 -- 大多數這樣的表連接產生於沒有加JOIN條件的錯誤。 -- 所以為了代碼的清晰,如果真的需要進行笛卡爾積連接,最好使用專門的關鍵詞CROSS JOIN: SELECT table1.col1, table2.col2, ...FROM table1 CROSS JOIN table2 4.2 -- 內連接:INNER JOIN -- 內連接只顯示參與連接的表中有匹配的記錄。JOIN和INNER JOIN在這里用法一樣。 在一次查詢中可以連接兩個以上的表: SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 4.3 -- 外連接:OUTER JOIN -- 內連接會將被連接的兩張表中互相沒有匹配值的紀錄忽略。 -- 如果想要在連接結果中看到沒有匹配值的記錄,則應該使用外連接。 -- 外連接又分為左外連接(left outer join)、右外連接(right outer join)和全外連接(full outer join)。 SELECT student_info.stu_name, course_info.course_name FROM student_info LEFT OUTER JOIN course_info ON (student_info.course_id = course_info.course_id); SELECT student_info.stu_name, course_info.course_name FROM student_info RIGHT OUTER JOIN course_info ON (student_info.course_id = course_info.course_id); SELECT student_info.stu_name, course_info.course_name FROM student_info FULL OUTER JOIN course_info ON (student_info.course_id = course_info.course_id); 4.4 -- 隱式連接:Implicit JOIN -- 隱式JOIN的命令中不含有JOIN…ON…關鍵詞,而是通過WHERE子句作為連接條件將兩張表連接。 SELECT student_info.stu_name, course_info.course_name FROM student_info, course_info WHERE student_info.course_id = course_info.course_id; 4.5 -- 自然連接:NATURAL JOIN -- 使用NATURAL JOIN,用戶可以不需要明確寫出JOIN條件。 -- Inceptor會自動在被連接的兩張表中尋找名字相同的列。如果兩張表table1和table2中存在同名列col1,Inceptor會自動生成JOIN條件table1.col1=table2.col1。 -- 如果Inceptor在被連接的兩張表中找不到同名列,Inceptor會將指令作為無條件的連接,也就是一個笛卡爾積。 SELECT name, trans_idFROM user_info NATURAL JOIN transactions; 4.6 -- 多表連接 -- 可以在一次查詢中用多個JOIN子句連接多張表。 SELECT select_expression, select_expression, ... FROM table_reference [(RIGHT|LEFT|FULL) OUTER] JOIN table_reference ON (join_condition) [(RIGHT|LEFT|FULL) OUTER] JOIN table_reference ON (join_condition) ... -- 每一個JOIN子句都可以是不同的連接(內連接,左/右/全外連接,左半連接等等)。 4.7 -- 重復連接 -- 有時候同一張表在一次查詢中需要和多張其他表連接。假設我們有三張表table1, table2和table3。其中table1要和table2和table3各連接一次。 -- 這種情況下,用戶需要給table1在兩次連接中起兩個不同的化名來讓Inceptor能夠分辨在各子句中table1的角色: SELECT t1.col1, tb1.col2, t2.col1, t3.col,... FROM table1 t1 JOIN table2 t2 ON t1.col1 = t2.col1 INNER JOIN table3 t3 ON t2.col2 = t3.col1 INNER JOIN table1 tb1 ON t3.col = tb1.col2; 4.8 -- 表的自連接 -- 一張表也可以和自己連接,此時需要給表取兩個不同的化名來讓Inceptor能夠分辨在各子句中表的角色。 -- 我們用一個包含了員工信息的表來作為例子。表中含有員工工號,員工姓名,員工的上級工號和入職時間: -- 我們用這張表和自己連接來查詢員工和他們上級的姓名: SELECT e.employee_name, sup.employee_name AS manager_name FROM employee_info e LEFT OUTER JOIN employee_info sup ON (e.sup_id = sup.employee_id); 4.9 -- 左半連接和左半反連接 -- 左半連接用來查看左表中符合和JOIN條件的記錄。左半反連接用來查看左表不符合JOIN條件的記錄。 -- 左半連接和左半反連接都只顯示左表中的記錄。 -- 左半連接可以通過LEFT SEMI JOIN, WHERE… IN 和WHERE EXISTS 中嵌套子查詢來實現。而左半反連接可以通過在LEFT …NOT IN/EXISTS中嵌套子查詢來實現。 4.9.1 -- 左半連接 SELECT t1.num, t1.letter FROM test11 t1 LEFT SEMI JOIN test2 t2 ON t1.num = t2.num; SELECT t1.num, t1.letter FROM test11 t1 WHERE t1.num IN (SELECT t2.num FROM test2 t2 ); SELECT t1.num, t1.letter FROM test11 t1 WHERE EXISTS ( SELECT 1 FROM test2 t2 WHERE t2.num = t1.num); 4.9.2 --左半反連接 SELECT t1.num, t1.letter FROM test11 t1 WHERE t1.num NOT IN (SELECT t2.num FROM test2 t2 ); SELECT t1.num, t1.letter FROM test11 t1 WHERE NOT EXISTS (SELECT 1 FROM test2 t2 WHERE t1.num = t2.num); 4.10 --不等價連接 -- 要執行不等價連接,ON子句中的連接條件必須是等價條件,不等價條件體現在WHERE子句中的過濾條件中。 -- 不等價連接和笛卡爾積相像,很容易返回大量結果(在兩表行數乘積的級別),ON子句中要求有等價條件可以限制結果的數量。 -- 如果確定不需要限制結果數量,可以在ON子句中的等價條件里放一個永遠成立的等式,比如1=1。 -- 執行這樣的操作必須格外小心。 -- 假設公司想要在員工中間組織一次下棋比賽,每對員工之間都要進行一場比賽,我們想要生成包含所有員工對的數據: SELECT e1.employee_name, e2.employee_name FROM employee_info e1 JOIN employee_info e2 ON 1 = 1 WHERE e1.employee_name <> e2.employee_name; -- 這里join條件是e1.employee_name<> e2.employee_name,因為一個人不能和自己比賽。 -- 這條指令會導致每個 員工對都會重復一次,所以我們可以修改連接條件為e1.employee_name > e2.employee_name: SELECT e1.employee_name, e2.employee_name FROM employee_info e1 JOIN employee_info e2 ON 1 = 1 WHERE e1.employee_name > e2.employee_name; 4.11 -- MAP JOIN -- 如果兩張被連接的表中有一張比較小(100MB以下),那么可以通過MAP JOIN來提高執行速度。 --MAP JOIN會將小表放入內存中,在map階段直接拿另一張表的數據和內存中表數據做匹配,由於省去了shuffle,速度會比較快。 SELECT /*+ MAPJOIN(b) */ select_expression, select_expression, ... FROM table_reference JOIN table_reference ON join_condition -- Inceptor已經有了自動MAP JOIN的功能,就是在有一張表在100MB一下時,Inceptor會自動執行MAP JOIN。 --所以用戶可以無需特別指明使用MAP JOIN。如果在參與JOIN的表都較大時卻指明使用MAP JOIN,可能會導致內存溢出。 5 -- 子查詢 -- 子查詢是嵌套在查詢語句中的查詢語句。子查詢根據是否和包含它的父查詢的結果相關分為非關聯子查詢和關聯子查詢。 -- Inceptor高度支持子查詢的各種嵌套:非關聯子查詢可以在FROM,WHERE,SELECT和HAVING子句中嵌套。 -- 關聯子查詢可以在WHERE和SELECT中嵌套,而不能在HAVING和FROM子句中嵌套。 5.1 -- 非關聯子查詢 -- 非關聯子查詢內容和包含它的父查詢結果不相關。當子查詢和父查詢不相關,Inceptor會在執行父查詢之前先執行完成子查詢。 5.1.1 -- 在WHERE子句中嵌套 -- 單行單列的子查詢結果 SELECT name, acc_num, citizen_id, acc_level, reg_date FROM user_info WHERE reg_date = ( SELECT MIN(reg_date) FROM user_info ); -- 單行多列的子查詢結果 -- IN運算符 當子查詢結果有不止一條記錄,要用IN來表示查詢結果須是子查詢結果集合中的元素: SELECT employee_name FROM employee_info WHERE employee_id IN ( SELECT sup_id FROM employee_info ); SELECT employee_name FROM employee_info WHERE employee_id NOT IN ( SELECT sup_id FROM employee_info ); 5.1.2 --在FROM子句中嵌套 -- 下例查詢所有進行過交易的賬戶持有人名字: SELECT DISTINCT name FROM ( SELECT name FROM user_info JOIN transactions ON user_info.acc_num = transactions.acc_num ); -- 下例查詢所有個人平均交易額大於所有平均交易額的用戶名字 SELECT name FROM user_info JOIN ( SELECT transactions.acc_num, AVG(price*amount) avg_trans FROM transactions GROUP BY transactions.acc_num ) temp ON user_info.acc_num = temp.acc_num WHERE avg_trans > (SELECT AVG(price*amount) FROM transactions); 5.1.3 --在SELECT子句中嵌套 -- 下例查看各用戶的個人平均交易額和所有交易的平均交易額的差: SELECT acc_num, AVG(price*amount) - (SELECT AVG(price*amount) FROM transactions) AS avg_gap FROM transactions GROUP BY acc_num; 5.1.4 --在HAVING子句中嵌套 -- 下例查詢最大一筆交易的執行賬戶和交易額 SELECT acc_num, MAX(price*amount) AS max_value FROM transactions GROUP BY acc_num HAVING MAX(price*amount) = ( SELECT max(price*amount) FROM transactions ); 5.2 -- 關聯子查詢 -- 關聯子查詢的內容和父查詢相關。Inceptor會對每條在父查詢中出現的記錄執行一次子查詢 -- 注意:關聯子查詢中的關聯條件不支持OR,也不支持僅包含非等值比較。 5.2.1 -- 在WHERE子句中嵌套 -- Inceptor支持的WHERE子句嵌套需要滿足以下要求: -- 1. WHERE子句中必須包含至少一條等值關系,如果執行業務沒有客觀要求等值關聯,請用戶手動添加條件“1=1”。這是為了避免資源被貪婪占用導致枯竭,以保證系統的穩定性。 -- 2. 主查詢和子查詢之間必須用標量比較運算符連接(包括‘>’、‘<’、‘=’、‘<>’、‘>=’、‘<=’)。 -- 3. 要求子查詢的結果必須是一行一列的返回,即標量。 -- 4. 子查詢中允許有等值與非等值條件 -- 下例查詢了總共進行過3筆交易的賬戶持有人姓名和賬戶號碼。 注意,當關聯子查詢中有COUNT函數時,必須打開開關set hive.support.subquery.join.conversion.count=true。 set hive.support.subquery.join.conversion.count=true; SELECT user_info.name, user_info.acc_num FROM user_info WHERE 3=( SELECT COUNT(*) FROM transactions WHERE user_info.acc_num = transactions.acc_num ); SELECT COUNT(*) AS cnt FROM TABLEA A, TABLEB B WHERE ((1=1)) AND ((A.salary > (SELECT (SUM(csA.age) - 114) FROM TABLEA csA, TABLEB csB WHERE (A.age = csA.age) AND ((csB.salary / -9) = (A.salary * -79))))); 5.2.2 -- EXISTS和NOT EXISTS -- 在WHERE中嵌套子查詢時經常會用到EXISTS和NOT EXISTS。當我們只關心子查詢有記錄返回,而不關心子查詢返回的記錄內容和記錄條數時,我們就可以用WHERE EXISTS。 -- WHERE EXISTS用來查看子查詢中的關系是否成立並且返回使得子查詢中關系成立的記錄(也就是過濾掉使得子查詢中的關系不成立的記錄)。 -- 比如,假設查詢買過單股價格在100元以內的股票的用戶,語句應為 SELECT user_info.name, user_info.acc_num FROM user_info WHERE EXISTS ( SELECT 1 FROM transactions WHERE user_info.acc_num = transactions.acc_num AND price < 100 ); -- 事實上,我們建議如果WHERE子句需要滿足某種關系(大於、等於、小於、不等於,等等),盡量使用WHERE EXISTS並在子查詢中表達關系,而不是通過比較子查詢的結果和別的量來表達關系。 -- WHERE NOT EXISTS則用來查看子查詢中的關系是否成立並且返回使得子查詢中關系不成立的記錄(也就是過濾掉使得子查詢中的關系成立的記錄)。 -- 下例查詢了所有沒有進行交易的賬戶持有人姓名和賬戶號碼 SELECT user_info.name, user_info.acc_num FROM user_info WHERE NOT EXISTS ( SELECT 1 FROM transactions WHERE user_info.acc_num = transactions.acc_num ); -- 這里,WHERE NOT EXISTS子句中嵌套的子查詢返回的是一個常數,這充分體現了EXISTS和NOT EXISTS僅關心子查詢是否返回結果,而不關心返回的結果是什么 。 5.2.3 -- 在SELECT子句中嵌套 -- 下例返回所有賬戶的持有人姓名,賬戶號碼和賬戶平均交易額: SELECT user_info.name, user_info.acc_num, ( SELECT AVG(price*amount) FROM transactions WHERE user_info.acc_num = transactions.acc_num ) FROM user_info; 5.3 -- 子查詢的多層嵌套 SELECT name FROM ( SELECT name, acc_num FROM ( SELECT name, acc_num, password FROM ( SELECT name, acc_num, password, bank_acc FROM user_info) ) ); 6 -- 集合運算:UNION/INTERSECT/EXCEPT -- Inceptor提供三種方法來對SELECT語句結果進行集合運算:並集(UNION)、交集(INTERSECT)和減去(EXCEPT)。而每個集合運算都有兩種選擇, 帶有ALL和不帶有ALL -- UNION和INTERSECT帶上ALL不去重 -- EXCEPT和EXCEPT ALL做集合減法。 -- A EXCEPT B 將A中所有和B重合的記錄除去,然后返回去重后的A中剩下的記錄。 -- A EXCEPT ALL B 將A中所有和B重合的記錄除去,然后不去重的A中剩下的記錄。
