2011-10-07 45 views
7

Tengo una pequeña base de datos que se usa para rastrear partes. por el bien de este ejemplo, la tabla es el siguiente:Relaciones bidireccionales en consultas SQL

Idpart (PK), int
PartNumber, varchar (50), único
Descripción, VARCHAR (255)

Tengo un requisito para definir que ciertas partes se clasifican como similares entre sí. Para ello he fijado una segunda tabla que tiene este aspecto:

Idpart, (PK), int
SecondPartID, (PK), int
ReasonForSimilarity, VARCHAR (255)

Luego se ha configurado una relación de muchos a muchos entre las dos tablas.

El problema viene cuando tengo que informar sobre las partes que se consideran similares porque la relación es bidireccional I.E. si parte XYZ123 es similar a ABC678 entonces ABC678 se considera que es similar a XYZ123. Entonces, si quisiera enumerar todas las partes que son similares a una parte dada, o bien debo asegurarme de que la relación esté configurada en ambas direcciones (lo cual es malo porque los datos están duplicados) o necesito tener 2 consultas que miren la tabla en ambas direcciones . Ninguna de estas soluciones me parece bien.

Entonces, ¿cómo se debe abordar este problema? ¿Se puede resolver esto solo con SQL o mi diseño debe cambiar para adaptarse a los requisitos del negocio?

Considere las siguientes partes XYZ123, ABC123, ABC234, ABC345, ABC456 & EFG456 que se han ingresado en la estructura existente ingresada anteriormente. Usted podría terminar con los datos que tiene este aspecto (omitiendo el campo de la razón, que es irrelevante en este punto):

Idpart, SecondPartID
XYZ123, ABC123
XYZ123, ABC234
XYZ123, ABC345
XYZ123, ABC456
EFG456, XYZ123

Mi usuario quiere saber "¿Qué partes son similares a XYZ123". Esto podría hacerse mediante una consulta de este modo:

SELECT SecondPartID 
FROM tblRelatedParts 
WHERE PartID = 'XYZ123' 

El problema con esto es sin embargo que no se le fuera parte EFG456 que se relaciona con XYZ123 a pesar de que las partes se han introducido al revés. Es posible que esto ocurra dependiendo de la parte con la que el usuario esté trabajando actualmente y la relación entre las partes será siempre sea bidireccional.

El problema que tengo con esto es que ahora necesito comprobar que cuando un usuario establece una relación entre dos partes, no existe ya en la otra dirección.

@Goran

me han hecho algunas pruebas iniciales usando su sugerencia y así es como tengo la intención de abordar el problema con su sugerencia.

Los datos mencionados anteriormente se introducen en la nueva tabla (Tenga en cuenta que he cambiado el Idpart al número de pieza para hacer el ejemplo más claro; la semántica de mi problema no han cambiado sin embargo)

se vería la tabla como esta:

RelationshipID, PartNumber
1, XYZ123
1, ABC123
2, XYZ123
2, ABC234
3, XYZ123
3, ABC345
4, XYZ123
4, ABC456
5, EFG456
5, XYZ123

puedo entonces recuperar una lista de partes similares utilizando una consulta como esta:

SELECT PartNumber 
FROM tblPartRelationships 
WHERE RelationshipID ANY (SELECT RelationshipID 
          FROM tblPartRelationships 
          WHERE PartNumber = 'XYZ123') 

voy a llevar a cabo más pruebas y si esto funciona me retroalimentación y aceptar la respuesta.

Respuesta

7

He resuelto este problema configurando una tabla de relaciones.

tabla

pieza:

Idpart (PK), int

PartNumber, VARCHAR (50), Unique

Descripción, VARCHAR (255)

PartRelationship tabla:

RelationshipId (FK), int

Idpart (FK), int

tabla de relación:

RelationshipId (PK), int partes

Ahora similares simplemente se añaden en la tabla de relaciones:

RelationshipId, PartId

1,1

1,2

Siempre que añada otra parte con relationshipId = 1 se considera similar a cualquier parte con relationshipId = 1.

posibles soluciones API para añadir relaciones:

  • Cree una nueva relación para cada lista de piezas similares. Deje que el cliente cargue, cambie y actualice la lista completa siempre que sea necesario.
  • Recuperar relación (es) para un objeto similar. Filtre la lista según algunos criterios para que solo quede uno o permita que el cliente elija entre las relaciones existentes. Cree y elimine el registro de PartRelationship según sea necesario.
  • Recuperar la lista de relaciones de la tabla de relaciones. Permita que el cliente especifique partes y relaciones. Crear y eliminar registros de PartRelationship según sea necesario.
+0

+1, aunque es posible que desee agregar una tabla adicional para el campo 'ReasonForSimilarity', que probablemente esté restringido a pares específicos (en lugar de aplicable a todas las partes de una relación). –

+0

@MarkBannister Buen punto. No estoy seguro de cuáles son todos los requisitos, pero esto debería hacer que OP apunte en la dirección correcta. Si hay alguna necesidad, actualizaré mi respuesta. @¿Benjamín? – Goran

+0

+ 1, esto parece una solución válida. Haré algunas pruebas y te dejaré saber cómo va esto. Solo una cosa con respecto a la relación Id; ¿Cómo se genera y mantiene esto? presumiblemente, tendré que asegurarme de que se usa la relación correcta al establecer un enlace entre las partes para garantizar que esto funcione. @MarkBannister Ya tengo una tabla separada para ReasonForSimilarity, pero la excluí porque no afecta lo que quiero. –

2

Agregar una restricción CHECK p. Ej.

CHECK (PartID < SecondPartID); 
0

Sé que esto es viejo, pero ¿por qué no hacer esta consulta con su esquema original? Menos tablas y filas

SELECT SecondPartID 
FROM tblRelatedParts 
WHERE PartID = 'XYZ123' 
UNION 
SELECT PartID 
FROM tblRelatedParts 
WHERE SecondPartID = 'XYZ123' 

estoy tratando con un problema similar y mirando a los dos enfoques y preguntándose por qué pensaba que el esquema con la tabla de relación era mejor. Parece que el problema original todavía existe en el sentido de que todavía necesita administrar las relaciones entre ellos desde ambas direcciones.

+1

Mi opción original tiene dos tablas mientras que la respuesta seleccionada solo tiene una. Acepto que todavía hay algunos problemas con la segunda opción (que aún tengo que resolver), pero la respuesta de Gorans fue la mejor en ese momento y fue un buen comienzo en la dirección correcta. –

0

¿Qué tal tener dos filas para cada similitud. Por ejemplo, si tiene objetos A, B similares que van a tener en su tabla de relación

A B 
B A 

Sé que va a duplicar los datos de relación, pero son números enteros de manera que no más de matar a su base de datos.En su lugar, tiene algunas ganancias:

  • no usará la unión. La unión está por encima de matar en cualquier dbms. Especialmente cuando tiene un pedido por grupo o por
  • puede implementar una relación más específica: a está en relación con b, pero b no está relacionado con a. Por ejemplo, John puede reemplazar a Dave, pero Dave no puede reemplazar a John.