【问题标题】:PHP sorting in descending order not working as expectedPHP按降序排序未按预期工作
【发布时间】:2016-04-14 09:51:15
【问题描述】:

我有下表:

store_items

id item_no   cat   sub
1  1l500bk   lady  sport
2  1l1550bk  lady  sport
3  2m1600rd  men   shoe
4  2m1599rd  men   shoe
5  2m1589rd  men   shoe
6  3l900bk   baby  shoe
7  3l1000bk  baby  shoe

如您所见,item_no 包含数字和文本,当涉及到排序时,我知道这很痛苦。但是,我尝试测试此 PHP 代码:

//Table of results
$query = "SELECT * from store_items GROUP by cat,sub ORDER by cat,sub,item_no Desc";
$result = mysql_query($query);
if(!$result){
    mysqli_error();
}

while($row=mysql_fetch_assoc($result)){
    echo "<tr><td align=center>{$row['cat']}</td><td align=center>{$row['sub']}</td><td align=center>";

   echo ucfirst($row['item_no']);

   echo "</td></tr>";
}

我想要的只是输出 cat 和 sub 组合在一起的列表,其中每一个都将在其旁边列出最新/最高的 item_no...,如下所示:

期待输出:

cat    sub    item_no
lady   sport  1l1550bk
men    shoe   2m1600rd
baby   shoe   3l1000bk

【问题讨论】:

    标签: php mysql sorting group-by


    【解决方案1】:

    这里的主要问题是 MAX(item_no) 与特定 catsub 值的 MAX(id) 不对应。另一个问题是item_no 本身是字母数字的,不能自然地确定哪个是最大值。对于这种情况,您可以先定义自己的函数(因为 MySQL 不提供此类函数),该函数允许您将 item_no 值转换为纯数字字符串(1l1550bk -> 11550):

    自定义SQL函数:

    DROP FUNCTION IF EXISTS STRIP_NON_DIGIT;
    DELIMITER $$
    CREATE FUNCTION STRIP_NON_DIGIT(input VARCHAR(255))
       RETURNS VARCHAR(255)
    BEGIN
       DECLARE output   VARCHAR(255) DEFAULT '';
       DECLARE iterator INT          DEFAULT 1;
       DECLARE count INT DEFAULT 0;
       WHILE iterator < (LENGTH(input) + 1) AND count < 10 DO
          IF SUBSTRING(input, iterator, 1) IN ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ) THEN
             SET output = CONCAT(output, SUBSTRING(input, iterator, 1));
             SET COUNT=COUNT+1;
          END IF;
          SET iterator = iterator + 1;
       END WHILE;
       RETURN output;
    END
    $$
    DELIMITER $$
    

    然后您可以使用此 STRIP_NON_DIGIT() 函数来确定每个 cat,sub 对的正确最大 item_no 值:

    SELECT
        s.cat,
        s.sub,
        s.item_no
    FROM
        store_items s,
        (
            SELECT MAX(CAST(STRIP_NON_DIGIT(item_no) AS UNSIGNED)) as numeric_item, cat, sub 
            FROM store_items 
            GROUP BY cat, sub
        ) t
    WHERE
        CAST(STRIP_NON_DIGIT(s.item_no) AS UNSIGNED) = t.numeric_item
        AND s.cat = t.cat
        AND s.sub = t.sub;
    

    这将为您提供所需的输出:

    +------+-------+----------+
    | cat  | sub   | item_no  |
    +------+-------+----------+
    | baby | shoe  | 3l1000bk |
    | lady | sport | 1l1550bk |
    | men  | shoe  | 2m1600rd |
    +------+-------+----------+
    3 rows in set
    

    希望这会对你有所帮助。

    【讨论】:

    • 感谢您的回复,我会理解并测试您所写的内容。我会通知你结果:) .. 再次感谢
    【解决方案2】:

    MySQL MAX() 不适用于字母数字值。

    如果您的表中不需要太多行,您可以获取所有数据并使用完整的 PHP 完成这项工作。

    如果您的表格太大,您应该考虑添加另一个字段,就像 Gary Hayes 所说的那样。您可以使用自动增量 ID。

    【讨论】:

    • 所以我认为这是不可能的,哦,我现在尝试编辑表结构。
    • @AliHamra 你可以做到。看我的回答。如果你想改变你的表结构,也许只需添加一个“created_at”列。
    【解决方案3】:

    如果您没有在 GROUP BY 中使用 SELECT item_no 或对其应用聚合函数,那么 SELECT item_no 没有任何意义。您将随机获得一个是到达行的 item_no 值。你可以SELECT cat, sub, GROUP_CONCAT(item_no) as item_nos 代替。

    SELECT cat, sub, SUBSTRING_INDEX(GROUP_CONCAT(item_no ORDER BY id DESC),',',1) as newest_item_no
    FROM store_items
    GROUP BY cat, sub
    ORDER BY cat,sub
    

    编辑:我不确定您所说的最新/最高项目编号是什么意思,但我上面的查询假设最高 ID 是最新项目。在 GROUP_CONCAT 内部,如果您想要排序,您可以将“id”更改为“item_no”。 GROUP_CONCAT 将按该顺序为您提供一个逗号分隔的 item_no 列表。然后,SUBSTRING_INDEX 函数只为您获取丢失的第一个 item_no,并将其余的丢弃。

    【讨论】:

    • 感谢您的回复,我的意思是根据预期的输出,我需要找出与其类别相关的最新商品编号,因为每次收到新产品时,商品编号都会增加.我试过使用你的查询,但我得到了 mysqli_error() expects 1 paramenter to be resource ... 。我会再检查一下有什么问题
    • 我修复了查询中的几个错误。 1 是我错过了 FROM 子句。我强烈建议您在 PHP 中尝试之前直接在 MySQL 中尝试查询(例如在 phpMyAdmin 中),这样您就可以清楚地看到任何 MySQL 错误。您的 mysqli 错误是因为我的查询错误导致返回值为 Boolean FALSE 而不是结果资源。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多