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。
这是我的解决方案:
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;
//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
排序
请容忍我的英文。
我有一个这样的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。
这是我的解决方案:
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;
//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
排序