testbook

插入数据:INSERT

INSERT语句可以用于将查询结果插入表中和将查询结果写入文件系统中。

将查询结果插入表中

  • 单次插入(single insert)
    语法
    INSERT [OVERWRITE|INTO] TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)[IF NOT EXISTS]]select_statement1 FROM from_statement
    
    举例
    之前,我们用LOAD语句为分区表partition_user_info按分区填入过数据。用INSERT语句和已有的未分区表user_info也可以像分区表partition_user_info填入数据:
    [$host] transwarp> INSERT INTO TABLE partition_user_info (acc_level='A')
                       SELECT name, acc_num, password, citizen_id, bank_acc, reg_date
                       FROM user_info WHERE acc_level='A';
    
  • 多次插入(multiple inserts)
    在单次插入中,每插入一个分区都伴随一次查询,Inceptor就需要扫描整张表。如果查询结果中分区很多,重复执行单次插入会导致不必要地重复同一次查询,这时我们可以用多次插入将一次查询的结果一次插入多个分区内。注意,插入的表也可以不同:
    语法
    FROM from_statement
    INSERT [OVERWRITE|INTO] TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1
    [INSERT [OVERWRITE|INTO] TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2]
    [INSERT [OVERWRITE|INTO] TABLE tablename2 [PARTITION ...] select_statement2] ...
    
    在单次插入和多次插入中,插入查询结果时必须指定插入的分区。

    举例
    在之前的例子中,我们创建过一张以acc_level分区的用户信息表partition_user_info。现在我们建两张和partition_user_info的schema相同的表,并向表内的分区插入数据:
    [$host] transwarp> CREATE TABLE partition_user_info1;
    [$host] transwarp> CREATE TABLE partition_user_info2;
    [$host] transwarp> FROM user_info
                         INSERT INTO TABLE partition_user_info1 PARTITION (acc_level = 'A')
                         SELECT  name, acc_num, password, citizen_id, bank_acc, reg_date
                         WHERE acc_level = 'A'
                         INSERT INTO TABLE partition_user_info1 PARTITION (acc_level = 'B')
                         SELECT  name, acc_num, password, citizen_id, bank_acc, reg_date
                         WHERE acc_level = 'B'
                         INSERT INTO TABLE partition_user_info2 PARTITION (acc_level = 'C')
                         SELECT  name, acc_num, password, citizen_id, bank_acc, reg_date
                         WHERE acc_level = 'C'
                         INSERT INTO TABLE partition_user_info2 PARTITION (acc_level = 'D')
                         SELECT  name, acc_num, password, citizen_id, bank_acc, reg_date
                         WHERE acc_level = 'D';
    [$host] transwarp> SELECT * FROM partition_user_info1;
    马从筠  6513065 115591  140400198711012307      96080357291141  20110101        A
    魏向卉  3912384 841242  522632199301029404      68537153578048  20091202        A
    邱坤    0700735 737297  340811199211252278      14388242322818  20121024        A
    华微    5224133 531547  420529198911075631      32638281095907  20080214        B
    [$host] transwarp> SELECT * FROM partition_user_info2;
    祝韩恒  6670192 205239  230801197908126178      73790369990971  20100101        C
    潘营泽  6600641 990590  511521198705077435      48471135593608  20110430        C
    管淑艳  2394923 783438  330683198005210864      99913863445174  20141003        C
    宁新瑶  4580952 986634  420822199001119507      97711008856576  20081031        D
    李韩瑶  2755506 015859  310230197912126559      42412396242237  20110916        D
    
  • 动态分区插入(dynamic partition inserts)
    查询结果中分区很多带来的另外一个问题是需要手工输入非常多的INSERT语句。动态分区插入可以不用指定分区,而是让Inceptor根据查询结果自动推断出分区。
    语法
    INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement;
    INSERT INTO TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement;
    
    注意
    动态分区时要格外注意分区键的选择,避免出现分区过多。
  • 说明
    • INSERT OVERWRITE会用查询结果将插入目标中原有的文件覆盖。
    • INSERT INTO会将查询结果插入在原有文件的结尾
    将查询结果写入文件系统中
    Inceptor支持将查询结果写入文件系统中指定的目录下。
    语法
    单次插入
    INSERT OVERWRITE [LOCAL] DIRECTORY directory1
      [ROW FORMAT row_format] [STORED AS file_format]
      SELECT ... FROM ...
    row_format
      : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
            [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
            [NULL DEFINED AS char]
    
    多次插入
    FROM from_statement
    INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
    [INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...
    
    说明
    • 目标目录可以是完整的URI。如果不指明scheme和authority,Inceptor会用指定namdenode URL的hadoop配置变量 fs.default.name中的scheme和authority。
    • 如果加上LOCAL选项,Inceptor会将数据写入本地。
    • 写进文件系统的数据会以^A分列、\n分行的形式序列化。不是原声数据类的列会被序列化成JSON格式。
    注意
    • 可以将用INSERT OVERWRITE写入HDFS上目录、本地目录、表和分区在同一次查询中混用
    • 用INSERT OVERWRITE将数据写入HDFS目录是从Inceptor提取大量数据的最好方法。Inceptor可以在一个map-reduce作业中将数据并行写入HDFS。
    • 目标目录如果已经存在,内容会被覆盖。
  • 将数据插入分桶表
    注意: 在向分区表写入数据时,用户需要手动确保数据写入正确的分区内,Inceptor没有信息来判断数据是否在正确的分区中。类似的,在向分桶表中写入数据时,Inceptor也不会自动确保按照建表时指定的方式分桶。所以,在向分桶表写入数据前,要将hive.enforce.bucketing设置为true。
    举例
    [$host]transwarp> CREATE TABLE user_info_bucketed (
                    > name STRING,
                    > acc_num STRING,
                    > password STRING,
                    > citizen_id STRING,
                    > bank_acc STRING,
                    > reg_date STRING)
                    > PARTITIONED BY (acc_level STRING)
                    > CLUSTERED BY (acc_num) INTO 25 BUCKETS;
    [$host]transwarp> set hive.enforce.bucketing = true;
    [$host]transwarp> FROM user_id
                    > INSERT OVERWRITE TABLE user_info_bucketed
                    > PARTITION (acc_level='A')
                    > SELECT name, acc_num, password, citizen_id, bank_acc, reg_date
                    >WHERE acc_level = 'A';