SQL Duplicate Values Issue on LEFT OUTER JOIN - sql

I am trying to do a Join within 4 tables but it is returning duplicate rows. Some Items might not exist on Sales and Inventory tables. What needs to be done to resolve the issue;
ProductList (We need all the items)
Item_ID
ProductDetail (it has the return all the matching items from Product List)
Item_ID
Product_Name
Sales (needs to return all matching items from ProductList)
Item_ID
Sales_Qty
Inventory
Item_ID
Remaining_Qty
SAMPLE DATA
ProductList
Item_Id
--------
0001
0002
0003
0004
ProductDetail
Item_Id Product_Name
-----------------------
0001 Eraser
0002 Pencil
0003 Pen
0004 Mouse
0005 Keyboard
0006 Monitor
0007 Cable
Sales
Item_ID Sales_Qty
--------------------
0001 15
0002 20
0004 50
0005 60
0006 45
Inventory
Item_ID Remaining
-------------------
0001 100
0002 95
0003 55
0005 101
0006 13
0007 18
Desired output:
Item_Id Item_Name Sales_Qty Remaining_Qty
--------------------------------------------------
0001 Eraser 15 100
0002 Pencil 20 95
0003 Pen 0 55
0004 Mouse 50 0
My query :
SELECT *
FROM ProductList a
INNER JOIN ProductDetail b ON a.Item_ID = b.ItemID
LEFT JOIN Sales c ON a.Item_Id = c.Item_ID
LEFT JOIN Inventory d ON a.Item_ID = d.Item_ID

You can use DISTINCT
SELECT DISTINCT a.Item_ID, *
FROM ProductList a
INNER JOIN ProductDetail b
ON a.Item_ID = b.ItemID
LEFT JOIN Sales c
ON a.Item_Id = c.Item_ID
LEFT JOIN Inventory d
ON a.Item_ID = d.Item_ID

Please try this:
SELECT a.Item_Id, b.product_Name, c.Sales_Qty, d.Remaining_Qty
FROM ProductList a
LEFT JOIN ProductDetail b
ON a.Item_ID = b.Item_ID
LEFT JOIN Sales c
ON a.Item_Id = c.Item_ID
LEFT JOIN Inventory d
ON a.Item_ID = d.Item_ID
This will produce this output:
Item_Id product_Name Sales_Qty Remaining_Qty
---------------------------------------------------
0001 Eraser 15 100
0002 Pencil 20 95
0003 Pen NULL 55
0004 Mouse 50 NULL
If you don't want nulls to be returned, then use COALESCE (if your database is sql server, you can use ISNULL instead of COALESCE) as shown below:
SELECT a.Item_Id, b.product_Name, COALESCE(c.Sales_Qty, 0), COALESCE(d.Remaining_Qty, 0)
FROM ProductList a
LEFT JOIN ProductDetail b
ON a.Item_ID = b.Item_ID
LEFT JOIN Sales c
ON a.Item_Id = c.Item_ID
LEFT JOIN Inventory d
ON a.Item_ID = d.Item_ID
This will produce this output:
Item_Id Item_Name Sales_Qty Remaining_Qty
--------------------------------------------------
0001 Eraser 15 100
0002 Pencil 20 95
0003 Pen 0 55
0004 Mouse 50 0

Related

Retrieve all records if no record exist in the joining table

I have these three tables,
PO_HEADER
po_number
vendor_name
10001
Xyz
100002
ABC
PO_LINEITEM
line_number
po_number
item_quantity
recieved_quantity
0001
10001
20
10
0002
10001
80
10
0002
10002
40
35
SHIPMENT_LINEITEM
line_number
po_number
shipping_quant
0001
10001
20
How to retrieve order_master based on these two conditions
if any po_lineitem having item_quantity > recieved quantity.
if po_lineitem having item_quantity > (sum of previously shippingquantity from asn_lineitem for same line_number & poNumber) .2(b) if there no items in the asn_lineitem this should return true.
I wrote this query but was not able to achieve 2(b)
select count(*) from erp_po_header
where po_number in
(select erlitms.po_number from erp_po_line_items erlitms
JOIN
(select sum(shipping_quantity) as total_prev_shipped_items,po_number,item_number from
asn_lineitem
Group by po_number,item_number)
asn_items
ON erlitms.po_number = asn_items.po_number
and erlitms.item_number = asn_items.item_number
and erlitms.item_quantity > CAST (erlitms.received_quantity AS INTEGER)
and erlitms.item_quantity > asn_items.total_prev_shipped_items )

SQL join misses data from table

I have 2 tables
Purchases:
PUR# EID PID CID QTY PTIME TOTAL_PRICE
--------------------------------------------------------
100001 e01 p002 c001 1 12-AUG-17 211.65
100002 e01 p003 c001 1 20-SEP-17 118.4
100003 e02 p004 c002 5 08-OCT-17 4.95
100005 e04 p007 c004 1 15-OCT-17 119.2
100006 e03 p008 c001 1 12-OCT-17 349.3
100007 e03 p006 c003 2 10-SEP-17 35.91
Products
PID NAME QOH | QOH_THRESHOLD | ORIGINAL_PRICE DISCNT_RATE
----------------------------------------------------------------------------
p001 stapler 60 20 9.99 .1
p002 TV 6 5 249 .15
p003 camera 20 5 148 .2
p004 pencil 100 10 .99 0
p005 chair 10 8 12.98 .3
I have to find
What I am able to find is people who purchases just in date and give the count but I AM NOT ABLE TO SHOW THE PRODUCT COUNT AS 0 FOR THOSE WHO DINT PURCHASED ANYTHING IN date.
I want the output to show for all products
My Query:
select count(qty) as "noc", pd.pid, pd.name
from purchases p
inner join products pd on pd.pid = p.pid
where (to_char(p.ptime, 'Mon-YYYY')='Oct-2017'
AND p.qty =p.qty
By default inner joins only output rows that have a match. To keep rows without a match, you need a left join in this case:
SELECT COUNT(qty) AS noc, PD.pid, PD.name
FROM products PD LEFT JOIN purchases P
ON (PD.pid = P.pid AND P.ptime = 'OCT-17')
GROUP BY PD.pid, PD.name
ORDER BY noc DESC;
Demo: http://sqlfiddle.com/#!9/1f8e5f/15.
Further reading: A Visual Explanation of SQL Joins.

sql server 2005 wrong output

I have 3 table stock,inward,issue
Stock table's columns and data :
part_no | part_name | totalqty
10100 ciol 30
112233 abc 20
123456 coper 50
inward table :
part_no | qty
123456 10
123456 20
10100 20
112233 15
10100 25
issue table :
part_no | qty
112233 20
112233 15
123456 10
112233 25
10100 40
10100 20
my desired output :
part_no | part_name |inwardQty |issueQty
10100 coil 45 60
112233 abc 15 60
123456 coper 30 10
following is the query i have written,but not giving my desired output
select s.part_no,s.part_name,sum(i.qty) as inwardQty,sum(p.qty)as issueQty
from stock s
left join inward i on s.part_no = i.part_no
left join issue p on s.part_no = p.part_no
group by
s.part_no,s.part_name
getting following output by this query :
part_no | part_name |inwardQty |issueQty
10100 coil 90 120
112233 abc 45 60
123456 coper 30 20
The problem is that you're matching every row for inward with every row for issue, for which they're dealing with the same part. I think subqueries would be best here:
select s.part_no,s.part_name,i.qty as inwardQty,p.qty as issueQty
from stock s
left join
(select part_no,sum(qty) as qty from inward group by part_no) i on s.part_no = i.part_no
left join
(select part_no,sum(qty) as qty from issue group by part_no) p on s.part_no = p.part_no
So now, there's only one (or zero) rows to join in each of the joins, and you don't get a cartesian product.
Try this query:
SELECT
s.part_no, s.part_name,
InwardQty = (SELECT SUM(qty) FROM #inward i WHERE i.part_no = s.part_no),
IssueQty = (SELECT SUM(qty) FROM #issue p WHERE p.part_no = s.part_no)
FROM
dbo.stock s
GROUP BY
s.part_no, s.part_name
Gives me exactly your desired output.

SQL Problem : Query

I have an issue in query. I have tables product, stockRecord and priceDetail. I want to display all products. If the price is not defined in priceDetail for that product, then it will be 0.00; similarly if the quantity is not defined in stockRecord table, then the quantity should be 0.
But if the price is defined in the priceDetail table, then we should get the latest price from the table
WMProduct
BusinessUnit ProductCode Description SalableFlag
MASS 0001 Pen 1
MASS 0002 Computer 1
MASS 0003 Book 1
MASS 0004 Bottle 1
WMStockRecord
ProductCode AvailableQuantity
0001 10
0003 15
WMPriceDetail
ProductCode DateFrom DateTo Price
0001 10-10-2009 10-10-2011 100
0001 10-12-2009 10-10-2010 80
0001 12-12-2010 01-12-2011 120
0002 12-01-2010 '' 200
0004 12-12-2010 12-05-2011 100
I need list of products like this:
BusinessUnit ProductCode Description SalableFlag Price AvailableQuantity
MASS 0001 Pen 1 120 10
MASS 0002 Computer 1 200 0
MASS 0003 Book 1 0.00 15
MASS 0004 Bottle 1 0.00 0
Try using sub query and left join like below :
SELECT P.ProductCode AS ProductCode,
P.Description AS ProductName,
P.SalableFlag AS Salable,
ISNULL(STK.AvailableQuantity, 0) AS Qty,
ISNULL((SELECT TOP 1 Price FROM WMPriceDetail
WHERE ProductCode = P.ProductCode ORDER BY DateTo DESC), 0) AS Price
FROM WMProduct P
LEFT JOIN WMStockRecord STK ON P.ProductCode = STK.ProductCode

Multiple Join Multipliers

I have 3 tables: Insurance Policies, Claims and Receivables
I need a query that will return one row per policy period per policy. The query needs to include the policy start and end date, total claims for each period, total paid and O/S for each period, and total amount received for each period.
I've managed to do everything but the recievables. When this is introduced to the query, everything is multiplied by the number of rows in that table.
Here is my data
Policies
PolNo Version TransType InceptionDate RenewalDate
0021 0 New 01/01/2008 01/01/2009
0021 1 MTA 01/01/2008 01/01/2009
0021 2 MTA 01/01/2008 01/01/2009
0021 3 Renewal 01/01/2009 01/01/2010
Claims
PolNo ClaimNo ClaimDate Paid Outstanding
0021 0001 01/05/2008 300.00 -100.00
0021 0002 01/06/2008 500.00 200.00
0021 0003 01/07/2008 200.00 300.00
0021 0004 01/08/2008 800.00 0.00
0021 0005 01/02/2009 0.00 0.00
0021 0006 01/10/2009 0.00 1000.00
Receivables
PolNo Version RecvdDate Amount
0021 0 02/01/2008 150.00
0021 0 01/02/2008 150.00
0021 0 01/03/2008 150.00
0021 0 01/04/2008 150.00
0021 0 01/05/2008 150.00
0021 0 01/06/2008 150.00
0021 0 01/07/2008 150.00
0021 0 01/08/2008 150.00
0021 2 01/09/2008 150.00
0021 2 01/10/2008 150.00
0021 3 02/01/2009 500.00
0021 3 01/02/2009 500.00
Here is my working query
select distinct(a.InceptionDate) as InceptionDate, a.RenewalDate as RenewalDate,
count(b.ClaimNo) as ClaimCount, sum(b.Paid) as TotPaid, sum(b.Outstanding) as TotalO/S
from Policies a, Claims b
where a.PolNo='0021'
and a.PolNo=b.PolNo
and b.ClaimDate between a.InceptionDate and a.RenewalDate
and a.TransType in ('New','Renewal')
group by a.InceptionDate, a.RenewalDate
Result:
InceptionDate RenewalDate ClaimCount TotPaid TotalO/S
01/01/2008 01/01/2009 4 1800.00 400.00
01/01/2009 01/01/2010 2 0 1000.00
I had to add TransType to the query as I was getting a multiplier for claims data, but this query works.
Now when I add the third table, I get a multiplier. Everything from Claims is multiplied by the number or rows in Receivables for the period, and AmountRecvd is multiplied by the number of rows in Claims for the period.
Here is the query:
select distinct(a.InceptionDate) as InceptionDate, a.RenewalDate as RenewalDate,
count(b.ClaimNo) as ClaimCount, sum(b.Paid) as TotPaid, sum(b.Outstanding) asTotalO/S,
sum(c.Amount) as RecvdAmount
from Policies a, Claims b, Receivables c
where a.PolNo='0021'
and a.PolNo=b.PolNo
and a.PolNo=c.PolNo
and b.ClaimDate between a.InceptionDate and a.RenewalDate
and c.RecvdDate between a.InceptionDate and a.RenewalDate
and a.TransType in ('New','Renewal')
group by a.InceptionDate, a.RenewalDate
Result
InceptionDate RenewalDate ClaimCount TotPaid TotalO/S AmountRecvd
01/01/2008 01/01/2009 40 18000 4000 6000.00
01/01/2009 01/01/2010 20 0 10000 2000.00
I cant see that it is possible to join Receivables with Claims. I tried joining them on PolNo but had the same result.
Can anyone see a solution?
Cheers
Updated This query doesn't muliply ClaimsCount, but AmountRevd still multiplying by Claims (TotPaid removed for simplicity):
SELECT
p.InceptionDate,
p.RenewalDate,
sum(c1.ClaimCount) AS ClaimsCount,
sum(r1.TotRecvd) AS AmountRecvd
FROM Policies p
LEFT JOIN (SELECT
p1.InceptionDate,
p1.RenewalDate,
c.Polno,
c.ClaimDate,
COUNT(c.SubCount) AS ClaimCount
FROM Policies p1
INNER JOIN (SELECT
PolNo,
ClaimDate,
Count(*) as SubCount
FROM Claims
GROUP BY PolNo, ClaimDate) c
ON p1.PolNo=c.PolNo
WHERE c.ClaimDate BETWEEN p1.InceptionDate AND p1.RenewalDate
AND p1.TransType IN ('New','Renewal')
GROUP BY p1.InceptionDate, p1.RenewalDate, c.Polno, c.ClaimDate) c1
ON p.PolNo=c1.PolNo
LEFT JOIN (SELECT
p2.InceptionDate,
p2.RenewalDate,
r.Polno,
SUM(r.SubTot) AS TotalRecvd
FROM Policies p2
INNER JOIN (SELECT
PolNo,
RecvdDate,
SUM(Amount) as SubTot
FROM Receivables
GROUP BY Polno,RecvdDate) r
ON p2.PolNo=r.PolNo
WHERE r.RecvdDate BETWEEN p2.InceptionDate AND p2.RenewalDate
AND p2.TransType IN ('New','Renewal')
GROUPBY p2.InceptionDate, p2.RenewalDate, r.Polno) r1
ON p.PolNo=r1.PolNo
WHERE p.PolNo = '0021'
AND p.TransType IN ('New','Renewal')
AND p.PolNo = c1.PolNo
AND p.PolNo = r1.PolNo
AND p.InceptionDate = c1.InceptionDate
AND p.RenewalDate = c1.RenewalDate
AND p.InceptionDate = r1.InceptionDate
AND p.RenewalDate = r1.RenewalDate
GROUP BY p.InceptionDate, p.RenewalDate
-- Query for the periods:
WITH Periods AS (
SELECT DISTINCT
PolNo, InceptionDate, RenewalDate
FROM Policies
WHERE TransType in ('New','Renewal')
),
-- Query for the claims
PeriodClaims AS (
SELECT
p.PolNo, p.InceptionDate, p.RenewalDate,
COUNT(*) AS CountClaims,
SUM(c.Paid) AS PaidClaims,
SUM(c.Outstanding) AS OutstandingClaims
FROM Periods p
INNER JOIN Claims c ON c.PolNo = p.PolNo
WHERE c.ClaimDate BETWEEN p.InceptionDate AND p.RenewalDate
GROUP BY p.PolNo, p.InceptionDate, p.RenewalDate
),
-- Query for the receivables
PeriodRecieved AS (
SELECT
p.PolNo, p.InceptionDate, p.RenewalDate,
COUNT(*) AS CountReceived,
SUM(r.Amount) AS AmountReceived
FROM Periods p
INNER JOIN Receivables r ON r.PolNo = p.PolNo
WHERE r.RecvdDate BETWEEN p.InceptionDate AND p.RenewalDate
GROUP BY p.PolNo, p.InceptionDate, p.RenewalDate
)
-- All together now
SELECT
p.PolNo, p.InceptionDate, p.RenewalDate,
c.CountClaims, c.PaidClaims, c.OutstandingClaims,
r.CountReceived, r.AmountReceived
FROM Periods p
LEFT JOIN PeriodClaims c
ON c.PolNo = p.PolNo
AND c.InceptionDate = p.InceptionDate
AND c.RenewalDate = p.RenewalDate
LEFT JOIN PeriodRecieved r
ON r.PolNo = p.PolNo
AND r.InceptionDate = p.InceptionDate
AND r.RenewalDate = p.RenewalDate
Or, without CTE:
SELECT
p.PolNo, p.InceptionDate, p.RenewalDate,
c.CountClaims, c.PaidClaims, c.OutstandingClaims,
r.CountReceived, r.AmountReceived
FROM (
-- Query for the periods:
SELECT DISTINCT
PolNo, InceptionDate, RenewalDate
FROM Policies
WHERE TransType in ('New','Renewal')
) p
LEFT JOIN (
-- Query for the claims
SELECT
p.PolNo, p.InceptionDate, p.RenewalDate,
COUNT(*) AS CountClaims,
SUM(c.Paid) AS PaidClaims,
SUM(c.Outstanding) AS OutstandingClaims
FROM (
-- Query for the periods:
SELECT DISTINCT
PolNo, InceptionDate, RenewalDate
FROM Policies
WHERE TransType in ('New','Renewal')
) p
INNER JOIN Claims c ON c.PolNo = p.PolNo
WHERE c.ClaimDate BETWEEN p.InceptionDate AND p.RenewalDate
GROUP BY p.PolNo, p.InceptionDate, p.RenewalDate
) c
ON c.PolNo = p.PolNo
AND c.InceptionDate = p.InceptionDate
AND c.RenewalDate = p.RenewalDate
LEFT JOIN (
-- Query for the receivables
SELECT
p.PolNo, p.InceptionDate, p.RenewalDate,
COUNT(*) AS CountReceived,
SUM(r.Amount) AS AmountReceived
FROM (
-- Query for the periods:
SELECT DISTINCT
PolNo, InceptionDate, RenewalDate
FROM Policies
WHERE TransType in ('New','Renewal')
) p
INNER JOIN Receivables r ON r.PolNo = p.PolNo
WHERE r.RecvdDate BETWEEN p.InceptionDate AND p.RenewalDate
GROUP BY p.PolNo, p.InceptionDate, p.RenewalDate
) r
ON r.PolNo = p.PolNo
AND r.InceptionDate = p.InceptionDate
AND r.RenewalDate = p.RenewalDate
Output (transposed):
PolNo 21 21
InceptionDate 2008-01-01 2009-01-01
RenewalDate 2009-01-01 2010-01-01
CountClaims 4 2
PaidClaims 1800.00 0.00
OutstandingClaims 400.00 1000.00
CountReceived 10 2
AmountReceived 1500.00 1000.00