First of all I'll just warn everyone that I'm something of a rookie with MySQL. Additionally I haven't tested the example queries below so they might not be perfect.
Anyway, I have a table of items, each one with a name, a category and a score. Every 12 hours the top item is taken, used and then removed.
So far I've simply been grabbing the top item with
SELECT * FROM items_table ORDER BY score DESC LIMIT 1
The only issue with this is that some categories are biased and have generally higher scores. I'd like to solve this by sorting by the score divided by the average score instead of simply sorting by the score. Something like
ORDER BY score/(GREATEST(5,averageScore))
I'm now trying to work out the best way to find averageScore. I have another table for categories so obviously I could add an averageScore column to that and run a cronjob to keep them updated and retrieve them with something like
SELECT * FROM items_table, categories_table WHERE items_table.category = categories_table.category ORDER BY items_table.score/(GREATEST(5,categories_table.averageScore)) DESC LIMIT 1
but this feels messy. I know I can find all the averages using something like
SELECT AVG(score) FROM items_table GROUP BY category
What I'm wondering is if there's some way to retrieve the averages right in the one query.
Thanks,
YM
You can join the query that calculates the averages:
SELECT i.*
FROM items_table i JOIN (
SELECT category, AVG(score) AS averageScore
FROM items_table
GROUP BY category
) t USING (category)
ORDER BY i.score/GREATEST(5, t.averageScore) DESC
LIMIT 1
Related
I have two tables table_entries and table_images.
table_images holds a series of images for any single item in table_entries
both tables are organized by a vid which is essentially an item id.
Not all items in table_entries will have an image, while others may have multiple images
What I am trying to construct is a query to only select items from table_entries that have an image, specifically 10 entries that have an image, which i've built as follows:
SELECT * FROM table_entries
INNER JOIN table_images ON (table_entries.vid = table_images.vid)
WHERE (model LIKE '%apple%' OR ext LIKE '%apple%')
ORDER BY lastupdated DESC LIMIT 0,10
EDIT: lastupdated, model and ext all belong to table_entries, in fact all sorting, selecting, etc.. is done based on table_entries
The problem with the above query is that it is successfully only picking items with images, but if a single item has 10 images, then it will return the 10 rows as item #1 with each of its images as individual rows. The intention is to have 10 distinct items, and limit the join to only 1 image for each item from table_entries
So I want to somehow limit the join to 1 row for the entire join.
I've searched for the answer here on SO and found so many good answers to this question (MySQL INNER JOIN select only one row from second table, MySQL JOIN with LIMIT 1 on joined table) , however they all use aliases for selecting the tables.
I could use alias and fix my query, but there is a TON of PHP code that I would have to change to deal with the aliased table names.
Is it possible to fix my query to only select 1 row from the joined table without the use of aliases?
You can do:
select *
from (
select *,
row_number() over(partition by i.vid order by i.updated) as rn
from table_entries e
join table_images i on i.vid = e.vid
where e.model like '%apple%' or e.ext like '%apple'
) x
where rn = 1 -- this is the key filter
order by lastupdated desc
limit 0, 10
Please consider this query could be awfully slow due to the use of LIKE '%text%' in the search condition, specially if the table table_entries has millions of rows.
I have a main table named tblorder.
It contains CUID(Customer ID), CuName(Customer Name) and OrDate(Order Date) that I care about.
It is currently ordered by date in ascending order(ex. 2001 before 2002).
Objective:
Trying to retrieve most recent 1 Million DISTINCT Customer's CUID and CuNameS, and Insert them Into a Tempdb(#Recent1M) for Later Joining Uses.
So I:
Would Need Order By desc to flip the date to retrieve most recent 1 Million Customers
Only want first 1 Million DISTINCT Customer Information(CUID, CuName)
I know following code is not correct, but it is the main idea. I just can't figure out the correct syntax. So far I have the While Loop with Select Into as the most plausible solution.
SQL Platform: SSMS
Declare #DC integer
Set #DC = Count(distinct(CUID)) from #Recent1M))
While (#DC <1000000)
Begin
Select CuID,CuName into #Recent1MCus from tblorder
End
Thank you very much, I appreciate any help!
TOP 1000000 is the way to go, but you're going to need an ORDER BY clause or you will get arbitrary results. In your case, you mentioned that you wanted the most recent ones, so:
ORDER BY OrderDate DESC
Also, you might consider using GROUP BY rather than DISTINCT. I think it looks cleaner and keeps the select list a select list so you have the option to include whatever else you might want (as I took the liberty of doing). Notice that, because of the grouping, the ORDER BY now uses MAX(ordate) since customers can presumably have multiple ordate's and we are interested in the most recent. So:
select top 1000000 cuid, cuname, sum(order_value) as ca_ching, count(distinct(order_id)) as order_count
into #Recent1MCus
from tblorder
group by cuid, cuname
order by max(ordate) desc
I hope this helps.
Wouldn't you just do this?
select distinct top 1000000 cuid, cuname
into #Recent1MCus
from tblorder;
If the names might not be distinct, you can do:
select top 1000000 cuid, cuname
into #Recent1MCus
from (select o.*, row_number() over (partition by cuid order by ordate desc) as seqnum
from tblorder o
) o
where seqnum = 1;
Use DISTINCT and ORDER BY <colname> DESC to get latest unique records.
Try this SQL query:
SELECT DISTINCT top 1000000
cuid,
cuname
INTO #Recent1MCus
FROM tblorder
ORDER BY OrDate DESC;
I have two tables - results and contestants. Result table cointains
result_id (PK)
resul_contestant (who scored this)
value (how much did he scored)
result_discipline(where he scored this)
contestants table cointains
contestant_id (PK)
contestant_name
contestant_category
What I want to do is to select results for all contestants, but I only want to show one result per contestant - the highest (lowest) one.
So far I managed to do this:
SELECT * FROM contenstants
JOIN results ON result_contestant = contenstant_id
WHERE result_discipline = 1 AND contestant_category = 1
ORDER BY value DESC
GROUP BY contenstant_id;
However, this gives me syntax error. If I delete the GROUP BY line, I got results ordered from highest, but if any of the contestants scored in this discipline more than once, I got all of his scores.
If I delete the ORDER BY line, I got only one result per contestant, but it returns the first record in db, not the highest one.
How to fix this command to be valid? Also, there are some less_is_better disciplines, where I want the lowest score, but as far as I could use the ORDER BY on final query, it should be achieved by replacing DESC with ASC.
Thanks.
Don't use group by. Using select * with group by just doesn't make sense. Instead, use a filter to get the row you want:
SELECT *
FROM contenstants c JOIN
results r
ON r.result_contestant = c.contestant_id
WHERE r.result_discipline = 1 AND c.contestant_category = 1 AND
r.value = (select min(r2.value)
from results r2
where r2.result_contestant = r.result_contestant and
r2.result_discipline = r.result_discipline
)
ORDER BY value DESC;
Note: I'm not sure if you want min() or max() in the subquery.
Posed a question: What school was attended most frequently?
I came up with the following statement...
select unitid, count(unitid) as 'Times_Occurred'
from people
group by unitid
order by count(*) desc
limit 50;
I made it limit 50 because multiple unitid's had 3. I have two tables, a people table, and a post table. They are connected by unitid. I am trying to figure out how to do an inner join to get not only the top 50 highest unitid's, and how often they occur, but also the colleges that go along with those Id's.
Any and all help is much appreciated!!
Perhaps your counts are being inflated and you don't know how to handle that... this is one approach using an inline view. The reason this works is because the counts are calculated and retained prior to the join. Thus the 1-M cardinality doesn't negatively effect the counts.
Select *
from (
select unitid, count(unitid) as 'Times_Occurred'
from people
group by unitid
order by count(*) desc
limit 50) A
INNER JOIN Post B
on A.UnitID = B.UnitID
I never really did ms access queries, but today I need one. I have 2 tables, models and orders. From first table one 2 fields are of interest here: number and color, from second only number which can only be equal to values of number from table "models" . What I need is to select most frequent color. In mysql that would be something like
SELECT models.color, orders.number FROM models
INNER JOIN orders ON (orders.number =models.number)
group by color
order by count(color) desc limit 1
But in ms-access that doesn't seem to work
How do you write query to do same thing in ms-access?
try this:
SELECT TOP 1 models.color, COUNT(orders.number) FROM models
INNER JOIN orders ON (orders.number=models.number)
GROUP BY models.color
ORDER BY 2 desc
All you need is to get rid of limit and use Top 1 instead:
SELECT Top 1 models.color FROM models
INNER JOIN orders ON (orders.number =models.number)
group by color
order by count(color) Desc
However, there is a caveat for Top n, in MS Access, Top n will return matches, so if several items have the same count, all will be returned. If this does not suit, you can work around this by ordering by a unique id as well:
order by count(color) desc, OrderID
Note also that number is a reserved word.