Segue o material com as notas de aula (resumão) sobre modelagem conceitural e lógico de banco de dados. Abordando normalização de banco de dados relacionais. Aqui
Arquivo da categoria: Banco de Dados
SQL Server 2008 R2 launch
Tá aí a palestra que fiz para o evento de launch do SQL Server 2008 R2, na FAESA em Março.
Fazendo upload de imagens no SQL Server 2005 com ASP.NET
Até o Sql server 2000 tinha-se o tipo de dados image para o armazenamento de informações binárias de até 2Gb no banco de dados, mas, com o lançamento do SQL Server 2005 surgiu o tipo de dados varbinary(max), o tipo image ainda continua existindo apenas para compatibilidade com a versão anterior.
Então, qual ou quais diferenças entre o tipo novo varbinary(max) e o image? Este novo tipo tem funcionalidades similar a sua contraparte varbinary(n). Pode-se definir variáveis desse tipo, podendo armazenar nas mesma até 2Gb de informação (atitude não muito normal, mas…), ainda, podemos utilizar este novo tipo de dados em cursores, variáves, utilizando com funções e referenciando na clausula where de um select.
O nosso exemplo de utilização do ASP.NET para upload de imagens será constituído por uma página de upload (exemplificando a forma de carga), uma página para download da imagen armazenada e uma página contendo um grid exibindo o nome original do arquivo, uma opção para download do arquivo e um preview do arquivo no grid – todo este projeto foi desenvolvimento utilizando o Visual Studio 2008.
Inicialmente vamos criar a nossa tabela para conter os arquivos, segue o script de criação:
CREATE TABLE [dbo].[Objetos]( [CD_OBJETO] [int] IDENTITY(1,1) NOT NULL, [OBJETO] [varbinary](max) NOT NULL, [FileName] [nvarchar](300) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, CONSTRAINT [PK_Objetos] PRIMARY KEY CLUSTERED ([CD_OBJETO] ASC) )
Devido a facilidade para se armazenar estas informações no banco de dados o código para o upload é bem simples:
conn.ConnectionString = ConfigurationManager.ConnectionStrings["TesteDB"].ConnectionString.ToString();
SqlCommand comm = new SqlCommand("insert into objetos (objeto,filename) values(@objeto,@filename)", conn);
comm.Parameters.Add("@objeto", SqlDbType.Image);
comm.Parameters["@objeto"].Direction = ParameterDirection.Input;
comm.Parameters["@objeto"].Value = FileUpload1.FileBytes;
comm.Parameters.Add("@filename", SqlDbType.NVarChar, 300);
comm.Parameters["@filename"].Value = FileUpload1.FileName;
conn.Open();
comm.ExecuteNonQuery();
Aqui utilizei o componente FileUpload do ASP.NET e este componente me expõe o arquivo carregado através do atributo FileBytes, que é uma array de bytes. Para atribuir estes bytes ao parâmetro bastou passar estes valores para a propriedade value do parametro e mais nada. Ao executar o comando ExecuteNonQuery a informação é armazenada no banco de dados. No exemplo construído aborda outras informações podem ser obtidas do componente FileUpload.
Para a recuperação dessas informações do banco de dados utilizei o seguinte código:
conn.ConnectionString = ConfigurationManager.ConnectionStrings["TesteDB"].ConnectionString.ToString();
//Obter as informações do arquivo
SqlCommand comm = new SqlCommand("select filename,objeto from objetos where cd_objeto = @cd_objeto", conn);
comm.Parameters.Add("@cd_objeto", SqlDbType.Int);
comm.Parameters["@cd_objeto"].Value = mCodigo;
conn.Open();
SqlDataReader dr = comm.ExecuteReader();
dr.Read();
FileName = dr["filename"].ToString();
//Lê os dados binários
blob = new Byte[(dr.GetBytes(1, 0, null, 0, int.MaxValue))];
dr.GetBytes(1, 0, blob, 0, blob.Length);
dr.Close();
conn.Close();
//Response.TransmitFile
Response.ContentType = GetContentMimeType(FileName);
if(mDownload)
Response.AddHeader("content-disposition", "attachment;filename=" + FileName);
Response.OutputStream.Write(blob, 0, blob.Length);
Response.Flush();
É realizada um select na base de dados para recuperar um arquivo específico, e para a recuperação das informações binárias devemos utilizar o método GetBytes do DataReader passando para o mesmo a posição do campo a ter as informações binárias lidas e o um buffer para a recuperação da informação.
No projeto de exemplo pode-se utilizar a página de upload: upload.aspx para a cargas dos arquivos e a página ViewObjetos.aspx para a visualização de um grid contendo as imagens. A página ShowObjeto.aspx contém a rotina para recuperação de uma imagem no banco de dados e descarregá-la no stream http, esta técnica é muito utilizada para exibição de imagens em grids e outros componentes Dataware que suportem templates. Nesta página ainda podemos descarregar as informações diretamente no stream Response (as imagens são exibidas no navegador) ou podemos exibir a janela de download para que o usuario grave a imagem no disco diretamente (muito util para arquivos que não são imagens). Isto é feito pela introdução do cabeçlho HTTP:
Response.AddHeader("content-disposition", "attachment;filename=" + FileName);
Isto diz ao navegados que existe um anexo ao conteúdo HTTP. Podemos ainda introduzir nessa funcionalidade a geração de thumbnails de imgem (um bom próximo tópico no blog….). Outra coisa importante é configurar corretamente o Content-Type (é através dessa propriedade que navegador saberá qual o tipo de arquivo está anexado ao protocolo HTTP), no exemplo o content-type é determinado pela extensão do arquivo original.
private string GetContentMimeType(string FileName)
{
string ret = "application/octet-stream";
string extensao = System.IO.Path.GetExtension(FileName).ToUpper();
switch (extensao)
{
case ".HTML": ret = "text/html"; break;
case ".HTM": ret = "text/html"; break;
case ".DOC": ret = "application/msword"; break;
case ".DOCX": ret = "application/msword"; break;
case ".XLS": ret = "application/x-msexcel"; break;
case ".XLSX": ret = "application/x-msexcel"; break;
case ".ZIP": ret = "application/zip"; break;
}
return ret;
}
O arquivo do projeto pode ser baixado aqui.
T+
Recurso de PIVOT no SQL Server
É muito comum a necessidade da exibição de informações tabular aonde as colunas são valores contidos em registros, esta técnica é conhecida como pivoteamento. Vamos considerar o seguinte exemplo:
Cliente Ano Valor
——————– ———– ———————
João 2004 1027,00
Pedro 2001 1111,00
João 2005 1018,00
Pedro 2005 1031,00
Paulo 2002 1099,00
João 2004 1084,00
…… …… …….
O problema ocorre quando queremos exibir as vendas por cliente e com o ano em colunas. Esta técnica é chamada de pivoteamento, pois, é necessário exibir um valor que naturalmente está em linha para uma posição em coluna. No Excel isto é uma moleza, mas, dentro de consultas SQL não é tão simples assim. Até o SQL Server 2000 utilizávamos uma combinação de instrução select e case para realizar esta tarefa. Um exemplo de SQL para esta tarefa seria:
select Cliente, sum(ano2001) as '2001', sum(ano2002) as '2002', sum(ano2003) as '2003' from ( select cliente, case when (ano=2001) then valor else 0.00 end as Ano2001, case when (ano=2002) then valor else 0.00 end as Ano2002, case when (ano=2003) then valor else 0.00 end as Ano2003 from lancamentos ) A group by Cliente
Mas, com o SQL Server 2008 esta tarefa foi simplificada com a introdução do comando PIVOT:
select cliente,[2001] as '2001',[2002] as '2002',[2003] as '2003' from ( select valor,cliente,ano from lancamentos ) p pivot ( sum(valor) for ano in ([2001],[2002],[2003]) ) pvt
Tendo como resultado:
cliente 2001 2002 2003
——————– ——————— ——————— ———————
Pedro 59685,00 49346,00 52961,00
Daniel 44000,00 43456,00 59661,00
Paulo 52024,00 40261,00 41441,00
João 45467,00 39211,00 45402,00
Este comando é bem legal, mas, temos uma questão. Reparem que foi fixado o número de anos, mas e no caso de novos serem acrescidos na base de dados? Teremos que alterar as nossas consultas!
Mas podemos desenvolver um código que dinamicamente introduz os novos valores de anos:
--Variável de tipo tabela para conter todos os anos
declare @tblAnos as table (y int not null primary key)
insert into @tblAnos
select distinct ano from lancamentos order by ano asc
declare @cols as nvarchar(max),@anos int
set @anos = (select min(y) from @tblAnos)
--Variável para conter a relação de anos
set @cols = N''
--Montagem da relação de anos
while (@anos is not null)
begin
set @cols = @cols+N',[' + cast(@anos as nvarchar(10))+ N']'
set @anos = (select min(y) from @tblanos where y > @anos)
end
set @cols = substring(@cols,2,len(@cols))
--Construção da query para execução
declare @sql as nvarchar(max)
set @sql = N'Select * from (select cliente,ano,valor from dbo.lancamentos) as p
pivot (sum(valor) for ano in (' + @cols + N')) as pv'
--Utilização do comando Execute para execução da query dinâmica
execute(@sql)
T+