2014/1/19 Eloi <[email protected]>

>
> > É, parece que você criou uma bagunça com as aspas mesmo... Acho que vai
> > ficar mais fácil refazer a função do que ajustar cada problema nela. Já
> que
> > vamos refazer, que tal adicionar algumas dicas de ouro? ;-)
> >
> >
> > Bom, primeiro, veja o modelo que criei (não testei, então pode ter algum
> > erro que eu não tenha visto):
> >
> >     CREATE OR REPLACE FUNCTION wosis.fun_create_sequence(sch text)
> >     RETURNS text
> >     LANGUAGE plpgsql VOLATILE
> >     AS
> >     $BODY$
> >     DECLARE
> >         row record;
> >     BEGIN
> >         FOR row IN
> >             SELECT table_name, table_name||'_id' AS id_name, 0 AS
> next_value
> >             FROM information_schema.tables
> >             WHERE table_schema = sch
> >             AND  table_type = 'BASE TABLE'
> >             ORDER BY table_name
> >         LOOP
> >             EXECUTE
> >                 format('SELECT max(%I)+1 FROM %I.%I', row.id_name, sch,
> > row.table_name)
> >                 INTO row.next_value;
> >             EXECUTE
> >                 format(
> >                     'CREATE SEQUENCE %I.%I START %L OWNED BY %I.%I.%I;',
> >                     sch,
> >                     row.table_name||'_'||row.id_name||'_seq',
>                                 row.next_value -- faltava
> >                     sch,
> >                     row.table_name,
> >                     row.id_name
> >                     );
> >            EXECUTE
> >                format(
> >                     'ALTER TABLE %I.%I ALTER COLUMN %I SET DEFAULT
> > nextval(%L);', -- AQUI FALTAVA A VIRGULA
> >                     sch,
> >                     row.table_name,
> >                     row.id_name,
> >                     row.table_name||'_'||row.id_name||'_seq'
> >                     );
> >         END LOOP;
> >         RETURN 'Sequences were created';
> >     END;
> >     $BODY$;
> >
> > Agora vejamos... Em primeiro lugar eu não usei uma tabela temporário,
> > simplesmente porque não vi sentido, e acho que acabou deixando a função
> > mais confusa ainda. Ao invés disso eu apenas naveguei no resultado da
> > consulta à view information_schema.tables. Repare também que não usei
> > consulta dinâmica (comando EXECUTE) nesta consulta, simplesmente porque
> não
> > é necessário e recomendo evitar o uso de EXECUTE ao máximo.
> >
> > Em segundo lugar, precisamos de três comandos, um para fazer um `SELECT
> > max` para recuperar o maior valor, outro para criar a sequência e o
> último
> > para alterar o DEFAULT da tabela. Em ambos os casos a função format ajuda
> > bastante, e não precisa de tantos quote_ident's, que podem ser confusos.
> >
> > Em [1] há um comparativo legal entre format e quote_ident. Veja lá e
> poste
> > dúvidas que sobrarem aqui.
> >
> > Por fim, adicionei a cláusula OWNED BY no CREATE SEQUENCE, para deixar
> > idêntico ao que o pseudo-tipo SERIAL faz, e é uma boa prática para
> futuras
> > manutenções.
> >
> > Só tenho mais um comentário. Esses comandos estão (talvez erroneamente)
> > assumindo que toda tabela tem um campo "<nome da tabela>_id", mas talvez
> > faça parte do seu modelo, mas eu evitaria isso, a não ser que seja algo
> > executado somente numa tarefa administrativa.
> >
> > Ufa... Leia com calma, tentei ser o mais claro possível. ^^
> >
> > [1]
> >
> http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-QUOTE-LITERAL-EXAMPLE
> >
> >
> > Atenciosamente,
>
> Obrigado a todos pelas respostas e desculpar-me por não responder antes.
>
> Gostei das dicas do 'format()', muito parecido ao python e também do
> 'INTO row.next_value', não conhecia. E sem duvida que conceptualmente a
> função ficou muito melhor, não complicou. Parece que terei de rever
> todas as minhas funções que estive a escrever na ultima semana.
>
> Sim, todas as tabelas tem o "<nome da tabela>_id", fiz uma função para
> que assim fosse. E sim, é apenas uma tarefa administrativa num esquema
> com 70 tabelas.
>
>

Ok. Fico mais tranquilo agora, +D.



> Foi necessário uns retoques minimos, uma virgula que falatva e passar o
> valor de row.next_value.
>
>

É, eu só digitei, não testei nada, então podia ter erros.



> Agora só falta um detalhe, esta a passar o valor de 'next_value' como
> texto e salta erro. Tentei o 'cast' (::int) mas parece-me que isso é
> apenas para o puro SQL.
>
> ERROR:  syntax error at or near "'25476'"
> LINE 1: ...E SEQUENCE wosis.class_fao_class_fao_id_seq START '25476' OW...
>                                                              ^
> QUERY:  CREATE SEQUENCE wosis.class_fao_class_fao_id_seq START '25476'
> OWNED BY wosis.class_fao.class_fao_id;
> CONTEXT:  PL/pgSQL function "fun_create_sequence" line 19 at EXECUTE
> statement
>
> Como faço para passar o valor como inteiro?
>
>

Realmente, o next_value devia ser passado como inteiro, não literal. Para
resolver isso, basta usar o %s ao invés de %L. Este irá alocar o valor
diretamente, por isso recomendo um CAST no parâmetro (ele já é inteiro, mas
é só para garantir 100% que não haverá erros):

   format('CREATE SEQUENCE %I.%I START %s OWNED BY %I.%I.%I;',  ....,
row.next_value::int, ...);



> Muito obrigado a todos pelas sugestões, correções e explicações.
>
>
Disponha. =D


Atenciosamente,
-- 
Matheus de Oliveira
Analista de Banco de Dados
Dextra Sistemas - MPS.Br nível F!
www.dextra.com.br/postgres
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a