根据订单列更新周围的行

时间:2018-04-11 20:26:28

标签: php mysql sorting

我需要在添加新类别和更改现有类别时为类别设置自定义顺序。我相信代码和SQL查询在两种情况下都是一样的 在我的webshop_categories - 表中,我有一个sorting_order INT - 列,用于阻止类别应该输出到观看者的顺序。

以下是我的表(so = sorting_order)的简化示例:

id  |   name   |  so
--------------------
1   |   Shoes  |  1
2   |   Hats   |  2
3   |   Bags   |  3
4   |   Coats  |  4
5   |   Rings  |  5

当添加未指定的类别时,我只会填写表格,并按如下方式提交:
(这将添加一个新类别,并将其放在最后。在这种情况下,so将设置为6)

$so = $dbh->query('SELECT (MAX(so)+1) FROM webshop_categories WHERE so != 0')->fetchColumn();
$ins = $dbh->prepare('INSERT INTO webshop_categories (name, so)')->execute([$_POST['name'], $so]);

但有时候我需要改变类别的顺序 我可能需要将Coats移到鞋子和帽子之间 这需要更新周围的类别 在这种情况下;无论我将这个类别移动到何处,我们都需要执行+1so列,以便为此移动腾出空间。但显然,增量需要停在高士。

反之亦然。如果我将帽子移到大衣和戒指之间,我需要-1做大衣和手袋。试。

实现这一目标的好方法是什么?

更改是通过form select进行的,其中选项move to top(表示1)和Move to after ?cat_name?

我相信在添加带有预设排序顺序的新类别时,它将是相同的代码。具有相同选项的相同选择列表。

我是否需要查询并获取需要使用so更新+/- 1的所有类别,并循环显示这些类别以进行更改?
或者可能有一种方法可以同时对它们进行+/- 1而无需循环遍历每一个?

复制所有行(进入PHP数组),删除它们,创建一个更新so的新列表,然后将它们重新插入,不应该只是为了进行这些更改......但这是我认为有效的一种方式......

1 个答案:

答案 0 :(得分:1)

有多种方法可以做到这一点,但具体方法实际上取决于您的结构。

那就是说,无论你接近它,你只需要增加或减少你正在改变的那个之下或之上的那些:

当新so值为:

  1. less 比当前的那个(从4到2),选择所有值 less 比当前的值(包括新的(2,3))和增量他们是1
  2. 更大比当前一个(从2到4),选择所有值更大而不是当前值<包括新值(4,3),并减少他们是1
  3. 我建议只选择您需要更新的行,因此“if less than”等逻辑将出现在select查询中。然后,您只需使用该结果数组进行更新。

    示例:

    1 = shoes
    2 = hats
    3 = bags
    4 = coats
    5 = rings
    

    警告:此代码非常老派,仅用于快速说明,以显示逻辑。它没有经过测试,可能有错误,请在使用前进行测试。

    示例代码函数将更改大于或小于的任何值,例如4到2,或2到4等等

    // You'd retrieve the requested change data from your form (or whatever)
    update_categories_so(
        (int) $_POST['category_id'],
        (int) $_POST['current_so'],
        (int) $_POST['new_so']
    );
    
    /**
     * @param int $categoryIdForChangedSo
     * @param int $currentSo
     * @param int $newSo
     *
     * @return void
     */
    function update_categories_so($categoryIdForChangedSo, $currentSo, $newSo)
    {
        // Determine if incrementing or decrementing
        $increment = $newSo < $currentSo  ? true : false;
    
        // Set increment or decrement var for the update
        $changeBy = $increment ? '+' : '-';
    
        // Set the where clause to get the current category_ids
        // which would need to be updated
        $selectWhereClause = $increment
            ? "'so' >= $newSo AND 'so' < $currentSo"
            : "'so' <= $newSo AND 'so' > $currentSo";
    
        $selectSql = "
            SELECT
                `category_id`
            FROM
                `webshop_categories`
            WHERE
                {$selectWhereClause}
            ";
    
        // Return the results into $categoryIdsForUpdate
    
        // Update the categories which are affected by the main change,
        // from the array from the DB
        $updateOtherSoSql = "
            UPDATE
                `webshop_categories`
            SET
                'so' = 'so' {$changeBy} 1
            WHERE
                'category_id' IN ({$categoryIdsForUpdate})
            ";
    
        // Update the main one being changed
        $updateRequestedSosql = "
            UPDATE
                `webshop_categories`
            SET
                so = {$newSo}
            WHERE
                'category_id' = {$categoryIdForChangedSo}
            ";
    }
    

    我不知道您是如何处理错误的,但是您可以返回结果 - 检查查询是否正常等等

    有关$selectWhereClause的更多信息,请了解其工作原理:

    • 请勿更新请求更新的内容(单独更新)
    • 如果新的“so”小于当前,那么我们从new(inc new)增加到当前的
    • 如果新的“so”大于当前,那么我们从当前的1减少到新的(包括新的)

    有关从数据库返回的$categoryIdsForUpdate数据的更多信息。 下面的示例数组是将“so”4(Coats)更改为2(当前为Hats)。 (示例ID不是1-5,以避免与“so”值混淆)

    category_id => so

    $categoryIdsForUpdate = [
        10 => 1, // (shoes) not included as is less than new "so"
        13 => 2, // (hats)  incremented by 1
        17 => 3, // (bags)  incremented by 1
        18 => 4, // (coats) not included as is current category_id
        27 => 5, // (rings) not included as greater than current "so"
    ];