Todos os produtos
Search
Central de documentação

MaxCompute:SQL em modo script

Última atualização: Jul 03, 2026

O modo script compila e envia várias instruções SQL como uma única unidade, gerando um plano de execução que entra na fila uma única vez e é executado em um único job. Essa abordagem é ideal para pipelines de dados ETL, processamento em lote periódico e cenários de orquestração de consultas que exigem múltiplas instruções coordenadas. O recurso oferece suporte ao modo normal (execução atômica, padrão) e ao modo de execução passo a passo (execução serial).

  • O modo script não oferece suporte à estimativa de custo. As taxas reais baseiam-se nos seus detalhes de faturamento.

  • Um único script pode referenciar até 10.000 tabelas. Cada referência é contada individualmente, incluindo referências repetidas à mesma tabela e tabelas referenciadas em definições de visualização.

  • Se a preparação de dados de várias fontes terminar em horários muito diferentes (por exemplo, uma às 01:00 e outra às 07:00), não use uma variável de tabela para combiná-las em um único job SQL em modo script.

Casos de uso

  • Reescrever instruções complexas: Decomponha subconsultas profundamente aninhadas em uma sequência legível de atribuições de variáveis de tabela.

  • Construir pipelines com múltiplas instruções: Agrupe instruções logicamente relacionadas em um único job para reduzir a sobrecarga de fila e agendamento. No modo normal, todas as instruções são executadas atomicamente. No modo de execução passo a passo, as instruções são executadas serialmente, o que é ideal para cenários de leitura após escrita ou migrações de outras plataformas. Para mais informações, consulte Modos de execução.

Sintaxe

  • Tipos de instrução: O modo script oferece suporte a instruções SET, algumas instruções DDL e instruções DML. Instruções de exibição de resultados, como DESC e SHOW, não são suportadas.

  • Ordem das instruções: Um script deve seguir a ordem fixa SETDDLDML. Cada seção pode conter zero ou mais instruções, mas não é permitido intercalar instruções de seções diferentes.

-- 1. SET
SET odps.sql.type.system.odps2=true;
[SET odps.stage.reducer.num=xxx;]
[SET odps.sql.step.script.mode=true;] -- Enable step-by-step execution mode
[...]
-- 2. DDL
CREATE TABLE table1 xxx;
[CREATE TEMPORARY TABLE table2 xxx;] -- Create a temporary table
[...]
-- 3. DML&DQL
@var1 := SELECT [ALL | DISTINCT] select_expr, select_expr, ...
        FROM table3
        [WHERE where_condition];
@var2 := SELECT [ALL | DISTINCT] select_expr, select_expr, ...
        FROM table4
        [WHERE where_condition];
@var3 := SELECT [ALL | DISTINCT] var1.select_expr, var2.select_expr, ...
        FROM @var1 JOIN @var2 ON ...;
INSERT OVERWRITE|INTO TABLE [PARTITION (partcol1=val1, partcol2=val2 ...)]
        SELECT [ALL | DISTINCT] select_expr, select_expr, ...
        FROM @var3;    
[@var4 := SELECT [ALL | DISTINCT] var1.select_expr, var1.select_expr, ... FROM @var1 
        UNION ALL | UNION 
        SELECT [ALL | DISTINCT] var2.select_expr, var2.select_expr, ... FROM @var2;    
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name 
        AS 
        SELECT [ALL | DISTINCT] select_expr, select_expr, ...
        FROM @var4;]
[...]

Modos de execução

O modo script oferece suporte a dois modos de execução.

Comportamento

Modo normal (padrão)

Modo de execução passo a passo

Como ativar

Padrão. Nenhuma configuração é necessária.

Adicione SET odps.sql.step.script.mode=true; à seção SET.

Compilação

Todas as instruções DML são compiladas em um único plano de execução.

Cada instrução DML é compilada em um plano de execução separado. Observação: Scripts muito complexos, como aqueles com milhares de linhas ou numerosas operações, podem exceder os limites de memória de compilação.

Execução

Todas as instruções são executadas atomicamente como um único job, que inicia apenas após todos os dados de entrada estarem prontos. Se alguma instrução falhar, todo o script falha e todas as operações são revertidas.

As instruções DML são executadas serialmente. Se uma instrução falhar, as instruções executadas anteriormente não serão revertidas e você deverá tentar executar o script novamente desde o início. Recomendamos dividir scripts grandes em menores.

Leitura após escrita

Não suportado. Ocorre um erro se você gravar e depois ler da mesma tabela em um script.

Suportado, exceto para tabelas transacionais ou particionadas.

Tabela temporária

Não suportado.

Suportado.

Sintaxe DDL

Criar uma tabela temporária

Tabelas temporárias armazenam resultados intermediários em cache para reutilização dentro do mesmo script. Como dependem de um padrão de leitura após escrita, elas são suportadas apenas no modo de execução passo a passo.

Sintaxe

CREATE TEMPORARY TABLE <table_name> (
  <col_name> <data_type>, ...
)
[LIFECYCLE <days>]
[AS <select_statement>];

Parâmetros

Parâmetro

Descrição

table_name

Acessível apenas dentro do script atual.

LIFECYCLE <days>

Opcional. Número de dias para reter a tabela antes que ela seja excluída automaticamente. Padrão: 1.

AS <select_statement>

Opcional. Popula a tabela com dados de uma instrução SELECT no momento da criação.

Limitações

  • Tabelas temporárias exigem o modo de execução passo a passo. Adicione SET odps.sql.step.script.mode=true; à seção SET do seu script.

  • Uma tabela temporária é acessível somente dentro do script onde foi criada.

  • Tabelas temporárias não podem ser tabelas particionadas ou tabelas transacionais.

  • Para remover explicitamente uma tabela temporária, a instrução DROP TABLE deve ser a última instrução do script.

  • Evite criar mais de 20 tabelas temporárias em um único script.

Criar uma tabela padrão

O modo script permite a criação de tabelas padrão. Para detalhes sobre a sintaxe, consulte CREATE TABLE.

Sintaxe DML e DQL

Limitações de instruções

  • Instruções de exibição de resultado: Um script pode conter apenas uma instrução que produza saída na tela, como uma instrução SELECT independente. Incluir mais de uma causa um erro. Evite usar esses tipos de instruções em scripts.

  • CREATE TABLE AS: Use esta instrução apenas uma vez por script, e ela deve ser a última instrução executável. Recomendamos criar a tabela primeiro e depois inserir os dados.

  • Modos de gravação mistos: Não é possível usar OVERWRITE e INTO na mesma tabela dentro do mesmo script. Operações DML em tabelas transacionais e tabelas padrão não podem ser misturadas.

  • Leitura após escrita: No modo normal, gravar e depois ler de uma tabela no mesmo script causa um erro. Para resolver esse problema, use uma variável de tabela ou mude para o modo de execução passo a passo. O modo passo a passo oferece suporte à operação de leitura após escrita, mas não para tabelas transacionais ou particionadas. Para um exemplo detalhado, consulte Exemplo 3: Leitura após escrita no modo normal.

Variáveis

Sintaxe

-- Declare a variable by using @. Supported types include TABLE and any MaxCompute data type.
@var1 <type>
-- Assign a value by using :=
@var1 := <select_statement>

Notas de uso

  • Não é possível atribuir uma variável do tipo tabela a uma variável com um tipo de dados especificado. Por exemplo, a seguinte sintaxe não é permitida:

    @a TABLE (name STRING);
    @a := SELECT 'tom';
    @b STRING;
    @b := SELECT * FROM @a;
  • Variáveis podem armazenar valores constantes. Converta o valor de uma variável para um escalar usando SELECT * FROM @var. Uma constante também pode ser armazenada em uma tabela de linha única, conforme mostrado no exemplo a seguir. Para mais informações sobre a sintaxe de conversão, consulte subconsulta.

    @a := SELECT 10;                                         -- Assign the constant 10
    @b := SELECT key, value + (SELECT * FROM @a) FROM t2;   -- Use @a as a scalar
    SELECT * FROM @b;

Instruções IF

Use instruções IF para controlar o fluxo de execução com base em condições.

Sintaxe

-- Single branch
IF (condition) BEGIN
  statements
END
-- Multi-branch
IF (condition) BEGIN
  statements
END ELSE IF (condition2) BEGIN
  statements
END ELSE BEGIN
  statements
END

Notas de uso

  • Se um ramo contiver apenas uma única instrução, as palavras-chave BEGIN e END são opcionais, semelhante a { } em Java.

  • Instruções DDL como CREATE TABLE, ALTER TABLE e TRUNCATE TABLE não são suportadas dentro de um ramo IF.

  • A condição oferece suporte a dois tipos:

    • Expressão booleana: O ramo é determinado no momento da compilação.

    • Subconsulta escalar booleana: O ramo é determinado em tempo de execução. O MaxCompute pode enviar vários jobs.

Exemplo 1: Em uma instrução IF, a condição é uma expressão do tipo BOOLEAN. Esse tipo de instrução IF ELSE pode determinar qual ramo executar no momento da compilação, conforme mostrado no exemplo a seguir:

@date := '20190101';
@row TABLE(id STRING);
IF (CAST(@date AS BIGINT) % 2 == 0) BEGIN
  @row := SELECT id FROM src1;
END ELSE BEGIN
  @row := SELECT id FROM src2;
END
INSERT OVERWRITE TABLE dest SELECT * FROM @row;

Exemplo 2: A condição na instrução IF é uma subconsulta escalar booleana. Para este tipo de instrução IF ELSE, o ramo de execução é determinado em tempo de execução, o que exige que o MaxCompute envie vários jobs:

@i BIGINT;
@t TABLE(id BIGINT, value BIGINT);
IF ((SELECT COUNT(*) FROM src WHERE a = '5') > 1) BEGIN
  @i := 1;
  @t := SELECT @i, @i*2;
END ELSE BEGIN
  @i := 2;
  @t := SELECT @i, @i*2;
END
SELECT id, value FROM @t;

Exemplos

Exemplo 1: Exemplo básico

O script a seguir faz join e união de dados de três tabelas de origem e insere os resultados em duas tabelas de destino. Todas as instruções são compiladas em um único DAG e executadas atomicamente.

CREATE TABLE IF NOT EXISTS dest(key STRING, value BIGINT) PARTITIONED BY (d STRING);
CREATE TABLE IF NOT EXISTS dest2(key STRING, value BIGINT) PARTITIONED BY (d STRING);
@a := SELECT * FROM src  WHERE value > 0;
@b := SELECT * FROM src2 WHERE key IS NOT NULL;
@c := SELECT * FROM src3 WHERE value IS NOT NULL;
@d := SELECT a.key, b.value FROM @a LEFT OUTER JOIN @b ON a.key = b.key AND b.value > 0;
@e := SELECT a.key, c.value FROM @a INNER JOIN @c ON a.key = c.key;
@f := SELECT * FROM @d UNION SELECT * FROM @e UNION SELECT * FROM @a;
INSERT OVERWRITE TABLE dest  PARTITION (d='20171111') SELECT * FROM @f;
@g := SELECT e.key, c.value FROM @e JOIN @c ON e.key = c.key;
INSERT OVERWRITE TABLE dest2 PARTITION (d='20171111') SELECT * FROM @g;

Exemplo 2: Leitura após escrita no modo passo a passo

O script a seguir ativa o modo de execução passo a passo para realizar uma operação de leitura após escrita no mesmo script.

SET odps.sql.step.script.mode=true;
DROP TABLE IF EXISTS foo_t1;
DROP TABLE IF EXISTS foo_t2;
CREATE TABLE foo_t1(a STRING) LIFECYCLE 1;
CREATE TABLE foo_t2(a STRING) LIFECYCLE 1;
@x := SELECT 'hello, world' AS a;
INSERT OVERWRITE TABLE foo_t1 SELECT * FROM @x;
INSERT INTO foo_t2 SELECT * FROM foo_t1 UNION ALL SELECT * FROM foo_t1;
SELECT * FROM foo_t2;

Exemplo 3: Leitura após escrita no modo normal

No modo normal, gravar e depois ler da mesma tabela em um script causa um erro. Este exemplo demonstra o erro e duas soluções possíveis.

Preparação de dados

CREATE TABLE src(key BIGINT, value BIGINT) LIFECYCLE 1;
CREATE TABLE src2(key BIGINT, value BIGINT) LIFECYCLE 1;
INSERT INTO src VALUES(1, 2), (3, 3);

Exemplo de erro (leitura após escrita no modo normal)

INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2;   -- Error: src2 is written to and then read from in the same script.
SELECT * FROM @a;

Solução 1: Ativar o modo de execução passo a passo

SET odps.sql.step.script.mode=true;
INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2;
SELECT * FROM @a;

Solução 2: Reescrever o SQL para usar uma variável de tabela

@a := SELECT * FROM src WHERE key > 0;
INSERT OVERWRITE TABLE src2 SELECT * FROM @a;
SELECT * FROM @a;

Exemplo 4: Criar e excluir uma tabela temporária

O script a seguir cria uma tabela temporária para armazenar em cache os resultados intermediários de um JOIN, lê dela duas vezes e depois a remove.

-- Enable step-by-step execution mode (required for temporary tables).
SET odps.sql.step.script.mode=true;
DROP TABLE IF EXISTS foo_t1;
CREATE TABLE foo_t1(a BIGINT, b BIGINT);
-- Create a temporary table by using a JOIN.
CREATE TEMPORARY TABLE t AS
SELECT t1.a AS a, t2.d AS b FROM
  (SELECT 1 a, 2 b) t1
JOIN
  (SELECT 1 c, 10 d) t2
ON t1.a = t2.c;
INSERT INTO foo_t1 SELECT * FROM t UNION ALL SELECT * FROM t;
SELECT * FROM foo_t1;
-- Drop the temporary table (must be the last statement in the script).
DROP TABLE t;

Enviar scripts

O modo script é suportado no MaxCompute Studio, no cliente MaxCompute (odpscmd), no DataWorks e nos SDKs Java e Python.

Cliente MaxCompute (odpscmd)

Use o odpscmd v0.27 ou posterior. Após instalar o cliente MaxCompute, envie um script usando a flag -s:

Crie um arquivo de script, como myscript.sql. Em seguida, execute o comando a seguir na sua interface de linha de comando para rodar o odpscmd. Para mais informações sobre como executar o cliente MaxCompute a partir da linha de comando, consulte Executar o cliente MaxCompute.

..\bin>odpscmd -s myscript.sql
Nota

O modo script e as variáveis de tabela não são suportados no shell interativo do odpscmd. A flag -s é uma opção de linha de comando para o odpscmd, semelhante a -f e -e. Não é um comando no ambiente interativo.

DataWorks

No DataWorks, use um nó ODPS Script para escrever e executar scripts.

No canto superior esquerdo, clique em + Create > Create Node. Na categoria MaxCompute, selecione ODPS Script.

Após escrever o script, clique no ícone Run na barra de ferramentas para executá-lo. O log de saída inclui uma URL do Logview para visualizar o plano de execução e os resultados.

SDKs

Execute scripts SQL diretamente com o SDK Java ou SDK Python. Para mais informações, consulte a documentação do SDK Java e do SDK Python.

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.aliyun.odps.Instance;
import com.aliyun.odps.Odps;
import com.aliyun.odps.OdpsException;
import com.aliyun.odps.account.Account;
import com.aliyun.odps.account.AliyunAccount;
import com.aliyun.odps.data.Record;
import com.aliyun.odps.task.SQLTask;
public class SdkTest {
  public static void main(String[] args) throws OdpsException {
    // Your Alibaba Cloud AccessKey pair grants full access to your account and carries high risks.
    // We strongly recommend that you create and use a RAM user for API calls and daily operations.
    // To create a RAM user, log on to the RAM console.
    // This example shows how to use environment variables to store your credentials.
    // For security, never hard-code your AccessKey pair into your code.
    Account account = new AliyunAccount(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"), System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
    Odps odps = new Odps(account);
    odps.setDefaultProject("your project_name");
    odps.setEndpoint("your end_point");
    String sqlScript = "@a := SELECT * FROM jdbc_test;\n"
                       + "SELECT * FROM @a;";
    // Required: Enable script mode.
    Map<String, String> hints = new HashMap<>();
    hints.put("odps.sql.submit.mode", "script");
    Instance instance = SQLTask.run(odps, "your project_name", sqlScript, hints, null);
    instance.waitForSuccess();
    List<Record> recordList = SQLTask.getResult(instance);
    for (Record record : recordList) {
      System.out.println(record.get(0));
      System.out.println(record.get(1));
    }
  }
}
import os
from odps import ODPS
# Your Alibaba Cloud AccessKey pair grants full access to your account and carries high risks.
# We strongly recommend that you create and use a RAM user for API calls and daily operations.
# To create a RAM user, log on to the RAM console.
# This example shows how to use environment variables to store your credentials.
# For security, never hard-code your AccessKey pair into your code.
o = ODPS(
    os.environ["ALIBABA_CLOUD_ACCESS_KEY_ID"],
    os.environ["ALIBABA_CLOUD_ACCESS_KEY_SECRET"],
    "your project_name",
    "your end_point"
)
sql_script = """
@a := SELECT * FROM jdbc_test;
SELECT * FROM @a;
"""
# Required: Enable script mode.
hints = {"odps.sql.submit.mode", "script"}
instance = o.execute_sql(sql_script, hints=hints)
with instance.open_reader() as reader:
    for rec in reader:
        print(rec[0], rec[1])

MaxCompute Studio

Antes de executar um script no MaxCompute Studio, conclua os seguintes pré-requisitos:

  1. Instalar o IntelliJ IDEA

  2. Adicionar uma conexão de projeto

  3. Criar um módulo MaxCompute Script

Após executar o script, o MaxCompute Studio exibe o plano de execução como um único DAG, mesmo quando o script contém várias instruções.