quarta-feira, 27 de agosto de 2008

Inserindo uma coluna indice

Não são raras as vezes que nos vemos frente a frente com uma tabela que não contem qualquer indice ou colunas com valores distintos pela qual pode ser indexada.

Como trabalhar com uma tabela assim? Como fazer selects ou updates sem ter uma chave a qual se referir em nossa clausula WHERE? E pior como inserir uma coluna com valores distintos se não podemos fazer updates?

O script abaixo lhe trará a solução para este problema.

Pena que a solução apresentada não pode ser usada em cursores implicitos mas independente disto é muito bem vinda esta solução.

Como teste criamos uma tabela chamada teste. Inserimos valores nela com uma coluna de valores repetidos. Criamos uma sequencia que nos dará numeros distintos e escrevemos o script que fará a magica de poder dar o update apenas em uma linha sem ter de nos referir a nenhum conteúdo especifico.

A magica toda refere-se a current of . Este é o cara que nos possibilita fazer isso.


create table teste (
i number(3),
c varchar(50)
);

insert into test (0, 'um');
insert into test (0, 'dois');
insert into test (0, 'cinco');
insert into test (0, 'dez');
insert into test (0, 'vinte e cinco');

commit;


create sequence numerar;

declare
cursor cur_test is
select i, c from teste for update;
i number(3);
c varchar(50);
begin
open cur_test;
loop
fetch cur_test into i, c;
exit when cur_test%notfound;
update test_for_cursor set i=numeraar.nextval where current of cur_test;
end loop;
end;



É isso.

Até a próxima.

Reginaldo

quinta-feira, 3 de julho de 2008

Resolvendo Chaves Duplas

Voce que trabalha com banco de dados deve ter se deparado algumas vezes com uma tabela com inumeros registros duplicados. Voce precisa excluir os registros duplos porém não há select possivel que possa trazer todos menos um para que voce possa excluir. Não é uma tarefa simples e faze-lo um a um, depedendo da quantidade de registros na tabela, se torna inviável.

O script abaixo, escrito para rodar no Oracle resolve esta questão, ou pelo menos, te coloca no caminho da solução.

DECLARE vSEQ INTEGER;

BEGIN
vSEQ := 0;
FOR REC IN ( SELECT NRBEM, NRINC FROM TPT21011 )
LOOP
vSEQ := vSEQ + 1;
UPDATE TPT21011 SET SEQ = vSEQ
WHERE NRBEM = rec.NRBEM AND NRINC = rec.NRINC AND ROWNUM = 1;
vSEQ := vSEQ + 1;
UPDATE TPT21011 SET SEQ = vSEQ
WHERE NRBEM = rec.NRBEM AND NRINC = rec.NRINC AND SEQ IS NULL;
END LOOP;
END;

DECLARE vNRBEM INTEGER;
vNRINC INTEGER;
BEGIN
FOR REC IN ( SELECT NRBEM, NRINC, SEQ FROM TPT21011 ORDER BY SEQ )
LOOP
IF rec.NRBEM <> vNRBEM AND rec.NRINC <> vNRINC THEN
DELETE FROM TPT21011 WHERE SEQ = ( SELECT MIN( SEQ ) FROM
TPT21011 WHERE NRBEM = rec.NRBEM AND NRINC = rec.NRINC );
END IF;
vNRBEM := rec.NRBEM;
vNRINC := rec.NRINC;
END LOOP;
END;


Até a proxima.


Reginaldo


quinta-feira, 19 de junho de 2008

SELECIONANDO TODOS OS CAMPOS MENOS ALGUNS - SQL-SERVER

Todos nós que trabalhamos com banco de dados por varias vezes seguida temos a necessidade de repetir um mesmo conjunto de dados alterando apenas um ou dois campos da chave.

Esta tarefa é bem fácil quando estamos trabalhando com uma tabela com poucos campo.

Suponhamos que temos a tabela TPT210 que contém um campo CDMOEDA que faz parte da chave e precisamos duplicar as linhas da tabela cujo campo CDMOEDA é igual a 1 alterando o valor para 20. Se temos poucos campos na tabela seria algo assim:

INSERT INTO TPT210 SELECT CAMPO1, CAMPO2, 20 AS CDMOEDA, CAMPO4 FROM
TPT210

Mas se temos muitos campos; reescreve-los todos é bastante trabalhoso e propenso a erros. Embora podemos utilizar alguns recursos de aplicativos dos bancos que copia os nomes de campos separados por virgula e tal, ainda assim, por experiência, é chato.

Portanto o script abaixo tem o objetivo de resolver esta questão.

O objetivo é o mesmo acima descrito. Copiar todos os registros da tabela com TPT210 com o valor do campo CDMOEDA = 1 e inseri-los na própria TPT210 alterando o conteúdo do campo
CDMOEDA para 20.


DECLARE @vCOLLIST VARCHAR(1000), @vSQLS VARCHAR(4000)
SET @vCOLLIST = ''
SELECT @vCOLLIST = @vCOLLIST + CASE WHEN NAME != 'CDMOEDA' THEN
NAME
ELSE
'20 AS CDMOEDA'
END + ', ' FROM SYSCOLUMNS WHERE ID = OBJECT_ID('TPT210') ORDER BY COLORDER
SELECT @vSQLS = 'INSERT INTO TPT210 SELECT ' + substring(@vCOLLIST,1,len(@vCOLLIST)-1) + ' FROM TPT210 WHERE CDMOEDA = 1'
PRINT @vSQLS



Por enquanto é somente isso.

Até a próxima.

Reginaldo

PS: Aqui na empresa funciona e quase todos os servidores menos em um e não sei porque.








segunda-feira, 16 de junho de 2008

Seleção de registros aleatórios - ORACLE

Por vezes gostaríamos de preencher um campo de uma tabela com valores aleatórios. Abaixo o script que pode ajuda-lo a cumprir esta tarefa.

Criei uma tabela teste para acumular os valores para podermos analisar o que foi feito pelo script.

Neste caso poderia utilizar o valor vCDFNC tranquilamente porque o valor já é um número aleatório e é isso que quero porém em alguns casos posso querer inserir um valor aleatório que vem de um SELECT de um campo VARCHAR. Neste caso passo à função RANDOM os valores minimos e maximos que quero. Aqui no exemplo tenho 124 registros na tabela TPT154, isto me traz um valor neste intervalo e após isso seleciono o campo VARCHAR da tabela cujo registro é exatamente este número.

Verifique que neste script estão contidas várias técnicas : selecionar um registro randomicamente, selecionar apenas um registro, ou vários aleatóriamente, etc.


CREATE TABLE TESTE
(
ID INTEGER PRIMARY KEY,
vCDFNC INTEGER,
aCDFNC VARCHAR(40)
);


DECLARE
vCDFNC INTEGER;
n INTEGER;
aCDFNC VARCHAR(40);
BEGIN
n := 1;
WHILE n <>
LOOP
SELECT ROUND( dbms_random.VALUE(1,124)) INTO vCDFNC FROM dual;
SELECT DSFNC INTO aCDFNC
FROM ( SELECT a.dsfnc, ROWNUM rnum FROM ( SELECT * FROM TPT154
ORDER BY CDFNC, ROWID ) a WHERE ROWNUM <= vCDFNC )
WHERE rnum > vCDFNC - 1;

INSERT INTO TESTE VALUES( n, vCDFNC, aCDFNC );

n := n + 1;

END LOOP;
END;



Espero que lhe seja útil em algum momento. Pode perguntar se não entender via comentário que terei prazer em lhe ajudar.

Até a próxima.

Reginaldo