0

我必须对产品名称的查询输出进行排序,其中名称同时包含字母和数字字符。

我已经找到了各种将变量转换为数值(+0 等)的解决方案,它们对产品名称的数字部分进行排序。但是产品名称字符串的前一部分长度不同,因此名称不按字母顺序排序:

Post Lantern PL1
Post Lantern PL2
Post Lantern PL10
Post Lantern PL22

Landscape Light LV1
Landscape Light LV2
Landscape Light LV10
Landscape Light LV11

我猜较短的名称首先排序?

我希望结果自然排序:按字母顺序排列,数字也按自然顺序排列。我努力了:

ORDER by CAST(`product_name` AS DECIMAL), product_name
...
ORDER by product_name+0

较短的名称首先排序,即使它们在字母表中较晚。最后一部分的数字需要按数字顺序排列。

4

1 回答 1

0

这是一个很长的查询,可以满足您的需求。不过,我不确定性能。您可能还想对几条记录进行一些测试以确保。

SELECT
    *
    ,SUBSTRING(
        REVERSE(CAST(REVERSE(CONCAT(`product_name`,'8')) AS UNSIGNED)),1,
        CHARACTER_LENGTH(
            REVERSE(CAST(REVERSE(CONCAT(`product_name`,'8')) AS UNSIGNED))
        )-1
    ) AS 'numericVal'
FROM `some_table`
ORDER BY
    SUBSTRING(`product_name`,1,CHAR_LENGTH(`product_name`)-CHAR_LENGTH(`numericVal`)),
    CAST(`numericVal` AS UNSIGNED INTEGER)

函数中的8CONCAT()用于以​​零结尾的数字。否则,当您反转例如字符串 "etc30" 并解析那里的数字时,它将是3,而不是03。因此,将其反转将再次产生3而不是30

您可以使用您喜欢的任何单个数字(零除外)更改函数中的这两个8 。CONCAT()

[编辑 2]

这是故障。

# Example record "Post Lantern PL10"...
SELECT
    *
    ,SUBSTRING(                                         # 5a) substring of this is calculated
        REVERSE(                                        # 4) gets re-reversed into "108"
            CAST(                                       # 3) gets casted into an integer so "801" part is parsed
                REVERSE(                                # 2) gets reversed: "801LP nretnaL tsoP"
                    CONCAT(`product_name`,'8')          # 1) is concatenated with an 8: "Post Lantern PL108"
                )
            AS UNSIGNED)
        ),
        1,                                              # 5b) from the first character (index is 1 for this in SQL)
        CHARACTER_LENGTH(                               # 5c) and the length is recalculated (steps 1-4 repeated)
            REVERSE(
                CAST(
                    REVERSE(
                        CONCAT(`product_name`,'8')
                    )
                AS UNSIGNED)
            )
        )-1                                             # 5d1) minus 1 because at the beginning we appended an 8 and we
                                                        # 5d2) want to get rid of it now, so we're dropping the last digit
    ) AS 'numericVal'
FROM `some_table`
ORDER BY                                                        # 6) order by
    SUBSTRING(`product_name`,                                   # 7a) first, substring `product_name`
        1,                                                      # 7b) from the first character
        CHAR_LENGTH(`product_name`)-CHAR_LENGTH(`numericVal`)   # 7c) with the total length - length of numeric part
    ),
    CAST(`numericVal` AS UNSIGNED INTEGER)                      # 8a) then, by the numeric part, which gets casted into
                                                                # 8b) an integer for accurate numeric ordering

[编辑 1]

我认为你拥有的最好的镜头(完全控制不同的数据)是product_name分成 3 列 - product_name(如"Landscape Light")、product_class(或其他任何东西,如"LV")和product_version(数字部分)。

于 2013-01-05T04:06:53.893 回答