repetidos - MySQL-Ordenar por category_id intenta evitar tener duplicados cerca uno del otro
select mysql (5)
Por favor ten paciencia con mi inglés.
Tengo una mesa como esta,
id | category_id | product_id
-----------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 2 | 3
5 | 1 | 4
6 | 3 | 5
Quiero que la salida sea,
id | category_id | product_id
----------------------------------
1 | 1 | 1
3 | 2 | 1
6 | 3 | 5
2 | 1 | 2
4 | 2 | 3
5 | 1 | 4
Entonces, en resumen, lo que necesito es que el category_id
se ordene de modo que se repita en ciclos como 1, 2, 3, 1, 2, 3,
... etc.
... trata de evitar tener duplicados cerca uno del otro
Bueno esta bien. La solución más sencilla que puedo encontrar es un GROUP BY ''product_id'' ORDER BY ''category_id''
. Esto haría que su mesa se vea así:
id | category_id | product_id
----------------------------------
1 | 1 | 1
3 | 2 | 1
2 | 1 | 2
4 | 2 | 3
5 | 1 | 4
6 | 3 | 5
Supongo que "category_id se debe ordenar para que se repita en ciclos" es una traducción de "No quiero duplicados cerca uno del otro".
Si tuviera tres categorías en el producto uno y en el producto dos, se agruparían (1,1,1,2,2,2) pero las categorías serían ordenadas numéricamente (1,2,3,1,2,3) . No es una solución perfecta para lo que quieres, pero es una solución simple que parece darte lo que necesitas.
Cualquier piratería complicada en su consulta solo ralentizará la consulta. Si bien puede que no sea un problema ahora, podría ser un gran problema si tiene muchos registros.
Aquí está mi solución:
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;
Demostración aquí: http://sqlfiddle.com/#!9/5bce3/37
Aquí hay una consulta que le da ese resultado:
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;
Donde el product
es tu mesa.
Ver DEMO AQUÍ
En serio, debe pensar en reestructurar su tabla, necesita agregar un campo temporal, lo que categorizaría la categoría categoría y luego ordenar por ese campo remp. Mi sugerencia es a continuación.
CREATE TABLE Test1 ( id
int, t_category int, category_id
int, Product_id
int);
INSERT INTO Test1 ( id
, t_category
, category_id
, product_id
) VALUES (1,1,1,1), (2,2,1,2), (3,1,2,1), (4,2,2, 3), (5,3,1,4), (6,1,3,5);
SELECCIONE category_id, product_id FROM Test1 orden por t_category, category_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]);
}
}
}
Primero obtenga el valor más grande para category_id
, luego pase de 1 a max category_id
y almacene todos los objetos de resultados en $resultsArray
. Ahora use foreach dentro de un tiempo para obtener los resultados.
El if else
inside foreach emite un registro o elimina un objeto de resultado de $resultsArray
si no tiene más registros en él. Cuando $resultsArray
está completamente vacío, mientras que el bucle se rompe.