Foros del Web » Programando para Internet » PHP »

Ayuda con tabla y busquedas

Estas en el tema de Ayuda con tabla y busquedas en el foro de PHP en Foros del Web. Bueno, ahora les voy a consultar como harian algo que en mi sitio ya esta funcionando, pero que ahora que estoy rediseñando y optimizando todo ...
  #1 (permalink)  
Antiguo 17/07/2003, 12:26
 
Fecha de Ingreso: junio-2002
Ubicación: Buenos Aires, Argentina
Mensajes: 876
Antigüedad: 21 años, 10 meses
Puntos: 0
Ayuda con tabla y busquedas

Bueno, ahora les voy a consultar como harian algo que en mi sitio ya esta funcionando, pero que ahora que estoy rediseñando y optimizando todo lo que pueda, quiero hacerlo mas eficiente.

Les resumo: en mi sitio se puede conocer gente. Las personas configuran lo que estan buscando de entre 4 opciones: Amistad, Relacion Estable, Sin Compromisos y Otro Tipo De Relacion.

El problema se me presenta a la hora de realizar busquedas. Tengan en cuenta que un usuario puede configurar todas las relaciones que quiera, por ejemplo Amistad y Sin Compromisos.

A la hora de buscar, los miembros seleccionan, entre otras cosas, la relacion que desean, por lo que se devolveran resultados que coincidan con por ejemplo Amistad y Sin Compromisos. Aclaro que la gente puede buscar por una de las relaciones o por todas ("Opcion Cualquiera").

Hasta ahora en mi tabla vengo guardando en un campo llamado relacion, datos como "Amistad, Relacion Estable", o "Amistad, Sin Compromisos", etc.

A la hora de buscar, como dentro de este campo puede haber varias relaciones separadas por comas, no me queda mas remedio que hacer

SELECT .... WHERE relacion LIKE '%Amistad%' OR relacion LIKE '%Sin Compromisos%'...

en el caso de que se busquen personas que a su vez quieran estas dos relaciones.

Yo quisiewra dejar de usar este LIKE porque estoy conciente de que demora mucho más que otras consultas, ya que mido los tiempos.
Y aca viene el problema, no se me ocurre que hacer.
Una solucion pienso que seria agregar tantos campos como relaciones, y de esta manera reemplazar el LIKE por un = , pero que pasa si en un futuro qiuero agregar relaciones, o cambiarle el nombre a alguna, por ejemplo Sin Compromisos llamarla Relaciones Esporadicas?

Yo quisiera usar una tabla aparte que contenga las relaciones como registros y con un id cada uno, y usar esos ids para relacionarlos con los miembros de alguna forma, pero caeria otra vez en lo de las comas, o sea, en vez de por ejemplo "Amistad, Relacion Estable" seria "1;2", y en definitiva es lo mismo.

Bueno, ese es el problema, me gustaria que me ayuden o comente que solucion implementarian.

Desde ya se los agradezco mucho.
  #2 (permalink)  
Antiguo 17/07/2003, 13:40
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Hola,

Podrias usar un campo como flag. Seria un campo numerico, solo tendrias que asignar una potencia de 2 a cada tipo de relacion, por ejemplo Amistad= 2^0 (2 a la 0) =1, Solo Sexo = 2^1 = 2, etc. Luego en ese campo flag almacenas la suma de los valores de los tipos de relaciones de ese registro (mas que suma, es un OR a nivel de bits de los valores). Asi, si solo tienes Amistad, el valor a almacenar seria 1, si es amistad y Solo Sexo, almacenarias 3 (1+2).

Al realizar la Busqueda, realizas la suma de lo que han elegido buscar. Luego en la consulta usas el operador a nivel de bits & para hacer el AND de los bits de ambos valores. El resultado del AND es cero si no hay ningun bit que coincida tener 1 en los dos operandos. La consulta seria algo asi:

SELECT * FROM donde_sea WHERE campo_flag & $valor_busqueda

Con esto te buscara todos aquellos que por lo menos cumplan un termino de busqueda. Si quieres buscar los que cumplan todos los terminos de busqueda:

SELECT * FROM donde_sea WHERE campo_flag & $valor_busqueda = $valor_busqueda

$valor_busqueda es la suma de las potencias de 2 de los tipos que quieres buscar.

El limite de tipos es el limite del tamaño del campo numerico del flag. Si usas un INT sin signo, creo que son valores de 0 a 4294967295, es decir, a 2^32 - 1, con lo que tienes para 32 tipos de relacion (de 2^0 a 2^31). Con esto tienes las 4294967296 combinaciones, creo que de sobra.

Espero haber sido de ayuda.

PD: ¿Se nota que he programado en ensamblador y C?
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #3 (permalink)  
Antiguo 17/07/2003, 14:19
 
Fecha de Ingreso: junio-2002
Ubicación: Buenos Aires, Argentina
Mensajes: 876
Antigüedad: 21 años, 10 meses
Puntos: 0
Muy buena tecnica!
Esta muy buena la idea, es posible que la use.

Ahora si uno quiere confeccionar una tabla entendible, resulta medio complicado hacer esto verdad?. El que mire la tabla no va a entender que quiere decir el valor "3" del campo relacion a menos que mire el codigo.

Yo queria hacer algo mas entendible, pero si no hay otra solucion voy a usar lo que me decis (creo que si hubiera otra solucion se te hubiera ocurrido no ? )

Muchas gracias, y soy todo oidos si se te llega a ocurrir algo mas visual en cuanto a diagramacion de las tablas.
  #4 (permalink)  
Antiguo 17/07/2003, 15:27
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Hombre, siempre tienes la opcion de crear una tabla intermedia para guardar las distintas relaciones de un registro. Es lo que se usa para cuando un registro se puede ralicionar con 0 o muchos registros de otra tabla. La estructura seria:

tabla: Registros (ID_registro, demas campos)
Tabla:Relaciones (ID_relacion, nombre de la relacion)
Tabla: Relaciones_registro (ID_registro, ID_relacion)

Si el registro 1 tiene las relaciones 1, 3 y 8 (amistad, solo sexo y sado), la tabla Relaciones_registro tendra estos 3 registros:

ID_registro -- ID_relacion
1 ------------------- 1
1 ------------------- 3
1 ------------------- 8

Luego para la busqueda, primero tienes que sacar la lista de ID_registros que tienen alguna de la relacion seleccionada. La consulta seria:

SELECT DISTINCT ID_registro FROM Relaciones_registros WHERE ID_relacion IN (lista de los ID_relacion seleccionados para la busqueda separados por comas)

Con esto obtienes el listado de los ID_registros que tiene alguna de los tipos de relacion a buscar. Luego haces esta otra consulta para sacar los datos completos:

SELECT * FROM Registro WHERE ID_registro IN (la lista de ID_registro que has obtenido de la consulta anterior separada por comas)

Si quieres podrias hacer las dos consultas en una:

SELECT DISTINCT Registro.* FROM Relaciones_registros LEFT JOIN Registro ON (ID_registro) WHERE ID_relacion IN (lista de los ID_relacion seleccionados para la busqueda separados por comas)

Ahora no recuerdo como se haria para el caso en que quieres los registros que tengan todos los tipos de relaciones especificadas en la busqueda, pero supongo que seria algo con GRUP BY, count() y HAVING.

Como ves, haciendolo mas "visual" aumentas el numero de tablas y complicas las consultas. Pero te doy la razon, se ve mas claro que con los flags (siempre que no tengas experiencia con ellos ).

Saludos.
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #5 (permalink)  
Antiguo 17/07/2003, 22:12
 
Fecha de Ingreso: junio-2002
Ubicación: Buenos Aires, Argentina
Mensajes: 876
Antigüedad: 21 años, 10 meses
Puntos: 0
Josemi, me parece a mi, o la primera solucion que me diste no me sirve?

Te explico por que me parece que no me sirve:
Si alguien hubiese configurado para si mismo sus preferencias por Amistad y por Sexo, ponele por ejemplo que el flag de tenga valor 3 (Amistad=1 y Sexo=2).
Ahora hay otra persona que busca gente para amistad, lo que daria 1. Por lo que los valores no coinciden, y sin embargo la primara persona sí buscaba amistad, ademas de sexo claro.

Se entiende, o estoy equivocado?
  #6 (permalink)  
Antiguo 17/07/2003, 23:15
Avatar de Manoloweb  
Fecha de Ingreso: enero-2002
Ubicación: Monterrey
Mensajes: 2.454
Antigüedad: 22 años, 2 meses
Puntos: 5
Estas equivocado...

Ese tipo de operadores y busquedas a nivel bits, pueden hacerte busquedas de coincidencias DENTRO del numero resultante, por decirlo de alguna manera.

debido a que las relaciones son así...

Amistad =1
Relacion Estable =2
Sin Compromisos =4
Otro Tipo =8

Entonces por lógica, no puede haber combinaciones repetidas, así que es facil saber cuales han sido las opciones elegidas...

9 = 8+1
13 = 1+4+8
3 = 1+2
12= 4+8

Y así para todas las combinaciones que se te ocurran...

Busca la documentación de los campos tipo SET de MySQL... han sido hechos EXACTAMENTE para eso, y te ahorran una de tiempo que no te imaginas, sobre todo en casos como el tuyo.
__________________
Manoloweb
  #7 (permalink)  
Antiguo 17/07/2003, 23:17
Avatar de Manoloweb  
Fecha de Ingreso: enero-2002
Ubicación: Monterrey
Mensajes: 2.454
Antigüedad: 22 años, 2 meses
Puntos: 5
Bueno, no encontré la liga a ese documento en la red, así que por si las dudas aqui te dejo una copia de esa parte del manual (en ingles):


The SET Type

A SET is a string object that can have zero or more values, each of which must be chosen from a list of allowed values specified when the table is created. SET column values that consist of multiple set members are specified with members separated by commas (,). A consequence of this is that SET member values cannot themselves contain commas.

For example, a column specified as SET("one", "two") NOT NULL can have any of these values:

""
"one"
"two"
"one,two"

A SET can have a maximum of 64 different members.

MySQL stores SET values numerically, with the low-order bit of the stored value corresponding to the first set member. If you retrieve a SET value in a numeric context, the value retrieved has bits set corresponding to the set members that make up the column value. For example, you can retrieve numeric values from a SET column like this:


mysql> SELECT set_col+0 FROM tbl_name;

If a number is stored into a SET column, the bits that are set in the binary representation of the number determine the set members in the column value. Suppose a column is specified as SET("a","b","c","d"). Then the members have the following bit values:


SET member Decimal value Binary value
a 1 0001
b 2 0010
c 4 0100
d 8 1000
If you assign a value of 9 to this column, that is 1001 in binary, so the first and fourth SET value members "a" and "d" are selected and the resulting value is "a,d".

For a value containing more than one SET element, it does not matter what order the elements are listed in when you insert the value. It also does not matter how many times a given element is listed in the value. When the value is retrieved later, each element in the value will appear once, with elements listed according to the order in which they were specified at table creation time. For example, if a column is specified as SET("a","b","c","d"), then "a,d", "d,a", and "d,a,a,d,d" will all appear as "a,d" when retrieved.

If you set a SET column to an unsupported value, the value will be ignored.

SET values are sorted numerically. NULL values sort before non-NULL SET values.

Normally, you perform a SELECT on a SET column using the LIKE operator or the FIND_IN_SET() function:


mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;

But the following will also work:


mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
mysql> SELECT * FROM tbl_name WHERE set_col & 1;

The first of these statements looks for an exact match. The second looks for values containing the first set member.

If you want to get all possible values for a SET column, you should use: SHOW COLUMNS FROM table_name LIKE set_column_name and parse the SET definition in the second column.
__________________
Manoloweb
  #8 (permalink)  
Antiguo 18/07/2003, 02:16
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Muy bien, Manoloweb, me has descubierto. Nunca he usado esta tecnica con base de datos, pero funciona bien en codigo (ensamblador, C, ...). Si lo hubiera usado en MySQL, sabria que existia ese tipo de datos. Es exactamente lo que yo hacia a mano. El link es al manual, http://www.mysql.com/doc/en/SET.html , donde tendria que haber mirado yo antes de complicarle la vida a zeus_bsas con mi explicacion.

Saludos.
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #9 (permalink)  
Antiguo 18/07/2003, 09:11
 
Fecha de Ingreso: junio-2002
Ubicación: Buenos Aires, Argentina
Mensajes: 876
Antigüedad: 21 años, 10 meses
Puntos: 0
Muchas gracias a los dos, ya antes de leer el documento (con mucho tiempo, ingles cero) imagino como viene la mano, me voy dando una idea. Lo que pasa es que yo pensaba que se comparaban como numeros comunes en la busqueda, pero ahora entiendo que no.
Me voy a poner al tanto sobre el SET de mysql y voy a usar esta tecnica.

Gracias de nuevo!
  #10 (permalink)  
Antiguo 08/10/2003, 01:40
 
Fecha de Ingreso: junio-2002
Ubicación: Buenos Aires, Argentina
Mensajes: 876
Antigüedad: 21 años, 10 meses
Puntos: 0
Otra vez estoy con este temita...
El tema que consulte antes ya lo tengo solucionado.
Tengo relaciones corta, larga, sin compromiso, otra de id 1, 2, 4 y 8 respectivamente.
Un miembro puede tener varias relaciones, como por ejemplo 3, que seria la 1 y la 2.
Para buscarlo, hago
select * from tbl_miembros where id_relacion & 3

Ahora bien, como corno hago el paso inverso???
Lo que necesito ahora es averiguar que relacio0nes son el numero 3 de un miembro, se entiende?
  #11 (permalink)  
Antiguo 08/10/2003, 02:48
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Hola,

Podrias hacerlo con PHP. Si tienes los tipos en un array asociativo cuyo indice es el codigo del tipo, podrias hacer algo asi:
Código PHP:
$tipos=array('1'=>'Amor','2'=>'Amistad','4'=>'Sexo','8'=>'Otro');
// en $tipo_bd tienes el campo de la base de datos
$tipo_bd=3;
// inicializamos la lista de tipos de este registro
$tipo=array();
// rellenamos $tipo con los tipos
foreach ($tipos as $codigo => $texto_tipo) {
  if (
1==($tipo_bd $codigo)) {
    
$tipo[]=$texto_tipo;
  }
}
// mostramos los tipos
foreach ($tipo as $texto) {
  echo 
$tipo.'<br>';

Todo se basa en los operadores de bit &, |, ... http://www.php.net/manual/en/languag...rs.bitwise.php

Saludos.
__________________
Josemi

Aprendiz de mucho, maestro de poco.
  #12 (permalink)  
Antiguo 08/10/2003, 11:52
 
Fecha de Ingreso: junio-2002
Ubicación: Buenos Aires, Argentina
Mensajes: 876
Antigüedad: 21 años, 10 meses
Puntos: 0
Cha gracia
Yo tengo los datos de las relaciones en una tabla. Me los tendria que bajar para usar lo que me decis?
  #13 (permalink)  
Antiguo 06/10/2004, 18:34
 
Fecha de Ingreso: junio-2004
Ubicación: Buenos Aires
Mensajes: 60
Antigüedad: 19 años, 10 meses
Puntos: 1
Alguien podria explicarme como usar esta tecnica pero de otra maner? Que tal si uno desea buscar registros que NO contengan una relacion especifica?

He probado con esto, pero no me funciona

SELECT * FROM tabla WHERE campo_set & ~relacion

O sea que buscamos los registros que en el campo SET tengan lo que sea, menos relacion.
  #14 (permalink)  
Antiguo 08/10/2004, 18:15
 
Fecha de Ingreso: junio-2004
Ubicación: Buenos Aires
Mensajes: 60
Antigüedad: 19 años, 10 meses
Puntos: 1
Nadie que sepa cómo?
  #15 (permalink)  
Antiguo 09/10/2004, 10:16
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 3 meses
Puntos: 129
boxin .. El problema es que esta técnica es más bien problema a resolver con SQL que con "PHP" ..

De estos mensajes hace ya como un año o más .. Hoy por hoy en forosdelweb.com se usa más los foros temáticos para cada cosa .. en tu caso "el foro de Base de datos".

Asì que te recomendaría preguntar en el foro de Base de datos como usar los campos de tipo "SET" con tu condición ..

Un saludo,
  #16 (permalink)  
Antiguo 11/10/2004, 04:47
 
Fecha de Ingreso: junio-2004
Ubicación: Buenos Aires
Mensajes: 60
Antigüedad: 19 años, 10 meses
Puntos: 1
Listo, solo era para dejar el link a la solucion por si alguien pasa por aca igual que yo:

http://www.forosdelweb.com/showthrea...613#post829613
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 05:45.