Array
(
    [0] => stdClass Object
        (
            [Votos_Balanceados] => 1
            [id] => 519783
            [titulo] => Concatenar conteúdo de um registro SQL Server 2005
            [dataCadastro] => DateTime Object
                (
                    [date] => 2015-05-13 19:03:29
                    [timezone_type] => 3
                    [timezone] => America/Sao_Paulo
                )

            [isFirstPost] => -1
            [idUsuario] => 203486
            [status] => A
            [isExample] => 
            [NomeUsuario] => Carlos Eduardo
            [Apelido] => 
            [Foto] => carlos_tedex-2.gif
            [Conteudo] => [quote]Um detalhe, pode usar o convert em campos que já sao do tipo varchar que não da erro.[/quote]

Vou testar a consulta sql e assim que possível postarei o resultado.

Grato pela contribuição. ) )

Concatenar conteúdo de um registro SQL Server 2005

Carlos Eduardo
   - 13 mai 2015

Boa tarde,
Estou com uma necessidade de retornar o conteúdo de um registro de uma determinada tabela. Exemplo:
Tenho uma tabela de PRODUTOS com os seguintes campos:
Citação:

CODIGO NOME MARCA VALOR
------------ -------------------------------- -------------- ---------
2514 MOUSE 3 BOTOES USB LOGITECH 45,00

Gostaria de saber se existe algum comando SQL ou Função ou StoreProcedure para que ao passar o nome da tabela como parâmetro a mesma me retorne o conteúdo do registro devidamente concatenado. Seguindo o exemplo do registro acima ficaria assim:
2514MOUSE 3 BOTÕES USBLOGITECH45,00
Atualmente estou utilizando uma função em Delphi7 para essa finalidade mas devido a alguns clientes terem muitos registros esta um pouco lento.

Citação:

if not QAux.FieldByName(CampoChave).IsNull then
begin
//Loop nos Fields
for i := 0 to QAux.FieldCount -1 do
begin
if QAux.FieldDefs[i].Name <> NomeCampo then //elimina o campo _HASH para que o mesmo não faça parte do calculo MD5
StringAux := StringAux + QAux.Fields.Fields[i].AsString;
end;
end;

Minha necessidade desta rotina é para atender um requisito do PAF-ECF para detectar se houve algum tipo de manipulação no banco de dados que não passou pelo meu sistema.

Post mais votado

Carlos Eduardo
   - 13 mai 2015


Citação:
Um detalhe, pode usar o convert em campos que já sao do tipo varchar que não da erro.


Vou testar a consulta sql e assim que possível postarei o resultado.

Grato pela contribuição.

Marcos P
   - 13 mai 2015

Se todos os campos forem char, você pode concatenar direto :

#Código

select CODIGO+NOME+MARCA+VALOR 


Se existirem campos numéricos, converta-os para char ( via convert, rtrim, str,... como no exemplo abaixo ) e depois execute a concatenação :

#Código
declare @Numerico1 Int
declare @Numerico2 Float

set @Numerico1 = 83
set @Numerico2 = 15.76

select @Numerico1, @Numerico2, rtrim(convert(varchar(20),@Numerico1)), rtrim(str(@Numerico2,10,2))

Carlos Eduardo
   - 13 mai 2015


Citação:
Se todos os campos forem char, você pode concatenar direto :

#Código

select CODIGO+NOME+MARCA+VALOR 


Se existirem campos numéricos, converta-os para char ( via convert, rtrim, str,... como no exemplo abaixo ) e depois execute a concatenação :

#Código
declare @Numerico1 Int
declare @Numerico2 Float

set @Numerico1 = 83
set @Numerico2 = 15.76

select @Numerico1, @Numerico2, rtrim(convert(varchar(20),@Numerico1)), rtrim(str(@Numerico2,10,2))


Marcos,

Como citado no post preciso de uma função ou algo parecido onde passo o nome da tabela como parâmetro sem a necessidade de informar os campos pois são varias tabelas.

Já consegui pegar o nome dos campos. rs

#Código
 SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'PRODUTOS' 


Grato pela atenção!

Ceilton M
   - 13 mai 2015

Carlos, defina melhor sua necessidade:
"detectar se houve algum tipo de manipulação no banco de dados que não passou pelo meu sistema. "

Você quer saber se a estrutura da tabela foi alterada?

Se for isso você tem que estudar triggers DDL....

Ceilton M
   - 13 mai 2015

Exemplo:
Esse trigger impede que tabelas sejam alteradas ou apagadas de um banco.

CREATE TRIGGER safety
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT 'You must disable Trigger "safety" to drop or alter tables!'
ROLLBACK ;

Marcos P
   - 13 mai 2015

Carlos,

Se sua ideia é fazer isso dinamicamente, crie uma stored procedure no banco que, passando o nome da tabela, leia sua estrutura e gere a concatenação conforme os campos disponíveis.

Você fará isso através de uma query dinâmica, tratando das devidas conversões para char / varchar.

Vai dar um "trabalhinho", mas eu testaria isso antes de maneira fixa, para verificar se a performance do lado da aplicação melhora...

Carlos Eduardo
   - 13 mai 2015


Citação:
Carlos, defina melhor sua necessidade:
"detectar se houve algum tipo de manipulação no banco de dados que não passou pelo meu sistema. "

Você quer saber se a estrutura da tabela foi alterada?

Se for isso você tem que estudar triggers DDL....


Minha necessidade não consiste em saber se a estrutura do banco foi alterada e sim um registro. Exemplo:

Tenho um sistema de Frente de Loja onde é feito uma emissão de cupom fiscal. Ao gravar o registro pertinente a venda eu também calculo o HASH do registro e armazeno num campo da tabela para que depois eu possa verificar se o conteúdo do registro esta igual ao que foi gravado.

Desta forma se alguém acessar uma ferramente de manutenção e modificar os dados deste registro eu tenho como saber se o mesmo foi manipulado.

Esta é uma exigência para quem vai homologar o sistema na legislação PAF-ECF.

Existe um arquivo eletrônico que é gerado todos os dias após a Redução Z e caso algum registro de produto, cliente, venda, estoque, etc... for manipulado eu tenho que gerar interrogações no lugar do campo. "????????"

Carlos Eduardo
   - 13 mai 2015


Citação:
Exemplo:
Esse trigger impede que tabelas sejam alteradas ou apagadas de um banco.

CREATE TRIGGER safety
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT 'You must disable Trigger "safety" to drop or alter tables!'
ROLLBACK ;


Vou guardar essa trigger achei bem interessante.

Obrigado!

Carlos Eduardo
   - 13 mai 2015


Citação:
Carlos,

Se sua ideia é fazer isso dinamicamente, crie uma stored procedure no banco que, passando o nome da tabela, leia sua estrutura e gere a concatenação conforme os campos disponíveis.

Você fará isso através de uma query dinâmica, tratando das devidas conversões para char / varchar.

Vai dar um "trabalhinho", mas eu testaria isso antes de maneira fixa, para verificar se a performance do lado da aplicação melhora...


Marcos, vou tentar criar essa StoreProcedure e caso eu consiga postarei aqui o resultado e principalmente a performance. Pois hoje já faço isso via Delphi a qual está muito lento pois um de meus clientes tem mais de 50 mil produtos. Atualmente minha estrutura de Produtos tem 60 campos. Fazendo uma conta rápida temos:

60 X 50.000 = 3.000.000 (essa é a quantidade de vezes que meu programa executa).

O cliente me disse que todo final de dia após a Redução Z todo o processo de geração do arquivo eletrônico demora aproximadamente 15 minutos.

Marcos P
   - 13 mai 2015

Qual a versão do Sql Server ?

Tente desenvolver a procedure, caso você tenha dificuldades... retorne a esse post que posso lhe ajudar via Skype.

Carlos Eduardo
   - 13 mai 2015


Citação:
Qual a versão do Sql Server ?

Tente desenvolver a procedure, caso você tenha dificuldades... retorne a esse post que posso lhe ajudar via Skype.


SQL Server 2005 Express

Beleza Marcos assim que eu conseguir fazer algo lhe aviso sim.

Grato pela atenção!

Ceilton M
   - 13 mai 2015

Segue um exemplo
Só deu erro em colunas do tipo timestamp.

declare @nometabela varchar(200) = 'TABELA';
declare @objectid int --= 124956663;
declare @name varchar(200), @system_type_id int;
declare @SQL varchar(2000) = ' select '
DECLARE @UID INT, @schemaname varchar(20)

select @objectid = id from sysobjects where type = 'U' and name = @nometabela

declare cursorcolumns cursor for SELECT name,system_type_id FROM sys.columns where object_id = @objectid
open cursorcolumns;

fetch cursorcolumns into @name, @system_type_id;

while @@FETCH_STATUS = 0
begin
if len (@SQL) > 8 set @SQL = @SQL + ' + ';
set @SQL = @SQL + ' convert(varchar(200), isnull(' + @name + ','''') ) ';
/*
if @system_type_id not in (35, 167, 175,231,239) -- Se nao for do tipo character
begin

set @SQL = @SQL + ' convert(varchar(50), ' + @name + ' ) '

end;
*/
fetch cursorcolumns into @name, @system_type_id
end;
close cursorcolumns;
deallocate cursorcolumns;

select @UID = UID from sysobjects where name IN ( 'GN_USUARIO' )
SELECT @schemaname = name from sys.SCHEMAS WHERE SCHEMA_ID = @UID

set @SQL = @SQL + ' from ' + @schemaname + '.' + @nometabela

select @SQL;

exec @SQL;

Ceilton M
   - 13 mai 2015

Um detalhe, pode usar o convert em campos que já sao do tipo varchar que não da erro.

Carlos Eduardo
   - 14 mai 2015

Boa tarde!

Caro Ceilton,

Fiz testes no exemplo que você disponibilizou mas não obtive sucesso pois ao executar a consulta informando minha tabela (@nometabela = 'PRODUTOS') a consulta esta retornando vazia.

Hoje consegui fazer uma store procedure e estou quase lá, só está faltando o procedimento me retornar o conteúdo do select que estou compondo no loop. Não consegui fazer com que este procedimento me retornasse o resultado do select mas sim a instrução sql. Exemplo: "select campo1, campo2 from PRODUTOS"

Estou postando meu procedimento para que vocês possam me ajudar:

Citação:
CREATE PROCEDURE [dbo].[sp_Retorna_Conteudo_Registro](
@nome_tabela varchar(50),
@campo_chave varchar(50),
@codigo varchar(10),
@resultado varchar(8000) OUTPUT)
AS
set nocount on

declare cursorcolumns cursor for
select column_name, data_type
from information_schema.columns
where table_name = @nome_tabela
and (column_name not like '%HASH')

declare @column_name varchar(100), @data_type varchar(100), @SQL varchar(5000)
set @SQL = 'select '
open cursorcolumns

fetch next from cursorcolumns into @column_name, @data_type

while (@@FETCH_STATUS = 0)
begin
if @data_type in ('char', 'nchar', 'nvarchar', 'varchar')
set @SQL = @SQL + 'coalesce(' + @column_name + ','''') + '
else
set @SQL = @SQL + 'coalesce(convert(varchar(8000), ' + @column_name + '),'''') + '
fetch next from cursorcolumns into @column_name, @data_type
end
close cursorcolumns
deallocate cursorcolumns

if right(@SQL,2) = '+ ' --remove o caracter "+" resultado da concatenação no loop dos campos
set @SQL = left(@SQL,(len(@SQL)-1))

----------------- É neste ponto que não consigo retornar o resultado deste select -----------------
select @Resultado = (@SQL + ' from ' + @nome_tabela + ' where ' + @campo_chave + ' = ' + @codigo)

set nocount off


Estou realizando os testes no Delphi:

Citação:
procedure TForm1.btnExecutarClick(Sender: TObject);
Var
sp_Retorna_Conteudo_Registro: TSQLStoredProc;
begin
//Store Procedure
try
try
sp_Retorna_Conteudo_Registro := TSQLStoredProc.Create(nil);
sp_Retorna_Conteudo_Registro.SQLConnection := AutoConnection;
sp_Retorna_Conteudo_Registro.SchemaName := 'dbo';
sp_Retorna_Conteudo_Registro.StoredProcName := 'sp_Retorna_Conteudo_Registro';
sp_Retorna_Conteudo_Registro.Params.FindParam('@nome_tabela').AsString := lbledtTabela.Text;
sp_Retorna_Conteudo_Registro.Params.FindParam('@campo_chave').AsString := lbledtChave.Text;
sp_Retorna_Conteudo_Registro.Params.FindParam('@codigo').AsString := lbledtCodigo.Text;
sp_Retorna_Conteudo_Registro.ExecProc;

lbledtResultSP.Text := sp_Retorna_Conteudo_Registro.Params.FindParam('@resultado').AsString;
finally
FreeAndNil(sp_Retorna_Conteudo_Registro);
end;
except on E: Exception do
Application.MessageBox(PChar(E.Message), 'Erro', MB_ICONERROR);
end
end;

Marcos P
   - 14 mai 2015

#Código

select @Resultado = (@SQL + ' from ' + @nome_tabela + ' where ' + @campo_chave + ' = ' + @codigo)

Não rola !

Faça...

#Código
set @SQL = @SQL + ' from ' + @nome_tabela + ' where ' + @campo_chave + ' = ' + @codigo
exec(@SQL)

Se quiser ver a query antes de rodar, troque o "exec" por "print".

Uma pergunta... um item cuja descrição é "SUPORTE PARA MONITOR", deve retornar "SUPORTE PARA MONITOR" ou "SUPORTEPARAMONITOR" ?

Carlos Eduardo
   - 14 mai 2015

Marcos, agora a situação é a seguinte.

O procedimento que você pediu para alterar funcionou somente quando executo o procedimento no "SQL Management Studio":

#Código

exec sp_Retorna_Conteudo_Registro 'PRODUTOS', 'PRD_CODIGO', 1, ''


Resultado:

Citação:
1CONJUNTO DIVS.Sep 18 2005 12:00AM CJ0.00000.00000.00001020.000017.000000.00009949.000049.00000.000025.00000.00000.00000.000067.379921100.0000.00000.0000R$Sep 29 2014 12:00AMTT0


Mas no Delphi executa sem da erro mas nao traz nada no retorno. Alguma sugestão? No post anterior eu inseri como estou utilizando a Store Procedure no Delphi.

Respondendo sua pergunta a descrição deve retornar com os devidos espaços: "SUPORTE PARA MONITOR"

Esse ta dando trabalho rs.

Grato pela atenção!

Marcos P
   - 14 mai 2015

Já é um avanço...

Vai ser necessário debug do código Delphi !

O Delphi gera algum erro ou somente não retorna nada ?

Caso retorne erro, cole ele aqui...

Caso não retorne, você provavelmente está chamando errado a SP...
> Confirme certinho a passagem de parâmetros para a procedure...
> Abra um "Sql Profiler" no server e debug a chamada à procedure...
> Pegue o comando gerado no banco e rode no Management Studio... ajustando a sintaxe de chamada no Delphi, até ficar certo !

Marcos P
   - 14 mai 2015

Em tempo... qual a versão do seu Delphi ?

Se for superior a 7, troque a passagem de parâmetros "AsString", para : "AsAnsiString".

Carlos Eduardo
   - 14 mai 2015

Estou utilizando o Delphi 7.

O engraçado é que antes quando estava com a linha abaixo na SP estava retornando pelo Delphi normalmente porém não com o conteúdo que preciso.

#Código

select @Resultado = (@SQL + ' from ' + @nome_tabela + ' where ' + @campo_chave + ' = ' + @codigo)


Não está ocorrendo erro.

Estou utilizando o DBExpress tentarei usar o ADO para fim de testes.

Qualquer novidade posto aqui.

Grato!

Marcos P
   - 14 mai 2015


Citação:

Não consegui fazer com que este procedimento me retornasse o resultado do select mas sim a instrução sql. Exemplo: "select campo1, campo2 from PRODUTOS"


Não entendi...

Conforme você mesmo disse a query anterior ( com select @Resultado ), não estava funcionando... pois retornava a instrução e não os dados !

Agora, você afirma que estava retornando normalmente no Delphi...

Você chegou a fazer o debug no banco ?

O execute está sendo gerado corretamente, pelo Delphi ?

Carlos Eduardo
   - 14 mai 2015

Marcos, desculpe a confusão... mas na verdade o que eu quis dizer e que no Delphi que não mais esta pegando o retorno do procedimento. O procedimento em si quando executo pelo SQL Management Studio esta OK.

Vou postar o código do Delphi que estou tendo problemas com o retorno do procedimento. O parâmetro "@resultado" esta retornando vazio.

#Código

  try
    try
      sp_Retorna_Conteudo_Registro := TSQLStoredProc.Create(nil);
      sp_Retorna_Conteudo_Registro.SQLConnection  := AutoConnection;
      sp_Retorna_Conteudo_Registro.SchemaName     := 'dbo';
      sp_Retorna_Conteudo_Registro.StoredProcName := 'sp_Retorna_Conteudo_Registro';
      sp_Retorna_Conteudo_Registro.Params.FindParam('@nome_tabela').AsString := lbledtTabela.Text;
      sp_Retorna_Conteudo_Registro.Params.FindParam('@campo_chave').AsString := lbledtChave.Text;
      sp_Retorna_Conteudo_Registro.Params.FindParam('@codigo').AsString      := lbledtCodigo.Text;
      sp_Retorna_Conteudo_Registro.ExecProc;
      lbledtResultSP.Text := sp_Retorna_Conteudo_Registro.Params.FindParam('@resultado').AsString;
    finally
      FreeAndNil(sp_Retorna_Conteudo_Registro);
    end;
  except on E: Exception do
    Application.MessageBox(PChar(E.Message), 'Erro', MB_ICONERROR);
  end