items are repeated in SAP B1 query - sapb1

Below query is giving me correct output on quantity (but have to add quantities of repeated styles) but item code and item description is repeated. i want to see one time code having Total PO qty and what in stock.
Can you please advise what's wrong with this query.
Thanks
Shahzad Ahmed enter image description here
SELECT
T1.[ItemCode],
T1.[Dscription],
sum(T1.[Quantity]) as 'PO QTY',
T3.[OnHand]
FROM
ORDR T0 INNER JOIN RDR1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
INNER JOIN OITW T3 ON T2.[ItemCode] = T3.[ItemCode]
WHERE
T0.[CardCode] = 'c00192' and
T0.[NumAtCard] Like '818276%%' and
T3.[WhsCode] = '161'
GROUP BY T1.[ItemCode], T1.[Dscription], T1.[Quantity], T3.[OnHand]

You just need to remove T1.[Quantity] from your GROUP BY. You should read on how to use a Group by, but to summarize, when you're calling a group by, you're asking to look for rows with the same values in some columns.
For exemple, here you want to add the quantities of every row with the same ItemCode, Dscription, OnHand, but you're asking to also look for rows with the same Quantity here.
Here is a good article on GROUP BY

Related

SQL query: SUM(Quantity)

I'm trying to build a simple SQL query for an item availability check. My aim is to query the items whose total/summed quantity exceeds the stock level. This is what my table (simplified example) looks like:
LineNumber
Item
Quantity
StockQuantity
1
Banana
1
1
2
Apple
1
1
3
Strawberry
1
1
4
Banana
1
1
I have tried it with the following query, but it doesn't work:
SELECT
T1.[LineNumber], T1.[Item],
SUM(T1.[Quantity]), T1.[Stockquantity]
FROM
Table T1
WHERE
T1.[Quantity] > T1.[Stockquantity]
GROUP BY
T1.[LineNumber], T1.[Item], T1.[Quantity], T1.[Stockquantity]
Does anyone have any advice or tips for me on how I should do this query so that the total/summed quantities per line are compared with the stock quantity and not just the individual/single quantities per line with the stock quantity?
Thank you very much for your help in advance.
Given your extended information in this post: https://stackoverflow.com/a/71452446/1690217 the query you are looking for is this:
WITH TotalsLookup as (
SELECT T1.[VisOrder] as [VisOrder], T1.[U_position] as [ItemGroup-LineNumber]
, T0.[DocNum] as [DocNumber], T2.[InvntItem], T1.[ItemCode] as [Itemcode]
, T1.[Quantity], T1.[OpenCreQty] as [openQuantity]
, T2.[OnHand] as [StockQuantity]
, SUM(T1.[Quantity]) OVER (PARTITION BY T1.[ItemCode] ORDER BY T1.[VisOrder]) AS RunningTotal
FROM OQUT T0
INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
)
SELECT VisOrder, [ItemGroup-LineNumber], DocNumber, Itemcode, Quantity, openQuantity, StockQuantity, RunningTotal
FROM TotalsLookup
WHERE DocNumber = '332050' AND [InvntItem] = 'Y' AND RunningTotal > StockQuantity
Original Post
Your example is possibly oversimplified, If StockQuantity is the result of a lookup into an inventory, so that in the example we can say the following:
Total stock on Hand of Bananas is 1
And then if you are expecting LineNumber 4 to be picked up because this line will make the SUM of Bananas greater than the total stock on hand of Bananas... then you need a Running Total of the Item records in this list:
WITH TotalsLookup as (
SELECT
T1.[LineNumber], T1.[Item],
T1.[Quantity], T1.[StockQuantity],
SUM (T1.[Quantity]) OVER (PARTITION BY Item ORDER BY LineNumber) AS RunningTotal
FROM
[Table] T1
)
SELECT *
FROM TotalsLookup
WHERE RunningTotal > StockQuantity;
LineNumber
Item
Quantity
Stockquantity
RunningTotal
4
Banana
1
1
2
See this Fiddle that covers a few variants of this query and will give you a playground to practice: http://sqlfiddle.com/#!18/a95bb/2
The origin of StockQuantity can itself have a significant impact on the performance and other query options that might be viable, I call this out so that you can be mindful of this when you apply this logic into your application domain, if StockQuantity is not a static value, but is itself an aggregate then that may impact how the comparison should be performed.
You can refer to aggregates of a GROUP BY in the having clause
SELECT
T1.[Item],
SUM(T1.[Quantity]) As TotalQuantity,
MAX(T1.[Stockquantity]) AS StockLevel
FROM
Table T1
GROUP BY
T1.[Item]
HAVING
SUM(T1.[Quantity]) > MAX(T1.[Stockquantity])
This assumes that the Stockquantity is the same for all occurrences of a product.
The WHERE clause is executed before grouping, the HAVING clause after grouping.
If you need the line numbers, then you can use the STRING_AGG aggregate function to join the line numbers into a single string per group
SELECT STRING_AGG(T1.[LineNumber], ', ') As LineNumbers, ...
your SQL modified code(SQL code didn't work) that does not provide a single output
SELECT linenumber,
a.item,
quantity,
SumQuantity,
stockquantity
FROM table A
JOIN(SELECT item,
Sum(quantity) SumQuantity,
max(stockquantity) stockquantity
FROM table C
GROUP BY item) B
ON A.item = B.item
WHERE SumQuantity> stockquantity
ouput
linenumber
item
quantity
quantity2
stockquantity
1
Banana
1
2
1
4
Banana
1
2
1
However I use the follwing query
SELECT String_agg(linenumber, ',') LineNumbers,
a.item,
quantity,
SumQuantity,
stockquantity
FROM table A
JOIN(SELECT item,
Sum(quantity) SumQuantity
max(stockquantity) stockquantity
FROM table C
GROUP BY item) B
ON A.item = B.item
WHERE SumQuantity> stockquantity
GROUP BY a.item,
quantity,
SumQuantity,
stockquantity
that bring following result
LineNumbers
Item
Quantity
SumQuantity
StockQuantity
1,4
Banana
1
2
1
Thank you all for your effort and suggestions for solutions. I have tried to incorporate them all. A few of them worked. With others I still have a few problems:
#Chris Schaller
I like you solution a lot! But in my non-simplified, real SQL code, there are item groups that the PARTITION function cannot cope with. My result with your solution is therefore as follows.
However, I will continue to work on it. Thanks!
WITH TotalsLookup as (
SELECT T1.[VisOrder] as 'VisOrder', T1.[U_position] as 'ItemGroup-LineNumber', T0.[DocNum] as 'DocNumber', T1.[ItemCode] as 'Itemcode', T1.[Quantity] as 'Quantity', T1.[OpenCreQty] as 'openQuantity', T2.[OnHand] as 'StockQuantity', SUM(T1.[Quantity]) OVER (PARTITION BY T1.[ItemCode] ORDER BY T1.[VisOrder]) AS RunningTotal
FROM OQUT T0
INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
WHERE T0.[DocNum] = '332050' AND T2.[InvntItem] = 'Y'
)
SELECT *
FROM TotalsLookup
WHERE RunningTotal > Quantity
Output: here
#RF1991
I have also tried to implement your solution, but it has not really worked so far. I am still looking for the mistake. Thanks for the help!
SELECT T1.[U_position], T1.[ItemCode], T1.[Quantity], T1.[OpenCreQty], T2.[OnHand]
FROM OQUT T0
INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry]
INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode]
JOIN(SELECT T1.[ItemCode], SUM(T1.[Quantity]) as 'SumQuantity', MAX(T2.[OnHand]) as 'Stockquantity' FROM OQUT T0 INNER JOIN QUT1 T1 ON T0.[DocEntry] = T1.[DocEntry] INNER JOIN OITM T2 ON T1.[ItemCode] = T2.[ItemCode] GROUP BY T1.[ItemCode]) B
ON T1.[ItemCode] = B.[ItemCode]
WHERE SumQuantity > stockquantity AND T0.[DocNum] = '332050' AND T2.[InvntItem] = 'Y'
#Oliver Jacot-Descombes
It works. Thank you very much!

Query to get the line with the latest date

SELECT T0.[ItemCode], T0.[PriceFOB], T0.[PriceAtWH], T0.[DocEntry], T0.[CardCode], T2.[DocDate], T3.[CardName] FROM IPF1 T0 LEFT JOIN OIPF T2 ON T2.[DocDate] = (SELECT MAX(T4.[DocDate]) FROM OIPF T4 WHERE T0.[DocEntry]=T4.[DocEntry]) INNER JOIN OCRD T3 ON T0.[CardCode] = T3.[CardCode] WHERE T3.[GroupCode] = '105'
I am using the following query listed above.
The issue rises where I have multiple lines of the same item listed but my goal is to get the one with the LATEST DocDate.
If someone can please help and explain what it is that I am doing wrong.
I have tried Order By, Group By but keep getting multiple errors (syntax mostly)
SELECT ItemCode, PriceAtWH, DocEntry, PriceFOB, CardCode FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY T0.[ItemCode] ORDER BY T0.[DocEntry] DESC) AS ROWNUM FROM IPF1 T0) IPF1 WHERE ROWNUM = 1
This is the other query that I was able to come close to my solution but I need it to filter for only GroupCode = '105' from OCRD matching the CardCode
The Main goal is to filter out a Master DATA which is combined with IPF1 and OCRD(Only need to pull Group Code from this) and to filter the IPF1 with the Group Code first. Then proceed to do the Max Date or Max DocEntry ID for each item.
You could use a distinct to get one row per event even if they have different dates and use the MAX on the select
SELECT distinct T0.[ItemCode],
T0.[PriceFOB],
T0.[PriceAtWH],
T0.[DocEntry],
T0.[CardCode],
T3.[CardName],
MAX(T2.[DocDate] ) DocDate
FROM IPF1 T0
LEFT JOIN OIPF T2
ON T0.[DocEntry]=T2.DocEntry]
INNER JOIN OCRD T3
ON T0.[CardCode] = T3.[CardCode]
WHERE T3.[GroupCode] = '105'
GROUP BY T0.[ItemCode], T0.[PriceFOB], T0.[PriceAtWH], T0.[DocEntry], T0.[CardCode],T3.[CardName]
WITH T AS (SELECT T10.[DocEntry], T10.[CardCode], T10.[ItemCode], T10.[PriceFOB], T10.[PriceAtWH] FROM IPF1 T10 INNER JOIN OCRD T11 ON T10.[CardCode] = T11.[CardCode] WHERE T11.[GroupCode] = '105')
SELECT T.[DocEntry], T.[CardCode], T.[ItemCode], T.[PriceFOB], T.[PriceAtWH] FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY T.[ItemCode] ORDER BY T.[DocEntry] DESC) AS ROWNUM FROM T) T WHERE ROWNUM = 1
So I ended up solving my own problem.
Thank you Julissa for trying buy your query has an error where you are missing a "[" in front of DocEntry and also the query does not do what I want it do, multiple instances of the same item for all date still show up. Thank you for trying!

Putting the results of a query into new table in SQL Server

I want to insert query results into new table is there any way I can make changes in code so that it gets stored in a table.
My query:
SELECT DISTINCT TOP 5 a.DocEntry
,b.TrgetEntry
,b.itemcode
,a.DocNum AS 'Order No.'
,a.CardCode
,a.CardName
,b.DocDate AS [Delivery No.]
,c.targettype AS 'Ctargettype'
,c.trgetentry AS 'Ctargetentry'
,c.itemcode AS 'c-itemcode'
,c.docentry AS 'Cdocentry' a.CancelDate
,a.Project
,a.DocStatus
,b.ObjType
,a.ObjType
FROM ORDR a
INNER JOIN rdr1 b ON a.DocEntry = b.DocEntry
LEFT JOIN dln1 c ON c.TrgetEntry = b.DocEntry
AND b.itemcode = c.ItemCode order by c.itemcode;
You can do it as it will create a new table and insert the records into that table. If you have already created table then you can give name and individual columns also for both insertion and selection.
SELECT *
INTO YourTableName
FROM (
SELECT DISTINCT TOP 5 a.DocEntry
,b.TrgetEntry
,b.itemcode
,a.DocNum AS 'Order No.'
,a.CardCode
,a.CardName
,b.DocDate AS [Delivery No.]
,c.targettype AS 'Ctargettype'
,c.trgetentry AS 'Ctargetentry'
,c.itemcode AS 'c-itemcode'
,c.docentry AS 'Cdocentry' a.CancelDate
,a.Project
,a.DocStatus
,b.ObjType
,a.ObjType
FROM ORDR a
INNER JOIN rdr1 b ON a.DocEntry = b.DocEntry
LEFT JOIN dln1 c ON c.TrgetEntry = b.DocEntry
AND b.itemcode = c.ItemCode
)
a
For using order by clause you can try something like this.
SELECT DISTINCT
Insured_Customers.FirstName, Insured_Customers.LastName,
Insured_Customers.YearlyIncome, Insured_Customers.MaritalStatus
INTO Fast_Customers from Insured_Customers INNER JOIN
(
SELECT * FROM CarSensor_Data where Speed > 35
) AS SensorD
ON Insured_Customers.CustomerKey = SensorD.CustomerKey
ORDER BY YearlyIncome;
You can learn in detail about INTO Clause Here
This looks like SQL Server code. In that database, you add into after the select clause:
Select distinct top 5 o.DocEntry, r.TrgetEntry, r.itemcode, o.DocNum as order_num, o.CardCode,
o.CardName, r.DocDate as delivery_num,
d.targettype as Ctargettype, d.trgetentry as Ctargetentry,
d.itemcode as c_itemcode, d.docentry as Cdocentry
a.CancelDate,a.Project, a.DocStatus,b.ObjType,a.ObjType
into <new table>
from ORDR o inner join
rdr1 r
On o.DocEntry = r.DocEntry left join
dln1 d
on d.TrgetEntry = r.DocEntry and
d.itemcode = r.ItemCode;
Note that I changed the table aliases so they are meaningful. Arbitrary letters are very hard to follow. Table abbreviations are more useful.
I also changed the column aliases so they do not need to be escaped. Do not make troublesome aliases!

What is the link in SAP Business One between Sales Orders, Deliveries, and Invoices

I'm trying to join ORDR, ODLN and OINV in a SAP Business One query, but I can't seem to find a field that they share in common.
There must be some record somewhere that links one to another.
Are they linked via a separate table? Or am I missing something obvious?
I am using SAP HANA as my DB, so queries in HANA are preferred rather than MSSQL.
First, credit to Eralper for their answer, as the link contained in it helped me find the solution I was looking for. However, their solution does not include an explanation and does not quite give the result that is being looked for.
The main information for a Sales Order in SAP is stored in two tables, ORDR and RDR1. ORDR has one line for each Sales Order, while RDR1 has one line for each product row on the Sales Order.
Delivery Notes and Invoices (and basically any document in SAP) follow this pattern.
Why is this important to this question? Because the column that contains the data to link Sales Orders, Delivery Notes and Invoices is in RDR1 (or the similar variant). It's name is TrgetEntry.
As there is a row for each product on a Sales Order, we can't simply do a join, as any Sales Order that has more than one product will appear multiple times in the result. The following query uses grouping to show a table that has a line for each Sales Order, and has the needed information to link it to Delivery Notes.
SELECT T0."DocEntry" AS "SO DE", T0."DocNum" AS "Sales Order Number", T1."TrgetEntry" AS "SO TE", COUNT(T0."DocNum") AS "Rows"
FROM ORDR T0
LEFT JOIN RDR1 T1 ON T0."DocEntry" = T1."DocEntry"
GROUP BY T0."DocEntry", T0."DocNum", T1."TrgetEntry"
By just changing the table names, similar queries can be created for Delivery Notes and Invoices.
Then you can use the TrgetEntry and DocEntry to link the various results.
The final code I use to show Sales Orders, their related Deliveries and Invoices is the following:
SELECT S0."SalesOrderNumber", S1."DeliveryNumber", S2."DocNum" AS "InvoiceNumber", S0."Rows", S2."DocTotal"
FROM (SELECT T0."DocEntry" AS "SO_DE", T0."DocNum" AS "SalesOrderNumber", T1."TrgetEntry" AS "SO_TE", COUNT(T0."DocNum") AS "Rows"
FROM ORDR T0
LEFT JOIN RDR1 T1 ON T0."DocEntry" = T1."DocEntry"
GROUP BY T0."DocEntry", T0."DocNum", T1."TrgetEntry") S0
LEFT JOIN (SELECT T0."DocEntry" AS "DN_DE", T0."DocNum" AS "DeliveryNumber", T1."TrgetEntry" AS "DN_TE"
FROM ODLN T0
LEFT JOIN DLN1 T1 ON T0."DocEntry" = T1."DocEntry"
GROUP BY T0."DocEntry", T0."DocNum", T1."TrgetEntry") S1 ON S0."SO_TE" = S1."DN_DE"
LEFT JOIN OINV S2 ON S1."DN_TE" = S2."DocEntry"
Please check https://archive.sap.com/discussions/thread/1440163
There following relationship is given
SELECT Distinct(T0.DocNum ),T0.DocDate, T0.CardCode, T0.CardName, T1.ItemCode, T1.Quantity, T1.Price,T1.TotalSumSy, T0.DocTotal
FROM ORDR T0
INNER JOIN RDR1 T1 ON T0.DocEntry = T1.DocEntry
INNER JOIN ODLN T2 ON T2.DocEntry = T1.TrgetEntry
INNER JOIN DLN1 T3 on T3.DocEntry = T2.Docentry
INNER JOIN OINV T4 ON T4.DocEntry = T3.TrgetEntry
INNER JOIN INV1 T5 ON T5.DocEntry = T4.DocEntry
LEFT JOIN ORDN T6 ON T6.DocEntry = T5.TrgetEntry
LEFT JOIN RDN1 T7 ON T7.DocEntry = T6.DocEntry
So following relation is also true
SELECT *
FROM ODLN T2
INNER JOIN DLN1 T3 on T3.DocEntry = T2.Docentry
INNER JOIN OINV T4 ON T4.DocEntry = T3.TrgetEntry

Can this SQL Server CTE be expressed with a "simpler" basic query?

So that I can union all or join it to a larger outer query of some kind?
-- Get purchase order due date for first purchase order after today which completes a cumulative sum satisfying demand which currently exceeds inventory supply
with cte as
(
select
t1.itemcode as itemcode,
t1.dscription as itemname,
t1.quantity as quantity,
(select sum(t6.quantity)
from por1 t6
inner join opor t7 on t6.docentry = t7.docentry
where t7.docduedate <= t2.docduedate
and t7.docduedate > getdate()
and t6.itemcode = 'item001') as totalqty,
t2.docduedate as eta
from
por1 t1
inner join
opor t2 on t1.docentry = t2.docentry
where
t1.itemcode = 'item001'
and t2.docduedate > getdate()
)
select
cte.itemcode, cte.itemname,
convert(char(10), min(cte.eta), 101)
from
cte
where
totalqty > 55 -- I don't want this to be literal, the outer join would supply this as a calculated value
group by
cte.itemcode, cte.itemname
Re the outer query (which isn't included above because I haven't been able to join an outer query to the cte - I don't know that you can), I'd like it to calculate the amount, currently shown as 55, from the outer query and control which itemcodes to return based on a filtered list from an outer query instead of choosing just one literal itemcode (as above), for example.
I made various attempts to get totalqty using a having clause with no success.
Thanks in advance for your help.
Do you want to get the result of what TotalQty is, or do you only want to use it as a condition?
If it's the former, I would say the CTE way is the best. Otherwise, I would reframe it as a WHERE EXISTS clause on the select going into TotalQty, like WHERE EXISTS (SELECT SUM(T6.Quantity) [...] HAVING SUM(T6.Quantity) > 55).