Erp Asistanı Erp Asistanı
SAP SQL

SAP Business One Hazır SQL Sorguları: Kopyala-Çalıştır 10 Örnek

SAP Business One için en çok aranan 10 hazır SQL: aktif müşteriler, depo bazında stok, aylık net satış, en çok satanlar, açık faturalar, bekleyen siparişler ve temsilci cirosu. Hepsi gerçek SAP B1 veritabanında test edildi.

Erp Asistanı Erp Asistanı Editör ekibi 9 dk okuma
SAP Business One Hazır SQL Sorguları: Kopyala-Çalıştır 10 Örnek

SAP Business One'ın kendi rapor ekranları çoğu ihtiyacı karşılar; ama veriyi Excel'e, bir panoya ya da başka bir sisteme almak istediğinizde iş SQL'e düşer. Bu yazıda en çok aranan 10 SAP Business One raporunun hazır SQL karşılığını bulacaksınız: aktif müşteriler, depo bazında stok, aylık net satış, en çok satan ürünler, müşteri bazında ciro, açık faturalar, bekleyen siparişler, temsilci performansı, fiyat listesi ve tahsilatlar. Sorguların hepsi SAP'nin resmi Türkiye demo şirketinde (SAP Business One 10.0, SQL Server) çalıştırılarak test edildi; kopyalayıp kendi şirket veritabanınızda çalıştırabilirsiniz.

Başlamadan önce: dört kural

Bu dört kural sorguların neden öyle yazıldığını açıklar. Kendi sorgunuzu yazarken de aynısını uygulayın:

Kural Neden
Her belge sorgusunda CANCELED = 'N' İptal edilen belge ile onu ters çeviren belge birlikte toplanmasın
Net satış = OINV eksi ORIN Alacak dekontu (satış iadesi faturası) satıştan düşülür; irsaliye (ODLN) toplama eklenmez
JOIN'ler DocEntry ve CardCode / ItemCode ile DocNum numara serisine göre tekrar edebilir
Türkçe metin N'...' ile SAP'nin demo şirketinin collation'ında ş, ğ, İ yoktur; öneksiz literal sessizce bozulur

Tablo adlarının ne anlama geldiğini merak ediyorsanız önce SAP Business One tablo yapısı rehberine bakın.

1. Aktif müşteri listesi

SELECT c.CardCode   AS CariKod,
       c.CardName   AS CariAd,
       g.GroupName  AS CariGrubu,
       c.LicTradNum AS VergiNo,
       c.City       AS Sehir,
       c.Phone1     AS Telefon,
       c.E_Mail     AS EPosta
FROM OCRD c
LEFT JOIN OCRG g ON g.GroupCode = c.GroupCode
WHERE c.CardType = 'C'        -- C müşteri, S tedarikçi, L aday
  AND c.frozenFor = 'N'       -- pasif kartlar hariç
ORDER BY c.CardName;

Tedarikçi listesi için CardType = 'S' yazmanız yeterli. Türkiye kurulumlarında vergi numarası ve TC kimlik numarası LicTradNum kolonunda durur.

2. Stok listesi ve toplam eldeki miktar

SELECT i.ItemCode    AS StokKod,
       i.ItemName    AS StokAd,
       b.ItmsGrpNam  AS StokGrubu,
       i.InvntryUom  AS Birim,
       i.OnHand      AS Eldeki,
       i.IsCommited  AS SipariseAyrilan,
       i.OnOrder     AS Beklenen
FROM OITM i
LEFT JOIN OITB b ON b.ItmsGrpCod = i.ItmsGrpCod
WHERE i.InvntItem = 'Y'       -- stoklu kalem (hizmet kartları hariç)
  AND i.frozenFor = 'N'
ORDER BY i.ItemCode;

3. Depo bazında stok ve kullanılabilir miktar

SELECT w.ItemCode                          AS StokKod,
       i.ItemName                          AS StokAd,
       w.WhsCode                           AS Depo,
       w.OnHand                            AS Eldeki,
       w.OnHand - w.IsCommited + w.OnOrder AS Kullanilabilir,
       w.MinStock                          AS MinimumStok
FROM OITW w
JOIN OITM i ON i.ItemCode = w.ItemCode
WHERE i.InvntItem = 'Y'
  AND w.WhsCode = '01'        -- depo kodu metindir: '01', 1 değil
ORDER BY w.OnHand DESC;

Bütün depoları görmek için WhsCode filtresini kaldırın. Minimum stok tanımlı kalemlerde kritik seviyeyi bulmak için AND w.MinStock > 0 AND w.OnHand < w.MinStock ekleyin.

4. Aylık net satış (KDV hariç, iadeler düşülmüş)

SELECT Yil, Ay, SUM(Tutar) AS NetSatisKdvHaric
FROM (
    SELECT YEAR(DocDate) AS Yil, MONTH(DocDate) AS Ay, DocTotal - VatSum AS Tutar
    FROM OINV
    WHERE CANCELED = 'N'
    UNION ALL
    SELECT YEAR(DocDate), MONTH(DocDate), -(DocTotal - VatSum)
    FROM ORIN
    WHERE CANCELED = 'N'
) s
WHERE Yil >= YEAR(GETDATE()) - 1
GROUP BY Yil, Ay
ORDER BY Yil, Ay;

DocTotal KDV dahil belge toplamıdır; DocTotal - VatSum belge altı indirim düşülmüş KDV hariç tutarı verir. Tutarlar yerel para birimindedir; dövizli faturanın döviz tutarı DocTotalFC kolonundadır.

5. En çok satan 10 ürün (son 12 ay)

SELECT TOP 10
       s.ItemCode           AS StokKod,
       i.ItemName           AS StokAd,
       SUM(s.Miktar)        AS NetSatilanMiktar,
       SUM(s.Tutar)         AS NetTutar
FROM (
    SELECT l.ItemCode, l.Quantity AS Miktar, l.LineTotal AS Tutar
    FROM INV1 l
    JOIN OINV f ON f.DocEntry = l.DocEntry
    WHERE f.CANCELED = 'N' AND f.DocDate >= DATEADD(MONTH, -12, CAST(GETDATE() AS date))
    UNION ALL
    SELECT l.ItemCode, -l.Quantity, -l.LineTotal
    FROM RIN1 l
    JOIN ORIN r ON r.DocEntry = l.DocEntry
    WHERE r.CANCELED = 'N' AND r.DocDate >= DATEADD(MONTH, -12, CAST(GETDATE() AS date))
) s
JOIN OITM i ON i.ItemCode = s.ItemCode
GROUP BY s.ItemCode, i.ItemName
ORDER BY NetSatilanMiktar DESC;

Ürün adını belge satırından (Dscription) değil karttan (OITM.ItemName) alıyoruz: satırdaki açıklama belgede elle değiştirilmiş olabilir ve aynı ürün raporda iki ayrı satıra bölünür.

6. Müşteri bazında ciro (bu yıl, ilk 10)

SELECT TOP 10
       s.CardCode     AS CariKod,
       c.CardName     AS CariAd,
       SUM(s.Tutar)   AS NetCiroKdvHaric
FROM (
    SELECT CardCode, DocTotal - VatSum AS Tutar
    FROM OINV
    WHERE CANCELED = 'N' AND DocDate >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1)
    UNION ALL
    SELECT CardCode, -(DocTotal - VatSum)
    FROM ORIN
    WHERE CANCELED = 'N' AND DocDate >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1)
) s
JOIN OCRD c ON c.CardCode = s.CardCode
GROUP BY s.CardCode, c.CardName
ORDER BY NetCiroKdvHaric DESC;

7. Ödenmemiş (açık) satış faturaları

SELECT f.DocNum                                         AS FaturaNo,
       f.CardCode                                       AS CariKod,
       c.CardName                                       AS CariAd,
       f.DocDate                                        AS Tarih,
       f.DocDueDate                                     AS Vade,
       f.DocTotal                                       AS FaturaTutari,
       f.PaidToDate                                     AS Odenen,
       f.DocTotal - f.PaidToDate                        AS Kalan,
       DATEDIFF(DAY, f.DocDueDate, CAST(GETDATE() AS date)) AS GecikmeGunu
FROM OINV f
JOIN OCRD c ON c.CardCode = f.CardCode
WHERE f.CANCELED = 'N'
  AND f.DocStatus = 'O'       -- O açık, C kapalı (tamamen ödenmiş)
ORDER BY GecikmeGunu DESC;

GecikmeGunu negatifse fatura henüz vadesine gelmemiştir. Yaşlandırma kovaları (0-30, 31-60, 61-90, 90+) ve yevmiyeden bakiye hesabı için SAP Business One cari bakiye ve yaşlandırma SQL yazısına bakın.

8. Bekleyen (açık) satış siparişleri

SELECT o.DocNum      AS SiparisNo,
       o.DocDate     AS SiparisTarihi,
       o.CardCode    AS CariKod,
       c.CardName    AS CariAd,
       l.ItemCode    AS StokKod,
       l.Quantity    AS SiparisMiktari,
       l.OpenQty     AS KalanMiktar,
       l.ShipDate    AS TeslimTarihi
FROM ORDR o
JOIN RDR1 l ON l.DocEntry = o.DocEntry
JOIN OCRD c ON c.CardCode = o.CardCode
WHERE o.CANCELED = 'N'
  AND l.LineStatus = 'O'
  AND l.OpenQty > 0
ORDER BY l.ShipDate, o.DocNum;

Kısmen sevk edilmiş satırda OpenQty yalnız kalan miktarı gösterir. Söz verilen tarihi geçmiş siparişler için AND l.ShipDate < CAST(GETDATE() AS date) ekleyin.

9. Satış temsilcisi bazında ciro (bu yıl)

SELECT s.SlpName                 AS Temsilci,
       COUNT(*)                  AS FaturaSayisi,
       SUM(f.DocTotal - f.VatSum) AS CiroKdvHaric
FROM OINV f
JOIN OSLP s ON s.SlpCode = f.SlpCode
WHERE f.CANCELED = 'N'
  AND f.DocDate >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1)
GROUP BY s.SlpName
ORDER BY CiroKdvHaric DESC;

SlpCode = -1 "temsilci yok" kaydıdır; temsilcisiz faturaları ayrı görmek istemiyorsanız AND f.SlpCode <> -1 ekleyin. Bu sorgu iadeleri düşmez; iade düşülmüş temsilci cirosu için 6. sorgudaki UNION ALL kalıbını SlpCode ile kurun.

10. Fiyat listesine göre ürün fiyatları

SELECT i.ItemCode   AS StokKod,
       i.ItemName   AS StokAd,
       p.ListName   AS FiyatListesi,
       f.Price      AS Fiyat,
       f.Currency   AS ParaBirimi
FROM ITM1 f
JOIN OITM i ON i.ItemCode = f.ItemCode
JOIN OPLN p ON p.ListNum = f.PriceList
WHERE i.SellItem = 'Y'
  AND i.frozenFor = 'N'
  AND f.PriceList = 1          -- kendi fiyat listenizin numarası (OPLN.ListNum)
ORDER BY i.ItemCode;

Fiyat listelerinizi SELECT ListNum, ListName, IsGrossPrc FROM OPLN ile görebilirsiniz. IsGrossPrc = 'N' olan listede fiyatlar KDV hariçtir.

Bonus: son 30 günün tahsilatları

SELECT r.DocNum                                 AS TahsilatNo,
       r.DocDate                                AS Tarih,
       r.CardCode                               AS CariKod,
       c.CardName                               AS CariAd,
       r.CashSum                                AS Nakit,
       r.TrsfrSum                               AS Havale,
       r.CheckSum                               AS Cek,
       r.CreditSum                              AS KrediKarti,
       r.CashSum + r.TrsfrSum + r.CheckSum + r.CreditSum AS Toplam
FROM ORCT r
JOIN OCRD c ON c.CardCode = r.CardCode
WHERE r.Canceled = 'N'
  AND r.DocDate >= DATEADD(DAY, -30, CAST(GETDATE() AS date))
ORDER BY r.DocDate DESC;

Tahsilat tablosunda iptal kolonu CANCELED değil Canceled olarak yazılır (SQL Server'da varsayılan olarak büyük/küçük harf fark etmez, ama kolonun adını doğru bilmek kodu okunur kılar).

Sık yapılan hatalar

  • İrsaliye ile faturayı birlikte toplamak: fatura irsaliyeden kopyalandıysa satış iki kez sayılır. Ciro faturadan (OINV - ORIN) alınır.
  • DocTotal'ı KDV hariç sanmak: DocTotal KDV dahildir. KDV hariç tutar DocTotal - VatSum ya da satır toplamı (LineTotal) ile alınır.
  • Depo koduna sayı yazmak: WhsCode = 1 sorgusu '01' deposunu bulmaz.
  • Türkçe aramayı N öneksiz yazmak: LIKE '%Şahin%' hata vermez, boş ya da yanlış sonuç döner. LIKE N'%Şahin%' yazın.
  • Pasif kartları listeye almak: dondurulmuş (pasif) cari ve stok kartlarında frozenFor = 'Y' olur.

Sık sorulanlar

Bu sorgular SAP Business One'ın hangi sürümünde çalışır? Sorgular SAP Business One 10.0'ın SQL Server sürümünde test edildi. Kullanılan tablolar (OINV, OCRD, OITM, OITW, ORDR, ORCT) uzun yıllardır aynı adla duruyor; 9.x sürümlerinde de büyük ölçüde aynen çalışır. HANA sürümünde ise tarih fonksiyonları (DATEADD, DATEFROMPARTS) farklıdır ve tablo/kolon adları çift tırnakla yazılır; bu sorgular orada uyarlanmadan çalışmaz.

SQL'i nerede çalıştırmalıyım? SQL Server Management Studio'da, SAP Business One şirketinizin veritabanı seçiliyken çalıştırın. Bu sorguların hepsi yalnız okuma yapar. SAP Business One veritabanına doğrudan INSERT, UPDATE ya da DELETE yazmayın; SAP veri yazmayı yalnız kendi arayüzü, DI API ve Service Layer üzerinden destekler.

Sorguyu SAP içindeki Sorgu Yöneticisi'nde kullanabilir miyim? Evet, SELECT sorgularını Sorgu Yöneticisi'ne (Query Manager) kaydedebilirsiniz. DECLARE ile değişken tanımlanan sorgularda değişkeni sabit değerle değiştirmeniz ya da SAP'nin [%0] parametre sözdizimini kullanmanız gerekir.

Ciro raporum SAP ekranındaki rakamla tutmuyor, neden? En sık üç sebep: iadelerin (ORIN) düşülmemesi, KDV dahil (DocTotal) ile KDV hariç tutarın karıştırılması ve iptal belgelerin (CANCELED) filtrelenmemesi. Ayrıca SAP raporları belge tarihi (DocDate) yerine vergi tarihine (TaxDate) göre filtrelenmiş olabilir.


Her rapor için sorgu uyarlamakla uğraşmak istemiyorsanız sorunuzu Türkçe yazın: Erp Asistanı SAP Business One şemanıza uygun, doğrulanmış SQL'i saniyeler içinde üretir. Nasıl çalıştığını SQL Üretme rehberinde görebilirsiniz.

Ücretsiz üye olun, SAP sorgunuzu doğal dille üretin →

Bu yazıyı paylaş
Konuşarak raporlayın

SAP Business One'da SQL ve raporu konuşarak alın

Türkçe sorunuzu yazın, şemanıza uygun çalışan SQL'i ya da hazır uygulamanızı saniyeler içinde alın.