Return details of the latest bill linked to the user - sql

I have two different sources of information and I am trying to marry them together to get information relating to a customer and their last bill. I have managed to get details of each customer and their max billing period end date but I am unsure as to how I can then get the details from the associated bill. I have the following query:
SELECT new_mprnnumber,
new_customernumber,
MAX(b.billingPeriodEndDate) as 'Billed up to date'
FROM [CRM].[crm4_MSCRM].[dbo].[AccountExtensionBase] as a
inner join Billing.dbo.bill as b
on a.new_mprnnumber = b.MPRN
where new_accountstage = 7
and new_accounttype = 2
group by new_mprnnumber,
new_customernumber
GO
The bill has fields like amount due etc but I only want to return details of those from the max dated bill, any help would be greatly appreciated

Use a CTE with row_number()
with CTE as
(
select a.new_mprnnumber,
a.new_customernumber,
b.*,
row_number()
over (partition by new_customernumber -- add additional partitions as you would group bys
order by billingPeriodEndDate desc) as r_ord
from AccountExtensionBase a
inner join bill b
on a.new_mprnnumber = b.MPRN
where new_accountstage = 7
and new_accounttype = 2
)
select *
from CTE
where r_ord = 1

Put your query into a CTE and then link back to table bill:
WITH CTE AS (
SELECT new_mprnnumber,
new_customernumber,
MAX(b.billingPeriodEndDate) as MaxBillDate
FROM [CRM].[crm4_MSCRM].[dbo].[AccountExtensionBase] as a
inner join Billing.dbo.bill as b
on a.new_mprnnumber = b.MPRN
where new_accountstage = 7
and new_accounttype = 2
group by new_mprnnumber,
new_customernumber
)
SELECT b.*
FROM CTE c
INNER JOIN Billing.dbo.bill b ON c.MaxBillDate = b.billingPeriodEndDate AND c.new_mprnnumber = b.MPRN

Related

SQL how to retrieve latest result from each joined table

I would like to retrieve one large table of products with the latest rows from all the joined tables via with MAX(ID) of each group (productToken) which ich unique name of the product. Joined tables are - products (store), availability (status), description (products), and price of the product. All of them contains the unique productToken and the mentioned tables can be changed over time by adding a new record (independently) so my aim is to compose one big table (with actual info about the products) via retrieving the lastest record from each table. My code is this. First added product worked well, but things got strange after adding new records to any of the tables (query has retrieved no results).
SELECT *
FROM products
JOIN productsStore ON products.productToken = productStore.productToken
JOIN productsStatus ON products.productToken = productsStatus.productToken
JOIN productsPrice ON products.produstToken = productsPrice.productToken
JOIN categories ON products.categoryToken = categories.categoryToken
WHERE products.shopToken = '$shopToken'
AND products.productID IN
(SELECT MAX(productID)
FROM products
GROUP BY productToken)
AND productsPrice.productPriceID IN
(SELECT MAX(productPriceID)
FROM productsPrice
GROUP BY produktToken)
AND productsStatus.productStatusID IN
(SELECT MAX(productStatusID)
FROM productsStatus
GROUP BY productToken)
AND produktyStore.productStoreID IN
(SELECT MAX(productStoreID)
FROM productsStore
GROUP BY productToken)
AND categories.categoryID IN
(SELECT MAX(categoryID)
FROM categories
GROUP BY categoryToken)
ORDER BY categories.categoryID DESC
I would like to retrieve one large table of products with the latest rows from all the joined tables
I think that you want equality conditions with correlated subqueries in the where clause rather than in conditions with aggregate queries. This lets you filter each joined table with the "latest" record for the given productToken.
SELECT *
FROM products p
JOIN productsStore psr ON psr.productToken = p.productToken
JOIN productsStatus psu ON psu.productToken = p.productToken
JOIN productsPrice ppr ON ppr.produstToken = p.productToken
JOIN categories c ON c.categoryToken = p.categoryToken
WHERE
p.shopToken = '$shopToken'
AND p.productID = (SELECT MAX(p1.productID) FROM products p1 WHERE p1.productToken = p.productToken)
AND psr.productStoreID = (SELECT MAX(psr1.productStoreID) FROM productsStore psr1 WHERE psr1.productToken = p.productToken)
AND psu.productStatusID = (SELECT MAX(psu1.productStatusID) FROM productStatus psu1 WHERE psu1.productToken = p.productToken)
AND ppr.productPriceID = (SELECT MAX(ppr1.productPriceID) FROM productsPrice ppr1 WHERE ppr1.productToken = p.productToken)
AND c.categoryID = (SELECT MAX(c1.categoryID) FROM category c1 WHERE c1.productToken = p.productToken)
If you are running MySQL 8.0 (or MariaDB 10.3 or higher), you can use ROW_NUMBER() in subqueries instead:
SELECT *
FROM (
SELECT p.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productID DESC) rn
FROM products p
) p
INNER JOIN (
SELECT psr.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productStoreID DESC) rn
FROM productsStore psr
) psr ON psr.productToken = p.productToken AND psr.rn = 1
INNER JOIN (
SELECT psu.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productStatusID DESC) rn
FROM productsStatus psu
) psu ON psu.productToken = p.productToken AND psu.rn = 1
INNER JOIN (
SELECT ppr.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productsPriceID DESC) rn
FROM productsPrice ppr
) ppr ON ppr.productToken = p.productToken AND ppr.rn = 1
INNER JOIN (
SELECT c.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY categoryID DESC) rn
FROM categories c
) c ON c.productToken = p.productToken AND c.rn = 1
WHERE p.shopToken = '$shopToken' AND p.rn = 1

I have problem in getting the min of column name TRANS the required output should be TOWN_HALL and 2 [duplicate]

This question already has answers here:
How do I limit the number of rows returned by an Oracle query after ordering?
(14 answers)
Closed 3 years ago.
SELECT
BRANCH_ADD,
COUNT(TRANS_AMOUNT) AS TRANS
FROM
(SELECT
A.BRANCH_ADD, C.TRANS_AMOUNT
FROM
BRANCHES A, ACCTS B, TRANSACTION C
WHERE
a.branch_code = b.branch_code
AND b.acct_no = c.acct_no
ORDER BY
BRANCH_ADD)
GROUP BY
BRANCH_ADD;
Output of the above query :
as text :
BRANCH_ADD TRANS
------------ ------
TOWN_HALL 2
CHAMRAJPET 4
CITY_MARKET 4
You need some subquery and filter for the count = to max
SELECT BRANCH_ADD, my_count AS max_value
FROM (
SELECT
A.BRANCH_ADD
, count(C.TRANS_AMOUNT ) my_count
FROM BRANCHES A
INNER JOIN ACCTS B ON a.branch_code=b.branch_code
INNER JOIN TRANSACTION C ON b.acct_no=c.acct_no
GROUP BY A.BRANCH_ADD;
)
WHERE my_count = (
select max(my_count)
from (
SELECT
A.BRANCH_ADD
, count(C.TRANS_AMOUNT ) my_count
FROM BRANCHES A
INNER JOIN ACCTS B ON a.branch_code=b.branch_code
INNER JOIN TRANSACTION C ON b.acct_no=c.acct_no
GROUP BY A.BRANCH_ADD;
)
)
Use ROW_NUMBER() to return the 1st row only:
SELECT t.BRANCH_ADD, t.TRANS FROM (
SELECT A.BRANCH_ADD, COUNT(C.TRANS_AMOUNT) TRANS,
ROW_NUMBER() OVER (ORDER BY COUNT(C.TRANS_AMOUNT)) rn
FROM BRANCHES A
INNER JOIN ACCTS B ON A.BRANCH_CODE = B.BRANCH_CODE
INNER JOIN TRANSACTION C ON B.ACCT_NO = C.ACCT_NO
GROUP BY BRANCH_ADD
) t
WHERE t.rn = 1
If you are using Oracle version 12+ you can also do it with FETCH:
SELECT A.BRANCH_ADD, COUNT(C.TRANS_AMOUNT) TRANS
FROM BRANCHES A
INNER JOIN ACCTS B ON A.BRANCH_CODE = B.BRANCH_CODE
INNER JOIN TRANSACTION C ON B.ACCT_NO = C.ACCT_NO
GROUP BY BRANCH_ADD
ORDER BY TRANS
FETCH FIRST 1 ROWS ONLY
You can use analytical functions
such as MIN(..) KEEP (DENSE_RANK FIRST ORDER BY ..) OVER (PARTITION BY ..):
SELECT * FROM
(
SELECT A.BRANCH_ADD, C.TRANS_AMOUNT,
MIN(C.TRANS_AMOUNT)
KEEP (DENSE_RANK FIRST ORDER BY C.TRANS_AMOUNT)
OVER (PARTITION BY 0) AS lowest
FROM BRANCHES A
JOIN ACCTS B ON B.branch_code = A.branch_code
JOIN TRANSACTION C ON C.acct_no = B.acct_no
)
WHERE TRANS_AMOUNT = lowest

Getting Latest 3 orders by Supplier ID

I have the following SQL Server code to get information from a combination of 4 tables.
I would like to modify it to only retrieve the latest 3 orders (pmpOrderDate) by supplier (pmpSupplierOrganizationID).
SELECT
PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName
FROM
PurchaseOrders PO
INNER JOIN
PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
INNER JOIN
Organizations O ON PO.pmpSupplierOrganizationID = O.cmoOrganizationID
INNER JOIN
Parts P ON POL.pmlPartID = P.impPartID
WHERE
P.impPartClassID LIKE 'PUMP%'
Can you please help?
EDIT:
I wasn't fully clear on my actual requirements. To clarify further, what I need in the end is to display the latest 3 unique Purchase Orders by Supplier ID based on at least one of the PartClassID for the PartID in the PurchaseOrderLines to have criteria of beginning with string 'PUMP'
Use a ROW_NUMBER to partition by pmpSupplierOrganizationID and order by pmpOrderDate.
with cteTopOrders AS (
SELECT PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName,
ROW_NUMBER() OVER(PARTITION BY pmpSupplierOrganizationID ORDER BY pmpOrderDate DESC) AS RowNum
FROM PurchaseOrders PO
Inner Join PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
Inner Join Organizations O On PO.pmpSupplierOrganizationID = O.cmoOrganizationID
Inner Join Parts P ON POL.pmlPartID = P.impPartID
WHERE P.impPartClassID Like 'PUMP%'
)
SELECT pmpPurchaseOrderID, pmpOrderDate, pmpSupplierOrganizationID, cmoName
FROM cteTopOrders
WHERE RowNum <= 3;
I'm a fan of lateral joins for this . . . cross apply:
select p.*, O.cmoName
from Organizations O cross apply
(select top (3) PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID
from PurchaseOrders PO join
PurchaseOrderLines POL
on PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID join
Parts P
on POL.pmlPartID = P.impPartID
where PO.pmpSupplierOrganizationID = O.cmoOrganizationID and
P.impPartClassID Like 'PUMP%'
order by PO.pmpOrderDate desc
) p
You need a nested row_number to get the three rows per supplier and another OLAP-function on top of it:
with OrderRowNum as
(
SELECT PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName, P.impPartClassID,
row_number()
over (partition by PO.pmpSupplierOrganizationID
order by pmpOrderDate desc) as rn
FROM PurchaseOrders PO
Inner Join PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
Inner Join Organizations O On PO.pmpSupplierOrganizationID = O.cmoOrganizationID
Inner Join Parts P ON POL.pmlPartID = P.impPartID
)
, CheckPUMP as
(
select *,
-- check if at least one of the three rows contains PUMP
max(case when impPartClassID Like 'PUMP%' then 1 else 0 end)
over (partition by PO.pmpSupplierOrganizationID) as PUMPflag
from OrderRowNum
where rn <= 3 -- get the last three rows per supplier
)
select *
from CheckPUMP
where flag = 1

Query in SQL Server 2014 for a report (I need the last ROW of a table)

I'm using SQL Server 2014 and I have a problem with a query.
I want to have in my report, ALL the items of the order with ID_Order = 9 that have been delivered. And for the items that have been delivered at two times (Item Code = Art3 for example), I just want to have the last row, that means the last delivery of this Item, with NO repetition.
I already tried these two queries without success:
Attempt #1: DISTINCT
SELECT DISTINCT
Order.ItemCode, Delivery. Qty, Delivery.ID_Delivery,
Order.ID_Order
FROM
Delivery
INNER JOIN
Order ON Order.ID_Order = Delivery.ID_Order
WHERE
Order.ID_Order = '9'
Attempt #2: subquery
SELECT *
FROM
(SELECT
Order.ItemCode, Delivery.Qty,
FROM
Delivery
INNER JOIN
Order ON Order.ID_Order = Delivery.ID_Order
WHERE
Order.ID_Order = '9')
GROUP BY
a.ItemCode, a.Qty
Try this query --
;WITH CTE
AS (
SELECT C.ID_Order
,D.ID_Delivery
,C.ItemCode
,C.Quantity
,ROW_NUMBER() OVER (
PARTITION BY C.ItemCode ORDER BY D.ID_Delivery DESC
) AS RowNum
FROM Customer_Order C
INNER JOIN Delivery D ON C.ID_Order = D.ID_Order
AND C.ItemCode = D.ItemCode
WHERE C.ID_Order = 9
)
SELECT ID_Order
,ID_Delivery
,ItemCode
,Quantity
FROM CTE
WHERE RowNum = 1
SELECT
Order.ItemCode, Delivery. Qty, Delivery.ID_Delivery,
Order.ID_Order
FROM
Delivery
INNER JOIN
Order ON Order.ID_Order = Delivery.ID_Order
WHERE
Order.ID_Order = '9'
AND Delivery.ID_Delivery IN
(
SELECT MAX(ID_Delivery) FROM Delivery D WHERE D.ID_Order = Delivery.ID_Order GROUP BY D.ID_Order
)
I hope it will work for you.

SQL Dynamic join?

Please see http://sqlfiddle.com/#!3/2506f/2/0
I have two tables. One is a general record, and the other is a table containing related documents that link to that record.
In my example I've created a straightforward query which shows all records and their associated documents. This is fine, but I want a more complex situation.
In the 'mainrecord' table there is a 'multiple' field. If this is 0, then I only want the most recent document from the documents table (that is, with the highest ID). If it is 1, I want to join all linked documents.
So, rather than the result of the query being this:-
ID NAME MULTIPLE DOCUMENTNAME IDLINK
1 One 1 first document 1
1 One 1 second document 1
2 Two 0 third document 2
2 Two 0 fourth document 2
3 Three 1 fifth document 3
3 Three 1 sixth document 3
It should look like this:-
ID NAME MULTIPLE DOCUMENTNAME IDLINK
1 One 1 first document 1
1 One 1 second document 1
2 Two 0 fourth document 2
3 Three 1 fifth document 3
3 Three 1 sixth document 3
Is there a way of including this condition into my query to get the results I'm after. I'm happy to explain further if needed.
Thanks in advance.
WITH myData
AS
(SELECT mainrecord.*, documentlinks.documentName, documentlinks.idlink,
Row_number()
OVER (
partition BY mainrecord.ID
ORDER BY mainrecord.ID ASC) AS ROWNUM
FROM mainrecord INNER JOIN documentlinks
ON mainrecord.id = documentlinks.idlink)
SELECT *
FROM mydata o
WHERE multiple = 0 AND rownum =
(SELECT max(rownum) FROM mydata i WHERE i.id = o.id)
UNION
SELECT *
FROM myData
WHERE multiple = 1
http://sqlfiddle.com/#!3/2506f/57
Another solution (tested at SQL-Fiddle):
SELECT m.*,
d.id as did, d.documentName, d.IDLink
FROM mainrecord AS m
JOIN documentlinks AS d
ON d.IDLink = m.id
AND m.multiple = 1
UNION ALL
SELECT m.*,
d.id as did, d.documentName, d.IDLink
FROM mainrecord AS m
JOIN
( SELECT d.IDLink
, MAX(d.id) AS did
FROM mainrecord AS m
JOIN documentlinks AS d
ON d.IDLink = m.id
AND m.multiple = 0
GROUP BY d.IDLink
) AS g
ON g.IDLink = m.id
JOIN documentlinks AS d
ON d.id = g.did
ORDER BY id, did ;
This will probably do:
SELECT mainrecord.name, documentlinks.documentname
FROM documentlinks
INNER JOIN mainrecord ON mainrecord.id = documentlinks.IDLink AND multiple = 1
UNION
SELECT mainrecord.name, documentlinks.documentname
FROM (SELECT max(id) id, IDLink FROM documentlinks group by IDLink) maxdocuments
INNER JOIN documentlinks ON documentlinks.id = maxdocuments.id
INNER JOIN mainrecord ON mainrecord.id = documentlinks.IDLink AND multiple = 0
How about this:
select * from mainrecord a inner join documentlinks b on a.Id=b.IDLink
where b.id=(case
when a.multiple=1 then b.id
else (select max(id) from documentlinks c where c.IDLink=b.IDLink) end)
SQL FIDDLE
select
m.ID, m.name, m.multiple, dl.idlink,
dl.documentName
from mainrecord as m
left outer join documentlinks as dl on dl.IDlink = m.id
where
m.multiple = 1 or
not exists (select * from documentlinks as t where t.idlink = m.id and t.id < dl.id)