MySQL - 按 category_id 排序尽量避免重复项彼此靠近

MySQL - Order by category_id try to avoid having duplicates close to each other

请容忍我的英文。

我有一个这样的table,

 id |  category_id  |  product_id
 -----------------------------------
  1 |  1            |  1
  2 |  1            |  2
  3 |  2            |  1
  4 |  2            |  3
  5 |  1            |  4
  6 |  3            |  5

我希望输出是,

id  |  category_id  |  product_id
----------------------------------
1   |  1            |  1
3   |  2            |  1
6   |  3            |  5
2   |  1            |  2
4   |  2            |  3
5   |  1            |  4

简而言之,我需要的是 category_id 必须按顺序重复,如 1, 2, 3, 1, 2, 3,...等等

...try to avoid having duplicates close to each other

嗯,好的。我能想到的最简单的解决方案是 GROUP BY 'product_id' ORDER BY 'category_id'。这将使您的 table 看起来像这样:

id  |  category_id  |  product_id
----------------------------------
1   |  1            |  1
3   |  2            |  1
2   |  1            |  2
4   |  2            |  3
5   |  1            |  4
6   |  3            |  5

我假设 "category_id must be ordered so that it repeats in cycles" 是 "I don't want duplicates near each other" 的翻译。

如果您在产品一和产品二上有三个类别,它们将组合在一起 (1,1,1,2,2,2),但类别将按数字顺序排列 (1,2,3,1 ,2,3).它不是您想要的完美解决方案,但它是一个简单的解决方案,似乎可以满足您的需求。

查询中任何复杂的黑客行为只会减慢查询速度。虽然现在这可能不是问题,但如果你有很多记录,这可能是个大问题。

这是一个给你结果的查询:

SELECT p1.*
FROM `product` p1
JOIN `product` p2
      ON p2.category_id = p1.category_id 
      AND p2.id <= p1.id
GROUP BY p1.id
ORDER BY COUNT(*),category_id;

其中 product 是您的 table。

DEMO HERE

这是我的解决方案:

SET @rank=-1;
SET @prior_category=null;
SELECT @cycle_length:=COUNT(distinct category_id) FROM table1;

SELECT id, category_id, product_id 
FROM 
     (SELECT @rank:=CASE WHEN @prior_category!=category_id THEN 0 ELSE @rank+1 END AS rank, @prior_category:=category_id AS prior_category_id, id, category_id, product_id 
      FROM table1 
      ORDER BY category_id) AS extended_table1
ORDER BY rank*@cycle_length + category_id, id;

演示在这里: http://sqlfiddle.com/#!9/5bce3/37

//Get largest category_id value
$sql = "SELECT category_id FROM table ORDER BY category_id DESC LIMIT 1";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
$maxCatId = $row['category_id'];

//Query for every possible category_id
$resultsArray = array();
for ($i = 1; $i <= $maxCatId; $i++) {
    $sql = "SELECT * FROM table WHERE category_id = " . $i;
    $resultsArray[] = $conn->query($sql);
}

//As long as $resultsArray is not empty
while ($resultsArray) {
    foreach ($resultsArray as $index => $res) {
        if ($row = $res->fetch_assoc()) {
            echo $row['id'] . ' ' . $row['category_id'] . ' ' . $row['product_id'];
        } else {
            unset($resultsArray[$index]);
        }
    }
}

先取category_id的最大值,然后从1循环到最大值category_id,将所有结果对象存入$resultsArray。现在用foreach里面一会儿输出结果。

foreach 中的 if else 回显一条记录或从 $resultsArray 中删除一个结果对象(如果其中没有更多记录)。当 $resultsArray 完全为空时,while 循环中断。

您真的需要考虑重组 table,您需要添加一个临时字段来对 category_id 进行分类,然后按该 remp 字段进行排序。 我的建议如下。

创建 TABLE 测试 1 (id 整数, t_category 整数, category_id 整数, Product_id 整数) ;

插入测试 1 (id,t_category,category_id,product_id) 价值观 (1,1,1,1), (2,2,1,2), (3,1,2,1), (4,2,2,3), (5,3,1,4), (6,1,3,5) ;

SELECT category_id, product_id 从 测试1 按 t_category、category_id

排序