SQL selecting the maximum value of multiple items with all the columns - sql

The data:
My query:
SELECT
itemcode, whsecode, MAX(quantity)
FROM
inventoryTable
GROUP BY
itemcode;
This returns this error:
Column 'inventoryTable.whsecode' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY
clause.
When I put the whsecode in the GROUP BY clause, it just returns all the data in the table.
The output that I want is to return the whsecode with the highest quantity of the item in it.
The output that it supposed to have is:
whsecode|itemcode|quantity
WHSE2 | SS585 | 50
WHSE2 | SS586 | 50
WHSE1 | SS757 | 30
Eventually I will put that query inside this another query:
SELECT
A.mrno, A.remarks,
B.itemcode, B.description, B.uom, B.quantity,
C.whsecode, C.whseqty, D.rate
FROM
Mrhdr A
INNER JOIN
Mrdtls B ON A.mrno = B.mrno
INNER JOIN
(
SELECT itemcode, whsecode, MAX(quantity) AS whseqty
FROM inventoryTable
GROUP BY itemcode, whsecode
) C ON B.itemcode = C.itemcode
INNER JOIN
Items D ON B.itemcode = D.itemcode
WHERE
A.mrno = #MRNo AND B.quantity < C.whseqty;
with the whsecode inside the GROUP BY clause the output is:
But as I said earlier, the problem is it returns multiple rows of the same itemcode. The output that it supposed to have is:
mrno | remarks| itemcode| description | uom |quantity|whsecode|whseqty| rate
MR211100003008 | SAMPLE | FG 4751 | LONG DRILL 3.4 X 200 L550 | PCS. | 50.00 | WHSE3 | 100 | 0.0000
MR211100003008 | SAMPLE | FG 5092 | T-SPIRAL TAP M3.0 X 0.5 L6904 | PCS | 20.00 | WHSE1 | 80 | 0.0000
I am not sure if the B.quantity < C.whseqty should be there but it eliminates the other values that are not the maximum value.

There are many ways to solve this. For example, by using the ROW_NUMBER function:
SELECT
itemcode,
whsecode,
quantity As whseqty
FROM
(
SELECT
itemcode,
whsecode,
quantity,
ROW_NUMBER() OVER (PARTITION BY itemcode ORDER BY quantity DESC) As RN
FROM
inventoryTable
)
WHERE
RN = 1
;

Edit:
select whsecode,A.itemcode,qty from inventoryTable
join (SELECT itemcode, MAX(quantity) as qty FROM inventoryTable GROUP BY itemcode) as A on A.itemcode = inventoryTable.itemcode and A.qty = inventoryTable.quantity

Related

SQL: Trying to add up a total row which was calculated from 2 other columns

I'm attempting, and partly done, to find out how much stock is left in a business. I have a stock table and product price table that I'm pulling values from. The TOTAL column is quantityinstock * price which is what I need but I'd like to the get an overall total of the TOTAL.
How would I go about this? I've been searching for quite a while now to no avail!
I would like to, if possible get a TOTAL of TOTAL row adding up all of the TOTAL i.e. 3551.13 + 2941.91 + 2713.19 = VALUE.
SELECT
A.productID,
quantityInStock,
productPrice,
quantityInStock * productPrice AS TOTAL
FROM gs_stock A
JOIN gs_productprice B ON A.productID = B.productID
WHERE endDate IS NULL
GROUP BY A.productID
ORDER BY TOTAL DESC
Sample Data:
+-----------+-----------------+--------------+---------+
| productID | quantityInStock | productPrice | TOTAL |
+-----------+-----------------+--------------+---------+
| 71 | 187 | 18.99 | 3551.13 |
| 73 | 109 | 26.99 | 2941.91 |
| 74 | 181 | 14.99 | 2713.19 |
+-----------+-----------------+--------------+---------+
SELECT
A.productID,
A.quantityInStock,
B.productPrice,
A.quantityInStock * B.productPrice AS TOTAL
FROM gs_stock A
JOIN gs_productprice B on A.productID = B.productID
WHERE endDate IS NULL
GROUP BY A.productID
ORDER BY TOTAL DESC
What I understood was that you need a total value of your stock that will be as follows:
SELECT
sum(TOTAL) as TOTAL_SUM
FROM (
SELECT
A.productID,
quantityInStock,
productPrice,
quantityInStock * productPrice AS TOTAL
FROM gs_stock A
JOIN gs_productprice B ON A.productID = B.productID
WHERE endDate IS NULL
GROUP BY A.productID
) TOTAL
Added in TOTAL following the end bracket which then gave me the required calculation I was looking for!!! Cheers again, really appreciate your help!

sum result is being multiplied by number of rows

I'm trying to get 2 sums from my tables, one is a table of ordered items and another is a table of received items. With my current query i'm getting a sum of 2014 which is from 106(the actual sum I want to get) multiplied by 19(the number of records)
select POD.PO_No, SUM(POD.Qty) as Qty, RRD.RR_No, SUM(RRD.QtyRcvd) as QtyReceived
from tbl_PODetail POD inner join tbl_RRDetail RRD on POD.PO_No = RRD.PO_Reference
where POD.PO_No = 'PO-000001'
group by POD.PO_No, RRD.RR_No
What causes this and how can I correct it?
Sample Table
PO No | Item | Qty
-------------------------
PO-0000001 | Item A | 5
PO-0000001 | Item B | 7
PO-0000001 | Item B | 3
RR No | Item | Qty | PO_Reference
----------------------------------------
RR-0000001 | Item A | 5 | PO-0000001
RR-0000001 | Item B | 7 | PO-0000001
RR-0000001 | Item B | 3 | PO-0000001
Expected Output:
PO No | Qty | RR No | Qty Rcvd
-----------------------------------------
PO-0000001 | 15 | RR-0000001 | 15
What I get
PO No | Qty | RR No | Qty Rcvd
-----------------------------------------
PO-0000001 | 45 | RR-0000001 | 45
You missed the POD.Item = RRD.Item on join, that's why you are getting multiplied records.
select POD.PO_No, SUM(POD.Qty) as Qty, RRD.RR_No, SUM(RRD.QtyRcvd) as QtyReceived
from tbl_PODetail POD
inner join tbl_RRDetail RRD on POD.PO_No = RRD.PO_Reference and POD.Item = RRD.Item
where POD.PO_No = 'PO-000001'
group by POD.PO_No, RRD.RR_No
Try aggregating the values in subqueries and joining them afterwards
Select *
From (
Select po_no, sum(qty) qty
From tbl_PODetail
Group by po_no
) p join (
Select rr_no, po_reference, sum(qty) qty_rcvd
From tbl_RRDetail
Group by rr_no, po_reference
) r on p.po_no = r.po_reference
Where p.po_no = 'PO-0000001'
Try this also. Hope this could help.
select * into #table1 from (
select 'PO-0000001' as PO_No,'Item A' as Item,5 as QTY union
select 'PO-0000001' as PO_No,'Item B' as Item,7 as QTY union
select 'PO-0000001' as PO_No,'Item C' as Item,3 as QTY
)t
select * into #table2 from (
select 'RR-0000001' as RR_No,'Item A' as Item,5 as QTY,'PO-0000001' as PO_Referrence union
select 'RR-0000001' as RR_No,'Item B' as Item,7 as QTY,'PO-0000001' as PO_Referrence union
select 'RR-0000001' as RR_No,'Item C' as Item,3 as QTY,'PO-0000001' as PO_Referrence
)t
select t1.PO_No,sum(t2.qty) as 'Qty' ,t2.RR_no,sum(t1.qty) as 'QTY Rcvd'
from #table1 t1
inner join #table2 t2
on t1.PO_no=t2.PO_Referrence and t1.item=t2.item
group by t1.PO_No,t2.RR_no
This answers reflects what my understanding of your problem is. It appears that you want to aggregate the tbl_PODetail by PO number and compute a sum as quantity. Then, you want to aggregate a second table tbl_RRDetail by two columns, and join the first aggregated result to that using only the PO number. If this be correct, then one approach would be to use two separate subqueries for the aggregation and join them together.
WITH cte1 AS (
SELECT RR_No, PO_Reference, SUM(QtyRcvd) AS QtyReceived
FROM tbl_RRDetail
GROUP BY RR_No, PO_Reference
),
WITH cte2 AS (
SELECT PO_No, SUM(Qty) AS Qty
FROM tbl_PODetail
GROUP BY PO_No
)
SELECT t2.PO_No, t2.Qty, t1.RR_No, t1.QtyReceived
FROM cte1 t1
INNER JOIN cte2 t2
ON t1.PO_Reference = t2.PO_No
WHERE t1.PO_No = 'PO-000001'

How to calculate max(column) row from a result set grouped by different items

SELECT T1.* FROM
(
SELECT
MAX(no_of_orders) [no_of_orders],
ord.customer_id [customer_id],
ord_dtl.item_id [item_id]
FROM order_main ord
INNER JOIN order_detail ord_dtl
ON ord.order_id = ord_dtl.order_id
GROUP BY
ord.customer_id, ord_dtl.item_id
) T1
INNER JOIN
(
SELECT
MAX(no_of_orders) [no_of_orders],
ord.customer_id
FROM order_main ord
INNER JOIN order_detail ord_dtl
ON ord.order_id = ord_dtl.order_id
GROUP BY
ord.customer_id
) T2
ON
T1.customer_id = T2.customer_id
AND T1.no_of_orders = T2.no_of_orders
I calculated the most ordered item by customer from table order_main and order_detail.
What I did is like I calculated the no of orders grouping by customer id and item id and to reduce the result set to most ordered item by customer, I joined the resultset by same query removing the grouping by item id.
I don't feel this is a good query.
Any better alternative ?
SQL Fiddle
Most ordered item by customer
Query:
SQLFIDDLEExample
SELECT a.no_of_orders,
a.customer_id,
a.item_id
FROM (SELECT
MAX(no_of_orders) [no_of_orders],
ord.customer_id [customer_id],
ord_dtl.item_id [item_id],
ROW_NUMBER() OVER(PARTITION BY ord.customer_id ORDER BY MAX(no_of_orders) DESC) AS rnk
FROM order_main ord
INNER JOIN order_detail ord_dtl
ON ord.order_id = ord_dtl.order_id
GROUP BY
ord.customer_id, ord_dtl.item_id) a
WHERE a.rnk = 1
Result:
| NO_OF_ORDERS | CUSTOMER_ID | ITEM_ID |
---------------|-------------|---------|
| 20 | 2 | 6 |
| 50 | 7 | 6 |
| 1500 | 8 | 7 |
| 10 | 9 | 3 |

Fusion of two tables with Specific SUM operation in SQL Server 2012

I have two views in my database, here are their structures:
Table 1 (Stock product entries) :
---------------------------------------
| Date | Product | Quantity |
---------------------------------------
|2013-06-06| Procuct001 | 40 |
---------------------------------------
Table 2 (Stock product outputs) :
---------------------------------------
| Date | Product | Quantity |
---------------------------------------
|2013-06-07| Procuct001 | 15 |
---------------------------------------
|2013-06-08| Procuct001 | 5 |
---------------------------------------
I want to have a third view (or table) where I'll store all the stock's movements (entries or outputs) but I don't want to store the entered or retrieved quantity, but the difference (which means the stock's balance). In our case, the new table should contain :
Table 3 (Stock balance) :
---------------------------------------
| Date | Product | Quantity |
---------------------------------------
|2013-06-06| Procuct001 | 40 |
---------------------------------------
|2013-06-07| Procuct001 | 25 |
---------------------------------------
|2013-06-07| Procuct001 | 20 |
---------------------------------------
I am using SQL Server 2012 with SP1.
Here's one option using a Common Table Expression, utilizing ROW_NUMBER to seed your list (grouped by product):
with cte as (
select dt, product, quantity, row_number() over (partition by product order by dt) rn
from (
select * from t1
union
select * from t2
) t
)
select c.dt, c.product,
c2.quantity - coalesce(sum(c3.quantity),0) runningty
from cte c
inner join (
select product, quantity
from cte
where rn = 1) c2 on c.product = c2.product
left join cte c3 on c.product = c3.product and c3.rn <= c.rn and c3.rn <> 1
group by c.dt, c.product, c2.quantity
SQL Fiddle Demo
Depending on your data, you may not need to extra inner join to get your "1st" record -- you could perhaps use something like this instead:
with cte as (
select dt, product, quantity, row_number() over (partition by product order by dt) rn
from (
select * from t1
union
select * from t2
) t
)
select c.dt, c.product,
max(c.quantity) over (partition by c.product) - coalesce(sum(c3.quantity),0) runningty
from cte c
left join cte c3 on c.product = c3.product and c3.rn <= c.rn and c3.rn <> 1
group by c.dt, c.product, c.quantity

Join with alternating possibilities

There is a Select statement
Select i.ItemID, s.Price, s.Qty, s.Company From Item i
Inner Join Sku s ON s.ItemID = i.ItemID
Which returns this:
ItemID | Price | Qty | Company
1 | $50.00 | 0 | Abc inc.
1 | $45.00 | 5 | Def inc.
1 | $35.00 | 15 | Xyz inc.
2 | $36.00 | 4 | Abc inc.
2 | $45.00 | 5 | Def inc.
2 | $35.00 | 1 | Xyz inc.
3 | $20.00 | 2 | Abc inc.
3 | $45.00 | 0 | Def inc.
3 | $35.00 | 5 | Xyz inc.
But there needs to be the following logic:
Show the row with the lowest Price and Qty > 0, including the referring Company to that Result.
Else...
Show the row with the lowest price, including the referring Company to that Price.
Which would look something like this:
ItemID | Price | Qty | Company
1 | $35.00 | 15 | Xyz inc.
2 | $35.00 | 1 | Xyz inc.
3 | $20.00 | 2 | Abc inc.
I haven't tried anything because I honestly don't know what to try or what to even ask in my question. Any suggestions?
Here is one way to do it:
SELECT I.ItemId
, S.Price
, S.Qty
, S.Company
FROM dbo.Item I
CROSS APPLY (
SELECT MIN(Price) Price
FROM dbo.Sku MP
WHERE I.ItemId = MP.ItemId
AND Qty > 0
) MP
CROSS APPLY (
SELECT
TOP 1 Price
, Qty
, Company
FROM dbo.Sku S
WHERE S.ItemId = I.ItemId
AND S.Price = MP.Price
) S
How about something like this, using row number:
select
i.ItemId, s.Price, s.Qty, s.Company
from
item i
inner join
(
select
t.ItemId,
t.Price,
t.Qty,
t.Company,
RowNumber = row_number() over (PARTITION BY t.ItemId order by t.price asc, t.qty desc)
from
Sku t
) s on s.itemid = i.ItemId
where
s.RowNumber = 1
The row numbers "partition by" and "order by" are important here to ensure the correct results and this works even if all quantities for an item are 0.
Here is the query,
Select i.ItemID, s.Price, s.Qty, s.Company
From Item i
Inner Join Sku s
ON s.ItemID = i.ItemID
Inner Join (
select min(price) as Price, ItemID
from Sku
where Qty > 0
group by ItemId
)a
on a.ItemId = s.ItemId
and a.Price = s.Price
If you need only ItemId from Item table, you can remove the join with Item table itself as ItemId is present in Sku.
Select i.ItemID, min(s.Price) as price, s.Qty, s.Company From Item i
Inner Join Sku s ON s.ItemID = i.ItemID and s.qty>0
group by i.itemid, s.company, s.qty
Select i.ItemID, Min(s.Price) as Price, s.Qty, s.Company
From Item i Inner Join Sku s ON s.ItemID = i.ItemID
Where s.qty > 0
Group by i.itemid, s.qty, s.Company
Basically, you want the first sku record, ordered first by whether or not it has any stock (items with stock appearing first), and then by price, ascending. In the following query the common table expression returns the required SKU fields, along with the RowNum calculated field. RowNum is partitioned by ItemID (i.e. resets to 1 for each new ItemID) and ordered by the presence of stock first, and then by price. The main query then selects the first record from each ItemID:
WITH cte AS (
SELECT ItemID, Price, Qty, company,
ROW_NUMBER() OVER (PARTITION BY ItemId ORDER BY
CASE WHEN Qty > 0 THEN 1 ELSE 0 END DESC, Price ASC) AS RowNum
FROM #sku
)
SELECT ItemID, price, qty, Company FROM cte WHERE RowNum = 1