Another option is to use GROUP BY
with concatenation. The idea is that you take the aggregate of the column as usual but append other columns to go along for the ride. As long as you're careful with data type conversions you can take the minimum of a string that concatenates together all relevant columns and piece them out later. There's a discussion of this technique here.
I'm going to make some guesses about data types for your table and I'll insert some data into it:
CREATE TABLE #uh_hi (
unid BIGINT NOT NULL,
cdts DATETIME NOT NULL,
unit_stats VARCHAR(30) NOT NULL
);
INSERT INTO #uh_hi WITH (TABLOCK)
SELECT
t.RN / 3
, DATEADD(HOUR, t.RN, '20170101')
, REPLICATE(CHAR(64 + t.RN % 26), 20)
FROM
(
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) t
OPTION (MAXDOP 1);
Here's one way to return the result set that you're looking for:
SELECT unid
, CAST(SUBSTRING(magic_column, 1, 23) AS DATETIME) cdts
, SUBSTRING(magic_column, 24, 8000) unit_stats
FROM
(
SELECT unid
, MIN(
CONVERT(CHAR(23), cdts, 126)
+ unit_stats
) magic_column
FROM #uh_hi
GROUP BY unid
) t;
Note how magic_column
has the aggregate column first and the other column is appended to it. Outside of the derived table I use SUBSTRING
to split the columns back out. Here's a sample of the results:
╔═══════╦═════════════════════════╦══════════════════════╗
║ unid ║ cdts ║ unit_stats ║
╠═══════╬═════════════════════════╬══════════════════════╣
║ 0 ║ 2017-01-01 01:00:00.000 ║ AAAAAAAAAAAAAAAAAAAA ║
║ 28387 ║ 2026-09-19 09:00:00.000 ║ KKKKKKKKKKKKKKKKKKKK ║
║ 5834 ║ 2018-12-31 06:00:00.000 ║ DDDDDDDDDDDDDDDDDDDD ║
║ 11407 ║ 2020-11-26 21:00:00.000 ║ EEEEEEEEEEEEEEEEEEEE ║
║ 22814 ║ 2024-10-22 18:00:00.000 ║ JJJJJJJJJJJJJJJJJJJJ ║
╚═══════╩═════════════════════════╩══════════════════════╝
This looks complicated, and it is. One advantage to this approach is that SQL Server will be able to create more accurate cardinality estimates on the result set since it knows that the number of rows will be equal to the number of distinct unid
values in the table. For this example, the cardinality estimate is perfect:
If this query is part of a more complex query then the optimizer may be able to generate a better performing plan. The cardinality estimate for queries that filter against window functions, such as the ROW_NUMBER()
solution, are almost always inaccurate:
The optimizer has poor modeling support for such queries. Again, this only might matter if your query is part of some larger, more complex query. If all that you need is the result set that you asked for in the question then you should use the simplest solution or the solution that you're most comfortable with.
distinct
is not a function; it applies to the entire select list.GROUP BY
makes sure that every row in the result set has a distinctunid
.