How to avoid DRY in PostgreSQL with a nested query - sql

This query works fine in this way:
SELECT DISTINCT inv.move_id,
inv.client_id,
inv.reference,
inv.date_inv,
inv.amount,
inv.state,
inv.client_type,
inv.agent_id,
(
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
) AS credit, (
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
) AS paid,
(inv.amount) - (
coalesce((
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
), 0) + coalesce((
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
), 0)
) AS outstanding
FROM invoice inv
INNER JOIN inv_move im ON im.id = inv.move_id
INNER JOIN client cl ON cl.id = inv.client_id
WHERE inv.agent_id = '%'
AND inv.date_inv
BETWEEN '%' AND '%'
AND inv.state = 'open'
ORDER BY inv.agent_id
I'm trying to DRY doing this:
SELECT DISTINCT inv.move_id,
inv.client_id,
inv.reference,
inv.date_inv,
inv.amount,
inv.state,
inv.client_type,
inv.agent_id,
(
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
) AS credit, (
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
) AS paid,
(inv.amount) - (
coalesce((credit), 0) + coalesce((paid), 0)
) AS outstanding
FROM invoice inv
INNER JOIN inv_move im ON im.id = inv.move_id
INNER JOIN client cl ON cl.id = inv.client_id
WHERE inv.agent_id = '%'
AND inv.date_inv
BETWEEN '%' AND '%'
AND inv.state = 'open'
ORDER BY inv.agent_id
But I'm getting an error in this way.
Because I want to use the alias column for operation values in other column.
How could I do it?
I was trying to use a WITH PostgreSQL statement but I couldn't find a better solution in that way.

You CANT use a field calculated on the same level.
SELECT 1 + 2 as three, three * 2 as six
^^^^^
undefined
So either you create a subquery.
SELECT three*2 as six
FROM ( SELECT 1 + 2 as three
FROM table
) T
or for your example use a JOIN
using CTE:
WITH cte as (
SELECT ref_move, state, SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
GROUP BY ref_move, state
)
SELECT *
FROM invoice i
JOIN cte c
ON i.ref_move= c.ref_move
AND i.state = c.state

Use subquery in FROM:
SELECT *, amount-credit-paid AS outstanding FROM (
SELECT DISTINCT inv.move_id,
inv.client_id,
inv.reference,
inv.date_inv,
inv.amount,
inv.state,
inv.client_type,
inv.agent_id,
(
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
) AS credit, (
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
) AS paid
FROM invoice inv ...
) AS _;

Related

Anyway to improve this SQL to avoid multiple Joins

I want to get sales result for 10 days for each product which is in my orders_summary table. Currently I'm joining orders_summary table 10 times to get sales for each day. Is there any better way to get this data?
Current sql:
SELECT P.ID,
P.SKU,
FIRST_DAY.ITEMS AS ITEMS_1,
FIRST_DAY.ORDERS AS ORDERS_1,
SECOND_DAY.ITEMS AS ITEMS_2,
SECOND_DAY.ORDERS AS ORDERS_2
FROM PRODUCTS AS P
LEFT JOIN
(SELECT SKU,
AMOUNT AS ITEMS,
ARRAY_LENGTH(LIST,
1) AS ORDERS
FROM ORDERS_SUMMARY
WHERE ORDER_DATE = TO_TIMESTAMP(1633158000000 / 1000.0)) AS FIRST_DAY ON P.SKU = FIRST_DAY.SKU
LEFT JOIN
(SELECT SKU,
AMOUNT AS ITEMS,
ARRAY_LENGTH(LIST,
1) AS ORDERS
FROM ORDERS_SUMMARY
WHERE ORDER_DATE = TO_TIMESTAMP(1633676400000 / 1000.0)) AS SECOND_DAY ON P.SKU = SECOND_DAY.SKU
...
result:
select main.sku, jsonb_populate_record(null::examples.table_fields, main.json_data)
from
(
select t2.sku, jsonb_object_agg(t2.itemNames, t2.items) || jsonb_object_agg(t2.orderNames, t2.orders) as json_data from
(
select
pr.sku,
'items' || tbl_dates.num::varchar as itemNames,
coalesce(sum(sOrd.amount), 0) as items,
'orders' || tbl_dates.num::varchar as orderNames,
coalesce(sum(sOrd.qty), 0) as orders
-- tbl_dates.dates
from products pr
inner join (
select tt.num, ('2021-01-01'::date + tt.num - 1) as dates
from (
select t.num from generate_series(1, 10, 1) AS t(num)
) tt
) tbl_dates on true
left join orders_summary sOrd on sOrd.sku = pr.sku and sOrd.order_date::date = tbl_dates.dates
group by pr.sku, tbl_dates.num, tbl_dates.dates
order by tbl_dates.num
) t2
group by t2.sku
) main;
I wrote simple select query, if you want to use a function then you can change this is '2021-01-01'::date to input variable and in this code generate_series(1, 10, 1) you can change 10 to the input variable

Error With total Column which calculate the summation of Row values

I created a pivot query which calculate the sum of specific transaction and i want to add additional column which calculate the sum of all transaction for every ID, But my total column give me nulls only for all IDs, Any one can help with that?
this is my Query:
SELECT
AccountID
, OpeningBalance
, OpeningBalanceStatus
, ISNULL([CI], 0) AS CI
, ISNULL([CO], 0) AS CO
, ISNULL([SI], 0) AS SI
, ISNULL([CN], 0) AS CN
, ISNULL([PI], 0) AS PI
, ISNULL([JE], 0) AS JE
, ISNULL([NR], 0) AS NR
, [OpeningBalance]+[CI]+[CO]+[SI]+[CN]+[PI]+[JE]+[NR] AS TOTAL
FROM (SELECT
Accounting.AccDocumentDetails.AccountID
, Accounting.AccDocumentDetails.AmountStatus
, Accounting.AccAccounts.AccountType
, Accounting.AccDocumentHeader.CodeTypePart
, AccAccounts_1.OpeningBalance
, AccAccounts_1.OpeningBalanceStatus
, CASE
WHEN AmountStatus = 'd'
THEN (Amount * 1)
WHEN AmountStatus = 'C'
THEN (Amount * - 1)
END AS NewAmount FROM Accounting.AccDocumentDetails
INNER JOIN Accounting.AccAccounts
ON Accounting.AccDocumentDetails.AccountID = Accounting.AccAccounts.ID
INNER JOIN Accounting.AccChartOfAccounts
ON Accounting.AccChartOfAccounts.ID = Accounting.AccAccounts.ParentNode
INNER JOIN Accounting.AccDocumentHeader
ON Accounting.AccDocumentDetails.AccDocumentHeaderID = Accounting.AccDocumentHeader.ID
INNER JOIN Accounting.AccAccounts AS AccAccounts_1
ON Accounting.AccDocumentDetails.AccountID = AccAccounts_1.ID) AS PivotSelect PIVOT( SUM(NewAmount) FOR CodeTypePart IN ([ci],[CO],[SI],[CN],[PI],[JE],[NR]) ) AS PVT
and this is my output
enter image description here
One way to have the total column is you can use your query as sub query, then create the computation for the total on the outer query. Or you can use cte as well
WITH t_pvt AS (
SELECT AccountID
,OpeningBalance
,OpeningBalanceStatus
,ISNULL([CI], 0) AS CI
,ISNULL([CO], 0) AS CO
,ISNULL([SI], 0) AS SI
,ISNULL([CN], 0) AS CN
,ISNULL([PI], 0) AS PI
,ISNULL([JE], 0) AS JE
,ISNULL([NR], 0) AS NR
FROM (SELECT Accounting.AccDocumentDetails.AccountID
,Accounting.AccDocumentDetails.AmountStatus
,Accounting.AccAccounts.AccountType
,Accounting.AccDocumentHeader.CodeTypePart
,AccAccounts_1.OpeningBalance
,AccAccounts_1.OpeningBalanceStatus
,CASE WHEN AmountStatus = 'd'
THEN (Amount * 1)
WHEN AmountStatus = 'C'
THEN (Amount * - 1)
END AS NewAmount
FROM Accounting.AccDocumentDetails
INNER JOIN Accounting.AccAccounts
ON Accounting.AccDocumentDetails.AccountID = Accounting.AccAccounts.ID
INNER JOIN Accounting.AccChartOfAccounts
ON Accounting.AccChartOfAccounts.ID = Accounting.AccAccounts.ParentNode
INNER JOIN Accounting.AccDocumentHeader
ON Accounting.AccDocumentDetails.AccDocumentHeaderID = Accounting.AccDocumentHeader.ID
INNER JOIN Accounting.AccAccounts AS AccAccounts_1
ON Accounting.AccDocumentDetails.AccountID = AccAccounts_1.ID) AS PivotSelect
PIVOT (SUM(NewAmount)
FOR CodeTypePart IN ([ci],[CO],[SI],[CN],[PI],[JE],[NR])) AS PVT
)
SELECT *
,[OpeningBalance]+[CI]+[CO]+[SI]+[CN]+[PI]+[JE]+[NR] AS TOTAL
FROM t_pvt
With CTE
AS
( select column1 as c1 from tbl)
Select c1 from CTE
thats a simple example of CTE syntax and how you can use it

SQL Server: select the largest order total from multiple customers with multiple orders, and there are multiple items on each order

I am really stuck on a problem and could use a little help. Here is the problem statement:
"Write the query that will show all the customers, the total of all orders, a count of orders made, the average total of each order, average number of items per order (with decimal points), the largest order total and the smallest order total for each customer. Show every customer even if a customer didn't make an order."
These are the tables:
the lovely tables
I've gotten this far, and I'm hung up on the max order total. I was thinking of a subquery for the highest and lowest order totals but I can't make it work.
SELECT
TC.intCustomerID
,TC.strLastName + ',' + ' ' + TC.strFirstName AS strCustomerName
,ISNULL(SUM( TCOI.intQuantity * TI.monPrice), 0) AS monOrderTotals
,COUNT(DISTINCT TCO.intOrderIndex) AS intNumberOfOrders
,ISNULL(SUM(TCOI.intQuantity * TI.monPrice) / COUNT(DISTINCT TCO.intOrderIndex), 0) AS monAverageOrderTotals
,(SELECT MAX(TCOI.intQuantity * TI.monPrice)
FROM TItems AS TI, TCustomerOrderItems AS TCOI
WHERE TI.intItemID = TCOI.intItemID
-- Cross-query join with two columns
-- AND TC.intCustomerID = TCOI.intCustomerID
-- AND TCO.intOrderIndex = TCOI.intOrderIndex
----GROUP BY
-- TCOI.intCustomerID
--,TCOI.intOrderIndex
) AS monMostExpensiveOrder
FROM
TCustomers AS TC
LEFT OUTER JOIN
TCustomerOrders AS TCO ON (TC.intCustomerID = TCO.intCustomerID)
LEFT OUTER JOIN
TCustomerOrderItems AS TCOI ON (TCO.intOrderIndex = TCOI.intOrderIndex)
LEFT OUTER JOIN
TItems AS TI ON (TCOI.intItemID = TI.intItemID)
GROUP BY
TC.intCustomerID
,TC.strLastName
,TC.strFirstName
Any insight would be greatly appreciated.
For me, using a common table expression goes a long way towards making code easier to read and write when you are working with derived tables (selecting from subqueries).
I think this should cover what you are trying to do, but I was not sure which way you wanted to count average items per order (by number of distinct items or the quantity of items):
with cte as (
select
tc.intCustomerId
, tc.strFirstName
, tc.strLastName
, tcoi.intOrderIndex
, TotalPrice = isnull(sum(tcoi.intQuantity * ti.monPrice), 0 )
, ItemCount = count(*)
, TotalItemQuantity = sum(tcoi.intQuantity)
from TCustomers tc
left join tCustomerOrderItems as tcoi
on tc.intCustomerId = tcoi.intCustomerId
left join tItems as ti
on ti.intItemID = tcoi.intItemID
)
select
intCustomerId
, Name = isnull(strLastName+', ') + isnull(strFirstName,'')
, countOrders = count(intOrderIndex)
, sumTotalPrice = sum(TotalPrice)
, minTotalPrice = min(TotalPrice)
, maxTotalPrice = max(TotalPrice)
, avgTotalPrice = avg(TotalPrice)
, avgItemCount = (sum(ItemCount)+.0)/nullif(count(intOrderIndex),0)
, avgItemQuant = (sum(TotalItemQuantity)+.0)/nullif(count(intOrderIndex),0)
from cte
group by
intCustomerId
, strFirstName
, strLastName
To take out the cte part, you would just move the query into the from.
select
intCustomerId
, Name = isnull(strLastName+', ') + isnull(strFirstName,'')
, countOrders = count(intOrderIndex)
, sumTotalPrice = sum(TotalPrice)
, minTotalPrice = min(TotalPrice)
, maxTotalPrice = max(TotalPrice)
, avgTotalPrice = avg(TotalPrice)
, avgItemCount = (sum(ItemCount)+.0)/nullif(count(intOrderIndex),0)
, avgItemQuant = (sum(TotalItemQuantity)+.0)/nullif(count(intOrderIndex),0)
from (
select
tc.intCustomerId
, tc.strFirstName
, tc.strLastName
, tcoi.intOrderIndex
, TotalPrice = isnull(sum(tcoi.intQuantity * ti.monPrice), 0 )
, ItemCount = count(*)
, TotalItemQuantity = sum(tcoi.intQuantity)
from TCustomers tc
left join tCustomerOrderItems as tcoi
on tc.intCustomerId = tcoi.intCustomerId
left join tItems as ti
on ti.intItemID = tcoi.intItemID
) as cte
group by
intCustomerId
, strFirstName
, strLastName
You will first need to calculate totals per order and per customer.
I will say that the schema is deficient in not storing order totals, since item price is likely to change, and TCustomerOrders likely includes historical orders. Prefixing tables and column names is also not recommended.
WITH CustomerOrders AS
(
SELECT
oi.intCustomerID as CustomerID,
oi.intOrderIndex as OrderID,
SUM(oi.intQuantity * i.monPrice) as SalesAmount,
COUNT(DISTINCT oi.intItemID) as DistinctItemCount,
SUM(oi.intQuantity) as ItemCount
FROM TCustomerOrderItems as oi
INNER JOIN TItems as i on oi.intItemID = i.intItemID
GROUP BY oi.intCustomerID, oi.intOrderIndex
),
CustomerSales AS
(
SELECT
co.CustomerID,
SUM(co.SalesAmount) as TotalSalesAmount,
COUNT(*) as OrderCount,
AVG(co.SalesAmount) as AvgOrderSalesAmount,
-- If item count should be distinct SKU's, use DistinctItemCount
-- Cast to numeric or another non-integer type to get fractional averages
AVG(CAST(co.ItemCount as numeric(14,4)) as AvgItemCount,
MIN(co.SalesAmount) as SmallestOrderSalesAmount,
MAX(co.SalesAmount) as LargestOrderSalesAmount
FROM CustomerOrders co
GROUP BY co.CustomerID
)
SELECT
c.intCustomerID as CustomerID,
c.strFirstName as CustomerFirstName,
c.strLastName as CustomerLastName,
COALESCE(cs.TotalSalesAmount, 0) as TotalSalesAmount,
COALESCE(cs.OrderCount, 0) as OrderCount,
COALESCE(cs.AvgOrderSalesAmount, 0) as AvgOrderSalesAmount,
COALESCE(cs.AvgItemCount, 0) as AvgItemCount,
COALESCE(cs.SmallestOrderSalesAmount, 0) as SmallestOrderSalesAmount,
COALESCE(cs.LargestOrderSalesAmount, 0) as LargestOrderSalesAmount
FROM TCustomers c
LEFT OUTER JOIN CustomerSales cs on c.intCustomerID = cs.CustomerID;

Sum of resulting set of rows in SQL

I've got the following query:
SELECT DISTINCT CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
/*MC.chemical_percentage,*/
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
--AND CU.permit_id = 2118
--GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month, MC.chemical_id, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound
--ORDER BY C.chemical_name ASC
Which returns:
But what I need is to return one row per month per material adding up the values of POC per month and NON_POC per month.
So, I should end up with something like:
Month material_id material_name POC NON_POC
1 52 Krylon... 0.107581 0.074108687
2 52 Krylon... 0.143437 0.0988125
I tried using SUM but it sums up the same result multiple times:
SELECT /*DISTINCT*/ CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
--MC.chemical_percentage,
POC_emissions = SUM(
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END),
NON_POC_emissions = SUM(
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END)
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE M.material_id = 52
--AND CU.permit_id = 187
AND (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month/*, CU.year, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound*/
--ORDER BY C.chemical_name ASC
The first query has a DISTINCT clause. What is the output without the DISTINCT clause. I suspect you have more rows than shows in your screenshot.
Regardless, you could try something like this to get the desired result.
select permit_id, month, material_id, material_name,
sum(poc_emissions), sum(non_poc_emissions)
from (
SELECT DISTINCT CU.permit_id, CU.month, M.material_id, M.material_name,
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
) main
group by permit_id, month, material_id, material_name
Explanation
Since the results you retrieved by doing a DISTINCT was consider source-of-truth, I created an in-memory table by making it a sub-query. However, this subquery must have a name of some kind...whatever name. I gave it a name main. Subqueries look like this:
select ... from (sub-query) <give-it-a-table-name>
Simple Example:
select * from (select userid, username from user) user_temp
Advanced Example:
select * from (select userid, username from user) user_temp
inner join (select userid, sum(debits) as totaldebits from debittable) debit
on debit.userid = user_temp.userid
Notice how user_temp alias for the subquery can be used as if the sub-query was a real table.
Use above query in subquery and group by (month) and select sum(POC_emissions) and sum(NON_POC_emissions )

SQL query select record with Max

I have these records below :
CustomerID | Name | Store | Quantity
1 | Elie | HO | 16
1 | Elie | S1 | 4
I would like to filter customers by taking only their max quantity?
I tried it with Max, but the problem I cannot render all the fields with it. If I add main.store in the first line, the second row shows.
Is there any solution?
Select main.CUSTOMER_ID, main.Name
from
(
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME
,Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID)
,cus.CUSTOMER_ID
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus
on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs
on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID
,cus.FIRST_NAME
,cus.LAST_NAME
,cs.Name
) as main
Group by CUSTOMER_ID
,main.Name
order by main.CUSTOMER_ID
This is a good use of window functions:
with t as (
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME,
Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID) , cus.CUSTOMER_ID
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID, cus.FIRST_NAME, cus.LAST_NAME, cs.Name
)
select name, store, Transaction_Number, CUSTOMER_ID
from (select t.*,
row_number() over (partition by customer_id order by transaction_number desc) as seqnum
from t
) t
where seqnum = 1;
You can actually dispense with the subquery. However, using window functions with aggregations looks funny at first:
with t as (
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME,
Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID) , cus.CUSTOMER_ID,
row_number() over (partition by cus.CUSTOMER_ID
order by count(ts.TRANSACTION_SUMMARY_ID) desc
) as seqnum
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID, cus.FIRST_NAME, cus.LAST_NAME, cs.Name
)
select name, store, Transaction_Number, CUSTOMER_ID
from t
where seqnum = 1;
Please try:
select * From tbl a
where a.Quantity=
(select MAX(b.Quantity) from tbl b where a.CustomerID=b.CustomerID)
what you want is
select customer_id, max( quantity )
from main
group by customer_id
then you can use this to join to itself if you want
select *
from main
, (
select customer_id, max( quantity ) qty
from main
group by customer_id
) m
where main.customer_id = m.customer_id
and main.quantity = m.qty
Obviously, name has no business being in this table, but you included it, so I did too...
SELECT x.*
FROM my_table x
JOIN
( SELECT customerid
, name
, MAX(quantity) max_quantity
FROM my_table
GROUP
BY customerid
, name
) y
ON y.customerid = x.customerid
AND y.name = x.name
AND y.max_quantity = x.quantity;