SQL Server: Migrando dados entre schemas diferentes

Fala pessoal! Depois de um longo tempo sem postar nada … estou de volta!!

Recentemente participei do projeto de integração entre 4 sistemas e unificação de suas bases de dados. Nessa base, nós dividimos as tabelas de alguns dos módulos específicos utilizando os schemas do SQL Server.

Vamos lá! O cenário é o seguinte: Temos bases diferentes onde o único schema é o dbo. Ao unificarmos as bases, deseja-se separar alguns objetos com schemas próprios (diferentes do dbo). Não consegui encontrar nenhuma ferramenta free que fizesse o trabalho completo e no meu caso e acredito que no caso de muitos, é complicado pagar um preço relativamente alto pra usar uma ferramento 1 ou 2 vezes apenas. Por esse motivo adotei essa solução.

Vou partir do principio que a nova base já está com a estrutura pronta e só é necessário importar os dados da base antiga.

1º Passo é gerar o script com os dados. Um espécie de “backup” … comum em outros SGBDs como PostgreSQL e MySQL.
Para tal, Clique com o botão direito na base que deseja exportar os dados e escolha a opção Tasks > Generate Scripts, como mostra a imagem abaixo:

Como só interessam os dados, escolha apenas as tabelas que deseja exportar. Na próxima tela, marque as opções “save to file”, “single file” e clique em “Advanced”. Nessa tela, você deverá mudar as propriedades: “Schema qualify object names” para “false”, “Script USE DATABASE” para “false” e por último “Types of data to script” para “data only”, como mostra a imagem abaixo:

Mas porque retirar o nome do schema e o “USE DATABASE”? Se o arquivo gerado for muito grande, maior que 2 GB por exemplo, você terá dificuldade para altera-lo em um editor de textos depois e lembre-se que você quer mudar de schema e não continuar com o dbo e a base destino também é diferente. Ah, eu poderia mudar o schema direto na minha base antiga e já exportar certinho? Claro que pode, mas como ainda trata-se da base de produção, quanto menos modificações, melhor … por isso prefiro alterar apenas o script que não causa nenhum impacto na estrutura atual.

Feito isso, pode gerar o script. A depender do tamanho da base, vai demorar um pouco.

2º Passo, depois do script gerado, nós vamos desativar temporariamente todas constraints e triggers. Para tal, você irá precisar rodar os seguintes comandos SQL:

EXEC sp_msforeachtable "ALTER TABLE ? DISABLE TRIGGER ALL"
GO

EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL"
GO

3º Passo, existe um detalhe muito importante agora, como usar o schema se não tem nenhuma referencia no script? O pulo do gato está no default schema do usuário que você irá utilizar na importação. Defina o default schema para o desejado  antes de executar o script de importação.

Agora você tem duas opções: Rodar pelo Management Studio ou pelo linha de comando com o sqlcmd.exe. Se o script for muito grande, você terá que usar o sqlcmd.
Sintaxe: sqlcmd.exe -S <host> -U <usuario> -P <senha> -d <banco destino> -b -i <caminho para o script> -o <log de saída>

Novamente, a depender do tamanho da base, o processo pode levar horas.
Se tudo deu certo até aqui, você já pode habilitar novamente as triggers e contraints:

EXEC sp_msforeachtable "ALTER TABLE ? ENABLE TRIGGER ALL"
GO

EXEC sp_msforeachtable "ALTER TABLE ? CHECK CONSTRAINT ALL"
GO

4º Passo, se tudo deu certo, vai no barzinho mais próximo e pede uma gelada!! \o/
Abrassssss galera!

Listando conteúdo de um arquivo sem repetição usando cat + sed + sort

Hoje precisei fazer um parse em um arquivo de configuração de um script de backup de bases de dados MySQL. O arquivo tem os dados de acesso de vários bancos, organizados por linha e estruturado da seguinte forma:

servidor porta banco usuario senha

O objetivo de fazer o parse nesse arquivo era de recuperar as duas primeiras colunas (servidor e porta) para formar o path de onde os arquivos sql estão armazenados, já que o dump é feito de acordo com o servidor, instância (porta) e período (mês-ano). Um caminho válido seria:
/media/servidor.com.br/3306/09-2009.

Meu problema é que existem várias entradas para a mesma instância do MySQL (Servidor/Porta) e precisava de um lista sem duplicidade, como num SELECT DISTINCT.
Para resolver o problema basta usar a linha de comando:

cat arquivo | sed -e 's/\(.*\) \(.*\) \(.*\) \(.*\) \(.*\)/\1\/\2/' | sort -u

Mas o que diabos isso ai faz? De uma forma bem resumida, o comando acima realiza a leitura do arquivo e passa a saída via pipe para o sed. O sed por sua vez, divide os dados em cinco colunas (cada \(.*\) representa uma coluna) e retorna como saída apenas as duas primeiras (servidor e porta no sed é o trecho /\1\/\2/) e passa o resultado para o comando sort. O sort é que faz a “mágica” do DISTINCT, sort -u exibe apenas as linhas únicas :p

Problema resolvido, mais uma batalha vencida 😀

Abrasss

Tutorial básico de shell script

Hoje eu precisei criar um pequeno script shell para realizar algumas configurações de um software que desenvolvi e ai me lembrei que a um tempo atrás, quando eu ainda estava na faculdade ( putz, faz trocentos anos isso ), fiz um tutorial básicão para mexer com shell script e acabei não disponibilizando isso .. não lembro bem porque. Bom desenterrei ele e vou postar ele aqui.

1 – Introdução
2 – Estrutura Básica
3 – Váriáveis
4 – Aspas simples, Aspas duplas e Crase
5 – O Comando Echo
6 – Expressões
7 – O Comando if
8 – Laço condicional While
9 – For
10- Case
11- Finalizando
12- Fonte de Pesquisa e Recomendação de leitura

1 – Introdução

Shell Script são programas interpretados por programas conhecidos como Shell.
A Shell é o elo de ligação entre o usuário e o Sistema. A shell é responsável por
interpretar os comandos passados pelo usuário.
Os Shell Scripts são largamente utilizados para automatizar tarefas administrativas
e simplificar ações dirárias como por exemplo efetuar um backup, mapear unidades de
rede samba, limpar diretório temporários etc.
Nesse artigo, iremos trabalhar com a shell bash, mas fique a vontade para trabalhar
com a shell que mas lhe agrade.

2 – Estrutura Básica

Todo shell script deve começar com uma instrução tipo #!/bin/bash. Essa instrução indica
quem é o programa responsável por interpretar os camandos contidos no script.
Caso o script fosse escrito em KSH, por exemplo, a linha ficaria #!/bin/ksh. Isso também
acontece em outras linguagens de programação interpretada tais como perl
(#!/bin/perl). Em seguida vem a sequencia de comandos que se deseja executar.
O caracter # é o caracter de comentário de linha (exceto na primeira instrução mencionada acima).
Tudo que estiver após o caracter # é ignorado pelo interpretador até que o caracter de fim de linha
seja encontrado.
Ex.:

#!/bin/bash
# Exemplo classico do alo mundo
echo “Alo Mundo”

Para que seu script possa ser executado, você tem que torna-lo executável com o comando chmod:
user@linuxbox:/$ chmod a+x meu_script

3 – Variáveis

3.1 – Declarando váriaveis

As variáveis em shell Script são declaradas implicitamente. para se declarar a variável, basta
atribuir-lhe um valor.
Ex.:

#!/bin/bash
var1=’Minha primeira variavel’

Para se referir a uma variavel dentro do script, é necessário usar o caracter $ antes do nome
da mesma. Assim você está se referindo ao conteudo da variavel.
Para se atribuir valores a variável o caracter $ não é utilizado
Ex.:

#!/bin/bash
var1=”Minha primeira variavel” #Atribuindo valor
echo $var1                     #Se referindo ao conteúdo da variável

3.2 – Recebendo entradas externas

O comando Read faz com que variaveis possam receber entradas do usuário.
Quando o script encontra um comando Read, ele para sua execução e aguarda
que o usuário informe os dados e tecle enter, para concluir a operação.
Ex.:

#!/bin/bash
Read nome
Echo “Meu nome é $nome”

3.3 – Variáveis passadas por parâmentro de linha de comando

As variáveis passadas por linha de comando, podem ser acessadas pelo número referente a posição em que
ela se encontrava quando foi passada. A variável $0 se refere ao nome do programa, $1 ao primeiro
parâmentro e assim por diante.
Ex.:

user@linuxbox:/$ meu_script.sh parametro1 parametro2
Sendo que:
$0 = meu_script.sh
$1 = parametro1
$2 = parametro2

A quantidade de parâmetros passados para o script (equivalente ao argc do C) fica armazenado
na variável $#.
Ex.:

#!/bin/bash
echo “Foram passados “$#” parâmetros”

4 – Aspas simples, Aspas duplas e Crase

Há muita diferença entre eles. A função da Aspas Simples é a de assumir a string sem que nada
seja processado. Já com as Aspas Duplas, as variáveis são processados dentro da string.
A Crase processam COMANDOS e adcionam à string, a resposta do mesmo.
Ex:
var = ‘Olá, eu sou $USER’
O Conteúdo de var é: Olá, eu sou $USER – A variavel $USER não foi processado. Tudo que
se encontra dentro das aspas simples é entendido literalmente.

var = “Olá, eu sou $USER”
Agora var contém: Olá, eu sou root – A variavel $USER agora vai devidamente processada e
seu valor passado para string.

var = “Eu agora estou em: `pwd`”
A Crase passa a saida de pwd para a string.
O conteúdo de var ficou: Eu agora estou em: /etc/rc.d

5 – O Comando Echo

A finalidade do comando Echo é exibir informações, que vão desde simples strings até uma mescla de
strings e variaveis e passar o cursor para a proxima linha. É bem similar ao puts() do C.

Ex.:

#!/bin/bash
var1=”Fernando”
echo “Aews $var1”

O Resultado será: Aewz Fernando

6 – Expressões

O comando Expr, informa o script que a proxima instrução se trata de uma expressão.
O formato de uma expressão é algo do tipo: expr $var “+” 1 ou `expr $var + 1`
Ex.:

#!/bin/bash
Echo “Digite um numero”
read num1
echo “Digite outro numero”
read num2
echo “`expr $num1 + $num2`”

7 – O comando if

O comando if, como você já deve saber, executa determinados comandos caso a expressão
em questão seja verdadeira. Acontece que uma expressão verdadeira para ele não é como
da forma que agente está acostumado. Uma condição no if é sempre um comando e todo comando
tem uma saida. Normalmente, quando a saida é 0, significa que o comando foi concluido
com sucesso. Valores superiores a 0, normalmente significam que algo de errado aconteceu,
logo, 0 significa verdadeiro para o if e 1 falso.
Um if normalmente é seguido do comando test.
Ex.:

if rm /etc/teste.txt; then
echo “Arquivo excluido”
fi

No bloco if acima, o comando rm é executado e o valor de retorno é passado para o if.
Caso rm termine sem problemas, 0 é retornado e a condição se torna verdadeira.

if test “a” = “a”; then
echo “Igual”
else
echo “Diferentes”
fi

Na instrução acima, o comando test retorna 0, pois “a” = “a”. Para entender melhor
o funcionamento do comando test vá a linha de comando e execute-o, para saber o que ele
retornou basta recorrer a variavel de ambiente $? que armazena a saida do ultimo comando.
Ex.:

user@linuxbox:/$ test “a” = “a”
user@linuxbox:/$ echo $?
0
user@linuxbox:/$ test “a” = “b”
user@linuxbox:/$ echo $?
1

Segue abaixo alguns dos parametros do comando test:

-b arquivo – Verdadeiro se arquivo é um arquivo de bloco, como /dev/hda.
-c arquivo – Verdadeiro se arquivo é um arquivo de caracter, como /dev/tty1.
-d arquivo – Verdadeiro se arquivo é um diretório.
-e arquivo – Verdadeiro se arquivo existe.
-f arquivo – Verdadeiro se arquivo existe e é um arquivo comum.
-s arquivo – Verdadeiro se arquivo existe e não é vazio.
-h arquivo – Verdadeiro se arquivo é um link simbólico.
-p arquivo – Verdadeiro se arquivo é um “named pipe” (fifo, lifo, etc).
-S arquivo – Verdadeiro se arquivo é um “socket”.
-k arquivo – Verdadeiro se arquivo tem seu “sticky bit” ligado.
-r arquivo – Verdadeiro se arquivo pode ser lido pelo usuário atual.
-w arquivo – Verdadeiro se arquivo pode ser escrito pelo usuário atual.
-x arquivo – Verdadeiro se arquivo pode ser executado pelo usuário atual.
-O arquivo – Verdadeiro se arquivo pertence ao usuário atual.
-G arquivo – Verdadeiro se arquivo pertence ao grupo do usuário atual.
-N arquivo – Verdadeiro se arquivo foi modificado desde a ultima vez que foi lido.
-eq (equal): Igual;
-ne (not-equal): Não Igual (diferente);
-lt (less than): Menor que (<);
-le (less than or equal): Menor ou igual ( <= );
-gt (greater than): Maior que (>);
-ge (greater than or equal): Maior ou igual (>=);

Test pode ser substituido por [], tornando o código mais legivél.
Ex.:

if [“a” = “a”];then
echo “Igual”
else
echo “diferente”
fi

8 – Laço condicional While

O Comando while, como o nome diz, executa um bloco de instruções enquanto uma
condição for verdadeira. O tratamento de expressões é feita da mesma forma que
acontece com o comando if.
Ex.:

cont = 0
while [$cont -ne 10]; do
echo $cont;
cont = expr $cont “+” 1;
done;

9 – For

for {variavel} in {lista} [lista]*;
do
comandos..
done;

O comando For executa um bloco de instruções até que a lista de elemntos termine.
a variavel é associada a cada elemento da lista e então o bloco de comandos é executado
a cada vez que a variavel é associada.
Ex.:

for arquivo in rc.local rc.M rc.httpd;
do
echo $arquivo
done;

A saida será:
rc.local
rc.M
rc.httpd

10 – Case

Um das intruções mais utilizadas em Shell Script. O Case funciona de maneira bem
similar ao if. Na verdade uma sequencia de ifs aninhados.
Ele é muito usado para checar parametros de linha de comando para realizar operações
com daemons (startar, restartar, parar daemons).
Ex.: – retirado do site Olinux

case “$1” in

‘start’ )
echo “Iniciando o serviço…”
<comandos para iniciar o serviço>
;;
‘restart’ )
echo “Reinicializando o serviço…”
<comandos para reinicializar o serviço>
;;
‘stop’ )
echo “Parando o serviço…”
<comandos para parar o serviço>
;;
*)
echo “Opção invalida!”
echo “As opções válidas são:
start,   stop   e   restart”
;;
esac

11- Finalizando

Espero ter ajudado a passar um pouco sobre o poder dos shell scripts.
Qualquer dúvida, sugestão, correção etc… manda uma email.
flw, Abraços, T+

12- Fonte de Pesquisa e Recomendação de leitura

http://www.olinux.com.br
http://tlm.conectiva.com.br/shell_script/
http://thobias.org/doc/cgi_shell.html
http://thobias.org/doc/shell_bd.html
http://www.vivaolinux.com.br