Erp Asistanı Erp Asistanı
Netsis SQL

Netsis Hareketsiz Stok Raporu: Satmayan Ürünleri SQL ile Bulun

7 dk okuma Erp Asistanı
Netsis Hareketsiz Stok Raporu: Satmayan Ürünleri SQL ile Bulun

Eldeki stoğun sağlıklı yönetimi, hangi ürünlerin "ölü" durumda olduğunu bilmekle başlar. Netsis'te son N aydır herhangi bir hareket (giriş/çıkış, fatura, irsaliye, transfer vb.) görmemiş stokları tespit etmek için TBLSTHAR tablosu üzerinde çalışan, tekrar kullanılabilir bir SQL raporuna ihtiyaç duyarsınız. Bu yazıda, tam olarak bu raporu kuracak sorguyu adım adım paylaşıyor, sık yapılan hataları ve sık sorulan soruları ele alıyoruz. Önce Netsis tablo yapısı ve stok hareketleri temellerine göz atabilirsiniz.

Hareketsiz stok raporunun mantığı

Temel yaklaşım basittir: TBLSTSABIT stok kartlarını, TBLSTHAR stok hareketleriyle ilişkilendirip belirlediğiniz son N ay içinde hareket kaydı olmayanları listelemek. TBLSTHAR, Netsis'teki tüm stok hareketlerini (alış, satış, transfer, açılış, üretim vb.) tutar. NOT EXISTS veya LEFT JOIN ... IS NULL ile son N ayda tarih filtresine takılan hareketi bulunmayan stok kodlarını yakalarsınız.

STHAR_FTIRSIP filtresi koymazsanız sorgu, satış olsun alış olsun fark etmeksizin hiç hareket görmemiş ürünleri getirir. Eğer yalnız satış hareketlerini baz almak isterseniz STHAR_FTIRSIP IN ('1','3') gibi bir ek filtre eklemeniz gerekir. Aşağıdaki ana sorguda genel hareketsizlik yaklaşımını kullanıyor, varsayılan olarak tüm hareket türlerini değerlendiriyoruz.

Ana sorgu: son N ayda hareketsiz ürünler, güncel bakiye ve son hareket tarihi

Aşağıdaki sorgu, @Months parametresiyle kaç ay geriye bakılacağını belirler. Çıktıda stok kodu, stok adı, güncel eldeki miktar (tüm hareketlerin G-C toplamı), son hareket tarihi ve hareketsiz kalınan gün sayısı yer alır.

Parametre Açıklama
@Months Geriye dönük ay sayısı (ör: 6)
@SubeKodu Çok şubede filtre için şube kodu (genelde 0)
DECLARE @Months INT = 6;          -- son 6 ay
DECLARE @SubeKodu SMALLINT = 0;  -- tek şube varsayılan

SELECT 
    s.STOK_KODU,
    s.STOK_ADI,
    ISNULL(sn.bakiye, 0) AS [Güncel Stok Bakiyesi],
    sn.son_hareket_tarihi AS [Son Hareket Tarihi],
    DATEDIFF(DAY, sn.son_hareket_tarihi, GETDATE()) AS [Hareketsiz Gün]
FROM TBLSTSABIT s
OUTER APPLY (
    SELECT 
        SUM(CASE WHEN h.STHAR_GCKOD = 'G' THEN h.STHAR_GCMIK
                 WHEN h.STHAR_GCKOD = 'C' THEN -h.STHAR_GCMIK
                 ELSE 0 END) AS bakiye,
        MAX(h.STHAR_TARIH) AS son_hareket_tarihi
    FROM TBLSTHAR h
    WHERE h.STOK_KODU = s.STOK_KODU
      AND h.SUBE_KODU = @SubeKodu
) sn
WHERE NOT EXISTS (
    SELECT 1 FROM TBLSTHAR h2
    WHERE h2.STOK_KODU = s.STOK_KODU
      AND h2.STHAR_TARIH >= DATEADD(MONTH, -@Months, GETDATE())
      AND h2.SUBE_KODU = @SubeKodu
)
ORDER BY sn.bakiye DESC;

OUTER APPLY içindeki toplama, stoğun tüm geçmiş hareketlerini hesaba katarak güncel bakiyeyi ve son hareket tarihini getirir. NOT EXISTS ise son N ay içinde herhangi bir hareketi olan stokları eler. Sonuç, hareket görmeyen stokları, elde kalan miktarı ve en son ne zaman hareket ettiğini gösterir.

Önemli: SUBE_KODU filtresi, çok şubeli ortamlarda her şube için ayrı hareketsizlik raporu alabilmenizi sağlar. Tek şubede genellikle 0 veya 1'dir; veritabanınızda SELECT DISTINCT SUBE_KODU FROM TBLSTHAR ile kontrol edebilirsiniz.

Hareketsiz stokları daha detaylı analiz etme

Yalnızca satış hareketlerine göre hareketsizlik

Eğer "sadece satış yapılmayan, ama alım yapılan ürünler" gibi özel bir kırılım istiyorsanız, NOT EXISTS alt sorgusuna STHAR_FTIRSIP filtresi ekleyebilirsiniz:

-- Sadece satış/irsaliye tipinde son 6 ay hareketi olmayanlar
DECLARE @Months INT = 6, @SubeKodu SMALLINT = 0;
SELECT 
    s.STOK_KODU,
    s.STOK_ADI,
    sn.bakiye,
    sn.son_hareket_tarihi
FROM TBLSTSABIT s
OUTER APPLY (
    SELECT 
        SUM(CASE WHEN h.STHAR_GCKOD = 'G' THEN h.STHAR_GCMIK ELSE -h.STHAR_GCMIK END) AS bakiye,
        MAX(h.STHAR_TARIH) AS son_hareket_tarihi
    FROM TBLSTHAR h
    WHERE h.STOK_KODU = s.STOK_KODU AND h.SUBE_KODU = @SubeKodu
) sn
WHERE NOT EXISTS (
    SELECT 1 FROM TBLSTHAR h2
    WHERE h2.STOK_KODU = s.STOK_KODU
      AND h2.STHAR_FTIRSIP IN ('1','3')   -- satış faturası ve satış irsaliyesi
      AND h2.STHAR_TARIH >= DATEADD(MONTH, -@Months, GETDATE())
      AND h2.SUBE_KODU = @SubeKodu
)
ORDER BY sn.bakiye DESC;

Depo bazında hareketsizlik

Deponun TBLSTHAR içindeki DEPO_KODU alanından yararlanabilirsiniz. OUTER APPLY içindeki toplamda h.DEPO_KODU = @DepoKodu filtresi ekleyerek yalnızca o depodaki bakiyeyi görür, NOT EXISTS alt sorgusunda da aynı depo için hareket kontrolü yaparsınız.

-- Belirli bir depoda son 6 ay hareket görmeyenler
DECLARE @Months INT = 6, @SubeKodu SMALLINT = 0, @DepoKodu SMALLINT = 1;
SELECT 
    s.STOK_KODU,
    s.STOK_ADI,
    ISNULL(depo.bakiye, 0) AS [Depo Bakiyesi],
    depo.son_hareket_tarihi
FROM TBLSTSABIT s
OUTER APPLY (
    SELECT 
        SUM(CASE WHEN h.STHAR_GCKOD = 'G' THEN h.STHAR_GCMIK ELSE -h.STHAR_GCMIK END) AS bakiye,
        MAX(h.STHAR_TARIH) AS son_hareket_tarihi
    FROM TBLSTHAR h
    WHERE h.STOK_KODU = s.STOK_KODU
      AND h.SUBE_KODU = @SubeKodu
      AND h.DEPO_KODU = @DepoKodu
) depo
WHERE NOT EXISTS (
    SELECT 1 FROM TBLSTHAR h2
    WHERE h2.STOK_KODU = s.STOK_KODU
      AND h2.DEPO_KODU = @DepoKodu
      AND h2.STHAR_TARIH >= DATEADD(MONTH, -@Months, GETDATE())
      AND h2.SUBE_KODU = @SubeKodu
)
ORDER BY depo.bakiye DESC;

Sık yapılan hatalar

  • SUBE_KODU filtresini unutmak: Çok şubeli veritabanında yanlış bakiye ve hareket sayısı alırsınız. Sorguların başında SET @SubeKodu ile değişkeni tanımlayıp tüm JOIN/WHERE bloklarında kullanın.
  • STHAR_GCKOD yönünü ters kullanmak: 'G' giriş, 'C' çıkıştır; net miktar = girişler - çıkışlar. Sadece SUM(STHAR_GCMIK) yazılırsa giriş ve çıkış aynı yönde toplanır, bakiye yanlış olur.
  • Son hareket tarihini alırken MAX kullanırken sadece son N aylık veriye bakmak: Oysa biz tüm tarih aralığını istiyoruz; bu yüzden OUTER APPLY içinde tarih filtresi yok.
  • NOT EXISTS kısmında tarih filtresini >= yerine > yapmak: >= DATEADD(MONTH, -@Months, GETDATE()) son N aylık sınırı doğru kapsar; > bir günü kaybetmenize yol açabilir.
  • Güncel bakiye ile hareketsizlik dönemini karıştırmak: Stoğun bakiyesi pozitif olmasına rağmen uzun süre hareketsiz olabilir. Hareketsizlik raporu sırf bakiyeye bakarak yapılamaz; hareket tarihleri esastır.

Sık sorulanlar

Sorgu neden bazı stokları hareketsiz göstermiyor?
Son N ay içinde iptal edilen bir hareket veya transfer gibi gözden kaçan bir kayıt, NOT EXISTS koşulunu bozar. Netsis'te TBLSTHAR tablosunda doğrudan bir iptal sütunu yoktur; ancak negatif giriş/çıkışla iptal simüle edilebilir. Böyle durumlarda stok hareketsiz görünmeyebilir; dilerseniz STHAR_HTUR gibi ek filtrelerle denetim yapın.

Sadece satış hareketsizliğini nasıl raporlarım?
Yukarıdaki ikinci örnekte olduğu gibi NOT EXISTS alt sorgusuna STHAR_FTIRSIP IN ('1','3') ekleyerek yalnızca satış faturası ve satış irsaliyesi tipindeki hareketleri baz alabilirsiniz. Bu durumda alım veya transfer hareketleri hareketsizlik sayılmaz.

Çok şubede çalışıyorum, tek sorguda tüm şubelerin hareketsiz stoklarını nasıl alırım?
Her şube için ayrı geçiş yaparak sorguyu çalıştırabilir ya da OUTER APPLY ve NOT EXISTS içine SUBE_KODU = s.SUBE_KODU gibi bir eşleme koyarak stok kartının bağlı olduğu şubeyi referans alabilirsiniz. Ancak stok kartı tablosu TBLSTSABIT'te SUBE_KODU şube stoğunu değil, kartın ait olduğu şubeyi gösterir (genelde tüm şubeler ortak kullanıyorsa 0); bu yüzden en sağlıklısı raporu şube bazında ayrı ayrı almaktır.

Güncel bakiyeyi neden TBLSTHAR'dan hesaplıyoruz, stok kartında hazır bakiye yok mu?
Netsis stok kartı (TBLSTSABIT) tanım tablosudur; anlık stok miktarını tutmaz. Stok miktarı yalnızca TBLSTHAR'daki giriş/çıkışların toplamından elde edilir. Bu nedenle bakiyeyi mutlaka hareket tablosu üzerinden hesaplamak gerekir.


Bu sorgularla hareketsiz stoklarınızı düzenli olarak izleyebilirsiniz. Daha karmaşık ihtiyaçlarınızda (örneğin stok grubu, marka bazında raporlama) Erp Asistanı'nda doğal dille sorgu yazarak anında SQL alabilirsiniz.

Ücretsiz üye olun, istediğiniz sorguyu doğal dille alın →

Netsis'te 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. Kredi kartı gerekmez.