SQL - Unknown column in where clause - mysql

I am rather new with SQL and I can't for the life of me figure out why I can't do what I'm trying here. I'm trying get the least number of free seats in a package-trip, and group them by the package ID.
The first of the subqueries work, but the second is the one I can't figure out. It says
Unkown column SuperPaket in 'where clause'.
select Paket.PaketID as "SuperPaket", Beskrivning, Resa.AvgångStad, Resa.AvgångTid, Resa.AvgångDatum,
(select AnkomstTid from Resa where Resa.ResID in
(select ResID from PaketResa where PaketResa.PaketID = SuperPaket and Ordningsnr =
(select max(Ordningsnr) from PaketResa where PaketResa.PaketID = SuperPaket))) "AnkomstTid",
(select min(LedigaPlatser) from
(select sum(AntalPlatser - Count) "LedigaPlatser", ResID from(
select Bokning.ResID, AntalPlatser, sum(Bokning.AntalBiljetter) as Count from
(Resa inner join Bokning on Resa.ResID = Bokning.ResID) where Bokning.ResID in
(select PaketResa.ResID from PaketResa where PaketResa.PaketID = SuperPaket)
group by Bokning.ResID order by Count desc)
as CountTable group by ResID)
as T) "LedigaPlatser"
from ((Paket inner join PaketResa on Paket.PaketID = PaketResa.PaketID) inner join Resa on PaketResa.ResID = Resa.ResID) group by Paket.PaketID;
Why does this work for the first subquery but not the second one?
Update..
The error seems to appear when I put a "sub-subquery" in a from clause. I don't know how to rewrite the problematic query to fix this problem though, and I would really appreciate some help. Thanks..

I don't think you can use column alias in a where clause in mysql and oracle
From mysql docs
Standard SQL disallows references to column aliases in a WHERE clause.
This restriction is imposed because when the WHERE clause is
evaluated, the column value may not yet have been determined.
You can use the alias in GROUP BY, ORDER BY, or HAVING clauses to
refer to the column:
I have no idea about sql server
Added :
Your subquery probably not getting Paket.PaketId.
Try modifying from clause of most outer query by adding
(select Paket.PaketID as "SuperPaket" from Paket)
as below
from (
(Paket inner join PaketResa on Paket.PaketID = PaketResa.PaketID)
inner join Resa on PaketResa.ResID = Resa.ResID),
(select Paket.PaketID as "SuperPaket" from Paket)
group by Paket.PaketID;
Also remove alias from first select and just say select SuperPaket

your column is Paket.PaketID not "SuperPaket" so use Paket.PaketID wherever you used superpaket
select Paket.PaketID as "SuperPaket", Beskrivning, Resa.AvgångStad,
Resa.AvgångTid, Resa.AvgångDatum,
(select AnkomstTid from Resa where Resa.ResID in
(select ResID from PaketResa where PaketResa.PaketID = Paket.PaketID and Ordningsnr =
(select max(Ordningsnr) from PaketResa where PaketResa.PaketID = Paket.PaketID))) "AnkomstTid",
(select min(LedigaPlatser) from
(select sum(AntalPlatser - Count) "LedigaPlatser", ResID from(
select Bokning.ResID, AntalPlatser, sum(Bokning.AntalBiljetter) as Count from
(Resa inner join Bokning on Resa.ResID = Bokning.ResID) where Bokning.ResID in
(select PaketResa.ResID from PaketResa where PaketResa.PaketID = Paket.PaketID)
group by Bokning.ResID order by Count desc)
as CountTable group by ResID)
as T) "LedigaPlatser"
from ((Paket inner join PaketResa on Paket.PaketID = PaketResa.PaketID) inner join Resa on PaketResa.ResID = Resa.ResID) group by Paket.PaketID;

Related

SELECT MAX in GROUP BY but LIMIT results to 1 in MYSQL

I have the following tables:
Task (id,....)
TaskPlan (id, task_id,.......,end_at)
Note that end_at is a timestamp and that one Task has many TaskPlans. I need to query for the MAX end_at for each Task.
This query works fine, except when you have the same exact timestamp for different TaskPlans. In that case, I would be returned multiple TaskPlans with the MAX end_at for the same Task.
I know this is an unlikely situation, but is there anyway I can limit the number of results for each task_id to 1?
My current code is:
SELECT * FROM Task AS t
INNER JOIN (
SELECT * FROM TaskPlan WHERE end_at in (SELECT MAX(end_at) FROM TaskPlan GROUP BY task_id )
) AS pt
ON pt.task_id = t.id
WHERE status = 'plan';
This works, except in the above situation, how can this be achieved?
Also in the subquery, instad of SELECT MAX(end_at) FROM TaskPlan GROUP BY task_id, is it possible to do something like this so I can use TaskPlan.id for the where in clause?
SELECT id, MAX(end_at) FROM TaskPlan GROUP BY task_id
When I try, it gives the following error:
SQL Error [1055] [42000]: Expression #1 of SELECT list is not in GROUP
BY clause and contains nonaggregated column 'TaskPlan.id' which is not
functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
Any explaination and suggestion would be much welcome!
Note on duplicate label: (Now reopened)
I already studied the this question, but it does not provide an answer for my situation where there are multiple max values in the result and it needs to be filtered out to include only one result row per group.
Use the id rather than the timestamp:
SELECT *
FROM Task AS t INNER JOIN
(SELECT tp.*
FROM TaskPlan tp
WHERE tp.id = (SELECT tp2.id FROM TaskPlan tp2 WHERE tp2.task_id = tp.task_id ORDER BY tp2.end_at DESC LIMIT 1)
) tp
ON tp.task_id = t.id
WHERE status = 'plan';
Or use in with tuples:
SELECT *
FROM Task AS t INNER JOIN
(SELECT tp.*
FROM TaskPlan tp
WHERE (tp.task_id, tp.end_at) in (SELECT tp2.task_id, MAX(tp2.end_at)
FROM TaskPlan tp2
GROUP BY tp2.task_id
)
) tp
ON tp.task_id = t.id
WHERE status = 'plan';
If you want to get a list of task ID's with MAX end_at for each, run the query below:
SELECT t.id, MAX(tp.end_at) FROM Task t JOIN TaskPlan tp on t.id = tp.task_id GROUP BY t.id;
EDIT:
Now, I know what exactly you are going to do.
If the TaskPlan table is so big, you can avoid the 'GROUP BY' and run the query below that is very efficient:
SET #first_row := 0;
SET #task_id := 0;
SELECT * FROM Task t JOIN (
SELECT tp.*
, IF(#task_id = tp.`task_id`, #first_row := 0, #first_row := 1) AS temp
, #first_row AS latest_record
, #task_id := tp.`task_id`
FROM TaskPlan tp ORDER BY task_id, end_at DESC) a ON t.task_id = a.task_id AND a.latest_record = 1;
Try this query:
select t.ID , tp1.end_at
from TASK t
left join TASKPLAN tp1 on t.ID = tp1.id
left join TASKPLAN tp2 on t.ID = tp2.id and tp1.end_at < tp2.end_at
where tp2.end_at is null;

Mysql Select unique record based on multiple columns and display only group and sum amount

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

Adding sub query - SQL Server 2008

I have following SQL query but this is not quite what I want:
SELECT
TOP (20) Attribs.ImageID AS ItemID
FROM
Attribs
LEFT OUTER JOIN
Items ON Attribs.ImageID = Items.ImageID
WHERE
(attribID IN ('a','b','c','d','e'))
AND (deleted NOT IN (1,2))
AND Attribs.attribID = 'a' AND Attribs.attribID = 'b'
GROUP BY
Attribs.ImageID
ORDER BY
COUNT(DISTINCT attribID) DESC
What I need is to query
AND Attribs.attribID = 'a' AND Attribs.attribID = 'b'
first, then rest of the WHERE clause based on the above query results.
Is this possible to achieve using sub query?
I'm using SQL Server 2008
Thank you
I'm not totally getting the reason why you want to do this one query first before the other.... but you could use a Common Table Expression (CTE) - something like this:
;WITH FirstQuery AS
(
SELECT a.ImageId
FROM dbo.Attribs a
WHERE a.attribID = 'a' AND a.attribID = 'b'
)
SELECT
TOP (20) a.ImageID AS ItemID
FROM
dbo.Attribs a
INNER JOIN
FirstQuery fq ON a.ImageId = fq.ImageId
LEFT OUTER JOIN
dbo.Items i ON a.ImageID = i.ImageID
WHERE
(attribID IN ('a','b','c','d','e'))
AND (deleted NOT IN (1,2))
GROUP BY
a.ImageID
ORDER BY
COUNT(DISTINCT attribID) DESC
With this, you first select the ImageID from your dbo.Attribs table in the CTE, and then join that result set with the result of the table and join to the Items table.
You want to do that for performance issues? Because splitting this up won't change the results.
Anyway, you can do this like:
SELECT TOP (20) rn_Attribs.ImageID AS ItemID
FROM (SELECT *
FROM Attribs
WHERE Attribs.attribID = '123' AND Attribs.attribID = '456') rn_Attribs
LEFT OUTER JOIN Items ON rn_Attribs.ImageID = Items.ImageID
WHERE(attribID IN ('a','b','c'))
AND (deleted NOT IN (1,2))
GROUP BY rn_Attribs.ImageID
ORDER BY COUNT(DISTINCT attribID) DESC

MySQL DISTINCT not Filtering out

I have the folowing sql query:
SELECT DISTINCT(tbl_products.product_id), tbl_products.product_title,
tbl_brands.brand_name, tbl_reviews.review_date_added,
NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
ORDER BY tbl_reviews.review_date_added DESC
That needs to filter out any duplicate product_id's unfortunatly selecting tbl_reviews.review_date_added makes each record unique which means DISTINCT will not work anymore.
Is there any otherway of doing this query so that product_id is still unique?
I did do the GROUP BY and the problem is I display the tbl_reviews.review_date_added on a website and it selects the oldest date. I need the newest date.
Regards
With the description given, it's a bit hard to be certain, but if review_date_added is the only problem, it seems like you want the MAX() of that date?
If the following doesn't help, please could you give example data, example output, and a description of how you want the output to be created?
SELECT
tbl_products.product_id,
tbl_products.product_title,
tbl_brands.brand_name,
MAX(tbl_reviews.review_date_added) AS review_date_added,
NOW() AS time_now
FROM
tbl_products
INNER JOIN
tbl_reviews
ON tbl_products.product_id = tbl_reviews.product_id
INNER JOIN
tbl_brands
ON tbl_products.brand_id = tbl_brands.brand_id
GROUP BY
tbl_products.product_id,
tbl_products.product_title,
tbl_brands.brand_name
ORDER BY
MAX(tbl_reviews.review_date_added) DESC
Distinct works for the entire row. The parenthesis are just around the field:
distinct (a), b, c === distinct a, b, c
A straightforward solution is group by. You can use min to select the oldest date.
select tbl_products.product_id
, min(tbl_products.product_title)
, min(tbl_brands.brand_name)
, min(tbl_reviews.review_date_added)
, NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
GROUP BY
tbl_products.product_id
ORDER BY
min(tbl_reviews.review_date_added) DESC
Note that if a product can have multiple brands, this will pick the lowest one.
Try this:
SELECT pr.product_id, pr.product_title,
bd.brand_name,
(SELECT MAX(rev.review_date_added) FROM tbl_reviews rev
WHERE pr.product_id = rev.product_id) AS maxdate,
NOW() AS time_now
FROM tbl_products pr INNER JOIN tbl_reviews re
ON pr.product_id = re.product_id
INNER JOIN tbl_brands bd
ON pr.brand_id = bd.brand_id
GROUP BY pr.product_id
ORDER BY re.review_date_added DESC
or (as suggested by #Hogan)
SELECT pr.product_id, pr.product_title,
bd.brand_name, md.maxdate
NOW() AS time_now
FROM tbl_products pr INNER JOIN tbl_reviews re
ON pr.product_id = re.product_id
INNER JOIN tbl_brands bd
ON pr.brand_id = bd.brand_id
INNER JOIN (SELECT product_id, MAX(review_date_added) AS maxdate
FROM tbl_reviews rev GROUP BY product_id) md
ON pr.product_id = md.product_id
GROUP BY pr.product_id
ORDER BY re.review_date_added DESC
I combined the answer of Andomar with some changes you will find here.
SELECT tbl_products.product_id, tbl_products.product_title,
tbl_products.product_date_added, tbl_brands.brand_name,
MAX(tbl_reviews.review_date_added) AS review_date_added, NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
GROUP BY tbl_products.product_id
ORDER BY MAX(tbl_reviews.review_date_added) DESC
Works beautifully and shows the newest date at tbl_reviews.review_date_added.
Regards

MySQL sum of sub queries

I have quite a long query that is causing me some problems. For the first sub-query I keep getting the error: "MySQL server version for the right syntax to use near 'SELECT project.project_total_num_hours_quoted FROM project inner join time_recor' at line 5".
The subquery in question is:
sum(SELECT
project.project_total_num_hours_quoted
FROM
project inner join time_recording using(project_id)
WHERE
project.company_id = company.company_id
AND project_is_retainer != 1
AND time_recording.time_recording_event_start_datetime >= '2011-01-01' AND time_recording.time_recording_event_stop_datetime <= '2011-03-01'
group by project_id
) AS hours_quoted,
This returns a set of results. In the larger query I simply want to have the sum.
SELECT
SUM((unix_timestamp(time_recording.time_recording_event_stop_datetime)-unix_timestamp(time_recording.time_recording_event_start_datetime))/3600) AS total_time,
company.company_label,
sum(SELECT
project.project_total_num_hours_quoted
FROM
project inner join time_recording using(project_id)
WHERE
project.company_id = company.company_id
AND project_is_retainer != 1
AND time_recording.time_recording_event_start_datetime >= '2011-01-01' AND time_recording.time_recording_event_stop_datetime <= '2011-03-01'
group by project_id
) AS hours_quoted,
(SELECT SUM(project.project_total_num_hours_quoted)
FROM project
INNER JOIN time_recording ON project.project_id = time_recording.project_id
WHERE time_recording.time_recording_event_start_datetime>='2011-01-01'
AND project_is_retainer!=1
AND time_recording.time_recording_event_stop_datetime<='2011-03-01'
AND project.company_id!=1
) AS total_hours_quoted,
(
SELECT
SUM((unix_timestamp(time_recording.time_recording_event_stop_datetime)-unix_timestamp(time_recording.time_recording_event_start_datetime))/3600)
FROM time_recording
INNER JOIN project ON time_recording.project_id = project.project_id
WHERE project.company_id!=1
AND project_is_retainer!=1
AND time_recording.time_recording_event_start_datetime>='2011-01-01'
AND time_recording.time_recording_event_stop_datetime<='2011-03-01'
)
AS total_hours
FROM time_recording
INNER JOIN project ON time_recording.project_id = project.project_id
INNER JOIN company ON project.company_id = company.company_id
WHERE company.company_id!=1
AND project_is_retainer!=1
AND time_recording.time_recording_event_start_datetime>='2011-01-01'
AND time_recording.time_recording_event_stop_datetime<='2011-03-01'
GROUP BY company.company_id
ORDER BY total_time desc
LIMIT 7
In your first subquery, you don't need the group by if you sum it in the outer query. And you are missing the ON clause.
SELECT project.project_total_num_hours_quoted
FROM project inner join time_recording
ON project.id=time_recording.project_id
WHERE
project.company_id = company.company_id
AND project_is_retainer != 1
AND time_recording.time_recording_event_start_datetime >= '2011-01-01'
AND time_recording.time_recording_event_stop_datetime <= '2011-03-01'
I would strongly recommend scrapping this and starting again.
Several, if not all, the subselects could be merged into a single SELECT statement. The outer SELECT is an aggregate operation which selects non-aggregated values not included in the GROUP BY clause. MySQL does not optimize push-predicates. And you've got redundant joins in the query.