|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contrariamente ao que o Oracle e outros sistemas de bancos de dados menos conhecidos dizem, uma string vazia, '', não é a mesma coisa do que NULL. Se você está habituado com outros sistemas, pode ser fácil cometer erros no entanto. Então, se você achar que está selecionando registros com valores NULL nas colunas que você não espera vê-lo, talvez esteja tendo problemas com strings vazias no lugar de NULLs. Você precisará prestar atenção na fonte de dados para prevenir futuros dados inválidos, achar os registros problemáticos, corrigí-los e então, escrever no quadro negro 100 vezes "NULL é diferente de uma string vazia" :-) Para ver se um valor é NULL ou uma string vazia, as pessoas enviaram um número razoável de consultas interessantes. As diversas formas que as pessoas escolhem para testar sobre o que há em uma coluna foi surpreendente. Alguns testam se é NULL, alguns se não é NULL, alguns por strings vazias, alguns por strings que não estão vazias e alguns através de uma operação sobre a coluna. Algumas destas consultas são melhores do que outras para esta tarefa. Eu mesmo prefiro usar a opção coalesce(). Mas cada seleção mostra uma maneira diferente de visualizar o problema e isto é muito interessante. Aqui estão algumas delas.
-- Se você consultar um registro onde a coluna jobcomment não é nula, então -- provavelmente há uma string vazia nela ... SELECT jobcomment FROM tblJobIncharge WHERE id=51 AND jobcomment IS NOT NULL; -- Para ter certeza que a coluna jobcomment não é [uma string vazia] você pode tentar esta consulta: -- Se jobcomment é uma string vazia então irá retornar um '0' no campo de comentários do serviço, -- Se estiver realmente null então não retornará nada SELECT jassignedid, ascii(JobComments) FROM tblJobIncharge WHERE JobComments IS NOT NULL AND projectid >= 50 AND projectid <= 100 -- Qualquer resultado nesta coluna que for null, será mostrado um 'X' ao invés de nada. SELECT jassignedid, coalesce(JobComments,'X') FROM tblJobIncharge WHERE JobComments IS NOT NULL AND projectid >= 50 AND projectid <= 100 -- Neste caso não somente irá mostrar a você onde há realmente valores null (já que null -- em uma operação || retorna null) mas também indica a string entre 'xx' e 'xx'. SELECT jassignedid, 'xx' || JobComments || 'xx' FROM tblJobIncharge WHERE projectid >= 50 AND projectid <= 100 -- O tamanho da coluna irá dizer quantos espaços (ou caracteres) há, se houver algum. SELECT jassignedid, JobComments, length(JobComments) FROM tblJobIncharge WHERE JobComments IS NOT NULL AND projectid >= 50 AND projectid <= 100; Não se esqueça de verificar suas origens de dados por semânticas perdidas. Por exemplo, aplicações baseadas em formulários irão submeter strings vazias às quais podem ser criadas para serem interpretadas como NULL. No PostgreQSL este é um jeito de como você poderia atualizar o dado baseado em uma entrada em branco. UPDATE tblJobIncharge SET JobComments = NULL WHERE LENGTH(RTRIM(JobComments)) = 0;
Este questionamento foi levantado caso as views se tornassem "obsoletas" com o advento das funções que retornam conjuntos de dados (SRF - Set Returning Functions). (na verdade a questão é sobre as funções que retornam conjuntos de registros - FRSR, functions returning sets of rows - que são um subconjunto dos SRFs :-) (Veja a Edição #26 para informações sobre funções que retornam conjuntos de dados, funções que retornam registros e funções que retornam conjuntos de registros.) A view não irá se tornar obsoleta com relação ao FRSR por diversas razões. A primeira delas é que as views já são conhecidas e muito utilizadas. Elas são fáceis de construir. As pessoas estão somente aprendendo a construir FRSRs e isto não é nada mais que um novo recurso. Este recurso é extremamente útil mas se uma view fosse adequada no caso, a view pode e deve ser usada considerando sua simplicidade, caso não haja uma outra razão. Mas há uma outra razão. A otimização do SQL no PostgreSQL é muito boa. E o planner (programa de pranejamento de execução das instruções em SQL) pode otimizar as views por causa simplicidade da definição do SQL. O planner, no entanto, não pode otimizar funções. Funções não são claras para o planner e podem resultar em inúmeras variações que, dessa maneira, ele não consegue determinar precisamente o plano. Funções em SQL também não são otimizadas. No entanto, poderia ser possível no futuro, que funções em SQL possam ser trazidas automaticamente para dentro das chamadas de instruções SQL e, otimizadas com o resto da instrução. Isto não está implementado no momento.
Quando usar CURSORes você precisa saber onde o CURSOR está após fazer um FETCH. A sintaxe de FETCH é: FETCH [direção] [número de registros] { FROM | IN } nome do cursorA primeira regra é que o cursor está posicionado no último registro retornado. Se o cursor está no ROW[n] (enésimo registro), então a busca relativa começa à partir do próximo registro, ROW[n+1]. A exceção à regra é quando você trabalha com FETCH ALL. Esta instrução posiciona o cursor uma linha após o ÚLTIMO registro retornado, já preparado para executar uma busca reversa.
Uma coluna com um tipo vetor (array), às vezes necessita de restrições (constraints). Em geral, não é possível criar uma restrição em elementos individuais de um vetor, exceto utilizando uma função como restrição. No caso deste exemplo, os elementos do vetor letters devem estar na coluna id da tabela lettervals. Esta foi a primeira tentativa. Isto NÃO funcionará: create table foo ( letters char(1)[3] REFERENCES lettervals(id) ...Isto não funciona porque está tentando referenciar o valor de um vetor completo para um único valor de letter. Um vetor completo e um valor único de letter não são o mesmo tipo. Nigel Andrews sugeriu a seguinte função utilizando-a como trigger. Esta função percorre todo o vetor e verifica se o elemento do vetor está na tabela lettervals (na coluna id). Caso não esteja, um erro é criado abortando o INSERT. CREATE FUNCTION letter_fk () RETURNS TRIGGER AS ' DECLARE ind integer; BEGIN FOR ind IN array_dims(NEW.letters) LOOP PERFORM 1 FROM lettervals WHERE id = NEW.letters[ind]; IF NOT FOUND THEN RAISE EXCEPTION ''Violação da minha restrição de chave estrangeira''; END IF; END LOOP; RETURN NEW; END; ' AS LANGUAGE 'plpgsql'; CREATE TRIGGER lettercheck BEFORE INSERT ON foo FOR EACH row EXECUTE PROCEDURE letter_fk(); Joe Conway nos lembra que ele está trabalhando numa atualização considerável à suporte de vetores para a versão 7.4, à qual irá mover algumas das funcionalidades de vetores encontradas em contrib para o código base do PostgreSQL. Nós temos visto algumas das suas funções em edições anteriores do General Bits tratando de arrays e buscando a sua inserção na versão 7.4.
Quando temos que carregar um volume muito grande de dados, às vezes, estes dados estão ruins e a transação inteira é interrompida (ou abortada) deixando você com todos os dados não processados por ir. Isto pode ser um tanto quanto frustrante. Não é fácil ignorar restrições na tabela. A alternativa é usar um script e inserir cada registro separadamente com autocommit ligado. Isto deixará os dados confiáveis entrar e você pode armazear os registros "ruins" para limpá-los (ou tratá-los) mais tarde. Uma outra sugestão de tratar isto veio de Jan Wieck. Ele sugeriu carregar em uma "staging table" (tabela de preparação) à qual irá conter as mesmas características da tabela de destino, mas sem as restrições e referências. Com esta tabela de preparação você pode consultar dados os quais não combinariam com as restrições, você irá querer reforçar os dados quando necessários, poderá corrigí-los ou remover os registros. Uma vez que todos os dados na tabela de preparação estão corretos, uma única instrução colocará os dados em seus devidos lugares: INSERT INTO realtable SELECT * FROM stagingtable;Este é um ótimo método porque os dados são inseridos rapidamente no banco de dados. Você pode utilizar-se da definição da tabela de preparação existente para construir suas consultas de teste. Você pode também decidir como manipular registros com dados ruins -- mesmo que seja para limpá-los ou removê-los.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comentários e Correções são bem vindos. Sugestões e contribuições de itens também são bem vindos. Envie-os!. Copyright A. Elein Mustain 2003 Traduzidos por Juliano da Silva Ignacio |