【问题标题】:Using a CASE in an Order By在 Order By 中使用 CASE
【发布时间】:2011-09-16 03:42:17
【问题描述】:

我有很多关于结果集必须如何排序的规则。我需要使用 CASE 来计算要排序的列。

我正在尝试这个:

ORDER BY
              CASE 
                    WHEN ISNULL(actual_appearance_date, scheduled_appearance_date) IS NOT NULL AND icbm.emma_id IS NOT NULL -- We have it all!
                          THEN ISNULL(actual_appearance_date, scheduled_appearance_date) DESC , icbm.emma_id , version_number , icaci_t.[ijis_court_appearance_court_item_tracker_id]
                    WHEN ISNULL(actual_appearance_date, scheduled_appearance_date) IS NOT NULL AND icbm.emma_id IS NULL -- We have an appearance date, but it's manual.
                          THEN ISNULL(actual_appearance_date, scheduled_appearance_date) DESC, icaci_t.[ijis_court_appearance_court_item_tracker_id] DESC
                    WHEN ISNULL(actual_appearance_date, scheduled_appearance_date) IS NULL AND icbm.emma_id IS NOT NULL -- No appearance date, but it has a Business Message
                          THEN icbm.emma_id DESC, version_number DESC, icaci_t.[ijis_court_appearance_court_item_tracker_id] DESC
                    ELSE icaci_t.[ijis_court_appearance_court_item_tracker_id] DESC -- No Appearance date, not Message.
               END

但似乎我只能在 THEN 之后包含一列。但我需要根据我的规则使用几列。

有没有办法做到这一点?

【问题讨论】:

  • 您可以在子查询的选择子句中使用这个丑陋的代码,无需排序,然后在父查询中按一列排序
  • @Andrey:但是每个 THEN 都想返回多个要订购的东西。我认为您需要四个条件相同的 CASE(每个要排序的组件一个);或者,如果 SQL Server 支持数组并对它们进行合理排序,那么您可以从 CASE 的每个分支返回数组(我认为 PostgreSQL 会支持这种诡计,不知道 SQL Server)。
  • @mu 太短:T-SQL 中没有数组。
  • 您也可以在没有列可排序的情况下为每一列重复一次逻辑,并在这种情况下替换一个常量值,但我想这会比子查询更丑陋。
  • OP 中思想的核心问题当然是,您不能告诉 SQL 根据一行中的值对不同列的整个结果进行排序。

标签: sql sql-server tsql sql-order-by


【解决方案1】:

在不同的行上按不同的规则对结果集进行排序实际上没有意义,因为冲突的规则会导致行之间的单独排序方式不一致。换句话说,如果排序规则不一致,就没有一致的排序。

但是,我怀疑您让这个问题变得比实际需要的复杂得多。我怀疑你可以通过以下方式订购:

ISNULL(actual_appearance_date, scheduled_appearance_date) DESC , icbm.emma_id , version_number , icaci_t.[ijis_court_appearance_court_item_tracker_id] 

NULL 值将自行排序并一起排序。也许从这里开始,找出需要改变的地方。

【讨论】:

  • +1 但最后一项可能应该有 DESC 说明符(OP 一定在第一个 THEN 中错过了它,因为 DESC 在其他三个地方出现在 icaci_t.[ijis_court_appearance_court_item_tracker_id] 旁边。跨度>
  • 这看起来不错 - 但 actual_appearance_date 和 sheduled_appearance_date 都可以为空。这还能用吗?
  • 好吧,它仍然可以工作,因为这些行将按 NULL 值排序。真正的问题是该排序是否对您有用,或者您是否需要调整上述内容以满足您的确切要求。
【解决方案2】:

在 T-SQL 中,CASE 是一个返回单个值的表达式,而不是流控制语句(如在某些语言中)。因此,您将需要重复表达式,其中可能需要对多个列进行排序......并且每个表达式都需要返回兼容的数据类型。这里可能有一些捷径,我可能遗漏了一些逻辑,但是如果您为其中一些列创建别名然后使用子查询,它可以帮助简化所有 CASE 结构。

SELECT * FROM 
(
    SELECT
        /* other columns */
        as_date = COALESCE(actual_appearance_date, scheduled_appearance_date),
        emma_id = icbm.emma_id,
        vn = version_number, 
        ca = icaci_t.[ijis_court_appearance_court_item_tracker_id]
    /* rest of query */
) AS x
ORDER BY
CASE WHEN as_date IS NOT NULL THEN as_date END DESC,
CASE WHEN as_date IS NOT NULL AND emma_id IS NOT NULL THEN emma_id END,
CASE WHEN as_date IS NOT NULL AND emma_id IS NULL THEN ca END DESC,
CASE WHEN as_date IS NULL AND emma_id IS NOT NULL THEN emma_id DESC,
CASE WHEN as_date IS NOT NULL AND emma_id IS NOT NULL THEN vn END,
CASE WHEN as_date IS NULL AND emma_id IS NOT NULL THEN vn END DESC,
CASE WHEN as_date IS NULL AND emma_id IS NOT NULL THEN ca END DESC,
ca DESC;

【讨论】:

    【解决方案3】:

    好吧,有一种方法可以做到这一点,但它是一个 UGLY UGLY hack。

    只需连接您的列(如果它们不是 varchar,则转换它们)并将它们从左到右添加。

    然后选择 (CONVERT(VARCHAR(10), actual_appearance_date,111)) + 转换(VARCHAR, emma_id)

    您需要确保日期字符串的格式为 YYYY、MM、DD(如上),以便顺序正确。如果您希望列降序排列,您可以反转字符串。

    此解决方案可行,但在道德上令人震惊,因此后果自负。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 2016-06-11
      • 1970-01-01
      相关资源
      最近更新 更多