How get data from 3 tables? - sql

I have 3 tables
collecton, paymentdata, payment
Payment table is computed table and it has only one product data
So, rcvamt and restamt get from payment table
I have following data
Collection:
id(PK) clientid company Client product total note
1 2001 Company1 Client1 Product1 50000 note1
2 2002 Company2 Client2 Product2 60000 note2
3 2003 Company3 Client3 Product3 70000 note3
PaymentData:
wid(PK)wcid(FK) clientid product rcvamt restamt rcvdate nxtdate Note
1 1 2001 Product1 500 49500 10-1-2015 11-2-2015 abc1
2 1 2001 Product1 800 48700 11-2-2015 12-3-2015 xyz1
3 2 2002 Product2 1500 58500 5-3-2015 6-4-2015 qwe1
Payment
id(PK) wid(FK) clientid product rcvamt restamt
1 2 2001 Product1 1300 48700
2 3 2002 Product2 1500 58500
I want to show a report like
clientid company procudt total rcvamt restamt rcvdate nxtdate note
2001 Company1 Product1 50000 1300 48700 11-2-2015 12-3-2015 xyz1
2002 Company2 Product2 60000 1500 58500 5-3-2015 6-4-2015 qwe1
2003 Company3 Product3 70000 - - - - -

I tried to make it simple:
SELECT DISTINCT
C.clientid
, C.company
, C.product
, C.total
, P.rcvamt
, P.restamt
, ( SELECT TOP 1 rcvdate FROM PaymentData AS PD1 WHERE PD1.ClientID=PD.ClientID AND PD1.Product=PD.Product ORDER BY rcvdate DESC)
, ( SELECT TOP 1 nxtdate FROM PaymentData AS PD1 WHERE PD1.ClientID=PD.ClientID AND PD1.Product=PD.Product ORDER BY rcvdate DESC)
, ( SELECT TOP 1 Note FROM PaymentData AS PD1 WHERE PD1.ClientID=PD.ClientID AND PD1.Product=PD.Product ORDER BY rcvdate DESC)
FROM
Collection C
LEFT OUTER JOIN Payment P
ON C.clientid = P.clientid
LEFT OUTER JOIN PaymentData PD
ON P.clientid = PD.clientid
But I don't know all the relationships between the tables.

The Answer to your Question could look like this
Select Collection.clientid
,Collection.company
,Collection.product
,Collection.total
,Payment.rcvamt
,Payment.restamt
,PaymentData.rcvdate
,PaymentData.nxtdate
,PaymentData.Note
From PaymentData
Inner Join (Select wcid
,Max(PaymentData.rcvdate) as rcvdate
,Max(PaymentData.nxtdate) as nxtdate
FROM PaymentData
GROUP BY wcid) AS SubSelect ON PaymentData.wcid = SubSelect.wcid
AND PaymentData.rcvdate = SubSelect.rcvdate
AND PaymentData.nxtdate = SubSelect.nxtdate
Inner Join Payment on PaymentData.wcid = Payment.id
RIGHT OUTER JOIN Collection ON PaymentData.clientid = Collection.clientid
Here the sqlfiddle to prove my Answer.

Something like this should work. It appears you want an aggregation on the restamt, both other fields are the last payment received. I also assume this is SQL Server due to your name. If it's a different db, please provide the
UPDATE: Changed to LEFT JOIN to handle client 3 without products, fixed typo in product. SQL Fiddle: http://sqlfiddle.com/#!3/8ad566/19/0
SELECT
c.clientid,
c.company,
c.product,
c.total,
SUM(pd.rcvamt) AS rcvamt,
LastPayment.restamt,
LastPayment.rcvdate,
LastPayment.nxtDate,
LastPayment.note
FROM Collection c
LEFT OUTER JOIN PaymentData pd
ON pd.wcid = c.id
LEFT OUTER JOIN (
SELECT
wcid,
restamt,
rcvdate,
nxtdate,
Note,
ROW_NUMBER() OVER (PARTITION BY wcid ORDER BY rcvdate DESC) AS RowNum
FROM PaymentData
) LastPayment
ON LastPayment.wcid = c.id
AND LastPayment.RowNum = 1 -- Get last payment info
GROUP BY
c.clientid,
c.company,
c.product,
c.total,
LastPayment.restamt,
LastPayment.rcvdate,
LastPayment.nxtDate,
LastPayment.note
ORDER BY
c.clientid

Related

How to apply join on tables while using having function?

There are two tables - trans and customer.
trans
customerid
pdate
purchase
1
11-01-2021
200
2
13-02-2021
400
1
18-01-2021
400
3
31-01-2021
600
4
23-03-2021
700
customer
customerid
firstname
lastname
1
raj
sharma
2
rahul
dev
3
riya
sen
4
rose
menon
The question is -
Find the firstname, lastname and sum of the purchase of the customers where sum of the purchase is greater than 500 in the month of January (Without using any CTE).
My take on this was -
SELECT
c.firstname,
c.lastname,
SUM( t.purchase )
FROM
customer c
INNER JOIN trans t ON c.id = t.id
GROUP BY
c.firstname,
c.lastname
HAVING
SUM( t.purchase ) > 500;
But this ignores the customers with id 1. The customerid 1 has made a purchase twice and the sum of his purchase is greater than 500.
I am using PostgreSQL.

SQL Query to get value of recent order alongwith data from other tables

I am writing an SQL query to get data from more than 3 tables, but for simplifying the question here I am using a similar scenario with 3 tables.
Table1 Customer (PK-CustomerID, Name)
CustomerID
Name
1
John
2
Tina
3
Sam
Table2 Sales (FK-Id, SalePrice)
ID
SalePrice
1
200.00
2
300.00
3
400.00
Table3 Order (PK-Id, FK-CustomerID, Date, Amount)
Id
CustomerID
Date
Amount
101
1
25-09-2021
30.0
102
1
27-09-2021
40.0
103
2
19-09-2021
60.0
In the output, Date and Amount should be the from most recent Order (latest Date), for a customer
My approach was
Select c.CustomerID, c.Name, s.SalePrice, RecentOrder.Date, RecentOrder.Amount from
Customer as c
LEFT JOIN Sales s ON c.CustomerID = s.ID
LEFT JOIN (SELECT top 1 o.Date, o.Amount, o.CustomerID
FROM Order o, Customer c1 WHERE c1.CustomerID = o.CustomerID ORDER BY o.Date DESC)
RecentOrder ON c.CustomerID = RecentOrder.CustomerID
Output I get
CustomerID, Name, SalePrice, Date, Amount
CustomerID
Name
SalePrice
Date
Amount
1
John
200.00
27-09-2021
40.0
2
Tina
300.00
null
null
3
Sam
400.00
null
null
The output I get includes the most recent order out of all the orders. But I want to get the recent order out of the orders made by that customer
Output Required
CustomerID, Name, SalePrice, Date, Amount
CustomerID
Name
SalePrice
Date
Amount
1
John
200.00
27-09-2021
40.0
2
Tina
300.00
19-09-2021
60.0
3
Sam
400.00
null
null
Instead of subquery in left join, you can check with outer apply.
Check following way
Select c.CustomerID, c.Name, s.SalePrice, RecentOrder.Date, RecentOrder.Amount
from Customer c
LEFT JOIN Sales s ON c.CustomerID = s.ID
OUTER APPLY (
SELECT top 1 o.Date, o.Amount, o.CustomerID
FROM [Order] o
WHERE o.CustomerID = c.CustomerID ORDER BY o.Date DESC) RecentOrder`
You need to pre-aggregate or identify the most recent order for each customer order, your query is selecting 1 row for all orders.
Try the following (untested!)
select c.CustomerID, c.Name, s.SalePrice, o.Date, o.Amount
from Customer c
left join Sales s on c.CustomerID = s.ID
outer apply (
select top (1) date, amount
from [order] o
where o.CustomerId=c.CustomerId
order by Id desc
)o

SQL MAX aggregate function not bringing the latest date

Purpose: I am trying to find the max date of when the teachers made a purchase and type.
Orders table
ID
Ordertype
Status
TeacherID
PurchaseDate
SchoolID
TeacherassistantID
1
Pencils
Completed
1
1/1/2021
1
1
2
Paper
Completed
1
3/5/2021
1
1
3
Notebooks
Completed
1
4/1/2021
1
1
4
Erasers
Completed
2
2/1/2021
2
2
Teachers table
TeacherID
Teachername
1
Mary Smith
2
Jason Crane
School table
ID
schoolname
1
ABC school
2
PS1
3
PS2
Here is my attempted code:
SELECT o.ordertype, o.status, t.Teachername, s.schoolname
,MAX(o.Purchasedate) OVER (PARTITION by t.ID) last_purchase
FROM orders o
INNER JOIN teachers t ON t.ID=o.TeacherID
INNER JOIN schools s ON s.ID=o.schoolID
WHERE o.status in ('Completed','In-progress')
AND o.ordertype not like 'notebook'
It should look like this:
Ordertype
Status
teachername
last_purchase
schoolname
Paper
Completed
Mary Smith
3/5/2021
ABC School
Erasers
Completed
PS1
2/1/2021
ABC school
It is bringing multiple rows instead of just the latest purchase date and its associated rows. I think i need a subquery.
Aggregation functions are not appropriate for what you are trying to do. Their purpose is to summarize values in multiple rows, not to choose a particular row.
Just a window function does not filter any rows.
You want to use window functions with filtering:
SELECT ordertype, status, Teachername, schoolname, Purchasedate
FROM (SELECT o.ordertype, o.status, t.Teachername, s.schoolname,
o.Purchasedate,
ROW_NUMBER() OVER (PARTITION by t.ID ORDER BY o.PurchaseDate DESC) as seqnum
FROM orders o JOIN
teachers t
ON t.ID = o.TeacherID
schools s
ON s.ID = o.schoolID
WHERE o.status in ('Completed', 'In-progress') AND
o.ordertype not like 'notebook'
) o
WHERE seqnum = 1;
You can use it in different way. it's better to use Group By for grouping the other columns and after that use Order by for reorder all records just like bellow.
SELECT top 1 o.ordertype, o.status, t.Teachername, s.schoolname
,o.Purchasedate
FROM orders o
INNER JOIN teachers t ON t.ID=o.TeacherID
INNER JOIN schools s ON s.ID=o.schoolID
having o.status in ('Completed','In-progress')
AND o.ordertype not like 'notebook'
group by o.ordertype, o.status, t.Teachername, s.schoolname
order by o.Purchasedate Desc

How to get all products from one order to the list

I have written a query that returns data, here is my code
SELECT o.Id, p.ProductName, po.Quantity, p.Price, DeliveryMethod,
OrderDate, TotalSum, u.UserName FROM [Order] o
JOIN ProductsOrders po ON o.Id = po.OrderId
JOIN Product p ON po.ProductId = p.Id
JOIN Users u ON o.UserId = u.Id
ORDER BY o.Id
And it returns next:
OrderId ProductName Quantity Price DeliveryMethod OrderDate TotalSum UserName
98 Bed3 1 3000 Express 2018-08-04 7015 Ivan
98 Bed4 1 4000 Express 2018-08-04 7015 Ivan
100 Bed2 1 2000 2018-08-05 2000 Ivan
101 Bed2 1 2000 2018-08-05 5000 Ivan
101 Bed3 1 3000 2018-08-05 5000 Ivan
102 Bed0 1 0 Standard 2018-09-04 1005 Ivan
We can notice that for each product - one record
But I want to group all products by one order and get something like that:
- orderId
- deliveryMethod
- userName
- product1 quantity price
- ...
- productN quantity price
- totalAmount
101
Courier
John Doe
Black bag 1 1500
Fat Bike 1 5000
Thermos bottle 5 200
Total amount 7500
How can I modify the query?
The proper way to do this, IMO, would be to select 2 datasets. First dataset containing the parent Order data, and the second containing the individual ProductsOrders (product line items) for the Orders in the first dataset.
-- Select Orders
SELECT
[o].[Id] AS [OrderId]
,[o].[DeliveryMethod]
,[o].[OrderDate]
,[u].[UserName]
FROM [Order] [o]
INNER JOIN [Users] [u] ON [o].[UserId] = [u].[Id]
WHERE
[o].[Id] IN(SomeRangeOfOrderIds) -- (Or however you'd like to filter the results)
-- Select Products (product line items)
SELECT
[p].[ProductName]
,[po].[Quantity]
,[p].[Price]
FROM [ProductsOrders] [po]
INNER JOIN [Product] [p] ON [po].[ProductId] = [p].[Id]
WHERE
[po].[OrderId] IN(SameRangeOfOrderIdsAsTheQueryAbove)
...then take those results and display them however you'd like. Will this be appearing in a report? Or on a web page?
I have just implemented this issue in LINQ. Should have noticed that there is many-to-many relationship
var orders = db.Orders.Select(o => new
{
o.Id,
o.DeliveryMethod,
o.OrderDate,
o.UserId,
o.TotalSum,
Products = o.ProductsOrders.Select(p => new { p.Product.ProductName, p.Quantity, p.Product.Price}).ToList()
}).ToList();

stock query not show exact result

I use this query to maintain my stock but its not show exact result
select p.Product_Name Product
,isnull(sum(d.qty),0) Purchase_Qty
,isnull(sum(i.qty),0) Issue_Qty
,(isnull(sum(d.qty),0)-isnull(sum(i.qty),0)) InStock
from purchase_dtl d
left join issue_dpt i on i.Product_ID=d.Product_ID
right join product p on p.id = d.Product_ID
group by Product_Name
Query result
Product | Purchase_Qty | Issue_Qty | InStock
---------------------------------------------
Pen 1000 300 700
Books 4000 1000 3000
My exact purchase qty
Product | Purchase_Qty
----------------------
Pen 500
Books 2000
My exact issue qty
Product | Issue_Qty
-------------------
Pen 300
Books 1000
Please help me to solve my problem
Thanks
select p.Product_Name Product
, p.Purchase_Qty
, isnull(sum(i.qty),0) Issue_Qty
, p.Purchase_Qty-isnull(sum(i.qty),0) InStock
from (select p.id, p.Product_Name, isnull(sum(d.qty),0) Purchase_Qty
from product p left join purchase_dtl d on p.id = d.Product_ID
group by p.id, p.Product_Name) p
left join issue_dpt i on i.Product_ID = p.id
group by Product_Name, p.Purchase_Qty
I suppose joining purchase_dtl and issue_dpt gives you some extra rows for Purchase_Qty
Join product with purchase_dtl first to calculate the aggregate data and then join again with issue_dpt