跳轉到內容

OpenClinica 使用者手冊/離線分發

來自華夏公益教科書

使用 Python 指令碼建立受試者並安排 OpenClinica 事件

[編輯 | 編輯原始碼]

肯亞內羅畢的 DNDi 資料中心一直在探索使用 OpenClinica 的“離線模式”的方法,並開發了一個 python 指令碼,使在離線模式下使用該軟體並在稍後與中央資料庫同步成為可能。該指令碼旨在在一個組織結構如下所示的環境中工作;


1. 首先在主研究伺服器上設定中央資料庫。建立研究資料庫的最終版本,並定義研究站點和站點使用者。這將成為主要研究資料庫或中央研究資料庫,在本例中,它託管在內羅畢的 DNDi 資料中心伺服器上。完成後,我們使用最終研究資料庫轉儲來複制所有站點計算機上的資料庫。


2. 在站點收集資料 在站點計算機上安裝資料庫後,站點使用者可以正常進行資料輸入。不需要網際網路連線,因為 OpenClinica 在站點計算機上本地安裝。然後定期從研究計算機中以 CDISC ODM 1.3 Xml 格式提取資料,併發送到內羅畢的 DNDi 資料中心,以便匯入到中央資料庫。最新的資料庫轉儲也會生成併發送到資料中心。


3. 與資料中心的中央研究資料庫同步。當資料中心收到提取的資料和最新的資料庫轉儲時,最新的資料庫轉儲將被插入與中央研究資料庫位於同一伺服器上的 Postgres 資料庫中。這意味著在與中央資料庫相同的伺服器上建立了一個“使用站點名稱”的資料庫,並將站點資料庫轉儲恢復到其中。一個 python(參見 https://python.club.tw)指令碼,稱為 OC 事件排程程式,將被執行。該指令碼將中央資料庫與插入的站點資料庫進行比較,檢查站點資料庫中可用的受試者是否也在中央資料庫中可用。如果受試者在中央資料庫中不可用,那麼它們將在中央資料庫中建立。該指令碼還檢查站點資料庫中的受試者事件是否已在中央資料庫中安排,如果沒有,則安排這些事件。一旦添加了新的受試者並將所有事件安排好,提取的站點資料就會使用 OpenClinica 資料匯入功能匯入。資料匯入可以手動完成,也可以安排匯入任務,以便 OpenClinica 按照計劃匯入放在匯入資料夾中的所有 ODM 檔案。


OC 事件排程程式是一個通用工具,僅提供中央資料庫名稱、站點資料庫名稱、資料庫使用者名稱、資料庫主機地址和資料庫密碼,以便用於同步站點和中央資料庫。

Python 指令碼安裝

要執行指令碼,必須安裝以下軟體;

1. 除了標準的 OpenClinica 軟體堆疊之外,還必須安裝 Python 軟體(來自 https://python.club.tw/download/releases/2.7.2/),以便執行 OC 事件排程程式指令碼。

2. Psycopg2(用於 Python 程式語言的 PostgreSQL 資料庫介面卡)可從 http://initd.org/pub/software/psycopg2 下載,也可從 http://www.stickpeople.com/projects/python/win-psycopg/ 為 Windows 下載。

關於指令碼工作原理的更多詳細資訊在指令碼中以註釋的形式提供。

python 指令碼

[編輯 | 編輯原始碼]
import csv
import psycopg2
"""
@Author: Michael Ochieng
        Data Manager/ Programmer
        DNDi Africa Liason Office
        Nairobi, Kenya.
        Pythons Script For Bulk Scheduling of OpenClinica Events in the Central Database
        - In preparation of Bulk Import from a site database.
       ------------------------------------------------------------------------------------------------
       Assumptions
       ------------------------------------------------------------------------------------------------
       1. The Site Database Must be a replica of the Central Database.
       2. The Site database backup dump must be plugged into the same server containing the central database
"""

def __getDBConnection(central_dbname,site_dbname,username,host,passwd):
    try:

        """Connection to site database i.e the database to import data from"""
        conn = psycopg2.connect("dbname='"+site_dbname+"' user='"+username+"' host='"+host+"' password='"+passwd+"'")
        cur=conn.cursor()
        cur3=conn.cursor()
        
        """Conncetion to the Main Study Database i.e the database to import data to"""
        conn2 = psycopg2.connect("dbname='"+central_dbname+"' user='"+username+"' host='"+host+"' password='"+passwd+"'")
        cur2=conn2.cursor()   

        """
        1. We begin by importing the subject from OpenClinica subject table.
        First, select all the study_subjects from the site study database so the we can
        compare with study_subjects from the Main study database whether they are already
        in the system or not.
        """

        print "------------Importing Subject and Study_Subject data---------------------- "
        cur.execute("""select * from study_subject;""")
        study_subject_rows = cur.fetchall()
        the_subject_id=0
        if study_subject_rows:
            for row in study_subject_rows:
                cur2.execute("""select * from study_subject where label='"""+row[1]+"""'""")
                site_study_subject_rows=cur2.fetchall()

                """
                Meaning that if the subject with the label passed in the query above
                is not present, then go ahead and add the subject in the main database.
                """
                if len(site_study_subject_rows)==0:
                    
                    cur3.execute("""select * from subject where subject_id=(select subject_id from study_subject where label='"""+row[1]+"""');""")                    
                    rows3=cur3.fetchall()
                    
                    if rows3:
                        for row3 in rows3:
                            
                            print row3
                            subjectStr="INSERT INTO subject(subject_id, father_id, mother_id, status_id, date_of_birth, gender, unique_identifier, date_created,"
                            subjectStr+="owner_id, date_updated, update_id,dob_collected) VALUES (nextval('subject_subject_id_seq'),%s, %s, %s,"

                            subjectStr=subjectStr % ('null','null',row3[3])

                            #Check if Date of Birth is Null
                            if row3[4] is None:
                                subjectStr+="null,"
                            else:
                                subjectStr+="'%s',"                                                                
                                subjectStr=subjectStr % (row3[4])

                            #Check if Gender is Null
                            if row3[5] is None:

                                subjectStr+="null,"
                            else:
                                subjectStr+="'%s',"                                                                
                                subjectStr=subjectStr % (row3[5])
                                
                            subjectStr+=" '%s', '%s', %s, %s,%s, '%s');"
                            
                            subjectStr=subjectStr % (row3[6],row3[7],row3[8],'null','null',row3[11])

                            cur2.execute(subjectStr)
                            conn2.commit()
                        
                    strSql="INSERT INTO study_subject(study_subject_id, label, secondary_label, subject_id, study_id,status_id, enrollment_date,"
                    strSql+="date_created, date_updated, owner_id, update_id,oc_oid) VALUES (nextval('study_subject_study_subject_id_seq'),'%s',"
                    strSql+="'%s', currval('subject_subject_id_seq'), %s, %s, '%s', '%s', %s, %s,%s,'%s');"

                    strSql = strSql % (row[1],row[2],row[4],row[5],row[6],row[7],'null',row[9],'null',row[11])
                    cur2.execute(strSql)
                    conn2.commit()

        cur2.execute("""select study_subject_id,label from study_subject;""")
        ss_rows=cur2.fetchall()

        if ss_rows:
            for ss_row in ss_rows:
                print "------------Importing Study_Event data----------------------Subject ID: ", ss_row[0]
                cur.execute("""select * from study_event where study_subject_id=(select study_subject_id from study_subject where label='"""+str(ss_row[1])+"""');""")
                site_study_event_rows=cur.fetchall()
                if site_study_event_rows:
                    for i in site_study_event_rows:
                        selEventStr="select * from study_event where study_subject_id=(select study_subject_id from study_subject where label='%s') and study_event_definition_id=%s and sample_ordinal=%s;"
                        selEventStr=selEventStr %(str(ss_row[1]),str(i[1]),str(i[4]))

                        #print selEventStr
                        cur2.execute(selEventStr)
                        maindb_study_event_rows=cur2.fetchall()
                       
                        if len(maindb_study_event_rows)==0:
                            
                            eventStr="INSERT INTO study_event(study_event_id, study_event_definition_id, study_subject_id,location, sample_ordinal,"
                            eventStr+="date_start, date_end, owner_id, status_id,date_created, date_updated, update_id, subject_event_status_id,"
                            eventStr+="start_time_flag, end_time_flag) VALUES (nextval('study_event_study_event_id_seq'),%s,%s,'%s',%s,%s,%s,%s,%s,%s,%s,%s,1,'%s','%s');"

                            eventStr=eventStr %(i[1],ss_row[0],'null' if i[3].find('None')!=-1 else i[3],i[4],'null' if str(i[5]).find('None')!=-1 else "'"+str(i[5])+"'",'null' if str(i[6]).find('None')!=-1 else "'"+str(i[6])+"'",i[7],i[8],'null' if str(i[9]).find('None')!=-1 else "'"+str(i[9])+"'",'null' if str(i[10]).find('None')!=-1 else "'"+str(i[10])+"'",'null' if str(i[11]).find('None')!=-1 else i[11],i[13],i[14])
                            #print eventStr
                            cur2.execute(eventStr)
                            conn2.commit()
        cur.close()
        conn.close()
                

    except psycopg2.DatabaseError, e:
        print 'Error %s' % e    
        #return null

"""
@CentralDatabaseName: refers to the Central OC Database Name
@SiteDatabaseName: Refers to the database name for the site database as restored on the main server
@Username: Database user assigned to both databases
@localhostOrServeIP: The server IP Address or localhost if the script is executed from the server
@YourPassword: Refers to the user password corresponding to the @Username
Assumption
----------
1. The Same database login role is used when creating the CentralDatabase and the Site Database.

"""

__getDBConnection('CentralDatabaseName','SiteDatabaseName','UserName','localhostOrServeIP','YourPassword')
華夏公益教科書