【问题标题】:Is this a dumb way to sort a few values?这是对一些值进行排序的愚蠢方法吗?
【发布时间】:2013-08-25 00:32:13
【问题描述】:

我正在检查事物的尺寸,我想知道从最大到最小的 3 个尺寸。

所以这是我写的有点“神奇”的函数:

CREATE FUNCTION dbo.SortDimensions
    ( @aDim1 udt_Dimension
    , @aDim2 udt_Dimension
    , @aDim3 udt_Dimension 
    )
RETURNS @rDimensions TABLE 
    ( Dim1 udt_Dimension
    , Dim2 udt_Dimension
    , Dim3 udt_Dimension 
    )
AS
BEGIN
  ; WITH OrderedDims ( Dimension ) AS ( 
                SELECT @aDim1
      UNION ALL SELECT @aDim2
      UNION ALL SELECT @aDim3
   )
  ,      Pairs ( Name, Value ) AS ( 
      SELECT 'Dim' + CAST( ROW_NUMBER() OVER (ORDER BY( Dimension ) DESC ) AS varchar ), Dimension 
        FROM OrderedDims 
  )
  INSERT INTO @rDimensions ( Dim1, Dim2, Dim3 )
      SELECT MAX(Dim1), MAX(Dim2), MAX(Dim3) 
        FROM Pairs 
      PIVOT ( MAX(Value) FOR Name IN ( [Dim1], [Dim2], [Dim3] )) p

  RETURN
END

做同样的事情不是很多工作吗:

DECLARE @lDim1 udt_Dimension
DECLARE @lDim2 udt_Dimension 
DECLARE @lDim2 udt_Dimension

IF @aDim2 > @aDim1 
  BEGIN
    SELECT @lDim1 = @aDim2 
         , @lDim2 = @aDim1
  END
ELSE 
  BEGIN 
    SELECT @lDim1 = @aDim1 
         , @lDim2 = @aDim2
  END

IF NOT @aDim3 > @aDim2 
  BEGIN 
    SET @lDim3 = @aDim3
  END
ELSE
  BEGIN
    SET @lDim3 = @lDim2
    IF @aDim3 > @lDim1 
      BEGIN
        SET @lDim2 = @lDim1
        SET @lDim1 = @aDim3
      END
    ELSE 
      BEGIN
        SET @lDim2 = @aDim3
      END
  END 

INSERT INTO @rDimensions VALUES ( @lDim1, @lDim2, @lDim3 )

我相信一位 DBA 曾经告诉我,设计 SQL Server 的人为变量重用了临时表技术,因此它几乎是在表和变量之间进行清洗。 (如果这不是真的,请继续打消我这个念头。)

【问题讨论】:

  • 是的,#temp 表和@table 变量的实现几乎相同。

标签: tsql sorting


【解决方案1】:

我很确定这应该会更快:

CREATE FUNCTION dbo.SortDimensions
    ( @aDim1 udt_Dimension
    , @aDim2 udt_Dimension
    , @aDim3 udt_Dimension 
    ) RETURNS TABLE
AS RETURN
(
    WITH cte As (     SELECT @aDim1 As Dim
            UNION All SELECT @aDim2
            UNION ALL SELECT @aDim3
    )
    , cte2 As ( SELECT Dim, ROW_NUMBER() OVER(ORDER BY Dim) As Odr FROM cte )
    SELECT  
            MAX(CASE WHEN Odr=1 THEN Dim ELSE NULL END) As Dim1,
            MAX(CASE WHEN Odr=2 THEN Dim ELSE NULL END) As Dim2,
            MAX(CASE WHEN Odr=3 THEN Dim ELSE NULL END) As Dim3
    FROM    cte2
)

【讨论】:

  • 它也更干净。枢轴会减慢速度吗?看到我感到困惑,因为我一直喜欢 SQL 的东西是基于集合的“算术”焦点,所以我很容易就陷入了 Anti-RBAR 人群,但其中一些人不喜欢 CASE 语句。另外,我喜欢内联 TVF,但我听说 CTE 真的可以让优化器失效。
  • 递归 CTE 可能会关闭优化器,但普通 CTE 只是别名子查询,应该完全相同。如果您听到不同的声音,请指出我,因为我真的很想知道它。正如 Jeff Moden 可以证明的那样,我和任何人一样都是反 RBAR,而用作交叉表/穷人 Pivot 的 CASE 表达式直接来自反 RBAR 手册。 AFAIK,CASE 表达式仅在用作 WHERE 子句中的 On/Off 开关时才会出现问题(这是 Catch-All Query 问题)。
  • 也许这已经过时了,但我发现它在谷歌上搜索:stackoverflow.com/questions/2086946/…
  • @Axeman 这是 2008 年前在 SQL 的 CU 中修复的已知错误:connect.microsoft.com/SQLServer/feedback/details/527843/…。没有理由避免 CTE。
猜你喜欢
  • 2011-06-09
  • 2021-10-01
  • 1970-01-01
  • 2013-12-16
  • 2015-02-12
  • 2011-06-23
  • 2015-06-16
  • 2022-08-19
相关资源
最近更新 更多