Todos os produtos
Search
Central de documentação

MaxCompute:SELECT TRANSFORM

Última atualização: Jun 26, 2026

O comando SELECT TRANSFORM encaminha linhas de uma tabela do MaxCompute para um script externo ou comando shell e mapeia a saída padrão do script de volta para colunas SQL. Esse recurso permite executar lógicas em AWK, Python, Perl, Shell ou Java diretamente em uma consulta SQL, sem criar uma função de valor de tabela definida pelo usuário (UDTF).

Quando usar o SELECT TRANSFORM

Tanto o SELECT TRANSFORM quanto as UDTFs processam linhas com código personalizado, mas cada um é mais adequado a cenários específicos:

Dimensão

SELECT TRANSFORM

UDTF

Esforço de desenvolvimento

Basta escrever um comando shell ou script inline diretamente no SQL, sem empacotamento

Exige criar e implantar uma classe Java ou Python

Análise ad hoc

Iteração rápida; funciona com AWK, Python, Perl e Shell sem upload de arquivos

Mais indicado para pipelines de produção

Tipos de dados

Toda entrada e saída é tratada como STRING, exigindo conversão explícita

Suporte completo a tipos de dados na entrada e na saída

Transmissão de dados

Baseada em pipeline do SO; buffer de pipeline de 4 KB (fixo); menor sobrecarga que código baseado em JVM

Sem limite de buffer de pipeline

Parâmetros constantes

Sempre transmitidos ao processo filho

Opcionais

Modelo de processo

Gera um processo filho; aproveita servidores multicore quando a computação é alta e o throughput é baixo

Executa em um único processo

Desempenho com pequenos volumes de dados

Superior — ferramentas nativas como AWK evitam a sobrecarga da JVM

Inferior

Desempenho com grandes volumes de dados

Inferior

Superior

Em resumo: Utilize o SELECT TRANSFORM para análises ad hoc e scripts leves. Para cargas de trabalho de produção com alto throughput, prefira as UDTFs.

Limitações

Os clusters de computação do MaxCompute não incluem PHP nem Ruby. Portanto, não é possível chamar scripts nessas linguagens no MaxCompute.

Sintaxe

SELECT TRANSFORM(<arg1>, <arg2>, ...)
  [ROW FORMAT DELIMITED
    [FIELDS TERMINATED BY '<field_delimiter>' [ESCAPED BY '<character_escape>']]
    [NULL DEFINED AS '<null_value>']]
USING '<unix_command_line>'
  [RESOURCES '<res_name>' [, '<res_name>'...]]
[AS (<col1> [<type>], <col2> [<type>], ...)]
  [ROW FORMAT DELIMITED
    [FIELDS TERMINATED BY '<field_delimiter>' [ESCAPED BY '<character_escape>']]
    [NULL DEFINED AS '<null_value>']]
Você pode substituir o SELECT TRANSFORM pela palavra-chave map ou reduce — ambas são aliases com semântica idêntica. Use o SELECT TRANSFORM para maior clareza.

Parâmetros

Parâmetro

Obrigatório

Descrição

arg1, arg2, ...

Sim

Colunas ou expressões de entrada. Os valores são convertidos implicitamente para STRING, unidos com \t e gravados na entrada padrão do processo filho.

Primeiro ROW FORMAT

Não

Formato dos dados enviados para o processo filho. Padrões: \t (delimitador de campo), \n (delimitador de linha), \N (nulo).

USING '<unix_command_line>'

Sim

Comando usado para iniciar o processo filho. Cria um subprocesso, não uma sessão shell. Recursos do shell, como pipes, loops e redirecionamento de E/S, não estão disponíveis na própria string de comando. Para usar esses recursos, passe um script shell como comando (por exemplo, using 'sh myscript.sh').

RESOURCES '<res_name>'

Não

Arquivos de recurso acessíveis ao processo filho. Alternativa: defina odps.sql.session.resources globalmente (consulte Anexar arquivos de script).

AS (<col1>, <col2>, ...)

Não

Nomes das colunas de saída e tipos opcionais. Se omitido, a saída assume o padrão key STRING, value STRING, onde key é tudo antes do primeiro \t e value é o restante. Não é possível especificar tipos apenas para algumas colunas — especifique tipos para todas ou para nenhuma.

Segundo ROW FORMAT

Não

Formato dos dados lidos da saída padrão do processo filho. Mesmos padrões do primeiro ROW FORMAT.

Restrições do ROW FORMAT

  • Os parâmetros field_delimiter e character_escape aceitam apenas caracteres únicos. Se você especificar uma string com vários caracteres, somente o primeiro será utilizado.

  • O uso de ROW FORMAT com inputRecordReader, outputRecordReader ou SerDe exige o modo compatível com Hive. Adicione set odps.sql.hive.compatible=true; antes da instrução SQL. Esses formatos específicos do Hive podem reduzir a velocidade de execução.

Para consultar a sintaxe completa do ROW FORMAT do Apache Hive, acesse Hive LanguageManual Transform.

Comportamento do formato de dados

Compreender como os dados trafegam entre o MaxCompute e o processo filho evita erros silenciosos.

Entrada para o processo filho:

  • Todos os valores das colunas são convertidos para STRING.

  • As colunas são unidas com \t e gravadas na entrada padrão, com uma linha por registro.

Saída do processo filho:

  • Cada linha da saída padrão se torna uma linha de saída.

  • Os campos são divididos por \t (ou pelo delimitador definido no segundo ROW FORMAT).

  • Se a cláusula AS for omitida, a saída será mapeada como key STRING, value STRING — o campo anterior ao primeiro \t torna-se key e as partes seguintes tornam-se value. Isso equivale a AS(key, value).

  • Se as colunas de saída não forem do tipo STRING, o MaxCompute chama CAST implicitamente para converter os valores. Uma exceção de tempo de execução poderá ocorrer se a conversão falhar.

Exemplos de scripts inline

Para transformações simples, escreva o script diretamente na instrução SQL. Não é necessário fazer upload de recursos.

Shell

Gere 50 linhas numeradas de 1 a 50:

SELECT TRANSFORM('for i in `seq 1 50`; do echo $i; done') USING 'sh' AS (data);

Saída:

+------+
| data |
+------+
| 1    |
| 2    |
| ...  |
| 50   |
+------+

Python

Gere 50 linhas numeradas de 1 a 50:

SELECT TRANSFORM('for i in xrange(1, 51):  print(i);') USING 'python' AS (data);

AWK

Extraia a segunda coluna de uma tabela:

-- Create and populate a test table
CREATE TABLE testdata (c1 BIGINT, c2 BIGINT);
INSERT INTO TABLE testdata VALUES (1, 4), (2, 5), (3, 6);

-- Extract c2 using AWK
SELECT TRANSFORM(*) USING "awk '//{print $2}'" AS (data) FROM testdata;

Saída:

+------+
| data |
+------+
| 4    |
| 5    |
| 6    |
+------+

Perl

Retorne todas as colunas (demonstrando a saída padrão key/value quando AS é omitido):

CREATE TABLE testdata (c1 BIGINT, c2 BIGINT);
INSERT INTO TABLE testdata VALUES (1, 4), (2, 5), (3, 6);

SELECT TRANSFORM(testdata.c1, testdata.c2)
USING "perl -e 'while($input = <STDIN>){print $input;}'"
FROM testdata;

Saída (sem cláusula AS — assume o padrão key, value):

+-----+-------+
| key | value |
+-----+-------+
| 1   | 4     |
| 2   | 5     |
| 3   | 6     |
+-----+-------+

Anexar arquivos de script

Para lógicas complexas, faça upload de um arquivo de script como recurso do MaxCompute e referencie-o na cláusula USING.

Usando a cláusula RESOURCES

Especifique o recurso inline na instrução:

SELECT TRANSFORM(...) USING 'python myplus.py' RESOURCES 'myplus.py' AS (...) FROM ...;

Usando uma configuração no nível da sessão

Defina os recursos uma única vez para todas as instruções SELECT TRANSFORM da sessão:

set odps.sql.session.resources=myplus.py,bar.txt;

Separe vários arquivos de recurso por vírgulas. Após essa configuração entrar em vigor, todas as instruções SELECT TRANSFORM subsequentes na sessão poderão acessar os recursos listados sem precisar especificar RESOURCES em cada instrução.

Exemplo de script Python

  1. Crie o arquivo myplus.py:

    #!/usr/bin/env python
    import sys
    
    line = sys.stdin.readline()
    while line:
        token = line.split('\t')
        if (token[0] == '\\N') or (token[1] == '\\N'):
            print('\\N')
        else:
            print(str(token[0]) + '\t' + str(token[1]))
        line = sys.stdin.readline()
  2. Faça upload do arquivo como um recurso do MaxCompute:

    Também é possível fazer upload do arquivo pelo console do DataWorks. Para mais detalhes, consulte Criar e usar recursos do MaxCompute .
    add py ./myplus.py -f;
  3. Execute a transformação:

    CREATE TABLE testdata (c1 BIGINT, c2 BIGINT);
    INSERT INTO TABLE testdata VALUES (1, 4), (2, 5), (3, 6);
    
    SELECT TRANSFORM(testdata.c1, testdata.c2)
    USING 'python myplus.py' RESOURCES 'myplus.py'
    AS (result1, result2)
    FROM testdata;

    Saída:

    +---------+---------+
    | result1 | result2 |
    +---------+---------+
    | 1       | 4       |
    |         | NULL    |
    | 2       | 5       |
    |         | NULL    |
    | 3       | 6       |
    |         | NULL    |
    +---------+---------+

Exemplo de script Java

  1. Escreva e compile uma classe Java e exporte-a como Sum.jar:

    package com.aliyun.odps.test;
    import java.util.Scanner;
    
    public class Sum {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            while (sc.hasNext()) {
                String s = sc.nextLine();
                String[] tokens = s.split("\t");
                if (tokens.length < 2) {
                    throw new RuntimeException("illegal input");
                }
                if (tokens[0].equals("\\N") || tokens[1].equals("\\N")) {
                    System.out.println("\\N");
                }
                System.out.println(Long.parseLong(tokens[0]) + Long.parseLong(tokens[1]));
            }
        }
    }
  2. Faça upload do arquivo JAR como um recurso do MaxCompute:

    add jar ./Sum.jar -f;
  3. Execute a transformação:

    CREATE TABLE testdata (c1 BIGINT, c2 BIGINT);
    INSERT INTO TABLE testdata VALUES (1, 4), (2, 5), (3, 6);
    
    SELECT TRANSFORM(testdata.c1, testdata.c2)
    USING 'java -cp Sum.jar com.aliyun.odps.test.Sum' RESOURCES 'Sum.jar'
    AS cnt
    FROM testdata;

    Saída:

    +-----+
    | cnt |
    +-----+
    | 5   |
    | 7   |
    | 9   |
    +-----+
Tanto Java quanto Python possuem frameworks de UDTF, mas o SELECT TRANSFORM costuma ser mais rápido de escrever, pois não exige dependências nem estrutura de classes. Scripts Java offline são resolvidos a partir de JAVA_HOME ; scripts Python offline, a partir de PYTHON_HOME .

Encadear múltiplas transformações

Passe a saída de uma transformação como entrada da seguinte aninhando instruções SELECT TRANSFORM. Use DISTRIBUTE BY e SORT BY para controlar como as linhas são particionadas e ordenadas antes de cada transformação.

SELECT TRANSFORM(key, value) USING '<cmd2>' FROM
(
    SELECT TRANSFORM(*) USING '<cmd1>' FROM
    (
        SELECT * FROM testdata DISTRIBUTE BY c2 SORT BY c1
    ) t DISTRIBUTE BY key SORT BY value
) t2;

Os aliases map e reduce tornam o padrão map-reduce explícito:

@a := SELECT * FROM data DISTRIBUTE BY col2 SORT BY col1;
@b := map * USING 'cmd1' DISTRIBUTE BY col1 SORT BY col2 FROM @a;
reduce * USING 'cmd2' FROM @b;

Os comandos cmd1 e cmd2 iniciam cada processo filho.