Costumo ler artigos de heróis famosos no CSDN e me beneficiei muito. Recentemente, estava trabalhando em um projeto e precisava usar uma crosstab no relatório, mas o cliente solicitou que ela pudesse ser operada no Grid. Não tive escolha a não ser escrevê-lo sozinho. Um trecho de código é usado para consultas gerais para realizar a tabela cruzada. Não me atrevo a usá-lo exclusivamente, então o carrego na esperança de que possa inspirar outras pessoas. alguns conselhos de heróis famosos.
função CreateTmptab(const AFieldDefs:TFieldDefs):TDataSet;
var
TempTable:TatClientDataSet;
começar
TabelaTemp:=nil;
Resultado:=nulo;
se AFieldDefs<>nil então
começar
tentar
TempTable:=TatClientDataSet.Create(aplicativo);
TempTable.FieldDefs.Assign(AFieldDefs);
TempTable.CreateDataSet;
Resultado:=(TempTable como TDataSet);
Exceto
se TempTable<>nil então
TempTable.Free;
Resultado:=nulo;
elevação;
fim
fim;
fim;
{
Conjunto de dados de origem SouDataset
Campo de coluna dinâmica da tabela cruzada ColField
Campo de linha da tabela cruzada RowField
CampoDataFielddata
}
function GenCrossTable(SouDataset:tdataset;ColField,RowField,DataField:string):tdataset;
var
Vdataset:tdataset;
tmpdataset:tatclientdataset;
Fonte de dados:tdatasource;
tmpstrs:tstrings;
rowval,colval,dataval:string;
i,j:inteiro;
tipo de dados: TFieldType;
DataSize:inteiro;
começar
resultado:=nulo;
se (ColField='') ou(RowField='')ou(DataField='') então
showmessage('Todos os campos não devem ser NULOS!')
outro
começar
if (ColField=RowField)
ou(ColField=DataField)
ou(RowField=DataField) então
showmessage('Todos os campos não são iguais!')
outro
if (self.SouDataSet.FieldByName(ColField).DataType=ftString)
ou (self.SouDataSet.FieldByName(ColField).DataType<>ftWideString)
ou (self.SouDataSet.FieldByName(ColField).DataType<>ftFixedChar)
ou (self.SouDataSet.FieldByName(ColField).DataType<>ftMemo)
ou (self.SouDataSet.FieldByName(ColField).DataType<>ftFmtMemo) então
começar
tentar
tmpstrs:=tstringlist.Create;
Vdataset:=SouDataSet;
Vdataset.Primeiro;
para i:=0 para Vdataset.RecordCount-1 faça
começar
if (varisnull(SouDataSet.FieldValues[colfield])=false) e (SouDataSet.FieldValues[colfield]<>'') então
se tmpstrs.IndexOf(SouDataSet.FieldValues[colfield])=-1 então
começar
tmpstrs.Add(SouDataSet.FieldValues[colfield]);
fim;
Vdataset.Next;
fim;
//Gerar títulos de coluna dinâmicos
tmpdataset:=TClientDataSet.Create(Self);
tmpdataset.FieldDefs.Add(rowfield,ftstring,50,False);
para i:=0 para tmpstrs.Count-1 faça
começar
com tmpdataset.FieldDefs faça
começar
Adicionar(tmpstrs.Strings[i],ftInteger,0,False);
fim;
fim;
tmpdataset.FieldDefs.Add('Soma',ftInteger,0,False);
DataSource:=tdatasource.Create(self);
DataSource.DataSet:=tmpdataset;
com DataSource faça
começar
conjunto de dados:=Createtmptab(tmpdataset.FieldDefs);
conjunto de dados.Open;
fim;
//Cria tabela temporária
Vdataset.Primeiro;
para i:=0 para Vdataset.RecordCount-1 faça
começar
rowval:=SouDataSet.fieldbyname(rowfield).AsString;
colval:=SouDataSet.fieldbyname(colfield).AsString;
dataval:=SouDataSet.fieldbyname(datafield).AsString;
se dataval='' então dataval:='0';
se DataSource.DataSet.Locate(rowfield,rowval,[loPartialKey]) então
começar
DataSource.DataSet.Edit;
DataSource.DataSet.FieldByName(colval).AsString:=dataval;
DataSource.DataSet.FieldByName('Soma').AsInteger:=
DataSource.DataSet.FieldByName('Sum').AsInteger+strtoint(dataval);
DataSource.DataSet.Post;
fim
outro
começar
DataSource.DataSet.Append;
DataSource.DataSet.FieldByName(rowfield).AsString:=rowval;
para j:=1 para DataSource.DataSet.Fields.Count-1 faça
DataSource.DataSet.Fields[j].AsCurrency:=0;
DataSource.DataSet.FieldByName(colval).AsString:=dataval;
DataSource.DataSet.FieldByName('Sum').AsString:=dataval;
DataSource.DataSet.Post;
fim;
Vdataset.Next;
fim;
resultado:=DataSource.DataSet;
//Gerar conjunto de dados de crosstab
tmpstrs.Free;
exceto
fim;
fim
outro
showmessage('ColField deve ser do tipo String!') ;
fim;
fim;
O código acima passou no teste em D7 e SQL Server 7.0/2000