14.3.23. crate_anon.crateweb.consent.lookup_rio
crate_anon/crateweb/consent/lookup_rio.py
Copyright (C) 2015, University of Cambridge, Department of Psychiatry. Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CRATE.
CRATE is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
CRATE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with CRATE. If not, see <https://www.gnu.org/licenses/>.
Functions to look up patient details from various versions of a Servelec RiO clinical database.
- crate_anon.crateweb.consent.lookup_rio.gen_opt_out_pids_mpids_rio_cpft_datamart(source_db: str) Generator[Tuple[str, str], None, None] [source]
Generates PIDs/MPIDs from all patients opting out, from a RiO database that is the version in the CPFT data warehouse.
- Parameters:
source_db – the type of the source database; see
crate_anon.crateweb.config.constants.ClinicalDatabaseType
- Yields:
tuple –
rio_number, nhs_number
for each patient opting out; both are in string format
- crate_anon.crateweb.consent.lookup_rio.gen_opt_out_pids_mpids_rio_generic(source_db: str, raw_rio: bool = False, cpft_datamart: bool = False) Generator[Tuple[str, str], None, None] [source]
Generates PIDs/MPIDs from all patients opting out, from a RiO database of some sort.
- Parameters:
source_db – the type of the source database; see
crate_anon.crateweb.config.constants.ClinicalDatabaseType
raw_rio – is the source database a raw copy of RiO?
cpft_datamart – is the source database the version from the CPFT data warehouse?
- Yields:
tuple –
rio_number, nhs_number
for each patient opting out; both are in string format
- crate_anon.crateweb.consent.lookup_rio.gen_opt_out_pids_mpids_rio_raw(source_db: str) Generator[Tuple[str, str], None, None] [source]
Generates PIDs/MPIDs from all patients opting out, from a raw RiO database.
- Parameters:
source_db – the type of the source database; see
crate_anon.crateweb.config.constants.ClinicalDatabaseType
- Yields:
tuple –
rio_number, nhs_number
for each patient opting out; both are in string format
- crate_anon.crateweb.consent.lookup_rio.get_latest_consent_mode_from_rio_cpft_datamart(nhs_number: int, source_db: str, decisions: List[str]) ConsentMode | None [source]
Returns the latest consent mode for a patient from the copy of RiO in the CPFT data warehouse.
- Parameters:
nhs_number – NHS number
source_db – the type of the source database; see
crate_anon.crateweb.config.constants.ClinicalDatabaseType
decisions – list of human-readable decisions; will be modified
- Returns:
- crate_anon.crateweb.consent.lookup_rio.get_latest_consent_mode_from_rio_generic(nhs_number: int, source_db: str, decisions: List[str], raw_rio: bool = False, cpft_datamart: bool = False) ConsentMode | None [source]
Returns the latest consent mode for a patient, from some style of RiO database.
- Parameters:
nhs_number – NHS number
source_db – the type of the source database; see
crate_anon.crateweb.config.constants.ClinicalDatabaseType
decisions – list of human-readable decisions; will be modified
raw_rio – is the source database a raw copy of RiO?
cpft_datamart – is the source database the version from the CPFT data warehouse?
- Returns:
Shared function as very similar for the various copies of RiO data.
In raw RiO at CPFT, the traffic-light table is UserAssessConsentrd. This is processed regularly into the CPFT Data Warehouse, so that contains very fresh data and is a good choice.
For CPFT’s custom consent mode, built into RiO v6, the table copy in the Data Warehouse is:
SELECT [ClientID] -- VARCHAR(15) NOT NULL; RiO number as text ,[AssessmentDate] -- DATETIME ,[ReferralNumber] -- NVARCHAR(20); a small integer as text ,[ResearchContact] -- NVARCHAR(20); 'RED', 'YELLOW', 'GREEN' ,[OptOut] -- BIT; 1 for opt out; NULL (or potentially 0?) for not -- opted out ,[OptOutFromMedicalResearch_AfterDetailsRemoved] -- VARCHAR(1); 'Y' for opt out; 9 for not opted out -- identical information to OptOut; OptOut is the simpler ,[PersonActingonBehalf_of_Patient] -- NTEXT, e.g. 'Mr Smith' or NULL ,[PersonActingonBehalf_of_Patient_Relation] -- NTEXT, e.g. 'Husband' or NULL or 'N/A' or 'n/a' ,[Personactingonbehalf_address] -- NTEXT, e.g. an address or NULL or 'N/A' or 'n/a' ,[WhoMakesDecisionFor_Patient] -- NVARCHAR(40), e.g. one of: -- '16 or over, has capacity' -- '16 or over, lacks capacity' -- 'Under 16, “Gillick competent”' -- note left/right double quotes -- 'Under 16, parent/guardian consent' FROM [CPFT_DATAMART].[dbo].[ConsentToResearch] -- NB this is on a different CPFT server; see databases.txt
Note also: the CPFT_DATAMART database does not provide patient- identifiable information, except PatientOverview_RiO:
SELECT [NHSNumber] -- VARCHAR(15); NHS number as text ,[ClientID] -- VARCHAR(15) NOT NULL; RiO number as text ,[PatientName] -- VARCHAR(202); e.g. 'Smith, John' ,[Surname] -- VARCHAR(100); e.g. 'Smith' ,[DOB] -- DATETIME; time part is zero ,[TeamStartDate] -- DATETIME ,[TeamName] -- NVARCHAR(50) ,[ReferralNumber] -- INT NOT NULL; a small integer ,[LastAttendedApptDate_WithTeam] -- DATE ,[FutureAppts_WithTeam] -- DATE; just one despite the name ,[HCPs] -- NVARCHAR(MAX); semicolon-delimited list; e.g. -- '; Alice Smith' -- '; Alice Smith; Bob Jones' -- '; Unknown Consultant' FROM [CPFT_DATAMART].[dbo].[PatientOverviewRiO]
In raw RiO at CPFT, the traffic-light table is UserAssessConsentrd.
SELECT [ClientID] -- VARCHAR(15); RiO number as text ,[AssessmentDate] -- DATETIME ,[system_ValidationData] -- NTEXT; XML style ,[ResearchContact] -- NVARCHAR(20); 'RED', 'YELLOW', 'GREEN', NULL ,[useemail] -- BIT (1, 0, NULL) ,[optout] -- BIT ,[capname] -- NTEXT ,[capaddress] -- NTEXT ,[caprelation] -- NTEXT ,[capacity] -- VARCHAR(20); e.g. 'a', 'b' ,[type12_NoteID] -- INT NOT NULL; small integer ,[type12_OriginalNoteID] -- INT; usually NULL ,[type12_DeletedDate] -- DATETIME; NULL if not deleted ,[type12_UpdatedBy] -- NVARCHAR(20); username ,[type12_UpdatedDate] -- DATETIME ,[formref] -- NVARCHAR(20); typically a small integer as text -- If it's been preprocessed, also these: ,[crate_pk] -- in CRATE preprocessed version only; BIGINT ,[crate_rio_number] -- in CRATE preprocessed version only; BIGINT FROM [dbo].[UserAssessconsentrd]
The NHS number table is:
SELECT [ClientID] -- VARCHAR(15); RiO number as text ,[NNN] -- CHAR(10); NHS number as text -- and lots more FROM [dbo].ClientIndex]
- crate_anon.crateweb.consent.lookup_rio.get_latest_consent_mode_from_rio_raw(nhs_number: int, source_db: str, decisions: List[str]) ConsentMode | None [source]
Returns the latest consent mode for a patient from a raw copy of RiO.
- Parameters:
nhs_number – NHS number
source_db – the type of the source database; see
crate_anon.crateweb.config.constants.ClinicalDatabaseType
decisions – list of human-readable decisions; will be modified
- Returns:
- crate_anon.crateweb.consent.lookup_rio.lookup_cpft_rio_crate_preprocessed(lookup: PatientLookup, decisions: List[str], secret_decisions: List[str]) None [source]
Look up patient details from a CRATE-preprocessed RiO database.
- Parameters:
decisions – list of human-readable decisions; will be modified
secret_decisions – list of human-readable decisions containing secret (identifiable) information; will be modified
Here, we use the version of RiO preprocessed by the CRATE preprocessor. This is almost identical to the RCEP version, saving us some thought and lots of repetition of complex JOIN code to deal with the raw RiO database.
However, the CRATE preprocessor does this with views. We would need to index the underlying tables; however, the CRATE processor has also done this for us for the lookup tables, so we don’t need so many.
USE my_database_name; CREATE INDEX _idx_cdd_nhs ON ClientIndex (NNN); -- already in RiO source CREATE INDEX _idx_cnh_id ON ClientName (ClientID); -- already in RiO source # noqa CREATE INDEX _idx_cnh_eff ON ClientName (EffectiveDate); -- ignored CREATE INDEX _idx_cnh_end ON ClientName (EndDate); -- ignored CREATE INDEX _idx_cah_id ON ClientAddress (ClientID); -- already in RiO source as part of composite index # noqa CREATE INDEX _idx_cah_from ON ClientAddress (FromDate); -- ignored CREATE INDEX _idx_cah_to ON ClientAddress (ToDate); -- ignored CREATE INDEX _idx_cch_id ON ClientTelecom (ClientID); -- already in RiO source as part of composite index # noqa CREATE INDEX _idx_cgh_id ON ClientHealthCareProvider (ClientID); -- already in RiO source # noqa CREATE INDEX _idx_cgh_from ON ClientHealthCareProvider (FromDate); -- ignored # noqa CREATE INDEX _idx_cgh_to ON ClientHealthCareProvider (ToDate); -- ignored CREATE INDEX _idx_cc_id ON CPACareCoordinator (ClientID); -- preprocessor adds this # noqa CREATE INDEX _idx_cc_start ON CPACareCoordinator (StartDate); -- ignored CREATE INDEX _idx_cc_end ON CPACareCoordinator (EndDate); -- ignored CREATE INDEX _idx_ref_id ON AmsReferral (ClientID); -- already in RiO source as part of composite index # noqa CREATE INDEX _idx_ref_recv ON AmsReferral (ReferralReceivedDate); -- ignored # noqa CREATE INDEX _idx_ref_removal ON AmsReferral (RemovalDateTime); -- ignored CREATE INDEX _idx_rsh_id ON AmsReferralAllocation (ClientID); -- already in RiO source as part of composite index # noqa CREATE INDEX _idx_rsh_start ON AmsReferralAllocation (StartDate); -- ignored CREATE INDEX _idx_rsh_end ON AmsReferralAllocation (EndDate); -- ignored CREATE INDEX _idx_rth_id ON AmsReferralTeam (ClientID); -- already in RiO source as part of composite index # noqa CREATE INDEX _idx_rth_start ON AmsReferralTeam (StartDate); -- ignored CREATE INDEX _idx_rth_end ON AmsReferralTeam (EndDate); -- ignored
… or alternative RiO number indexes on CRATE_COL_RIO_NUMBER field.
Then, the only field name differences from RCEP are:
Client_Name_History.End_Date -- not End_Date_
- crate_anon.crateweb.consent.lookup_rio.lookup_cpft_rio_generic(lookup: PatientLookup, decisions: List[str], secret_decisions: List[str], as_crate_not_rcep: bool) None [source]
Look up patient details from a RiO database, either as a CRATE-processed or an RCEP-processed version. (They are very similar.)
- Parameters:
decisions – list of human-readable decisions; will be modified
secret_decisions – list of human-readable decisions containing secret (identifiable) information; will be modified
as_crate_not_rcep – is it a CRATE-preprocessed, rather than an RCEP-preprocessed, database?
Main:
Client_Demographic_Details Client_ID -- PK; RiO number; integer in VARCHAR(15) field Date_of_Birth -- DATETIME Date_of_Death -- DATETIME; NULL if not dead Death_Flag -- INT; 0 for alive, 1 for dead Deleted_Flag -- INT; 0 normally; 1 for deleted NHS_Number -- CHAR(10) Gender_Code -- 'F', 'M', 'U', 'X' Gender_Description -- 'Male', 'Female', ...
Then, linked to it:
Client_Name_History Client_ID -- integer in VARCHAR(15) Effective_Date -- DATETIME End_Date_ -- DATETIME, typically NULL -- in the CRATE version, this is End_Date instead Name_Type_Code -- '1' for 'usual name', '2' for 'Alias', '3' for 'Preferred name', '4' for 'Birth name', '5' for 'Maiden name', '7' for 'Other', 'CM' for 'Client Merge'; NVARCHAR(10) Name_Type_Description -- e.g. 'Usual name', 'Alias' Deleted_Flag -- INT title Given_Name_1 -- through to Given_Name_5 Family_Name suffix ... Client_Address_History Client_ID -- integer in VARCHAR(15) Address_Type_Code -- e.g. 'PRIMARY' but also 'CA', 'FCH'... Address_Type_Description Address_From_Date -- DATETIME Address_To_Date -- DATETIME; NULL for active ones Address_Line_1 Address_Line_2 Address_Line_3 Address_Line_4 Address_Line_5 Post_Code ... -- no e-mail address field Client_GP_History Client_ID -- integer in VARCHAR(15) GP_From_Date -- DATETIME GP_To_Date -- DATETIME; NULL for active ones GP_Name -- e.g. 'Smith JT' GP_Practice_Address_Line1 GP_Practice_Address_Line2 GP_Practice_Address_Line3 GP_Practice_Address_Line4 GP_Practice_Address_Line5 GP_Practice_Post_code ...
CPFT clinician details/?discharged info appear to be here:
CPA_CareCoordinator Client_ID -- integer in VARCHAR(15) Start_Date -- DATETIME End_Date -- DATETIME End_Reason_Code End_Reason_Description End_Reason_National_Code Care_Coordinator_User_title Care_Coordinator_User_first_name Care_Coordinator_User_surname Care_Coordinator_User_email Care_Coordinator_User_Consultant_Flag -- INT; 0 or 1 (or NULL?) Main_Referral_Data Client_ID -- integer in VARCHAR(15) Referral_Received_Date -- DATETIME Removal_DateTime -- DATETIME # Care_Spell_Start_Date # Care_Spell_End_Date -- never non-NULL in our data set # Discharge_HCP -- ??user closing the referral Referred_Consultant_User_title Referred_Consultant_User_first_name Referred_Consultant_User_surname Referred_Consultant_User_email Referred_Consultant_User_Consultant_Flag -- 0, 1, NULL Referral_Staff_History Client_ID -- integer in VARCHAR(15) Start_Date -- DATETIME End_Date -- DATETIME Current_At_Discharge -- INT -- ? -- 1 or NULL HCP_User_title HCP_User_first_name HCP_User_surname HCP_User_email HCP_User_Consultant_Flag -- 0, 1, NULL Referral_Team_History -- similar, but for teams; no individual info Client_ID -- integer in VARCHAR(15) Start_Date -- DATETIME End_Date -- DATETIME Current_At_Discharge -- INT -- ? -- 1 or NULL Team_Code -- NVARCHAR -- e.g. 'TCGMH712' Team_Description -- NVARCHAR -- e.g. 'George Mackenzie' Team_Classification_Group_Code -- NVARCHAR -- e.g. 'FS' Team_Classification_Group_Description -- NVARCHAR -- e.g. 'Forensic Service'
Not obviously relevant:
Client_CPA -- records CPA start/end, etc. Client_Professional_Contacts -- empty table!
Added 2017-02-27:
Client_Communications_History -- email/phone Client_ID -- integer in VARCHAR(15) Method_Code -- NVARCHAR(10); '1' for 'Telephone number', '3' for 'Email address', '4' for 'Minicom/textphone number' Method_Description Context_Code -- e.g. '1' for 'Communication address at home', other codes for 'Vacation home...', etc. Context_Description Contact_Details -- NVARCHAR(80)
- crate_anon.crateweb.consent.lookup_rio.lookup_cpft_rio_rcep(lookup: PatientLookup, decisions: List[str], secret_decisions: List[str]) None [source]
Look up patient details from a RiO database that’s been preprocessed through Servelec’s RCEP (RiO CRIS Extraction Program) tool.
- Parameters:
decisions – list of human-readable decisions; will be modified
secret_decisions – list of human-readable decisions containing secret (identifiable) information; will be modified
RiO notes, 2015-05-19
… ADDENDUM 2017-02-27: this is the RiO database as modified by Servelec’s RiO CRIS Extraction Program (RCEP). See also lookup_cpft_rio_raw().
For speed, RiO-RCEP needs these indexes:
USE my_database_name; CREATE INDEX _idx_cdd_nhs ON Client_Demographic_Details (NHS_Number); CREATE INDEX _idx_cnh_id ON Client_Name_History (Client_ID); CREATE INDEX _idx_cnh_eff ON Client_Name_History (Effective_Date); CREATE INDEX _idx_cnh_end ON Client_Name_History (End_Date_); CREATE INDEX _idx_cah_id ON Client_Address_History (Client_ID); CREATE INDEX _idx_cah_from ON Client_Address_History (Address_From_Date); CREATE INDEX _idx_cah_to ON Client_Address_History (Address_To_Date); CREATE INDEX _idx_cch_id ON Client_Communications_History (Client_ID); CREATE INDEX _idx_cgh_id ON Client_GP_History (Client_ID); CREATE INDEX _idx_cgh_from ON Client_GP_History (GP_From_Date); CREATE INDEX _idx_cgh_to ON Client_GP_History (GP_To_Date); CREATE INDEX _idx_cc_id ON CPA_CareCoordinator (Client_ID); CREATE INDEX _idx_cc_start ON CPA_CareCoordinator (Start_Date); CREATE INDEX _idx_cc_end ON CPA_CareCoordinator (End_Date); CREATE INDEX _idx_ref_id ON Main_Referral_Data (Client_ID); CREATE INDEX _idx_ref_recv ON Main_Referral_Data (Referral_Received_Date); CREATE INDEX _idx_ref_removal ON Main_Referral_Data (Removal_DateTime); CREATE INDEX _idx_rsh_id ON Referral_Staff_History (Client_ID); CREATE INDEX _idx_rsh_start ON Referral_Staff_History (Start_Date); CREATE INDEX _idx_rsh_end ON Referral_Staff_History (End_Date); CREATE INDEX _idx_rth_id ON Referral_Team_History (Client_ID); CREATE INDEX _idx_rth_start ON Referral_Team_History (Start_Date); CREATE INDEX _idx_rth_end ON Referral_Team_History (End_Date); -- CREATE INDEX _idx_rth_teamdesc ON Referral_Team_History (Team_Description); # noqa