• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Rui Carlos

[PostgreSQL] Ajuda em query para alterar BD

6 mensagens neste tópico

O meu problema é o seguinte:

Suponhamos que tenho uma tabela com os atributos:

- id (int4)

- a (int4)

- b (bool)

- data (date)

Agora queria que entre todos os valores com o atributo a igual, só aquel que tem menor valor de date tivesse o atributo b a false, i.e., queria alterar todos os outros para true.

Pensei na seguinte query:

UPDATE tabela
SET b = true
WHERE data <> (SELECT MIN(date) FROM tabela WHERE a = ...)

Onde estão os "..." eu queria que usasse o valor do atributo a, mas do UPDATE. Se colocar lá só a aquila dará sempre verdade.

De certo forma queria que houvesse uma variável que armazenasse o valor do a do UPDATE para usar no SELECT.

Não sei há alguma forma de fazer isto com uma query deste género, ou se vou ter que recorrer a outro tipo de coisas. Agradeço qualquer ajuda para resolver o problema.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não percebi bem, acho que te esqueceste de uma ou duas palavras aí na parte onde expões a dúvida.

Mas parece-me que é só meteres outro subquery onde tens os três pontinhos.

Mas tens sempre a possibilidade de usar plpgsql, uma linguagem de procedimentos tipo o PLSQL do oracle.

Tens no site do postgresql boa documentação

http://www.postgresql.org/docs/7.4/interactive/plpgsql.html

o básico de pgpsql aprende-se em minutos.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Um exemplo para ajudar a perceber o meu problema.

Supondo que tenho os seguintes valores:

1 | 1 | false | 2008-01-01

2 | 1 | false | 2008-01-02

3 | 1 | false | 2007-01-01

4 | 2 | false | 2007-01-01

5 | 2 | false | 2007-02-01

Queria passar a ter:

1 | 1 | true  | 2008-01-01

2 | 1 | true | 2008-01-02

3 | 1 | false | 2007-01-01

4 | 2 | false | 2007-01-01

5 | 2 | true  | 2007-02-01

Ou seja, para cada valor diferente da segunda coluna, só há um que tem false (o que tem menos data).

A subquery ali não dá, porque eu quero um valor fixo, quero o valor da entrada que está a ser processada pelo update naquele momento.

Eu já ando a ver o PLSQL, mas com um update directo devia ficar mais simples :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Poderá ser isto?

CREATE TABLE tab_teste(
    id serial not null unique,
    a  int,
    b bool,
    data date
);
INSERT INTO tab_teste(a,b,data) VALUES(1,'false','2008-01-01');
INSERT INTO tab_teste(a,b,data) VALUES(1,'false','2008-01-02');
INSERT INTO tab_teste(a,b,data) VALUES(1,'false','2007-01-01');
INSERT INTO tab_teste(a,b,data) VALUES(2,'false','2007-01-01');
INSERT INTO tab_teste(a,b,data) VALUES(2,'false','2007-02-01');

SELECT * FROM tab_teste;

UPDATE
    tab_teste
SET
    b = 'true'
WHERE
    data NOT IN (
        SELECT data
        FROM (
            SELECT DISTINCT(a), MIN(data) AS data
            FROM tab_teste
            GROUP BY a
        ) AS t1
    );
SELECT * FROM tab_teste ORDER BY id;
DROP TABLE tab_teste;

teste_rc=# \i teste_rc.sql
CREATE TABLE
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1
id | a | b |    data
----+---+---+------------
  1 | 1 | f | 2008-01-01
  2 | 1 | f | 2008-01-02
  3 | 1 | f | 2007-01-01
  4 | 2 | f | 2007-01-01
  5 | 2 | f | 2007-02-01
(5 rows)

UPDATE 3
id | a | b |    data
----+---+---+------------
  1 | 1 | t | 2008-01-01
  2 | 1 | t | 2008-01-02
  3 | 1 | f | 2007-01-01
  4 | 2 | f | 2007-01-01
  5 | 2 | t | 2007-02-01
(5 rows)

DROP TABLE

EDIT:

Isto pode dar barraca nos casos em que existam duas datas inferiores iguais. Como não disseste o que deveria acontecer, não me preocupei com isso.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Isso nem sempre funciona...

Por exemplo, falha para a seguinte tabela:

id | a | b |    data

----+---+---+------------

  1 | 1 | f | 2008-01-01

  2 | 1 | f | 2008-01-02

  3 | 1 | f | 2007-01-01

  4 | 2 | f | 2007-01-01

  5 | 2 | f | 2007-02-01

  6 | 2 | f | 2006-01-01


De qualquer forma, já resolvi o problema.

create or replace function setTrue() returns integer as '
  declare a1 record;

  begin
    for a1 in select a from tabela loop
      execute
''update tabela
set b = true
where a = '' || a1.a ||
	'' and data <> (select min(data)
		from tabela
		where a = '' || a1.a || '')'';
    end loop;

    return 1;
  end;
' language plpgsql

Não me parece a forma ideal de resolver o problema, a query demora uns minutos a correr, mas como só é para ser executada uma vez, já serve.

De qualquer modo, obrigado pela ajuda.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora