DB Schema Analysis
Overall Schema Assessment¶
Strengths:
- Good Granularity: You've broken down complex LIS concepts into logical, manageable tables.
- Clear Relationships: Most foreign keys are correctly identified, establishing necessary links between entities.
- Audit Fields: Consistent inclusion of
CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserIDfor basic auditing is excellent. - External System Focus: Explicit tables like
ExternalSystemsandExternalSystemTestMappingsshow you're thinking about interoperability from the ground up. - Compliance Awareness: Tables like
TestResultVersions,CriticalValueNotificationLog,AuditLogs, andProficiencyTestsindicate a strong focus on regulatory requirements (e.g., CLIA, CAP, 21 CFR Part 11).
General Suggestions:
- Consistent Data Types: Ensure
SMALLDATETIMEis appropriate or considerDATETIME2for higher precision (especially for timestamps like result times, audit logs). - Master/Lookup Table Strategy: Many
VARCHARfields representing controlled vocabularies (e.g.,Gender,PatientClass,OrderPriority,SpecimenType,ResultStatus) would benefit greatly from dedicated lookup tables. This improves data integrity, reporting, and simplifies future mapping to standardized terminologies. I'll highlight these for specific tables. - Indexing: While not explicitly in the schema, ensure unique constraints are backed by unique indexes, and add non-clustered indexes on frequently queried foreign key columns and columns used in
WHEREclauses for performance.
Table-by-Table Analysis & Suggestions¶
1. Patients
- Purpose: Core patient demographic information.
- Suggestions:
SSN: Very sensitive. If stored, ensure encryption at rest. LengthVARCHAR(25)is too long;VARCHAR(11)(allowing hyphens) orVARCHAR(9)(numeric only) with aCHECKconstraint for format is more appropriate. Consider if it's truly required or ifExternalSystemMRNand other identifiers are sufficient for patient matching.Gender: Good, but consider aGenderTypeslookup table (GenderID,Code,Description).PrimaryLanguage,MaritalStatus,RaceCode,EthnicityCode: Strongly recommend dedicated lookup tables for these to ensure data consistency, enforce valid values, and allow for mapping to standardized codes (e.g., HL7, CDC Race/Ethnicity). Store the FK (LanguageID,MaritalStatusID,RaceID,EthnicityID) instead of theVARCHARcode/name directly.LastModifiedByUserID: Should beFOREIGN KEY to Users.UserID. (Apply this general fix to all tables where this applies).- Unique Constraint: Explicitly define the
UNIQUE (ExternalSystemID, ExternalSystemMRN)constraint in your DDL.
2. Visits
- Purpose: Patient visits and encounters.
- Suggestions:
AttendingProviderID,ReferringProviderID: WhileNOT NULLis specified, in real-world scenarios, one of these might be optional (e.g., walk-in patients without a formal referring provider). Reconfirm if both are always mandatory.LocationID,LocationRoom,LocationBed: Consider a hierarchicalLocationsmaster table (LocationID,Name,Type,ParentLocationID,IsActive) to manage hospital units, departments, rooms, and beds centrally. ThenLocationIDcould be a FK to this table.PatientClass: Define aPatientClasseslookup table (PatientClassID,Code,Description).
3. Insurances
- Purpose: Patient insurance details.
- Suggestions:
LISVisitID: Insurance typically applies to a patient, not just a single visit. If insurance can change per visit, this is okay. However, if it's patient-level data, consider makingLISVisitIDnullable, or havingLISPatientIDbe the sole FK and associating insurance with visits via a separate bridge table if needed (e.g.,VisitInsurances).InsurancePlanID,InsuranceCompanyID,InsuranceCompanyName,InsuranceGroupNumber,InsuranceGroupName: Consider dedicated master tables forInsuranceCompaniesandInsurancePlansto centralize insurance definitions and reduce data duplication. Then,InsuranceCompanyIDandInsurancePlanIDwould be FKs to these masters.
4. Allergies
- Purpose: Patient allergy information.
- Suggestions:
LISVisitID: Similar toInsurances, allergies are generally patient-level. MakeLISVisitIDnullable, or remove it and only link toLISPatientID. AnIdentificationDateis good for when it was noted, but the allergy itself persists.AllergyType,AllergyCode,AllergySeverity,AllergyReaction: Excellent candidates for lookup tables to standardize codes and descriptions (e.g.,AllergyTypes,AllergySeverities,AllergyReactions).AllergyCodeshould ideally map to a clinical terminology like SNOMED CT.
6. DXCodes
- Purpose: Diagnosis codes (ICD-10) for patients/visits.
- Suggestions:
DxCode,DxCodeDesc,DxCodeType: Strongly recommend aDiagnosisCodeMasterstable (DxMasterID,Code,Description,CodeTypeID,EffectiveDate,RetiredDate).DxCodewould then be aFOREIGN KEYto this master. This allows for versioning of ICD codes (e.g., ICD-9 vs. ICD-10) and ensuresDescriptionis consistent.DxCodeType: (e.g., 'ICD-10', 'ICD-9') should be a lookup tableDxCodeTypes.
7. LabOrders
- Purpose: Laboratory orders.
- Suggestions:
OrderTransactionDate: Clarify its exact meaning vs.OrderDate. If it's when LIS received the order, rename toLISReceivedDateTime.OrderTestCatalogID: This is the most critical point for this table. An order can include multiple individual tests and/or multiple panels. The current design suggests an order is for a singleTestCatalogID.- Recommendation: Remove
OrderTestCatalogIDfromLabOrders. Instead, create anOrderedTests(orOrderedTestComponents) bridge table:- New Table:
OrderedTestsOrderTestID(INT, PK, IDENTITY)LISOrderID(INT, FK toLabOrders.LISOrderID, NOT NULL)TestCatalogID(INT, FK toTestCatalog.TestCatalogID, NOT NULL)TestPanelID(INT, FK toTestPanels.TestPanelID, NULLABLE): Identifies if this ordered test is part of a panel ordered within the sameLISOrderID.IsPanelTest(BIT, DEFAULT 0): Flag to indicate if this specific test was part of a panel order or ordered individually.OrderedTestStatus(VARCHAR(50)): Status of this specific ordered test (e.g., 'Collected', 'In Progress', 'Finalized').CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserID
- This allows a
LabOrderto contain many individualTestCatalogIDs, some of which might be part of aTestPanelID.
- New Table:
- Recommendation: Remove
OrderStatus,ResultStatus: Use lookup tables for these (OrderStatuses,ResultStatuses).LastModifiedOn: DefaultGETDATE()is problematic for update timestamps; it should be updated on modification, not on creation. Remove the default for this field, and ensure your application logic updates it.
8. OrderDiagnosticCodes
- Purpose: Links diagnostic codes (ICD-10) to lab orders.
- Suggestions:
ICD10Code,Description: Instead, useDxMasterID(INT,FOREIGN KEYto the suggestedDiagnosisCodeMasters.DxMasterID,NOT NULL) to link to the master diagnosis codes. This makesDescriptionredundant here.
9. TestPanels
- Purpose: Defines panels of tests.
- Suggestions:
PanelLOINCCode,PanelCPTCode: Good to have these.- Versioning:
EffectiveDateandRetiredDateare good for basic versioning.
10. TestCatalog
- Purpose: Defines all available tests.
- Suggestions:
TestCategoryID: Missing FK reference. Should beFOREIGN KEY to TestCategories.TestCategoryID.TestPanelID: Remove this field. A test can be part of many panels, and panels can have many tests. This many-to-many relationship is correctly handled byTestPanelComponents. Storing it here creates redundancy and limits flexibility.TestCatalogshould define the atomic test.Units: Create aUnitsOfMeasurelookup table and make thisUnitsID(FOREIGN KEY to UnitsOfMeasure.UnitID).SampleType,ContainerType: CreateSampleTypesandContainerTypeslookup tables.- Reference Ranges (
Ref Ranges along age and Gender levelfrom prompt): You mentionRef Ranges along age and Gender levelin your prompt and haveTestRanges(Table 36/38). TheTestCatalogtable itself should not contain reference ranges.TestRangesshould be the single source for this, withTestCatalogIDas its FK.
11. TestPanelComponents
- Purpose: Links individual tests to panels.
- Suggestions:
- Looks solid. Correctly handles the many-to-many relationship.
12. LISRules
- Purpose: Configurable rules engine for autoverification, reflex testing, etc.
- Suggestions:
RuleType: Create aRuleTypeslookup table.RuleLogic:VARCHAR(MAX)is appropriate. Ensure application enforces valid JSON or scripting language format.
13. Specimens
- Purpose: Tracks individual specimens.
- Suggestions:
- "Version Required": Your note implies a need for history. Instead of
Specimensstoring version, use a dedicated log table for status changes.- Recommendation: Remove
CurrentStatusfromSpecimensand rely on aSpecimenStatusLogtable (see below) to track all changes.Specimens.CurrentStatuswould then be a computed column or derived from the latest entry inSpecimenStatusLog.
- Recommendation: Remove
SpecimenType,ContainerType,CurrentStatus,Priority: Strongly recommend lookup tables for these for consistency.CollectedByUserID,ReceivedByUserID,LastModifiedByUserID: Should beFOREIGN KEY to Users.UserID.CurrentLocation: Consider aLabLocationstable (see below) and make thisLocationID(FOREIGN KEY to LabLocations.LocationID) for better physical tracking.ChainOfCustody:VARCHAR(MAX)for JSON is fine, but if you need to query or report on specific custodian changes, consider a separateChainOfCustodyLogtable to track each transfer.
- "Version Required": Your note implies a need for history. Instead of
14. Aliquots
- Purpose: Tracks derived specimens from a parent specimen.
- Suggestions:
AliquotType: Create anAliquotTypeslookup table.LastModifiedByUserID: Should beFOREIGN KEY to Users.UserID.
15. RejectionReasons
- Purpose: Standardized reasons for specimen rejection.
- Suggestions:
- Looks good. A solid master table.
16. TestResults
- Purpose: Stores the results for each test.
- Strengths: Very detailed and comprehensive.
- Suggestions:
- "Auditing Table Required": You've noted this, and
TestResultVersions(Table 17) is planned. This is crucial.TestResultsshould always hold the current, final, validated result. All changes (corrections, amendments) should trigger an insert intoTestResultVersionsbeforeTestResultsis updated. Units: Should beUnitsID(FOREIGN KEY to UnitsOfMeasure.UnitID, if created).ReferenceRangeLow,ReferenceRangeHigh: These values should be the actual ranges used for the calculation and flagging at the time the result was generated/verified. This is correct to store them here, as ranges can change over time in theTestRangesmaster table.AbnormalFlag,ResultStatus: Create lookup tables for these (AbnormalFlags,ResultStatuses).VerificationUserID,InstrumentID,CreatedByUserID,LastModifiedByUserID: Should beFOREIGN KEY to Users.UserIDandLabInstruments.InstrumentIDrespectively.IsCriticalValue: Good flag.Test Analysis Start and End Date Times: Absolutely essential. Add:AnalysisStartDateTime(DATETIME)AnalysisEndDateTime(DATETIME)- These are vital for calculating analytical turnaround time (TAT).
ResultValue(VARCHAR): While flexible, ifIsResultNumericis1, considerDECIMAL(18,4)for numerical values and a separateTextResult(VARCHAR(MAX)) for textual results (e.g., microscopy observations, culture results). This separation aids in data analysis and querying for numeric vs. non-numeric.
- "Auditing Table Required": You've noted this, and
17. TestResultVersions
- Purpose: For auditing changes to results.
- Suggestions:
- "DROP": NO, DO NOT DROP. This table is extremely important for regulatory compliance (e.g., 21 CFR Part 11) and provides an immutable audit trail.
- Completeness: This version table should capture a full snapshot of all fields in
TestResultsthat can change. This includesResultValue,Units,ReferenceRangeLow,ReferenceRangeHigh,AbnormalFlag,ResultStatus,VerificationUserID,ResultDateTime,VerificationDateTime,IsAutoverified,AutoverificationRulesApplied,InstrumentID,ResultComments,IsCriticalValue, and the newly suggestedAnalysisStartDateTime/EndDateTime.
18. CriticalValueNotificationLog
- Purpose: Documents critical value notifications.
- Suggestions:
NotifiedProviderID: Correct FK toProviders.LoggedByUserID: Should beFOREIGN KEY to Users.UserID.NotificationMethod,NotificationStatus: Create lookup tables for these (NotificationMethods,NotificationStatuses).
19. QualityControls
- Purpose: Records daily QC runs and their results.
- Suggestions:
ControlLotNumber: Consider linking this to aControlLotsmaster table (see missing tables) to manage control reagent inventory and expiration dates.ControlLevel: Create aControlLevelslookup table.WestgardRuleBreach: Create aWestgardRuleslookup table.PerformedByUserID: Should beFOREIGN KEY to Users.UserID.CorrectiveActions,RootCauseAnalysis:VARCHAR(MAX)is fine. If you need structured tracking of multiple actions, a childQCCorrectiveActionstable could be considered.
20. ProficiencyTests
- Purpose: Tracks proficiency testing samples and scores.
- Suggestions:
PTProgram: Create aPTProgramslookup table.ExpectedResult,ActualResult: Ensure data type is consistent withTestResults.ResultValue(e.g.,DECIMALif numeric,VARCHARotherwise).PerformedByUserID: Should beFOREIGN KEY to Users.UserID.
21. LabInstruments
- Purpose: Details of integrated laboratory instruments.
- Suggestions:
Location,SubLocation: Consider these asFOREIGN KEYto aLabLocationstable (see missing tables) for hierarchical lab area management.DeviceType: Create aDeviceTypeslookup table.InterfaceProtocol: Create anInterfaceProtocolslookup table.IPAddress: UseVARCHAR(45)for IPv6 compatibility.Middleware: If middleware systems are distinct entities, create aMiddlewareSystemsmaster table (see missing tables) and make thisMiddlewareID(FOREIGN KEY).- Add audit fields:
CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserID.
22. InstrumentTestMappings
- Purpose: Maps LIS internal test codes to instrument-specific codes.
- Suggestions:
- Composite Unique Key: Add a
UNIQUE CONSTRAINT (InstrumentID, TestCatalogID, InstrumentTestCode)to ensure uniqueness for each mapping. - Add audit fields:
CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserID.
- Composite Unique Key: Add a
23. ExternalSystemOtherMappings
- Purpose: For mapping codes between LIS and external systems (EMR, billing).
- Suggestions:
- "Not Needed / Delete": NO, DO NOT DELETE. This table is essential for general data mapping (e.g., Patient Class, Admit Source, Race, Ethnicity, Custom Order Types, Result Interpretation) that isn't specific to test codes.
- Naming: Consider renaming to
ExternalSystemVocabularyMappingsorGeneralExternalMappingsfor clarity. MappingType: Create aMappingTypeslookup table.- Add audit fields:
CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserID.
24. Users
- Purpose: Stores user credentials and links to roles for RBAC.
- Suggestions:
CreatedByUserID: This FK to itself can be problematic for the very first user. You might need to handle initial user creation outside this FK constraint or allow it to be nullable for the first record.- Password Storage: Emphasize the use of strong hashing algorithms (e.g., bcrypt, Argon2) and proper salt generation.
- Security: Consider adding fields like
IsLockedOut(BIT),FailedLoginAttempts(INT),LastPasswordChangeDate(DATETIME).
25. Roles
- Purpose: Defines different user roles.
- Suggestions:
- Looks good.
26. UserRoles
- Purpose: Links users to their assigned roles (many-to-many relationship).
- Suggestions:
- Composite Primary Key: Add a
PRIMARY KEY (UserID, RoleID)orUNIQUE CONSTRAINT (UserID, RoleID)to enforce that a user can only have a specific role once.UserRoleIDas identity is fine, but the combination is key for uniqueness.
- Composite Primary Key: Add a
27. Permissions
- Purpose: Defines granular permissions within the system.
- Suggestions:
- Looks good.
28. RolePermissions
- Purpose: Assigns permissions to roles.
- Suggestions:
- Composite Primary Key: Add a
PRIMARY KEY (RoleID, PermissionID)orUNIQUE CONSTRAINT (RoleID, PermissionID).
- Composite Primary Key: Add a
29. AuditLogs
- Purpose: Comprehensive and immutable logging of all system activities.
- Suggestions:
LogDateTime: ConsiderDATETIME2(7)for higher precision.UserID:NULLABLEis correct for system-generated events.OldValue,NewValue:VARCHAR(MAX)for JSON is good.- Performance: This table will grow very large. Ensure proper indexing on
LogDateTime,UserID,ActivityType,TableName,RecordID. Plan for data archiving/purging strategy.
30. Providers
- Purpose: Stores information about referring physicians and other clinicians.
- Suggestions:
ProviderType: Create aProviderTypeslookup table.NPI:VARCHAR(10)andUNIQUEis correct for NPI.- Degrees/Specialties: Consider a
ProviderSpecialtiesbridge table if you need to track multiple specialties or degrees. - Affiliation: Add
OrganizationID(FOREIGN KEYto a newOrganizationsmaster table) if providers are associated with specific institutions.
31. ArchivedReports
- Purpose: For storing final reports and ensuring long-term retention.
- Suggestions:
LISVisitID: The foreign key reference is missing in your description. It should beFOREIGN KEY to Visits.LISVisitID, NOT NULL.ReportType,ReportFormat: Create lookup tables for these.StorageLocation: If it's a URL, useVARCHAR(2048)for max URL length.RetentionPolicyEndDate: Good for compliance.IndexedFields:VARCHAR(MAX)for JSON is a good flexible approach for key-value search.
32. StorageLocations
- Purpose: Manages physical specimen storage locations.
- Suggestions:
LocationType: Create aLocationTypeslookup table.- Hierarchy: If you need to manage locations hierarchically (e.g., Freezer A > Shelf 1 > Rack 2), add
ParentLocationID(SMALLINT,FOREIGN KEYtoStorageLocations.LocationID,NULLABLE). - Add audit fields:
CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserID.
33. SpecimenStorageLog
- Purpose: Tracks precise specimen positions and retrieval history.
- Suggestions:
ActionType: Create aStorageActionTypeslookup table.CurrentStabilityStatus: Create aSpecimenStabilityStatuseslookup table.
34. TableMetaData
- Purpose: Stores metadata about tables and columns.
- Suggestions:
- Composite Unique Key: Add a
UNIQUE CONSTRAINT (TableName, ColumnName). - Add audit fields:
LastModifiedOn,LastModifiedByUserID.
- Composite Unique Key: Add a
35. ExternalSystems
- Purpose: Defines each external system your LIS interacts with.
- Suggestions:
SystemType,CommunicationMode,Direction,APIAuthType: Create lookup tables for these.ReceivingApplication: Clarify its exact use. If it refers to an internal component or Mirth channel, that's fine.- Address Fields: As noted, add
Address1,Address2,City,State,ZipCode,Country. - Add audit fields:
CreatedOn,CreatedByUserID. (You haveLastUpdated, rename it toLastModifiedOnfor consistency).
36. ExternalSystemTestMappings (Renamed from original Table 36/37 for clarity)
- Purpose: Links Infinity LIS Test with External Systems Tests.
- Suggestions:
- Composite Unique Key: Add
UNIQUE CONSTRAINT (TestCatalogID, ExternalSystemId, ExternalSystemTestCode)to enforce uniqueness for the mapping. - Add audit fields:
CreatedOn,CreatedByUserID. (You haveLastModifiedOnandLastModifiedByUserID, good).
- Composite Unique Key: Add
37. TestRanges (Renamed from original Table 36/38 for clarity)
- Purpose: Reference lab high and low ranges for each test.
- Suggestions:
- Precision:
DECIMAL(10, 2)might not be enough precision for all lab values. ConsiderDECIMAL(18, 4)or higher if very small or very large values with many decimal places are expected. Gender: If you created aGenderTypeslookup table forPatients, useGenderID(FOREIGN KEY to GenderTypes.GenderID).- Add audit fields:
CreatedOn,CreatedByUserID,LastModifiedOn,LastModifiedByUserID. - Reference Range Versions: The
EffectiveDateandRetiredDateare good for basic versioning of ranges.
- Precision:
Suggested Missing Tables¶
Based on common LIS functionalities and your discussed workflow, here are some tables that might be beneficial:
-
TestCategories(Master Table)TestCategoryID(INT, PK, IDENTITY)CategoryName(VARCHAR(100), NOT NULL, UNIQUE): e.g., 'Hematology', 'Chemistry', 'Microbiology'Description(VARCHAR(255))IsActive(BIT, DEFAULT 1)- Used as FK for
TestCatalog.TestCategoryID.
-
UnitsOfMeasure(Master Table)UnitID(INT, PK, IDENTITY)UnitCode(VARCHAR(20), NOT NULL, UNIQUE): e.g., 'mg/dL', 'g/L', 'IU/mL'Description(VARCHAR(100))IsActive(BIT, DEFAULT 1)- Used as FK for
TestCatalog.UnitsandTestResults.Units.
-
LabLocations(Master Table)LocationID(INT, PK, IDENTITY)LocationName(VARCHAR(100), NOT NULL): e.g., 'Chemistry Lab', 'Hematology Workstation 1', 'Sample Receiving'LocationType(VARCHAR(50)): e.g., 'Department', 'Workstation', 'Processing Area' (FK toLocationTypeslookup)ParentLocationID(INT, FK toLabLocations.LocationID, NULLABLE): For hierarchical structure.IsActive(BIT, DEFAULT 1)- Used as FK for
LabInstruments.LocationIDandSpecimens.CurrentLocation. This is distinct fromStorageLocations(for freezers/refrigerators).
-
SpecimenStatusLog(Transactional Table)StatusLogID(BIGINT, PK, IDENTITY)SpecimenID(INT, FK toSpecimens.SpecimenID, NOT NULL)Status(VARCHAR(50), NOT NULL): e.g., 'Collected', 'Received', 'In Process', 'Rejected', 'Archived' (FK toSpecimenStatuseslookup)StatusDateTime(DATETIME, NOT NULL)ChangedByUserID(SMALLINT, FK toUsers.UserID, NOT NULL)Reason(VARCHAR(MAX), NULLABLE): e.g., rejection reason, notes on status change.- This provides a full audit trail of a specimen's lifecycle.
-
ControlLots(Master/Inventory Table)ControlLotID(INT, PK, IDENTITY)ControlName(VARCHAR(100), NOT NULL)LotNumber(VARCHAR(50), NOT NULL, UNIQUE)Manufacturer(VARCHAR(100))ExpirationDate(DATE)IsActive(BIT, DEFAULT 1)- Used as FK for
QualityControls.ControlLotNumber.
-
InstrumentMaintenanceLog(Transactional Table)MaintenanceLogID(BIGINT, PK, IDENTITY)InstrumentID(INT, FK toLabInstruments.InstrumentID, NOT NULL)MaintenanceType(VARCHAR(50), NOT NULL): e.g., 'Preventative', 'Corrective', 'Calibration' (FK toMaintenanceTypeslookup)MaintenanceDateTime(DATETIME, NOT NULL)PerformedByUserID(SMALLINT, FK toUsers.UserID, NOT NULL)Description(VARCHAR(MAX))DowntimeStart,DowntimeEnd(DATETIME, NULLABLE): If instrument was offline.ResolutionNotes(VARCHAR(MAX))PartsUsed(VARCHAR(MAX)): JSON or delimited string.
-
MiddlewareSystems(Master Table)MiddlewareID(SMALLINT, PK, IDENTITY)SystemName(VARCHAR(100), NOT NULL)Vendor(VARCHAR(100))Version(VARCHAR(50))IsActive(BIT, DEFAULT 1)- If you use middleware,
LabInstruments.Middlewarewould becomeMiddlewareID(FK).
-
MessageLogs(Transactional Table)MessageLogID(BIGINT, PK, IDENTITY)ExternalSystemID(SMALLINT, FK toExternalSystems.ExternalSystemID, NOT NULL)MessageType(VARCHAR(50), NOT NULL): e.g., 'ADT', 'ORM', 'ORU'Direction(VARCHAR(20), NOT NULL): 'Inbound', 'Outbound'MessageContent(VARCHAR(MAX), NULLABLE): Raw HL7 message (consider encryption/compression).ProcessingStatus(VARCHAR(50), NOT NULL): 'Received', 'Parsed', 'Error', 'Queued', 'Sent', 'Acknowledged'ErrorDetails(VARCHAR(MAX), NULLABLE)MessageDateTime(DATETIME, NOT NULL)TransactionIdentifier(VARCHAR(100), NULLABLE): For linking related inbound/outbound messages (e.g., HL7 Message Control ID).- This is for interface-level logging, distinct from
AuditLogs.
Summary of Key Recommendations and Next Steps:¶
- Implement Master/Lookup Tables: This is the single most impactful change for data quality and consistency. Go through all
VARCHARfields that represent fixed sets of values and create dedicated lookup tables for them. - Refine Test/Order Relationship: Implement the
OrderedTeststable as suggested, and removeTestPanelIDfromTestCatalog. This will correctly model complex orders. - Enhance Result/Specimen Auditing: Keep
TestResultVersionsand ensure it captures a full snapshot. ImplementSpecimenStatusLogfor granular status tracking. - Add Analysis Timestamps: Include
AnalysisStartDateTimeandAnalysisEndDateTimeinTestResultsfor accurate TAT measurement. - Data Type Review: Reconfirm
DECIMALprecision for all numeric results/ranges andVARCHARlengths (especially for IP addresses to support IPv6). - "ExternalSystemOtherMappings": RETITLE and RETAIN. It's essential for general mapping.
- Consider New Tables: Evaluate the suggested missing tables (
TestCategories,UnitsOfMeasure,LabLocations,ControlLots,InstrumentMaintenanceLog,MiddlewareSystems,MessageLogs) to see which align with your immediate and future scope.