DISTINCT is not working properly in left join - sql

I have two tables StockIn and StockOut.
StockIn table has an Id number for the product, this Id number is unique in the StockIn table, where else this Id number will be duplicated in StockOut table as many time the stock will be sold out.
Now I want to create a view to find the stock in hand where StockIn.Id = StockOut.Id. So far I manage to query and it is giving the result but it fails when there are multiple order in the StockOut table of the same product, because of the duplicate Id number.
Below is my query:
select DISTINCT
i.Id,
i.AssetsName,
i.Rate,
i.Qty,
So.QtyOut,
Balance = sum( COALESCE(i.Qty,0)- COALESCE(so.QtyOut,0)) OVER(PARTITION BY i.id)
from dbo.StockIn i
LEFT Join StockOut So
on i.Id = So.Id
GO

A simple GROUP BY with normal SUM's should do.
SELECT
si.Id,
si.AssetsName,
si.Rate,
si.Qty,
SUM(so.QtyOut) AS QtyOut,
COALESCE(si.Qty, 0) - SUM(so.QtyOut) AS Balance
FROM dbo.StockIn si
LEFT JOIN dbo.StockOut so ON so.Id = si.Id
GROUP BY si.Id, si.AssetsName, si.Rate, si.Qty;

You'd be better off collapsing your stock out to single row before you join
Remove the distinct - it doesn't help and isn't needed
select
id,
si.qtyin - so.qtyout as balance
from
stockin si
left join
(select id, sum (qtyout) as qtyout from stockout group by id) so
on so.id = si.id
That means your joins will only ever be 1:0 (if no sales) or 1:1 (all sales summed before join)
What happens when you order more stuff? If you create another stockin record with the same ID then the same problem will happen for products that have been re-stocked. Use the same technique to collapse stockin to a single row before you join:
select
id,
si.qtyin - so.qtyout as balance
from
(Select id, sum(qtyin) as qtyin stockin group by id) si
left join
(select id, sum (qtyout) as qtyout from stockout group by id) so
on so.id = si.id

Try this
select
i.Id,
i.AssetsName,
i.Rate,
i.Qty,
sum( COALESCE(i.Qty,0)- COALESCE((Select Qtyout from StockIn Where StockIn.Id=StockOut.Id),0)) OVER(PARTITION BY i.id) as Balance
from dbo.StockIn i
group by Id,AssetsName,Rate,Qty

Related

Use 1 SQL query to join 3 tables and find the category of products that generates the most revenue for each customer segment

I am using SQLite3 for this following query.
I have a table called "products" that looks like this:
I have a table called "transactions" that looks like this:
I have a table called "segments" that looks like this:
For each active segment, I want to find the category that produces the highest revenue.
I think that I know how to do this in 3 different queries.
create table table1 as
SELECT s.seg_name, p.category, t.item_qty * t.item_price as revenue
from segments s
JOIN
transactions t
on s.cust_id = t.cust_id
JOIN products p
on p.prod_id = t.prod_id
where s.active_flag = 'Y'
order by s.seg_name, p.category
;
create table table2 as
select seg_name, category, sum(revenue) as revenue
from table1
group by seg_name, category;
select seg_name, category, max(revenue) as revenue
from table2
group by seg_name;
How can I do it in 1 query?
here is one way :
select seg_name,category,revenue
from (
select
s.seg_name,
p.category,
sum(t.item_qty * t.item_price) as revenue,
rank() over (partition by seg_name order by sum(t.item_qty * t.item_price) desc) rn
from segments s
join transactions t on s.cust_id = t.cust_id
join products p on p.prod_id = t.prod_id
where s.active_flag = 'Y'
group by seg_name, p.category
) t where rn = 1

Select Sold and unsold product from same table in SQL Server for last month

I have Database table and trying to write query to find sold and not sold product list from one table.
Table is Below
Expecting Result
How do i get this result? i am using CTE to create Tamp table and with all services and then do left join but it dose give me only product sold in Feb, but i want all product with no sell too.
You can cross join the products and the dates, and then bring the table with a left join:
select
p.product,
t.quantity_sold,
d.yr,
d.mn
from (select distinct product from mytable) p
cross join (select distinct yr, mn from mytable) d
left join mytable t
on t.product = p.product
and t.yr = d.yr
and t.mn = d.mn
This puts nulls for rows with no sale - that's presumably a numeric column so you generally don't want to write a string like 'Not Sold' into it.
If there is a possibility of duplicate (product, yr, mn), you might want to use outer aggregation:
select
p.product,
sum(t.quantity_sold) quantity_sold,
d.yr,
d.mn
from (select distinct product from mytable) p
cross join (select distinct yr, mn from mytable) d
left join mytable t
on t.product = p.product
and t.yr = d.yr
and t.mn = d.mn
group by p.product, d.yr, d.mn

Triple Table Join with Subtraction

I have 3 tables (production, sales, wastage)
All 3 tables have the columns: Product and Quantity
I need a query statement that will join all 3 tables in the following manner:production - sales - wastage Grouped by Product
Thanks in advance for the tips and tricks :)
Combine tables using left join, group by product and get total quantity by substracting values assuming that there can be no record for a given product within sales or wastage tables and then count them as 0.
select p.product, sum(p.quantity - coalesce(s.quantity,0) - coalesce(w.quantity,0)) as qty
from production p
left join sales s on p.product = s.product
left join wastage w on p.product = w.product
group by p.product
You can group each table individually and then [left] join them:
SELECT p.product, p_quantity - COALESCE(s_quantity, 0) - COALESCE(w_quantity, 0)
FROM (SELECT product, SUM(quantity) AS p_quantity
FROM production
GROUP BY product) p
LEFT JOIN (SELECT product, SUM(quantity) AS s_quantity
FROM sales
GROUP BY product) s ON p.product = s.product
LEFT JOIN (SELECT product, SUM(quantity) AS w_quantity
FROM wastage
GROUP BY product) w ON p.product = w.product

Getting a SUM of the values in INNER JOIN adds up duplicate values

I am running a query which is counting the records on monthly basis from the table.
I am trying to add one extra column called "TotalPrice", I need a sum of all the prices from 'settle' table.
The problem I am facing is because of INNER JOIN, 'SUM' of the prices is adding up multiple prices due to duplicate records which the INNER JOIN is returning. Is there a way to avoid it and get a SUM of the prices from unique records ?
SELECT
CONCAT(year(datetime), '-', month(datetime)) AS YearMonth,
COUNT (DISTINCT a.id) AS TOTAL, SUM(total_price) AS TotalPrice
FROM settle AS a with (nolock)
INNER JOIN transfers b with (nolock) ON b.settleId = a.id
INNER JOIN Fdata AS c with (nolock) ON c.id= b.data
GROUP BY CONCAT(year(datetime), '-', month(datetime))
Thanks in advance.
sql server 2008 onwards:
with CTE as -- A CTE alows us to manipulate the data before we use it, like a derived table
(
select datetime, id, total_price,
row_number() over(partition by id, datetime order by total_price) as rn -- This creates a row number for each combo of id and datetime that appears
FROM settle AS a with (nolock)
INNER JOIN transfers b with (nolock) ON b.settleId = a.id
INNER JOIN Fdata AS c with (nolock) ON c.id= b.data
)
SELECT CONCAT(year(datetime), '-', month(datetime)) AS YearMonth,
COUNT (DISTINCT a.id) AS TOTAL,
SUM(total_price) AS TotalPrice
from CTE
where rn = 1 -- that row_number we created? This selects only the first one, removing duplicates
group by CONCAT(year(datetime), '-', month(datetime))

Join two tables but only get most recent associated record

I am having a hard time constructing an sql query that gets all the associated data with respect to another (associated) table and loops over into that set of data on which are considered as latest (or most recent).
The image below describes my two tables (Inventory and Sales), the Inventory table contains all the item and the Sales table contains all the transaction records. The Inventory.Id is related to Sales.Inventory_Id. And the Wanted result is the output that I am trying to work on to.
My objective is to associate all the sales record with respect to inventory but only get the most recent transaction for each item.
Using a plain join (left, right or inner) doesn't produce the result that I am looking into for I don't know how to add another category in which you can filter the most recent data to join to. Is this doable or should I change my table schema?
Thanks.
You can use APPLY
Select Item,Sales.Price
From Inventory I
Cross Apply(Select top 1 Price
From Sales S
Where I.id = S.Inventory_Id
Order By Date Desc) as Sales
WITH Sales_Latest AS (
SELECT *,
MAX(Date) OVER(PARTITION BY Inventory_Id) Latest_Date
FROM Sales
)
SELECT i.Item, s.Price
FROM Inventory i
INNER JOIN Sales_Latest s ON (i.Id = s.Inventory_Id)
WHERE s.Date = s.Latest_Date
Think carefully about what results you expect if there are two prices in Sales for the same date.
I would just use a correlated subquery:
select Item, Price
from Inventory i
inner join Sales s
on i.id = s.Inventory_Id
and s.Date = (select max(Date) from Sales where Inventory_Id = i.id)
select * from
(
select i.name,
row_number() over (partition by i.id order by s.date desc) as rownum,
s.price,
s.date
from inventory i
left join sales s on i.id = s.inventory_id
) tmp
where rownum = 1
SQLFiddle demo