Mysql Database - Average value - mysql

Here's a question:
Using appropriate column names, show admit id and average obs value for obs type 'CONT' where the average obs value of the CONT is >= 40.
Lets say admit is table1 and observe is table2 but with the same primary key Admit_id. I'm trying to get the result where average of obs value is greater than 40 but
however I got this error instead: Unknown column 'Average' in 'where clause. Any solution here?
Select
ADMIT.Admit_id,
(SELECT AVG(Obs_value) FROM OBSERVE) AS Average
from
ADMIT,OBSERVE
Where
ADMIT.Admit_id=OBSERVE.Admit_id
AND
OBSERVE.Obs_type = 'CONT'
AND
Average >=40;

you should try joining the two tables and you cant reference an alias inside the WHERE .. it has to be HAVING. so something like this..
SELECT a.Admit_id, AVG(o.Obs_value) AS Average
FROM ADMIT a
JOIN OBSERVE o ON o.admit_id = a.admit_id
WHERE o.Obs_type = "CONT"
GROUP BY a.Admit_id
HAVING Average >=40;
Think of it this way...
SELECT is making an order at a restaurant....
FROM and JOIN is saying what menu's you want to order from....
WHERE is any customization you want to make to your order (aka no mushrooms)....
GROUP BY and anything after is after the order has been completed and is at your table...
ORDER BY is saying what dishes you want first (aka i want my entree then dessert then appetizer ).
HAVING can be used to pick out any mushrooms that were accidentally left on the plate....
etc.. I know its a weird analogy but its a good way to understand how it works..
the alias to a table cannot be referenced until you create that table with your select you could also make it a sub select and do the same thing with a WHERE like so
SELECT *
FROM
( ... your_inner_select -- without the HAVING
)t -- every table must have an alias
WHERE t.Average >=40

Related

SQL Temporary Table or Select

I've got a problem with MySQL select statement.
I have a table with different Department and statuses, there are 4 statuses for every department, but for each month there are not always every single status but I would like to show it in the analytics graph that there is '0'.
I have a problem with select statement that it shows only existing statuses ( of course :D ).
Is it possible to create temporary table with all of the Departments , Statuses and amount of statuses as 0, then update it by values from other select?
Select statement and screen how it looks in perfect situation, and how it looks in bad situation :
SELECT utd.Departament,uts.statusDef as statusoforder,Count(uts.statusDef) as Ilosc_Statusow
FROM ur_tasks_details utd
INNER JOIN ur_tasks_status uts on utd.StatusOfOrder = uts.statusNR
WHERE month = 'Sierpien'
GROUP BY uts.statusDef,utd.Departament
Perfect scenario, now bad scenario :
I've tried with "union" statements but i don't know if there is a possibility to take only "the highest value" for every department.
example :
I've also heard about
With CTE tables, but I don't really get how to use it. Would love to get some tips on it!
Thanks for your help.
Use a cross join to generate the rows you want. Then use a left join and aggregation to bring in the data:
select d.Departament, uts.statusDef as statusoforder,
Count(uts.statusDef) as Ilosc_Statusow
from (select distinct utd.Departament
from ur_tasks_details utd
) d cross join
ur_tasks_status uts left join
ur_tasks_details utd
on utd.Departament = d.Departament and
utd.StatusOfOrder = uts.statusNR and
utd.month = 'Sierpien'
group by uts.statusDef, d.Departament;
The first subquery should be your source of all the departments.
I also suspect that month is in the details table, so that should be part of the on clause.

error #1055 yet another contains nonaggregated column which is not functionally dependent on columns in GROUP BY

I know a lot of questions have already been answered on this one but I still cant wrap my head around it why the following isnt working.
My main goal was to join a price and product table and select the cheapest price for each product based on each 3 factors.
For quick testing I went ahead and just filtered my price table which contains the a ref to my corresponding product, price, rrp and some columns for knowing when to apply which price.
SELECT product_ref_id, price, rrp WHERE (.... filter by attributes ....).
This works fine, but for consistency I get at least 2 rows. Thing is I want to get the cheapest price BUT I also need the rrp for displaying. So I went ahead and made:
SELECT product_ref_id, min(price), rrp WHERE (.... filter by attributes ....) GROUPY BY product_ref_id
Which gives me error #1055:
#1055 - Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'igros_backend.prices.rrp' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
Once I leave out the rrp select it works just fine, but I cant get my rrp then (the rrp can differ on the results as well). If I put the rrp into my group_by I get more than 1 result per id which is also not the way it is intended to be.
And as I read disabling the only_full_group_by is not the way to go.
Any help where my brain is going wrong here?
Could this be due to the fact that not all rrp have a set price but can also be null?
Edit: As a matter of fact each entry has its own id, so in my opinion the most logical way when using subqueries would be to prefilter the table by my conditions, join on the id with the price and uvp, then select by my min(price) and group by after.
Further edit: as I just cant get it to work I will explain all in more detail.
This is my table
id product_id_ref filterOption filterOptionCode price rrp
For each product_id_ref there might be more than one or one entry in the table.
I have to check if the filterOption applies (this depends on the logged user). So I get at least 1 result back, mostly 2 but more are also possible.
Which works fine... If I just want the price and product_ref_id back.
Might the problem be that I get back the same product_id_ref multiple times?
You can get it when you find MIN price in a subquery:
SELECT
sub.product_ref_id,
sub.price,
sub.product_id,
sub.id,
main.rrp
FROM
{table} AS main
JOIN
(SELECT
product_ref_id,
MIN(price),
product_id,
MIN(id)
WHERE
[... filter by attributes ....]
GROUP BY
product_ref_id, product_id
) AS sub ON sub.product_ref_id = main.product_ref_id AND sub.price = main.price AND sub.id = main.id AND sub.product_id = main.product_id;
So in a subuquery you get the field with min price and you use this resultset to join with original table records. This way you can get the rest of the fields for the row with MIN price.
My main goal was to join a price and product table and select the cheapest price for each product based on each 3 factors.
The simplest method is to use window functions. The looks something like this:
select pp.*
from (select pr.*, p.*,
min(pr.price) over (partition by pr.product_id) as min_price
from price pr join
product p
on pr.product_id = p.product_id
) pp
where price = min_price
Your question does not elaborate on what the data really looks like, but this is the structure for joining two tables and taking the smallest value by some unit (such as product).

SQL: Column Must Appear in the GROUP BY Clause Or Be Used in an Aggregate Function

I'm doing what I would have expected to be a fairly straightforward query on a modified version of the imdb database:
select primary_name, release_year, max(rating)
from titles natural join primary_names natural join title_ratings
group by year
having title_category = 'film' and year > 1989;
However, I'm immediately running into
"column must appear in the GROUP BY clause or be used in an aggregate function."
I've tried researching this but have gotten confusing information; some examples I've found for this problem look structurally identical to mine, where others state that you must group every single selected parameter, which defeats the whole purpose of a group as I'm only wanting to select the maximum entry per year.
What am I doing wrong with this query?
Expected result: table with 3 columns which displays the highest-rated movie of each year.
If you want the maximum entry per year, then you should do something like this:
select r.*
from ratings r
where r.rating = (select max(r2.rating) where r2.year = r.year) and
r.year > 1989;
In other words, group by is the wrong approach to writing this query.
I would also strongly encourage you to forget that natural join exists at all. It is an abomination. It uses the names of common columns for joins. It does not even use properly declared foreign key relationships. In addition, you cannot see what columns are used for the join.
While I am it, another piece of advice: qualify all column names in queries that have more than one table reference. That is, include the table alias in the column name.
If you want to display all the columns you can user window function like :
select primary_name, year, max(rating) Over (Partition by year) as rating
from titles natural
join primary_names natural join ratings
where title_type = 'film' and year > 1989;

Creating joins based on range of number value

Could you guys provide me on the situation below?
I have 2 tables.
Table 1 looks like this:
Meanwhile, this is table 2:
I would like to join table 2 to table 1 to lookup the grade for each job based on the upper and lower limit column.
By conceptualizing some of the lovely answers here, I manage to come up with a statement that looks something like this:
FROM table2 LEFT JOIN table1 ON (table2.[score] >= table1.[lower limit]) AND (table2.[score] <= table1.[upper limit])
The statement above manage to join them according to a range, however, for some unknown reasons, some rows from the left table went missing and I could not determine what it is. e.g (2000 rows in table 2, but only 1800 in the query)
I am sure the join is the cause, as if i change the join to a equal left join, 2000 rows appear in the query.
Can someone advice me on this?
Regards,
Guang Yong
Perhaps it would be much cleaner to create a table with values from 1-100 and assign them each on of your categories, and essentially mirroring your table 1.
Then you can do Table 2
SELECT Table1.Grade, Table2.Score
FROM Table2 LEFT JOIN Table1 ON Table2.Score = Table1.Score
This would definitely cover all integers between 0 and 100.
If you are manually inputing the scores, you could also use a data macro as simple as this:
go to Table Tools >> Table >> Before Change
Then use the Set Field Action, and set
Name = Table2.Grade
Value = IIf([Score]>=70,"Good",IIf([Score]<=59,"bad","so so"))
With this ^ everytime you type in a score, it will automatically populate the grade column.
Another option is create a query as follows, that will evaluate each line and assign the proper grade:
SELECT Table2.Score,
IIf([Score]>=70,"Good",IIf([Score]<=59,"bad","so so")) AS Grade
FROM Table2;
Good luck!

Join on 3 tables insanely slow on giant tables

I have a query which goes like this:
SELECT insanlyBigTable.description_short,
insanlyBigTable.id AS insanlyBigTable,
insanlyBigTable.type AS insanlyBigTableLol,
catalogpartner.id AS catalogpartner_id
FROM insanlyBigTable
INNER JOIN smallerTable ON smallerTable.id = insanlyBigTable.catalog_id
INNER JOIN smallerTable1 ON smallerTable1.catalog_id = smallerTable.id
AND smallerTable1.buyer_id = 'xxx'
WHERE smallerTable1.cont = 'Y' AND insanlyBigTable.type IN ('111','222','33')
GROUP BY smallerTable.id;
Now, when I run the query first time it copies the giant table into a temp table... I want to know how I can prevent that? I am considering a nested query, or even to reverse the join (not sure the effect would be to run faster), but that is well, not nice. Any other suggestions?
To figure out how to optimize your query, we first have to boil down exactly what it is selecting so that we can preserve that information while we change things around.
What your query does
So, it looks like we need the following
The GROUP BY clause limits the results to at most one row per catalog_id
smallerTable1.cont = 'Y', insanelyBigTable.type IN ('111','222','33'), and buyer_id = 'xxx' appear to be the filters on the query.
And we want data from insanlyBigTable and ... catalogpartner? I would guess that catalogpartner is smallerTable1, due to the id of smallerTable being linked to the catalog_id of the other tables.
I'm not sure on what the purpose of including the buyer_id filter on the ON clause was for, but unless you tell me differently, I'll assume the fact it is on the ON clause is unimportant.
The point of the query
I am unsure about the intent of the query, based on that GROUP BY statement. You will obtain just one row per catalog_id in the insanelyBigTable, but you don't appear to care which row it is. Indeed, the fact that you can run this query at all is due to a special non-standard feature in MySQL that lets you SELECT columns that do not appear in the GROUP BY statement... however, you don't get to select WHICH columns. This means you could have information from 4 different rows for each of your selected items.
My best guess, based on column names, is that you are trying to bring back a list of items that are in the same catalog as something that was purchased by a given buyer, but without any more than one item per catalog. In addition, you want something to connect back to the purchased item in that catalog, via the catalogpartner table's id.
So, something probably akin to amazon's "You may like these items because you purchased these other items" feature.
The new query
We want 1 row per insanlyBigTable.catalog_id, based on which catalog_id exists in smallerTable1, after filtering.
SELECT
ibt.description_short,
ibt.id AS insanlyBigTable,
ibt.type AS insanlyBigTableLol,
(
SELECT smallerTable1.id FROM smallerTable1 st
WHERE st.buyer_id = 'xxx'
AND st.cont = 'Y'
AND st.catalog_id = ibt.catalog_id
LIMIT 1
) AS catalogpartner_id
FROM insanlyBigTable ibt
WHERE ibt.id IN (
SELECT (
SELECT ibt.id AS ibt_id
FROM insanlyBigTable ibt
WHERE ibt.catalog_id = sti.catalog_id
LIMIT 1
) AS ibt_id
FROM (
SELECT DISTINCT(catalog_id) FROM smallerTable1 st
WHERE st.buyer_id = 'xxx'
AND st.cont = 'Y'
AND EXISTS (
SELECT * FROM insanlyBigTable ibt
WHERE ibt.type IN ('111','222','33')
AND ibt.catalog_id = st.catalog_id
)
) AS sti
)
This query should generate the same result as your original query, but it breaks things down into smaller queries to avoid the use (and abuse) of the GROUP BY clause on the insanlyBigTable.
Give it a try and let me know if you run into problems.