1. 程式人生 > >關於HiveQL的常用語法總結(二)——DML

關於HiveQL的常用語法總結(二)——DML

本節,應該是資料庫作業中使用最頻繁的內容,也是至為重要的一節。但是也不必緊張,無非就是增刪改查,重點在於,為什麼呢?在大資料時代,最重要的兩個主題是分析和挖掘。無論是分析還是挖掘,其基礎都是有資料可依據,那麼就需要將目標資料查找出來,因此這是最基礎的一步,當然也就是用的最多的一步。

本節主要講四個方面:匯入資料,插入資料,刪除資料,查詢資料。

1、匯入資料

一般來說,在SQL建立表後,我們可以使用insert語句插入資料。但在hive中,我們可以使用Load Data載入資料到hive表中。
插入資料到hive表中時,最好使用 LOAD DATA載入大量資料。

根據經驗,應該有三種常用的匯入資料情況:


1、Load data到指定的表
2、Load data到指定表的指定分割槽
3、 insert+select。這一種情況在插入資料章節進行講述。

1、Load data到指定的表
直接將file,載入到指定的表,其中,表可以是普通表或者分割槽表。具體sql如下:

LOAD DATA LOCAL INPATH '/home/admin/test/test.txt' OVERWRITE INTO TABLE test_1  

關鍵字[OVERWRITE]意思是是覆蓋原表裡的資料,不寫則不會覆蓋。
關鍵字[LOCAL]是指你載入檔案的來源為本地檔案,不寫則為hdfs的檔案。
其中
‘home/admin/test/test.txt’是相對路徑
‘/home/admin/test/test.txt’為據對路徑

hive> LOAD DATA LOCAL INPATH './examples/files/kv1.txt' OVERWRITE INTO TABLE pokes;

2、Load data到指定表的指定分割槽
直接將file,載入到指定表的指定分割槽。表本身必須是分割槽表,如果是普通表,匯入會成功,但是資料實際不會被匯入。具體sql如下:

LOAD DATA LOCAL INPATH '/home/admin/test/test.txt' OVERWRITE INTO TABLE test_1 PARTITION(pt=’xxxx)  

load資料,hive支援資料夾的方式,將資料夾內的所有檔案,都load到指定表中。Hdfs會將檔案系統內的某資料夾路徑內的檔案,分散到不同的實際實體地址中。這樣,在資料量很大的時候,hive支援讀取多個檔案載入,而不需要限定在唯一的檔案中。

hive> LOAD DATA LOCAL INPATH './examples/files/kv2.txt' OVERWRITE INTO TABLE invites PARTITION (dt='2008-08-15');

2、插入資料

插入資料,即向一個已經存在的表中插入一些與之相匹配的資料。HQL中有兩種方式:insert into 和insert overwrite。常用的方式有兩種,如下圖所示:
插入資料兩種方式

假設A表和B表的欄位及其資料型別都是匹配的,那麼就有

--用法一
INSERT INTO TABLE A SELECT * FROM B;

--用法二
INSERT OVERWRITE TABLE A SELECT * FROM B;

如果以上A,B表資料維度或者資料型別不一樣,則會報錯,也有可能插入到A表中的資料是來源於多個表的,那樣,就需要將多個表中的資料按照A表字段的順序和型別進行逐個列出。

當然還有一個情況比較重要:

insert into --追加資料
insert overwrite --覆蓋資料,重寫資料

插入檔案資料和分割槽資料

INSERT OVERWRITE TABLE dest3 PARTITION(ds='2008-04-08', hr='12') SELECT src.key WHERE src.key >= 200 and src.key < 300
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/dest4.out' SELECT src.value WHERE src.key >= 300;

3、刪除資料

delect:用於刪除特定行條件,你可以從給定表中刪除所有的行。沒用過。
TRUNCATE:truncate用於刪除所有的行,這個行為在Hive元儲存刪除資料是不可逆的,也較少使用。* 它不能刪除外部表!因為外部表裡的資料並不是存放在Hive Meta store中*

truncate table IF EXISTS employees;

DROP:刪除hive中的表,使用非常頻繁,基本上每次建立表的時候都會用到。

DROP table IF EXISTS employees;

4、查詢資料

查詢資料,即找到目標資料。這一節的內容如果深究的話,可以寫一本書的,因此,在此不做深究,分為基本查詢、聯表查詢和查詢優化。查詢優化將放到另一片部落格中去,這也是很有深度的一個問題,在那裡會分享一些常見的優化策略。
首先來看看關於查詢的官方語法:

SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[CLUSTER BY col_list|[DISTRIBUTE BY col_list][SORT BY| ORDER BY col_list]]
[LIMIT number]

•使用ALLDISTINCT選項區分對重複記錄的處理。預設是ALL,表示查詢所有記錄。DISTINCT表示去掉重複的記錄
•Where 條件
•類似我們傳統SQLwhere 條件
•目前支援 AND,OR ,0.9版本支援between
•IN, NOT IN
•不支援EXIST ,NOT EXIST

ORDER BY與SORT BY的不同
•ORDER BY 全域性排序,只有一個Reduce任務
•SORT BY 只在本機做排序

Limit
•Limit 可以限制查詢的記錄數
SELECT * FROM t1 LIMIT 5

•實現Top k 查詢
•下面的查詢語句查詢銷售記錄最大的 5 個銷售代表。
SET mapred.reduce.tasks = 1 
SELECT * FROM test SORT BY amount DESC LIMIT 5
•REGEX Column Specification
SELECT 語句可以使用正則表示式做列選擇,下面的語句查詢除了 ds 和 hr 之外的所有列:
SELECT `(ds|hr)?+.+` FROM test

4.1基本查詢
如上語法,舉幾個例子。

hive> SELECT a.foo FROM invites a WHERE a.ds='<DATE>';--按條件查詢
hive> INSERT OVERWRITE DIRECTORY '/tmp/hdfs_out' SELECT a.* FROM invites a WHERE a.ds='<DATE>';--將查詢資料輸出到目錄
hive> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/local_out' SELECT a.* FROM pokes a;--將查詢結果輸出至本地目錄

4.2聯表查詢
在hive中,關於聯表查詢:
•Hive 只支援等值連線(equality joins)、外連線(outer joins)和(left semi joins)。Hive 不支援所有非等值的連線,因為非等值連線非常難轉化到 map/reduce 任務

•LEFT,RIGHT和FULL OUTER關鍵字用於處理join中空記錄的情況

•LEFT SEMI JOIN 是 IN/EXISTS 子查詢的一種更高效的實現

•join 時,每次 map/reduce 任務的邏輯是這樣的:reducer 會快取 join 序列中除了最後一個表的所有表的記錄,再通過最後一個表將結果序列化到檔案系統

•實踐中,應該把最大的那個表寫在最後

join 查詢時,需要注意幾個關鍵點

•只支援等值join

•SELECT a.* FROM a JOIN b ON (a.id = b.id)

•SELECT a.* FROM a JOIN b 
    ON (a.id = b.id AND a.department = b.department)

•可以 join 多於 2 個表,例如
SELECT a.val, b.val, c.val FROM a JOIN b 
    ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
•如果join中多個表的 join key 是同一個,則 join 會被轉化為單個 map/reduce 任務

LEFT,RIGHT和FULL OUTER

例如:

SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)

如果你想限制 join 的輸出,應該在 WHERE 子句中寫過濾條件——或是在 join 子句中寫

容易混淆的問題是表分割槽的情況

 SELECT c.val, d.val FROM c LEFT OUTER JOIN d ON (c.key=d.key) 
  WHERE a.ds='2010-07-07' AND b.ds='2010-07-07‘

如果 d 表中找不到對應 c 表的記錄,d 表的所有列都會列出 NULL,包括 ds 列。也就是說,join 會過濾 d 表中不能找到匹配 c 表 join key 的所有記錄。這樣的話,LEFT OUTER 就使得查詢結果與 WHERE 子句無關
解決辦法是:

  SELECT c.val, d.val FROM c LEFT OUTER JOIN d 
     ON (c.key=d.key AND d.ds='2009-07-07' AND c.ds='2009-07-07')

LEFT SEMI JOIN
LEFT SEMI JOIN 的限制是, JOIN 子句中右邊的表只能在 ON 子句中設定過濾條件,在 WHERE 子句、SELECT 子句或其他地方過濾都不行,這樣可以將where子查詢改為聯表查詢。

SELECT a.key, a.value 
  FROM a 
  WHERE a.key in 
   (SELECT b.key 
    FROM B);

可以被重寫為:

SELECT a.key, a.val 
   FROM a LEFT SEMI JOIN b on (a.key = b.key)

UNION ALL
•用來合併多個select的查詢結果,需要保證select中欄位須一致
例如,

select_statement UNION ALL select_statement UNION ALL select_statement ...