Mysql nested select query inside having - mysql

Mysql says "Error Code: 1054. Unknown column 'ju.id' in 'where clause'"
Why I can't use the alias ju inside the nested select. Is there any issue the way I have ordered the query?
SELECT `ac`.`name`, COALESCE(SUM(tr.amount*ju.rate), 0) as amount
FROM `transactions` `tr`
LEFT JOIN `journals` `ju` ON `tr`.`journal_id` = `ju`.`id`
LEFT JOIN `accounts` `ac` ON `ac`.`id` = `tr`.`account`
WHERE `ju`.`txn_date` >= UNIX_TIMESTAMP('2021-01-01 00:00:00')
AND `ju`.`txn_date` <= UNIX_TIMESTAMP('2021-07-08 23:59:59')
AND `tr`.`type` = 'debit'
AND (`ac`.`bank` = 1 OR `ac`.`cash` = 1)
AND `ac`.`business` = 201
GROUP BY `ac`.`id`
HAVING ( SELECT tra.id
FROM transactions tra
LEFT JOIN accounts acc ON `acc`.`id` = `tra`.`account`
WHERE `tra`.`journal_id` = `ju`.`id`
AND `tra`.`type` = 'credit'
AND `acc`.`category` IN ('Sales Revenue','Other Income')
) IS NOT NULL;

I think the correct explanation is that the subquery after HAVING (between the parenthesis) make the alias "ju" in the top level query out of scope.
I've never used HAVING before, but my solution would be to add the "journals" table to the subquery with the needed criteria. But that really depends on what you want to query for.

Related

Using Inline Query Field in Where Condition

I have gone through this solution Using Inline Query Alias in Where clause outside of inline Query but its not working for below query
select `leads`.*, `departmentdata`.`name` as `department`,
(
select activitytype.activity_name
from activities inner
join activitytype on activitytype.id = activities.activity_type_id
where activities.leadid = leads.id
and activities.followup_date >= CURDATE()
order by activities.followup_date asc
limit 0,1
)temp1
from `leads`
left join `departmentdata` on `departmentdata`.`id` = `leads`.`department`
where activity_name = 'Email'
order by `leads`.`id` desc
i am still getting below error.
MySQL said: Documentation
#1054 - Unknown column 'activity_name' in 'where clause'
Any help?
Since this is a very big query so removed other fields. Below is the query without putting condition on activity_name fields.
But when i apply condition on activity_name field then i get above error.
See if moving your where to your inline select gives you your result.
I wonder if you need to join activitytype but can't really tell because I don't know what your expected outcome is and there is no test data.
select
`leads`.*,
`departmentdata`.`name` as `department`,
(
select
activitytype.activity_name
from
activities
inner join
activitytype
on
activitytype.id = activities.activity_type_id
where
activities.leadid = leads.id and
activities.followup_date >= CURDATE() and
activities.activity_name = 'Email'
order by
activities.followup_date asc
limit 0,1
) as temp1
from
`leads`
left join
`departmentdata`
on
`departmentdata`.`id` = `leads`.`department`
order by
`leads`.`id` desc

Unknown Column In Where Clause With Join

I want to join 3 table one column sum has to be compare with another column
Here is my query
SELECT
*, `e`.`id` AS `event_ac_id`,
SUM(CASE WHEN trans.gift_transaction_status = 1
THEN trans.event_gift_amount
ELSE 0 END) as amount
FROM
`tbl_event_category` `cat`
LEFT JOIN
`tbl_event` `e` ON e.event_category = cat.id
LEFT JOIN
`tbl_organisation` `org` ON e.organisation_id = org.id
LEFT JOIN
`tbl_event_gift_transaction` `trans` ON e.id = trans.event_id
WHERE
cat.type ='campaign' AND is_approved=1
AND e.funding_goal_amount <= amount
GROUP BY
`event_ac_id`
LIMIT 8
Exception (Database Exception) 'yii\db\Exception' with message
'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'amount' in
'where clause'
A computed value cannot be on the WHERE clause. Only actual columns need to be used there.
If you want to filter AFTERWARDS the WHERE clause has been executed, you can use the HAVING statement
You need to understand that SQL is evaluated from right to left. So when the MYSQL parser looks for amount column then it is not found and hence the error.
The manual says:
"A select_expr can be given an alias using AS alias_name. The alias is
used as the expression's column name and can be used in GROUP BY,
ORDER BY, or HAVING clauses."
and
Standard SQL doesn't allow you to refer to a column alias in a WHERE
clause. This restriction is imposed because when the WHERE code is
executed, the column value may not yet be determined.
You can try this:
SELECT *, `e`.`id` AS `event_ac_id`,
SUM(CASE WHEN trans.gift_transaction_status = 1 THEN trans.event_gift_amount
ELSE 0 END) as amount
FROM `tbl_event_category` `cat` LEFT JOIN `tbl_event` `e`
ON e.event_category=cat.id
LEFT JOIN `tbl_organisation` `org` ON e.organisation_id=org.id
LEFT JOIN `tbl_event_gift_transaction` `trans` ON e.id=trans.event_id
WHERE cat.type ='campaign'
AND is_approved=1
HAVING e.funding_goal_amount <= amount
GROUP BY `event_ac_id` LIMIT 8
The filter on aggregate values is base on having
could be you need this
SELECT *, `e`.`id` AS `event_ac_id`,
SUM(CASE WHEN trans.gift_transaction_status = 1 THEN trans.event_gift_amount
ELSE 0 END) as amount
FROM `tbl_event_category` `cat` LEFT JOIN `tbl_event` `e`
ON e.event_category=cat.id
LEFT JOIN `tbl_organisation` `org` ON e.organisation_id=org.id
LEFT JOIN `tbl_event_gift_transaction` `trans` ON e.id=trans.event_id
WHERE cat.type ='campaign'
AND is_approved=1
HAVING e.funding_goal_amount <= amount
GROUP BY `event_ac_id` LIMIT 8

MySQL Count returns More Rows than it Should

I am attempting to count the number of rows from a given query. But count returns more rows than it should. What is happening?
This query returns only 1 row.
select *
from `opportunities`
inner join `companies` on `opportunities`.`company_id` = `companies`.`id`
left join `opportunityTags` on `opportunities`.`id` = `opportunityTags`.`opportunity_id`
where `opportunities`.`isPublished` = '1' and `opportunities`.`Company_id` = '1'
group by `opportunities`.`id` ;
This query returns that there are 3 rows.
select count(*) as aggregate
from `opportunities`
inner join `companies` on `opportunities`.`company_id` = `companies`.`id`
left join `opportunityTags` on `opportunities`.`id` = `opportunityTags`.`opportunity_id`
where `opportunities`.`isPublished` = '1' and `opportunities`.`Company_id` = '1'
group by `opportunities`.`id`;
When you select count(*) it is counting before the group by. You can probably (unfortunately my realm is SQL Server and I don't have a mySQL instance to test) fix this by using the over() function.
For example:
select count(*) over (partition by `opportunities`.`id`)
EDIT: Actually doesn't look like this is available in mySQL, my bad. How about just wrapping the whole thing in a new select statement? It's not the most elegant solution, but will give you the figure you're after.

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.

SUM() of COUNT() column in MySQL

I have the following query:
SELECT COUNT(employees.id) AS emp_count
FROM `orders`
INNER JOIN `companies` ON `companies`.`id` = `orders`.`company_id`
INNER JOIN employees ON employees.company_id = companies.id
AND (employees.deleted_at >= companies.activate_at OR employees.deleted_at IS NULL)
AND employees.created_at <= companies.activate_at
WHERE
(companies.activate_at BETWEEN '2012-01-31 23:00:00' AND '2012-02-29 22:59:59'
AND orders.type = 'Order::TrialActivation'
AND orders.state = 'completed')
I need the SUM of all the "emp_count" columns. Currently I iterate over all the rows returned by above query, and then SUM on "emp_count" in Ruby. But there are many rows, so this takes up a lot of memory.
How would I SUM on "emp_count" in SQL and return just this number?
--- Update: ---
Since the question has been updated, I'll update my answer:
If you are trying to just get the number of rows from your query based on the WHERE syntax, then you can use COUNT(). However, if you want the sum of all of the employees.id values from the query, then change COUNT(employees.id) to SUM(employees.id), and that should do what you want.
--- Original Answer ---
Try using a subquery, kinda like this (code not tested):
SELECT SUM(x.emp_count) FROM (
SELECT COUNT(employees.id) AS emp_count
FROM `orders`
INNER JOIN `companies` ON `companies`.`id` = `orders`.`company_id`
INNER JOIN employees ON employees.company_id = companies.id
AND (employees.deleted_at >= companies.activate_at OR employees.deleted_at IS NULL)
AND employees.created_at <= companies.activate_at
WHERE
(companies.activate_at BETWEEN '2012-01-31 23:00:00' AND '2012-02-29 22:59:59'
AND orders.type = 'Order::TrialActivation'
AND orders.state = 'completed')
) x;
You can read more on subqueries in the MySQL documentation, and see also: How to SUM() multiple subquery rows in MySQL?