【问题标题】:How to use order by with modified column如何通过修改列使用 order by
【发布时间】:2021-10-31 16:01:54
【问题描述】:

有一个带有年龄列的表。此列的值是 varchar,因为 1 岁以下的人的年龄以月为单位保存,并带有额外的 'm' (9 Month old -> '9m')

我知道这通常是一个坏主意,应该坚持出生日期,但在这种情况下,年龄是指历史上特定日期的年龄 - 此外,这是课程的一部分,也是整个重点是学习如何处理“奇怪”的数据。

我的第一个想法是在所有非纯数字的年龄上加上前导零:

SELECT * 
FROM db 
ORDER BY REPLACE(age, (IF ISNUMERIC(age) age ELSE CONCAT('0', age))) DESC;

但是,这不是有效的 SQL 语句,我的其他尝试也不是。 问题是:如何在不改变数据库的情况下调整ORDER BY 的值?

另一种方法是仅选择具有纯数字年龄值的行,并为其余行单独选择单独排序,然后将它们组合起来。

我对此的看法如下:

(SELECT name, age 
 FROM titanic 
 WHERE ISNUMERIC(age) 
 ORDER BY age DESC) 
UNION 
(SELECT name, age 
 FROM titanic 
 WHERE NOT ISNUMERIC(age) 
 ORDER BY age);

这实际上是有效的,或者至少它给了我一个结果。但在结果中我真的看不到订单发生了什么,看起来UNION 撤消了所有操作。

提前致谢,我会接受任何提示,甚至只是我应该研究的函数/方法的名称!

【问题讨论】:

  • 您可能可以使用CASE WHEN … ELSE … 结构而不是IF
  • 也试过了,ELSE 出现错误 - 然后我尝试了两个没有 ELSE 的 WHEN 案例,同样的错误
  • 如果将人的年龄存储在数据库中,数据会随着时间的推移而腐烂。存储生日。

标签: sql postgresql sql-order-by


【解决方案1】:

这行得通吗?

选择姓名、年龄 来自泰坦尼克号 ORDER BY isnumeric(age), 年龄

【讨论】:

    【解决方案2】:

    我会使用“Case When”结构并在“Order by”中进行一些转换,以获取两种年龄类型的总月数。

    Select name, age
    From tbl
    Where age SIMILAR TO '[1-9][0-9]*' Or
          age SIMILAR TO '[1-9][0-2]?m'
    Order by Case When age SIMILAR TO '[1-9][0-2]?m' Then Substring(age,1,CHAR_LENGTH(age)-1)::int
                  When age SIMILAR TO '[1-9][0-9]*' Then age::int * 12 End   
    

    【讨论】:

    • 我在问题中准确地解决了您在此处解释的内容......这不是一个选项
    • @ningelsohn 为什么这毕竟不是一个选项,它有效。
    【解决方案3】:

    首先存储年龄是个坏主意,您必须定期更新每一行,在这种情况下至少每月更新一次。将其存储为字符串会将一个糟糕的想法变成一个糟糕的想法。不仅你有维护,它不是直截了当的,也不是直截了当的插入它。而是将出生日期存储为时间戳或日期。然后,您可以快速获取年龄(通过age),然后可以在所需的任何级别对​​结果间隔使用extract 函数。如果您绝对必须使用文本指示器显示年龄/年/月(甚至几天),则您创建一个派生适当值的视图。 (见demo

    create or replace view titanic as 
        select name "Name"
             , case when extract( year from age(dob))::integer > 0 then to_char (extract( year from age(dob)), '999') || ' years'
                    when extract( month from age(dob))::integer> 0 then to_char (extract( month from age(dob)), '99') || ' months'
                    else to_char (extract( day  from age(dob)),'99') || ' days'
               end "Age"
          from titanic_tbl;
    

    【讨论】:

    • 谢谢 - 老实说,我完全了解年龄列的问题。我本可以问一个更笼统的问题,即在操作字符串之后对字符串进行排序,而无需实际更改数据库中的值。就我而言,如果它是数字,我想在将其转换为数字后按年龄排序。如果不是,我想删除非数字字符(在这种情况下,只需删除“m”就可以了)并将数字除以 12。9m 应该导致 0.75,以便顺序正确。我目前正在度假,回家后会详细研究您的建议 - 谢谢!
    • 不用担心。只要您知道存储年龄的问题。我刚刚在几次看到它的实现(以及由此产生的需要重写)。这只是我看到它时要指出的事情之一。但是您的评论比实际问题更好地描述了该问题。对于完全不知道您要解决什么问题的人,请始终仔细考虑您的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多