SQL get all columns from max aggregation [duplicate] - sql

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 5 months ago.
I have a table like This:
ID (Not PK)
time_to_prioritize
extra_info_1
extra_info_2
001
0
info_1
info_1
001
1
info_1
info_1
001
2
info_1_last
info_1_last
002
1
info_2
info_2
002
2
info_2_last
info_2_last
003
0
info_3_last
info_3_last
My objective is to get the max(time_to_prioritize) of all distinct ID's along with the extra columns, like this:
ID (Not PK)
time_to_prioritize
extra_info_1
extra_info_2
001
2
info_1_last
info_1_last
002
2
info_2_last
info_2_last
003
0
info_3_last
info_3_last
I got stuck at
SELECT TOP 1 * FROM my_table
ORDER BY time_to_prioritize DESC
I am trying to join it with itself, but with no results.
What is the next step to achieve the result ?
thanks.
P.S. the result on SQL MAX of multiple columns?
does not help me, bc that link is the max of every column, I need the max of only 1 column, along with the rest of the data

You may use ROW_NUMBER function as the following:
SELECT T.ID, T.time_to_prioritize, T.extra_info_1, T.extra_info_2
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY time_to_prioritize DESC) rn
FROM my_table
) T
WHERE T.rn=1
ORDER BY T.ID
See a demo.

Your approach with TOP 1 can be employed, though it requires some fixes.
If you want to get the first row with respect the ordering, you use TOP 1, though if you want to get the first row for each ID, then you require the clause TOP 1 WITH TIES, where the tie should happen to the ordering value. If you want to make your three "interesting rows" to be tied in the ordering, you should use the ROW_NUMBER window function inside the ORDER BY clause as follows:
SELECT TOP 1 WITH TIES *
FROM my_table
ORDER BY ROW_NUMBER() OVER(PARTITION BY ID ORDER BY time_to_prioritize DESC)
Check the demo here.

Try this:
SELECT TOP 1 MAX(time_to_prioritize) AS MAXtime_to_prioritize ,* FROM my_table
GROUP BY time_to_prioritize ,extra_info_1, extra_info_2
ORDER BY time_to_prioritize DESC

Related

SQL Select Rows with Highest Version

I am trying to query the following table:
ID
ConsentTitle
ConsentIdentifier
Version
DisplayOrder
1
FooTitle
foo1
1
1
2
FooTitle 2
foo1
2
2
3
Bar Title
bar1
1
3
4
Bar Title 2
bar1
2
4
My table has entries with unique ConsentTemplateIdentifier. I want to bring back only the rows with the highest version number for that particular unique Identifier...
ID
ConsentTitle
ConsentIdentifier
Version
DisplayOrder
2
FooTitle 2
foo1
2
2
4
Bar Title 2
bar1
2
4
My current query doesn't seem to work. It is telling me:
Column 'ConsentTemplates.ID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
Select Distinct ID,ConsentTitle, DisplayOrder, ConsentTemplateIdentifier, MAX(Version) as Version
from FooDocs
group by ConsentTemplateIdentifier
How do I select the rows distinctly which have the highest Version number for their respective ConsentTemplateIdentifiers ordered by their display order?
Any help would be really appreciated. I am using SQL Server.
You can do this with CROSS APPLY.
SELECT DISTINCT ca.*
FROM FooDocs fd
CROSS APPLY (SELECT TOP 1 *
FROM FooDocs
WHERE ConsentIdentifier = fd.ConsentIdentifier
ORDER BY Version DESC) ca
If your unique identifier has it's own table.
SELECT ca.*
FROM ConsentTable ct
CROSS APPLY (SELECT TOP 1 *
FROM FooDocs
WHERE ConsentIdentifier = ct.Identifier
ORDER BY Version DESC) ca
Using CROSS APPLY works, but effectively invokes the sub-query for every row in in your table, then expend effort to de-duplicate the results with DISTINCT, resulting in a semi-cartesian-product / triangular-join.
It is usually much more efficient just to use ROW_NUMBER() and avoid the implicit join all together...
WITH
sorted_by_version AS
(
SELECT
*,
ROW_NUMBER()
OVER (
PARTITION BY ConsentTemplateIdentifier
ORDER BY version DESC
)
AS version_ordinal
FROM
ConsentTemplates
)
SELECT
*
FROM
sorted_by_version
WHERE
version_ordinal = 1
ORDER BY
DisplayOrder
With a slight modification to Derrick's answer, I was able to get the data back the way I wanted to see it using CROSS APPLY
SELECT DISTINCT ca.*
FROM ConsentTemplates fd
CROSS APPLY (SELECT TOP 1 *
FROM ConsentTemplates
WHERE ConsentTemplateIdentifier = fd.ConsentTemplateIdentifier
ORDER BY Version DESC) ca
order by DisplayOrder

Use window functions to select the value from a column based on the sum of another column, in an aggregate query

Consider this data (View on DB Fiddle):
id
dept
value
1
A
5
1
A
5
1
B
7
1
C
5
2
A
5
2
A
5
2
B
15
2
A
2
The base query I am running is pretty simple. Just get the total value by id and the most frequent dept.
SELECT
id,
MODE() WITHIN GROUP(ORDER BY dept) AS dept_freq,
SUM(value) AS value
FROM test
GROUP BY id
;
id
dept_freq
value
1
A
22
2
A
27
But I also need to get, for each id, the dept that concentrates the greatest value (so the greatest sum of value by id and dept, not the highest individual value in the original table).
Is there any way to use window functions to achieve that and do it directly in the base query above?
The expected output for this particular example would be:
id
dept_freq
dept_value
value
1
A
A
22
2
A
B
27
I could achieve that with the query below and then joining that with the results of the base query above
SELECT * FROM(
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY value DESC) as row
FROM (
SELECT id, dept, SUM(value) AS value
FROM test
GROUP BY id, dept
) AS alias1
) AS alias2
WHERE alias2.row = 1
;
id
dept
value
row
1
A
10
1
2
B
15
1
But it is not easy to read/maintain and seems also pretty inefficient. So I thought it should be possible to achieve this using window functions directly in the base query, and that also may also help Postgres to come up with a better query plan that does less passes over the data. But none of my attempts using over partition and filter worked.
step-by-step demo:db<>fiddle
You can fetch the dept for the highest values using the first_value() partition function. Adding this before your mode() grouping should do it:
SELECT
id,
highest_value_dept,
MODE() WITHIN GROUP(ORDER BY dept) AS dept_freq,
SUM(value) as value
FROM (
SELECT
id,
dept,
value,
FIRST_VALUE(dept) OVER (PARTITION BY id ORDER BY value DESC) as highest_value_dept
FROM test
) s
GROUP BY 1,2

SQL Server : increase the value by one in a field where matching foreign key id

This is probably really easy for someone good at SQL, at that someone isn't me!
I have a database table with two fields in it. the id field is a fk id to another table, and the other field displayorder currently contains all 1's.
I want to, as below, update display order by one, starting at 1 each time the fk id changes. I am using SQL Server. This is what is should look like in the end:-
FKID displayorder
---------------------
1 1
2 1
2 2
3 1
3 2
3 3
4 1
4 2
5 1
5 2
5 3
etc
It looks like you need ROW_NUMBER():
SELECT FKID,
ROW_NUMBER() OVER(PARTITION BY FKID ORDER BY (SELECT 1)) AS displayorder
FROM table
ORDER BY FKID;
Update:
WITH cte AS (
SELECT FKID, displayorder,
ROW_NUMBER() OVER(PARTITION BY FKID ORDER BY (SELECT 1)) AS do
FROM table
)
UPDATE cte
SET displayorder = do;
Please keep in mind that to get stable sort you should ORDER BY some column like PK/timestamp.

SQL: How many rows have the largest value for a column

I am sure this is a very simple answer, though I have not turned anything up. Most because I am sure I am phrasing the question wrong.
Anyway, lets say I have this very simple table:
Table: election_candidates
id | candidate_id | election_id | votes
---------------------------------------
1 | 2 | 1 | 3
2 | 5 | 1 | 3
3 | 3 | 1 | 2
I need to know if two candidates are tied. So if there is more than one candidate with the most amount of votes for an election.
I know I can use MAX function to get the largest value for an election, but is their an easy query to get how many candidates have the MAX for a given election?
I'm using PHP and the Codeigniter framework, though just a general example of a query that could work is just fine.
Most databases support ANSI-standard window functions. One way to do this is using rank():
select ec.election_id, count(*) as NumTies
from (select ec.*, rank(votes) over (partition by election_id order by votes desc) as seqnum
from election_candidates ec
) ec
where seqnum = 1
group by ec.election_id;
Couldn't you just do something like:
select e.*
from election_candidates e
inner join (
select election_id, max(votes) as maxVotes,
from election_candidates
group by election_id
) maxVotesPerElectionId on e.election_Id = maxVotesPerElectionId.election_id
and e.votes = maxVotesPerElectionId.maxVotes
this should get you the candiates (per election) with the max votes.
Just the winner:
SELECT *
from election_candidates
ORDER BY votes DESC
LIMIT 0,1
This will group all elections together, using rank() sort each election by votes cast and list in the order of placement.
All candidates are listed and displayed on how they did in each election.
DECLARE #T AS TABLE (id INT,candidate_id INT,election_id INT,votes INT)
INSERT INTO #T VALUES
(1 ,2,1,3),(2 ,5,1,3),(3 ,3,1,2),(4 ,2,2,3),(5 ,5,3,1),(6 ,6,1,4),(7 ,2,3,3),(8 ,1,4,3),
(9 ,1,5,2),(10,4,5,3),(11,5,5,3),(12,6,5,4)
SELECT
election_id,
votes,
RANK() OVER (PARTITION BY election_id ORDER BY votes) AS RANKING,
candidate_id
FROM #T
ORDER BY election_id,
RANK() OVER (PARTITION BY election_id ORDER BY votes)

How to find first duplicate row in a table sql server

I am working on SQL Server. I have a table, that contains around 75000 records. Among them there are several duplicate records. So i wrote a query to know which record repeated how many times like,
SELECT [RETAILERNAME],COUNT([RETAILERNAME]) as Repeated FROM [Stores] GROUP BY [RETAILERNAME]
It gives me result like,
---------------------------
RETAILERNAME | Repeated
---------------------------
X | 4
---------------------------
Y | 6
---------------------------
Z | 10
---------------------------
Among 4 record(s) of X record, i need take only first record of X.
so here i want to retrieve all fields from first row of duplicate records. i.e. Take all records whose RETAILERNAME='X' we will get some no. of duplicate records, we need to get only first row from them.
Please guide me.
You could try using ROW_NUMBER.
Something like
;WITH Vals AS (
SELECT [RETAILERNAME],
ROW_NUMBER() OVER(PARTITION BY [RETAILERNAME] ORDER BY [RETAILERNAME]) RowID
FROM [Stores ]
)
SELECT *
FROm Vals
WHERE RowID = 1
SQL Fiddle DEMO
You can then also remove the duplicates if need be (BUT BE CAREFUL THIS IS PERMANENT)
;WITH Vals AS (
SELECT [RETAILERNAME],
ROW_NUMBER() OVER(PARTITION BY [RETAILERNAME] ORDER BY [RETAILERNAME]) RowID
FROM Stores
)
DELETE
FROM Vals
WHERE RowID > 1;
You Can write query as under
SELECT TOP 1 * FROM [Stores] GROUP BY [RETAILERNAME]
HAVING your condition
WITH cte
AS (SELECT [retailername],
Row_number()
OVER(
partition BY [retailername]
ORDER BY [retailername])'RowRank'
FROM [retailername])
SELECT *
FROM cte