none
Como replicar alterações estruturais para os Clientes? RRS feed

  • Pergunta

  • Olá!

    Sou desenvolvedor de uma aplicação que trabalha atualmente com banco de dados Access.

    Há bastante tempo desenvolvi um aplicativo em VB6 que compara 2 arquivos .mdb, e replica as diferenças do primeiro para o segundo, criando scripts sql (como alteração de tipos de campos, novos campos, novas tabelas etc.).

    Isto sempre facilitou a replicação das alterações da estrutura do banco de dados, pois enviava um arquivo .mdb atualizado no pacote de atualização e executava esta rotina que incrementava os bancos de dados dos clientes com as alterações, evitando falhas manuais.

    Gostaria de saber como vocês trabalham com isso no SQL SERVER 2008 R2, já que cada cliente tem seu servidor e seus bancos de dados têm de ser atualizados com as alterações feitas no ambiente de desenvolvimento.

    Desde já agradeço enormemente a atenção!

    Forte abraço!

    Heitor C. Passos


    Enjoy the Silence...
    • Movido Gustavo Maia Aguiar segunda-feira, 23 de maio de 2011 16:20 (De:SQL Server - Desenvolvimento Geral)
    segunda-feira, 23 de maio de 2011 14:22

Respostas

  • Boa Tarde,

    Não creio que alternativas como replicação transacional se apliquem nesse caso. Para que a replicação transacional funcionasse, necessariamente a matriz teria de estar conectável com todos os clientes. Isso talvez fosse adequado para uma matriz com escritórios regionais, mas me parece que o cenário está mais voltado para uma software house que comercializa um software com vários clientes e se esse for o caso, a replicação transacional não seria viável em virtude dos links de comunicação. Além do mais, a replicação transacional replica dados e não estrutura. Ainda que a partir do 2005, seja possível replicar alterações de estrutura, a replicação transacional não iria replicar a estrutura de novas tabelas, procedures, views, triggers, etc (típicas de pacotes de atualização).

    No caso do SQL Server 2008 R2, você pode procurar mais informações sobre um recurso chamado DAC. Não me refiro a Dedicated Administrator Connection, mas a Data Tier Applications (até hoje não sei porque se chama DAC). Esse recurso é próprio para fazer Deploy de bancos de dados concentrando em um único pacote executável um conjunto de atualizações do SQL Server. Muitas vezes é mais interessante que aplicar scripts de forma independente. É ótimo para fazer Deploy, mas não é tão eficiente no seu objetivo de comparação. Se você realmente precisar comparar estruturas, um bom ponto de partida é comparar com base no catálogo (INFORMATION_SCHEMA.COLUMNS).

    [ ]s,

    Gustavo Maia Aguiar
    http://gustavomaiaaguiar.wordpress.com


    Classifique as respostas. O seu feedback é imprescindível
    segunda-feira, 23 de maio de 2011 20:01
  • Heitor,



    Eu poderia te passar cada passo mas fica mais facil te passando as rotinas, sendo apenas parte do projeto não 
    tem problema algum com a propriedade do código, pode usar e transmitir a outros.

    (poderia ser problema eu disponibilizar o webform todo... ou o projeto todo)


    '-----------------------------------------------------
    'Essa é a função para criar um arquivo delimitado, com dados para posteriormente atualizar
    'Neste ponto eu rodo a rotina com a conexão setada p/ meu servidor, onde está meu BD atualizado (este modi.strSql é a string de conexão).
    'está em VB, mas acredito que facilmente se traduza para C#


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim ff As Integer = FreeFile()

    Dim dma As String = Format(Now, "ddMMyy")
    Dim arquivo As String = Server.MapPath("SQL\BancoSQL_" & dma & ".txt")
    Dim arq As String = "SQL/BancoSQL_" & dma & ".txt"
    Dim sql As String = ""

    Dim folder As Directory
    Dim path As String = Server.MapPath("SQL")
    If folder.Exists(path) = False Then
    folder.CreateDirectory(path)
    End If

    sql = "SELECT table_name, column_name, data_type, character_maximum_length"
    sql += ",column_default,is_nullable FROM INFORMATION_SCHEMA.COLUMNS "
    sql += " WHERE TABLE_NAME <> 'dtproperties' AND EXISTS "
    sql += " (SELECT 'x' FROM SYSOBJECTS "
    sql += " WHERE TYPE = 'U' AND SYSOBJECTS.NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME) "
    'novo
    sql += " AND SUBSTRING(table_name, 1, 3) <> 'sys' AND SUBSTRING(table_name, 1, 5) <> 'MSpub' "
    'fim
    sql += " ORDER BY table_name" ', column_name"
    Dim i As Integer = 0
    Dim espaco As String = ""
    Dim c As New SqlConnection(modi.strSql) : c.Open()
    Dim dr As SqlDataReader : Dim cmd As SqlCommand
    cmd = New SqlCommand(sql, c) : dr = cmd.ExecuteReader
    Dim Tabela As String = ""
    Dim Campo As String = ""
    Dim tipo As String = ""
    Dim tam As Long
    Dim def As String = ""
    Dim x As Integer = 0
    FileOpen(ff, arquivo, OpenMode.Output)
    While dr.Read

    espaco = ""
    Tabela = dr("table_name") '50 casas
    x = 50 - Val(Len(Tabela))
    For i = 1 To x
    espaco += " "
    Next
    Tabela += espaco

    espaco = ""
    Campo = dr("column_name") '30 casas
    x = 30 - Val(Len(Campo))
    For i = 1 To x
    espaco += " "
    Next
    Campo += espaco

    espaco = ""
    tipo = dr("data_type") '20 casas
    x = 20 - Val(Len(tipo))
    For i = 1 To x
    espaco += " "
    Next
    tipo += espaco

    tam = 0
    If Not IsDBNull(dr("character_maximum_length")) Then
    tam = dr("character_maximum_length")
    End If


    espaco = ""
    def = ""
    If Not IsDBNull(dr("column_default")) Then
    def = dr("column_default") '30 casas
    End If
    x = 30 - Val(Len(def))
    For i = 1 To x
    espaco += " "
    Next
    def += espaco


    espaco = ""
    Dim nulo As String = ""
    If Not IsDBNull(dr("is_nullable")) Then
    nulo = dr("is_nullable")
    End If
    x = 5 - Val(Len(nulo))
    For i = 1 To x
    espaco += " "
    Next
    nulo += espaco


    PrintLine(ff, TAB(1), Tabela & Campo & tipo & Format(tam, "0000000000") & def & nulo)

    End While
    dr.Close()
    c.Close()

    PrintLine(ff, TAB(1), "FIM")
    FileClose(ff)
    mensagem("Arquivo BancoSQL_" & dma & ".net gerado com sucesso!", Color.Green)

    End Sub








    '-----------------------------------------------------
    'Depois de gerar, tem que de alguma maneira transmitir este arquivo para o servidor de aplicação do cliente.
    'E esta função é para ler o arquivo e efetuar as atualizações no cliente
    'Talvez tenha algumas partes que não se apliquem ao seu caso, como a parte que ele altera as collations (tive

    problemas com isso, quando há algum t-sql que concatena colunas com 2 collations diferentes....)
    'Eu alterei algumas coisas que estavam especificas , mas talvez tenha ficado alguns nomes de variaveis ou

    tabelas particulares do meu sistema ainda...
    'Ja tem um comando q faz um backup full antes de fazer a atualização, em caso de der algum problema... no

    meu caso estou deixando opcional, pois fica bem mais demorado, e nunca deu nenhum problema



    Sub Atualizatabelas()


    Dim conn As New conn
    Dim tabela As String = ""
    Dim TestaTabela As String = ""
    Dim campo As String = ""
    Dim tipo As String = ""
    Dim tam As String = ""
    Dim tabe As String = ""
    Dim TabNaoExistem As String = ""
    Dim Defout As String = ""
    Dim rs As New ADODB.Recordset
    Dim atu As String = ""
    Dim flg As Boolean = False
    Dim Nulo As String = ""

    mensagem("", Color.Green)

    If txtdma.Text = "" Then
    mensagem("Informe a data!", Color.Red)
    Response.Cookies("Focus").Value = "txtdma"
    Exit Sub
    End If
    If Len(txtdma.Text) <> 6 Then
    mensagem("Data inválida!", Color.Red)
    Response.Cookies("Focus").Value = "txtdma"
    Exit Sub
    End If



    'Vai fazer uma copia antes de alterar o banco
    Dim folder As Directory
    Dim Path As String = Server.MapPath("SQL")
    'Dim Local As String = Replace(Path, "/", "\", 1)
    'Local += "\"
    If folder.Exists(Path) = False Then
    folder.CreateDirectory(Path)
    End If

    Dim arquivoBanco As String = Server.MapPath("SQL/BancoSQL_" & txtdma.Text & ".txt")
    If IO.File.Exists(arquivoBanco) = False Then
    mensagem("Arquivo não encontrado!", Color.Red)
    modi.SetFocus("txtdma")
    Exit Sub
    End If


    Dim Local As String = "" ' Replace(Path, "/", "\", 1)
    Local = modi.LeRegistro("cd_cf_geral", "LocalCopia", " cod = 1")
    If Local = "" Then
    mensagem("Não foi definido o local de Cópia do SQL", Color.Red)
    Exit Sub
    End If
    Local += "\"
    Dim nomebkp As String = "Sistema backup " & Format(Now, "ddMMyyyy")



    'Obs:Onde sera gravado o bkp esta na variavel "local" Tem que ser um local no PC que esta o servidor do

    SQL.
    'com o server.mapPath pega o caminho do aplicativo e o banco sql pode estar em outra maquina ai não vai

    fazer o bkp
    'da erro , pois o bkp so é feito na maquina onde esta instalado o SQL.
    On Error GoTo trata

    If chkBkpOpcional.Checked = True Then
    Dim B As ADODB.Connection
    B = New ADODB.Connection
    B.Open(modi.strOledb)
    B.Execute("BACKUP DATABASE [Sistema] TO DISK = N'" & Local & nomebkp & "' WITH INIT ,

    NOUNLOAD , NAME = N'" & nomebkp & "', SKIP , STATS = 10, NOFORMAT")
    B.Close()
    End If



    Dim dma As String = txtdma.Text
    Dim arqLog As String = Server.MapPath("SQL\Log_" & dma & ".txt")
    Dim arqLog2 As String = "SQL/Log_" & dma & ".txt"

    Dim ff As Integer = FreeFile()
    'abre para gravar as tabelas nao encontradas

    FileOpen(ff, arqLog, OpenMode.Output)

    Dim flgIntegracaogrupo As Boolean = False

    'novo 05112008
    Dim CollationBANCO As String
    Dim CollationCampo As String
    'pega o collation padrao do banco...
    Dim cB As New SqlConnection(modi.strSql) : cB.Open()
    Dim drB As SqlDataReader : Dim cmdB As SqlCommand
    cmdB = New SqlCommand("SP_HELPDB", cB)
    drB = cmdB.ExecuteReader(CommandBehavior.CloseConnection)
    While drB.Read
    If UCase(drB("Name")) = UCase(conn.Connecta(2)) Then
    'If UCase(drB("Name")) = UCase("FERTIMAR") Then
    CollationBANCO = drB("Status")
    CollationBANCO = Mid(CollationBANCO, InStr(CollationBANCO, "Collation=") + 10,

    Len(CollationBANCO))
    CollationBANCO = Mid(CollationBANCO, 1, InStr(CollationBANCO, ",") - 1)
    Exit While
    End If
    End While
    cB.Close()
    drB.Close()

    Dim cont As Integer = 0
    Dim arquivo As String = Server.MapPath("SQL\BancoSQL_" & dma & ".txt")
    Dim arq As StreamReader = New StreamReader(arquivo)
    Dim Nrlinha As Integer
    Dim linha As String = ""
    While arq.BaseStream.CanRead


    cont += 1
    If cont = 151 Then
    mensagem("", Color.Red)
    End If

    linha = arq.ReadLine
    If Mid(linha, 1, 3) = "FIM" Then
    Exit While
    End If

    tabela = Trim(Mid(linha, 1, 50))
    campo = Trim(Mid(linha, 51, 29))
    tipo = Trim(Mid(linha, 81, 19))
    'tam = Mid(linha, 101, 5)
    tam = Mid(linha, 101, 10)
    'Defout = Trim(Mid(linha, 106))
    Defout = Trim(Mid(linha, 111, 30))

    'Somente quando cria
    Nulo = Trim(Mid(linha, 141, 5))


    sql = "SELECT table_name FROM INFORMATION_SCHEMA.tables "
    sql += " WHERE table_name = '" & tabela & "'"
    sql += " group by table_name"


    tabe = tabela

    Dim c As New SqlConnection(modi.strSql) : c.Open()
    Dim dr As SqlDataReader : Dim cmd As SqlCommand
    cmd = New SqlCommand(sql, c)
    dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    While dr.Read
    tabe = "" 'se acho limpa
    sql = "SELECT Collation_Name,column_name,data_type ,isnull(character_maximum_length,0) as

    length FROM INFORMATION_SCHEMA.columns"
    sql += " WHERE table_name = '" & tabela & "'"
    sql += " And column_name = '" & campo & "'"
    Dim c1 As New SqlConnection(modi.strSql) : c1.Open()
    Dim dr1 As SqlDataReader : Dim cmd1 As SqlCommand
    cmd1 = New SqlCommand(sql, c1)
    dr1 = cmd1.ExecuteReader(CommandBehavior.CloseConnection)
    'testa se o campo existe na tabela do cliente
    'Se nao achou entra e atualiza a tabela
    If Not dr1.Read Then


    Dim c2 As New SqlConnection(modi.strSql) : c2.Open()
    Dim cmd2 As SqlCommand

    Dim def As String = ""
    If Defout <> "" Then
    'If tipo = "char" Or tipo = "nchar" Or tipo = "varchar" Or tipo = "nvarchar" Then
    ' 'se for string tem aspas
    ' def = "DEFAULT ('" & Defout & "')"
    'Else
    def = "DEFAULT " & Defout
    'End If
    End If
    Dim var As String = campo & " " & tipo
    If Val(tam) > 0 Then
    var += "(" & tam & ")"
    End If

    If UCase(Nulo) = "YES" Then
    var += " NULL "
    End If
    If UCase(Nulo) = "NO" Then
    var += " NOT NULL "
    End If

    If def <> "" Then
    var += " " & def
    End If



    cmd2 = New SqlCommand("alter table " & tabela & " add " & var, c2)
    cmd2.CommandTimeout = 0
    cmd2.ExecuteNonQuery()



    'Se vem campo default deve preencher a tabela com o valor dele
    If def <> "" Then
    def = Replace(def, "DEFAULT", "", 1)
    def = Replace(def, "(", "", 1)
    def = Replace(def, ")", "", 1)
    def = Trim(def)
    Dim str As String = "update " & tabela & " set " & campo & " = " & def
    cmd2 = New SqlCommand(str, c2)
    cmd2.CommandTimeout = 0
    cmd2.ExecuteNonQuery()
    End If

    c2.Close()
    atu += "Tabela: " & tabela & " campo:" & campo

    Else
    'Achou mas verifica se o campo continua o mesmo tipo de varicavel
    'Ex: se esta varchar de 6 e vai atualizar para varchar de 10
    'de Int para varchar etc....

    'novo 05112008
    If IsDBNull(dr1("Collation_Name")) = True Then
    CollationCampo = ""
    Else
    CollationCampo = dr1("Collation_Name")
    End If

    'If tipo <> dr1("data_type") Or tam <> Val(dr1("length")) Then
    'novo 05112008
    If tipo <> dr1("data_type") Or tam <> Val(dr1("length")) Or (CollationBANCO <> CollationCampo

    And CollationCampo <> "") Then

    Dim c3 As New SqlConnection(modi.strSql) : c3.Open()
    Dim cmd3 As SqlCommand
    Dim str As String = ""

    str = "ALTER TABLE " & tabela & " ALTER COLUMN " & campo
    str += " " & tipo
    'Aqui mudou o tamanha ex.: varchar de 6 para 100
    If Val(tam) <> dr1("length") Then
    'quando vem tipo int,bigint nao precisa expecificar o tam
    'pois ele ficao padarao conforme o tipo da variavel
    If Val(tam) > 0 Then str += "(" & tam & ")"
    End If

    'novo 05112008
    If CollationBANCO <> CollationCampo Then
    If CollationCampo <> "" Then
    If InStr(str, ")") = 0 Then
    str += "(" & Val(tam) & ")"
    End If
    str += " collate " & CollationBANCO
    End If
    End If

    Erro = str
    cmd3 = New SqlCommand(str, c3)
    cmd3.CommandTimeout = 0
    cmd3.ExecuteNonQuery()
    c3.Close()
    Erro = ""


    End If

    End If
    dr1.Close()


    End While
    dr.Close()



    If tabe <> "" Then
    flg = True
    If tabela <> TestaTabela Then
    PrintLine(ff, TAB(1), "tabela não encontrada: " & tabela)
    TestaTabela = tabela
    End If
    End If
    End While
    arq.Close()



    FileClose(ff)

    'Dim msgExtra As String = ""
    If flg = True Then
    'msgExtra = "Verficar arquivo de Log_" & dma
    modi.AbreArquivo(arqLog2, "tela", False)
    End If
    mensagem("Banco Atualizado!, Backup salvo em " & Local, Color.Green)

    trata:
    If Err.Number <> 0 Then
    'se der algum erro pelo menos fecha o arq.
    'para quando tentar de novo ano estar aberto
    If Err.Number = 5 Then
    Dim msg As String = "Erro encontrado: " & Err.Number & " " & Err.Description
    msg += "-" & Erro & "-" & cont
    PrintLine(ff, TAB(1), msg)
    Resume Next
    Else
    FileClose(ff)
    If Err.Number = 53 Then
    mensagem("Arquivo não existe!!!", Color.Red)
    Response.Cookies("Focus").Value = "txtdma"
    Else
    mensagem("Erro: " & Err.Description, Color.Red)

    End If
    End If

    End If

    End Sub




    Ah, neste webform eu uso:
    Imports System.IO
    Imports System.IO.File
    Imports System.Data.OleDb
    Imports System.Data.SqlClient



    Ve se da para tirar alguma ideia, ou mesmo usar como está (alterando apenas para se adequar ao teu caso)
    se nao entender algo, ou qualquer coisa que precisar extra para fazer isso funcionar, pode pedir aí...



    []s







    • Editado Julio Costi sábado, 28 de maio de 2011 15:44 msdn fez confusão com o html
    • Marcado como Resposta Richard Juhasz segunda-feira, 6 de junho de 2011 20:26
    sábado, 28 de maio de 2011 15:31

Todas as Respostas

  • Bem, caso eu não tenha sido objetivo, minha dúvida é:

    Como vocês atualizam as alterações feitas durante o desenvolvimento do banco de dados, para os bancos de dados de seus clientes?

    Abraços!


    Enjoy the Silence...
    segunda-feira, 23 de maio de 2011 17:23
  • Heior,

     

    Bem, não sei se vivemos exatamente este cenario, o que temos na maioria das vezes é um banco de dados de teste, que quando é feito alguma alteração, o mesmo não é automaticamente replicado para produção por motivos obvios, o que pode ser feito, até onde entendi, creio que replicação seria a melhor opção, a transacional por exemplo, seria algo mais ou menos assim:

    Banco Matriz -> Filial

     

    Ha como fazer que em determinadas tabelas (Até todas, mas obvio que não é recomendado), qualquer comando que seja executado no banco da matriz, tambem seja executado no banco da filial.... 


    Oracle OCA11g, MCC 2011! Dicas e novidades: www.fabrizziocaputo.wordpress.com
    segunda-feira, 23 de maio de 2011 18:40
    Moderador
  • Boa Tarde,

    Não creio que alternativas como replicação transacional se apliquem nesse caso. Para que a replicação transacional funcionasse, necessariamente a matriz teria de estar conectável com todos os clientes. Isso talvez fosse adequado para uma matriz com escritórios regionais, mas me parece que o cenário está mais voltado para uma software house que comercializa um software com vários clientes e se esse for o caso, a replicação transacional não seria viável em virtude dos links de comunicação. Além do mais, a replicação transacional replica dados e não estrutura. Ainda que a partir do 2005, seja possível replicar alterações de estrutura, a replicação transacional não iria replicar a estrutura de novas tabelas, procedures, views, triggers, etc (típicas de pacotes de atualização).

    No caso do SQL Server 2008 R2, você pode procurar mais informações sobre um recurso chamado DAC. Não me refiro a Dedicated Administrator Connection, mas a Data Tier Applications (até hoje não sei porque se chama DAC). Esse recurso é próprio para fazer Deploy de bancos de dados concentrando em um único pacote executável um conjunto de atualizações do SQL Server. Muitas vezes é mais interessante que aplicar scripts de forma independente. É ótimo para fazer Deploy, mas não é tão eficiente no seu objetivo de comparação. Se você realmente precisar comparar estruturas, um bom ponto de partida é comparar com base no catálogo (INFORMATION_SCHEMA.COLUMNS).

    [ ]s,

    Gustavo Maia Aguiar
    http://gustavomaiaaguiar.wordpress.com


    Classifique as respostas. O seu feedback é imprescindível
    segunda-feira, 23 de maio de 2011 20:01
  • Eu pesquisei muito isso, e tambem não consegui nada "automatico"

     

    Na empresa, temos um codigo em vb.net (generico, para varios sistemas) que gera um arquivo com todos os campos, tipos e tamanhos,

    e uma rotina que faz o processo inverso, isso é, que verifica se esses campos existem e se está com o mesmo  tipo/tamanho na base dos clientes (produção).

     

    vou ver se consigo  colocar o codigo aqui

    terça-feira, 24 de maio de 2011 19:25
  • Muito obrigado pelas contribuições!

    Gustavo, nosso caso é exatamente o que você entendeu.

    Vou estudar sobre o DAC (também não entendi o porque desta sigla^^), mas provavelmente eu tenha de estruturar um algoritmo como o mencionado pelo Julio.

    Minha dúvida ainda é com base em que (se script ou outro arquivo) eu vou poder comparar o SCHEMA do meu servidor com os dos Clientes.

    Se você puder compartilhar algo Julio, eu agradeço, mas não se preocupe em me passar o código fonte, imagino que seja patrimônio de sua companhia.

    Abraços a todos!


    Enjoy the Silence...
    sexta-feira, 27 de maio de 2011 13:43
  • Heitor,



    Eu poderia te passar cada passo mas fica mais facil te passando as rotinas, sendo apenas parte do projeto não 
    tem problema algum com a propriedade do código, pode usar e transmitir a outros.

    (poderia ser problema eu disponibilizar o webform todo... ou o projeto todo)


    '-----------------------------------------------------
    'Essa é a função para criar um arquivo delimitado, com dados para posteriormente atualizar
    'Neste ponto eu rodo a rotina com a conexão setada p/ meu servidor, onde está meu BD atualizado (este modi.strSql é a string de conexão).
    'está em VB, mas acredito que facilmente se traduza para C#


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim ff As Integer = FreeFile()

    Dim dma As String = Format(Now, "ddMMyy")
    Dim arquivo As String = Server.MapPath("SQL\BancoSQL_" & dma & ".txt")
    Dim arq As String = "SQL/BancoSQL_" & dma & ".txt"
    Dim sql As String = ""

    Dim folder As Directory
    Dim path As String = Server.MapPath("SQL")
    If folder.Exists(path) = False Then
    folder.CreateDirectory(path)
    End If

    sql = "SELECT table_name, column_name, data_type, character_maximum_length"
    sql += ",column_default,is_nullable FROM INFORMATION_SCHEMA.COLUMNS "
    sql += " WHERE TABLE_NAME <> 'dtproperties' AND EXISTS "
    sql += " (SELECT 'x' FROM SYSOBJECTS "
    sql += " WHERE TYPE = 'U' AND SYSOBJECTS.NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME) "
    'novo
    sql += " AND SUBSTRING(table_name, 1, 3) <> 'sys' AND SUBSTRING(table_name, 1, 5) <> 'MSpub' "
    'fim
    sql += " ORDER BY table_name" ', column_name"
    Dim i As Integer = 0
    Dim espaco As String = ""
    Dim c As New SqlConnection(modi.strSql) : c.Open()
    Dim dr As SqlDataReader : Dim cmd As SqlCommand
    cmd = New SqlCommand(sql, c) : dr = cmd.ExecuteReader
    Dim Tabela As String = ""
    Dim Campo As String = ""
    Dim tipo As String = ""
    Dim tam As Long
    Dim def As String = ""
    Dim x As Integer = 0
    FileOpen(ff, arquivo, OpenMode.Output)
    While dr.Read

    espaco = ""
    Tabela = dr("table_name") '50 casas
    x = 50 - Val(Len(Tabela))
    For i = 1 To x
    espaco += " "
    Next
    Tabela += espaco

    espaco = ""
    Campo = dr("column_name") '30 casas
    x = 30 - Val(Len(Campo))
    For i = 1 To x
    espaco += " "
    Next
    Campo += espaco

    espaco = ""
    tipo = dr("data_type") '20 casas
    x = 20 - Val(Len(tipo))
    For i = 1 To x
    espaco += " "
    Next
    tipo += espaco

    tam = 0
    If Not IsDBNull(dr("character_maximum_length")) Then
    tam = dr("character_maximum_length")
    End If


    espaco = ""
    def = ""
    If Not IsDBNull(dr("column_default")) Then
    def = dr("column_default") '30 casas
    End If
    x = 30 - Val(Len(def))
    For i = 1 To x
    espaco += " "
    Next
    def += espaco


    espaco = ""
    Dim nulo As String = ""
    If Not IsDBNull(dr("is_nullable")) Then
    nulo = dr("is_nullable")
    End If
    x = 5 - Val(Len(nulo))
    For i = 1 To x
    espaco += " "
    Next
    nulo += espaco


    PrintLine(ff, TAB(1), Tabela & Campo & tipo & Format(tam, "0000000000") & def & nulo)

    End While
    dr.Close()
    c.Close()

    PrintLine(ff, TAB(1), "FIM")
    FileClose(ff)
    mensagem("Arquivo BancoSQL_" & dma & ".net gerado com sucesso!", Color.Green)

    End Sub








    '-----------------------------------------------------
    'Depois de gerar, tem que de alguma maneira transmitir este arquivo para o servidor de aplicação do cliente.
    'E esta função é para ler o arquivo e efetuar as atualizações no cliente
    'Talvez tenha algumas partes que não se apliquem ao seu caso, como a parte que ele altera as collations (tive

    problemas com isso, quando há algum t-sql que concatena colunas com 2 collations diferentes....)
    'Eu alterei algumas coisas que estavam especificas , mas talvez tenha ficado alguns nomes de variaveis ou

    tabelas particulares do meu sistema ainda...
    'Ja tem um comando q faz um backup full antes de fazer a atualização, em caso de der algum problema... no

    meu caso estou deixando opcional, pois fica bem mais demorado, e nunca deu nenhum problema



    Sub Atualizatabelas()


    Dim conn As New conn
    Dim tabela As String = ""
    Dim TestaTabela As String = ""
    Dim campo As String = ""
    Dim tipo As String = ""
    Dim tam As String = ""
    Dim tabe As String = ""
    Dim TabNaoExistem As String = ""
    Dim Defout As String = ""
    Dim rs As New ADODB.Recordset
    Dim atu As String = ""
    Dim flg As Boolean = False
    Dim Nulo As String = ""

    mensagem("", Color.Green)

    If txtdma.Text = "" Then
    mensagem("Informe a data!", Color.Red)
    Response.Cookies("Focus").Value = "txtdma"
    Exit Sub
    End If
    If Len(txtdma.Text) <> 6 Then
    mensagem("Data inválida!", Color.Red)
    Response.Cookies("Focus").Value = "txtdma"
    Exit Sub
    End If



    'Vai fazer uma copia antes de alterar o banco
    Dim folder As Directory
    Dim Path As String = Server.MapPath("SQL")
    'Dim Local As String = Replace(Path, "/", "\", 1)
    'Local += "\"
    If folder.Exists(Path) = False Then
    folder.CreateDirectory(Path)
    End If

    Dim arquivoBanco As String = Server.MapPath("SQL/BancoSQL_" & txtdma.Text & ".txt")
    If IO.File.Exists(arquivoBanco) = False Then
    mensagem("Arquivo não encontrado!", Color.Red)
    modi.SetFocus("txtdma")
    Exit Sub
    End If


    Dim Local As String = "" ' Replace(Path, "/", "\", 1)
    Local = modi.LeRegistro("cd_cf_geral", "LocalCopia", " cod = 1")
    If Local = "" Then
    mensagem("Não foi definido o local de Cópia do SQL", Color.Red)
    Exit Sub
    End If
    Local += "\"
    Dim nomebkp As String = "Sistema backup " & Format(Now, "ddMMyyyy")



    'Obs:Onde sera gravado o bkp esta na variavel "local" Tem que ser um local no PC que esta o servidor do

    SQL.
    'com o server.mapPath pega o caminho do aplicativo e o banco sql pode estar em outra maquina ai não vai

    fazer o bkp
    'da erro , pois o bkp so é feito na maquina onde esta instalado o SQL.
    On Error GoTo trata

    If chkBkpOpcional.Checked = True Then
    Dim B As ADODB.Connection
    B = New ADODB.Connection
    B.Open(modi.strOledb)
    B.Execute("BACKUP DATABASE [Sistema] TO DISK = N'" & Local & nomebkp & "' WITH INIT ,

    NOUNLOAD , NAME = N'" & nomebkp & "', SKIP , STATS = 10, NOFORMAT")
    B.Close()
    End If



    Dim dma As String = txtdma.Text
    Dim arqLog As String = Server.MapPath("SQL\Log_" & dma & ".txt")
    Dim arqLog2 As String = "SQL/Log_" & dma & ".txt"

    Dim ff As Integer = FreeFile()
    'abre para gravar as tabelas nao encontradas

    FileOpen(ff, arqLog, OpenMode.Output)

    Dim flgIntegracaogrupo As Boolean = False

    'novo 05112008
    Dim CollationBANCO As String
    Dim CollationCampo As String
    'pega o collation padrao do banco...
    Dim cB As New SqlConnection(modi.strSql) : cB.Open()
    Dim drB As SqlDataReader : Dim cmdB As SqlCommand
    cmdB = New SqlCommand("SP_HELPDB", cB)
    drB = cmdB.ExecuteReader(CommandBehavior.CloseConnection)
    While drB.Read
    If UCase(drB("Name")) = UCase(conn.Connecta(2)) Then
    'If UCase(drB("Name")) = UCase("FERTIMAR") Then
    CollationBANCO = drB("Status")
    CollationBANCO = Mid(CollationBANCO, InStr(CollationBANCO, "Collation=") + 10,

    Len(CollationBANCO))
    CollationBANCO = Mid(CollationBANCO, 1, InStr(CollationBANCO, ",") - 1)
    Exit While
    End If
    End While
    cB.Close()
    drB.Close()

    Dim cont As Integer = 0
    Dim arquivo As String = Server.MapPath("SQL\BancoSQL_" & dma & ".txt")
    Dim arq As StreamReader = New StreamReader(arquivo)
    Dim Nrlinha As Integer
    Dim linha As String = ""
    While arq.BaseStream.CanRead


    cont += 1
    If cont = 151 Then
    mensagem("", Color.Red)
    End If

    linha = arq.ReadLine
    If Mid(linha, 1, 3) = "FIM" Then
    Exit While
    End If

    tabela = Trim(Mid(linha, 1, 50))
    campo = Trim(Mid(linha, 51, 29))
    tipo = Trim(Mid(linha, 81, 19))
    'tam = Mid(linha, 101, 5)
    tam = Mid(linha, 101, 10)
    'Defout = Trim(Mid(linha, 106))
    Defout = Trim(Mid(linha, 111, 30))

    'Somente quando cria
    Nulo = Trim(Mid(linha, 141, 5))


    sql = "SELECT table_name FROM INFORMATION_SCHEMA.tables "
    sql += " WHERE table_name = '" & tabela & "'"
    sql += " group by table_name"


    tabe = tabela

    Dim c As New SqlConnection(modi.strSql) : c.Open()
    Dim dr As SqlDataReader : Dim cmd As SqlCommand
    cmd = New SqlCommand(sql, c)
    dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    While dr.Read
    tabe = "" 'se acho limpa
    sql = "SELECT Collation_Name,column_name,data_type ,isnull(character_maximum_length,0) as

    length FROM INFORMATION_SCHEMA.columns"
    sql += " WHERE table_name = '" & tabela & "'"
    sql += " And column_name = '" & campo & "'"
    Dim c1 As New SqlConnection(modi.strSql) : c1.Open()
    Dim dr1 As SqlDataReader : Dim cmd1 As SqlCommand
    cmd1 = New SqlCommand(sql, c1)
    dr1 = cmd1.ExecuteReader(CommandBehavior.CloseConnection)
    'testa se o campo existe na tabela do cliente
    'Se nao achou entra e atualiza a tabela
    If Not dr1.Read Then


    Dim c2 As New SqlConnection(modi.strSql) : c2.Open()
    Dim cmd2 As SqlCommand

    Dim def As String = ""
    If Defout <> "" Then
    'If tipo = "char" Or tipo = "nchar" Or tipo = "varchar" Or tipo = "nvarchar" Then
    ' 'se for string tem aspas
    ' def = "DEFAULT ('" & Defout & "')"
    'Else
    def = "DEFAULT " & Defout
    'End If
    End If
    Dim var As String = campo & " " & tipo
    If Val(tam) > 0 Then
    var += "(" & tam & ")"
    End If

    If UCase(Nulo) = "YES" Then
    var += " NULL "
    End If
    If UCase(Nulo) = "NO" Then
    var += " NOT NULL "
    End If

    If def <> "" Then
    var += " " & def
    End If



    cmd2 = New SqlCommand("alter table " & tabela & " add " & var, c2)
    cmd2.CommandTimeout = 0
    cmd2.ExecuteNonQuery()



    'Se vem campo default deve preencher a tabela com o valor dele
    If def <> "" Then
    def = Replace(def, "DEFAULT", "", 1)
    def = Replace(def, "(", "", 1)
    def = Replace(def, ")", "", 1)
    def = Trim(def)
    Dim str As String = "update " & tabela & " set " & campo & " = " & def
    cmd2 = New SqlCommand(str, c2)
    cmd2.CommandTimeout = 0
    cmd2.ExecuteNonQuery()
    End If

    c2.Close()
    atu += "Tabela: " & tabela & " campo:" & campo

    Else
    'Achou mas verifica se o campo continua o mesmo tipo de varicavel
    'Ex: se esta varchar de 6 e vai atualizar para varchar de 10
    'de Int para varchar etc....

    'novo 05112008
    If IsDBNull(dr1("Collation_Name")) = True Then
    CollationCampo = ""
    Else
    CollationCampo = dr1("Collation_Name")
    End If

    'If tipo <> dr1("data_type") Or tam <> Val(dr1("length")) Then
    'novo 05112008
    If tipo <> dr1("data_type") Or tam <> Val(dr1("length")) Or (CollationBANCO <> CollationCampo

    And CollationCampo <> "") Then

    Dim c3 As New SqlConnection(modi.strSql) : c3.Open()
    Dim cmd3 As SqlCommand
    Dim str As String = ""

    str = "ALTER TABLE " & tabela & " ALTER COLUMN " & campo
    str += " " & tipo
    'Aqui mudou o tamanha ex.: varchar de 6 para 100
    If Val(tam) <> dr1("length") Then
    'quando vem tipo int,bigint nao precisa expecificar o tam
    'pois ele ficao padarao conforme o tipo da variavel
    If Val(tam) > 0 Then str += "(" & tam & ")"
    End If

    'novo 05112008
    If CollationBANCO <> CollationCampo Then
    If CollationCampo <> "" Then
    If InStr(str, ")") = 0 Then
    str += "(" & Val(tam) & ")"
    End If
    str += " collate " & CollationBANCO
    End If
    End If

    Erro = str
    cmd3 = New SqlCommand(str, c3)
    cmd3.CommandTimeout = 0
    cmd3.ExecuteNonQuery()
    c3.Close()
    Erro = ""


    End If

    End If
    dr1.Close()


    End While
    dr.Close()



    If tabe <> "" Then
    flg = True
    If tabela <> TestaTabela Then
    PrintLine(ff, TAB(1), "tabela não encontrada: " & tabela)
    TestaTabela = tabela
    End If
    End If
    End While
    arq.Close()



    FileClose(ff)

    'Dim msgExtra As String = ""
    If flg = True Then
    'msgExtra = "Verficar arquivo de Log_" & dma
    modi.AbreArquivo(arqLog2, "tela", False)
    End If
    mensagem("Banco Atualizado!, Backup salvo em " & Local, Color.Green)

    trata:
    If Err.Number <> 0 Then
    'se der algum erro pelo menos fecha o arq.
    'para quando tentar de novo ano estar aberto
    If Err.Number = 5 Then
    Dim msg As String = "Erro encontrado: " & Err.Number & " " & Err.Description
    msg += "-" & Erro & "-" & cont
    PrintLine(ff, TAB(1), msg)
    Resume Next
    Else
    FileClose(ff)
    If Err.Number = 53 Then
    mensagem("Arquivo não existe!!!", Color.Red)
    Response.Cookies("Focus").Value = "txtdma"
    Else
    mensagem("Erro: " & Err.Description, Color.Red)

    End If
    End If

    End If

    End Sub




    Ah, neste webform eu uso:
    Imports System.IO
    Imports System.IO.File
    Imports System.Data.OleDb
    Imports System.Data.SqlClient



    Ve se da para tirar alguma ideia, ou mesmo usar como está (alterando apenas para se adequar ao teu caso)
    se nao entender algo, ou qualquer coisa que precisar extra para fazer isso funcionar, pode pedir aí...



    []s







    • Editado Julio Costi sábado, 28 de maio de 2011 15:44 msdn fez confusão com o html
    • Marcado como Resposta Richard Juhasz segunda-feira, 6 de junho de 2011 20:26
    sábado, 28 de maio de 2011 15:31