Extra Fields with SQL MIN() & GROUP BY
If you wanted to get the "cheapest" employee in each department you would have two choices off the top of my head:
SELECT
E.* -- Don't actually use *, list out all of your columns
FROM
Employees E
INNER JOIN
(
SELECT
department,
MIN(salary) AS min_salary
FROM
Employees
GROUP BY
department
) AS SQ ON
SQ.department = E.department AND
SQ.min_salary = E.salary
Or you can use:
SELECT
E.*
FROM
Employees E1
LEFT OUTER JOIN Employees E2 ON
E2.department = E1.department AND
E2.salary < E1.salary
WHERE
E2.employee_id IS NULL -- You can use any NOT NULL column here
The second statement works by effectively saying, show me all employees where you can't find another employee in the same department with a lower salary.
In both cases, if two or more employees have equal salaries that are the minimum you will get them both (all).
SQL MIN() with GROUP BY select additional columns
One method uses a correlated subquery:
select t.*
from t
where t.price = (select min(t2.price) from t t2 where t2.productid = t.productid);
In most databases, this has very good performance with an index on (productid, price)
.
Select additional fields when using GROUP BY
If you want to select rows from Driver
along with the max()
and avg()
values for speed
, then use window functions:
SELECT d.*, CAST(d.date as DATE) as date,
MAX(d.speed) OVER (PARTITION BY CAST(d.date as DATE)) AS maxSpeed,
AVG(d.speed) OVER (PARTITION BY CAST(d.date as date)) AS avgSpeed
FROM Driver as d
WHERE d.date between '2014-01-01 09:00:00.491' and '2014-03-11 17:00:00.491'
ORDER BY date DESC;
EDIT:
If you want one row per driver, per day, then use a simple group by
:
SELECT d.userId, CAST(d.date as DATE) as date,
MAX(d.speed) as maxSpeed, AVG(d.speed) as avgSpeed
FROM Driver as d
WHERE d.date between '2014-01-01 09:00:00.491' and '2014-03-11 17:00:00.491'
GROUP BY d.userId, CAST(d.date as DATE)
ORDER BY date DESC;
If you want to add additional columns, you need to add them both to the select
and the group by
.
Group by minimum value in one field while selecting distinct rows
How about something like:
SELECT mt.*
FROM MyTable mt INNER JOIN
(
SELECT id, MIN(record_date) AS MinDate
FROM MyTable
GROUP BY id
) t ON mt.id = t.id AND mt.record_date = t.MinDate
This gets the minimum date per ID, and then gets the values based on those values. The only time you would have duplicates is if there are duplicate minimum record_dates for the same ID.
SQL: How to find min value per group in sql?
As mentioned you should use concatenation to create a single date and then select the lowest value.
select domain, MIN(CAST(CONCAT(`year`, '-'`,month`,'-',`day`) AS DATE)) from snapshots group by domain
Haven't tested this but this should give you an idea.
SQL GROUP BY and MIN to find people with minimum salary in each department
Instead fo a IN clause you can also use an inner join
SELECT first_name, last_name, salary, department_id
FROM employees
INNER JOIN ( SELECT department_id, MIN(salary) min_sal
FROM employees
GROUP BY department_id
) t on t.department_id =employees.department_id
and employees.salary = t.min_sal;
this should be better for performance
MySQL GROUP BY with MIN - incorrect column data
In general, unless you're trying to perform some sort of MySQL "magic" you should always group by every non-aggregate, non-constant column in your SELECT
list.
In your case, the best approach is to get a list of (name, # bedrooms, minimum rent), and then find all the rows that match these values - in other words, all rows whose (name, # bedrooms, rent) match the list with the minimum rent:
SELECT ru.id, run.name, ru.rent, ru.bedrooms
FROM rental_units ru
JOIN rental_unit_names run ON run.id = ru.name_id
WHERE run.merge = 1
AND (run.name, ru.bedrooms, ru.rent) IN (
SELECT inrun.name, inru.bedrooms, MIN(inru.rent)
FROM rental_units inru
JOIN rental_unit_names inrun ON inrun.id = inru.name_id
WHERE inrun.merge = 1
GROUP BY inrun.name, inru.bedrooms)
This query will give all lowest-rent units by name/bedrooms. The sample data has ties for lowest in a couple of places. To include only one of the "tied" rows (the one with the lowest rental_units.id
, try this instead - the only change is the MIN(ru.id)
on the first line and the addition of an overall GROUP BY
on the last line:
SELECT MIN(ru.id) AS ru_id, run.name, ru.rent, ru.bedrooms
FROM rental_units ru
JOIN rental_unit_names run ON run.id = ru.name_id
WHERE run.merge = 1
AND (run.name, ru.bedrooms, ru.rent) IN (
SELECT inrun.name, inru.bedrooms, MIN(inru.rent)
FROM rental_units inru
JOIN rental_unit_names inrun ON inrun.id = inru.name_id
WHERE inrun.merge = 1
GROUP BY inrun.name, inru.bedrooms)
GROUP BY run.name, ru.rent, ru.bedrooms
Related Topics
How to Manually Execute SQL Commands in Ruby on Rails Using Nuodb
SQL Statement Indentation Good Practice
Is There Any Difference Between "!=" and "<>" in Oracle SQL
How to Sort the Result from String_Agg()
Alter Data Type of a Column to Serial
How to Change the Date Format from Mm/Dd/Yyyy to Yyyy-Mm-Dd in Pl/Sql
One-To-Many Query Selecting All Parents and Single Top Child for Each Parent
Sequentially Number Rows by Keyed Group in SQL
When to Use an Enum or a Small Table in a Relational Database
Rename a Constraint in SQL Server
Convert 24 Hour Time to 12 Hour Plus Am/Pm Indication Oracle SQL
How to Add Results of Two Select Commands in Same Query
Postgresql Copy/Transfer Data from One Database to Another
Oracle: Getting Maximum Value of a Group
Postgres "Missing From-Clause Entry" Error on Query with With Clause
SQL Server 2005: Determine Datatype of Variable
Why Does the SQLserver Optimizer Get So Confused with Parameters