如何在 table 值函数中使用动态 'order by'
How to use dynamic 'order by' in a table-valued function
我使用 table 值函数作为参数化视图。几乎一切正常,除了 'order by' part.I 将原始函数更改为这个短函数。
函数:
ALTER FUNCTION [dbo].[fn_Get_NormalOrders]
(
@minimalLevel int,
@recordStart int,
@recordsEnd int,
@orderBy varchar(30)
)
RETURNS TABLE
AS
RETURN
(
select *
from
(
select
ROW_NUMBER() over (order by @orderBy) as row
,d.nameModel
,t.idToner
from toner t
inner join vwWebDevice d on d.idDevice = t.idDevice
and d.statusDevice not like '%stale%'
and isnull(d.deleted,0) = 0
inner join groups g on g.idGroup = d.idGroup
where
t.currentLevel <= @minimalLevel
) as x
where x.row between @recordStart and @recordsEnd
)
我通过将此查询设为 varchar 并执行它找到了解决方案,但我 return 如何获得结果?当我现在使用它时,结果总是一样的。
我很确定你不能轻易做到这一点。一种方法是 case
:
. . .
order by (case when @OrderBy = 'col1' then col1 end),
(case when @OrderBy = 'col2' then col2 end),
. . .
(请注意,每种可能性都有一个单独的 case
。这可以防止用于排序的值发生类型冲突。)
遗憾的是,参数不能替换列名或表达式。那将是最简单的解决方案。
另一种不起作用的可能性是动态 SQL(您提到的 "varchar" 方法)。不幸的是,SQL 服务器不允许动态 SQL。
有一个非常复杂的方法,其中函数使用 xp_cmdshell
来绕过这些限制。这可能不值得为此付出努力。
exec
的限制是 phrased by specifying that EXECUTE
can only be used for extended stored procedures:
EXECUTE statements calling extended stored procedures.
您必须覆盖所有硬编码的列名:
ALTER FUNCTION [dbo].[fn_Get_NormalOrders]
(
@minimalLevel int,
@recordStart int,
@recordsEnd int,
@orderBy varchar(30)
)
RETURNS TABLE
AS
RETURN
(
select *
from
(
select case @orderBy
when 'Column1' then ROW_NUMBER() over (order by Column1)
when 'Column2' then ROW_NUMBER() over (order by Column2)
when 'Column3' then ROW_NUMBER() over (order by Column3)
when 'Column4' then ROW_NUMBER() over (order by Column4)
end as row
,d.nameModel
,t.idToner
from toner t
inner join vwWebDevice d on d.idDevice = t.idDevice
and d.statusDevice not like '%stale%'
and isnull(d.deleted,0) = 0
inner join groups g on g.idGroup = d.idGroup
where
t.currentLevel <= @minimalLevel
) as x
where x.row between @recordStart and @recordsEnd
)
我使用 table 值函数作为参数化视图。几乎一切正常,除了 'order by' part.I 将原始函数更改为这个短函数。
函数:
ALTER FUNCTION [dbo].[fn_Get_NormalOrders]
(
@minimalLevel int,
@recordStart int,
@recordsEnd int,
@orderBy varchar(30)
)
RETURNS TABLE
AS
RETURN
(
select *
from
(
select
ROW_NUMBER() over (order by @orderBy) as row
,d.nameModel
,t.idToner
from toner t
inner join vwWebDevice d on d.idDevice = t.idDevice
and d.statusDevice not like '%stale%'
and isnull(d.deleted,0) = 0
inner join groups g on g.idGroup = d.idGroup
where
t.currentLevel <= @minimalLevel
) as x
where x.row between @recordStart and @recordsEnd
)
我通过将此查询设为 varchar 并执行它找到了解决方案,但我 return 如何获得结果?当我现在使用它时,结果总是一样的。
我很确定你不能轻易做到这一点。一种方法是 case
:
. . .
order by (case when @OrderBy = 'col1' then col1 end),
(case when @OrderBy = 'col2' then col2 end),
. . .
(请注意,每种可能性都有一个单独的 case
。这可以防止用于排序的值发生类型冲突。)
遗憾的是,参数不能替换列名或表达式。那将是最简单的解决方案。
另一种不起作用的可能性是动态 SQL(您提到的 "varchar" 方法)。不幸的是,SQL 服务器不允许动态 SQL。
有一个非常复杂的方法,其中函数使用 xp_cmdshell
来绕过这些限制。这可能不值得为此付出努力。
exec
的限制是 phrased by specifying that EXECUTE
can only be used for extended stored procedures:
EXECUTE statements calling extended stored procedures.
您必须覆盖所有硬编码的列名:
ALTER FUNCTION [dbo].[fn_Get_NormalOrders]
(
@minimalLevel int,
@recordStart int,
@recordsEnd int,
@orderBy varchar(30)
)
RETURNS TABLE
AS
RETURN
(
select *
from
(
select case @orderBy
when 'Column1' then ROW_NUMBER() over (order by Column1)
when 'Column2' then ROW_NUMBER() over (order by Column2)
when 'Column3' then ROW_NUMBER() over (order by Column3)
when 'Column4' then ROW_NUMBER() over (order by Column4)
end as row
,d.nameModel
,t.idToner
from toner t
inner join vwWebDevice d on d.idDevice = t.idDevice
and d.statusDevice not like '%stale%'
and isnull(d.deleted,0) = 0
inner join groups g on g.idGroup = d.idGroup
where
t.currentLevel <= @minimalLevel
) as x
where x.row between @recordStart and @recordsEnd
)