MySQL group by twice and COUNT - mysql

Some sql query gives me the following result:
As you can see, it already has GROUP BY.
So what I need? I need to group it again (by treatment_name) and count rows for each group. See more details on screenshot.
Here is full query:
SELECT
treatment_summaries.*
FROM `treatment_summaries`
INNER JOIN
`treatments`
ON
`treatments`.`treatment_summary_id` = `treatment_summaries`.`id`
AND
(treatment <> '' and treatment is not null)
INNER JOIN
`treatment_reviews`
ON
`treatment_reviews`.`treatment_id` = `treatments`.`id`
INNER JOIN
`conditions_treatment_reviews`
ON
`conditions_treatment_reviews`.`treatment_review_id` = `treatment_reviews`.`id`
INNER JOIN
`conditions` ON `conditions`.`id` = `conditions_treatment_reviews`.`condition_id`
INNER JOIN `conditions_treatment_summaries` `conditions_treatment_summaries_join`
ON
`conditions_treatment_summaries_join`.`treatment_summary_id` = `treatment_summaries`.`id`
INNER JOIN `conditions` `conditions_treatment_summaries`
ON `conditions_treatment_summaries`.`id` = `conditions_treatment_summaries_join`.`condition_id`
WHERE
`conditions`.`id` = 9
AND `conditions`.`id` IN (9)
AND (latest_review_id is not null)
GROUP BY
treatment_reviews.id
ORDER BY
treatment_summaries.reviews_count desc
LIMIT 20 OFFSET 0

Maybe there is another issue, cause GROUP BY should not leave same lines (for given column), but anyway you can wrap it like this:
SELECT * FROM ( YOUR_SQL_SELECT_WITH_EVERYTHING ) GROUP BY id
So the result you get will behave as another table and you can do all operations like GROUP BY again.

Related

Left join sql query

I want to get all the data from the users table & the last record associated with him from my connection_history table , it's working only when i don't add at the end of my query
ORDER BY contributions DESC
( When i add it , i have only the record wich come from users and not the last connection_history record)
My question is : how i can get the entires data ordered by contributions DESC
SELECT * FROM users LEFT JOIN connections_history ch ON users.id = ch.guid
AND EXISTS (SELECT 1
FROM connections_history ch1
WHERE ch.guid = ch1.guid
HAVING Max(ch1.date) = ch.date)
The order by should not affect the results that are returned. It only changes the ordering. You are probably getting what you want, just in an unexpected order. For instance, your query interface might be returning a fixed number of rows. Changing the order of the rows could make it look like the result set is different.
I will say that I find = to be more intuitive than EXISTS for this purpose:
SELECT *
FROM users u LEFT JOIN
connections_history ch
ON u.id = ch.guid AND
ch.date = (SELECT Max(ch1.date)
FROM connections_history ch1
WHERE ch.guid = ch1.guid
)
ORDER BY contributions DESC;
The reason is that the = is directly in the ON clause, so it is clear what the relationship between the tables is.
For your casual consideration, a different formatting of the original code. Note in particular the indented AND suggests the clause is part of the LEFT JOIN, which it is.
SELECT * FROM users
LEFT JOIN connections_history ch ON
users.id = ch.guid
AND EXISTS (SELECT 1
FROM connections_history ch1
WHERE ch.guid = ch1.guid
HAVING Max(ch1.date) = ch.date
)
We can use nested queries to first check for max_date for a given user and pass the list of guid to the nested query assuming all the users has at least one record in the connection history table otherwise you could use Left Join instead.
select B.*,X.* from users B JOIN (
select A.* from connection_history A
where A.guid = B.guid and A.date = (
select max(date) from connection_history where guid = B.guid) )X on
X.guid = B.guid
order by B.contributions DESC;

SUM case returns value without GROUP BY

When I add SUM around my case select, it returns the summed value without the GROUP BY.
The query I am using, without the SUM, is the following
SELECT CASE WHEN subscription_types.type = 'Succes lidmaatschap' THEN 7 ELSE 8 END FROM subscription_used
INNER JOIN training_sessions ON training_sessions.id = subscription_used.training_session_id
INNER JOIN training_series AS tserie ON tserie.id = training_sessions.training_serie_id
INNER JOIN user_training_session ON user_training_session.training_session_id = training_sessions.id
INNER JOIN subscriptions ON subscriptions.id = subscription_used.subscription_id
INNER JOIN subscription_types ON subscription_types.id = subscriptions.subscription_type_id
WHERE subscription_used.training_session_id = (SELECT training_sessions.id FROM training_sessions WHERE DATE(event_start_date) = #week_2_ago_date AND training_serie_id = 17) AND present=1
GROUP BY subscriptions.id
This query returns the values: 8,7. However, when I put a SUM around the case, it gives me the number 75. 75 is the SUM of the values that are getting returned without the GROUP BY.
Any ideas on how to fix this problem so that the query gives me the correct value (8+7 = 15, 1 row)? Thanks in advance
Group by is implying distinct values based on subscription.id so probably if you take the group by you you will get something like 8,8,8,8,8,7,7,7,7,7 due to the joins and such.
With the group by you only get the distinct values of 8 and 7. When you do sum with the group it will sum all of them though not the 2 distinct.
Most Simple fix that will give you 15:
SELECT SUM(SUBSCRIPTION_USED) FROM (
SELECT CASE WHEN subscription_types.type = 'Succes lidmaatschap' THEN 7 ELSE 8 END FROM subscription_used
INNER JOIN training_sessions ON training_sessions.id = subscription_used.training_session_id
INNER JOIN training_series AS tserie ON tserie.id = training_sessions.training_serie_id
INNER JOIN user_training_session ON user_training_session.training_session_id = training_sessions.id
INNER JOIN subscriptions ON subscriptions.id = subscription_used.subscription_id
INNER JOIN subscription_types ON subscription_types.id = subscriptions.subscription_type_id
WHERE subscription_used.training_session_id = (SELECT training_sessions.id FROM training_sessions WHERE DATE(event_start_date) = #week_2_ago_date AND training_serie_id = 17) AND present=1
GROUP BY subscriptions.id);
Probably a better way to write it in general though.
EDIT: You could also do SUM(DISTINCT CASE......) if you only want to sum distinct values.

MySQL join multiple tables and limit the output from "ON"

when i write a MySQL query, there occur a problem. here is my query
SELECT
SUM(view_product_count_details.view_product_count) AS count_sum,
product_details.product_name,
product_details.product_url,
product_details.product_price,
product_image_details.product_image_name,
main_category_details.main_category_url,
sub_category_details.sub_category_url
FROM
view_product_count_details
JOIN
product_details ON view_product_count_details.product_id_fk = product_details.product_id
JOIN
product_image_details ON product_image_details.product_id_fk = view_product_count_details.product_id_fk
JOIN
main_category_details ON product_details.product_main_cat_id = main_category_details.main_category_id
JOIN
sub_category_details ON product_details.product_sub_cat_id_fk = sub_category_details.sub_category_id
WHERE
view_product_count_details.view_product_status = 'active'
GROUP BY view_product_count_details.product_id_fk
ORDER BY count_sum DESC
LIMIT 4
Here I have multiple images for one product.the images are in table "product_image_details". this query returns count as the number of images, where I need the count of product viewed by people which is stored in table "view_product_count_details". when I just pick the count, i got the count as it is. but when i join the table "product_image details", result become wrong. Is there any way to do it in single query?
Please help me... Thanks in advance.... :)
You can do it by having an inline query. I am not sure how this will perform when you have more data.
SELECT table1.*,product_image_details.product_image_name FROM
(
SELECT
SUM(view_product_count_details.view_product_count) AS count_sum,
product_details.product_id,
product_details.product_name,
product_details.product_url,
product_details.product_price,
main_category_details.main_category_url,
sub_category_details.sub_category_url
FROM
view_product_count_details
JOIN
product_details ON view_product_count_details.product_id_fk = product_details.product_id
JOIN
product_image_details ON product_image_details.product_id_fk = view_product_count_details.product_id_fk
JOIN
main_category_details ON product_details.product_main_cat_id = main_category_details.main_category_id
JOIN
sub_category_details ON product_details.product_sub_cat_id_fk = sub_category_details.sub_category_id
WHERE
view_product_count_details.view_product_status = 'active'
GROUP BY view_product_count_details.product_id_fk
ORDER BY count_sum DESC
LIMIT 4
) table1
JOIN
product_image_details ON product_image_details.product_id_fk = table1.product_id
LIMIT 4

Sql query to combine result of two tables

Currently I am using the following query to display the following result.
SELECT * FROM RouteToGrowthRecord, GradeMaster,MileStoneMaster
WHERE MemberID = 'ALV01L11034A06' AND
RouteToGrowthRecord.GradeID=GradeMaster.GradeID AND
RouteToGrowthRecord.MileStoneID=MileStoneMaster.MileStoneID
ORDER BY CheckupDate DESC
Now I have another table named RouteToGrowthRecord_st that has same
columns as RouteToGrowthRecord with some additional fields.
I need to display result that are present in both the table. ie . if RouteToGrowthRecord_st has 3 records with the given menberID,then output must contain 3 more records along with the above query result.(fr ex above its 9+3=12 records in total).
You can use Union here to merge the results getting from both queries. Use default values for the unmapped additional fields.
You can write above query in following way
SELECT * FROM RouteToGrowthRecord
INNER JOIN GradeMaster ON RouteToGrowthRecord.GradeID=GradeMaster.GradeID
INNER JOIN MileStoneMaster ON RouteToGrowthRecord.MileStoneID=MileStoneMaster.MileStoneID
LEFT JOIN RouteToGrowthRecord_st ON RouteToGrowthRecord_st.memberID=RouteToGrowthRecord.memberID
WHERE
RouteToGrowthRecord.MemberID = 'ALV01L11034A06'
order by CheckupDate DESC
this is my answer
SELECT CheckUpDate,AgeInMonths,PresentWeight,Height,Diagnosis,growthstatus,GradeName,MilestoneName,MemberID
FROM RouteToGrowthRecord, GradeMaster,MileStoneMaster WHERE
MemberID = 'ALV01L56107A11 ' and
RouteToGrowthRecord.GradeID=GradeMaster.GradeID and
RouteToGrowthRecord.MileStoneID=MileStoneMaster.MileStoneID
union
SELECT CheckUpDate,AgeInMonths,PresentWeight,Height,Diagnosis,growthstatus,GradeName,MilestoneName,MemberID
FROM RouteToGrowthRecord_st, GradeMaster,MileStoneMaster WHERE
MemberID = 'ALV01L56107A11 ' and
RouteToGrowthRecord_st.GradeID=GradeMaster.GradeID and
RouteToGrowthRecord_st.MileStoneID=MileStoneMaster.MileStoneID
order by CheckupDate DESC
SELECT * FROM RouteToGrowthRecord a inner join GradeMaster b inner
join MileStoneMaster c inner join RouteToGrowthRecord_st d on
a.GradeID=b.GradeID AND a.MileStoneID=c.MileStoneID and
d.GradeID=b.GradeID AND d.MileStoneID=c.MileStoneID
WHERE a.MemberID = 'ALV01L11034A06'
ORDER BY CheckupDate DESC

MySQL Inner Join with where clause sorting and limit, subquery?

Everything in the following query results in one line for each invBlueprintTypes row with the correct information. But I'm trying to add something to it. See below the codeblock.
Select
blueprintType.typeID,
blueprintType.typeName Blueprint,
productType.typeID,
productType.typeName Item,
productType.portionSize,
blueprintType.basePrice * 0.9 As bpoPrice,
productGroup.groupName ItemGroup,
productCategory.categoryName ItemCategory,
blueprints.productionTime,
blueprints.techLevel,
blueprints.researchProductivityTime,
blueprints.researchMaterialTime,
blueprints.researchCopyTime,
blueprints.researchTechTime,
blueprints.productivityModifier,
blueprints.materialModifier,
blueprints.wasteFactor,
blueprints.maxProductionLimit,
blueprints.blueprintTypeID
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
So what I need to get in here is the following table with the columns below it so I can use the values timestamp and sort the entire result by profitHour
tablename: invBlueprintTypesPrices
columns: blueprintTypeID, timestamp, profitHour
I need this information with the following select in mind. Using a select to show my intention of the JOIN/in-query select or whatever that can do this.
SELECT * FROM invBlueprintTypesPrices
WHERE blueprintTypeID = blueprintType.typeID
ORDER BY timestamp DESC LIMIT 1
And I need the main row from table invBlueprintTypes to still show even if there is no result from the invBlueprintTypesPrices. The LIMIT 1 is because I want the newest row possible, but deleting the older data is not a option since history is needed.
If I've understood correctly I think I need a subquery select, but how to do that? I've tired adding the exact query that is above with a AS blueprintPrices after the query's closing ), but did not work with a error with the
WHERE blueprintTypeID = blueprintType.typeID
part being the focus of the error. I have no idea why. Anyone who can solve this?
You'll need to use a LEFT JOIN to check for NULL values in invBlueprintTypesPrices. To mimic the LIMIT 1 per TypeId, you can use the MAX() or to truly make sure you only return a single record, use a row number -- this depends on whether you can have multiple max time stamps for each type id. Assuming not, then this should be close:
Select
...
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Left Join (
SELECT MAX(TimeStamp) MaxTime, TypeId
FROM invBlueprintTypesPrices
GROUP BY TypeId
) blueprintTypePrice On blueprints.blueprintTypeID = blueprintTypePrice.typeID
Left Join invBlueprintTypesPrices blueprintTypePrices On
blueprintTypePrice.TypeId = blueprintTypePrices.TypeId AND
blueprintTypePrice.MaxTime = blueprintTypePrices.TimeStamp
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
Order By
blueprintTypePrices.profitHour
Assuming you might have the same max time stamp with 2 different records, replace the 2 left joins above with something similar to this getting the row number:
Left Join (
SELECT #rn:=IF(#prevTypeId=TypeId,#rn+1,1) rn,
TimeStamp,
TypeId,
profitHour,
#prevTypeId:=TypeId
FROM (SELECT *
FROM invBlueprintTypesPrices
ORDER BY TypeId, TimeStamp DESC) t
JOIN (SELECT #rn:=0) t2
) blueprintTypePrices On blueprints.blueprintTypeID = blueprintTypePrices.typeID AND blueprintTypePrices.rn=1
You don't say where you are putting the subquery. If in the select clause, then you have a problem because you are returning more than one value.
You can't put this into the from clause directly, because you have a correlated subquery (not allowed).
Instead, you can put it in like this:
from . . .
(select *
from invBLueprintTypesPrices ibptp
where ibtp.timestamp = (select ibptp2.timestamp
from invBLueprintTypesPrices ibptp2
where ibptp.blueprintTypeId = ibptp2.blueprintTypeId
order by timestamp desc
limit 1
)
) ibptp
on ibptp.blueprintTypeId = blueprintType.TypeID
This identifies the most recent records for all the blueprintTypeids in the subquery. It then joins in the one that matches.