1C:Enterprise EĞİTİM

DERS 3

1C:Enterprise Ders 3-1

Birikim Kontrolü (devamı)

Ders 2’de görüldüğü gibi birikim kontrolü yapmak için kullandığımız sorguda hala bir problem var. Bizim kullandığımız sorgu cümlesi:

SELECT
BalanceOfMaterialsBalance.Material AS Material,
BalanceOfMaterialsBalance.Warehouse AS Warehouse,
BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance
FROM
AccumulationRegister.BalanceOfMaterials.Balance AS BalanceOfMaterialsBalance
WHERE
BalanceOfMaterialsBalance.QuantityBalance < 0

­

Sorgu cümlesi tek bir koşul içermekte ‘BalanceOfMaterialsBalance.QuantityBalance <0’. Sorgu geçerli belge ile ilgisi olup olmadığını kontrol etmeksizin negatif bakiyesi olan tüm kayıtları döndürür. Bu 1C İşletme ’de (dosya modu veya istemci/sunucu modu) DBMS (Veri tabanı Yönetim Sistemi) ile eşzamanlı çalışan kullanıcı sayısına bağlı olarak bazı sorunlara sebep olabilir.

Oluşabilecek sorunların çoğu bu dersimizin dışındadır. Fakat nispeten basit bir örnek vermek için şöyle belirtebiliriz: Bu sorgu cümlesi ile 1C İşletme DBMS (Veri tabanı Yönetim Sistemi)’nin kayıtlarına göz atmak için Birikim Kayıt Tablosundaki tüm kayıtları tarar ve teker teker kontrol eder. Birikim Kayıt Tablosu her depo için aylık olarak her malzeme için kayıt tutmaktadır. O kayıtlar zaman içerisinde binlerce olacak ve sayı sürekli artacaktır. Bu nedenle de bu sorgu cümlesinin çalıştırılması zaman kaybına neden olacaktır. Birikim kayıt tablolarında arama yapmak için kullanılacak ideal alanlar Birikim Kayıt Tablosunun boyutlarıdır. Diğer alanlarla ile arama yapılabilir fakat çokta verimli olmayacaktır.

Yani, biz kesinlikle Birikim Kayıt Tablosunun Malzeme ve Depo parametrelerini sorgunun koşullarına eklemeliyiz. Böylece işlem yapılan belge ile ilgisi olmayan kayıtları filtre etmiş olacağız. Aşağıdaki resim bu sorgu prensibini gösterir:

Biz ilk iki kaydı okumak (yeşile boyalı olan satırlar) ve Birikim Kayıt Tablosundaki son iki kaydı da (kırmızı boyalı olan satırlar) filtrelemek istiyoruz.

Bunu yapmak için 3 tane seçeneğimiz var:

  • – WHERE;
  • – JOIN;
  • – Sanal tablonun parametreleri.

Tahmin edebileceğiniz gibi, tek bir seçeneği kullanarak işlem yapmak önerilir ama biz dersimizde tartışarak tüm yolları deneyeceğiz.

WHERE komutu ile Birikim Kayıt Tablosu filtreleme

WHERE komutu 1C’de sınırsız sayıda AND, OR, NOT ve parantez içerebilir. Bu koşullar amaçlarımız için yararlı olanlardır:

  • – <Expression> <Comparison operation> <Expression>
  • – <Expression> [NOT] IN (<List or Subquery>)

<Expression> <Comparison operation> <Expression>

Koşul oluştururken kullanabileceğimiz geçerli tüm karşılaştırma operatörleri aşağıda gösterilmiştir:

  • – >
  • – <
  • – =
  • – >=
  • – <=
  • – <>

Burada kullanılabilecek ifadeler (sağında veya solunda – önemli değil):

  • – BalanceTab için herhangi bir alan. Örnekler:
    •      – BalanceTab.QuantityBalance
    •      – BalanceTab.Material
  • – BalanceTab içerisindeki herhangi bir nesnenin alanları:
    •      – BalanceTab.Material. MaterialOrService
    •      – BalanceTab.Warehouse. Description
  • – Herhangi bir tür (değişmez – önceden tanımlı):
    •      – 100
    •      – “Main”
  • – Değeri sonradan belirlenecek parametre (sorgu çalıştırılmadan önce):
    •      – &BalanceLimit
    •      – &DefaultWarehouse
  • – Herhangi bir değer döndüren operatör (aritmetik veya aritmetik değil):
    •      – BalanceTab.QuantityBalance / 2 + 10
    •      – “PRE:” + BalanceTab.Material. Code

Bu ifadeler herhangi bir kombinasyonu karşılaştırmak için her iki tarafta herhangi bir sıra ile kullanılabilir.

Unutmayın ki, string ifadeleri karşılaştırmak için =, <> ifadeleri haricinde diğer tüm ifadeleri de kullanabilirsiniz. Bu durumda ifadeler alfabetik sıralarına göre karşılaştırılacak. Burada TRUE değeri döndüren birkaç örnek göreceğiz:

  • – “Abc” <“bcd”
  • – “23” <“qqq”

Burada WHERE komutu için birkaç geçerli komut örneğini göreceğiz:

// Returns all of the Balance table records with a balance not equal to 5
WHERE BalanceTab.QuantityBalance <> 5

 

­

// Returns nothing
WHERE 2 * 2 = 5

 

­

// Returns all rows
WHERE “abc” + “def” = “abcdef”

 

­

// Returns balances of all materials that are in “Plumber stuff” group
BalanceTab.Material.Parent.Description = “Plumber stuff”

­

Şimdi ihtiyacımız olmayan kayıtları Birikim Kayıt Tablosundan sorgu koşulları kullanarak filtreleyebilir miyiz? Evet, hadi deneyelim. Şu şekilde sorgu cümlesini tekrar yazabiliriz:

SELECT
BalanceOfMaterialsBalance.Material AS Material,
BalanceOfMaterialsBalance.Warehouse AS Warehouse,
BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance
FROM
AccumulationRegister.BalanceOfMaterials.Balance AS BalanceOfMaterialsBalance
WHERE
QuantityBalance < 0 AND
Warehouse = &Warehouse AND
(
Material = &Material1 OR
Material = &Material2 OR
Material = &Material3 OR

)

­

İşte burada bir problem karşımıza çıkmaktadır. Çünkü biz bu tablo alanında ne kadar kayıt olduğunu bilmiyoruz. Yani sorgu koşullarına sabit bir değer yazmamalıyız. Ama biz çalışma zamanında inşa edilebilen belgeyi kaydederken kullanılan birçok string değişken üretiyoruz.

Böyle dinamik sorguları 1C geliştiricileri çok yoğun olarak kullanmaktadır. Eğer herhangi bir 1C uygulamasını açarsanız, içerisinde sabit sorgu cümlesi çok az bulursunuz, genel olarak dinamik sorgu cümlesi kullanılır. Belirgin avantajları bir yana, bu yaklaşımın bir dezavantajı var: uygulama kaynak koduna baktığınızda sorgu sonucunda elde edilecek değerleri bilmiyoruz. Ama bir ipucu: hata ayıklayıcı kullanarak, durdurma noktası işaretlediğinizde sorgu çalıştırıldığı zaman hangi değerleri döndürdüğünü görebilir ve sorgudaki değişkenleri takip edebilirsiniz.

Şimdi ihtiyacımıza göre Birikim kayıt tablosu için dinamik sorgu oluşturmak için çalışalım.

Burada yeni oluşturulan sorgu cümlesini görmekteyiz:

Procedure Posting(Cancel, Mode)

 

// 1. Filling out BalanceOfMaterials recordset
RegisterRecords.BalanceOfMaterials.Write = True;
For Each CurRowMaterialsAndServices In MaterialsAndServices Do
If CurRowMaterialsAndServices.MaterialOrService.MaterialOrService =
Enums.MaterialOrService.Service Then Continue;
EndIf;
Record = RegisterRecords.BalanceOfMaterials.Add();
Record.RecordType = AccumulationRecordType.Expense;
Record.Period = Date;
Record.Material = CurRowMaterialsAndServices.MaterialOrService;
Record.Warehouse = Warehouse;
Record.Quantity = CurRowMaterialsAndServices.Quantity;
EndDo;

 

//2. Writing down BalanceOfMaterials recordset
RegisterRecords.BalanceOfMaterials.LockForUpdate = True;
RegisterRecords.Write();

 

//3. Checking if there any negative balance records
Query = New Query;
Query.Text =
“SELECT
| BalanceOfMaterialsBalance.Material AS Material,
| BalanceOfMaterialsBalance.Warehouse AS Warehouse,
| BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance
|FROM
| AccumulationRegister.BalanceOfMaterials.Balance AS
| BalanceOfMaterialsBalance
|WHERE
| BalanceOfMaterialsBalance.QuantityBalance < 0″;

//4. Add filter on Materials from this document only
Counter = 0;
MaterialsCondition = “”;
For Each CurRowMaterialsAndServices In MaterialsAndServices Do
//Skip services
If CurRowMaterialsAndServices.MaterialOrService.MaterialOrService =
Enums.MaterialOrService.Service Then Continue;
EndIf;
//Add Warehouse to the condition

 

Counter = Counter + 1;
If Counter > 1 Then
MaterialsCondition = MaterialsCondition + OR + Chars.CR;
EndIf;
MaterialsCondition = MaterialsCondition + Chars.Tab + Chars.Tab +
“BalanceOfMaterialsBalance.Material = &Material” + Counter;
Query.SetParameter(“Material” + Counter,
CurRowMaterialsAndServices.MaterialOrService);
EndDo;
If MaterialsCondition <> “” Then
Query.Text = Query.Text + AND + Chars.CR +
Chars.Tab + “Warehouse = &Warehouse” + Chars.CR +
Chars.Tab + AND ( + Chars.CR +
MaterialsCondition + Chars.CR +
Chars.Tab + );
EndIf;
Query.SetParameter(“Warehouse”, ThisObject.Warehouse);

 

­

//5. Execute the query

QueryResult = Query.Execute();
SelectionDetailRecords = QueryResult.Select();
//6. If the result is not empty, cancel the document’s posting

If SelectionDetailRecords.Count() = 0 Then
Return;
EndIf;
Cancel = True;

 

//7. divpare the error message and display it.
MessageText =
“There is not enough materials on the “ +
ThisObject.Warehouse.Description +
. See the list of deficits below:” +
MessageText;
While SelectionDetailRecords.Next() Do
MessageText =
MessageText + Chars.CR + Chars.LF +
SelectionDetailRecords.Material.Description + “: “ +
SelectionDetailRecords.QuantityBalance;
EndDo;
Message(MessageText);

 

EndProcedure

­

Sonuç olarak, bizim ihtiyacımız olan Birikim kayıt tablosu kayıtları listelenecek ve istenmeyen kayıtlar filtre edilecektir. Ama bu yöntem ne kadar iyi? Pekâlâ, bir hizmet belgesi içerisinde yüzlerce kayıt var ve bizim hepsinin cevabını bildiğimizi hayal edin. Böyle bir belgenin Birikim Kayıt Tablosu bakiyesini öğrenmek için çok büyük bir sorgu yazmak gerekmektedir ve bu sorgu çalıştırıldığında da çok yüksek miktarda kaynak tüketen bir görev olacaktır.

Bir sorun daha var ki sorgu cümlesi her çalıştırıldığında sonucun farklılık göstermesi ihtimalidir. (Çünkü parametre sayısı belgenin tablo bölümünde satır sayısına bağlı olarak değişir). Uygulama daha sık sorgu derlemeye çalışırsa bu uygulamanın yavaşlamasına sebep olacaktır.

Başka bir sorun, kaynak kodunun artması olacaktır. Kaynak kodunu okumak bir kâbusa dönüşecek ve hatta hata riski sabit sorgulara göre artacaktır.

Sonuç, gerçek hayattaki gibi bir yaklaşımla Birikim kayıt tablosunda bakiye kontrolü yapmayı tavsiye etmiyoruz.

Parametreler ve Değişmez Değerler

Sorgu derleme hakkında birkaç kelime daha söyleyelim. Unutulmaması gereken bir şey var. O da şu: değişmez değerler kullanılarak sorgu hazırlandığında ve sonrasında değişmez değer değiştirildiğinde uygulamanın tekrar derlenmesi gerektiğidir. Örneğin, üç tane sorgu da aynı değeri döndürmektedir:

//Query 1
Query.Text = “SELECT * FROM Catalog.Clients AS C WHERE C.Name =“Sigizmund”“”;

 

­

//Query 2

Name = “Sigizmund”;
Query.Text = “SELECT * FROM Catalog.Clients AS C WHERE C.Name =“” + Name + “”“”;

 

­

//Query 3

Query.Text = “SELECT * FROM Catalog.Clients AS C WHERE C.Name = &Name”;
Query.SetParameter(“Name”, “Sigizmund”);

­

Ama birinci ve ikinci sorgu da müşteri adını değiştirmek için sorgu cümlesinin değiştirilmesi ve tekrar derlenmesi gerekmektedir. Bu üçünü sorgu için geçerli değildir. Üçüncü sorguda sadece parametre kısmındaki değişmez değeri değiştirdiğimizde ilk çalıştırmada sorgu yeni parametresi ile hazır olacaktır. Ama çoğu zaman bizi bunun gibi basit sorgular kurtaramaz. Ama bu gerçek hayattaki bazı sorgular için önemli olabilir.

Bu nedenle, 1C sorgularında asla değişmez değer kullanmamalısınız. Sorgularda zorunlu kalmadıkça parametre kullanmalısınız.

1C:Enterprise Ders 3-2

<Expression> [NOT] IN (<List or Subquery>)

Koşul tipinin bir alt sorgudan elde edilen kayıt olup olmadığını veya listedeki bir değer olup olmadığını kontrol edebiliriz. Liste formu kullanarak sorgu cümlesini tekrar yazarsak:

SELECT

BalanceOfMaterialsBalance.Material AS Material,

BalanceOfMaterialsBalance.Warehouse AS Warehouse,

BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance

FROM

AccumulationRegister.BalanceOfMaterials.Balance AS BalanceOfMaterialsBalance

WHERE

QuantityBalance < 0 AND

Warehouse = &Warehouse AND

Material IN (&Material1, &Material2, &Material3,…)

­

Bu sorgu işini yapar, ama dinamik olarak inşa edilecek veriler olduğundan aynı sorunlar vardır: sorgu metni büyük ve sık sık yeniden hesaplanması gerekir. Alt sorgu metni kullanarak bu işlemi yapmak daha iyi bir seçim olacaktır. Bu mantık için basit bir örnek:

SELECT <Something>

FROM <Somewhere>

WHERE <SomeField> IN (

SELECT <SomethingElse>

FROM <SomewhereElse>

WHERE <AnotherCondition>

)

­

Yani biz bu sorgumuzun içindeki WHERE komutunun altına bir alt sorgu yazarak ihtiyacımız olan verilere daha hızlı bir biçimde ulaşabiliriz. Alt sorguları her türlü koşul için kullanabilirsiniz, “IN (sub-sub-query)” şeklinde ana sorguya dâhil olmak üzere, düzenli ve istediğiniz kadar alt sorgu kullanabilirsiniz.

Bu tür durumlar hakkında bizim istediğimiz sorgu için statik bir metin kullanabilmenin iyi bir şey olduğunu görebiliriz. Bunu nasıl yapabileceğimizi görelim.

Burada ortaya çıkan kodu görebiliriz:

//3. Checking if there any negative balance records

Query = New Query;

Query.Text =

“SELECT

| BalanceOfMaterialsBalance.Material AS Material,

| BalanceOfMaterialsBalance.Warehouse AS Warehouse,

| BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance

|FROM

| AccumulationRegister.BalanceOfMaterials.Balance AS BalanceOfMaterialsBalance

|WHERE

| BalanceOfMaterialsBalance.QuantityBalance < 0

| AND BalanceOfMaterialsBalance.Warehouse = &Warehouse

| AND BalanceOfMaterialsBalance.Material IN

|   (SELECT

|    ServicesMaterialsAndServices.MaterialOrService

|   FROM

|    Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

|   WHERE

|    ServicesMaterialsAndServices.Ref = &Ref

|    AND ServicesMaterialsAndServices.MaterialOrService.MaterialOrService =

|    &MaterialOrService);

 

Query.SetParameter(“Warehouse”, ThisObject.Warehouse);

Query.SetParameter(“Ref”, ThisObject.Ref);

Query.SetParameter(“MaterialOrService”, Enums.MaterialOrService.Material);

­

Yani, statik bir sorguyu alt sorgu metni kullanarak bitirmiş olduk.

Burada bu koşul tipleri hakkında bir şeyin daha olduğunu dikkate almamız gerekir. Burada mevcut hizmet belgesi yapısı şöyledir:

Dikkat edilmesi gereken Depo (WareHouse) belgenin özniteliklerinde yer almaktadır ancak Malzeme veya Hizmet (MetarialOrService) belgenin tablo özellikleri kısmında yer almaktadır. Belge farklı sayıda malzeme veya hizmet içerebilir ancak tek bir tane Depo içerebilmektedir. Diğer bir değişle tüm malzeme/hizmetler tek bir depodan alınacaktır.

Bu nedenle, biz depo için tek parametre kontrolü yapabiliriz fakat malzeme/hizmetler için belgede bulunan listede bulunan tüm değerler için kontrol yapabiliriz.

Şimdi, tek bir hizmet için farklı depolardan farklı malzemeler getirilerek uygulamanın işlevselliği arttırılmak isteniyorsa, biz bunu nasıl yapabiliriz?

Bu durumda, bizim ihtiyacımız olan belgenin yapısını aşağıdaki gibi değiştirmektir:

Burada Depo (Warehouse) u özniteliklerden tablo öznitelikleri içerisine taşıdığımızda, her malzeme için bizden depo isteyecektir ve farklı malzemeler farklı depolardan seçilebilir olacaktır.

Şimdi, bu durumda düzgün çalışması için, bakiye kontrol sorgusunu usule uygun nasıl değiştireceğiz? Bizim depo listene göre depoları kontrol etmemiz gerekiyor ama bunu yapmak için burada nasıl bir sorgu cümlesi kullanmalıyız? En bariz çözüm bu gibi gözüküyor:

SELECT

BalanceOfMaterialsBalance.Material AS Material,

BalanceOfMaterialsBalance.Warehouse AS Warehouse,

BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance

FROM

AccumulationRegister.BalanceOfMaterials.Balance AS BalanceOfMaterialsBalance

WHERE

BalanceOfMaterialsBalance.QuantityBalance < 0

AND BalanceOfMaterialsBalance.Material IN

(SELECT

ServicesMaterialsAndServices.MaterialOrService

FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

WHERE

ServicesMaterialsAndServices.Ref = &Ref

AND ServicesMaterialsAndServices.MaterialOrService.MaterialOrService =

&MaterialOrService)

AND BalanceOfMaterialsBalance.Warehouse IN

(SELECT

ServicesMaterialsAndServices.Warehouse

FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

WHERE

ServicesMaterialsAndServices.Ref = &Ref)

­

Biz burada sadece başka bir depo kontrolü için alt sorgu ekledik ve malzemelerin kombine olarak alt sorguda AND komutu ile kontrolünü sağladık.

Şimdi bu sorgu bizim ihtiyacımız olan değerleri döndürecek mi? Görelim. Bizim elimizde bulunan tablo özniteliklerinde iki satırdan oluşan bir bölüm var:

Bu durumda, bu durum yukarıdaki resimde görüldüğü gidi ifade edilebilir:

Material IN (M1, M2) AND Warehouse IN (W1, W2)

Den:

(Material = M1 OR Material = M2) AND (Warehouse = W1 OR Warehouse = W2)

Muhtemelen bildiğiniz gibi, mantıksal operatörler AND ve OR çarpma (*) ve toplama (+) operatörleri ile aynı mantıkta çalışabilmektedirler. Yani biz yukarıdaki koşulu şu şekilde tekrar yazarsak:

(M1 + M2) * (W1 + W2)

Ve parantezleri kaldırıp işlemleri yaparsak:

M1*W1 + M1*W2 + M2*W1 + M2*W2

Mantıksal operatörlerin geri döndürülmesi ile sorgu aşağıdaki şeklini almış olacak:

(Material = M1 AND Warehouse = W1) OR

(Material = M1 AND Warehouse = W2) OR

(Material = M2 AND Warehouse = W1) OR

(Material = M2 AND Warehouse = W2)

Diğer bir değişle, biz bu koşul ile Birikim kayıt tablosundan aşağıdaki sonuçları almış oluruz:

Yani, şu an biz ihtiyacımız olan iki kaydı alıyoruz ama bizim belgemiz ile alakası olmayan iki kaydı da almış olduk.

Tamam, bu koşul bize gereksiz kayıtları da vermektedir. Peki, biz bunu düzeltmek için ne yapabiliriz?

Eğer genel SQL komutlarına aşina iseniz, tek değerli ifadelerin nasıl yazılacağını biliyor olmalısınız. Örneğin <expression> IN <subquery>, ama burada bu sorunu çözmek için farklı türde sorgu komutu kullanmanız gerekmektedir. (JOIN komutunu daha sonra değinilecektir.)

Ama 1C:Enterprise’de (SQL sözdizimi için bazı uzantıları destekler) birden fazla alt sorgu kullanmak için IN komutunu kullanmak yeterlidir. Bu IN koşullu sözdizimi biçimi şuna benzer:

(<exp1>, <exp2>…) IN (SELECT <exp1>, <exp2>…)

Depo (Warehouse) özniteliğini belgenin özniteliklerinden tablo özniteliklerine taşıdıktan sonra ve IN komutu ile koşullu sorgu sağlandıktan sonra elimizde olan belge kaydetme prosedürü:

Procedure Posting(Cancel, Mode)

 

// 1. Filling out BalanceOfMaterials recordset

RegisterRecords.BalanceOfMaterials.Write = True;

For Each CurRowMaterialsAndServices In MaterialsAndServices Do

If CurRowMaterialsAndServices.MaterialOrService.MaterialOrService =

Enums.MaterialOrService.Service Then Continue;

EndIf;

Record = RegisterRecords.BalanceOfMaterials.Add();

Record.RecordType = AccumulationRecordType.Expense;

Record.Period = Date;

Record.Material = CurRowMaterialsAndServices.MaterialOrService;

Record.Warehouse = CurRowMaterialsAndServices.Warehouse;

Record.Quantity = CurRowMaterialsAndServices.Quantity;

EndDo;

 

//2. Writing down BalanceOfMaterials recordset

RegisterRecords.BalanceOfMaterials.LockForUpdate = True;

RegisterRecords.Write();

 

//3. Checking if there any negative balance records

Query = New Query;

Query.Text =

“SELECT

| BalanceOfMaterialsBalance.Material AS Material,

| BalanceOfMaterialsBalance.Warehouse AS Warehouse,

| BalanceOfMaterialsBalance.QuantityBalance AS QuantityBalance

|FROM

| AccumulationRegister.BalanceOfMaterials.Balance AS BalanceOfMaterialsBalance

|WHERE

| BalanceOfMaterialsBalance.QuantityBalance < 0

| AND (BalanceOfMaterialsBalance.Warehouse, BalanceOfMaterialsBalance.Material) IN

|   (SELECT

|    ServicesMaterialsAndServices.Warehouse,

|    ServicesMaterialsAndServices.MaterialOrService

|   FROM

|    Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

|   WHERE

|    ServicesMaterialsAndServices.Ref = &Ref

|    AND ServicesMaterialsAndServices.MaterialOrService.MaterialOrService =

|    &MaterialOrService);

 

Query.SetParameter(“Ref”, ThisObject.Ref);

Query.SetParameter(“MaterialOrService”, Enums.MaterialOrService.Material);

 

//4. Execute the query

QueryResult = Query.Execute();

SelectionDetailRecords = QueryResult.Select();

 

//5. If the result is not empty, cancel the document’s posting

If SelectionDetailRecords.Count() = 0 Then

Return;

EndIf;

Cancel = True;

 

//6. divpare the error message and display it.

MessageText =

“There is not enough materials. See the list of deficits below:” +

MessageText;

While SelectionDetailRecords.Next() Do

MessageText =

MessageText + Chars.CR + Chars.LF +

SelectionDetailRecords.Warehouse.Description + “\” +

SelectionDetailRecords.Material.Description + “: “ +

SelectionDetailRecords.QuantityBalance;

EndDo;

Message(MessageText);

 

EndProcedure

1C:Enterprise Ders 3-3

JOIN komutu ile Birikim Kayıt Tablosunu Filtreleme

Birikim kayıt tablosunu filtrelemek için bir sonraki seçenek JOIN komutu kullanılıyor. Şimdi biz bunu öğrenmeden önce nasıl çalıştığını görelim.

JOIN ile ilgili temel bilgiler

JOIN komutu ile ilgili temel bilgileri öğrenmeye başlayalım. Öncelikle Depo (Warehouse) kart listesine adres özniteliğini ekleyelim:

Ve bu öznitelik alanını kullanıcı ortamında dolduralım:

Şimdi biz bu adres alanının Malzeme toplamları dinamik listesinde göstermek istiyoruz:

İşte çalışma planı:

Biz şu an Birikim kayıt tablosundaki kayıtlar arasında döngü oluşturarak her bir depo için benzersiz olan depo numarasını kullanarak arama yapabiliriz. Daha sonra sonuç kümesindeki deponun adresini ek bir sütunda okuyabiliriz.

Süper, JOIN komutunun yaptığı iş tam olarak bu. Burada temel JOIN komutu kullanım örneğini görebiliriz:

SELECT <fields list>

FROM <Table1>

[LEFT | RIGHT] [INNER | OUTER] JOIN <Table2> ON <join condition>

WHERE <filter conditions>

­

Şimdi Birikim kayıt tablosundaki kayıtlar için depo bilgisini alabileceğimiz sorgu cümlesi aşağıda verilmiştir:

SELECT

Balance.Material,

Balance.Warehouse,

Balance.QuantityBalance,

Warehouses.Address

FROM

AccumulationRegister.BalanceOfMaterials.Balance AS Balance

LEFT JOIN Catalog.Warehouses AS Warehouses

ON Balance.Warehouse = Warehouses.Ref

­

Hadi deneyelim.

Bu birleştirme işi en basit örnek oldu. Fakat JOIN komutunun anlaşılması için uygun bir örnek. Sonuç olarak Tablo 1 (Birikim kayıt tablosu) deki her bir değer için Tablo 2 (Depo kart listesi) de tam eşleşen bir kayıt var. Eğer Tablo 2 de hiç eşleşme olmazsa ne olur? Biz ekstra depolardan birini silelim. Bu durumda ortaya çıkan sonuç kümesi nasıl gözükür?

Şimdi JOIN komutunun bağlanma şekillerini inceleyelim INNER ve OUTER.

INNER ve OUTER JOIN farklılıkları

INNER ve OUTER JOIN komutları JOIN ile birleştirilecek iki tablonun tüm kayıtları tamamen eşlemediği zamanlarda kullanılır. Örneğin Tablo 1’deki tüm kayıtların Tablo 2’deki kayıtların birinde bile karşılığı bulunmadığı durumda INNER veya OUTER JOIN komutlarını kullanmak gerekmektedir. Bu komutlar sayesinde karşılığı olmayan kayıt sonuç kümesinin genel görünümü bozmayacaktır. INNER ve OUTER arasındaki farklara birazdan değineceğiz.

OUTER JOIN komutu Tablo 1’deki kayıtlardan Tablo 2 de karşılığı olmayanların satırdaki yerlerine NULL yazacaktır:

NOT: Yani bunu dıştan yapılan bir bağlantı olarak görebiliriz. Dıştaki tablonun kayıt sayısı önemlidir ve o kayıt sayısı içerideki tablonun kayıt sayısından az olduğunda içerideki tablonun satırlarındaki karşılığı olmayan yerlere NULL yazacaktır.

INNER JOIN komutu ise karşılığı olmayan kayıtları yok sayar:

Şimdi bir örnek üzerinde görelim.

Not, eğer biz bir ekstra depo verisini değiştirirsek ve kaydedilmemiş ancak doldurulmuş belgeyi tekrar açtığımızda kayıtlarda OUTER JOIN kullandığımız için eski kaydı görürüz. Yani INNER ve OUTER JOIN komutları Tablo 1’deki her kayıt için Tablo 2 de bir karşılık bulunduğu durumda genellikle aynı sonucu verir. Yani iki tablo arasında birebir ilişki olduğu durumlarda INNER ve OUTER JOIN komutları arasında bir farklılık yoktur.

Peki, Tablo 1’deki bir kayıt için Tablo 2 de birden fazla kayıt varsa, bu durumda ne olacak? Böyle bir durumda Tablo 1’deki bir kayıt için Tablo 2’deki birden fazla değer döndürülerek sonuç kümesi tekrarlanarak büyüyecek.

1C:Enterprise Ders 3-4

LEFT ve RIGHT JOIN

INNER JOIN komutu ON koşuluna uymayan sağdaki soldaki tablolardaki tüm kayıtları filtreler. Biz burada soldaki tablodaki bir kayıt için sağdaki tablodaki herhangi bir kayıt yoksa bunu filtrelemek istiyoruz. Başka bir yol – eğer sağdaki tablodaki kayıtların soldaki tabloda bir karşılığı yoksa bu kayıtları otomatik olarak filtrelenecektir. Bu bağlamda, INNER JOIN komutu simetriktir. INNER JOIN komutu şu şekilde yazılabilir:

SELECT … FROM Table1 INNER JOIN Table2 ON …

Veya

SELECT … FROM Table2 INNER JOIN Table1 ON …

Eğer yukarıdaki iki yazımda da aynı koşul kullanılırsa iki yazım da aynı sonuç kümesini verecektir. Bu nedenle INNER JOIN komutu kullanılırken LEFT veya RIGHT komutlarını eklemeye gerek yoktur. Lütfen unutmayın, INNER JOIN komutu JOIN komutu için varsayılan bir tür, bu yüzden INNER JOIN komutunu yok sayabilirsiniz.

Ancak OUTER JOIN komutu için durum böyle değil, Elimizde iki adet kart listesi olduğunu varsayalım:

Bu sorgu cümlesi

SELECT C1.Field1, C2.Field1

FROM Catalog.Catalog1 AS C1

LEFT JOIN Catalog.Catalog2 AS C2

ON C1.Field1 = C2.Field1

­

Bu sonuç kümesini döndürecektir:

Görüldüğü gibi bu sorgu cümlesi Kart Listesi 2 de karşılığı olmayan kayıtları da listeledi. Karl-t Listesi 1 deki kayıtlardan Kart Listesi 2 de karşılığı olmayanların Kart Listesi 2 deki alan yerine NULL yazıldı.

Peki biz sorgu içerisinde kart listelerinin yerini değiştirerek aynı sorguyu çalıştırdığımızda yine aynı sonucu elde edebilir miyiz? Sorgu cümlesini şu şekilde değiştirelim:

SELECT C1.Field1, C2.Field1

FROM Catalog.Catalog2 AS C2

LEFT JOIN Catalog.Catalog1 AS C1

ON C1.Field1 = C2.Field1

­

Sonuç kümesinin farklı olduğunu görüyoruz:

Biz şu an sonuç kümesi içindeki bir kaydı nasıl kaybettik? Harika, bu sorgu kart listesi 1 ve kart listesi 2 de çift eşleşen, iki tabloda da birbirinin karşılığı olan, kayıtları arar. Bu nedenle sonuç kümesinde 4 – NULL gibi bir kayıt görünmemektedir. Bu sorguda sonuç kümesini oluşturmak için kullanılan ana tablo kart listesi 2 değildi.

Sonuç olarak OUTER JOIN simetrik değildir. Tablodaki bağlantı yerine göre JOIN komutunun verdiği sonuçlar farklı olabilmektedir. Bu yüzden LEFT ve RIGHT komutlarına ihtiyacımız vardır. Bu komutlar ile tablolardaki tüm kayıtları veya sadece eşleşen kayıtları alabiliriz.

LEFT OUTER JOIN komutu kullanmak demek sol tablodaki tüm kayıtları seç ve her bir kayıt için sağ tabloda karşılığı olan bir değer var mı kontrol et. RIGHT OUTER JOIN komutu kullanmak demek sağ tablodaki tüm kayıtları seç ve her bir kayıt için sol tabloda karşılığı olan bir değer var mı kontrol et.
Unutmayın, OUTER komutunu yok sayabilirsiniz.

Tabi bunu söylemeye gerek yok ama sağ ve sol tablolardaki anahtar kelimeler tamamen değişebilir. O zaman bizimde sorguyu değiştirmemiz gerekecektir. Diğer bir değişle, Table1 LEFT JOIN Table2 ile Table2 RIGHT JOIN Table1 tamamen aynı sonucu vermektedir.

JOIN Türleri (devam)

Şimdi JOIN komutu ile ilgili öğrendiklerimizi özetleyelim.

Çoklu JOIN komutları

Bir sorgu cümlesi içinde birden fazla JOIN komutu kullanabiliriz. MaterialsAndServices kart listesi ile Depo kart listesi aynı birikim kayıt tablosuna kayıt yaptığı için birikim kayıt tablosunu her iki kart listesine JOIN komutu kullanarak bağlayabiliriz:

SELECT * FROM

AccumulationRegister.BalanceOfMaterials.Balance AS Balance

LEFT JOIN Catalog.Warehouses AS Warehouses

ON Balance.Warehouse = Warehouses.Ref

LEFT JOIN Catalog.MaterialsAndServices AS Materials

ON Balance.Material = Materials.Ref

­

Veya biz tüm depoları seçip MaterialsAndServices kart listesinin tablo özniteliklerine Hizmetler belgesinde bağlayabiliriz:

SELECT * FROM

Catalog.Warehouses AS Warehouses

LEFT JOIN Document.Services.MaterialsAndServices AS Material

ON (Material.Warehouse = Warehouses.Ref)

LEFT JOIN Catalog.MaterialsAndServices AS MaterialsAndServices

ON (Material.MaterialOrService = MaterialsAndServices.Ref)

­

WHERE ve JOIN koşulları

Biz Hizmetler belgesinde MaterialsAndServices kart listesinin tablo bölümündeki tüm malzeme ve hizmetleri seçebiliriz. Eğer sorgu cümlesini aşağıdaki gibi yazarsak:

SELECT * FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

LEFT JOIN Catalog.MaterialsAndServices AS MaterialsAndServices

ON ServicesMaterialsAndServices.MaterialOrService = MaterialsAndServices.Ref

­

Şu an biz tablodaki tüm kayıtları almış olduk ama bu kayıtlar içerisinde ihtiyacımız olmayan kayıtlarda var. Bu kayıtlardan kurtulmak için şu koşulu sorgu cümlemize ekleyelim:

MaterialsAndServices.MaterialOrService = VALUE (Enum.MaterialOrService. Material).

VALUE anahtar kelimesi kart listesinde önceden tanımlı olan bir değer olabilir veya bir enum (sayım) değeri olabilir ve sorgu içerisinde direk olarak kullanılabilir. Başka bir kullanım şekli ise parametredir (&) ve Query.SetParameter(, ) şeklinde sorgu cümlesine parametre olarak eklenebilir.

Bir soru daha var. Biz koşulu nereye eklemeliyiz? JOIN komutu içerisine mi yoksa WHERE komutu içerisine mi?

Hadi görelim.

Sadece kullandığımız sorgu cümleleri burada. Sorgu cümlesine WHERE komutu eklersek:

SELECT

MaterialsAndServices.Description,

ServicesMaterialsAndServices.Quantity

FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

LEFT JOIN Catalog.MaterialsAndServices AS MaterialsAndServices

ON ServicesMaterialsAndServices.MaterialOrService = MaterialsAndServices.Ref

WHERE

MaterialsAndServices.MaterialOrService = VALUE(Enum.MaterialOrService.Material

­

Sorgu cümlesinin içine INNER JOIN filtresi eklersek:

SELECT

MaterialsAndServices.Description,

ServicesMaterialsAndServices.Quantity

FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

INNER JOIN Catalog.MaterialsAndServices AS MaterialsAndServices

ON ServicesMaterialsAndServices.MaterialOrService = MaterialsAndServices.Ref AND

MaterialsAndServices.MaterialOrService = VALUE(Enum.MaterialOrService.Material

­

Cevaplamamız için bir soru daha eğer WHERE komutu ile INNER JOIN filtresi kullanmak aynı sonucu veriyorsa, hangi yöntemi kullanmak daha iyi? Evet, çoğu durumda iki kullanım şekli arasında performans farklılığı olmamaktadır ancak bir tablo için diğer bir tabloya filtreleme yapılacağı zaman JOIN ile filtreleme yapılmasını tercih etmelisiniz. Bu daha doğal bir seçimdir ve bazı durumlarda uygulama hızını daha da arttırabilmektedir.

1C sorgu cümlesi içinde gizli JOIN komutu

Kullandığımız son sorguya tekrar göz atalım.

Yukarıda kullanılan sorgu cümlesi:

SELECT

ServicesMaterialsAndServices.Quantity,

ServicesMaterialsAndServices.MaterialOrService.Description,

ServicesMaterialsAndServices.MaterialOrService.Parent.Description

FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

­

Yani, Platform başka tabloları JOIN komutu ile bağlamadan o tablolardan alanları alabilir mi? Evet, çok basit: aslında Platform genelde JOIN komutunu kullanır ama bunu bize göstermez. Sorgu önce DBMS (Veritabanı Yönetim Sistemi) üzerinde çalışacak, Platform sorguyu saf bir SQL forma dönüştürecektir ve sonucunda DBMS tarafında anlaşılamayan her şeyden kurtulmuş olacaktır. (DBMS tablo adları ile 1C meta veri nesnelerin isimlerini değiştirme gibi). Bu işlem sırasında Platform eş tablolardaki noktalar LEFT OUTER JOINS ile bağlantı noktaları oluşturulmuş olacaktır.

Bu yüzden, bu nokta sözdizimini klasik SQL sorgu dilinin 1C sorgu dili uzantısı olarak düşünebiliriz. Bu anlatım yeni işlemler tanıtmak değil ama sorgu metnini daha kısa ve şeffaf hale getirme yöntemidir.

Not, bu nokta sözdizimi ve klasik JOIN komutu kullanımı arasında hiçbir fark olmadığını unutmayın. Aşağıdaki bu sorgu da yukarıdaki ile aynı sonuca ulaşmak için kullanılır ancak biraz daha uzundur:

SELECT

ServicesMaterialsAndServices.Quantity,

MaterialsAndServices.Description,

MaterialsAndServices1.Description AS Description1

FROM

Document.Services.MaterialsAndServices AS ServicesMaterialsAndServices

LEFT JOIN Catalog.MaterialsAndServices AS MaterialsAndServices

ON ServicesMaterialsAndServices.MaterialOrService = MaterialsAndServices.Ref

LEFT JOIN Catalog.MaterialsAndServices AS MaterialsAndServices1

ON MaterialsAndServices1.Ref = MaterialsAndServices.Parent

­

Not, biz yukarıdaki sorguda Catalog.MaterialsAndServices kataloğunun Description kısmını almak için ilk defa iki kez LEFT JOIN komutu kullandık.

Yani, ihtiyacımız olan meta veri sayısı kadar nesne kullanabiliriz.

JOIN komutu kullanarak Bakiye sorgulama

Şimdi JOIN filtresi kullanarak bakiye sorgu işlemi yapalım.

Veri almak için kullanacağımız iki tablo var:

  • – BalanceOfMaterials. Balance AS BalanceTable
  • – Services. MaterialsAndServices AS TabularSection

Ve filtrelemek için 5 tane koşul:

  • – Ref = &Ref
  • – MaterialOrService = &Material
  • – QuantityBalance <0
  • – Material = TabularSection.MaterialOrService
  • – Warehouse = TabularSection.Warehouse

Biz hangi JOIN komutunu kullanmalıyız RIGHT veya LEFT? Tabloları hangi sırada kullanmalıyız? BalanceTable JOIN TabularSection veya TabularSection JOIN BalanceTable? Koşulları nasıl ve nerede kullanmalıyız – hangi koşulları WHERE komutu içinde ve hangi koşulları JOIN komutunun ON kısmı içinde?

Örnek olarak aşağıdaki verileri kullanalım ve ihtiyacımız olan veriye ulaşmak için adım adım düşünerek sorgumuzu oluşturalım:

Temel algoritma şöyledir:

1. Ana tablo seçimi

Sorgunun FROM kısmında bulunan tabloya “Main” (Ana) tablo diyelim. Elbette, SQL sözdizimi açısından bir sorguda ana tablo diye bir şey yoktur. Biz “BalanceTable JOIN TabularSection” veya “TabularSection JOIN BalanceTable” şeklinde yazabiliriz ve eğer her şeyi doğru yaptıysak her iki yazımında sonucu aynı olacaktır.

Yani, ana tablo seçimi kolaylık sağlar. Benim zevkime göre, TabularSection BalanceTable a göre daha anlamlı olduğu için ben onu kullanacağım.

İlk adımda elde edilen sorgu bu şekildedir:

SELECT

TabularSection.Warehouse AS Warehouse,

TabularSection.MaterialOrService AS Material

FROM

Document.Services.MaterialsAndServices AS TabularSection

­

Sonuç şu şekilde olacaktır:

2. Bağımsız koşullara göre ana tablo filtreleme

Eğer koşullar listesine bir göz atacak olursak, iki farklı koşul tipi olduğunu göreceğiz:

  • – Bağımsız – alanları kendi değerlerine göre filtrelemek için:
    •      – Ref = &Ref
    •      – MaterialOrService = &Material
    •      – QuantityBalance < 0
  • – Bağımlı – alanları başka tablo değerlerine göre filtrelemek için:
    •      – Material = TabularSection.MaterialOrService
    •      – Warehouse = TabularSection.Warehouse

Bu adımda WHERE komutu için tüm bağımsız koşulları eklememiz gerekir:

SELECT

TabularSection.Warehouse AS Warehouse,

TabularSection.MaterialOrService AS Material

FROM

Document.Services.MaterialsAndServices AS TabularSection

WHERE

TabularSection.Ref = &Ref

AND TabularSection.MaterialOrService = &Material

­

Ve şimdi sonucu görelim:

3. JOIN komutu tipi seçimi

Eğer ana tabloda arama yapmak için ek bilgiye sahip değilsek <main table> LEFT JOIN kullanmamız gerekir. Ana tablomuzu başka bir tablo ile filtreleme yapacaksak <main table> INNER JOIN kullanmamız gerekir.

Bu nedenle, bizim burada INNER JOIN kullanmamız gerekiyor.

4. JOIN komutunun ON kısmında ana tabloyu filtrelemek için bağımlı koşul kullanma

Şimdi ON kısmına bağımlı koşullarımızı ekleyelim:

SELECT

TabularSection.Warehouse AS Warehouse,

TabularSection.MaterialOrService AS Material,

BalanceTable.QuantityBalance AS QuantityBalance

FROM

Document.Services.MaterialsAndServices AS TabularSection

INNER JOIN AccumulationRegister.BalanceOfMaterials.Balance AS BalanceTable

ON (BalanceTable.Material = TabularSection.MaterialOrService)

AND (BalanceTable.Warehouse = TabularSection.Warehouse)

WHERE

TabularSection.Ref = &Ref

AND TabularSection.MaterialOrService = &Material

­

Not, JOIN komutunu ekledikten sonra şimdi bu eklediğimiz tabloyu SELECT listesi içinde kullanalım “BalanceTable.QuantityBalance”. Diğer bir not, biz birden fazla eş koşul kullanacağımız zaman, her tablo için ON kısmının aşağıdaki gibi yazılması gerekir.

SELECTFROM <main table>

JOIN <table1> ON <table1 dependent conditions>

JOIN <table2> ON <table2 dependent conditions>

­

Bu adım sonrasında oluşacak sonuç kümesi:

SELECT

TabularSection.Warehouse AS Warehouse,

TabularSection.MaterialOrService AS Material,

BalanceTable.QuantityBalance AS QuantityBalance

FROM

Document.Services.MaterialsAndServices AS TabularSection

INNER JOIN AccumulationRegister.BalanceOfMaterials.Balance AS BalanceTable

ON (BalanceTable.Material = TabularSection.MaterialOrService)

AND (BalanceTable.Warehouse = TabularSection.Warehouse)

WHERE

TabularSection.Ref = &Ref

AND TabularSection.MaterialOrService = &Material

AND BalanceTable.QuantityBalance < 0

­

5. WHERE komutu altına bağlı tablo için bağımsız koşul eklemek

Soldan bir bağımsız koşula sahibiz. Bu koşulu WHERE komutu altına ekleyelim:

Ve son olarak elde ettiğimiz sonuç:

1C:Enterprise Ders 3-5

Sanal tablo parametrelerini kullanarak bakiye sorgulama

Daha önce Platformun birikim kayıt tablosundan her an sorgulama yapmak için bize izin verdiğini söylemiştik. Peki, bu Birikim kayıt tablosunda her an için veri olduğu anlamına gelmektedir? Tabiki hayır, Eğer böyle olsaydı depolamak ve arama yapmak için çok fazla veri olacaktır. Peki, nasıl çalışıyor?

Birikim kayıt tablosu verilerini saklayan iki fiziksel tablo var:

  • – Ana tablo: Orijinal haliyle kaydedilen tüm kayıtları depolayan bir tablodur. (Toplama yapılmadan)
  • – Birikim kayıt tablosu: Birikim boyutlarını göre toplanan kayıtlarını depolayan bir tablodur.

Bazı malzeme ve depolar için tablo içeriklerini örnek olarak şöyle alalım:

Eğer malzemenin ilk bakiyesinin 0 olduğunu varsayarsak, şu anki bakiye 0 + 20- 5- 1- 10 + 20- 10- 1 = 13 olurdu. Bu cari bakiye direkt olarak Birikim kayıt tablosundan elde edilebilir. Her an için ara bakiye kayıtları yoktur ancak her iki tabloyu kullanılarak bunları hesaplayabiliriz.

Örneğin, 2015-05-01 gece yarısı bakiye 13 + 1 + 10- 20 = 4 olacak. (Eğer biz bunu geriye dönük kayıtlara bakarak hesaplarsak) veya (biz bunu ilk kaydı ileriye dönük kullanarak hesaplarsak) 0 + 20- 5- 1- 10 = 4 olur.

Hesaplamayı hızlandırmak için, aylık orta bakiye kayıt toplamları ayarlanabilir. Böylece kayıt tablosundan bu veri kolayca alınabilir. Birikim kayıt tablosunda aylık bakiyeler varsa, belirli bir süre için bakiye en yakın aylık bakiye değerinden itibaren hesaplanacaktır.

Şimdi, herhangi bir zaman noktası için bakiye değerini elde etmek için kullandığınız bir sorgu cümlesi düşünün. Bu gerçekten büyük, karmaşık ve okunamaz bir şey olurdu. Platform bu karmaşıklığı sanal tablolar oluşturarak gizler ve işlemleri kolaylaştırır. BalanceOfMaterials kayıt tablosundan herhangi bir &DateTime için bakiye almak için basit bir sorgu kullanılabilir:

SELECT

BalanceTable.Material,

BalanceTable.Warehouse,

BalanceTable.QuantityBalance

FROM

AccumulationRegister.BalanceOfMaterials.Balance(&DateTime) AS BalanceTable

­

“AccumulationRegister.BalanceOfMaterials. Balance(&DateTime)” herhangi bir anda fiziksel bir tablo gibi bakiyeleri içeren sanal bir tablodur. DBMS (Veritabanı Yönetim Sistemi) ne sorguyu göndermeden önce, Platform bakiye hesaplamak için sorguyu yeniden yazar.

Burada, sorgu yapılandırıcısı açılıp hem sanal hem de gerçek tabloları görebilirsiniz (sanal tablolar kırmızı renkte):

Not, biz burada form parametresi olarak zamanı anını gönderdik. Farklı sanal tablolar farklı parametre listeleri içerir. Aşağıda gösterilen butona basarak sorgu için eklediğiniz tabloya ait tüm parametreleri görebilirsiniz:

Burada bizim Birikim kayıt tablomuzun iki tane parametresi vardır.

  • – Period – parametreye ait andaki değeri verir. Eğer parametre atlanırsa ya da yok sayılırsa son hesaplanan bakiye değerini verir.
  • – Condition – ek koşul (isteğe bağlı).

Unutmayın, ek koşul eklerken sanal tablonun bazı parametreleri kullanılabilir. Mevcut alanların listesini almak için, üç nokta butonuna basın. Alacağınız görüntü budur:

Görüldüğü gibi, ek koşul için kullanılabilecek iki tane sanal tablo parametresi görülmektedir. QuantityBalance hiç alan olmadığı için, ek koşul olarak kullanılamaz. Ancak ek koşullar sanal tablonun arkasındaki fiziksel tablolar için kullanılamaz çünkü bu koşullar sadece sanal tablo için hesaplanmaktadır. Bu nedenle, gerçek fiziksel tablolardaki boyutları fiziksel tablo koşulu olarak kullanabiliriz. Ancak bu boyutlar sanal tablolarda öncelikle hesaplandığı için ek koşul olarak ta kullanılabilir.

Tamam. Şimdi, bakiye kontrolü yapmak için sanal tabloyu nasıl kullanabiliriz? Koşulları nerede kullanmalıyız – sanal tablo ek koşulu olarak mı yoksa WHERE komutu içerisinde mi?

Burada ana kural şudur: tüm koşulların sanal tablo parametreleri içinde olması zorunludur. Eğer sanal tablo parametrelerinin kullanmanın hiçbir yolu yoksa bir sanal tabloyu filtrelemek için WHERE komutu içinde sanal tablo parametrelerini kullanabilirsiniz. Bu kurala uyulmazsa ciddi performans sorunları ile karşılaşılabilirsiniz.

Yani, bu şekilde doğru sonuçları verir ancak sanal tablo parametreleri kullanılarak yeniden yazılması gereken soruya bir örnek verelim:

SELECT

BalanceTable.Material,

BalanceTable.Warehouse,

BalanceTable.QuantityBalance

FROM

AccumulationRegister.BalanceOfMaterials.Balance AS BalanceTable

WHERE

BalanceTable.Material = &Material

­

Ve bu düzenlenmiş sorgu da aynı sonucu verir:

SELECT

BalanceTable.Material,

BalanceTable.Warehouse,

BalanceTable.QuantityBalance

FROM

AccumulationRegister.BalanceOfMaterials.Balance(, Material = &Material) AS BalanceTable

­

Şimdi, sanal tablo parametreleri kullanarak bakiye sorgulaması yapmaya hazırız:

SELECT

BalanceTable.Material,

BalanceTable.Warehouse,

BalanceTable.QuantityBalance AS QuantityBalance

FROM

AccumulationRegister.BalanceOfMaterials.Balance(

, (Material, Warehouse) IN (

SELECT

Document.Services.MaterialsAndServices.MaterialOrService,

Document.Services.MaterialsAndServices.Warehouse

FROM

Document.Services.MaterialsAndServices

WHERE

Document.Services.MaterialsAndServices.Ref = &Ref AND

Document.Services.MaterialsAndServices.MaterialOrService.MaterialOrService = &Material)

) AS BalanceTable

WHERE

BalanceTable.QuantityBalance < 0

­

Not, burada aynı tanıdık sözdizimini (<exp1>, <exp2>,) IN (SELECT <exp1>, <exp2>…) kullandık – Ama bu sefer sanal tablo parametreleri WHERE komutu içerisinde değil.

En iyi bakiye sorgusu seçme

Biz bu derste negatif bakiye olup olmadığını sorgulamak için 3 farklı yöntem öğrendik.

  • – WHERE;
  • JOIN;
  • – Sanal tablo parameteleri

Hangisini tercih etmeliyiz? Eğer sanal tablo kullanırsak tüm parametreler için tüm koşulları eklemeliyiz. İlk iki sorgu cümlesi içinde sanal tablo kullandık ve tüm koşulları WHERE komutu içine veya JOIN komutunun ON kısmı içine eklemek zorunda kaldık.

Bu nedenle, burada en iyi seçim son sorgu cümlesi olacaktır. Ve evrak kaydedilirken yapılacak işlemlerin son hali aşağıdadır.

Procedure Posting(Cancel, Mode)

 

// 1. Filling out BalanceOfMaterials recordset

RegisterRecords.BalanceOfMaterials.Write = True;

For Each CurRowMaterialsAndServices In MaterialsAndServices Do

If CurRowMaterialsAndServices.MaterialOrService.MaterialOrService =

Enums.MaterialOrService.Service Then Continue;

EndIf;

Record = RegisterRecords.BalanceOfMaterials.Add();

Record.RecordType = AccumulationRecordType.Expense;

Record.Period = Date;

Record.Material = CurRowMaterialsAndServices.MaterialOrService;

Record.Warehouse = CurRowMaterialsAndServices.Warehouse;

Record.Quantity = CurRowMaterialsAndServices.Quantity;

EndDo;

 

//2. Writing down BalanceOfMaterials recordset

RegisterRecords.BalanceOfMaterials.LockForUpdate = True;

RegisterRecords.Write();

 

//3. Checking if there any negative balance records

Query = New Query;

Query.Text =

“SELECT

| BalanceTable.Material,

| BalanceTable.Warehouse,

| BalanceTable.QuantityBalance AS QuantityBalance

|FROM

| AccumulationRegister.BalanceOfMaterials.Balance(

|   ,

|   (Material, Warehouse) IN

|    (SELECT

|     Document.Services.MaterialsAndServices.MaterialOrService,

|     Document.Services.MaterialsAndServices.Warehouse

|    FROM

|     Document.Services.MaterialsAndServices

|    WHERE

|     Document.Services.MaterialsAndServices.Ref = &Ref

|     AND Document.Services.MaterialsAndServices.MaterialOrService.MaterialOrService =

|     &Material)) AS BalanceTable

|WHERE

| BalanceTable.QuantityBalance < 0″;

 

Query.SetParameter(“Ref”, ThisObject.Ref);

Query.SetParameter(“Material”, Enums.MaterialOrService.Material);

 

//4. Execute the query

QueryResult = Query.Execute();

SelectionDetailRecords = QueryResult.Select();

 

//5. If the result is not empty, cancel the document’s posting

If SelectionDetailRecords.Count() = 0 Then

Return;

EndIf;

Cancel = True;

 

//6. divpare the error message and display it.

MessageText =

“There is not enough materials. See the list of deficits below:” +

MessageText;

While SelectionDetailRecords.Next() Do

MessageText =

MessageText + Chars.CR + Chars.LF +

SelectionDetailRecords.Warehouse.Description + “\” +

SelectionDetailRecords.Material.Description + “: “ +

SelectionDetailRecords.QuantityBalance;

EndDo;

Message(MessageText);

 

EndProcedure

­