PREMISE: The application code cannot be changed. The conditions are very specific. I am looking for something off the books, a last resort workaround if you may.
I have a table-valued function (inline) that produces between 2 and 7 records. At times it could be only 1 or up to 15 (but rarely).
The function is only used by an application in this way, without any ORDER BY.
select * from dbo.myfunction(...)
Is there any way at all, in your experience, to guarantee ensure (as far as you have ever observed using a particular technique) that the results are returned ordered by the second column? Columns are: varchar(3), datetime, varchar(50).
Don’t get me started on select *, it is INTENTIONAL so that the front end will display however many columns I make the function display in the future.
From experience, with a single index (clustered PK) to traverse the data, any current version of SQL Server and SP level should always perform a simple INDEX SCAN on <20 records without parallelism, thereby giving me ordered results in the application select.
Your thoughts? I would prefer to keep theory out of the discussion. If you can stick to practical experience and keep sermons about best practice at home, I would also appreciate it.
UPDATED
This is what it looks like now
create function dbo.myfunction(....)
returns @RES table
(
[#] int identity primary key clustered,
[Varchar3Col] varchar(3),
[DateTimeCol] datetime,
[Varchar50Col] varchar(50)
) as
BEGIN
declare @RES2 table
(
rn int,
[Varchar3Col] varchar(3),
[DateTimeCol] datetime,
[Varchar50Col] varchar(50)
)
insert @RES2
select rn=row_number() over (order by action_time),
[Varchar3Col]
[DateTimeCol]
[Varchar50Col]
from (.....)
inner join (.....) ON (.....)
declare @i int
set @i = 0
while @@rowcount > 0 begin
set @i=@i+1
insert @RES
select [Varchar3Col], [DateTimeCol], [Varchar50Col]
from @RES2
where rn=@i
end
return
END
GO
- If you look at the above, the population of @RES is done sequentially in the order desired, manually.
- @RES has a clustered PK representing the order inserted.
- the columns are small enough that 20 rows should always fit in a single 8K page
Would this work (with the straightforward SELECT from the application layer)?
For an inline TVF nothing will really work. Not only that, the inline TVF may even return more rows than you believe it should, and the rows will be trimmed after the TVF executed (basically a predicate in the TVF definition can be pulled out of the TVF and moved somewhere else in the query tree). See T-SQL functions do no imply a certain order of execution for an example of this happening.
Converting the inline TVF to a multi statement one will introduce some procedural order, since the statements cannot be executed out of order, but the TVF result may be re-ordered, sorted, split, spooled, basically mangled by the optimizer generated plan and in the end break your assumption about output order. I’m afraid if you must have a certain order of execution, cursors are your best friend.