2010-07-09 16 views
6

que tienen la siguiente tabla de base de datos con información sobre las personas, las enfermedades y las drogas:¿Cómo traduzco una declaración booleana simple a SQL?

PERSON_T    DISEASE_T    DRUG_T 
=========    ==========    ======== 
PERSON_ID    DISEASE_ID    DRUG_ID 
GENDER    PERSON_ID    PERSON_ID 
NAME     DISEASE_START_DATE  DRUG_START_DATE 
         DISEASE_END_DATE  DRUG_END_DATE 

A partir de estas tablas, corro algunas estadísticas acerca de qué individuos han tomado medicamentos que y tenían qué enfermedades. De esto puedo deducir qué patrones son interesantes para profundizar en el . Por ejemplo, a continuación es un ejemplo simplificado del patrón booleano que podría encontrar para la enfermedad 52:

((Drug 234 = false AND Drug 474 = true AND Drug 26 = false) OR 
    (Drug 395 = false AND Drug 791 = false AND Drug 371 = true)) 

Editar: He aquí otro ejemplo:

((Drug 234 = true AND Drug 474 = true AND Drug 26 = false) OR 
     (Drug 395 = false AND Drug 791 = false AND Drug 371 = true)) 

Ahora quiero convertir este patrón en una consulta SQL y encuentre a todas las personas que coinciden con este patrón.
Por ejemplo, quiero encontrar todas las personas en PERSON_T que tuvieron la enfermedad y ((que no tomaron el medicamento 234 y 26 antes de presentar síntomas, pero sí tomaron el medicamento 474 antes de presentar los síntomas) o (que tomaron el medicamento 371 antes de presentar síntomas, pero no el medicamento 791 y 395 antes de presentar síntomas))

¿Cómo podría volver a traducir este patrón en la consulta original?

Aquí es mi primer intento, pero se queda bloqueado en el primer plazo:

SELECT * FROM PERSON_T, DRUG_T, DISEASE_T 
    WHERE DISEASE_ID = 52 AND 
    PERSON_T.PERSON_ID = DISEASE_T.PERSON_ID AND 
    PERSON_T.PERSON_ID = DRUG_T.PERSON_ID AND 
    (DRUG_T.DRUG_ID=234 AND (DRUG_T.DRUG_START_DATE>DISEASE_T.END_DATE || ???) 

necesito que esto funcione en PostgreSQL, pero supongo que cualquier respuesta dada puede ser traducido de una base de datos dada a PostgreSQL.

Respuesta a los comentarios

  1. que fija el formato de base de datos tablas. Gracias.
  2. Necesito poder tomar una declaración booleana arbitraria y traducirla a SQL. Las declaraciones booleanas que en realidad estamos creando son mucho más extensas que el ejemplo que di. Cualquier tabla nueva que cree estará en una nueva base de datos y necesita tener el mismo esquema que las tablas originales. De esta forma para el usuario final, puede ejecutar su mismo código en las nuevas tablas y funciona igual que si se ejecutara en las tablas originales. Este es un requisito del cliente. Espero poder crear una vista que sea solo una consulta a las tablas originales. Si no podemos lograr que funcione, puedo crear una copia de las tablas y filtrar los datos mientras los copio en la nueva tabla. No estamos usando redes neuronales para hacer el análisis. Estamos utilizando nuestros propios algoritmos personalizados que escalan mucho mejor que las redes neuronales.
  3. La Disease_Start_Date es la fecha en la que la persona obtiene los síntomas, lo que es probable cuando comienzan a aparecer los síntomas. Disease_End_Date es cuando la persona se recupera, lo que es probable cuando los síntomas desaparecen.
  4. Drug_start_date es cuando la persona comienza a tomar los medicamentos. Drug_end_date es cuando la persona deja de tomar las drogas.

Editar he añadido mi propia respuesta. ¿Alguien puede encontrar una respuesta más simple?

+0

creo que sus defs de mesa tienen un formato incorrecto. ¿ENFERMEDAD_END_DATE debe estar en la tabla Person o en la tabla Disease? Creo que el espaciado se estropeó. Además, debido a eso, el DRUG_END_DATE aparece en la tabla de Enfermedades. – MJB

+0

¿Está interesado solo en esa combinación particular de drogas o habrá otras?Si hay más combinaciones en lugar de hacer de esto una consulta SQL estática, recomendaría hacer otras tablas que contengan los patrones de medicamentos que busca y generar una consulta SQL dinámica para hacer referencia a su tabla de restricciones. Esto escalará mejor con sus requerimientos futuros y le ahorrará tiempo de hacer diferentes consultas cada vez que cambie las "drogas de interés". Este tipo de análisis también me grita "red neuronal": encontrar un patrón no lineal entre los datos caóticos. –

+0

No se mencionan los síntomas en ninguna de las tablas. ¿Debemos suponer que las tablas solo registran datos antes de que se exhiban los síntomas? ¿Los síntomas se registran como enfermedades separadas en la tabla de enfermedades? ¿O los síntomas son irrelevantes para la consulta en cuestión? –

Respuesta

4

Para mí, el sencillo (si es feo) solución es usar existe y no EXISTS cláusulas:

SELECT * 
FROM PERSON_T INNER JOIN DISEASE_T 
    USING (PERSON_ID) 
WHERE DISEASE_ID = 52 
    AND EXISTS (SELECT 1 FROM DRUG_T 
       WHERE DRUG_T.PERSON_ID = PERSON_T.PERSON_ID 
       AND DRUG_ID = 474 
       AND [time condition]) 
    AND NOT EXISTS (SELECT 1 FROM DRUG_T 
       WHERE DRUG_T.PERSON_ID = PERSON_T.PERSON_ID 
       AND DRUG_ID = 234 
       AND [time condition]) 

... y así sucesivamente. En el ejemplo, estamos solicitando personas que hayan tomado el medicamento 474 pero no 234. Obviamente, puede agrupar las cláusulas con AND y OR según lo que necesite.

Aparte: encuentro que todas las tapas son difíciles de leer. Usualmente uso mayúsculas para palabras clave SQL y minúsculas para nombres de tablas y columnas.

+0

No creí que esto funcionara al principio, pero parece dar la respuesta correcta. Gracias. –

0

Pardon ningún error, pero creo que algo como esto podría funcionar (en T-SQL):

SELECT col1, col2, col3...
FROM PERSON_T AS P, DRUG_T AS DR, DISEASE_T AS DI
WHERE disease_id = 52
AND P.person_id = DI.person_id
AND P.person_id = DR.person_id
AND drug_id NOT IN(234, 26)
AND drug_id = 474
AND disease_start_date < drug_start_date
UNION
SELECT col1, col2, col3...
FROM PERSON_T AS P, DRUG_T AS DR, DISEASE_T AS DI
WHERE disease_id = 52
AND P.person_id = DI.person_id
AND P.person_id = DR.person_id
AND drug_id NOT IN(791, 395)
AND drug_id = 371
AND disease_start_date < drug_start_date

Ahora no tiene que ser hecho con una UNION pero para readibility pensé que esto era el más fácil dadas tus condiciones Tal vez esto te lleve en la dirección correcta.

+0

Esto no manejará mi segundo patrón que acabo de agregar. Mis patrones pueden especificar que una persona haya tomado el medicamento 234 y 474 antes de contraer la enfermedad, pero no el medicamento 26. Esta consulta da como resultado cero en este caso. –

0
SELECT per.person_id, per.name, per.gender 
FROM person_t per 
INNER JOIN disease_t dis 
USING (person_id) 
INNER JOIN drug_t drug 
USING (person_id) 
WHERE dis.disease_id = 52 AND drug.drug_start_date < dis.disease_start_date AND ((drug.drug_id IN (234, 474) AND drug.drug_id NOT IN (26)) OR (drug.drug_id IN (371) AND drug.drug_id NOT IN (395, 791))); 

Esto hará lo que está pidiendo. Las declaraciones de IN al final son bastante auto explicativas.

+0

Esto no manejará mi segundo patrón que acabo de agregar. Mis patrones pueden especificar que una persona haya tomado el medicamento 234 y 474 antes de contraer la enfermedad, pero no el medicamento 26. Esta consulta da como resultado cero en este caso. –

+0

Simplemente tuve que mover el 234 a la otra cláusula IN - simplemente ponerlos al revés - funciona ahora. La primera IN es las drogas que quiere ver antes de los síntomas, 2nd IN son las drogas que quiere ver después de que los síntomas comenzaron. La tercera y la cuarta IN son su próximo patrón: el mismo formato de entrada. –

+0

error tipográfico en el 2 ° y 4 ° INs son los medicamentos que no desea ver antes de que comenzaran los síntomas. –

0

Ninguna de las respuestas dadas parece funcionar. De nuevo, aquí está el patrón que quiero implementar: ((Droga 234 = verdadera Y Droga 474 = verdadera Y Droga 26 = falsa) O (Droga 395 = falsa Y Droga 791 = falsa Y Droga 371 = verdadera))

Creo que la siguiente consulta funcionará para (Drug 234 = true AND Drug 474 = true AND Drug 26 = false). Dado eso, es bastante fácil agregar la segunda mitad de la consulta.

SELECT p.person_id, p.gender FROM person_t as p 
    join drug_t as dr on dr.person_id = p.person_id 
    join disease_t as ds on ds.person_id=p.person_id 
    WHERE dr.drug_start_date < ds.disease_start_date AND disease_id = 52 AND dr.drug_id=234 
INTERSECT 
SELECT p.person_id, p.gender FROM person_t as p 
    join drug_t as dr on dr.person_id = p.person_id 
    join disease_t as ds on ds.person_id=p.person_id 
    WHERE dr.drug_start_date < ds.disease_start_date AND disease_id = 52 AND dr.drug_id=474 
INTERSECT (
SELECT p.person_id, p.gender 
    FROM person_t as p 
    JOIN disease_t as ds on ds.person_id = p.person_id 
    LEFT JOIN drug_t as dr ON dr.person_id = p.person_id AND dr.drug_id = 26 
    WHERE disease_id = 52 AND dr.person_id is null 
UNION 
SELECT p.person_id, p.gender 
    FROM person_t as p 
    JOIN disease_t as ds on ds.person_id = p.person_id 
    JOIN drug_t as dr ON dr.person_id = p.person_id AND dr.drug_id = 26 
    WHERE disease_id = 52 AND dr.drug_start_date > ds.disease_start_date) 

Esta consulta funciona, pero es bastante fea. También sospecho que será extremadamente lento una vez que tenga una base de datos de producción con 100 millones de personas. ¿Hay algo que pueda hacer para simplificar/optimizar esta consulta?

+0

¿Por qué disease_id cambió repentinamente a 26 a la mitad? Eso no estaba en la pregunta? –

+1

Eso fue error tipográfico. Está arreglado ahora. Gracias por atrapar eso. –

1

No tengo idea de cómo funcionará esto con las tablas grandes (me imagino que será bastante pésimo ya que las comparaciones de fechas suelen ser bastante caras), pero este es un método que debería funcionar. Es relativamente detallado, pero es muy fácil de modificar para diferentes casos booleanos.

Ejemplo 1:

SELECT dis.* 
FROM disease_t dis 
LEFT JOIN drug d1 ON d1.person_id = dis.person_id AND d1.drug_id = 234 
LEFT JOIN drug d2 ON d2.person_id = dis.person_id AND d2.drug_id = 474 
LEFT JOIN drug d3 ON d3.person_id = dis.person_id AND d3.drug_id = 26 
LEFT JOIN drug d4 ON d4.person_id = dis.person_id AND d4.drug_id = 395 
LEFT JOIN drug d5 ON d5.person_id = dis.person_id AND d5.drug_id = 791 
LEFT JOIN drug d6 ON d6.person_id = dis.person_id AND d6.drug_id = 371 
WHERE dis.disease_id = 52 
AND (((d1.person_id IS NULL OR dis.startdate < d1.startdate) AND 
     (d2.person_id IS NOT NULL AND d2.startdate < dis.startdate) AND 
     (d3.person_id IS NULL OR dis.startdate < d3.startdate)) 
    OR 
    ((d4.person_id IS NULL OR dis.startdate < d4.startdate) AND 
     (d5.person_id IS NULL OR dis.startdate < d5.startdate) AND 
     (d6.person_id IS NOT NULL AND d6.startdate < dis.startdate))) 

Ejemplo 2:

SELECT dis.* 
FROM disease_t dis 
LEFT JOIN drug d1 ON d1.person_id = dis.person_id AND d1.drug_id = 234 
LEFT JOIN drug d2 ON d2.person_id = dis.person_id AND d2.drug_id = 474 
LEFT JOIN drug d3 ON d3.person_id = dis.person_id AND d3.drug_id = 26 
LEFT JOIN drug d4 ON d4.person_id = dis.person_id AND d4.drug_id = 395 
LEFT JOIN drug d5 ON d5.person_id = dis.person_id AND d5.drug_id = 791 
LEFT JOIN drug d6 ON d6.person_id = dis.person_id AND d6.drug_id = 371 
WHERE dis.disease_id = 52 
AND (((d1.person_id IS NOT NULL AND d1.startdate < dis.startdate) AND 
     (d2.person_id IS NOT NULL AND d2.startdate < dis.startdate) AND 
     (d3.person_id IS NULL OR dis.startdate < d3.startdate)) 
    or 
    ((d4.person_id IS NULL OR dis.startdate < d4.startdate) AND 
     (d5.person_id IS NULL OR dis.startdate < d5.startdate) AND 
     (d6.person_id IS NOT NULL AND d6.startdate < dis.startdate))) 
+0

Esto parece funcionar. Gracias. –

1

Aquí es una consulta que maneja ((Drug 234 = true AND Drug 474 = true AND Drug 26 = false) OR (Drug 395 = false AND Drug 791 = false AND Drug 371 = true)), como informados.

/* 
-- AS DEFINED BY JOINS 
-- All "person_id"'s match 
-- Drug 1 is not Drug 2 
-- Drug 1 is not Drug 3 
-- Drug 2 is not Drug 3 
-- All Drugs are optional as far as the SELECT statement is concerned (left join) 
    -- Drug IDs will be defined in the WHERE clause 
-- All Diseases for "person_id" 

-- AS DEFINED IN WHERE STATEMENT 
-- Disease IS 52 
-- AND ONE OF THE FOLLOWING: 
-- 1) Disease started AFTER Drug 1 
--  Disease started AFTER Drug 2 
--  Drug 1 IS 234 
--  Drug 2 IS 474 
--  Drug 3 IS NOT 26 (AND NOT 234 or 474, as defined in JOINs) 
-- 2) Disease started AFTER Drug 3 
--  Drug 1 IS NOT 395 
--  Drug 2 IS NOT 791 
--  Drug 3 IS 371 
*/ 

SELECT p.person_id, p.gender FROM person_t as p 
LEFT JOIN drug_t AS dr1 ON (p.person_id = dr1.person_id) 
LEFT JOIN drug_t AS dr2 ON (p.person_id = dr2.person_id AND dr1.drug_id != dr2.drug_id) 
LEFT JOIN drug_t AS dr3 ON (p.person_id = dr3.person_id AND dr1.drug_id != dr3.drug_id AND dr2.drug_id != dr3.drug_id) 
JOIN  disease_t AS ds ON (p.person_id = ds.person_id) 
WHERE ds.disease_id = 52 
AND ( ( (dr1.drug_start_date < ds.disease_start_date AND dr2.drug_start_date < ds.disease_start_date) 
     AND (dr1.drug_id = 234 AND dr2.drug_id = 474 AND dr3.drug_id != 26) 
     ) 
    OR 
     ( (dr3.drug_start_date < ds.disease_start_date) 
     AND (dr1.drug_id != 395 AND dr2.drug_id != 791 AND dr3.drug_id = 371) 
     ) 
    ) 
0

no tengo datos de prueba reales a mano para probar esto, pero creo que se podría hacer algo como:

SELECT * 
FROM DISEASE_T D 
INNER JOIN DRUG_T DR ON D.PERSON_ID = DR.PERSON_ID AND D.DRUG_ID=52 
INNER JOIN PERSON_T P ON P.PERSON_ID = D.PERSON_ID 
GROUP BY PERSON_ID 
HAVING SUM(
    CASE WHEN DRUG_ID=234 AND DRUG_START_DATE<DISEASE_START_DATE THEN -1 
    WHEN DRUG_ID=474 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 
    WHEN DRUG_ID=26 AND DRUG_START_DATE<DISEASE_START_DATE THEN -1 
    ELSE 0 END) = 1 
    OR 
    SUM(
    CASE WHEN DRUG_ID=395 AND DRUG_START_DATE<DISEASE_START_DATE THEN -1 
    WHEN DRUG_ID=791 AND DRUG_START_DATE<DISEASE_START_DATE THEN -1 
    WHEN DRUG_ID=371 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 
    ELSE 0 END) = 1 

El caso que conozco fallará no es si usted tiene múltiples registros para la misma persona y la misma droga/enfermedad en las tablas de medicamentos/enfermedades. Si ese es el caso, también se puede cambiar la cláusula HAVING para parecerse más a:

(SUM(CASE WHEN DRUG_ID=234 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 ELSE 0 END) = 0 
AND SUM(CASE WHEN DRUG_ID=474 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 ELSE 0 END) > 0 
AND SUM(CASE WHEN DRUG_ID=26 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 ELSE 0 END) = 0) 
OR 
(SUM(CASE WHEN DRUG_ID=395 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 ELSE 0 END) = 0 
AND SUM(CASE WHEN DRUG_ID=791 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 ELSE 0 END) = 0 
AND SUM(CASE WHEN DRUG_ID=371 AND DRUG_START_DATE<DISEASE_START_DATE THEN 1 ELSE 0 END) > 0) 
+0

Una persona puede tomar el mismo medicamento más de una vez y habrá una fila por cada vez que tomaron el medicamento. Creo que lo mismo es cierto para las enfermedades. –

0

que probablemente abordar este problema desde una dirección similar a este. Es bastante flexible.

DRUG_DISEASE_CORRELATION_QUERY 
=============================== 
DRUG_DISEASE_CORRELATION_QUERY_ID 
DISEASE_ID 
DESCRIPTION 

(1, 52, 'What this query does.') 
(2, 52, 'Add some more results.') 

DRUG_DISEASE_CORRELATION_QUERY_INCLUDE_DRUG 
=========================================== 
DRUG_DISEASE_CORRELATION_QUERY_ID 
DRUG_ID 

(1, 234) 
(1, 474) 
(2, 371) 

DRUG_DISEASE_CORRELATION_QUERY_EXCLUDE_DRUG 
=========================================== 
DRUG_DISEASE_CORRELATION_QUERY_ID 
DRUG_ID 

(1, 26) 
(2, 395) 
(2, 791) 



CREATE VIEW DRUG_DISEASE_CORRELATION 
AS 
SELECT 
    p.*, 
    q.DRUG_DISEASE_CORRELATION_QUERY_ID 
FROM 
    DRUG_DISEASE_CORRELATION_QUERY q 
    INNER JOIN DISEASE_T ds on ds.DISEASE_ID = q.DISEASE_ID 
    INNER JOIN PERSON_T p ON p.PERSON_ID = ds.PERSON_ID 
    WHERE 
    AND EXISTS (SELECT * FROM DRUG_T dr WHERE dr.PERSON_ID = p.PERSON_ID AND dr.DRUG_ID IN 
     (SELECT qid.DRUG_ID FROM DRUG_DISEASE_CORRELATION_QUERY_INCLUDE_DRUG qid WHERE 
     qid.DRUG_DISEASE_CORRELATION_QUERY_ID = q.DRUG_DISEASE_CORRELATION_QUERY_ID) 
     AND DRUG_START_DATE < ds.DISEASE_START_DATE) 
    AND NOT EXISTS (SELECT * FROM DRUG_T dr WHERE dr.PERSON_ID = p.PERSON_ID AND dr.DRUG_ID IN 
     (SELECT qed.DRUG_ID FROM DRUG_DISEASE_CORRELATION_QUERY_EXCLUDE_DRUG qed WHERE 
     qed.DRUG_DISEASE_CORRELATION_QUERY_ID = q.DRUG_DISEASE_CORRELATION_QUERY_ID) 
     AND DRUG_START_DATE < ds.DISEASE_START_DATE) 
GO 


SELECT * FROM DRUG_DISEASE_CORRELATION WHERE DRUG_DISEASE_CORRELATION_QUERY_ID = 1 
UNION 
SELECT * FROM DRUG_DISEASE_CORRELATION WHERE DRUG_DISEASE_CORRELATION_QUERY_ID = 2 
0

Si lo tengo, que desea:

  • Seleccione esas personas
  • que han sido infectadas con un (1) enfermedad específica
  • que han sido tratados con una sola o medicamentos más especificados
  • Y que NO han sido tratados con uno o más otros medicamentos especificados

Esto podría simplificarse al convertir sus "requisitos de medicamentos" en una tabla temporal de alguna forma. Esto permitiría el uso de cualquier cantidad de drogas "buenas" y "malas" para consultar. Lo que tengo a continuación podría implementarse como un procedimiento almacenado, pero si eso no es una opción, hay varias opciones intrincadas disponibles.

El desglose de los pasos:

Primera, he aquí cómo se seleccionan los pacientes deseados. Vamos a utilizar esto como una sub consulta más adelante:

SELECT [PersonData] 
from DISEASE_T di 
    inner join PERSON_T pe 
    on pe.Person_Id = di.Person_Id 
where di.Disease_Id = [TargetDisease] 
    and [TimeConstraints] 

Segunda, para cada conjunto de medicamentos "objetivo" que ha AND juntos, crear una tabla temporal como tal (esto es la sintaxis SQL Server, PostgreSQL debe tener algo similar):

CREATE TABLE #DrugSet 
(
    Drug_Id [KeyDataType] 
    ,Include int not null 
) 

poblarlo con una fila para cada medicamento que está considerando:

  • Drug_Id = el medicamento que está comprobando
  • Incluir = 1 si la persona es haber tomado el medicamento, y 0 si son no haber tomado

y calcular dos valores:

@GoodDrugs, el número de medicamentos que desea que el paciente ha tomado
@BadDrugs, el número de medicamentos que usted quiere que el paciente no ha tomado

Ahora, puntada todo lo anterior juntos en la siguiente consulta:

SELECT pe.[PersonData] -- All the desired columns from PERSON_T and elsewhere 
from DRUG_T dr 
    -- Filter to only include "persons of interest" 
    inner join (select [PersonData] 
       from DISEASE_T di 
       inner join PERSON_T pe 
       on pe.Person_Id = di.Person_Id 
       where di.Disease_Id = [TargetDisease] 
       and [TimeConstraints]) pe 
    on pe.Person_Id = dr.Person_ID 
-- Join with any of the drugs we are intersted in 
left outer join #DrugSet ta 
    on ta.Drug_Id = dr.Drug_Id 
group by pe.[PersonData] -- Same as in the SELECT clause 
having sum(case ta.Include 
       when 1 then 1 -- This patient has been given a drug that we're looking to match 
       else 0   -- This patient has not been given this drug (catches NULLs, too) 
      end) = @GoodDrugs 
    and sum(case ta.Include 
       when 0 then 1 -- This patient has been given this drug that we're NOT looking to match 
       else 0   -- This patient has not been given this drug (catches NULLs, too) 
      end) = @BadDrugs 

He ignorado intencionalmente los criterios de tiempo ya que no entró en detalles sobre ellos, pero deberían ser bastante simples de agregar (aunque espero que no sean las últimas palabras famosas). Se pueden realizar más optimizaciones, pero mucho depende de los datos y otros criterios posibles.

Debería ejecutar esto una vez para cada "conjunto de medicamentos" (es decir, conjuntos de drogas FIDELES o VERDADERAS y juntas), concatenando la lista con cada pase. Probablemente pueda expandir #DrugSet para tener en cuenta cada conjunto de medicamentos que esté revisando, pero no estoy dispuesto a probar el código sin algunos datos serios para probarlo.

*/

+0

Desestime las columnas de fecha y asumo que hay claves primarias intuitivas presentes. Si este no es el caso, se solicitarán algunas cláusulas distintas y de grupo por. –

0

he tratado de romper el problema, y ​​seguir adelante como lógicamente como pude.

primer lugar las tres tablas (Person_t, Drugs_T, Disease_T) puede ser pensado como se muestra en la Figura 1.0:

una persona puede tener múltiples drogas y múltiple enfermedades. Cada medicamento y enfermedad tiene una fecha de inicio &.

por lo tanto yo haría primero desnormalizar las tres tablas en una tabla (Table_dn) así:

dnId | PersonId | DrugId | DiseaseId | DgSt | DgEn | DiSt | DiEn 
---- -------- ------ --------- ---- ---- ---- ---- 

Esta tabla desnormalizada puede ser una tabla temporal si es necesario, independientemente Table_dn ahora contiene toda la totalidad del Mundial conjunto de datos como se muestra en la figura 2.0 (denotado como G).

Según entiendo su descripción, puedo ver esencialmente un filtro de dos capas.

Filtro 1

Este filtro es simplemente un conjunto de fármacos booleano Combinaciones, como ya se ha indicado en la descripción de su pregunta. por ejemplo:

(drug a = 1 & drug b = 0 & etc) OR (..... 

Filtro 2

Este filtro es un poco más complicado que el primero, es criterios intervalo de fechas. La figura 3.0 muestra este rango de fechas en ROJO. El amarillo representa las fechas de registro que abarcan múltiples maneras:

  • antes del período ROJO
  • Después periodo ROJO
  • Entre período ROJO
  • que finalice antes del final del periodo ROJO
  • partir después del comienzo del período de ROJO

Ahora los períodos de fechas AMARILLOS podrían ser el período de medicamentos o el período de enfermedad O la combinación de ambos.

Este filtro debe aplicarse al conjunto de resultados obtenidos a partir de los primeros resultados.

Por supuesto, dependiendo de su pregunta exacta, es posible que los dos filtros tengan que ir al revés (por ejemplo, f2 primero y luego f1). pseudo código

SQL:

Select sub.* 
From  
     (select * 
     from  Table_dn 
     where  [Filter 1] 
    ) as sub 

where [Filter 2] 

alt text

Cuestiones relacionadas