basically i have this structure:
Deal has and belongs to many Channels
Deal has many DealSales
Deal belongs to Channel
When i want to find the amount sold by a deal, i use this query:
SELECT targets.id,SUM(deal_sales.amount_sold) AS amount_sold
FROM deal_sales
INNER JOIN deals ON deals.id = deal_sales.deal_id
INNER JOIN targets ON deals.target_id = targets.id
WHERE targets.approved = 1 AND targets.active = 1
GROUP BY targets.id
its working just fine, the problem is when i need to filter by channel, find the amount sold by a deal in a channel:
SELECT targets.id,SUM(deal_sales.amount_sold) AS amount_sold
FROM deal_sales
INNER JOIN deals ON deals.id = deal_sales.deal_id
INNER JOIN targets ON deals.target_id = targets.id
**INNER JOIN channels_deals ON channels_deals.deal_id = deals.id**
WHERE targets.approved = 1 AND targets.active = 1
GROUP BY targets.id
When i add the join to channels table, the amount_sold is multiplied by each channel a deal has relation with. How can i avoid this?
Use IN or Exists
for example
SELECT targets.id,SUM(deal_sales.amount_sold) AS amount_sold
FROM deal_sales
INNER JOIN deals ON deals.id = deal_sales.deal_id
INNER JOIN targets ON deals.target_id = targets.id
WHERE targets.approved = 1 AND targets.active = 1
and
deals.id IN (SELECT deal_id from channels_deals where something = 1)
GROUP BY targets.id
Try this:
SELECT channels_deals.deal_id,SUM(deal_sales.amount_sold) AS amount_sold
FROM deal_sales
INNER JOIN deals ON deals.id = deal_sales.deal_id
INNER JOIN targets ON deals.target_id = targets.id
INNER JOIN channels_deals ON channels_deals.deal_id = deals.id
WHERE targets.approved = 1 AND targets.active = 1
GROUP BY channels_deals.deal_id
Related
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 the following query:
SELECT e_c.*, c.name, j.status, j.version, j.articleId, j.title FROM assetcategory AS c
INNER JOIN assetentries_assetcategories AS e_c
ON c.categoryId = e_c.categoryId AND c.name = 'news'
INNER JOIN assetentry AS e
ON e.entryId = e_c.entryId
INNER JOIN journalarticle AS j
ON j.resourcePrimKey = e.classPK
AND e.classNameId = (SELECT classNameId FROM classname_ WHERE value = 'com.liferay.portlet.journal.model.JournalArticle')
AND j.companyId= e.companyId
WHERE j.status = 0
which returns all the category news in the journalarticles. From the results I need to select the most recent versions for each articleId. For example suppose there is an article with 4 versions, even with different title, it is the same article because it will have the same articleId. So therefore for each unique articleId I need the latest version. How can I do that?
Add a join to a subquery which finds the most recent version for each article:
SELECT e_c.*, c.name, j1.status, j1.version, j1.articleId, j1.title
FROM assetcategory AS c
INNER JOIN assetentries_assetcategories AS e_c
ON c.categoryId = e_c.categoryId AND c.name = 'news'
INNER JOIN assetentry AS e
ON e.entryId = e_c.entryId
INNER JOIN journalarticle AS j1
ON j1.resourcePrimKey = e.classPK AND
e.classNameId = (SELECT classNameId FROM classname_
WHERE value = 'com.liferay.portlet.journal.model.JournalArticle') AND
j.companyId = e.companyId
INNER JOIN
(
SELECT articleId, MAX(version) AS max_version
FROM journalarticle
WHERE status = 0
GROUP BY articleId
) j2
ON j1.articleId = j2.articleId AND j1.version = j2.max_version;
The basic idea behind the join to the subquery aliased as j2 above is that it restricts the result set to only the most recent version of each article. We don't necessarily have to change the rest of the query.
I am trying to get the rounded average rating for each trades person using ROUND(AVG(travisor_review.rating)). However this is returning the average for all reviews and only returning one row, when there should be a row for each trades person and the average for that trades person only. My query is below (I hope you can infer table structure from that).
SELECT travisor_tradesperson.name, travisor_catagory.catname,
travisor_city.cityname, travisor_company.cname,
travisor_company.description, ROUND(AVG(travisor_review.rating))
FROM `travisor_tradesperson`
INNER JOIN travisor_company
ON travisor_tradesperson.company = travisor_company.id
INNER JOIN travisor_catagory
ON travisor_tradesperson.catagory = travisor_catagory.id
INNER JOIN travisor_city
ON travisor_tradesperson.city = travisor_city.id
INNER JOIN travisor_review
ON travisor_review.tradesperson = travisor_tradesperson.id
WHERE travisor_catagory.catname = '$catagory'
AND travisor_city.cityname = '$city'
You need an aggregation
SELECT travisor_tradesperson.name, travisor_catagory.catname,
travisor_city.cityname, travisor_company.cname,
travisor_company.description, ROUND(AVG(travisor_review.rating))
FROM `travisor_tradesperson`
INNER JOIN travisor_company
ON travisor_tradesperson.company = travisor_company.id
INNER JOIN travisor_catagory
ON travisor_tradesperson.catagory = travisor_catagory.id
INNER JOIN travisor_city
ON travisor_tradesperson.city = travisor_city.id
INNER JOIN travisor_review
ON travisor_review.tradesperson = travisor_tradesperson.id
WHERE travisor_catagory.catname = '$catagory'
AND travisor_city.cityname = '$city'
group by travisor_tradesperson.name, travisor_catagory.catname,
travisor_city.cityname, travisor_company.cname,
travisor_company.description
I have a query that selects properties, and I need to join them to get the most recent activity on each one, where that activity_status = 3 (closed deal). when I get that, I need to get the bank that closed the deal (banks.is_reward = 1)
Problem is that the data is spread over many tables, so when I join to get all the results, and then try to limit to the max(activity_date), I need to group the results, and then I don't get the correct data from the other columns.
Here is a SQL Fiddle
I can do
Select * from properties
join
(SELECT deal_properties.property_id, activity.deal_id, activity.activity_date, banks.bank_id
FROM deal_properties
JOIN activity on activity.deal_id = deal_properties.deal_id
AND activity.activity_status = 3
JOIN banks ON banks.deal_id = activity.deal_id
AND banks.is_rewarded = 1) a
on a.property_id = properties.property_id;
and that will get me all the closed properties, with the rewarded banks, but I cant seem to limit that by the max(activity_date).
Option 1
The following gives what you're looking for following your current line of thought:
SELECT LastActivities.property_id, ActivityDetails.bank_id, LastActivities.activity_date
FROM (
SELECT p.property_id, MAX(a.activity_date) AS activity_date
FROM properties p
JOIN deal_properties dp
ON dp.property_id = p.property_id
JOIN activity a
ON a.deal_id = dp.deal_id AND a.activity_status = 3
GROUP BY p.property_id
) LastActivities
JOIN(
SELECT a.activity_date, dp.property_id, b.bank_id
FROM deal_properties dp
JOIN activity a
ON a.deal_id = dp.deal_id AND a.activity_status = 3
JOIN banks b
ON b.deal_id = a.deal_id AND b.is_rewarded = 1
) ActivityDetails
ON ActivityDetails.property_id = LastActivities.property_id
AND ActivityDetails.activity_date = LastActivities.activity_date
Here is the fiddle: HERE
Option 2
Below is another way to get the same results... This should be a bit more efficient as it only has one derived table instead of two.
SELECT p.property_id, b.bank_id, a.activity_date
FROM activity a
JOIN banks b
ON b.deal_id = a.deal_id AND b.is_rewarded = 1
JOIN deal_properties dp
ON dp.deal_id = a.deal_id
JOIN properties p
ON p.property_id = dp.property_id
JOIN(SELECT p.property_id, max(a.activity_date) AS activity_date
FROM activity a
JOIN deal_properties dp
ON dp.deal_id = a.deal_id
JOIN properties p
ON p.property_id = dp.property_id
GROUP BY p.property_id
) latest
ON latest.activity_date = a.activity_date AND latest.property_id = p.property_id
WHERE a.activity_status = 3
Here is the fiddle for option 2: HERE
looking to your sample seems you need
Select * from properties p
inner join
( SELECT deal_properties.property_id as property_id , max(activity.activity_date) max_date
FROM deal_properties
INNER JOIN activity on activity.deal_id = deal_properties.deal_id
AND activity.activity_status = 3
INNER JOIN banks ON banks.deal_id = activity.deal_id AND banks.is_rewarded = 1
group by property_id
) a on a.property_id = p.property_id;
I have the SQL to display ALL the activities and relative Admin permissions (if any) for that activity.
Current SQL Code:
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
WHERE `activities`.`active` = 1
Returning:
id | name | description | active | admin_role_id (or null)
I then need to detect whether they are an active member within that Activity.
I have the following SQL code:
SELECT DISTINCT `products`.`activity_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `activities` ON `activities`.`id` = `products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Is there any way to merge this into one SQL query. I can't figure out how to use the correct JOIN queries, because of the complexity of the JOINs.
Help please, thanks! :)
Try like this
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
JOIN (`transactions_items`
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`)
ON `activities`.`id`=`products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Seems to me that a query like this would be marginally more comprehensible and (I think) adhere more closely to the spec...
SELECT c.*
, d.admin_role_id
FROM activities c
LEFT
JOIN admins d
ON d.activity_id = c.id
AND d.member_id = 27500
LEFT
JOIN products p
ON p.activity_ID = c.id
LEFT
JOIN transactions_items ti
ON ti.product_id = p.id
LEFT
JOIN transactions t
ON t.id = ti.id
AND t.member_id = 27500
WHERE c.active = 1