Foros del Web » Programando para Internet » PHP »

Ordenar datos arbitrariamente

Estas en el tema de Ordenar datos arbitrariamente en el foro de PHP en Foros del Web. Tengo la siguiente duda: Estoy construyendo un CMS (PHP), en el cual, quiero que los usuarios puedan elegir libremente el orden en que se despliega ...
  #1 (permalink)  
Antiguo 13/02/2006, 20:16
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Ordenar datos arbitrariamente

Tengo la siguiente duda:

Estoy construyendo un CMS (PHP), en el cual, quiero que los usuarios puedan elegir libremente el orden en que se despliega la información de cierta tabla en una base de datos (MySQL).

Me explico con un ejemplo, supongamos que tengo esta tabla:

|------------------------------|
|--id --Nombre--Apellido---|
|------------------------------|
|--1------Juan-------Pérez--|
|--2------Perdo-----Gómez-|
|--3------Raúl------López---|
|------------------------------|

Haciendo la consulta, obtengo los datos en el orden:
1 - Juan
2 - Pedro
3 - Raúl

Ahora, si por cualquier razón, el usuario quiere que "Pedro" esté en primer lugar, independientemente del orden alfabético o el orden en que fueron introducidos los datos, no hay ninguna consulta (SQL) que resuelva eso.

La idea es darle al usuario la posibilidad de "subir" o "bajar" un registro de lugar.

Una idea que tuve, fue de agregar una tercer columna, llamada por ejemplo "view_index", en la cual asigno el orden que tiene cada elemento (1,2,3,...)

Sin embargo, esta solución supone que para subir o bajar de posición un registro, hay que modificar el "view_index" de TODOS los demás registros, además que el cálculo del valor de dicho campo es muy pesado

Se me ocurre que dicha información de orden, no esté en la base de datos, sino en otro lugar, a lo mejor en forma de un arreglo...


¿Alguien conoce un método efectivo para hacer esto?



Gracias de antemano por cualquier ayuda.

P.D.
Probablemente este post encaje más en el foto "Bases de datos", pero como busco una solución orientada a PHP, decidí ponerlo aquí.
  #2 (permalink)  
Antiguo 13/02/2006, 22:38
Avatar de uamistad  
Fecha de Ingreso: diciembre-2004
Ubicación: Cd. de México
Mensajes: 1.395
Antigüedad: 19 años, 4 meses
Puntos: 1
Cita:
Sin embargo, esta solución supone que para subir o bajar de posición un registro, hay que modificar el "view_index" de TODOS los demás registros, además que el cálculo del valor de dicho campo es muy pesado
No necesariamente tienen que cambiar el view_index de todos los demás registros ni hacer complicados cálculos.

Simplemente haste una función que intercambie valores de view_index, se vería como:

intercambia_lugares(id1, id2);

Por dentro, la función nada más toma el view_index de cada uno e intercambia valores, pero sólo se atacaron dos registros de tu tabla.
__________________
"Di no al Internet Explorer" -Proverbio Chino-
  #3 (permalink)  
Antiguo 14/02/2006, 00:57
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Cita:
Por dentro, la función nada más toma el view_index de cada uno e intercambia valores, pero sólo se atacaron dos registros de tu tabla.
Tienes toda la razón, pero la intensión es no sólo subir o bajar un nivel a la vez, sino varios (con un clásico drag & drop). Etonces se tendrían que modificar todos los valores que queden "enmedio", lo cual, la misma función puede hacer...

Mi duda es más bien, si ya existe algún método estándar para hacer eso (ya que es bastante común), y no tener que "reinventar la rueda".

Gracias!
  #4 (permalink)  
Antiguo 14/02/2006, 01:10
Avatar de uamistad  
Fecha de Ingreso: diciembre-2004
Ubicación: Cd. de México
Mensajes: 1.395
Antigüedad: 19 años, 4 meses
Puntos: 1
otra idea

Hola, ya te entendí, quién sabe si haya algo estándar, me interesaría saberlo a ver qué opinan los demás, pero no creo que sea tan complicado yo declararía a view_index como un flotante.

(enteros) Cuántos valores puede haber entre el número 1 y el número 3? Sólo un número, el 2.

(flotantes) ¿Pero cuántos números puede haber entre el número 1 y el 3? Miles y miles de millones, teóricamente sería infinito.

Así, al hacer Drag & Drop, mira el registro de arriba, mira el de abajo, y le asignas al view_index del registro insertado el promedio de ambos. Así no modificarás más registros que el que estás insertando.
__________________
"Di no al Internet Explorer" -Proverbio Chino-
  #5 (permalink)  
Antiguo 14/02/2006, 01:32
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Fabuloso... a mí no se me hubiera ocurrido tan rápido!

Si hay una forma estándar de hacerlo, de seguro es así

Ahora sólo me pregunto qué tan infinito es.. Es decir, entre más registros, menos preciso es el valor, hasta llegar un punto donde se agote la resolución de flotantes en PHP, y a partir de ese momento toma puros valores iguales (ceros)

No sé, quizá sean miles, muchas más que suficientes para mis necesidades...

Última edición por dreglad; 14/02/2006 a las 02:01
  #6 (permalink)  
Antiguo 14/02/2006, 01:57
Avatar de uamistad  
Fecha de Ingreso: diciembre-2004
Ubicación: Cd. de México
Mensajes: 1.395
Antigüedad: 19 años, 4 meses
Puntos: 1
No son tantos, es sorprendente, pero si divides 1 entre 2 y otra vez y otra vez, etc, etc. no son miles de veces posibles, son muy poquitas.

La web de mysql http://dev.mysql.com/doc/refman/5.1/...-overview.html indica que el tipo de dato FLOAT tiene 7 posiciones decimales, mientras que DOBLE tiene 15 posiciones.

Haciendo el cálculo con FLOAT:

1E-7 * 2EXP(X) = 1

X=[1 - LOG(1E-7)]/LOG(2)

nos lleva a que X = 26, así que sólo puedes insertar entre dos números enteros, 26 registros utilizando el método de promediar (muy malo).

Para un DOBLE puedes utilizar el doble (unos 52 registros), que siguen siendo pocos y tiene sentido, pues estamos desperdiciando muchos números en el camino.

Bueno, como ni lo creía, lo chequé con mi calcu y sí, al dividir uno entre 2, entre 2, entre 2 no te tardas más de 26 iteraciones en llegar a las siete posiciones decimales que te permiten los float.

Debe haber otro proceso que permita explotar mejor a los FLOAT, se me anda ocurriendo cómo pero igual y ya es demasiado. Pero permitiría explotar a los FLOAT y poder insertar al menos 5 millones de registros y para los DOBLE, 500 billones.

Ahora sí que me quedé sorprendido.
__________________
"Di no al Internet Explorer" -Proverbio Chino-
  #7 (permalink)  
Antiguo 14/02/2006, 02:12
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Sí, serían muy pocos registros.. No se me ocurre ninguna forma de hacerlo tocando sólo 3 registros (o al menos no tocando todos!!)

Qué tienes en mente ?
  #8 (permalink)  
Antiguo 14/02/2006, 02:22
Avatar de uamistad  
Fecha de Ingreso: diciembre-2004
Ubicación: Cd. de México
Mensajes: 1.395
Antigüedad: 19 años, 4 meses
Puntos: 1
Ohh, creo que era una burrada, porque no podrías asegurar que todas las posiciones van a ser ocupadas, así que en el peor de los casso, tendríamos 26 registros acomodados máximo y en el mejor, pues todos esos millones.

Todo lleva a que hay que modificar todos los registros, pero no tiene sentido.

Sabes, no sé si fue mi imaginación, pero creo qeu un día vi que hay una forma de hacer tipos de datos "personalizados", es decir, hacerlos arbitrariamente grandes, tanto como lo necesites, ¿lo habré imaginado o sería de otro lenguaje? jeje.

Está interesante este post, voy a estar pendiente. =)

No había visto que eras de Méx, DF
__________________
"Di no al Internet Explorer" -Proverbio Chino-
  #9 (permalink)  
Antiguo 14/02/2006, 07:10
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 3 meses
Puntos: 129
El tema que mencionan siempre lo he visto tratado de forma "visual" con alguna aplicación javascript/DHMTL para entregar al script de proceso (PHP en este caso) el conjunto de registro -> "view_index" que quedó despues de todos los movimientos. De esta forma el "ordenamiento" se hace o mejor dicho se carga el proceso al "lado del cliente".

Sería algo tipo:
http://javascript.internet.com/forms...ion-order.html

O algo más "vistoso" en DHTML
http://www.dhtmlgoodies.com/index.ht...=arrange_nodes

El caso es que con PHP sólo generamos nuestros registros y el javascript/DHTML que esas rutinas necesiten .. luego sólo procesamos lo que estas rutinas dejan "ordenado" con nuestro nuevo criterio.

Si lo hacemos en PHP directo .. debería ser un proceso recursivo. Lento lo más probable si hay gran cantidad de datos. (mi fuerte no es la "recursividad").

Un saludo,
  #10 (permalink)  
Antiguo 14/02/2006, 14:10
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Posible solución

Efectivamente, con DHTML o algunos recursos de "Web 2.0" podemos ordenar facilmente los registros del lado del cliente, el reto es cómo almacenar y respetar este orden en consultas sucesivas..

Se me ocurrió una solución, teniendo la información de orden separado de la base de datos, con un arreglo de números enteros

Así lo planteo:


Tenemos almacenado (a lo mejor serializado en un archivo, o en otra tabla de la base de datos, etc..) este arreglo que contiene la información de orden:



Código PHP:
//
// "lugar" => "id en la tabla"
$orden = array (
   
1  => 3
   2  
=> 1
   3  
=> 4
   4  
=> 2


Ahor, hacemos UNA SOLA consulta a la base de datos...
Código PHP:
$arrayRegistros consultar("SELECT * FORM Tabla ORDER BY id");
// Realmente el ORDER BY puede ser cualquiera, ya que la vamos
// a ordenar después 
Suponemos que la función consultar() nos devuelve un arreglo parecido a éste (modelo relacional, como MySQL):

Código PHP:
//
array (
   [
0] =>
         [
'id'] => 1
         
['nombre'] => ....
         ........   => ....
   [
1] =>
        [
'id']  => 2
        
['nombre'] => ....
         ........  => ....
   [
2]  .....
   ..........


Ahora, para ordenar este arreglo con nuestro propio criterio ($orden)...


Código PHP:
//
arrayOrdenado($arrayRegistros$arrayOrden)
{
  
$arrayOrdenado = array();

  foreach (
$arrayOrden as $orden => $id)
  {
    foreach (
$arrayRegistros as $registro)
    {
      if (
$registro['id'] == $id)
       {
         
$arrayOrdenado[$orden] = $registro['id'];
         break;
       }
    }
  }
  return 
$arrayOrdenado;


Entonces, los pasos generales para hacer la consulta serían:

Código PHP:
//
$orden    obtener_array_orden();
$consulta obtener_datos_de_bd();
$resiltado arrayOrdenado($resultado$orden);

//Y listo, el arreglo $resultado tiene los datos ya ordenados 
Efectivamente Cluster, esta es una función bastante recursiva (doble ciclo anidado), sin embargo sólo se manipulan un par de "arrays" en la memoria, y no decenas o cientos de consultas a la base de datos.

El mayor inconveniente de este "método", es que dicho arreglo de $orden, tiene que ser actualizado cada vez que hacemos un INSERT o un DELETE, para mantenerlos "sincronizados"...

No sé, qué opinan? No será demasiado desmadre y haya una solución más simple?
  #11 (permalink)  
Antiguo 14/02/2006, 14:15
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 3 meses
Puntos: 129
Cita:
Efectivamente, con DHTML o algunos recursos de "Web 2.0" podemos ordenar facilmente los registros del lado del cliente, el reto es cómo almacenar y respetar este orden en consultas sucesivas..
Las rutinas DHTML y demás sólo te van a entregar como comenté el par "id registro" -> "nuevo n° de orden de visualización" .. Sólo tienes que hacer un "UPDATE" a tu campo "view_index" con ese nuevo dato . .Eso sí .. se mete en la consulta SQL a todo registro que contenga esa tabla.

Un saludo,
  #12 (permalink)  
Antiguo 14/02/2006, 14:25
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 3 meses
Puntos: 129
Cita:
Se me ocurrió una solución, teniendo la información de orden separado de la base de datos, con un arreglo de números enteros
Pero .. ¿con esta solución igualmente debo generar el array con el par id registro -> n° de orden por otros médios? Es decir .. tener mi rutina DHTML, u otros médios para que pueda darle orden de forma "visual" (o bajo algún interface) por un "humano".

Es decir .. ¿lo que me ayuda la función recursiva es a re-generar mi indice de "ordenamiento" cada vez que ingrese un nuevo registro (sin definición de orden especifica => que quede el último) o por si se borran registros?

Si en tu campo de tu registro .. añades un campo extra para definir su "orden" y presentas esos registros haciendo tu consulta SQL por ese criterio de ordenamiento .. creo que con esto ya sobraría para la presentación de esos datos .. (esto tal vez es obvio pero no está de más aclararlo).

Un saludo,
  #13 (permalink)  
Antiguo 14/02/2006, 14:36
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Claro, lo que dices es totalmente cierto...

Los datos los obtendría de otra interfaz DHTML por un humano, justo como dices.

Pero qué tal si son miles de registros y el orden es cambiado constantemente? No sería mucha sobrecarga al servidor de bases de datos? No sería mejor tener separado la información de orden que los datos en si ?
  #14 (permalink)  
Antiguo 14/02/2006, 14:50
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 3 meses
Puntos: 129
Cita:
Iniciado por dreglad
Claro, lo que dices es totalmente cierto...

Los datos los obtendría de otra interfaz DHTML por un humano, justo como dices.

Pero qué tal si son miles de registros y el orden es cambiado constantemente? No sería mucha sobrecarga al servidor de bases de datos? No sería mejor tener separado la información de orden que los datos en si ?
mm Yo creo que no .. En mis aplicaciones uso mucho "flag's" .. ya sean que definen un estado (y por el ordeno y hago muchas operaciones con el).

De hecho si son "miles" de registros como dices, ... ordenar ese array o trabajarlo en sí por PHP no será tan óptimo con un "order BY" de una sentencia SQL ejecutada por un motor de BBDD optimizado para trabajar con sus própios datos. Así mismo con "Miles" de registros .. cualquier rutina DHTML se le atragantará para manajarlo por un navegador.
-------------

Otra propuesta de un caso típico:

Un foro, como este .. tiene miles de mensajes pero hay unos pocos que quedan marcados como "importantes" y estos tienen su "orden". En ese caso lo que he visto que hacen es colocar el n° de orden en ese supuesto campo extra "orden" y el resto queda como "0" .. Así el movimiento de ordenamiento se hace sobre unos pocos registros .. nunca sobre todos.

Supongo que habrá mejores técnicas, sistemas de "foros" como estos son buena fuente para ver como tratan esos temas.

Un saludo,
  #15 (permalink)  
Antiguo 14/02/2006, 22:54
Avatar de uamistad  
Fecha de Ingreso: diciembre-2004
Ubicación: Cd. de México
Mensajes: 1.395
Antigüedad: 19 años, 4 meses
Puntos: 1
Cita:
No sería mucha sobrecarga al servidor de bases de datos? No sería mejor tener separado la información de orden que los datos en si ?
Se hace que por la aplicación, no importa si es recursivo, si se carga todo en memoria, si se maneja del lado del cliente o del servidor, pues quizá por lo que menciona el autor del problem es algo sencillo:

|------------------------------|
|--id --Nombre--Apellido---|
|------------------------------|
|--1------Juan-------Pérez--|
|--2------Perdo-----Gómez-|
|--3------Raúl------López---|
|------------------------------|


Malo sería, como mencionan, que quisieran trabajar con un arreglo muy grande, entonces no sería óptimo. Cuando es demasiado grande sí conviene pensar en lo óptimo, pero si es algo pequeño, casi da igual si es o no es óptimo, de hecho muchas veces lo 'óptimo' podría caer en que sea más dificil de mantener que la solución más simple.

Por ejm, sé que a muchos programadores (me incluyo), a veces nos cuesta un poquito pensar los algoritmos en términos de recursividad.
__________________
"Di no al Internet Explorer" -Proverbio Chino-
  #16 (permalink)  
Antiguo 15/02/2006, 00:02
dreglad
Invitado
 
Mensajes: n/a
Puntos:
Muchas gracias a los dos por sus comentarios.

De hecho, más que necesidad, se convirtió en curiosidad de mi parte conocer el método más eficaz, ya que en realidad, no son más de 50 registros en cada tabla que pretendo "ordenar"..

En cuanto implemente esto, les cuento cómo lo hice finalmente, y los resultados.

Saludos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:44.