Mann kann auch das nutzen. Habe selber codiert.
/*
Artikel mit Lagerbestand,
die entweder nie verkauft wurden
oder deren letzter Verkauf vor @DatumVerkauf liegt,
und deren erster Lagerzugang vor @DatumLager liegt.
Mit aktuellem Lagerplatz (aus vWarenlagerPlatzArtikel + tWarenLagerPlatz).
JTL-Wawi 1.10.x
*/
DECLARE @DatumVerkauf DATE = '2025-03-01'; -- Grenze für Letzter Verkauf (hier manuell Datum einsetzen)
DECLARE @DatumLager DATE = '2025-01-01'; -- Grenze für Erster Lagerzugang (hier manuell Datum einsetzen)
WITH CTE_Bestand AS (
SELECT
we.kArtikel,
MIN(TRY_CONVERT(DATE,we.dErstellt)) AS ErsteLagerung, -- ältester Lagerzugang
SUM(we.fAnzahl - ISNULL(wo.fAnzahl,0)) AS AktuellerBestand
FROM dbo.tWarenLagerEingang AS we
LEFT JOIN (
SELECT
kWarenLagerEingang,
SUM(fAnzahl) AS fAnzahl
FROM dbo.tWarenLagerAusgang
GROUP BY kWarenLagerEingang
) AS wo ON we.kWarenLagerEingang = wo.kWarenLagerEingang
WHERE TRY_CONVERT(DATE,we.dErstellt) IS NOT NULL
AND TRY_CONVERT(DATE,we.dErstellt) <= GETDATE() -- keine zukünftigen Daten
GROUP BY we.kArtikel
),
CTE_LetzterVerkauf AS (
SELECT
ap.kArtikel,
MAX(TRY_CONVERT(DATE,a.dErstellt)) AS LetzterVerkauf
FROM Verkauf.tAuftragPosition AS ap
JOIN Verkauf.tAuftrag AS a ON ap.kAuftrag = a.kAuftrag
WHERE TRY_CONVERT(DATE,a.dErstellt) IS NOT NULL
GROUP BY ap.kArtikel
),
-- aktueller Lagerplatz mit Bestand > 0 (aus vWarenlagerPlatzArtikel + tWarenLagerPlatz)
CTE_AktuellerLagerplatz AS (
SELECT
v.kArtikel,
lp.cName AS Lagerplatz,
ROW_NUMBER() OVER(PARTITION BY v.kArtikel ORDER BY v.fAnzahl DESC) AS rn
FROM dbo.vWarenlagerPlatzArtikel AS v
JOIN dbo.tWarenLagerPlatz AS lp ON v.kWarenLagerPlatz = lp.kWarenLagerPlatz
WHERE v.fAnzahl > 0
)
SELECT
a.cArtNr AS [Artikelnummer],
ab.cName AS [Artikelbezeichnung],
CAST(s.AktuellerBestand AS int) AS [Bestand],
s.ErsteLagerung AS [Erster Lagerzugang],
ISNULL(CONVERT(varchar(10),v2.LetzterVerkauf,104),'Nie verkauft') AS [Letzter Verkauf],
al.Lagerplatz AS [Aktueller Lagerplatz]
FROM dbo.tArtikel AS a
JOIN dbo.tSpracheUsed AS sp
ON sp.nStandard = 1
JOIN dbo.tArtikelBeschreibung AS ab
ON a.kArtikel = ab.kArtikel
AND ab.kSprache = sp.kSprache
AND ab.kPlattform = 1
JOIN CTE_Bestand AS s
ON a.kArtikel = s.kArtikel
LEFT JOIN CTE_LetzterVerkauf AS v2
ON a.kArtikel = v2.kArtikel
LEFT JOIN CTE_AktuellerLagerplatz AS al
ON a.kArtikel = al.kArtikel AND al.rn = 1 -- nur der erste Lagerplatz (höchster Bestand)
WHERE
s.AktuellerBestand > 0 -- Bestand vorhanden
AND (v2.LetzterVerkauf IS NULL OR v2.LetzterVerkauf < @DatumVerkauf) -- nie verkauft ODER letzter Verkauf vor @DatumVerkauf
AND s.ErsteLagerung < @DatumLager -- Lagerzugang vor @DatumLager
ORDER BY v2.LetzterVerkauf;