SQL query: SUM(Quantity) - sql

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!

Related

DISTINCT return same ID two times wrongly

This is my SQL query:
SELECT DISTINCT(ItemId), TCode, PartNumber,ModelNumber, ItemUOM
FROM #Results
This query returns:
ItemId TCode Source PartNumber ModelNumber ItemUOM
-----------------------------------------------------------------
1024 1000 NULL NULL EA
1024 1000 FLEX FLEX EA
#Result is a temp table I have used left join in that query
Why does SELECT DISTINCT return the same ItemID 1024 twice?
SELECT DISTCINT(I.ItemId),
(DENSE_RANK() OVER(ORDER BY I.ItemId ASC)) AS RowNumber,
(I.TCode), E.Name AS Source,
I.GoldenRecordNumber AS GoldenRecordNo, I.ItemCode AS MMRefNo,
I.ShortDescription AS ShortText, I.LongDescription AS POText,
Suppliers.Description AS Manufacturer, Suppliers.Name AS ManufacturerCode,
Suppliers.Abbreviation AS ManufacturerAbbr,
ItemSuppliers.ReferenceNo AS PartNumber, ItemSuppliers.ReferenceNo AS ModelNumber,
UOM.Name AS ItemUOM, MG.Name AS PSGC,
NM.Noun AS ClassName, NM.LongAbbrevation AS ClassDescription
INTO
#Results
FROM
Items I
LEFT JOIN
ItemSuppliers ON I.ItemId = ItemSuppliers.ItemsId
LEFT JOIN
Suppliers ON ItemSuppliers.ManufacturerId = Suppliers.SupplierId
LEFT JOIN
UnitOfMeasurement UOM ON UOM.UOMId = I.UOMId
LEFT JOIN
MaterialGroup MG ON MG.MaterialGroupId = I.MaterialGroupId
LEFT JOIN
NounModifiers NM ON NM.NounModifierId = I.NounModifierId
LEFT JOIN
AutoClass AC ON AC.ClassName = NM.Noun
LEFT JOIN
ERP E ON E.ERPId = I.ERPName
LEFT JOIN
NounModifierAttributes NMA ON NMA.NounModifierId =
NM.NounModifierId
LEFT JOIN
Attributes A ON A.AttributeId = NMA.AttributeId
LEFT JOIN
ItemAttributes IA ON IA.ItemId = I.ItemId
WHERE
(I.ItemCode LIKE '%'+'2001010088'+'%' )
SELECT 'Int' = COUNT(distinct(ItemId))
FROM #Results
WHERE (TCode IS NOT NULL OR MMRefNo IS NOT NULL)
SELECT DISTINCT(ItemId),
TCode, Source, GoldenRecordNo, MMRefNo, ShortText, POText,
Manufacturer, ManufacturerCode, ManufacturerAbbr, PartNumber, ModelNumber,
ItemUOM, PSGC, ClassName, ClassDescription
FROM
#Results
WHERE
(TCode IS NOT NULL OR MMRefNo IS NOT NULL)
AND RowNumber BETWEEN (1-1)*100 + 1 AND (((1-1) * 100 + 1) + 100) - 1
DROP TABLE #Results
if you are convinced the rows which are selected can be grouped together then it should work fine.
1. but if rows are having different data then distinct will not help.
2. use ltrim,rtrim to remove leading and trailing spaces.
example: distinct(ltrim(rtrim(ItemId)))
this will help if it due to spaces or for junk values
The behavior of DISTINCT works as expected. For instance, you could use GROUP BY clause to group them by ItemId, TCode to get top most records
SELECT
ItemId, TCode,
MAX(PartNumber) PartNumber, MAX(ModelNumber) ModelNumber,
MAX(ItemUOM), ...
FROM #Results
GROUP BY ItemId, TCode
In case any failure in GROUP BY clause use ranking function to assign the rank and get the record based on rank value.

SQL: How to find the MAX value/price of a particular item?

I am new to SQL and was wondering if anyone could guide me.
Here is my code and table output:
Code
Prices that are lower than 2.25 are appearing. I only want the 2.25 (highest) values.
I've tried removing the MAX in the select statement, removing the grouping,and replacing the WHERE statement with
WHERE Price = (
SELECT MAX(Price)
FROM tblPurchaseOrderLine
)
AND tblProduct.Description LIKE 'Alpine Small Pot'
buuut it gave no output.
SOLUTION:
SELECT tblPurchaseOrder.PONumber 'PO Number',
tblVendor.Name 'Vendor Name',
tblProduct.ProductID 'Product ID',
tblProduct.Description,
MAX(tblPurchaseOrderLine.Price)'Price'
FROM tblPurchaseOrder
INNER JOIN tblVendor
ON tblVendor.VendorID = tblPurchaseOrder.VendorID
INNER JOIN tblPurchaseOrderLine
ON tblPurchaseOrderLine.PONumber = tblPurchaseOrder.PONumber
INNER JOIN tblProduct
ON tblProduct.ProductID = tblPurchaseOrderLine.ProductID
WHERE Price = (SELECT MAX(Price)
FROM tblPurchaseOrderLine
WHERE tblProduct.ProductID = tblPurchaseOrderLine.ProductID)
AND tblProduct.Description LIKE 'Alpine Small Pot'
GROUP BY tblPurchaseOrder.PONumber,tblVendor.Name,tblProduct.ProductID,tblProduct.Description
Thank you! I got it working
What you want in your case is a correlated subquery:
from tblPurchaseOrderLine t1
WHERE Price = (
SELECT MAX(Price)
FROM tblPurchaseOrderLine t2
where t1.product_id = t2.product_id
)
AND tblProduct.Description LIKE 'Alpine Small Pot'
There is a better way to do this:
You can do this using TOP 1 with window function in order clause:
select top 1 with ties t.*
from your_table t
where tblProduct.Description LIKE 'Alpine Small Pot'
order by row_number() over (
partition by product_id
order by price desc
);

FIFO match first stock buys to first sells sql

I have data that looks like this:
Stock buys and sells
I need a query to apply the FIFO method to the Buys and Sells so I get a table that looks like this:
FIFO Buys and Sells
I want to be able to match the first buy/s to the first sells with buys on the left and sells on the right. If there is no sell then Nulls should be applied on the right and if there is no buy then nulls should be applied on the left. The brokerage transaction key can be used as the order in which the trades occurred. This is what I've tried so far. Any help would be much appreciated!
SELECT a.ACCT_ID, a.Trade_Date_Key, a.Brokerage_Transaction_Key, a.Buy_Sell_Code, a.Principal_Amt, a.Security_Quantity
, (a.Security_Quantity + b.Security_Quantity) CUMULATIVE_POSITION
, a.SHARE_PRICE
, (A.Principal_Amt + B.Principal_Amt) CUMULATIVE_VALUE
from #TRANSACTIONS_WITH_RANK a
left join #TRANSACTIONS_WITH_RANK b
on a.acct_id = b.acct_id and a.rank = b.rank + 1
ORDER BY BROKERAGE_TRANSACTION_KEY
In your question you mention matching the first buy(s) with the first sell(s), but your example output seems to ignore that part. Here's an example of how to do if you want to match the first buy(s) to first sell(s) based on the Acct_ID and Trade_Date
SELECT buy.*, sell.*
FROM #TRANSACTIONS_WITH_RANK buy
INNER JOIN (
SELECT MIN(Trade_Date) Trade_Date
FROM #TRANSACTIONS_WITH_RANK
WHERE Buy_Sell_Code = 'B'
GROUP BY Acct_ID
) TDateBuy
ON buy.Trade_Date = TDateBuy.Trade_Date
FULL OUTER JOIN #TRANSACTIONS_WITH_RANK sell
INNER JOIN (
SELECT MIN(Trade_Date) Trade_Date
FROM #TRANSACTIONS_WITH_RANK
WHERE Buy_Sell_Code = 'S'
GROUP BY Acct_ID
) TDateSell
ON sell.Trade_Date = TDateSell.Trade_Date
ON buy.Acct_ID = sell.Acct_ID
EDIT: after seeing OP's comment I have changed the query
SELECT
buy.Acct_ID, buy.Trade_Date, buy.Brokerage_Transaction_Key, buy.Buy_Sell_Code, buy.Principal_Amt, buy.Security_Quantity,
sell.Acct_ID, sell.Trade_Date, sell.Brokerage_Transaction_Key, sell.Buy_Sell_Code, sell.Principal_Amt, sell.Security_Quantity
FROM (
SELECT wr.*, MIN(TransKey) TransKey -- This is the value of the Sell to be joined
FROM #TRANSACTIONS_WITH_RANK wr
LEFT OUTER JOIN (
SELECT MIN(Brokerage_Transaction_Key) TransKey, Acct_ID
FROM (
SELECT
tr.*,
(
SELECT MAX(Brokerage_Transaction_Key) --Purpose is to give outer query value to GROUP on
FROM #TRANSACTIONS_WITH_RANK
WHERE Buy_Sell_Code = 'B'
AND Acct_ID = tr.Acct_ID
AND Brokerage_Transaction_Key < tr.Brokerage_Transaction_Key
) MaxLesserKey
FROM #TRANSACTIONS_WITH_RANK tr
) data
WHERE Buy_Sell_Code = 'S'
GROUP BY Acct_ID, MaxLesserKey
) MinSell
ON wr.Acct_ID = MinSell.Acct_ID
AND wr.Brokerage_Transaction_Key < MinSell.TransKey
WHERE Buy_Sell_Code = 'B'
GROUP BY wr.Acct_ID, Trade_Date, Brokerage_Transaction_Key, Buy_Sell_Code, Principal_Amt, Security_Quantity
) buy
FULL OUTER JOIN (
SELECT wr.*, MIN(MinBuy.TransKey) TransKey -- This is the value of the Buy to be joined
FROM #TRANSACTIONS_WITH_RANK wr
LEFT OUTER JOIN (
SELECT MIN(Brokerage_Transaction_Key) TransKey, Acct_ID
FROM (
SELECT
tr.*,
(
SELECT MAX(Brokerage_Transaction_Key) --Purpose is to give outer query a value to GROUP on
FROM #TRANSACTIONS_WITH_RANK
WHERE Buy_Sell_Code = 'S'
AND Brokerage_Transaction_Key < tr.Brokerage_Transaction_Key
) MaxLesserKey
FROM #TRANSACTIONS_WITH_RANK tr
) data
WHERE Buy_Sell_Code = 'B'
GROUP BY Acct_ID, MaxLesserKey
) MinBuy
ON wr.Acct_ID = MinBuy.Acct_ID
AND wr.Brokerage_Transaction_Key < MinBuy.TransKey
WHERE Buy_Sell_Code = 'S'
GROUP BY wr.Acct_ID, Trade_Date, Brokerage_Transaction_Key, Buy_Sell_Code, Principal_Amt, Security_Quantity
) sell
ON buy.TransKey = sell.Brokerage_Transaction_Key
OR sell.TransKey = buy.Brokerage_Transaction_Key
Basically what this does is grab all Buy(s) and their matching Sell Brokerage_Transaction_Key (TransKey) and does a FULL OUTER JOIN (NULLs out the Buy or Sell side when there are no opposite matching transactions) to the set of Sell(s) and their matching Buy Brokerage_Transaction_Key (TransKey).
The TransKey is the smallest Brokerage_Transaction_Key of the opposite Buy_Sell_Code for each group of Buy(s)/Sell(s). This will give you first Sell to first Buy(s) or first Buy to first Sell(s) per group of transactions for a particular Acct_ID. The MaxLesserKey field is there to just to give the TransKey query a value to GROUP on

Add column that counts times value occurs in results

I have a query with 5 columns. I want to add 1 column that defines the number of times the value in column 2 (ItemCode) occurs in the results.
This is my query:
SELECT
Items.Description_0 AS [Items.Description],
Items.ItemCode,
warehouse_location,
Stock.Quantity AS StockQty,
Stock.warehouse
FROM
((SELECT gbkmut.artcode, gbkmut.warehouse, ISNULL(gbkmut.warehouse_location,'') AS warehouse_location,
SUM(gbkmut.aantal) AS Quantity FROM gbkmut
INNER JOIN Items ON Items.ItemCode = gbkmut.artcode
INNER JOIN voorrd ON voorrd.artcode=gbkmut.artcode
AND voorrd.magcode=gbkmut.warehouse
INNER JOIN ItemUnits ON ItemUnits.Unit = Items.PackageDescription
WHERE gbkmut.reknr = Items.GLAccountDistribution
AND (( gbkmut.transtype IN ('N', 'C', 'P', 'X')
AND gbkmut.datum BETWEEN {d '2000-01-09'} AND {d '2031-02-08'} ) )
AND (gbkmut.warehouse='MAG1' )
AND Items.Type IN ('S','B')
AND NOT (Items.GLAccountAsset IS NOT NULL AND Items.IsSerialNumberItem=1) AND NOT (Items.Type = 'S' AND ItemUnits.UnitType = 'T')
GROUP BY gbkmut.artcode, gbkmut.warehouse, ISNULL(gbkmut.warehouse_location,'')
HAVING SUM(gbkmut.aantal) > 0)) Stock
INNER JOIN Items ON Items.ItemCode=Stock.artcode
WHERE Items.ItemCode like '10.27021%'
ORDER BY Items.ItemCode
Lazy version, use a common table expression (cte):
with cte as
(
[your huge select]
)
select t1.*, t2.codecount
from cte t1
join (select ItemCode, count(*) as codecount from cte group by ItemCode) as t2
ON t2.ItemCode = t1.ItemCode

Complex Full Outer Join

Sigh ... can anyone help? In the SQL query below, the results I get are incorrect. There are three (3) labor records in [LaborDetail]
Hours / Cost
2.75 / 50.88
2.00 / 74.00
1.25 / 34.69
There are two (2) material records in [WorkOrderInventory]
Material Cost
42.75
35.94
The issue is that the query incorrectly returns the following:
sFunction cntWO sumLaborHours sumLaborCost sumMaterialCost
ROBOT HARNESS 1 12 319.14 236.07
What am I doing wrong in the query that is causing the sums to be multiplied? The correct values are sumLaborHours = 6, sumLaborCost = 159.57, and sumMaterialCost = 78.69. Thank you for your help.
SELECT CASE WHEN COALESCE(work_orders.location, Work_Orders_Archived.location) IS NULL
THEN '' ELSE COALESCE(work_orders.location, Work_Orders_Archived.location) END AS sFunction,
(SELECT COUNT(*)
FROM work_orders
FULL OUTER JOIN Work_Orders_Archived
ON work_orders.order_number = Work_Orders_Archived.order_number
WHERE COALESCE(work_orders.order_number, Work_Orders_Archived.order_number) = '919630') AS cntWO,
SUM(Laborhours) AS sumLaborHours,
SUM(LaborCost) AS sumLaborCost,
SUM(MaterialCost*MaterialQuanity) AS sumMaterialCost
FROM work_orders
FULL OUTER JOIN Work_Orders_Archived
ON work_orders.order_number = Work_Orders_Archived.order_number
LEFT OUTER JOIN
(SELECT HoursWorked AS Laborhours, TotalDollars AS LaborCost, WorkOrderNo
FROM LaborDetail) AS LD
ON COALESCE(work_orders.order_number, Work_Orders_Archived.order_number) = LD.WorkOrderNo
LEFT OUTER JOIN
(SELECT UnitCost AS MaterialCost, Qty AS MaterialQuanity, OrderNumber
FROM WorkOrderInventory) AS WOI
ON COALESCE(work_orders.order_number, Work_Orders_Archived.order_number) = WOI.OrderNumber
WHERE COALESCE(work_orders.order_number, Work_Orders_Archived.order_number) = '919630'
GROUP BY CASE WHEN COALESCE(work_orders.location, Work_Orders_Archived.location) IS NULL
THEN '' ELSE COALESCE(work_orders.location, Work_Orders_Archived.location) END
ORDER BY sFunction
Try using the SUM function inside a derived table subquery when doing the full join to "WorkOrderInventory" like so...
select
...
sum(hrs) as sumlaborhrs,
sum(cost) as sumlaborcost,
-- calculate material cost in subquery
summaterialcost
from labordetail a
full outer join
(select ordernumber, sum(materialcost) as summaterialcost
from WorkOrderInventory
group by ordernumber
) b on a.workorderno = b.ordernumber
i created a simple sql fiddle to demonstrate this (i simplified your query for examples sake)
Looks to me that work_orders and work_orders_archived contains the same thing and you need both tables as if they were one table. So you could instead of joining create a UNION and use it as if it was one table:
select location as sfunction
from
(select location
from work_orders
union location
from work_orders_archived)
Then you use it to join the rest. What DBMS are you on? You could use WITH. But this does not exist on MYSQL.
with wo as
(select location as sfunction, order_number
from work_orders
union location, order_number
from work_orders_archived)
select sfunction,
count(*)
SUM(Laborhours) AS sumLaborHours,
SUM(LaborCost) AS sumLaborCost,
SUM(MaterialCost*MaterialQuanity) AS sumMaterialCost
from wo
LEFT OUTER JOIN
(SELECT HoursWorked AS Laborhours, TotalDollars AS LaborCost, WorkOrderNo
FROM LaborDetail) AS LD
ON COALESCE(work_orders.order_number, Work_Orders_Archived.order_number) = LD.WorkOrderNo
LEFT OUTER JOIN
(SELECT UnitCost AS MaterialCost, Qty AS MaterialQuanity, OrderNumber
FROM WorkOrderInventory) AS WOI
ON COALESCE(work_orders.order_number, Work_Orders_Archived.order_number) = WOI.OrderNumber
where wo.order_number = '919630'
group by sfunction
order by sfunction
The best guess is that the work orders appear more than once in one of the tables. Try these queries to check for duplicates in the two most obvious candidate tables:
select cnt, COUNT(*), MIN(order_number), MAX(order_number)
from (select order_number, COUNT(*) as cnt
from work_orders
group by order_number
) t
group by cnt
order by 1;
select cnt, COUNT(*), MIN(order_number), MAX(order_number)
from (select order_number, COUNT(*) as cnt
from work_orders_archived
group by order_number
) t
group by cnt
order by 1;
If either returns a row where cnt is not 1, then you have duplicates in the tables.