Is it possible to get a function result with columns which are not in the group by (SQL)? - sql

I am trying to get the last registration date of a course, but I want to know the id of thar record. As MAX is a function, I must use group by id, which I do not want, because the result is very different (From only one record to each record per id).
Which is the way to manage a query like this?:
SELECT id, MAX(registration_date) AS registration_date
FROM courses;
Because it gives an error and I must do this to avoid it:
SELECT id, MAX(registration_date) AS registration_date
FROM courses
GROUP BY id;
And I do not want the result of the last one.

You could use the rank() window function for that:
SELECT id
FROM (SELECT id, RANK() OVER (ORDER BY registration_date DESC) AS rk
FROM courses)
WHERE rk = 1

One method is to use a sub query like this:
select *
from [dbo].[Courses]
where registration_date =
(select max(registration_date)
from [dbo].[Courses])
but with only a date to match this may return more than one record.
If possible, include more fields in the where clause to narrow it down.

Related

Getting MAX of a column and adding one more

I'm trying to make an SQL query that returns the greatest number from a column and its respective id.
For more information I have two columns ID and NUMBER. Both of them have 2 entries and I want to get the highest number with the ID next to it. This is what I tried but didn't success.
SELECT ID, MAX(NUMBER) AS MAXNUMB
FROM TABLE1
GROUP BY ID, MAXNUMB;
The problem I'm experiencing is that it just shows ALL the entries and if I add a "where" expression it just shows the same (all entries [ids+numbers]).
Pd.: Yes, I got what I wanted but only with one column (number) if I add another column (ID) to select it "brokes".
Try:
SELECT
ID,
A_NUMBER
FROM TABLE1
WHERE A_NUMBER = (
SELECT MAX(A_NUMBER)
FROM TABLE1);
Presuming you want the IDs* of the row with the highest number (and not, instead, the highest number for each ID -- if IDs were not unique in your table, for example).
* there may be more than one ID returned if there are two or more IDs with equal maximum numbers
you can try this
Select ID,maxNumber
From
(
SELECT
ID,
(Select Max(NUMBER) from Tmp where Id = t.Id) maxNumber
FROM
Tmp t
)T1
Group By ID,maxNumber
The query you posted has an illegal column name (number) and is group by the alias for the max value, which is illegal and also doesn't make sense; and you can't include the unaliased max() within the group-by either. So it's likely you're actually doing something like:
select id, max(numb) as maxnumb
from table1
group by id;
which will give one row per ID, with the maximum numb (which is the new name I've made up for your numeric column) for each ID. Or as you said you get "ALL the entries" you might have group by id, numb, which would show all rows from the table (unless there are duplicate combinations).
To get the maximum numb and the corresponding id you could group by id only, order by descending maxnumb, and then return the first row only:
select id, max(numb) as maxnumb
from table1
group by id
order by maxnumb desc
fetch first 1 row only
If there are two ID with the same maxnumb then you would only get one of them - and which one is indeterminate unless you modify the order by - but in that case you might prefer to use first 1 row with ties to see them all.
You could achieve the same thing with a subquery and analytic function to generating a ranking, and have the outer query return the highest-ranking row(s):
select id, numb as maxnumb
from (
select id, numb, dense_rank() over (order by numb desc) as rnk
from table1
)
where rnk = 1
You could also use keep to get the same result as first 1 row only:
select max(id) keep (dense_rank last order by numb) as id, max(numb) as maxnumb
from table1
fiddle

SQL Max or empty value grouped by conditions

I have a table like this
and i want my output to look like this
I need to look at the ID and then take max created date and max completed date for that ID. There is also some cases where completed date is still empty so in that case i just need to look at the max created date. Im not sure how to tackle this, doing a group by doesnt account for my multiple scenarios
Use ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY QUOTE_NUMBER
ORDER BY WORKBOOK_CREATED_DATE DESC) rn
FROM yourTable
)
SELECT *
FROM yourTable
WHERE rn = 1;

Group By: What if I don't want to perform an aggregate function on a column?

I have a table, Students, with the following columns:
________________________________________________
| id | name | class | date_registrered |
------------------------------------------------
I want to select one row for every unique class, and only the row with the largest value in date_registrered,
i.e. I want to select the latest registrered Student for every class, including all the data for that one.
I tried:
SELECT id, name, class, MAX(date_registrered)
FROM Students
GROUP BY class;
I get the following error:
Column 'Students.id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This question on SO adresses a simplified version of this issue. However, the example is for 2 columns only.
I only want to group by class, and I only want to perform an aggregate function on date_registrered. I also want to display all the other columns for the row with the max date_registrered for every class.
Do you know how to fix it?
use ROW_NUMBER()
SELECT *
FROM ( SELECT id, name, class, date_registrered
ROW_NUMBER() OVER (partition by class ORDER BY date_registrered DESC) rn
FROM Students
) T
WHERE T.rn = 1
The error message explains your issue very well, you can't perform an aggregation on one column, and not use the rest in the GROUP BY. In this case, you'll want to use something like ROW_NUMBER:
WITH CTE AS
(
SELECT id,
name,
class,
date_registered,
RN = ROW_NUMBER() OVER(PARTITION BY class ORDER BY date_registrered DESC)
FROM students
)
SELECT id,
name,
class,
date_registered
FROM CTE
WHERE RN = 1;

Max of a Date field into another field in Postgresql

I have a postgresql table wherein I have few fields such as id and date. I need to find the max date for that id and show the same into a new field for all the ids. SQLFiddle site was not responding so I have an example in the excel. Here is the screenshot of the data and the output for the table.
You could use the windowing variant of max:
SELECT id, date, MAX(date) OVER (PARTITION BY id)
FROM mytable
Something like this might work:
WITH maxdts AS (
SELECT id, max(dt) maxdt FROM table GROUP BY id
)
SELECT id, date, maxdt FROM table t, maxdts m WHERE t.id = m.id;
Keep in mind without more information that this could be a horribly inefficient query, but it will get you what you need.

Select row with the highest order value

For example, I have the table with the next columns: id, fk_id, date, order. How can I select something like this:
select
id
from cards
where fk_id = pId
and date = pDate;
but I need to get only the row with the highest order value. How can I do that? Thank you.
UPD1: First of all - thank you for your answers. Column names are completely different in the real table, it's just dummy names for question. Is there any way to do so that select by joining tha table with itself?
You would use the aggregating function KEEP DENSE_RANK FIRST for that:
select
MIN(id) KEEP (DENSE_RANK FIRST ORDER BY "order" desc)
from cards
where fk_id = pId
and "date" = pDate;
First of all, do not use the words "order" and "date" for column names. Both are reserved words in SQL (ORDER BY ... clause, DATE is a data type). So in my example I am going to use "myorder" and "mydate" instead...
I assume your example as purely hypothetical because with the selected column names it would most likely not work on any SQL database, anyway.
In Oracle database you could try this:
select ID from
( select ID, row_number() over (partition by ID order by MYORDER) as RN
from CARDS where FK_ID = PID and MYDATE = PDATE)
where RN = 1
However, your select only has one column, ID. So if you simply do
select distinct ID from CARDS
you will get exactly the same result...
Something like this:
SELECT id
FROM cards
WHERE orderValue = (SELCT MAX(orderValue)
FROM cards
WHERE fk_id = pId
AND date = pDate)
AND fk_id = pId
AND date = pDate;
This is fairly efficient.
You can try something like this:
select
id
from cards
where fk_id = pId
and date = pDate
order by desc
limit 1;