ms-access queries - ms-access

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.

Related

How to INNER JOIN only 1 row from second table into the first table WITHOUT using alias

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.

SQL: Inner join on a Max Times Occurred Statement

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

Order by highest number of records in a field in mysql

I'd like to order contents of a table from MySQL database that looks like below.
name,h1,h2
a,f1,3
a,g3,5
a,h3,4
b,g3,4
c,h5,2
c,j12,6
I'd like to get the lengths for each element in name column i.e, length of 'a' would be 3 (since it has three rows of data associated with it) and get data of the top 2 elements (here it'd include 3 rows for a's and 2 for c's since they have the highest length in descending order). So the required output would look something like below
name,h1,h2
a,f1,3
a,g3,5
a,h3,4
c,h5,2
c,j12,6
How can this be achieved in MySQL?
Joining to a count of the top two records should give you your results.
select
t.*
from
table1 t
inner join (select
name,
count(*) as cnt
from table1
group by name
order by count(*) desc
limit 2) as c on t.name = c.name
order by c.cnt desc
Here's a fiddle

MySQL - Get row and average of rows

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

How can I make these two queries into one?

I have two tables, one for downloads and one for uploads. They are almost identical but with some other columns that differs them. I want to generate a list of stats for each date for each item in the table.
I use these two queries but have to merge the data in php after running them. I would like to instead run them in a single query, where it would return the columns from both queries in each row grouped by the date. Sometimes there isn't any download data, only upload data, and in all my previous tries it skipped the row if it couldn't find log data from both rows.
How do I merge these two queries into one, where it would display data even if it's just available in one of the tables?
SELECT DATE(upload_date_added) as upload_date, SUM(upload_size) as upload_traffic, SUM(upload_files) as upload_files
FROM packages_uploads
WHERE upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY upload_date
ORDER BY upload_date DESC
SELECT DATE(download_date_added) as download_date, SUM(download_size) as download_traffic, SUM(download_files) as download_files
FROM packages_downloads
WHERE download_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY download_date
ORDER BY download_date DESC
I want to get result rows like this:
date, upload_traffic, upload_files, download_traffic, download_files
All help appreciated!
Your two queries can be executed and then combined with the UNION cluase along with an extra field to identify Uploads and Downloads on separate lines:
SELECT
'Uploads' TransmissionType,
DATE(upload_date_added) as TransmissionDate,
SUM(upload_size) as TransmissionTraffic,
SUM(upload_files) as TransmittedFileCount
FROM
packages_uploads
WHERE upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY upload_date
ORDER BY upload_date DESC
UNION
SELECT
'Downloads',
DATE(download_date_added),
SUM(download_size),
SUM(download_files)
FROM packages_downloads
WHERE download_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY download_date
ORDER BY download_date DESC;
Give it a Try !!!
What you're asking can only work for rows that have the same add date for upload and download. In this case I think this SQL should work:
SELECT
DATE(u.upload_date_added) as date,
SUM(u.upload_size) as upload_traffic,
SUM(u.upload_files) as upload_files,
SUM(d.download_size) as download_traffic,
SUM(d.download_files) as download_files
FROM
packages_uploads u, packages_downloads d
WHERE u.upload_date_added = d.download_date_added
AND u.upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY date
ORDER BY date DESC
Without knowing the schema is hard to give the exact answer so please see the following as a concept not a direct answer.
You could try left join, im not sure if the table package exists but the following may be food for thought
SELECT
p.id,
up.date as upload_date
dwn.date as download_date
FROM
package p
LEFT JOIN package_uploads up ON
( up.package_id = p.id WHERE up.upload_date = 'etc' )
LEFT JOIN package_downloads dwn ON
( dwn.package_id = p.id WHERE up.upload_date = 'etc' )
The above will select all the packages and attempt to join and where the value does not join it will return null.
There is number of ways that you can do this. You can join using primary key and foreign key. In case if you do not have relationship between tables,
You can use,
LEFT JOIN / LEFT OUTER JOIN
Returns all records from the left table and the matched
records from the right table. The result is NULL from the
right side when there is no match.
RIGHT JOIN / RIGHT OUTER JOIN
Returns all records from the right table and the matched
records from the left table. The result is NULL from the left
side when there is no match.
FULL OUTER JOIN
Return all records when there is a match in either left or right table records.
UNION
Is used to combine the result-set of two or more SELECT statements.
Each SELECT statement within UNION must have the same number of,
columns The columns must also have similar data types The columns in,
each SELECT statement must also be in the same order.
INNER JOIN
Select records that have matching values in both tables. -this is good for your situation.
INTERSECT
Does not support MySQL.
NATURAL JOIN
All the column names should be matched.
Since you dont need to update these you can create a view from joining tables then you can use less query in your PHP. But views cannot update. And you did not mentioned about relationship between tables. Because of that I have to go with the UNION.
Like this,
CREATE VIEW checkStatus
AS
SELECT
DATE(upload_date_added) as upload_date,
SUM(upload_size) as upload_traffic,
SUM(upload_files) as upload_files
FROM packages_uploads
WHERE upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY upload_date
ORDER BY upload_date DESC
UNION
SELECT
DATE(download_date_added) as download_date,
SUM(download_size) as download_traffic,
SUM(download_files) as download_files
FROM packages_downloads
WHERE download_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY download_date
ORDER BY download_date DESC
Then anywhere you want to select you just need one line:
SELECT * FROM checkStatus
learn more.