AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 91731
Accepted
John
John
Asked: 2015-02-12 12:02:24 +0800 CST2015-02-12 12:02:24 +0800 CST 2015-02-12 12:02:24 +0800 CST

Redefina a sequência de um PK serial com SQL dinâmico

  • 772

Como posso referenciar dinamicamente um nome de sequência (como abaixo) usando uma combinação de strings e DECLAREvariáveis? O código abaixo está correto ou existe outro método para fazer isso?

Meu objetivo é fazer isso dentro de um bloco DO/ BEGINpor motivos de desempenho, além de me ajudar a entender o plpgsql fazendo algo útil, então não vou misturar isso ao PHP, a menos que seja realmente necessário.

DO $$
 DECLARE PKEY VARCHAR;
BEGIN

SELECT pg_attribute.attname INTO PKEY 
FROM pg_index, pg_class, pg_attribute 
WHERE pg_class.oid = 'parts1'::regclass 
AND indrelid = pg_class.oid 
AND pg_attribute.attrelid = pg_class.oid 
AND pg_attribute.attnum = any(pg_index.indkey) 
AND indisprimary;

--SELECT setval('parts1_id_seq', (SELECT MAX(pkey) + 1 FROM parts));
SELECT setval('parts1_' || PKEY || '_seq', (SELECT MAX(pkey) + 1 FROM parts));

  END;
$$ LANGUAGE plpgsql;
postgresql plpgsql
  • 2 2 respostas
  • 1494 Views

2 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2015-02-12T19:25:18+08:002015-02-12T19:25:18+08:00

    Conselho Geral

    Você mesmo mencionou, acabou de começar a usar o Postgres. No entanto, você está lidando com tarefas extremamente avançadas imediatamente, fazendo malabarismos com catálogos do sistema e operando com SQL dinâmico avançado para automatizar as coisas.

    Embora seus objetivos pareçam razoáveis, você ainda precisa começar do básico . Há muito o que explicar aqui. Comece com (partes relevantes de) o excelente manual . Forneci alguns links profundos mais abaixo.

    Responda

    Para obter o(s) nome(s) (e tipo(s) de dados) das colunas envolvidas na chave primária, use esta consulta mais simples:

    SELECT a.attname, format_type(a.atttypid, a.atttypmod) AS data_type
    FROM   pg_index i
    JOIN   pg_attribute a ON a.attrelid = i.indrelid
                         AND a.attnum = ANY(i.indkey)
    WHERE  i.indrelid = 'tbl'::regclass
    AND    i.indisprimary;
    

    Atualizei a página Postgres Wiki de onde sua consulta original parece ter se originado.

    No entanto , isso pode retornar várias linhas, enquanto você atribui apenas um único valor. Supondo que você tenha estabelecido que estamos lidando com uma serialchave primária do tipo (coluna única). Caso contrário, use técnicas semelhantes às apresentadas na minha resposta anterior para ter certeza.

    Em seguida, use a função de informações do sistema dedicada pg_get_serial_sequence()para determinar o nome da sequência usada, como demonstrado na minha resposta anterior .
    Por documentação:

    obtenha o nome da sequência que um serial, smallserialou bigserialcoluna usa

    DO
    $do$
    BEGIN
       EXECUTE (
       SELECT format($$SELECT setval('%s'::regclass, max(%I)) FROM %s$$
                     , pg_get_serial_sequence(a.attrelid::regclass::text, a.attname)
                     , a.attname
                     , a.attrelid::regclass
                    )
       FROM   pg_index i
       JOIN   pg_attribute a ON a.attrelid = i.indrelid
                            AND a.attnum = i.indkey[0]
       WHERE  i.indrelid = 'tbl'::regclass
       AND    i.indisprimary
       );
    END
    $do$ LANGUAGE plpgsql;
    

    Isso cria e executa uma consulta do formulário:

    SELECT setval('tbl_tbl_id_seq'::regclass, max(tbl_id)) FROM tbl;
    

    Explicar / Aconselhar

    • Isso é algo avançado e não é realmente adequado para iniciantes. Mexer nos catálogos do sistema pode dar errado rapidamente se você não souber exatamente o que está fazendo.

    • Atenha-se aos identificadores legais em minúsculas no Postgres e no plpgsql para facilitar sua vida. Mas nunca confie nele em SQL dinâmico, onde você também precisa se defender contra a injeção de SQL o tempo todo.

    • Fazendo uso pesado format()para construir a string de consulta de forma conveniente e segura.

    • Dentro de uma função plpgsql você não pode chamar SELECTsem atribuir o resultado. Você usaria PERFORMem vez disso. Detalhes no manual.
      Eu removi isso completamente, já que reduzi tudo a um único arquivo EXECUTE.

    • Como toda a operação só faz sentido para uma chave primária de coluna única, simplifiquei a JOINcondição para a.attnum = i.indkey[0]
      Note que pg_index.indkeypossui o tipo especial (interno) int2vector. Ao contrário das matrizes do Postgres, seu índice começa com 0 , não 1.

    • Crie o hábito de usar aspas com um token em torno do código plpgsql (incluindo DOinstruções). Isso permite aninhar cotações de dólares simples como eu faço no meu exemplo. Detalhes:

      • Inserir varchar com aspas simples no PostgreSQL
    • Você só precisa de um único SELECTaqui:

      SELECT setval('tbl_tbl_id_seq'::regclass, max(tbl_id)) FROM tbl;
      

      ao invés de:

      SELECT setval('tbl_tbl_id_seq'::regclass, (SELECT max(tbl_id) FROM tbl));
      

    SQL Fiddle demonstrando algumas coisas.

    • 4
  2. Joishi Bodio
    2015-02-12T12:07:55+08:002015-02-12T12:07:55+08:00

    Sempre que você tiver uma instrução SQL de natureza dinâmica (possivelmente alterada em tempo de execução) que precisa ser executada dentro de uma função, você precisa executá EXECUTE-la.

    Consulte a Seção 40.5.4. Executando Comandos Dinâmicos

    Você precisa estar ciente de que a execução do SQL dessa maneira PODE ser vulnerável a ataques de SQL Injection .

    Sua linha acima:

    SELECT setval('parts1_' || INTO PKEY || '_seq', (SELECT MAX(pkey) + 1 FROM parts));
    

    Se tornaria (pelo menos, acredito que essa seja a intenção)

    EXECUTE 'SELECT setval(''parts1_' || PKEY || '_seq'', (SELECT MAX(' || pkey || ') + 1 FROM parts))';
    
    • Nota .. a aspa simples dupla ( '') dentro de uma string é tratada como uma aspa simples literal (como \')
    • Nota 2 .. para proteger contra SQL Injection, você pode EXECUTE uma string formatada (como Erwin Brandstetter já forneceu vários exemplos para você em um post diferente)
    • 1

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve