2010-07-09 10 views
6

Ho la seguente tabella del database con le informazioni su persone, malattie e farmaci:Come si traduce una semplice istruzione booleana in 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 

Da queste tabelle, corro alcune statistiche su cui gli individui hanno preso quali farmaci e aveva cui le malattie. Da questo posso capire quali modelli sono interessanti per da approfondire. Per esempio, di seguito è un esempio semplificato del modello booleano potrei trovare per la malattia 52:

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

Edit: Ecco un altro esempio:

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

Ora voglio convertire questo modello in una query sql e trovare tutte le persone che corrispondono a questo modello.
Ad esempio, voglio trovare tutte le persone in PERSON_T che hanno avuto la malattia e ((che non ha assunto farmaci 234 e 26 prima di manifestare sintomi, ma ha assunto il farmaco 474 prima di manifestare i sintomi) o (che ha assunto droga 371 prima di manifestare i sintomi, ma non i farmaci 791 e 395 prima di manifestare sintomi))

Come potrei fare per tradurre questo modello nella query originale?

Ecco il mio primo tentativo, ma mi si blocca sul primo termine:

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 || ???) 

Ho bisogno di questo per lavorare in PostgreSQL, ma suppongo che ogni dato risposta può essere tradotto da un determinato database per PostgreSQL.

risposta ai commenti

  1. ho fissato la formattazione di base di dati tavoli. Grazie.
  2. Devo essere in grado di prendere un'istruzione booleana arbitraria e tradurla in SQL. Le affermazioni booleane che stiamo effettivamente creando sono molto più lunghe dell'esempio che ho dato. Qualsiasi nuova tabella che creo sarà in un nuovo database e deve avere lo stesso schema delle tabelle originali. In questo modo per l'utente finale, possono eseguire lo stesso codice sulle nuove tabelle e funzionano allo stesso modo come se fosse eseguito sulle tabelle originali. Questo è un requisito da parte del cliente. Spero di poter creare una vista che è solo una query alle tabelle originali. Se non riusciamo a farlo funzionare, potrei creare una copia delle tabelle e filtrare i dati mentre sto copiandolo sulla nuova tabella. Non stiamo usando le reti neurali per fare l'analisi. Utilizziamo i nostri algoritmi personalizzati che si adattano molto meglio delle reti neurali.
  3. The Disease_Start_Date è la data in cui la persona riceve i diseaes che è probabile quando i sintomi iniziano a comparire. Disease_End_Date è quando la persona viene recuperata, il che è probabile quando i sintomi scompaiono.
  4. Drug_start_date è quando la persona inizia a prendere i farmaci. Drug_end_date è quando la persona smette di assumere i farmaci.

Edit ho aggiunto la mia risposta. Qualcuno può trovare una risposta più semplice?

+0

Penso che i tuoi defs tabella sono formattati sbagliato. DISEASE_END_DATE dovrebbe essere nella tabella Persona o nella tabella Malattia? Penso che la spaziatura sia incasinata. Inoltre, a causa di ciò, il DRUG_END_DATE viene visualizzato nella tabella Disease. – MJB

+0

Sei interessato solo a quella particolare combinazione di farmaci o ce ne saranno altri?Se ci sono più combinazioni invece di rendere questa una query SQL statica, consiglierei di creare altre 1-2 tabelle contenenti i modelli di farmaci che stai cercando e di generare una query SQL dinamica per fare riferimento alla tabella dei vincoli. Questo scalerà meglio con le tue esigenze future e ti farà risparmiare tempo per fare domande diverse ogni volta che cambierai le "droghe di interesse". Questo tipo di analisi urla anche "rete neurale" - trovando un modello non lineare tra i dati caotici. –

+0

Non si parla di sintomi in nessuno dei tavoli. Dobbiamo supporre che le tabelle registrino solo i dati prima che i sintomi vengano esibiti? I sintomi sono registrati come malattie separate nella tabella delle malattie? O i sintomi sono irrilevanti per la query in questione? –

risposta

4

Per me, la semplice (se brutto) soluzione è usare esiste e NON ESISTE clausole:

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]) 

... e così via. Nell'esempio, chiediamo persone che hanno assunto farmaci 474 ma non 234. Ovviamente, è possibile raggruppare le clausole con AND e OR in base a ciò che è necessario.

A parte: trovo che tutti i cappucci siano difficili da leggere. Di solito uso lettere maiuscole per parole chiave SQL e lettere minuscole per nomi di tabelle e colonne.

+0

Non pensavo che funzionasse all'inizio, ma sembra dare la risposta corretta. Grazie. –

0

Pardon errori ma penso che qualcosa di simile potrebbe funzionare (in 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

Ora non deve essere fatto con un UNION ma per leggibilità ho pensato che questo era il più facile date le vostre condizioni. Forse questo ti porterà nella giusta direzione.

+0

Questo non gestirà il mio secondo schema che ho appena aggiunto. I miei schemi potrebbero specificare che una persona ha assunto la droga 234 e 474 prima di contrarre la malattia, ma non la droga 26. In questo caso, in questa query si ottengono risultati zero. –

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))); 

Questo farà quello che stai chiedendo. Le dichiarazioni IN alla fine sono piuttosto auto-esplicative.

+0

Questo non gestirà il mio secondo schema che ho appena aggiunto. I miei schemi potrebbero specificare che una persona ha assunto la droga 234 e 474 prima di contrarre la malattia, ma non la droga 26. In questo caso, in questa query si ottengono risultati zero. –

+0

Dovevo semplicemente spostare il 234 nell'altra clausola IN - basta metterli all'indietro - ora funziona. Il primo IN è i farmaci che vuoi vedere prima dei sintomi, il 2 ° IN sono i farmaci che vuoi vedere dopo l'inizio dei sintomi. Il 3 ° e il 4 ° IN sono il tuo prossimo modello: lo stesso formato di input. –

+0

errore di battitura sul 2 ° e 4 ° IN sono le droghe che non vuoi vedere prima che inizino i sintomi. –

0

Nessuna delle risposte fornite sembra funzionare. Anche in questo caso è il modello che voglio implementare: ((Drug 234 = true and Drug 474 = true and Drug 26 = false) OR (Drug 395 = false and Drug 791 = false and Drug 371 = true))

Credo che la seguente query funzionerà (Drug 234 = true AND Drug 474 = true AND Drug 26 = false). Detto questo, è abbastanza facile aggiungere la seconda metà della query.

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) 

Questa query funziona, ma è piuttosto brutta. Sospetto anche che sarà estremamente lento una volta che avrò un database di produzione con 100 milioni di persone. C'è qualcosa che posso fare per semplificare/ottimizzare questa query?

+0

Perché il parametro disease_id è improvvisamente cambiato a 26 a metà? Non era nella domanda? –

+1

Quello era l'errore di battitura. È ora riparato. Grazie per averlo capito. –

1

Non ho idea di come funzionerà con tabelle di grandi dimensioni (immagino che sarà piuttosto scadente dato che i confronti delle date sono in genere piuttosto costosi), ma qui c'è un metodo che dovrebbe funzionare. È relativamente dettagliato, ma è molto facile da modificare per diversi casi booleani.

Esempio 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))) 

Esempio 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

Sembra funzionare. Grazie. –

1

Ecco una query che gestisce ((Drug 234 = true AND Drug 474 = true AND Drug 26 = false) OR (Drug 395 = false AND Drug 791 = false AND Drug 371 = true)), come hai postato.

/* 
-- 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

Non ho i dati di prova reale portata di mano per provare questo fuori, ma credo che si potrebbe fare qualcosa di simile:

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 

Il caso so che non riuscirà c'è se si dispone di più record per la stessa persona e lo stesso farmaco/malattia nelle tabelle droga/malattia. Se questo è il caso, si potrebbe anche modificare la clausola di dover guardare più simile 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 può assumere lo stesso farmaco più di una volta e ci sarebbe una riga per ogni volta che ha preso il farmaco. Credo che lo stesso sia vero per le malattie. –

0

mi sarebbe probabilmente affrontare questo problema da una direzione simile a questo. È piuttosto flessibile

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

Se ho bene, si consiglia di:

  • Selezionare fuori quelle persone
  • che sono stati infettati con un (1) specifica malattia
  • che sono stati trattati con una sola o più farmaci specificati
  • E che NON sono stati trattati con uno o più farmaci specificati

Questo potrebbe essere semplificato convertendo i "requisiti di droga" in una tabella temporanea di qualche forma. Ciò consentirebbe l'uso di un numero qualsiasi di farmaci "buoni" e "cattivi" su cui interrogare. Quello che ho di seguito potrebbe essere implementato come una stored procedure, ma se questa non è un'opzione sono disponibili numerose opzioni contorte.

Abbattere i gradini:

primo, ecco come i pazienti desiderati vengono selezionati. Useremo questo come una sottoquery tardi:

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] 

In secondo luogo, per ogni gruppo di farmaci "target" che si è ANDed insieme, impostare una tabella temporanea in questo modo (questa è la sintassi SQL Server, Postgres dovrebbe avere qualcosa di simile):

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

popolarlo con una riga per ogni farmaco che si stanno prendendo in considerazione:

  • Drug_Id = il farmaco si sta controllando
  • Includere = 1 se la persona è di aver assunto il farmaco, e 0 se sono di non aver preso

e calcolare due valori:

@GoodDrugs, il numero di farmaci che si desidera al paziente di aver preso
@BadDrugs, il numero di farmaci che si desidera al paziente di non aver preso

Ora, punto tutto quanto sopra insieme nella seguente query:

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 

Ho intenzionalmente ignorato i criteri del tempo perché non sono stati inseriti nei dettagli, ma dovrebbero essere abbastanza semplici da aggiungere (anche se spero che non siano le ultime parole famose). Ulteriori ottimizzazioni possono essere possibili, ma molto dipende dai dati e da altri possibili criteri.

È necessario eseguire questa volta per ciascun "set di farmaci" (ovvero set di farmaci TRUE o FALSE ANDed insieme), concatenando l'elenco con ciascun passaggio. Probabilmente potresti espandere #DrugSet come fattore in ogni set di farmaci che stai controllando, ma sono riluttante a provare il codice che senza alcuni dati seri per testarlo.

*/

+0

Ho ignorato le colonne della data e ho supposto che lì fossero presenti le chiavi primarie intuitive. Se questo non è il caso, verranno richieste alcune clausole distinte e di gruppo. –

0

ho cercato di abbattere il problema, e seguire attraverso logicamente che potevo.

primo luogo i tre tabelle (Person_T, Drugs_T, Disease_T) può essere pensato come mostrato in Figura 1.0:

Una persona può avere molteplici farmaci e multipla malattie. Ogni farmaco e malattia ha una data di inizio & data di fine.

Therfore avrei prima de-normalizzare i tre tabelle in una tabella (Table_dn) così:

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

Questa tabella de-normalizzata può essere una tabella temporanea, se necessario, a prescindere Table_dn ora contiene tutto l'intero globale set di dati come mostrato in Fig 2.0 (indicato come G).

Dalla mia comprensione della descrizione, posso vedere essenzialmente un filtro a due strati.

Filtro 1

Questo filtro è semplicemente un insieme di farmaci booleano Combinazioni, come si è già detto nella descrizione domanda. es:

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

filtro 2

Questo filtro è un po 'più complicato rispetto alla prima, è data intervallo di criteri. La Fig 3.0 mostra questo intervallo di date in RED. Il giallo rappresenta date di registrazione che si estendono in diversi modi:

  • prima del periodo ROSSO
  • Dopo il periodo di RED
  • Tra periodo ROSSO
  • Fine prima della fine del periodo di RED
  • partire dopo l'inizio del periodo di RED

Ora i periodi di data GIALLA potrebbero essere il periodo di farmaci o il periodo di malattia O la combinazione di entrambi.

Questo filtro deve essere applicato all'insieme di risultati ottenuti dai primi risultati.

Naturalmente, a seconda della domanda esatta, è possibile che i due filtri facciano il contrario (ad es. F2 prima quindi f1).

SQL pseudo codice:

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

where [Filter 2] 

alt text

Problemi correlati