TSQL:从具有最低正值的列集中选择

时间:2009-06-25 12:37:19

标签: sql-server sql-server-2005 tsql

示例架构:

RowID    Quantity    ModifiedPrice    GroupPrice    CustomPrice    SalePrice
----------------------------------------------------------------------------
1        5           20.00            0             15.00          17.00
2        2           14.00            7.00          22.00          0
3        9           10.00            10.00         0              11.00

基于此示例表,我希望能够以最有效/最简单的方式选择四个* Price列之间的最低非零值。

示例输出:

RowID    Quantity    EndPrice
------------------------------
1        5           15.00
2        2           7.00
3        9           10.00

有关额外信息,数据库是SQL Server 2005。

3 个答案:

答案 0 :(得分:4)

SELECT  RowId, Quantity,
        (
        SELECT  MIN(price)
        FROM    (
                SELECT  ModifiedPrice AS price
                UNION ALL
                SELECT  GroupPrice
                UNION ALL
                SELECT  CustomPrice
                UNION ALL
                SELECT  SalePrice
                ) qi
        WHERE   price > 0
        )
FROM    mytable

这比一堆CASE语句更具可读性。

但请注意,这大约是4语句的CASE倍。

这是测试脚本,它解析并产生正确的结果:

CREATE TABLE #t_prices
        (
        RowID INT NOT NULL,
        Quantity INT NOT NULL,
        ModifiedPrice FLOAT NOT NULL,
        GroupPrice FLOAT NOT NULL,
        CustomPrice FLOAT NOT NULL,
        SalePrice FLOAT NOT NULL
        )

INSERT
INTO    #t_prices
VALUES  (1, 5, 20.00, 0, 15.00, 17.00)
INSERT
INTO    #t_prices
VALUES  (2, 2, 14.00, 7.00, 22.00, 0)
INSERT
INTO    #t_prices
VALUES  (3, 9, 10.00, 10.00, 0, 11.000)


SELECT  RowId, Quantity,
        (
        SELECT  MIN(price)
        FROM    (
                SELECT  ModifiedPrice AS price
                UNION ALL
                SELECT  GroupPrice
                UNION ALL
                SELECT  CustomPrice
                UNION ALL
                SELECT  SalePrice
                ) qi
        WHERE   price > 0
        )
FROM    #t_prices

答案 1 :(得分:3)

我会使用案例陈述:

CASE
  WHEN condition THEN trueresult
  [...n]
[ELSE elseresult]
END

从一个整洁的答案开始,假设没有值为NULL:

CASE 
  WHEN ModifiedPrice > GroupPrice AND ModifiedPrice > CustomPrice AND ModifiedPrice > SalePrice THEN ModifiedPrice
  WHEN GroupPrice > CustomPrice AND GroupPrice > SalePrice THEN GroupPrice
  WHEN CustomPrice > SalePrice THEN CustomPrice
  ELSE SalePrice
END

如果任何值为NULL,那么这些子句将返回false,因此我们需要使用ISNULL进行修复,并将NULLS替换为较大的负数或零,如果您不期望任何负值。假设没有负价格,我将使用零。

CASE 
  WHEN ModifiedPrice > ISNULL(GroupPrice, 0) AND ModifiedPrice > ISNULL(CustomPrice, 0) AND ModifiedPrice > ISNULL(SalePrice,0) THEN ModifiedPrice
  WHEN GroupPrice > ISNULL(CustomPrice, 0) AND GroupPrice > ISNULL(SalePrice, 0) THEN GroupPrice
  WHEN CustomPrice > ISNULL(SalePrice, 0) THEN CustomPrice
  ELSE ISNULL(SalePrice, 0)
END

不漂亮,但它会起作用。如果执行某些统计信息以查看哪个列通常是最大值,则可以更改查询以首先测试该列。 (您不能仅仅重新排列我的WHEN子句,因为他们都认为先前的价格已被拒绝。如果CustomPrice通常是最大的,我会在上面的代码中交换ModifiedPrice和CustomPrice。)

答案 2 :(得分:0)

我对这个特定问题有点迟了,但UNPIVOT也可能在这方面很方便。 4列可能不是太糟糕,但当你看到30个你想要取消交叉表的列时,UNPIVOT是天赐之物: - )