2011-03-31 22 views
5

Tengo un requisito de proporcionar un partido sugerido entre los datos en dos tablas de bases de datos. El requisito básico es; - Se debe sugerir una "coincidencia" para el mayor número de palabras coincidentes (independientemente del orden) entre las dos columnas en cuestión.palabra coincidente en SQL Server

Por ejemplo, dados los datos;

Table A       Table B 
1,'What other text in here'  5,'Other text in here' 
2,'What am I doing here'   6,'I am doing what here' 
3,'I need to find another job' 7,'Purple unicorns' 
4,'Other text in here'   8,'What are you doing in here' 

Ideally, my desired matches would look as follows; 
1 -> 8 (3 words matched) 
2 -> 6 (5 words matched) 
3 -> Nothing 
4 -> 5 (4 words matched) 

que he encontrado word count functions que parecen prometedores, pero no puedo pensar en cómo usarlo en una sentencia SQL, que me dará mi pareja deseada. Además, la función vinculada no es exactamente lo que necesito, ya que utiliza charindex, que creo que busca una palabra dentro de una palabra (es decir, 'in' coincidirá con 'bin').

¿Puede alguien ayudarme con esto ??

Gracias.

+0

3 partidos 6. Ambos tienen la palabra "yo". Y 1 coincide con 5 mejores que 8. Comparten 4 palabras en común. –

+0

Tienes razón, pero olvidé mencionar que no debería haber duplicados en los partidos. Una vez que se coincide una fila determinada, no se puede hacer coincidir nuevamente. Tiene razón acerca de 5 coincidencia 8 también, pero como acabo de comentar su respuesta, idealmente debería tener en cuenta el porcentaje de palabras generales que coinciden también. –

Respuesta

5

He usado sys.dm_fts_parser siguiente para dividir las oraciones en palabras. Hay plenty of TSQL split functions around si no está en SQL Server 2008 o encuentra que esto no es adecuado por algún motivo.

El requisito de que cada A.id solo se pueda emparejar con un B.id que no se haya utilizado anteriormente y viceversa no es una solución que se pueda considerar eficiente.

;WITH A(Id, sentence) As 
(
    SELECT 1,'What other text in here' UNION ALL 
    SELECT 2,'What am I doing here'  UNION ALL 
    SELECT 3,'I need to find another job' UNION ALL 
    SELECT 4,'Other text in here'   
), 
B(Id, sentence) As 
(
SELECT 5,'Other text in here'   UNION ALL 
SELECT 6,'I am doing what here'  UNION ALL 
SELECT 7,'Purple unicorns'    UNION ALL 
SELECT 8,'What are you doing in here' 
), A_Split 
    AS (SELECT Id AS A_Id, 
       display_term, 
       COUNT(*) OVER (PARTITION BY Id) AS A_Cnt 
     FROM A 
       CROSS APPLY 
        sys.dm_fts_parser('"' + REPLACE(sentence, '"', '""')+'"',1033, 0,0)), 

    B_Split 
    AS (SELECT Id AS B_Id, 
       display_term, 
       COUNT(*) OVER (PARTITION BY Id) AS B_Cnt 
     FROM B 
       CROSS APPLY 
        sys.dm_fts_parser('"' + REPLACE(sentence, '"', '""')+'"',1033, 0,0)), 
    Joined 
    As (SELECT A_Id, 
       B_Id, 
       B_Cnt, 
       Cnt = COUNT(*), 
       CAST(COUNT(*) as FLOAT)/B_Cnt AS PctMatchBToA, 
       CAST(COUNT(*) as FLOAT)/A_Cnt AS PctMatchAToB 
     from A_Split A 
       JOIN B_Split B 
        ON A.display_term = B.display_term 
     GROUP BY A_Id, 
        B_Id, 
        B_Cnt, 
        A_Cnt) 
SELECT IDENTITY(int, 1, 1) as id, * 
INTO #IntermediateResults 
FROM Joined 
ORDER BY PctMatchBToA DESC, 
      PctMatchAToB DESC 

DECLARE @A_Id INT, 
     @B_Id INT, 
     @Cnt INT 

DECLARE @Results TABLE (
    A_Id INT, 
    B_Id INT, 
    Cnt INT) 

SELECT TOP(1) @A_Id = A_Id, 
       @B_Id = B_Id, 
       @Cnt = Cnt 
FROM #IntermediateResults 
ORDER BY id 

WHILE (@@ROWCOUNT > 0) 
    BEGIN 

     INSERT INTO @Results 
     SELECT @A_Id, 
      @B_Id, 
      @Cnt 

     DELETE FROM #IntermediateResults 
     WHERE A_Id = @A_Id 
       OR B_Id = @B_Id 

     SELECT TOP(1) @A_Id = A_Id, 
        @B_Id = B_Id, 
        @Cnt = Cnt 
     FROM #IntermediateResults 
     ORDER BY id 
    END 

DROP TABLE #IntermediateResults 

SELECT * 
FROM @Results 
ORDER BY A_Id 

devoluciones

A_Id  B_Id  Cnt 
----------- ----------- ----------- 
1   8   3 
2   6   5 
4   5   4 
+0

¡Guau! Pensé que sabía una cosa o dos sobre SQL, pero acaba de señalar que hay muchas cosas que no sé :) Esto es realmente útil. Una cosa que olvidé mencionar es que no debería haber duplicados en los partidos. En realidad, el partido con el mayor porcentaje de palabras coincidentes debe tener prioridad. Esta es la razón por la cual en mi ejemplo, tenía 4 coincidencias con 5 ya que el texto es igual (100% de coincidencia), y por lo tanto, deja 1 para que coincida con 8 ya que es la siguiente mejor coincidencia. Aunque me gusta mucho tu respuesta. Es una gran comida para el pensamiento. +1 para ti ... si tuviera alguna reputación. –

+0

@Mr Moose: ¿No es así? :) @Martin: aunque desde entonces se ha afirmado que una fila solo puede coincidir una vez, sigo pensando que tu solución es útil. E incluso si no vas a volver a trabajar, es una buena idea para empezar. –

+0

@Andriy - Gracias. Podría volver a trabajarlo. Su bastante fácil de hacer 'ROW_NUMBER() OVER (POR PARTICIÓN A_ID ...' para obtener la parte superior del 1 por A. Y 'ROW_NUMBER() OVER (POR PARTICIÓN B_Id ...' para obtener la parte superior del 1 por B pero su escape en el momento de una buena manera de combinar los dos. –