sum result is being multiplied by number of rows - sql

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'

Related

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

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

Sum Group By Column

I have a column (PL.UNITS) that I need to Total at the bottom of the results of a query, is it possible to sum PL.UNITS that is already summed?
Please see query below.
SELECT ID.DUEDATE AS [DUE DATE], CD.RENEWALDATE, CD.RENEWALSTATUS, CD.CONTRACTNUMBER, L.LOCNAME, L.LOCADDRESS1, L.LOCADDRESS2, L.LOCADDRESS3, L.LOCADDRESS4, L.POSTCODE, SUM(PL.UNITS) AS UNITS from CLIENTDETAILS CD
INNER JOIN LOCATIONS L ON CD.CLIENTNUMBER = L.CLIENTNUMBER
INNER JOIN ITEMDETAILS ID ON L.LOCNUMBER = ID.LOCNUMBER
INNER JOIN PLANT PL ON ID.CODE = PL.CODE
WHERE L.OWNER = 210 and L.STATUSLIVE = 1 and ID.DUEDATE > '01/01/2017'
GROUP BY ID.DUEDATE, CD.RENEWALDATE, CD.RENEWALSTATUS, CD.CONTRACTNUMBER, L.LOCNAME, L.LOCADDRESS1, L.LOCADDRESS2, L.LOCADDRESS3, L.LOCADDRESS4, L.POSTCODE
It's probably best to do this sort of thing in front end development. Nevertheless, here is an example (quick and dirty, but shows the idea) for sql-server:
SELECT COALESCE(a.id, 'total') AS id
, SUM(a.thing) AS thing_summed
FROM (
SELECT '1' id
, 1 thing
UNION
SELECT '2'
, 2 thing
UNION
SELECT '1'
, 3 thing
) AS a
GROUP BY ROLLUP(a.id)
Result:
+-------+--------------+
| id | thing_summed |
+-------+--------------+
| 1 | 4 |
| 2 | 2 |
| total | 6 |
+-------+--------------+

How to get Order numbers where collection number has a top and a corresponding bottom?

This is how the main order table looks :-
| Order_num | Collection_Num |
+--------------+----------------+
| 20143045585 | 123456 |
| 20143045585 | 789012 |
| 20143045585 | 456897 |
| 20143758257 | 546465 |
+--------------+----------------+
These are the collections:-
| tops | bottom |
+--------------+----------------+
| 353735 | 745758 |
| 123456 | 789012 |
| 456456 | 456897 |
| 323456 | 546465 |
+--------------+----------------+
Desired Output:-
| Order_num |
+--------------+
| 20143045585 |
Here Order number 20143045585 has both a top and a bottom from the same row in table number 2 (each row in 2nd table forms a particular combination called 'A Collection' i.e. 1 top and corresponding bottom ).
What I want to know -
All the order numbers which have a top and a corresponding bottom in 'Collection_num' column.
Can anyone help me with a SQL code for this ?
Let me know if any of this is unclear.
select Order_num
From table_1 as A
where exists
(select tops from table_2 as B where B.tops = A.Collection_num)
AND
(select bottom from table2 as B where B.bottom = A.Collection_num)
I am assuming you just have the first table of data and each order can only have the two relevant collections or less. Perhaps:
select T1.Order_Num
,T1.Collection_Num AS Tops
,T2.Collection_Num AS Bottom
from Table1 T1
inner join Table1 T2
on T1.Order_Num = T2.Order_Num
and T1.Collection_Num < T2.Collection_Num
order by T1.Order_Num
You can try using subquery
select distinct order_num from #yourorder where collection_num
in (select tops from #yourcollections)
and order_num in
( select order_num from #yourorder where collection_num in
(select bottom from #yourcollections) )
Pretty sure that something like this should work for you. I am just using the ctes here to create the test data so it can be queried.
with Orders (OrderNum, CollectionNum) as
(
select 20143045585, 123456 union all
select 20143045585, 789012 union all
select 20143045585, 456897 union all
select 20143758257, 546465
)
, Collections (CollectionID, tops, bottoms) as
(
select 1, 353735, 745758 union all
select 2, 123456, 789012 union all
select 3, 456456, 456897 union all
select 4, 323456, 546465
)
select o.OrderNum
, t.tops
, b.bottoms
from Orders o
join Collections t on t.tops = o.CollectionNum
join
(
select o.OrderNum
, b.bottoms
, b.CollectionID
from Orders o
join Collections b on b.bottoms = o.CollectionNum
) b on b.CollectionID = t.CollectionID
Here is the query that I used:
Select *
From (select A.Order_num, B.Coll_ID, B.Bottoms from Orders_table as A
Join Collections_Table as B
on A.Collection_num = B.Bottoms
) as C
join
(select K.Order_num, M.Coll_ID, M.Tops from Orders_table as K
Join Collections_Table as M
on A.Collection_num = B.Tops
) as D
on C.Orders_B = D.Orders_Num AND C.Coll_ID = D.Coll_ID
)

Select columns with and without group by

Having Table1
id | productname | store | price
-----------------------------------
1 | name a | store 1 | 4
2 | name a | store 2 | 3
3 | name b | store 3 | 6
4 | name a | store 3 | 4
5 | name b | store 1 | 7
6 | name a | store 4 | 5
7 | name c | store 3 | 2
8 | name b | store 6 | 5
9 | name c | store 2 | 1
I need to get all columns but only the rows with the
lowest price.
Result needed:
id | productname | store | price
-----------------------------------
2 | name a | store 2 | 3
8 | name b | store 6 | 5
9 | name c | store 2 | 1
My best try is:
SELECT ProductName, MIN(Price) AS minPrice
FROM Table1
GROUP BY ProductName
But then I need the ID and STORE for each row.
Try this
select p.* from Table1 as p inner join
(SELECT ProductName, MIN(Price) AS minPrice FROM Table1 GROUP BY ProductName) t
on p.productname = t.ProductName and p.price = t.minPrice
Select ID,ProductName,minPrice
from
(
SELECT ProductName, MIN(Price) AS minPrice
FROM Table1
GROUP BY ProductName
) t
join Table1 t1 on t.ProductName = t1.ProductName
You didn't mention your SQL dialect, but most DBMSes support Standard SQL's "Windowed Aggregate Functions":
select *
from
( select t.*,
RANK() OVER (PARTITION BY ProductName ORDER BY Price) as rnk
from table1 as t
) as dt
where rnk = 1
If multiple stores got the same lowest price all of them will be returned. If you want only a single shop you have to switch to ROW_NUMBER instead of RANK or add column(s) to the ORDER BY.
I think this query should do:
select min(t.id) id
, t.productname
, t.price
from table1 t
join
( select min(price) min_price
, productname
from table1
group
by productname
) v
on v.productname = t.productname
and v.price = t.min_price
group
by t.productname
, t.price
It determines the lowest price per product and fetches every line in the base table (t). This avoids duplicates by grouping on the productname and selecting the lowest id.
This should work for you:
SELECT * FROM `Table1` AS `t1`
WHERE (
SELECT count(*) FROM `Table1` AS `t2` WHERE `t1`.`productName` = `t2`.`productName` AND `t2`.`price` < `t1`.`price`) < 1
Check SqlFiddle
But if you have same products with same minimum price in two stores, you will get both of them in result output

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