I need have created a select statement to list out all the customers that have been to multiple merchants below.
I want to create another statement to display how many of those customers have been to each merchant.
What is the optimal method of approaching this problem?
Lists out all customers that have been to multiple merchants.
WITH valentinesDayMerchant AS (
SELECT m.MerchantId, m.MerchantGroupId, m.WebsiteName
FROM Merchant m
INNER JOIN OpeningHours oh ON m.MerchantId = oh.MerchantId AND oh.DayOfWeek = 'TUE'
LEFT JOIN devices.DeviceConnectionState AS dcs ON dcs.MerchantId = oh.MerchantId
WHERE MerchantStatus = '-' AND (m.PrinterType IN ('V','O') OR dcs.State = 1 OR dcs.StateTransitionDateTime > '2023-01-23')
)
SELECT DISTINCT ul.UserLoginId, ul.FullName, ul.EmailAddress, ul.Mobile
FROM dbo.UserLogin AS ul
INNER JOIN dbo.Patron AS p ON p.UserLoginId = ul.UserLoginId
INNER JOIN valentinesDayMerchant AS m ON (m.MerchantId = ul.ReferringMerchantId OR m.MerchantId IN (SELECT pml.MerchantId FROM dbo.PatronMerchantLink AS pml WHERE pml.PatronId = p.PatronId AND ISNULL(pml.IsBanned, 0) = 0))
LEFT JOIN (
SELECT mg.MerchantGroupId, mg.MerchantGroupName, groupHost.HostName [GroupHostName]
FROM dbo.MerchantGroup AS mg
INNER JOIN dbo.Merchant AS parent ON parent.MerchantId = mg.ParentMerchantId
INNER JOIN dbo.HttpHostName AS groupHost ON groupHost.MerchantID = parent.MerchantId AND groupHost.Priority = 0
) mGroup ON mGroup.MerchantGroupId = m.MerchantGroupId
LEFT JOIN (
SELECT po.PatronId, MAX(po.OrderDateTime) [LastOrder]
FROM dbo.PatronsOrder AS po
GROUP BY po.PatronId
) orders ON orders.PatronId = p.PatronId
INNER JOIN dbo.HttpHostName AS hhn ON hhn.MerchantID = m.MerchantId AND hhn.Priority = 1
WHERE ul.UserLoginId NOT IN (1,2,100,372) AND ul.UserStatus <> 'D' AND (
ISNULL(orders.LastOrder, '2000-01-01') > '2020-01-01' OR ul.RegistrationDate > '2022-01-01'
)
GROUP BY ul.UserLoginId, ul.FullName, ul.EmailAddress, ul.Mobile
HAVING COUNT(m.MerchantId) > 1
Methods I have tried include adding the merchant name to a group by and displaying the count of the customers, however this does not work as I cannot have anything related to the Merchant in the GROUP BY, or I wouldn't be able to use HAVING clause to identify the customers that have been to multiple merchants. I have also tried selecting all the merchants and counting the distinct customers which doesn't work as it takes into account all the customers, not specifically the customers that have been to multiple merchants only.
I have this query:
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls.ProdServiceID
FROM Products prod
LEFT JOIN ProductServices ls ON ls.ProdServiceID=(SELECT ProdServiceID FROM
ProductServices WHERE ProductID=prod.ProductID ORDER BY Modified DESC LIMIT
1) ;
This query returns 175 rows
I want to convert this to JOIN.
I used below query:
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls1.ProductServicesID
FROM Products prod
inner join ProductServices ls on ls.ProductID=prod.ProductID
inner JOIN (SELECT ProductServicesID, ProductID, max(Modified) as Modified
FROM
ProductServices group by Modified) as ls1 ON ls.ProductServicesID =
ls1.ProductServicesID and ls.Modified = ls1.Modified and ls.ProductID =
ls1.ProductID;
which doesn't return correct result. Can I get some direction on this.
The purpose is to optimize the query. Would it be good idea to use join in place of original query.
Thanks!
Try this:
SELECT ProductID
, Name
, ProdExtID
, ProdServiceID
FROM
(
SELECT prod.ProductID
, prod.Name
, prod.ProdExtID
, ls.ProdServiceID
, RANK() OVER(PARTITION BY ls.ProdServiceID ORDER BY ls.Modified DESC) AS rnk
FROM Products prod
LEFT JOIN ProductServices ls ON ls.ProductID=prod.ProductID
) x
WHERE rnk = 1
So basically: your join needs to be on ProductID but you only want the most recent ProdServiceID, right?
try this select query please.
Here you get the serviceid which corresponds to productid and the last modiied
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls.ProdServiceID
FROM Products prod
LEft join ProductServices ls on ls.ProductID=prod.ProductID
inner JOIN (SELECT ProductID, max(Modified) as Modified
FROM
ProductServices group by ProductID) as ls1 ON ls.ProductID =
ls1.ProductID and ls.Modified = ls1.Modified;
Hi I am trying to query a table that conatains multiple duplicates on Code,Amount and Status How will I do this if I only one to get a result group according to the client_group name and get the sum of amount under that group
SELECT `client`.`client_group`
, FORMAT(SUM(`Data_result`.`Data_result_amount` ),2) as sum
FROM
`qwer`.`Data_result`
INNER JOIN `qwer`.`Data`
ON (`Data_result`.`Data_result_lead` = `Data`.`Data_id`)
INNER JOIN `qwer`.`Data_status`
ON (`Data_result`.`Data_result_status_id` = `Data_status`.`Data_status_id`)
INNER JOIN `qwer`.`client`
ON (`Data`.`Data_client_id` = `client`.`client_id`)
WHERE `Data_status`.`Data_status_name` IN ('PAID') AND MONTH(`Data_result`.`result_ts`) = MONTH(CURRENT_DATE())
AND YEAR(`Data_result`.`result_ts`) = YEAR(CURRENT_DATE())
GROUP BY `client`.`client_group`
Result of said query:
Table
Try to distinct before run the 'sum' check whether this solve your problem
SELECT `client_group` , FORMAT(SUM(`Data_result_amount` ),2) as sum from (
SELECT DISTINCT `client`.`client_group` , `Data_result`.`Data_result_amount`
FROM
`qwer`.`Data_result`
INNER JOIN `qwer`.`Data`
ON (`Data_result`.`Data_result_lead` = `Data`.`Data_id`)
INNER JOIN `qwer`.`Data_status`
ON (`Data_result`.`Data_result_status_id` = `Data_status`.`Data_status_id`)
INNER JOIN `qwer`.`client`
ON (`Data`.`Data_client_id` = `client`.`client_id`)
WHERE `Data_status`.`Data_status_name` IN ('PAID') AND MONTH(`Data_result`.`result_ts`) = MONTH(CURRENT_DATE())
AND YEAR(`Data_result`.`result_ts`) = YEAR(CURRENT_DATE())
) T
GROUP BY `client_group`
you can check the query here http://sqlfiddle.com/#!9/36a3f8/6
The goal here is to:
1. Fetch the row with the most recent date from EACH store for EACH ingredient.
2. From this result, compare the prices to find the cheapest store for EACH ingredient.
I can accomplish either the first or second goal in separate queries, but not in the same.
How can i filter out a selection and then apply another filter on the previous result?
EDIT:
I've been having problems with results that i get from MAX and MIN since it just fetches the rest of the data arbitrarily. To avoid this im supposed to join tables on multiple columns (i guess). Im not sure how this will work with duplicate dates etc.
I've included an image of a query and its output data.
If we use ingredient1 as an example, it exists in three separate stores (in one store twice on different dates).
In this case the cheapest current price for ingredient1 would be store3. If the fourth row dated 2013-05-25 was even cheaper, it would still not "win" due to it being out of date.
(Disregard brandname, they dont really matter in this problem.)
Would appreciate any help/input you can offer!
This question is really interesting!
So, first, we get the row with the most recent date from EACH store for EACH ingredient. (It is possible that the most recent dates from each store can be different.)
Then, we compare the prices from each store (regardless of the date) to find the least price for each ingredient.
The query below uses the GROUP_CONCAT function in good measure. Here's a SO question regarding the use of the function.
SELECT
i.name as ingredient_name
, MIN(store_price.price) as price
, SUBSTRING_INDEX(
GROUP_CONCAT(store_price.date ORDER BY store_price.price),
',',
1
) as date
, SUBSTRING_INDEX(
GROUP_CONCAT(s.name ORDER BY store_price.price),
',',
1
) as store_name
, SUBSTRING_INDEX(
GROUP_CONCAT(b.name ORDER BY store_price.price),
',',
1
) as brand_name
FROM
ingredient i
JOIN
(SELECT
ip.ingredient_id as ingredient_id
, stip.store_id as store_id
, btip.brand_id as brand_id
, CONVERT(SUBSTRING_INDEX(
GROUP_CONCAT(ip.ingredient_price_id ORDER BY ip.date DESC),
',',
1
), UNSIGNED INTEGER) as ingredient_price_id
, MAX(ip.date) as date
, CONVERT(SUBSTRING_INDEX(
GROUP_CONCAT(ip.price ORDER BY ip.date DESC),
',',
1
), DECIMAL(5,2)) as price
FROM ingredient_price ip
JOIN store_to_ingredient_price stip ON ip.ingredient_price_id = stip.ingredient_price_id
JOIN brand_to_ingredient_price btip ON ip.ingredient_price_id = btip.ingredient_price_id
GROUP BY
ip.ingredient_id
, stip.store_id) store_price
ON i.ingredient_id = store_price.ingredient_id
JOIN store s ON s.store_id = store_price.store_id
JOIN brand b ON b.brand_id = store_price.brand_id
GROUP BY
store_price.ingredient_id;
You can check the implementation on this SQL Fiddle.
The version below, which ignores the brand, is slightly smaller:
SELECT
i.name as ingredient_name
, MIN(store_price.price) as price
, SUBSTRING_INDEX(
GROUP_CONCAT(store_price.date ORDER BY store_price.price),
',',
1
) as date
, SUBSTRING_INDEX(
GROUP_CONCAT(s.name ORDER BY store_price.price),
',',
1
) as store_name
FROM
ingredient i
JOIN
(SELECT
ip.ingredient_id as ingredient_id
, stip.store_id as store_id
, CONVERT(SUBSTRING_INDEX(
GROUP_CONCAT(ip.ingredient_price_id ORDER BY ip.date DESC),
',',
1
), UNSIGNED INTEGER) as ingredient_price_id
, MAX(ip.date) as date
, CONVERT(SUBSTRING_INDEX(
GROUP_CONCAT(ip.price ORDER BY ip.date DESC),
',',
1
), DECIMAL(5,2)) as price
FROM ingredient_price ip
JOIN store_to_ingredient_price stip ON ip.ingredient_price_id = stip.ingredient_price_id
GROUP BY
ip.ingredient_id
, stip.store_id) store_price
ON i.ingredient_id = store_price.ingredient_id
JOIN store s ON s.store_id = store_price.store_id
GROUP BY
store_price.ingredient_id;
References:
Simulating First/Last aggregate functions in MySQL
This probably needs a couple of sub queries joined together.
This isn't tested (as I don't have your table definitions, nor any test data), but something like this:-
SELECT i.name AS ingredient,
ip.price,
ip.date,
s.name AS storename,
b.name AS brandname
FROM ingredient i
INNER JOIN ingredient_price ip
ON ingredient.ingredient_id = ingredient_price.ingredient_id
INNER JOIN store_to_ingredient_price stip
ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
INNER JOIN store s
ON store_to_ingredient_price.store_id = store.store_id
INNER JOIN brand_to_ingredient_price btip
ON ingredient_price.ingredient_price_id = brand_to_ingredient_price.ingredient_price_id
INNER JOIN brand b
ON brand_to_ingredient_price.brand_id = brand.brand_id
INNER JOIN
(
SELECT i.ingredient_id,
stip.store_id,
ip.date,
MIN(ip.price) AS lowest_price
FROM ingredient i
INNER JOIN ingredient_price ip
ON ingredient.ingredient_id = ingredient_price.ingredient_id
INNER JOIN store_to_ingredient_price stip
ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
INNER JOIN
(
SELECT i.ingredient_id,
stip.store_id,
MAX(ip.date) AS latest_date
FROM ingredient i
INNER JOIN ingredient_price ip
ON ingredient.ingredient_id = ingredient_price.ingredient_id
INNER JOIN store_to_ingredient_price stip
ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
GROUP BY ingredient_id, store_id
) Sub1
ON i.ingredient_id = Sub1.ingredient_id
AND stip.store_id = Sub1.store_id
AND ip.date = Sub1.latest_date
GROUP BY i.ingredient_id, stip.store_id, ip.date
) Sub2
ON i.ingredient_id = Sub2.ingredient_id
AND stip.store_id = Sub2.store_id
AND ip.date = Sub2.date
AND ip.price = Sub2.lowest_price
Try this:
SELECT `newest`.ingredient, `newest`.store,
`newest`.brand, `newest`.price, `newest`.`latest_date`
FROM
(SELECT ingredient.name AS ingredient, store.name AS store,
brand.name AS brand, ingredient_price.price,
MAX( ingredient_price.date ) AS `latest_date`
FROM ingredient
LEFT OUTER JOIN ingredient_price
ON ingredient.ingredient_id = ingredient_price.ingredient_id
LEFT OUTER JOIN store_to_ingredient_price
ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
LEFT OUTER JOIN store
ON store_to_ingredient_price.store_id = store.store_id
LEFT OUTER JOIN brand_to_ingredient_price
ON ingredient_price.ingredient_price_id = brand_to_ingredient_price.ingredient_price_id
LEFT OUTER JOIN brand
ON brand_to_ingredient_price.brand_id = brand.brand_id
GROUP BY ingredient.name) `newest`
ORDER BY `newest`.price
LIMIT 1
I have four tables person,loan,ca,payments
I would like to get the sum of all payments amounts and cash advance amounts which has the same ID as the loan joined with a person from a specific date.
Here is my code, but the sum is calculated incorrectly:
SELECT pd.*,
l.total_loan_amount,
sum(c.ca_total_amount) AS ctot,
sum(p.payment_amount)
FROM personal_data pd
LEFT JOIN loans l
ON pd.id_personal_data = l.id_personal_data
LEFT JOIN ca c
ON l.id_loan = c.id_loan
LEFT JOIN payments p
ON l.id_loan = p.id_loan
WHERE l.loan_date = curDate()
AND (
c.ca_date = curDate()
OR c.ca_date IS NULL
)
AND (
p.payment_date = curDate()
OR p.payment_date IS NULL
)
GROUP BY pd.id_personal_data
Doing that may sometimes retrieve invalid results because id may or may not sometimes be present on other table.
Try using a subquery for each column you want to retrieve.
SELECT pd.*,
l.total_loan_amount,
c.totalCA,
p.totalPayment
FROM personal_data pd
LEFT JOIN loans l
ON pd.id_personal_data = l.id_personal_data
LEFT JOIN
(
SELECT id_loan, SUM(ca_total_amount) totalCA
FROM ca
-- WHERE DATE(ca_date) = DATE(CURDATE()) OR
-- ca_date IS NULL
GROUP BY id_loan
) c ON l.id_loan = c.id_loan
LEFT JOIN
(
SELECT id_loan, SUM(payment_amount) totalPayment
FROM payments
-- WHERE DATE(payment_date) = DATE(CURDATE()) OR
-- payment_date IS NULL
GROUP BY id_loan
) p ON l.id_loan = p.id_loan
WHERE DATE(l.loan_date) = DATE(curDate())
I think dates on every payment and cash advance are irrelevant because you are looking for its totals based on the date of loan