none
Sincronizar um arquivo CSV com SQL Server RRS feed

  • Pergunta

  • Boa tarde a todos. Estou com uma situação aqui e gostaria de saber se é possível a solução. 

    Tenho um arquivo CSV que é populado com alguns dados (item, quantidade, timestamp) a cada 1 minuto em uma máquina.

     Em outra máquina tenho o SQL Server Express 2014 instalado. Nessa máquina foi mapeado uma unidade de rede para máquina com arquivo CSV, então é possível acessar esse arquivo através da rede, colocando usuário e senha.

    Gostaria de saber a possibilidade de Sincronizar esse arquivo, dinamicamente com o SQL Server. Conforme for entrando dados nesse arquivo CSV, automáticamente ele já joga no SQL. Caso seja perdida a conexão entre as máquinas, o CSV vai continuar populando, e ao reestabelecer a conexão, o SQL sincroniza com CSV e popula os dados do tempo de conexão perdida. 

    Isso é possível de ser feito? Gostaria de obter apenas um norte, para trabalhar nesse projeto. 

    Obrigado a todos.

    sexta-feira, 1 de novembro de 2019 15:31

Todas as Respostas

  • Qual sistema que gera esse CSV?

    É possível fazer o que você precisa. Como a versão do seu sql server é express, ele não possui o agent, é necessário utulizar o agendador de tarefas combinado com o SQL CMD.

    A ideia inicial é criar um arquivo bat com o código #1 e criar a agenda no agendador de tarefas para rodar conforme a sua necessidade.

    sqlcmd -S myServer\instanceName -i C:\myScript.sql -o C:\EmpAdds.txt


    Fabiano Carvalho

    sexta-feira, 1 de novembro de 2019 16:18
  • William,

    • o que é o processo que preenche o arquivo CSV?
    • o processo que preenche o arquivo CSV não poderia enviar os dados diretamente para o banco de dados?

     

    Avalie se o Service Broker atende ao que necessita, substituindo um arquivo por fila de mensagens. Para a questão de perda de conexão, o próprio aplicativo pode utilizar um arquivo para armazenar as mensagens, enviando-as ao SQL Server tão logo se restabeleça a comunicação.


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    sexta-feira, 1 de novembro de 2019 16:25
  • Obrigado Fabiano por sua ajuda. Então, estou usando um raspberry Pi para fazer uma leitura de um sensor remoto com Node red e gerar esse CSV, como não posso colocar um PC no local, optei por essa arquitetura. Não posso enviar os dados diretamente para o Servidor com SQL, pois no local, a conexão com a internet não é muito estável, e como a intenção não é perder dados, eu pensei nesse sistema. Como o raspberry vai estar coletando os dados localmente, optei por gerar esse csv localmente, para posteriormente subir para o Servidor com SQL, e em caso de perca de conexão, ele Sincronizar após a conexão reestabelecida.
    sexta-feira, 1 de novembro de 2019 16:57
  • Obrigado José por sua ajuda. Então, estou usando um raspberry Pi para fazer uma leitura de um sensor remoto com Node red e gerar esse CSV, como não posso colocar um PC no local, optei por essa arquitetura. Não posso enviar os dados diretamente para o Servidor com SQL, pois no local, a conexão com a internet não é muito estável, e como a intenção não é perder dados, eu pensei nesse sistema. Como o raspberry vai estar coletando os dados localmente, optei por gerar esse csv localmente, para posteriormente subir para o Servidor com SQL, e em caso de perca de conexão, ele Sincronizar após a conexão reestabelecida.
    sexta-feira, 1 de novembro de 2019 16:57
  • Minha dúvida é. Como eu tenho apenas um arquivo CSV onde eu vou incrementando ele com os dados, quando eu criar esse bat para importar o CSV no SQL ele vai importar tudo? ou é possível ir importando os registros conforme for entrando no CSV?
    sexta-feira, 1 de novembro de 2019 18:30
  • O objetivo não é transferir arquivo CSV mas sim armazenar em um banco de dados SQL Server os dados coletados, certo?

    Eu acho que o processo do coletor ir gravando continuamente em um arquivo e um processo externo ir lendo no mesmo arquivo não será confiável. Um dos motivos é que em algum momento o que já foi lido pelo processo que roda no SQL Server terá que ser apagado; como fazer isso em um arquivo texto que continua tendo novas linhas incluídas a cada 30 segundos?

    A sugestão é que programe o processo no raspberry para coletar os dados e ir armazenando os dados coletados em um tamborete local, com SQLite. Outro processo em paralelo no raspberry fica responsável por ler no tamborete, enviar as informações para o banco de dados SQL Server (sempre que houver conexão com a rede) e ir apagando no tamborete o que já foi enviado para o banco de dados.

    O processo responsável pelo envio pode usar instruções INSERT ou se comunicaria com o Broker do SQL Server.

    Pesquisei na web e vi que há como implementar:


    Lembre-se de marcar esta resposta se ela te ajudou a resolver o problema


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Editado José Diz quinta-feira, 7 de novembro de 2019 10:31
    sexta-feira, 1 de novembro de 2019 20:39
  • Obrigado José Diz pela atenção. Segui o seu conselho e parti para o SQLITE no meu raspberry. Acredito que estou perto do meu objetivo. 

    Instalei o sqlite3 no meu raspberry, criei o arquivo de DATABASE em uma pasta compartilhada na rede, onde consigo acessar do meu servidor com SQL Server,

    fiz as configurações no node-red, e já consigo popular minha tabela.  

    No meu servidor fiz um dump para me comunicar o arquivo de database que está na pasta compartilhada. Criei um Linked Server e consigo fazer um select dos dados do SQLITE no Sql Server com openquery. 

    Até para efeito de teste, consegui carregar em um database do SQL Server os dados do SQLITE com o seguinte comando: 

    Porém, preciso seguir o seu raciocínio, de carregar as informações nesse database do SQL Server, por exemplo de 30 em 30 minutos, e apagar o do SQLITE. 

    Todavia e vejo um problema de confirmação de recebimento. Por exemplo, se eu programar no SQLITE para apagar os dados a cada 30 minutos, posso perder dados caso nesse período o raspberry esteja sem conexão com o Servidor. 

    Estou com dificuldade de fazer um comando onde só apague caso o sql já recebeu. Deu para entender meu raciocínio? 

    Agradeço mais uma vez se puder me dar um help José Diz, obrigado.

    terça-feira, 5 de novembro de 2019 19:02
  • Instalei o sqlite3 no meu raspberry, criei o arquivo de DATABASE em uma pasta compartilhada na rede, onde consigo acessar do meu servidor com SQL Server

    Willian, criar o tamborete no SQLite foi o primeiro passo.

    Há duas formas de fazer com que o servidor principal (o que está com o banco de dados SQL Server) receba os dados que foram coletados no raspberry: push ("enviar") ou pull ("buscar"). O que eu te sugeri foi push: o coletor envia os dados para o servidor principal.

    No coletor ficariam dois processos permanentemente rodando: um, processo A, coletando os dados e gravando-os no tamborete; outro, processo B, lendo do tamborete e enviando para o servidor principal. A cada linha do tamborete lida pelo processo B, ele a envia para o servidor principal e, não ocorrendo erro no envio, logo após a apaga do tamborete. O envio pode ser através de comando INSERT: terminou sem erro, então está ok. Nos momentos em que não houver conexão com a rede, então o processo B tenta posteriormente.

    A outra técnica, pull, mantém um processo ativo no coletor, o processo A anteriormente definido, e outro processo ativo no servidor principal, o processo C. Este processo C lê linhas no tamborete e as apaga, logo após ter confirmado que gravou com sucesso no banco de dados do servidor principal.

    Acho que fica mais simples se você conseguir implementar o push.

     

    Lembre-se de marcar esta resposta se ela te ajudou a resolver o problema


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Editado José Diz quinta-feira, 7 de novembro de 2019 10:34
    terça-feira, 5 de novembro de 2019 21:32

  • Até para efeito de teste, consegui carregar em um database do SQL Server os dados do SQLITE com o seguinte comando: 

    A abordagem acima seria pull: o servidor principal busca os dados que estão no tamborete.

    Neste caso não pode ser SELECT ... INTO mas sim INSERT into ... SELECT.

    -- código #1 v3 declare @NOVO table (chave_incluida ___);
    DBCC TRACEON (3604, 7300); -- retrieve the full error message from providers
    set XACT_ABORT on; --

    BEGIN DISTRIBUTED TRANSACTION;

    INSERT into tabela (id, topic, value, currentdate) output inserted.id into @NOVO (chave_incluida) SELECT id, topic, value, currentdate from openquery (SQLITE3_LINKED_SERVER, 'SELECT * from mqqtmcworks') as C;

    DELETE C
    from openquery (SQLITE3_LINKED_SERVER, 'SELECT id from mqqtmcworks') as C
    where C.id in (SELECT chave_incluida from @NOVO);

    COMMIT;

    DBCC TRACEOFF (3604, 7300);

    E, após fazer o INSERT deve-se apagar as linhas que foram lidas do tamborete. Por exemplo, supondo que tenha lido as linhas 6, 7, e 10 no tamborete, após o INSERT com sucesso deve-se apagar as linhas 6, 7 e 10 do tamborete. Assim, na próxima execução essas linhas não serão lidas novamente, pois não existirão mais.

    O que deve ter em mente é que agora é um tamborete no coletor e que não se apaga o tamborete mas sim as linhas que foram transferidas com sucesso.

    Sobre linked server você encontra dicas e técnicas de otimização no artigo “Programação e otimização de consultas distribuídas”.

     

    Lembre-se de marcar esta resposta se ela te ajudou a resolver o problema


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Editado José Diz quinta-feira, 7 de novembro de 2019 14:31
    terça-feira, 5 de novembro de 2019 21:37
  • Boa noite José Diz, obrigado mais uma vez pela atenção. 

    Entendi o seu raciocínio, e tentei implementar um pull nesse caso, seguindo o seu código. Porém obtive um erro e não estou conseguindo identificar. 

    Tentei executar o código por partes. A parte do INSERT funcionou perfeitamente. Porém a parte do DELETE deu um erro de permissão. Não entendi que permissão seria essa, visto que meu database do SQLITE não tem usuário e senha. 


    Estou logando com o usuário do Windows no SQL Server. Saberia onde estou errando? 

    Obrigado mais uma vez.

    quarta-feira, 6 de novembro de 2019 23:02
  • Willian,

    Estou entrando neste post para tentar ajudar com base na sua última postagem.

    Provavelmente a conta de logon configurada para executar este Linked Server estabelecido entre o SQL Server e seu SQLLite não tem permissão suficiente para realizer os procedimentos que você esta tentando processar.

    Nas configurações deste Linked Server, verifique o nível de permissão definida para a conta configurada.


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quarta-feira, 6 de novembro de 2019 23:41
  • Obrigado Junior Galvão, pela atenção. Porém não estou encontrando onde posso definir as permissões para esse logon para este linked server específico. Tentei nas propriedades do linked server sem sucesso: 

    Tentei nas propriedades do meu logon, porém não encontro onde posso definir para o linked server: 

    Há um lugar específico, onde defino as permissões para os linked server criados?

    quarta-feira, 6 de novembro de 2019 23:50
  • Entendi o seu raciocínio, e tentei implementar um pull nesse caso, seguindo o seu código. Porém obtive um erro e não estou conseguindo identificar. 
    >

     

    Pode transcrever para este tópico como foi configurado o linked server?

    Verifique como está a opção "Enable Promotion of Distribution Transaction" nas propriedades do linked server SQLITE3_LINKED_SERVER. Fica em "Server Options". Ela deve estar habilitada.

    ---

    Experimentalmente, substitua
       BEGIN TRANSACTION;

    por
       BEGIN DISTRIBUTED TRANSACTION;

    ---

    O serviço MS DTC (Microsoft Distributed Transaction Coordinator) deve estar ativo no computador com o servidor SQL Server.

    ---

    Por favor faça os seguintes testes:

    -- código #2
    SELECT top (5) C.*
      from SQLITE3_LINKED_SERVER...mqqtmcworks as C;

    DELETE
      from SQLITE3_LINKED_SERVER...mqqtmcworks as C
    where C.id = 2;


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Editado José Diz quinta-feira, 7 de novembro de 2019 00:41
    quinta-feira, 7 de novembro de 2019 00:14
  • Willian,

    Na primeira tela, existe a opção: Be made using this security context, aqui você poderá configurar justamente uma conta de login que possa ser utilizada em ambos os lados do seu linked server, sendo um logon que possa lêr e gravar.

    O que esta configurado na guia Server Options?


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]


    quinta-feira, 7 de novembro de 2019 00:28
  • José diz, configurei o linked server da seguinte forma: 

    1º - Configurei a fonte ODBC para apontar para o meu sqlite: 

    2º Criei um Linked Server em Server Objects > Linked server(botão direito) new linked server: 

    Verifiquei a opção "Enable Promotion of Distribution Transaction" e está habilitada: 

    O serviço MS DTC (Microsoft Distributed Transaction Coordinator) está em execução no servidor com SQL Server. 

    Troquei o BEGIN TRANSACTION; por BEGIN DISTRIBUTED TRANSACTION; porém o erro persiste. 

    O teste que você mencionou não entendi se é para fazer dentro dessa função ou somente o código, retornou o seguinte erro: 

    Era dessa forma? 

    Obrigado mais uma vez.

    quinta-feira, 7 de novembro de 2019 00:47
  • Junior Galvão, 

    Fiz um teste colocando o meu logon do windows, visto que logo com esse logon na opção sugerida porém sem exito. 

    Imagino que nessa opção eu colocaria o USER e Password do meu banco remoto, no caso o SQLITE3, porém no sqlite eu não tenho um user e password, e pelo que pesquisei esse banco não possui mesmo, pois ele e criado em cima de um arquivo e não da suporte para user e password, me corrija se estou equivado por favor. 

    Verifiquei a permissão do arquivo do banco e está como leitura e escrita: 

    quinta-feira, 7 de novembro de 2019 00:53
  •  O teste que você mencionou não entendi se é para fazer dentro dessa função ou somente o código, retornou o seguinte erro: 

    Era dessa forma? 

    Isso mesmo.

    A mensagem de erro informa que o SQL Server recebeu coluna com tipo de dados que o SQL Server não conseguiu identificar; pode ser alguma incompatibilidade, embora o SQLite possua o conceito de "type affinity" que pode gerar erros quando não se faz conversão prévia. Como estão declaradas as colunas id, topic, value e currentdate no tamborete?

    ---

    O que quero é descobrir como usar a "identificação de 4 partes" com o SQLite do raspberry. Normalmente se informa
                          servidor.bancodedados.esquema.tabela

    mas nesse caso não sei se é possível informar bancodedados e esquema. Por isso os "...".

    O objetivo é saber quais construções "identificação de 4 partes" são válidas na combinação SQLite + raspberry:

    -- código #3 v2
    SELECT top (5) C.id
      from SQLITE3_LINKED_SERVER...mqqtmcworks as C;
    
    SELECT top (5) C.id
      from SQLITE3_LINKED_SERVER..dbo.mqqtmcworks as C;

    SELECT top (5) C.id
      from SQLITE3_LINKED_SERVER.pimcworks_db.dbo.mqqtmcworks as C;


    Descobrindo uma que seja válida, espero que possamos utilizá-la no comando DELETE, sem o uso da função OPENQUERY.

    ---

    Estive pesquisando sobre a mensagem de erro da imagem abaixo:

    e encontrei o artigo How to troubleshoot error 7391 that occurs when you use a linked server in SQL Server. A partir de algumas informações contidas nele fiz modificações no código #1, para obter prováveis causas do erro 7391. Após reexecutar o código #1, analise também o log de eventos Windows, na parte de aplicações.

    Lembre-se de marcar esta resposta se ela te ajudou a resolver o problema

     

    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    quinta-feira, 7 de novembro de 2019 12:03
  • Bom dia José Diz. 

    Bom os tipo de dados são: id(INTEGER), topic(TEXT), value(NUMERIC), currentdate(DATETIME) como pode ser observado a seguir: 

    Executei os comandos sugeridos para a "identificação da s 4 partes", porém todas as possibilidades me retornam o mesmo erro: 

    Fiz como sugeriu  e executei novamente o código 1, e obtive o seguinte retorno: 

    Log do Windows > aplicativo

    quinta-feira, 7 de novembro de 2019 12:08
  • Bom dia José Diz. 

    Bom os tipo de dados são: id(INTEGER), topic(TEXT), value(NUMERIC), currentdate(DATETIME) como pode ser observado a seguir: 

    Ok.

    Me parece que foi o tipo de dados TEXT do SQLite que não foi reconhecido quando utilizando a "identificação de 4 partes" e gerou aquela mensagem de erro na execução do código #2. Conforme consta na documentação do SQLite, "A column with TEXT affinity stores all data using storage classes NULL, TEXT or BLOB".

    O tipo de dados da coluna topic poderia ser alterado para varchar(n)? Se sim, após a alteração você pode reexecutar o código #2?


    Executei os comandos sugeridos para a "identificação das 4 partes", porém todas as possibilidades me retornam o mesmo erro

    Estranho, pois quando da execução do código #2 parece ter reconhecido, mas dando erro de provável tipo de dados não aceito.

     

    Fiz como sugeriu  e executei novamente o código 1, e obtive o seguinte retorno: 

    Sobre a mensagem de erro "unsupported connect attribute 1207", após pesquisas no google o que encontrei foi relação com SQLSetConnectAttr e com SQL_ATTR_ENLIST_IN_DTC e que levou ao erro "Illegal operation while in a local transaction", que possui 3 diferentes descrições. Acrescentei no texto do código #1 o DISTRIBUTED, para ficar claro que é uma transação distribuída e não uma transação local; você pode reexecutar o código #1? Se der o mesmo erro, nem precisa me avisar!  :)

    ---

    Sobre o log de aplicativos, nenhuma informação útil. No log de eventos não havia nenhum mensagem relacionado ao MS DTC?

    ---

    O objetivo do código #1 é estabelecer uma transação distribuída, onde parte é executada no servidor SQL Server e parte no SQLite. Entretanto, até o momento não se teve sucesso em algo simples. Como o Raspberry Pi possui uma versão embarcada do Linux, não sei até onde ela está preparada para aceitar transações distribuídas ou se é o driver ODBC que possui restrições.

    São muitas variáveis para descobrir o que está a impedir o funcionamento do código #1.

    ---

    Somente se pode apagar linhas da tabela no SQLite quando tiver certeza de que elas foram transferidas com sucesso para o SQL Server e o uso da transação distribuída é a forma mas simples para obter tal garantia. Se não for possível seguir nessa linha, há algumas alternativas. Mas antes de prosseguir em outra alternativa, é necessário verificar se é possível apagar linhas no SQLite a partir do SQL Server, usando DELETE.

    Outra opção para apagar linhas na tabela do SQLite é o uso de processamento remoto, através de EXECUTE() AT.

    ---

    Tem como você avaliar a implementação da abordagem push?


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este coneúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.


    • Editado José Diz quinta-feira, 7 de novembro de 2019 17:14
    quinta-feira, 7 de novembro de 2019 13:52
  • Willian,

    Certo, certo, estamos trabalhando no conceito de acesso direto ao arquivo, então este é o problema, como você vai escrever em um arquivo que esta sendo acessado por outra aplicação.

    Eu trabalho com Arduino aqui na Fatec São Roque, no começo do ano elaboramos um projeto de controle de temperatura que armazenava os dados coletados pelo Arduino em um arquivo txt e depois enviamos diretamente para o SQL Server.

    Talvez podemos pensar em algo assim, em invês de utilizar um Linked Server, dentro do próprio SQL Server fazer acesso através do commando Bulk Insert.

    A máquina ou servidor que você utiliza para trabalhar com o SQL Server consegui via rede acessar esta interface do Raspberry?


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quinta-feira, 7 de novembro de 2019 17:57
  • Obrigado pelo retorno mais uma vez José Diz.

    Bom, fiz a alteração na minha tabela colocando a coluna topic como VARCHAR, reexecutei os códigos, porém sem sucesso, ainda obtenho o retorno de "invalid column": 

    Reexecutei o código um também com o DISTRIBUTED, porém foi me retornado um erro referente a "unable begin distributed": 

    Referente ao log, o que encontrei sobre MS DTC: 

    Compreendo as variáveis possíveis para encontrar onde está o problema, acredito que há vários fatores que podem influenciar nessa comunicação.

    Estou pensando, inclusive, em usar talvez o SQLITE também, no lado do servidor. Porém, não conheço muito esse "mini BD", e não sei como ele se comportaria em produção, aquisitando vários registros por hora. 

    Mas vou continuar a testar essa idéia com o SQL Server, vou tentar implementar o push, porém ainda não tenho um norte para seguir com essa implementação, se puder me dar uma dica, agradeceria. 

    Mais uma vez agradeço pela atenção e compartilhamento de conhecimento.

    Obrigado. 

    sexta-feira, 8 de novembro de 2019 14:51
  • Obrigado pelo retorno Junior Galvão. 

    Sim, consigo acessar via rede o raspberry, pelo servidor com SQL através de uma VPN. 

    Cheguei a pensar nessa idéia, Junior, no raspberry, eu consigo criar um arquivo txt ou csv, e ir populando ele com meus dados. 

    Minha dúvida é, eu consigo seguir a mesma idéia, ir transferindo meus dados para o SQL Server e deletando do arquivo txt? Quando não houver conexão para tal, ele mantem os dados no txt, e, posteriormente, quando reestabelecida a conexão, ele transferir os dados desse período de falha? 

    Há uma forma de automatizar esse Bulk Insert? Pensei talvez em criar um arquivo .bat e executa-lo a cada período usando o agendador de tarefas do windows, visto que minha versão do SQL é Express 2014.

    É uma idéia a se seguir também. 

    Mais uma vez, obrigado.

    sexta-feira, 8 de novembro de 2019 14:59
  • Willian,

    Vamos por partes:

    Minha dúvida é, eu consigo seguir a mesma idéia, ir transferindo meus dados para o SQL Server e deletando do arquivo txt?

    -- A transferência pode ser feita sim, basta você estabelecer uma forma de acesso para este arquivo, no que se refere a deletar isso é um controle que você pode implementar tanto no Raspberry como também na sua rotina de importação dos dados, mas pense bem para não corer risco de perda de dados.

    Quando não houver conexão para tal, ele mantem os dados no txt, e, posteriormente, quando reestabelecida a conexão, ele transferir os dados desse período de falha? 

    -- Isso eu não deixaria para o SQL Server controlar, o que eu pensaria seria justamente em estabelecer uma forma de identificar se o conteúdo do arquivo foi importado para o SQL Server e após esta confirmação você se necessário realizaria o delete do mesmo.

    Há uma forma de automatizar esse Bulk Insert? Pensei talvez em criar um arquivo .bat e executa-lo a cada período usando o agendador de tarefas do windows, visto que minha versão do SQL é Express 2014.

    -- Sim, tranquilamente, mesmo sendo a edição Express, você pode implementar um arquivo .bat contendo o Código que deseja realizar o acesso e importação do dados, neste caso, recomendo analisar a possibilidade de utilizar as ferramentas de linha de commando SQLCMD ou BCP dentro do bloco de código a ser implementado no arquivo .bat.

    Destaco também que este mesmo arquivo poderá ser configurado como uma tarefa agendada do seu Windows para ser executado no momento desejado, ou executado por você.

    Deixo um exemplo de Código implementado em um arquivo .bat:

    @Echo off
    SQLCMD -SSERVER -UJUNIOR -P***** -dBancoDeDados -Q "Select * from Produtos" 
    
    
    


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    sexta-feira, 8 de novembro de 2019 16:35


  • Referente ao log, o que encontrei sobre MS DTC: 


    Temos aí algo a analisar: "Recovery of any in-doubt distributed transactions involving Microsoft Distributed Transaction ...". O que consta na aba "Detalhes" dos dois eventos?

     

    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Editado José Diz segunda-feira, 11 de novembro de 2019 14:24
    segunda-feira, 11 de novembro de 2019 12:17
  • Willian,

    Poderia responder as perguntas abaixo:

    1- Qual é a linguagem de programação que você esta utilizando neste projeto com o RaspberryPI?

    2- Se possível poderia verificar o valor que esta configurado para a chave de registro TurnOffRpcSecurity no seguinte caminho: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC

    3- A porta TCP 3372 esta liberada para as regras de Inbound e Outbound em seu firewall?


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    segunda-feira, 11 de novembro de 2019 19:09
  • Segue um print da aba de "Detalhes" dos eventos. 

    Os códigos de EventData: 

    0E4300000A0000001F0000004400450053004B0054004F0050002D0056005000480031003600390051005C00530051004C00450058005000520045005300530032003000310034000000070000006D00610073007400650072000000 

    712100000A0000001F0000004400450053004B0054004F0050002D0056005000480031003600390051005C00530051004C00450058005000520045005300530032003000310034000000070000006D00610073007400650072000000 

    terça-feira, 12 de novembro de 2019 14:27
  • Bom dia Junior Galvão. 

    Bom, minha arquitetura é a seguinte: 

    - utilizo o node-red para fazer as aquisições de dados dos meus sensores, via modbus tcp, e pós leitura faço o insert em uma tabela que criei em um database do SQLITE3, Esse database eu criei em uma pasta do raspberry, que compartilho na rede, através do samba. 

    - no servidor, com Windows server, eu acesso essa pasta do raspberry via rede e, tenho o SQL Server Express 2014, onde, tenho como intenção, ter os dados gravados no SQLITE3, pois, eu não posso depender de acessar os dados diretos no SQLITE3, pois caso perca a conexão, eu fico sem acesso à esses dados.

    - Para ficar mais claro a situação, vou explicar minha configuração atual que utilizei para "contornar" essa situação:

    Instalei no Servidor, um aplicativo chamado  FreeFileSync, criei uma pasta local (no Servidor), e programei para ficar sincronizando com a pasta do raspberry a cada 1 minutos, ou seja, é feita uma cópia dos arquivos dessa pasta do raspberry, para pasta local, dessa forma, mesmo que caia a comunicação entre raspberry e servidor, eu consigo acessar os dados do servidor (até o momento da queda de comunicação), e quando a comunicação é reestabelecida, o aplicativo faz a sincronização, e eu consigo acessar todos os dados novamente. 

    Minha única duvida, é, como o SQLITE se comportaria nessa situação em um ambiente de produção, onde teria mais de 20000 registros de insert por dia. Como se comportaria o raspberry, por exemplo...

    Pois nesse cenário, estou dependendo totalmente do SQLITE no raspberry, e se der algum problema em um dos 2 terei problemas. Até posso programar um backup desse arquivo em outro folder no servidor, mas não sei se bastaria como solução. 

    O valor da chave de registro, TurnOffRpcSecurity está como 0. 

    A porta 3372 está liberada.

    Obrigado.

    terça-feira, 12 de novembro de 2019 14:52
  • Instalei no Servidor, um aplicativo chamado  FreeFileSync, criei uma pasta local (no Servidor), e programei para ficar sincronizando com a pasta do raspberry a cada 1 minutos, ou seja, é feita uma cópia dos arquivos dessa pasta do raspberry, para pasta local, dessa forma, mesmo que caia a comunicação entre raspberry e servidor, eu consigo acessar os dados do servidor (até o momento da queda de comunicação), e quando a comunicação é reestabelecida, o aplicativo faz a sincronização, e eu consigo acessar todos os dados novamente.

    Willian, mas permanece a questão que comentei lá no início, em um contexto de arquivo de texto: como serão apagadas as linhas que já foram importadas? Chegará um momento em que o tamborete ocupará todo a memória de armazenamento do raspberry e o processo de coleta será interrompido.

    (1) Ainda acho que a abordagem mais simples é pull (empurrar), em que é o raspberry que faz toda a ação: coletar dados e enviar para o servidor central, sempre que houver comunicação.

    (2) A solução push (buscar) ainda não se desenvolveu por causa da dificuldade com o controle de transação distribuída. Uma solução de contorno pode ser a não utilização da transação distribuída, ficando o código #1 na seguinte forma:

    -- código #1 v4
    declare @NOVO table (chave_incluida ___);
    declare @Ultimo datetime;

    -- último transferido
    SELECT @Ultimo= max (currentdate) from tabela;
    --
    INSERT into tabela (id, topic, value, currentdate) output inserted.id into @NOVO (chave_incluida) SELECT id, topic, value, currentdate from openquery (SQLITE3_LINKED_SERVER, 'SELECT * from mqqtmcworks') as C where C.currentdate > @Ultimo; -- apaga transferidos
    DELETE C from openquery (SQLITE3_LINKED_SERVER, 'SELECT * from mqqtmcworks') as C where C.id in (SELECT chave_incluida from @NOVO);

    Mas me parece que em testes anteriores não se conseguiu executar o DELETE.
     

    (3) E há uma terceira opção que é retornar ao uso de arquivo texto onde o processo coletor criará um arquivo por dia, cada um com nome que indique a data e hora de criação. Desta forma o processo que roda no servidor tem como saber que arquivos apagar, depois que importar o conteúdo de cada um. E nunca apagar o arquivo mais recente, pois é aquele em que o coletor está a gravar os dados do dia.

    ---

    A situação por você relatada é interessante; vou depois simular localmente para encontrar a causa do não funcionamento, pois é algo que me interessa.



    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Editado José Diz terça-feira, 12 de novembro de 2019 20:06
    terça-feira, 12 de novembro de 2019 18:53
  • José Diz, sim é verdade com relação aos limites do SQLITE, não sei até onde chegaria a memória desse banco, nem mesmo em questão a performance dele com o passar do tempo. 

    Quanto a abordagem "pull", para ser sincero, não saberia nem por onde começar, visto que, acredito eu que a programação deveria ser feita no sqlite, correto? 

    Em relação ao "push", realmente, me parece que o problema está com a permissão do usuário, no Delete, pois, reexecutei o código que você acabou de me enviar e, os registros foram inseridos na minha tabela do SQL Server, porém não foram deletados do SQLITE, como pode ver: 

    Quanto a criar um arquivo txt por dia, me parece uma situação válida, vou analisar e fazer uns testes por aqui. 

    No mais, agradeço mais uma vez pela colaboração.

    terça-feira, 12 de novembro de 2019 21:15
  • Bom dia Junior Galvão. 

    Bom, minha arquitetura é a seguinte: 

    - utilizo o node-red para fazer as aquisições de dados dos meus sensores, via modbus tcp, e pós leitura faço o insert em uma tabela que criei em um database do SQLITE3, Esse database eu criei em uma pasta do raspberry, que compartilho na rede, através do samba. 

    - no servidor, com Windows server, eu acesso essa pasta do raspberry via rede e, tenho o SQL Server Express 2014, onde, tenho como intenção, ter os dados gravados no SQLITE3, pois, eu não posso depender de acessar os dados diretos no SQLITE3, pois caso perca a conexão, eu fico sem acesso à esses dados.

    - Para ficar mais claro a situação, vou explicar minha configuração atual que utilizei para "contornar" essa situação:

    Instalei no Servidor, um aplicativo chamado  FreeFileSync, criei uma pasta local (no Servidor), e programei para ficar sincronizando com a pasta do raspberry a cada 1 minutos, ou seja, é feita uma cópia dos arquivos dessa pasta do raspberry, para pasta local, dessa forma, mesmo que caia a comunicação entre raspberry e servidor, eu consigo acessar os dados do servidor (até o momento da queda de comunicação), e quando a comunicação é reestabelecida, o aplicativo faz a sincronização, e eu consigo acessar todos os dados novamente. 

    Minha única duvida, é, como o SQLITE se comportaria nessa situação em um ambiente de produção, onde teria mais de 20000 registros de insert por dia. Como se comportaria o raspberry, por exemplo...

    Pois nesse cenário, estou dependendo totalmente do SQLITE no raspberry, e se der algum problema em um dos 2 terei problemas. Até posso programar um backup desse arquivo em outro folder no servidor, mas não sei se bastaria como solução. 

    O valor da chave de registro, TurnOffRpcSecurity está como 0. 

    A porta 3372 está liberada.

    Obrigado.

    Willian,

    Obrigado pelas respostas, em relação aos meus questionamentos esta dentro do que eu esperava.


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quarta-feira, 13 de novembro de 2019 00:25
  • Willian,

    Este arquivo por de texto criado diariamente é sempre encerrado por esta aplicação? Você consegui acessar algum arquivo anterior, algo por exemplo de uma semana atrás e verificar o que acontece.

    Estou suspeitando que esta utilitário que você esta utilizando não esta liberando o arquivo para acesso.


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quarta-feira, 13 de novembro de 2019 00:28
  • Olá Junior Galvão. 

    Ainda não implementei esse cenário de criar um arquivo texto por dia, e ir deletando conforme for passando para o SQL Server, na verdade, essa foi uma sugestão do José Diz. 

    Por enquanto, meus dados estão sendo gravado no Sqlite (1 arquivo) localizado no raspberry, e agora estamos tentando fazer, do Servidor com SQL Server, um Select nesse Banco(sqlite), inserir os dados em um database local do SQL Server, e deletar os registros inseridos no SQL Server, do SQLITE. 

    O select, e o insert no banco local funcionou, porém o Delete dá esse problema de permissão. 

    Att.


    quarta-feira, 13 de novembro de 2019 00:48
  • Olá José Diz, 

    Eu fiz o seguinte teste aqui: 

    Copiei o arquivo de database do SQLITE do raspberry para meu servidor com SQL Server, fiz a configuração do ODBC Driver apontando para esse arquivo que está local, fiz a configuração do Linked Server e testei o delete, e, dessa forma, o DELETE funciona, ou seja, o que está dando problema de permissão não é em relação ao arquivo do SQLITE, e sim, quando estamos tentando fazer o DELETE no database no raspberry, pela rede. 

    Vou tentar analisar por aqui, o que pode dar problema de permissão nesse caso. 

    Att.

    quarta-feira, 13 de novembro de 2019 13:29
  • Olá Junior Galvão. 

    Ainda não implementei esse cenário de criar um arquivo texto por dia, e ir deletando conforme for passando para o SQL Server, na verdade, essa foi uma sugestão do José Diz. 

    Por enquanto, meus dados estão sendo gravado no Sqlite (1 arquivo) localizado no raspberry, e agora estamos tentando fazer, do Servidor com SQL Server, um Select nesse Banco(sqlite), inserir os dados em um database local do SQL Server, e deletar os registros inseridos no SQL Server, do SQLITE. 

    O select, e o insert no banco local funcionou, porém o Delete dá esse problema de permissão. 

    Att.


    Willian,

    Ok, somente o Delete? Isso é um possível indicative que o arquivo esta bloqueado para o acesso.


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quarta-feira, 13 de novembro de 2019 22:30
  • Olá José Diz, 

    Eu fiz o seguinte teste aqui: 

    Copiei o arquivo de database do SQLITE do raspberry para meu servidor com SQL Server, fiz a configuração do ODBC Driver apontando para esse arquivo que está local, fiz a configuração do Linked Server e testei o delete, e, dessa forma, o DELETE funciona, ou seja, o que está dando problema de permissão não é em relação ao arquivo do SQLITE, e sim, quando estamos tentando fazer o DELETE no database no raspberry, pela rede. 

    Vou tentar analisar por aqui, o que pode dar problema de permissão nesse caso. 

    Att.

    Willian,

    Perfeito, desta forma teria que funcionar mesmo, quando você esta acessando o arquivo no Raspberry o usuário utilizado para abrir o arquivo é o mesmo utilizado pelo aplicação?


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quarta-feira, 13 de novembro de 2019 22:31
  • Copiei o arquivo de database do SQLITE do raspberry para meu servidor com SQL Server, fiz a configuração do ODBC Driver apontando para esse arquivo que está local, fiz a configuração do Linked Server e testei o delete, e, dessa forma, o DELETE funciona, ou seja, o que está dando problema de permissão não é em relação ao arquivo do SQLITE, e sim, quando estamos tentando fazer o DELETE no database no raspberry, pela rede. 

    Vou tentar analisar por aqui, o que pode dar problema de permissão nesse caso. 

    Uma possibilidade é que o driver ODBC utilizado no raspberry, ou a configuração criada para utilizá-lo, esteja bloqueando o DELETE. Para simular a situação que você relata, quando possível vou criar uma máquina virtual ou com o raspbian (sistema operacional do raspberry, derivado do Debian) ou com o próprio Debian. Assim posso fazer (inúmeros) testes locais, até encontrar a causa.

    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    • Sugerido como Resposta IgorFKModerator segunda-feira, 2 de dezembro de 2019 18:06
    quarta-feira, 13 de novembro de 2019 23:54