2010-07-09 29 views
6

Tôi có bảng cơ sở dữ liệu sau đây với thông tin về con người, bệnh tật, và các loại thuốc:Làm cách nào để dịch một câu lệnh boolean đơn giản sang 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 

Từ các bảng, tôi chạy một số thống kê về những cá nhân đã có thuốc và đã có bệnh. Từ điều này tôi có thể tìm ra những mẫu nào thú vị cho tôi để nghiên cứu kỹ hơn. Ví dụ, dưới đây là một ví dụ đơn giản của mô hình boolean Tôi có thể tìm thấy cho bệnh 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: Dưới đây là một ví dụ:

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

Bây giờ tôi muốn chuyển đổi mô hình này vào một truy vấn sql và tìm tất cả những người phù hợp với mô hình này.
Ví dụ: tôi muốn tìm tất cả những người trong PERSON_T đã mắc bệnh và ((người không dùng thuốc 234 và 26 trước khi biểu hiện triệu chứng nhưng đã dùng thuốc 474 trước khi có triệu chứng) hoặc (người đã uống thuốc) 371 trước khi trưng bày các triệu chứng, nhưng không phải thuốc 791 và 395 trước khi biểu hiện triệu chứng))

Làm cách nào để chuyển mẫu này trở lại truy vấn gốc?

Đây là nỗ lực đầu tiên của tôi, nhưng tôi gặp khó khăn về thời hạn đầu tiên:

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

tôi cần điều này để làm việc trong PostgreSQL, nhưng tôi cho rằng bất kỳ câu trả lời nhất định có thể được dịch từ một cơ sở dữ liệu cho PostgreSQL.

Response to comments

  1. Tôi cố định định dạng của cơ sở dữ liệu bảng. Cảm ơn bạn.
  2. Tôi cần có thể lấy một câu lệnh boolean tùy ý và dịch nó sang SQL. Các câu lệnh boolean mà chúng ta đang tạo ra dài hơn nhiều so với ví dụ mà tôi đã đưa ra. Bất kỳ bảng mới nào tôi tạo sẽ nằm trong cơ sở dữ liệu mới và cần phải có cùng một lược đồ như các bảng gốc. Bằng cách này cho người dùng cuối, họ có thể chạy cùng mã của họ trên các bảng mới và nó hoạt động giống như khi nó chạy trên các bảng gốc. Đây là yêu cầu của khách hàng. Tôi hy vọng tôi có thể tạo ra một cái nhìn mà chỉ là một truy vấn đến các bảng ban đầu. Nếu chúng ta không thể làm điều đó để làm việc, tôi có thể tạo một bản sao của các bảng và lọc dữ liệu khi tôi sao chép nó sang bảng mới. Chúng tôi không sử dụng mạng thần kinh để thực hiện phân tích. Chúng tôi đang sử dụng các thuật toán tùy chỉnh của chúng tôi có quy mô tốt hơn nhiều so với mạng thần kinh.
  3. The Disease_Start_Date là ngày mà người đó nhận được sự phân biệt có khả năng khi các sympton bắt đầu xuất hiện. Bệnh_End_Date là khi người đó được hồi phục, có khả năng là khi các triệu chứng biến mất.
  4. Drug_start_date là khi người đó bắt đầu uống thuốc. Drug_end_date là khi người đó ngừng dùng thuốc.

Chỉnh sửa Tôi đã thêm câu trả lời của riêng mình. Bất cứ ai có thể đưa ra một câu trả lời đơn giản hơn?

+0

Tôi nghĩ defs bảng của bạn được định dạng sai. DISEASE_END_DATE có nên ở trong bảng Person hoặc bảng Bệnh không? Tôi nghĩ rằng khoảng cách sai lầm. Ngoài ra, do đó, DRUG_END_DATE xuất hiện trong bảng Bệnh. – MJB

+0

Bạn chỉ quan tâm đến sự kết hợp đặc biệt của các loại thuốc đó hoặc sẽ có những loại thuốc khác?Nếu có nhiều kết hợp thay vì thực hiện truy vấn SQL tĩnh này, tôi khuyên bạn nên tạo 1-2 bảng khác chứa các mẫu thuốc mà bạn đang tìm kiếm và tạo truy vấn SQL động để tham chiếu bảng ràng buộc của bạn. Điều này sẽ mở rộng tốt hơn với các yêu cầu trong tương lai của bạn và sẽ giúp bạn tiết kiệm thời gian thực hiện các truy vấn khác nhau mỗi khi bạn thay đổi "loại thuốc quan tâm". Loại phân tích này cũng hét lên "mạng thần kinh" với tôi - tìm ra một mô hình phi tuyến tính giữa dữ liệu hỗn loạn. –

+0

Không có đề cập đến các triệu chứng trong bất kỳ bảng nào. Chúng ta có thể giả định rằng các bảng chỉ ghi lại dữ liệu trước khi các triệu chứng được trưng bày? Các triệu chứng có được ghi nhận là các bệnh riêng biệt trên bảng bệnh không? Hoặc là các triệu chứng không liên quan đến truy vấn được đề cập? –

Trả lời

4

Với tôi, đơn giản (nếu xấu xí) giải pháp là sử dụng EXISTS và NOT EXISTS khoản:

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

... và vân vân. Trong ví dụ này, chúng tôi yêu cầu những người đã dùng thuốc 474 nhưng không phải là 234. Rõ ràng, bạn có thể nhóm các mệnh đề với AND và OR theo những gì bạn cần.

Ngoài ra: Tôi thấy tất cả các mũ khó đọc. Tôi thường sử dụng chữ hoa cho các từ khóa SQL và chữ thường cho các tên bảng và cột.

+0

Tôi đã không nghĩ rằng điều này làm việc lúc đầu, nhưng nó xuất hiện để cung cấp cho câu trả lời đúng. Cảm ơn. –

0

Pardon bất kỳ sai lầm nhưng tôi nghĩ rằng một cái gì đó như thế này sẽ làm việc (trong 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

Bây giờ nó không nhất thiết phải được thực hiện với một UNION nhưng đối với readibility Tôi nghĩ đây là dễ nhất cho điều kiện của bạn. Có lẽ điều này sẽ dẫn bạn đi đúng hướng.

+0

Điều này sẽ không xử lý mẫu thứ hai của tôi mà tôi vừa thêm vào. Các mẫu của tôi có thể chỉ định rằng một người đã uống thuốc 234 và 474 trước khi mắc bệnh, nhưng không dùng thuốc 26. Truy vấn này dẫn đến kết quả bằng không trong trường hợp này. –

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

Điều này sẽ làm những gì bạn đang yêu cầu. Các báo cáo IN ở cuối là khá tự giải thích.

+0

Điều này sẽ không xử lý mẫu thứ hai của tôi mà tôi vừa thêm vào. Các mẫu của tôi có thể chỉ định rằng một người đã uống thuốc 234 và 474 trước khi mắc bệnh, nhưng không dùng thuốc 26. Truy vấn này dẫn đến kết quả bằng không trong trường hợp này. –

+0

Chỉ cần di chuyển 234 đến mệnh đề IN khác - chỉ cần đặt chúng ngược lại - nó hoạt động ngay bây giờ. IN đầu tiên là loại thuốc bạn muốn xem trước các triệu chứng, 2nd IN là loại thuốc bạn muốn thấy sau khi các triệu chứng bắt đầu. IN thứ 3 và thứ 4 là mẫu tiếp theo của bạn - cùng một định dạng đầu vào. –

+0

typo trên 2nd & 4th INs họ là những loại thuốc bạn không muốn thấy trước khi các triệu chứng bắt đầu. –

0

Không có câu trả lời nào dường như có hiệu quả. Một lần nữa ở đây là mẫu mà tôi muốn thực hiện: ((ma túy 234 = true VÀ ma túy 474 = true AND Drug 26 = false) HOẶC (ma túy 395 = false VÀ ma túy 791 = false VÀ ma túy 371 = true))

Tôi tin rằng truy vấn sau đây sẽ hiệu quả (Thuốc 234 = true VÀ Drug 474 = true AND Drug 26 = false). Cho rằng, nó là khá dễ dàng để thêm một nửa thứ hai của truy vấn.

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) 

Truy vấn này hoạt động nhưng khá xấu. Tôi cũng nghi ngờ nó sẽ rất chậm khi tôi có một cơ sở dữ liệu sản xuất với 100 triệu người. Tôi có thể làm gì để đơn giản hóa/tối ưu hóa truy vấn này không?

+0

Tại sao bệnh tật đột ngột thay đổi thành 26 nửa? Đó không phải là câu hỏi? –

+1

Đó là lỗi chính tả. Nó được cố định ngay bây giờ. Cảm ơn vì đã bắt được điều đó. –

1

Tôi không biết làm thế nào điều này sẽ thực hiện với các bảng lớn (tôi tưởng tượng nó sẽ khá tệ hại như so sánh ngày thường khá đắt tiền), nhưng đây là một phương pháp mà nên làm việc. Nó tương đối dài dòng, nhưng rất dễ sửa đổi đối với các trường hợp boolean khác nhau.

Ví dụ 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))) 

Ví dụ 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

Điều này có vẻ như hoạt động. Cảm ơn. –

1

Đây là một truy vấn để xử lý ((Drug 234 = true AND Drug 474 = true AND Drug 26 = false) OR (Drug 395 = false AND Drug 791 = false AND Drug 371 = true)), khi bạn đăng.

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

tôi không có dữ liệu thử nghiệm thực sự tiện dụng này để thử ra đi, nhưng tôi nghĩ rằng bạn có thể làm một cái gì đó như:

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 

Các trường hợp tôi biết sẽ không có nếu bạn có nhiều hồ sơ cho cùng một người và cùng một loại thuốc/bệnh trong bảng thuốc/bệnh. Nếu trường hợp đó xảy ra, bạn cũng có thể thay đổi mệnh đề HAVING để trông giống như sau:

(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

Một người có thể dùng cùng một loại thuốc nhiều lần và sẽ có một hàng cho mỗi lần họ uống thuốc. Tôi tin điều tương tự cũng đúng đối với bệnh tật. –

0

Tôi có thể tiếp cận vấn đề này từ một số hướng tương tự như vậy. Nó khá linh hoạt.

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

Nếu tôi có điều đó đúng, bạn muốn:

  • Chọn ra những người
  • Ai đã bị nhiễm một (1) bệnh cụ thể
  • Ai đã được điều trị bằng một hoặc nhiều thuốc được chỉ định
  • Và những người chưa được điều trị bằng một hoặc nhiều loại thuốc được chỉ định khác

Điều này có thể được đơn giản hóa bằng cách chuyển đổi "yêu cầu ma túy" thành bảng tạm thời của một số biểu mẫu. Điều này sẽ cho phép sử dụng bất kỳ số lượng thuốc "tốt" và "xấu" nào để truy vấn. Những gì tôi có dưới đây có thể được thực hiện như là một thủ tục được lưu trữ, nhưng nếu đó không phải là một lựa chọn một số tùy chọn phức tạp có sẵn.

Breaking down các bước:

Đầu tiên, dưới đây là cách các bệnh nhân mong muốn được lựa chọn. Chúng tôi sẽ sử dụng điều này như một subquery sau:

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] 

Second, cho mỗi bộ thuốc "mục tiêu" mà bạn đã ANDed với nhau, thiết lập một bảng tạm thời như vậy (đây là SQL Server cú pháp, Postgres nên có một cái gì đó tương tự):

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

cư nó với một hàng cho mỗi loại thuốc bạn đang xem xét:

  • Drug_Id = thuốc bạn đang kiểm tra
  • Include = 1 nếu người đó đã lấy thuốc, và 0 nếu họ không đã lấy nó

và tính toán hai giá trị:

@GoodDrugs, số lượng thuốc bạn muốn bệnh nhân đã lấy
@BadDrugs, số lượng thuốc bạn muốn bệnh nhân đã không được thực hiện

Bây giờ, khâu tất cả các bên trên với nhau trong truy vấn sau đây:

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 

Tôi đã cố ý bỏ qua các tiêu chí thời gian khi bạn không đi vào chi tiết về chúng, nhưng chúng nên khá đơn giản để thêm (mặc dù tôi hy vọng đó không phải là những từ cuối cùng nổi tiếng). Có thể tối ưu hóa thêm, nhưng rất nhiều tùy thuộc vào dữ liệu và các tiêu chí có thể khác.

Bạn sẽ cần phải chạy điều này một lần cho mỗi "bộ thuốc" (nghĩa là, bộ TRUE hoặc FALSE ma túy ANDed với nhau), nối danh sách với mỗi lần vượt qua. Bạn có thể mở rộng #DrugSet thành yếu tố trong mỗi bộ thuốc bạn đang kiểm tra, nhưng tôi không muốn thử và mã số mà không có một số dữ liệu nghiêm trọng để kiểm tra nó.

*/

+0

Tôi bỏ qua các cột ngày và giả sử rằng có các khóa chính trực quan hiện diện. Nếu đây không phải là trường hợp, một số khác biệt và nhóm theo điều khoản sẽ được gọi cho. –

0

Tôi đã cố gắng giải quyết sự cố và theo dõi một cách hợp lý nhất có thể.

Thứ nhất là ba bảng (Person_T, Drugs_T, Disease_T) có thể được coi như hình 1.0:

một người có thể có nhiều ma túy và nhiều bệnh. Mỗi loại thuốc và bệnh có ngày bắt đầu & ngày kết thúc.

therfore đầu tiên tôi sẽ hủy chuẩn hóa ba bảng vào một bảng (Table_dn) như sau:

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

bảng de-bình thường này có thể là một bảng tạm thời nếu cần thiết, bất kể Table_dn bây giờ chứa tất cả toàn bộ toàn cầu tập dữ liệu như trong hình 2.0 (ký hiệu là G).

Từ hiểu biết của tôi về mô tả của bạn, tôi có thể thấy cơ bản là bộ lọc hai lớp.

Lọc 1

Bộ lọc này chỉ đơn giản là một tập hợp boolean thuốc Kết hợp, như bạn đã ghi trong mô tả câu hỏi của bạn. ví dụ:

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

Lọc 2

Bộ lọc này là nhiều hơn một chút phức tạp hơn so với lần đầu tiên, đó là tiêu chí phạm vi ngày. Hình 3.0 cho thấy phạm vi ngày này trong RED. Màu vàng tượng trưng cho ngày kỷ lục mà span theo nhiều cách:

  • trước kỳ RED
  • Sau giai đoạn RED
  • giữa kỳ RED
  • Kết thúc trước khi kết thúc giai đoạn RED
  • Bắt đầu từ sau khi bắt đầu giai đoạn RED

Bây giờ, khoảng thời gian ngày VÀNG có thể là khoảng thời gian thuốc hoặc khoảng thời gian bệnh HOẶC kết hợp cả hai.

Bộ lọc này nên được áp dụng cho tập hợp các kết quả thu được từ kết quả đầu tiên.

Tất nhiên tùy thuộc vào câu hỏi chính xác của bạn, hai Bộ lọc này có thể cần phải đi theo chiều ngược lại (ví dụ: f2 trước rồi đến f1).

SQL pseudo code:

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

where [Filter 2] 

alt text

Các vấn đề liên quan