Herhangi bir muhasebe sistemi geliştiricisi, büyük veri hacimlerini analiz etme göreviyle karşı karşıya kalır. "Bilgi çorbasını" yapılandırılmış raporlara dönüştürmek, yönetim kararları almak için kritik önem taşır. Bu, örneğin şunları kapsar:
Örneğin, OLAP küpleri (FastCube), bu görevleri hızlı, görsel ve karmaşık SQL sorguları yazmadan çözmenizi sağlar. İki boyutlu tabloların aksine, çok boyutlu pivot tablolar veriye farklı açılardan (veri kesiği ile) gerçek zamanlı olarak bakma imkânı sunar.
Bu makalede, Delphi'de TfrGrid (kaynak veriler için) ve TfcxSliceGrid (pivot özeti oluşturmak için) bileşenlerini kullanarak analitik bir uygulama oluşturma sürecini adım adım inceleyeceğiz.
Analitiği kurmadan önce ilk veri kesiğini görmemiz gerekir. Örnek olarak 2025 yılına ait bir makine imalat işletmesinin verilerini alalım.
TfrGrid bileşenine ihtiyacımız olacak; bu bileşen FastReport VCL paketinin parçasıdır ve demo sürümünde ücretsiz olarak sunulur.
Grid bileşeninin ana özelliği — hücrelerin doğrudan düzenlenmesidir (veritabanı alanındaki kaynak verilerin değiştirilmesi). FastGrid'de bu, alan türüne göre editörlerin otomatik olarak atanmasıyla gerçekleştirilir. Örneğin:
Önemli: Bu aşamada kaynak verileri görüntülemek ve elle düzeltmek için bir arayüz elde ettik. Bu henüz analitiğin nihai sonucu değil.
Şimdi ana araca geçiyoruz — pivot tabloya. Bunun için TfcxSliceGrid bileşenini kullanacağız ve onu TfrGrid ile aynı veri kaynağına bağlayacağız.
Zaman dönemleriyle rahat çalışmak için tarihin bölünmesini yapılandırmak gerekir:
Ardından, uygulamayı her başlattığımızda alanları fareyle sürüklememek için formun OnShow olay işleyicisini yazacağız.
uses …, fcxTypes; procedure TForm1.FormShow(Sender: TObject); var LIndex: Integer; begin fcxSlice1.BeginUpdate; try // Adding fields to the Filters area fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Machine'], 'Machine', 'Machine'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Date'], 'Date', 'Date'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Department'], 'Department', 'Work Area'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Shift'], 'Shift', 'Shift'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Operator'], 'Operator', 'Operator'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Product'], 'Product', 'Product'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Product_Category'], 'Product_Category', 'Product Category'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Work_Order'], 'Work_Order', 'Product Order'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Downtime_Reason'], 'Downtime_Reason', 'Downtime Reason'); fcxSlice1.PageContainer.AddFilterField(fcxSlice1.SliceFields.ItemByName['Plant'], 'Plant', 'Workshop'); // Adding fields to the Rows area fcxSlice1.YAxisContainer.AddDimension(fcxSlice1.SliceFields.ItemByName['Supervisor'], 'Supervisor', 'Foreman'); // Setting up data fields LIndex := fcxSlice1.MeasuresContainer.AddMeasure(fcxSlice1.SliceFields.ItemByName['Planned_Qty'], 'Planned_Qty', 'Plan, pcs', af_Sum); fcxSlice1.MeasuresContainer.Measures[LIndex].Visible := False; fcxSlice1.MeasuresContainer.AddMeasure(fcxSlice1.SliceFields.ItemByName['Produced_Qty'], 'Produced_Qty', 'Produced, pcs', af_Sum); fcxSlice1.MeasuresContainer.AddMeasure(fcxSlice1.SliceFields.ItemByName['Defective_Qty'], 'Defective_Qty', 'Defects, pcs', af_Sum); LIndex := fcxSlice1.MeasuresContainer.AddMeasure(fcxSlice1.SliceFields.ItemByName['Operating_Hours'], 'Operating_Hours', 'Operating Time, h', af_Sum); fcxSlice1.MeasuresContainer.Measures[LIndex].Visible := False; LIndex := fcxSlice1.MeasuresContainer.AddMeasure(fcxSlice1.SliceFields.ItemByName['Downtime_min'], 'Downtime_min', 'Downtime, min', af_Sum); fcxSlice1.MeasuresContainer.Measures[LIndex].Visible := False; LIndex := fcxSlice1.MeasuresContainer.AddMeasure(fcxSlice1.SliceFields.ItemByName['Unit_Cost'], 'Unit_Cost', 'Unit Cost', af_Sum); fcxSlice1.MeasuresContainer.Measures[LIndex].Visible := False; // Adding fields to the Data area fcxSlice1.XAxisContainer.AddMeasuresField; finally // The table is rebuilt only here fcxSlice1.EndUpdate; end; end;
BeginUpdate ve EndUpdate kullanımı performans için kritik önemdedir, çünkü her alan eklenirken arayüzün birden çok kez yeniden çizilmesini engeller.
Raporu oluşturduktan sonra, alanları fareyle sürükleyerek (drag and drop) anormallikleri anında bulabiliriz. OLAP'ın gerçek görevlerde nasıl yardımcı olduğuna dair 3 örneği inceleyelim.
Elde edilen gridte şu gruplandırmaları ayarlıyoruz: "Ustabaşı" Y ekseninde, "Fire" X ekseninde.
Sonuç çıkarıyoruz: Ustabaşı Smirnov'un fire oranı şüpheli biçimde düşükse, bu, onun çalışma yöntemlerini incelemek için bir sinyal veya onu ödüllendirmek için bir gerekçedir. Veriler, en iyi uygulamaların nerede aranacağını gösteriyor.
Gruplandırma kurallarını değiştiriyoruz. Artık "Vardiya" — Y ekseninde; "Plan, Üretim, Fire" — X ekseninde.
Bu veriler temelinde, üçüncü vardiyanın düşük plana ama yüksek fire oranına sahip olduğu sonucuna varıyoruz. Bu, gece çalışma organizasyonunun verimsizliğine işaret edebilir.
Bir kez daha gruplandırma parametrelerini değiştiriyoruz. Bu kez "Makine Türü" Y ekseninde, "Fire" X ekseninde.
Özetlersek: Belirli bir makine türünde fire değeri ortalama göstergeyi önemli ölçüde aşıyorsa, takım ekipmanının değiştirilmesi veya onarım gereklidir.
FastCube, farklı karmaşıklıkta çok sayıda veri kesiği oluşturmanıza olanak tanır:
Önemli işlevler:
Delphi/Lazarus ortamındaki FastGrid + FastCube bağlaşımı — kurumsal uygulamalara BI analitiği eklemek için hazır bir çözümdür. Şunları elde edersiniz:
Sitemizdeki FastReport VCL'in demo sürümünde belirtilen tüm işlevleri deneyin.