SQL 按标量值函数的参数值排序,不将其包含在 select 中

SQL Order by the parameter value from scalar-valued function without including it into select

我有结构查询

SELECT DISTINCT
--parameters
[ProjectNum] = dbo.ProjNumFunction(P.A, P.B, P.C, P.D, P.E)
--other parameters
FROM dbo.Project P
WHERE --conditions
ORDER BY --parameter

ProjNumber 函数只是从项目 table 中获取 A、B、C、D 和 E 的值,并将它们连接成一个字符串,类似于 'A B C D E'.

我需要在函数内按这些参数之一进行排序,而不是将它们放入我的 select 列表中。 可能吗?

following thread (and the second) 是我得到的最接近的,但这不是我需要的。

编辑

我试过使用下面的语句,结果是

ORDER BY SUBSTRING(ProjectNumber, 9, 13) desc --Invalid column name error

[ProjectNumber] = CONCAT(P.A, P.B, P.C, P.D, P.E) 
-- it concatinated successfully, but still does not allow me to order by any of those 
-- parameters without including onto select list

不,你不能(嗯,没有复杂的字符串操作)。但是,您可以执行以下操作:

SELECT ProjectNum
FROM dbo.Project P OUTER APPLY
     (VALUES (dbo.ProjNumFunction(P.A, P.B, P.C, P.D, P.E)) x(ProjectNum)
WHERE --conditions
GROUP BY ProjectNum
ORDER BY MAX(A);

也就是说,如果将SELECT DISTINCT替换为GROUP BY,则可以在ORDER BY.

中使用聚合函数

编辑 3:

我相信这会奏效。这个想法是首先创建一个子查询来定义您的排序字段和您要检索的数据。第二步是根据排序字段为每条记录分配排序顺序。这是您的主要类别。下一个字段将为组中的每条记录分配一个 1,如果您的要求更复杂,排序方式可以提供额外的选项,例如将哪条记录保留在组中。

外部查询不需要 distinct 或 group by,因为 window 函数会处理这些。我无法访问测试环境,因此语法和逻辑可能会有些偏差,但我认为这对您有用。

Select Data, 
   From
      (
       Select Data, 
              Row_Number() Over (Order By SortField) TopLevelSort,
              Row_Number() Over (Partition By Data Order By SortField) Keepers       
         From
             (Select SUBSTRING(dbo.ProjNumFunction(P.A, P.B, P.C, P.D, P.E), 9, 13) SortField,
                   dbo.ProjNumFunction(P.A, P.B, P.C, P.D, P.E), 9, 13) Data
                  From dbo.Project P
                  Where --conditions
              ) A
       ) B
    Where Keepers = 1
    Order By TopLevelSort

这是对分隔字符串进行排序的一种小方法。也许可以根据您的功能对其进行修改。

目前我有 9 个对象的限制。这可以扩展或收缩以满足您的需求

Edit - Removed the need for the UGLY Union Alls

Declare @String     varchar(200) = 'P.C, P.A, P.E, P.D, P.B, P.A'
Declare @Delimeter  varchar(25)  = ','
Declare @NewString  varchar(200) = ''
Declare @NewDelimer varchar(25)  = ' '

Declare @XML xml
;with cteBase as (
    Select Pos1 = xDim.value('/x[1]','varchar(250)')
          ,Pos2 = xDim.value('/x[2]','varchar(250)')
          ,Pos3 = xDim.value('/x[3]','varchar(250)')
          ,Pos4 = xDim.value('/x[4]','varchar(250)')
          ,Pos5 = xDim.value('/x[5]','varchar(250)')
          ,Pos6 = xDim.value('/x[6]','varchar(250)')
          ,Pos7 = xDim.value('/x[7]','varchar(250)')
          ,Pos8 = xDim.value('/x[8]','varchar(250)')
          ,Pos9 = xDim.value('/x[9]','varchar(250)')
     From (Select Cast('<x>' + Replace(@String,@Delimeter,'</x><x>')+'</x>' as XML) as xDim) A
)
Select @XML = (Select * from cteBase for XML RAW)
Select @NewString = @NewString+@NewDelimer+ltrim(rtrim(Value)) 
 From (Select Distinct Top 100 Percent 
              Value = ltrim(rtrim(Attr.value('.','varchar(max)') )) 
        From  @XML.nodes('/row') as A(r) 
        Cross Apply A.r.nodes('./@*') AS B(Attr)
        Order By 1) A

Select @NewString

Returns

 P.A P.B P.C P.D P.E

Notice the list is DISTINCT and SORTED from the original