Error when trying to use aliased column name in where clause - mysql

I have a problem with my SQL query. I want to select records by debt amount. Amount is counted by relation with two tables.
This works fine:
SELECT `i`.*,
(i.amount_netto + (i.amount_netto * i.vat / 100)) - (SUM(p.amount_netto)) AS `debt`,
`e`.`name` AS `user_name`,
`e`.`surname` AS `user_surname`,
`c`.`name` AS `contractor_name`
FROM `invoices` AS `i`
INNER JOIN `payments` AS `p` ON i.id = p.invoice_id
INNER JOIN `employees` AS `e` ON i.employee_id = e.id
INNER JOIN `contractors` AS `c` ON i.contractor_id = c.id
GROUP BY `i`.`id`
ORDER BY `debt` ASC
But when I add a WHERE clause by debt I get an error:
Unknown column 'debt' in 'where clause'
Query looks like this:
SELECT `i`.*,
(i.amount_netto + (i.amount_netto * i.vat / 100)) - (SUM(p.amount_netto)) AS `debt`,
`e`.`name` AS `user_name`,
`e`.`surname` AS `user_surname`,
`c`.`name` AS `contractor_name`
FROM `invoices` AS `i`
INNER JOIN `payments` AS `p` ON i.id = p.invoice_id
INNER JOIN `employees` AS `e` ON i.employee_id = e.id
INNER JOIN `contractors` AS `c` ON i.contractor_id = c.id
WHERE `debt` > 1
GROUP BY `i`.`id`
ORDER BY `debt` ASC
Why I can't access debt in the WHERE clause, but I can in the ORDER clause?

debt is not a column, but an alias. Column (expression) aliases are not resolved until after the query is executed, therefore they cannot be used in WHERE clauses.
For example this query is not legal:
select foo + 3 as bar
from baz
where bar = 39
And instead you have to rewrite the whole expression in the WHERE clause:
select foo + 3 as bar
from baz
where foo + 3 = 39
Furthermore, since debt is actually based on an aggregate, you cannot filter this in a WHERE clause. You must instead use HAVING to evaluate the predicate after the aggregation. Therefore your query should be:
SELECT ...
FROM ...
GROUP BY ...
HAVING (i.amount_netto + (i.amount_netto * i.vat / 100)) - (SUM(p.amount_netto)) > 1
ORDER BY ...
Note that MySql offers an SQL extension which enables the use of aliases in the HAVING clause, so you can also do:
SELECT ...
FROM ...
GROUP BY ...
HAVING debt > 1
ORDER BY ...

SQL doesn't typically allow you to reference column aliases in WHERE, GROUP BY or HAVING clauses. MySQL does support referencing column aliases in the GROUP BY and HAVING
try change your where query to
WHERE (i.amount_netto + (i.amount_netto * i.vat / 100)) - (SUM(p.amount_netto)) > 1 GROUP BY i.id ORDER BY debt ASC
another option, you could use a subquery
SELECT * from (`i`.*, (i.amount_netto + (i.amount_netto * i.vat / 100)) - (SUM(p.amount_netto)) AS `debt`, `e`.`name` AS `user_name`, `e`.`surname` AS `user_surname`, `c`.`name` AS `contractor_name` FROM `invoices` AS `i` INNER JOIN `payments` AS `p` ON i.id = p.invoice_id INNER JOIN `employees` AS `e` ON i.employee_id = e.id INNER JOIN `contractors` AS `c` ON i.contractor_id = c.id GROUP BY `i`.`id`) as newTable
WHERE `debt` > 1 ORDER BY `debt` ASC

Related

MySQL Query, (access mainquery from subquery)

I have a problem that I need a WHERE clause in a subquery that depends on the results of the main Query, otherwise my results would be wrong and the query takes too long / is not executeable.
The circumstances that I need this query to create a view which I need for a search server support the problem that I cannot split this into two queries, nor process it with a script dynamically.
The problem occurs with the following query:
SELECT `s`.`id` AS `seminar_id`, (SUM( `sub`.`seminar_rate` ) / COUNT( `sub`.`seminar_id` )) AS `total_rate`
FROM
(
SELECT (SUM( value ) / COUNT( * )) AS `seminar_rate` , `r`.`seminar_id`
FROM `rating` r
INNER JOIN `rating_item` ri ON `r`.`id` = `ri`.`rating_id`
WHERE `r`.`seminar_id` = `s`.`id`/* <- Here is my problem, this is inacessible */
GROUP BY `r`.`seminar_id`
) AS sub,
`seminar` s
INNER JOIN `date` d
ON `s`.`id` = `d`.`seminar_id`
INNER JOIN `date_unit` du
ON `d`.`id` = `du`.`date_id`
LEFT JOIN `seminar_subject` su
ON `s`.`id` = `su`.`seminar_id`
LEFT JOIN `subject` suj
ON `su`.`subject_id` = `suj`.`id`
INNER JOIN `user` u
ON `s`.`user_id` = `u`.`id`
INNER JOIN `company` c
ON `u`.`company_id` = `c`.`id`
GROUP BY `du`.`date_id`, `sub`.`seminar_id`
This query should calculate a total rate out of ratings for each Seminar.
However my ratings are stored in my "rating" table and should be processed live.
(Sidenote: If you wonder about all the joins: This query has alooot more SELECT'ed fields, I just removed them because they are not nesessary to solve the problem and to make the query look less complicated [I know it still is >.>]...)
The reason is that I want this results to be sortable by my search engine later depending
on the users sort parameters, thatswhy I need it inside this query.
The problem itself is pretty obvious:
ERROR 1054 (42S22): Unknown column 's.id' in 'where clause'
The subselect doesnt know about the results of the main query, is there a solution to bypass this?
Could someone give me a hint to get this working?
Thanks in advance.
Using your subquery in the JOIN you can eliminate the WHERE clause and achieve nearly the same result. Here is your modified query. Hope this solves your problem.
SELECT `s`.`id` AS `seminar_id`, (SUM( `sub`.`seminar_rate` ) / COUNT( `sub`.`seminar_id` )) AS `total_rate`
FROM `seminar` s
INNER JOIN
(
SELECT (SUM( value ) / COUNT( * )) AS `seminar_rate` , `r`.`seminar_id`
FROM `rating` r
INNER JOIN `rating_item` ri ON `r`.`id` = `ri`.`rating_id`
/*WHERE `r`.`seminar_id` = `s`.`id` <- Here is my problem, this is inacessible */
GROUP BY `r`.`seminar_id`
) AS sub ON s.id = sub.`seminar_id`
INNER JOIN `date` d
ON `s`.`id` = `d`.`seminar_id`
INNER JOIN `date_unit` du
ON `d`.`id` = `du`.`date_id`
LEFT JOIN `seminar_subject` su
ON `s`.`id` = `su`.`seminar_id`
LEFT JOIN `subject` suj
ON `su`.`subject_id` = `suj`.`id`
INNER JOIN `user` u
ON `s`.`user_id` = `u`.`id`
INNER JOIN `company` c
ON `u`.`company_id` = `c`.`id`
GROUP BY `du`.`date_id`, `sub`.`seminar_id`

Need to Optimise the following MySQL query

I've tried this query successfully with a limit. The following query runs endless without limit:
SELECT o.product_sku
FROM order_table o
WHERE EXISTS (SELECT 1
FROM (SELECT DISTINCT u.type_id,
u.charge_type,
u.billed_weight
FROM ups_table u
WHERE charge_type = 'order_shipping_table'
AND NOT billed_weight = '0'
) dtm
WHERE o.order_id = dtm.type_id)
GROUP BY product_sku
HAVING Count(product_sku) > 1
First of all you don't need these subqueries with DISTINCT and so on:
SELECT o.product_sku
FROM order_table o
WHERE EXISTS (SELECT 1
FROM ups_table u
WHERE charge_type = 'order_shipping_table'
AND NOT billed_weight = '0'
AND type_id=o.order_id
)
GROUP BY product_sku
HAVING Count(product_sku) > 1
I don't know your table structure (what do you want to count in the HAVING?) but you can try to change EXISTS to JOIN:
SELECT o.product_sku
FROM order_table o
JOIN ups_table u on (u.type_id=o.order_id)
AND (u.charge_type = 'order_shipping_table')
AND NOT (billed_weight = '0')
GROUP BY product_sku
HAVING Count(DISTINCT o.order_id) > 1
And you need indexes on o.order_id, o.product_sku, u.type_id,u.charge_type, u.billed_weight

MySQL throwing error on second JOIN

I'm getting the following error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'JOIN product_catalog ON product_catalog.entity_id
As a result of the following query:
SELECT sales_order.created_at , order_item.order_id, sales_order.increment_id, SUM(order_item.qty_ordered) AS qty_ordered , COUNT( * )
FROM order_item
JOIN sales_order
ON sales_order.entity_id = order_item.order_id
WHERE sales_order.created_at > '2012-11-15 00:00:00'
JOIN product_catalog
ON product_catalog.entity_id = order_item.product_id
WHERE product_catalog.size = 14
GROUP BY order_item.order_id;
Variations on this query have worked for grouping different types of product by sales order in the past where I only needed to perform one JOIN to get all the info I needed. The problem I'm encountering is from the second JOIN. Clearly I'm missing something but I really am not sure what. :(
Please make sure that WHERE condition must be after all JOIN
SELECT sales_order.created_at , order_item.order_id, sales_order.increment_id, SUM(order_item.qty_ordered) AS qty_ordered , COUNT( * )
FROM order_item
JOIN sales_order
ON sales_order.entity_id = order_item.order_id
JOIN product_catalog
ON product_catalog.entity_id = order_item.product_id
WHERE product_catalog.size = 14
AND sales_order.created_at > '2012-11-15 00:00:00'
GROUP BY order_item.order_id;
First of all you have to JOIN your tables which you need. Then after WHERE clause come for conditions.
Your WHERE clauses are in the wrong spots. See the code below for proper JOIN syntax.
SELECT sales_order.created_at,
order_item.order_id,
sales_order.increment_id,
SUM(order_item.qty_ordered) AS qty_ordered,
COUNT( * )
FROM order_item
JOIN sales_order
ON sales_order.entity_id = order_item.order_id
AND sales_order.created_at > '2012-11-15 00:00:00'
JOIN product_catalog
ON product_catalog.entity_id = order_item.product_id
AND product_catalog.size = 14
GROUP BY order_item.order_id
JOIN...ON... clause it's also section to input condition so you don't need where clause, just add AND instead.
SELECT sales_order.created_at , order_item.order_id, sales_order.increment_id,
SUM(order_item.qty_ordered) AS qty_ordered , COUNT( * )
FROM order_item
JOIN sales_order ON sales_order.entity_id = order_item.order_id
and sales_order.created_at > '2012-11-15 00:00:00'
JOIN product_catalog ON product_catalog.entity_id = order_item.product_id
and product_catalog.size = 14
GROUP BY order_item.order_id;
Please consider below example I added aliases. It's good practice to use it because code is more readable.
SELECT SO.created_at , OI.order_id, SO.increment_id,
SUM(OI.qty_ordered) AS qty_ordered , COUNT( * )
FROM order_item OI
JOIN sales_order SO ON SO.entity_id = OI.order_id
and SO.created_at > '2012-11-15 00:00:00'
JOIN product_catalog PC ON PC.entity_id = OI.product_id
and PS.size = 14
GROUP BY OI.order_id;

MySQL Joined SELECT COUNT()

I wish to select results across several tables, but I only want to return rows based on the COUNT() result of joined SELECT query.
Here's how the query looks at the moment:
SELECT `s`.`venue_id` AS `id`,
CONCAT(`u`.`First_name`, ' ', `u`.`Surname`) AS `user_name`,
`u`.`avatar` AS `avatar`,
`u`.`facebookId` AS `fid`,
`x`.`imgs` AS `num_imgs`
FROM `new_shortlists_venues` `s`
INNER JOIN `new_shortlists` ON `new_shortlists`.`id` = `s`.`list_id`
INNER JOIN `users` `u` ON `u`.`id` = `new_shortlists`.`bride_id`
LEFT JOIN (SELECT `listing_id`, COUNT(*) `imgs` FROM `listingsImages`) `x` ON `s`.`venue_id` = `x`.`listing_id`
WHERE `new_shortlists`.`venues` > 4
AND `new_shortlists`.`bride_id` != 0
GROUP BY `s`.`list_id`
ORDER BY `s`.`date_added` DESC
LIMIT 6
For some reason, the query returns NULL for num_imgs. Essentially, I'd like to select only records which have at least 4 records in the listingsImages table.
Please note that this is for a legacy system, and I didn't design the DB! As a result, I have now option to change the schema.
You left off the GROUP BY of your subquery. Your current query is returning COUNT(*) associated with a random listing_id. Add GROUP BY listing_id and you should return the correct counts.
SELECT `s`.`venue_id` AS `id`,
CONCAT(`u`.`First_name`, ' ', `u`.`Surname`) AS `user_name`,
`u`.`avatar` AS `avatar`,
`u`.`facebookId` AS `fid`,
`x`.`imgs` AS `num_imgs`
FROM `new_shortlists_venues` `s`
INNER JOIN `new_shortlists` ON `new_shortlists`.`id` = `s`.`list_id`
INNER JOIN `users` `u` ON `u`.`id` = `new_shortlists`.`bride_id`
LEFT JOIN (SELECT `listing_id`, COUNT(*) `imgs`
FROM `listingsImages`
GROUP BY `listing_id`) `x` ON `s`.`venue_id` = `x`.`listing_id`
WHERE `new_shortlists`.`venues` > 4
AND `new_shortlists`.`bride_id` != 0
GROUP BY `s`.`list_id`
ORDER BY `s`.`date_added` DESC
LIMIT 6
And to return those with at least 4 records, just add that constraint to your WHERE criteria:
AND `x`.`imgs` >= 4
This might be the culprit:
ON `s`.`venue_id` = `x`.`listing_id`

Help on MySQL query

I have the following table structure:
Customers - Cust_Orders - Cust_Items - Cust_Payments - Drivers
id id id id id
company cid oid oid name
driver price amount
date qty date
vat
What I want to do is showing last unpaid order marked by a specific driver id + the sum of all unpaid orders for that particular customer except the order that is already selected.
Since there might be more than one cust_items & more than one cust_payments I had to use select from select as otherwise I would have wrong sums & things got messy till I reached a point I forgot what I was doing.
Any Help would be greatly appreciated.
My current SQL which lacks the final part only (sum of other unpaid orders amounts):
SELECT `customers`.`company`,
T1.*,
ROUND( IFNULL( SUM(`cust_payments`.`amount`), 0 ), 2) AS `paid`
FROM (
SELECT `cust_orders`.*,
ROUND( IFNULL( SUM(`cust_items`.`qty` * `cust_items`.`price`), 0 ), 2) AS `total`,
SUM( ( `cust_items`.`price` * `cust_items`.`qty` * `vat` ) / 100) AS `vat`
FROM `cust_orders`
LEFT JOIN `cust_items` ON `cust_orders`.`id` = `cust_items`.`oid`
GROUP BY `cust_orders`.`id`
) `T1`
LEFT JOIN `customers` ON `T1`.`cid` = `customers`.`id`
LEFT JOIN `cust_payments` ON `T1`.`id` = `cust_payments`.`oid`
WHERE `T1`.`driver` = ? GROUP BY `T1`.`id` HAVING (`T1`.`total` - `paid`) > ?
ORDER BY `T1`.`id` DESC LIMIT 1
Can you try
SELECT
x.id,
x.company,
y.id,
y.cid,
y.driver,
y.date,
#ut:=ROUND(SUM(z.qty*z.price),2) AS unpaid_total,
#uv:=SUM((#ut*z.vat)/100) AS unpaid_vat,
#st:=ROUND(SUM(b.qty*b.price),2)-#ut AS sum_total,
SUM((#st*b.vat)/100)-#uv AS sum_vat
FROM Customers x
INNER JOIN Cust_Orders y ON x.id=y.cid
INNER JOIN Cust_Items z ON y.id=z.oid
LEFT JOIN Cust_Orders a ON x.id=a.cid
LEFT JOIN Cust_Items b ON a.id=b.oid
WHERE
y.driver=? AND
NOT EXISTS (SELECT * FROM Cust_Payments WHERE oid=y.id) AND
NOT EXISTS (SELECT * FROM Cust_Payments WHERE oid=a.id)
GROUP BY x.id,x.company, y.id, y.cid, y.driver, y.date