:root{color-scheme:light;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}html{scroll-padding-top:env(safe-area-inset-top,0px)}body{margin:0;padding:0;font:14px -apple-system,BlinkMacSystemFont,sans-serif;background:#fff;color:#000}img{max-width:100%}[hidden]:not([hidden=until-found i]){display:none!important} Health PMI Build Guide /* Layout: one column of table sections in load order; each section flows source -> build -> result, top to bottom. */ :root { –bg: #f4f7f8; –surface: #ffffff; –ink: #16212a; –muted: #56646f; –line: #d3dce2; –spine: #8fa6b3; –accent: #0f5f72; –accent-bg: #e2f0f3; –src: #6b5a3e; –src-bg: #f6f1e8; –hl: #e3ecf9; –create: #17734c; –create-bg: #e1f2e9; –look: #2457a3; –tbc: #9a3d3d; –tbc-bg: #f7e5e5; –sans: “IBM Plex Sans”, “Segoe UI”, Helvetica, Arial, sans-serif; –mono: “IBM Plex Mono”, ui-monospace, “SFMono-Regular”, Menlo, Consolas, monospace; } @media (prefers-color-scheme: dark) { :root:not([data-theme=”light”]) { –bg: #0e1418; –surface: #161f26; –ink: #e2e9ee; –muted: #9babb7; –line: #2a3843; –spine: #4b6271; –accent: #6cc3d6; –accent-bg: #15313a; –src: #d8c39c; –src-bg: #2a241a; –hl: #1b2f4d; –create: #62cf9c; –create-bg: #14362a; –look: #86b4f6; –tbc: #f0a0a0; –tbc-bg: #3a1d1d; color-scheme: dark } } :root[data-theme=”dark”] { –bg: #0e1418; –surface: #161f26; –ink: #e2e9ee; –muted: #9babb7; –line: #2a3843; –spine: #4b6271; –accent: #6cc3d6; –accent-bg: #15313a; –src: #d8c39c; –src-bg: #2a241a; –hl: #1b2f4d; –create: #62cf9c; –create-bg: #14362a; –look: #86b4f6; –tbc: #f0a0a0; –tbc-bg: #3a1d1d; color-scheme: dark } body { background: var(–bg); color: var(–ink); font-family: var(–sans); font-size: 15px; line-height: 1.55; } .wrap { max-width: 1100px; margin: 0 auto; padding-inline: 20px; padding-block: 28px 64px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 28px; } .wrap > * { min-width: 0; } h1 { font-size: 1.8rem; line-height: 1.2; margin: 0; letter-spacing: -0.01em; text-wrap: balance; } h2 { font-size: 1.3rem; line-height: 1.25; margin: 0; text-wrap: balance; } h3 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(–muted); margin: 0 0 10px; display: flex; align-items: center; gap: 10px; } p { margin: 0; max-width: 75ch; } .lede { display: grid; gap: 10px; } .lede p:first-of-type { font-size: 1.02rem; } .small { font-size: 0.86rem; color: var(–muted); } code { font-family: var(–mono); font-size: 0.85em; background: var(–accent-bg); color: var(–ink); padding: 1px 5px; border-radius: 4px; overflow-wrap: anywhere; } /* how to read */ .howto { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; } .how { display: flex; gap: 12px; align-items: flex-start; background: var(–surface); border: 1px solid var(–line); border-radius: 10px; padding: 12px 14px; min-width: 0; } .how > div { display: grid; gap: 3px; min-width: 0; } .how span:not(.pn):not(.id):not(.empty):not(.tbcv) { color: var(–muted); font-size: 0.9rem; } .pn { flex: none; width: 24px; height: 24px; border-radius: 50%; display: inline-grid; place-items: center; font: 600 0.8rem/1 var(–mono); color: var(–surface); background: var(–accent); } /* chips and cell states */ .id { font: 600 0.82rem/1 var(–mono); padding: 3px 8px; border-radius: 999px; white-space: nowrap; display: inline-block; } .id.new { color: var(–create); background: var(–create-bg); border: 1.5px solid var(–create); } .id.ref { color: var(–look); background: transparent; border: 1.5px dashed var(–look); } .empty { color: var(–muted); } .tbcv { color: var(–tbc); background: var(–tbc-bg); font: 600 0.75rem/1 var(–sans); padding: 3px 6px; border-radius: 4px; letter-spacing: 0.04em; } /* map */ .mapwrap { display: grid; gap: 8px; } .mapscroll { background: var(–surface); padding: 10px; } .narrow-only { display: none; } .map { display: block; width: 100%; min-width: 860px; height: auto; } .map rect { fill: var(–bg); stroke: var(–spine); stroke-width: 1.2; } .map .bt { fill: var(–ink); font: 600 13px var(–mono); } .map .bc { fill: var(–muted); font: 400 11.5px var(–sans); } .map .ln { stroke: var(–spine); stroke-width: 1.5; } .map .ahp { fill: var(–spine); } .map .lb { fill: var(–muted); font: 500 11.5px var(–sans); paint-order: stroke; stroke: var(–surface); stroke-width: 5px; stroke-linejoin: round; } .map .self { font-style: italic; } /* table of contents */ .toc { display: flex; flex-wrap: wrap; gap: 8px; } .toc a { text-decoration: none; color: var(–ink); background: var(–surface); border: 1px solid var(–line); border-radius: 8px; padding: 6px 10px; display: inline-flex; gap: 8px; align-items: center; font-weight: 500; font-size: 0.92rem; } .toc a b { font: 600 0.78rem/1 var(–mono); color: var(–accent); } .toc a:hover, .toc a:focus-visible { border-color: var(–accent); outline: none; } /* entity sections */ .ent { background: var(–surface); border: 1px solid var(–line); border-radius: 12px; padding: 20px 22px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; scroll-margin-top: 16px; } .ent > * { min-width: 0; } .ent-head { display: grid; gap: 4px; padding-bottom: 6px; border-bottom: 1px solid var(–line); } .ent-head p { color: var(–muted); } .stepno { font: 600 0.72rem/1 var(–sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(–accent); } .part { display: grid; gap: 10px; padding-top: 8px; min-width: 0; } .down { color: var(–spine); font-size: 1.3rem; line-height: 1; padding-left: 4px; } .plain { color: var(–muted); font-size: 0.92rem; } /* tables */ .tbl { display: grid; gap: 4px; min-width: 0; justify-items: start; } .tbl > * { max-width: 100%; } .tname { font: 600 0.8rem/1.2 var(–mono); color: var(–src); letter-spacing: 0.02em; } .tname.res { color: var(–accent); font-size: 0.85rem; } .tnote { font-size: 0.86rem; color: var(–muted); } .scroll { overflow-x: auto; border: 1px solid var(–line); border-radius: 8px; } table { border-collapse: collapse; font-variant-numeric: tabular-nums; } th, td { text-align: left; padding: 6px 9px; border-bottom: 1px solid var(–line); vertical-align: top; white-space: nowrap; } tbody tr:last-child td { border-bottom: 0; } .srct thead th { background: var(–src-bg); color: var(–src); font: 500 0.72rem/1.3 var(–mono); } .srct td { font: 400 0.85rem/1.4 var(–mono); } .srct td.hl { background: var(–hl); } .rest thead th { background: var(–accent-bg); vertical-align: bottom; } .rest th .cn { display: block; font: 600 0.74rem/1.3 var(–mono); color: var(–ink); } .rest th .kk { display: inline-block; margin-top: 4px; font: 600 0.66rem/1 var(–sans); letter-spacing: 0.04em; padding: 3px 5px; border-radius: 4px; } .rest th .kk.pk { color: var(–create); background: var(–create-bg); } .rest th .kk.fk { color: var(–look); border: 1px dashed var(–look); } .rest td { font: 400 0.86rem/1.4 var(–mono); } .tbl + .tbl { margin-top: 10px; } /* build steps and facts */ .build { margin: 0; padding-left: 1.4em; display: grid; gap: 6px; max-width: 90ch; } .build li::marker { font: 600 0.85rem var(–mono); color: var(–accent); } .facts { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; margin-top: 6px; } .fact { display: flex; gap: 10px; align-items: flex-start; background: var(–bg); border-radius: 8px; padding: 10px 12px; min-width: 0; } .fact > div, .fact ul { min-width: 0; } .fact .lab { flex: none; font: 600 0.68rem/1 var(–sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(–accent); padding-top: 4px; width: 42px; } .fact b { display: block; font-weight: 600; } .fact .eg { display: block; font: 400 0.84rem/1.4 var(–mono); color: var(–muted); overflow-wrap: anywhere; } .fact ul { margin: 0; padding-left: 1.1em; display: grid; gap: 3px; font-size: 0.93rem; } .open { font-size: 0.88rem; color: var(–muted); border-top: 1px dashed var(–line); padding-top: 10px; margin-top: 4px; max-width: none; } .open b { color: var(–tbc); } @media (max-width: 760px) { .howto, .facts { grid-template-columns: minmax(0, 1fr); } .ent { padding: 16px 14px; } h1 { font-size: 1.5rem; } .narrow-only { display: block; } } @media (prefers-reduced-motion: no-preference) { .toc a { transition: border-color .15s ease; } } .norows { color: var(–muted); font-family: var(–sans); font-style: italic; white-space: normal; }

Health PMI Build Guide

How each Health PMI ODS table is filled from GMS and ACPM. Every table is shown in three parts: what the source file sends, how the ODS builds each row, and what the finished table holds.

Two example policies run through every table: 001BZB, a family with one primary member and a partner, and 520417, a group policy with two primary members, each with their own dependants.

All values are made-up examples. IDs are shown as short labels (C1, R2…); in the ODS each one is a generated unique identifier. Table and column names are illustrative: the LDM name in capitals with underscores. Logic as in LDD v0.8.

1
What the source sendsThe file as it arrives. Blue cells are the values used to build the key.
2
How the ODS builds each rowThe steps in order, the key that makes each row unique, and what the row links to.
3
What the table holdsThe finished rows. C1 is this table’s own ID; C1 is a link to another table; — is empty; TBC has no source yet.

How the tables connect

Arrows point from a table to the tables that link to it. “1 : 0 or many” means one row on the first table can have no rows, one row or many rows on the second; “1 : 0 or 1” means at most one.

PMI_POLICYsame ID as PMI_CONTRACTPMI_SCHEMEsame ID as PMI_CONTRACTPMI_CONTRACTfrom GMS_POLICYCATEGORYfrom GMS_MEMCOVCONTRACT_ROLE_PHONE_NUMBERfrom GMS_MEMBFILECONTRACT_ROLE_EMAIL_ADDRESSfrom GMS_BDPRCNAK1_MEMBERPMI_CONTRACT_ROLEfrom GMS_MEMBFILE + GMS_POLICYMEMBER_COVERfrom GMS_MEMCOVADDRESSfrom GMS_BDPRCNAK1_MEMBERCONTRACT_ROLE_ADDRESSfrom GMS_BDPRCNAK1_MEMBERCLAIMfrom ACPM_THI_CLAIM1 : 0 or 11 : 0 or 11 : 0 or many1 : 0 or many1 : 0 or many1 : 0 or many1 : 0 or many1 : 0 or many1 : 0 or many1 : many1 : 0 or many1 : 0 or manya dependant links to its primary member

Scroll sideways to see the whole map.

1PMI Contract2PMI Policy and PMI Scheme3Category4PMI Contract Role5Member Cover6Address7Contract Role Address8Contract Role Phone Number9Contract Role Email Address10Claim
Load step 1 of 10

PMI Contract

One row for each policy (case) in GMS. A renewal does not create a new row.

1What the source sends

GMS_POLICY

The policy file: one row per policy.

CASE_NOSTATUSEFFECTIVE_DATESTATUS_DT
001BZBAC2006120120061201
520417AC2019030120190301

2How the ODS builds each row

  1. Take each policy in GMS_POLICY. Here there are two: 001BZB and 520417.
  2. Create the Contract ID from ‘GMS’ + CASE_NO: 001BZB gives C1, 520417 gives C2. This is the only place a Contract ID is created.
  3. Copy CASE_NO as the Policy Identifier, kept as text so leading zeros stay.
  4. Set Policy Admin System to ‘GMS’.
  5. Contract Type: Scheme if CASE_NO starts with 95, 96 or 98; otherwise Policy. Both examples are policies.
  6. Copy STATUS as the Contract Status and EFFECTIVE_DATE as the Effective Date.
  7. End Date: if STATUS is TM (terminated), use STATUS_DT; otherwise leave it empty. Both examples are active (AC), so End Date is empty.
Key
Policy Admin System + Policy IdentifierExample: 'GMS' + 520417
Links
  • Top of the model: it links to nothing above it.
  • A contract can have none, one or many categories, and none, one or many roles.
  • Each contract is either one PMI Policy or one PMI Scheme.

3What the table holds

PMI_CONTRACT
CONTRACT_IDPKPOLICY_IDENTIFIERPOLICY_ADMIN_SYSTEMCONTRACT_TYPECONTRACT_STATUSEFFECTIVE_DATEEND_DATE
C1001BZBGMSPolicyAC2006-12-01—
C2520417GMSPolicyAC2019-03-01—

Still open: Whether GMS end dates are the last day covered or the first day not covered (Q-43).

Load step 2 of 10

PMI Policy and PMI Scheme

Each contract is either a policy or a scheme, never both. These tables reuse the contract’s ID.

1What the source sends

No separate file. Built from the PMI Contract rows above, which come from GMS_POLICY.

2How the ODS builds each row

  1. Each PMI Contract with Contract Type = Policy gets a PMI Policy row with the same Contract ID: C1 and C2.
  2. Each PMI Contract with Contract Type = Scheme gets a PMI Scheme row with the same Contract ID. Neither example is a scheme; a contract whose number starts with 95, 96 or 98 (for example 950417) would go here.
  3. Scheme Name: no source found yet, so it stays empty.
Key
Contract ID: the same ID as PMI Contract; no new ID is madeExample: C1 (001BZB), C2 (520417)
Links
  • Each row is exactly one PMI Contract.
  • A contract has one row in PMI Policy or one row in PMI Scheme, never both.

3What the table holds

PMI_POLICY
CONTRACT_IDPK, FK → PMI_CONTRACT
C1
C2
PMI_SCHEME
CONTRACT_IDPK, FK → PMI_CONTRACTSCHEME_NAME
No rows in this example: neither contract is a scheme.

Still open: Where the scheme name is held (Q-07).

Load step 3 of 10

Category

One row for each plan code + plan code version used on a contract.

1What the source sends

GMS_MEMCOV

The member cover file. A member’s cover is a period during which that member holds one plan code + version. This file has one row for each cover period: which policy and member, which plan code and version, and the start and end dates. It is the only GMS file where the policy, plan code and version sit together.

MEMBPCD_POLICY_NOMEMBPCD_MEMBER_NOMEMBPCD_PLAN_CODEMEMBPCD_PLAN_CODE_VERSIONMEMBPCD_START_DATEMEMBPCD_END_DATE
001BZB00000110074A012024012220250122
001BZB00000110086K032025012259990101
001BZB00000120086K032025012259990101
52041700000110091B022019030159990101
52041700000120091B022019030159990101
52041700000210093C012021060159990101
52041700000220093C012021060159990101
52041700000230093C012022091559990101

2How the ODS builds each row

  1. Read the cover rows in GMS_MEMCOV. Each row is one member holding one plan code + version for a period.
  2. Keep one row for each distinct policy + plan code + version. Here 001BZB has 74A / 01 and 86K / 03; 520417 has 91B / 02 and 93C / 01.
  3. Find the contract using the policy number on the cover row: ‘GMS’ + MEMBPCD_POLICY_NO finds the Contract ID created in step 1, C1 or C2.
  4. Create the Category ID from ‘GMS’ + policy + plan code + version: K1 for 001BZB 86K / 03, K2 for 001BZB 74A / 01, K3 for 520417 91B / 02, K4 for 520417 93C / 01.
Key
Contract ID + Plan Code + Plan Code VersionExample: 'GMS' + 520417 + 93C + 01
Links
  • Belongs to one PMI Contract. A contract can have none, one or many categories.
  • A category can be linked to none, one or many roles. K2 has none today: nobody holds 74A / 01 any more.

3What the table holds

CATEGORY
CATEGORY_IDPKCONTRACT_IDPK, FK → PMI_CONTRACTPLAN_CODEPLAN_CODE_VERSION
K1C186K03
K2C174A01
K3C291B02
K4C293C01

Still open: A plan code set up on a policy but used by no member does not appear (Q-32).

Load step 4 of 10

PMI Contract Role

One row for each member on a contract (for as long as they keep one member number), plus one row for each contract’s Policyholder.

1What the source sends

GMS_MEMBFILE

The member file: one row per member record. Each row has its own copy of the member’s policy number, in MIS_MEMBER_CASE_NO.

MIS_MEMBER_CASE_NOMIS_MEMBER_NOMIS_MEMBER_STATUSMIS_MEMBER_EFF_DTMIS_MEMBER_CANC_DT
001BZB000001100AC2024012299999999
001BZB000001200AC2025012299999999
520417000001100AC2019030199999999
520417000001200AC2019030199999999
520417000002100AC2021060199999999
520417000002200AC2021060199999999
520417000002300AC2022091599999999
How to read a member number

9 digits: the first 6 are the family (one family per primary member), the last 3 the relationship. GMS often shows them without the leading zeros.

MIS_MEMBER_NOOften shown asFamilyRelationshipMeaning
0000011001100000001100First family: the primary member
0000012001200000001200First family: the partner
0000021002100000002100Second family: another primary member (on a group policy, another employee)
0000022002200000002200Second family: the partner
0000023002300000002300Second family: a child

Relationship codes: 1xx primary member, 2xx partner, 3xx child. Partners and children are dependants of the primary member in their family.

GMS_POLICY

Used only for the Policyholder rows.

CASE_NO
001BZB
520417

The members’ covers in GMS_MEMCOV (Category section) are used to find each member’s current Category.

2How the ODS builds each row

  1. Take each member record in GMS_MEMBFILE.
  2. Find the member’s contract. The member file has its own copy of the policy number, MIS_MEMBER_CASE_NO. Put ‘GMS’ in front of it and look it up in PMI Contract, which was built from GMS_POLICY in step 1: ‘GMS’ + 001BZB finds C1; ‘GMS’ + 520417 finds C2. Nothing about the members is read from GMS_POLICY.
  3. Create the PMI Contract Role ID from ‘GMS’ + MIS_MEMBER_CASE_NO + MIS_MEMBER_NO, one per member record: R1, R2, R4, R5, R6, R7, R8. Member number 000001100 is on both policies; the policy number keeps them apart (R1 and R4).
  4. Work out the role type from the last 3 digits of the member number: 1xx Primary Member, 2xx Partner, 3xx Child.
  5. Copy MIS_MEMBER_NO as the Membership Number and MIS_MEMBER_STATUS as the Membership Status.
  6. Start Date = MIS_MEMBER_EFF_DT. End Date = MIS_MEMBER_CANC_DT; 99999999 means no end date, so it stays empty.
  7. Link each dependant to their primary member: same policy, same family (first 6 digits), relationship 100. On 520417, 000002300 (child) and 000002200 (partner) both point to 000002100, R6.
  8. Link to the Category of the member’s cover in force today, from GMS_MEMCOV. On 520417 the second family is on 93C / 01, so K4.
  9. Give each member record an interim Party ID, P1 to P7, until the Party domain exists.
  10. Add one Policyholder row per contract from GMS_POLICY: R0 for 001BZB and R3 for 520417. Administrator rows follow once a source is found.
Key
Members: Contract ID + Member Number. Policyholder or Administrator: Contract ID + Role TypeExample: 'GMS' + 520417 + 000002300
Links
  • Belongs to one PMI Contract. A contract can have none, one or many roles.
  • Can point to one Category (the cover in force today). A Policyholder has none.
  • A dependant points to its primary member’s role, in the same table.
  • Has one interim Party ID (members only, for now).

3What the table holds

PMI_CONTRACT_ROLE
PMI_CONTRACT_ROLE_IDPKCONTRACT_IDFK → PMI_CONTRACTCATEGORY_IDFK → CATEGORYPRIMARY_PMI_CONTRACT_ROLE_IDFK → PMI_CONTRACT_ROLEPARTY_IDFK → PARTY (interim)PMI_CONTRACT_ROLE_TYPEMEMBERSHIP_NUMBERMEMBERSHIP_STATUSSTART_DATEEND_DATE
R0C1——TBCPolicyholder——TBCTBC
R1C1K1—P1Primary Member000001100AC2024-01-22—
R2C1K1R1P2Partner000001200AC2025-01-22—
R3C2——TBCPolicyholder——TBCTBC
R4C2K3—P3Primary Member000001100AC2019-03-01—
R5C2K3R4P4Partner000001200AC2019-03-01—
R6C2K4—P5Primary Member000002100AC2021-06-01—
R7C2K4R6P6Partner000002200AC2021-06-01—
R8C2K4R6P7Child000002300AC2022-09-15—

Still open: Where the Administrator and the Policyholder’s dates come from (Q-05); a policy + member number held under two billing units (Q-25); the meaning of codes 201-206 and 301-315 (Q-06).

Load step 5 of 10

Member Cover

One row for each cover period of a member: plan code + version + start date.

1What the source sends

GMS_MEMCOV

Same member cover rows as in the Category section: one row per cover period.

MEMBPCD_POLICY_NOMEMBPCD_MEMBER_NOMEMBPCD_PLAN_CODEMEMBPCD_PLAN_CODE_VERSIONMEMBPCD_START_DATEMEMBPCD_END_DATE
001BZB00000110074A012024012220250122
001BZB00000110086K032025012259990101
001BZB00000120086K032025012259990101
52041700000110091B022019030159990101
52041700000120091B022019030159990101
52041700000210093C012021060159990101
52041700000220093C012021060159990101
52041700000230093C012022091559990101
GMS_MEMBER

Used for the underwriting type, held once per member record.

CASE_NOMEMBER_NOMEMB_UW_TYPE
001BZB000001100NMORI
001BZB000001200NMORI
520417000001100MHD
520417000001200MHD
520417000002100MHD
520417000002200MHD
520417000002300MHD

2How the ODS builds each row

  1. Each GMS_MEMCOV row is one cover period: one member holding one plan code + version from a start date.
  2. Find the member’s role using the cover row’s own policy and member number: ‘GMS’ + MEMBPCD_POLICY_NO + MEMBPCD_MEMBER_NO finds the role created in step 4. For example 520417 + 000002300 finds R8.
  3. Create the Member Cover ID from the role + plan code + version + start date: M0, M1, M2, M3, M4, M5, M6, M7.
  4. Copy plan code, version and start date. End Date = MEMBPCD_END_DATE; 59990101 means no end date, so it stays empty.
  5. Underwriting Type comes from GMS_MEMBER for the same policy + member number, so every cover of that member shows the same value.
Key
PMI Contract Role ID + Plan Code + Plan Code Version + Start DateExample: R8 + 93C + 01 + 2022-09-15
Links
  • Belongs to one member’s role. A role can have none, one or many cover periods; a Policyholder has none.
  • The end date is not part of the key, because it can change.
  • A cover can be pointed to by none, one or many claims.

3What the table holds

MEMBER_COVER
MEMBER_COVER_IDPKPMI_CONTRACT_ROLE_IDPK, FK → PMI_CONTRACT_ROLEPLAN_CODEPLAN_CODE_VERSIONSTART_DATEEND_DATEUNDERWRITING_TYPE
M0R174A012024-01-222025-01-22NMORI
M1R186K032025-01-22—NMORI
M2R286K032025-01-22—NMORI
M3R491B022019-03-01—MHD
M4R591B022019-03-01—MHD
M5R693C012021-06-01—MHD
M6R793C012021-06-01—MHD
M7R893C012022-09-15—MHD

Still open: A member holding two covers at the same time (Q-37); whether Underwriting Type belongs on the role instead (Q-39).

Load step 6 of 10

Address

One row for each distinct address. Everyone at the same address shares one row.

1What the source sends

GMS_BDPRCNAK1_MEMBER

The member name-and-address file: one row per member record, with the member’s address and email.

ADDR_MEM_RCD_CASEADDR_MEM_RCD_NOADDR_ADDRESS2ADDR_ADDRESS3ADDR_ADDRESS4ADDR_ADDRESS5ADDR_ZIP
001BZB0000011001 SAMPLE ROAD.Testville——AB1 2CD
001BZB0000012001 Sample RoadTESTVILLE——ab12cd
5204170000011002 Example StreetDemoton——XY2 3EF
5204170000012002 EXAMPLE STDemoton——XY2 3EF
5204170000021003 Test LaneDemoton——XY4 5GH
5204170000022003 Test LaneDEMOTON——xy45gh
5204170000023003 Test LaneDemoton——XY4 5GH

2How the ODS builds each row

  1. Take ADDR_ADDRESS2 to ADDR_ADDRESS5 as address lines 1 to 4, and ADDR_ZIP as the postcode.
  2. Clean them into one standard form: capitals, punctuation removed, standard abbreviations (ROAD becomes RD, STREET becomes ST, LANE becomes LN), and the postcode with one space before the last three characters.
  3. Create the Address ID from the cleaned lines + postcode. The seven member rows clean to three addresses: A1, A2, A3. Everyone at the same address shares one Address ID.
Key
Address Line 1 to 4 + Postcode, after cleaningExample: 3 TEST LN + DEMOTON + XY4 5GH
Links
  • No ‘GMS’ in the key: an address is the same whichever system sends it.
  • An address can be used by one or many roles, through Contract Role Address.

3What the table holds

ADDRESS
ADDRESS_IDPKADDRESS_LINE_1ADDRESS_LINE_2ADDRESS_LINE_3ADDRESS_LINE_4POSTCODEADDRESS_TYPE
A11 SAMPLE RDTESTVILLE——AB1 2CD—
A22 EXAMPLE STDEMOTON——XY2 3EF—
A33 TEST LNDEMOTON——XY4 5GH—

Still open: What ADDR_CORRES1 and ADDR_CORRES2 hold (Q-11); flags for wrong or third-party addresses (Q-51); Address Type is proposed for removal from this table (Q-12).

Load step 7 of 10

Contract Role Address

Links a member’s role to an address. One row for each role and address.

1What the source sends

GMS_BDPRCNAK1_MEMBER

Same rows as in the Address section. Each row has its own copy of the member’s policy number and member number.

ADDR_MEM_RCD_CASEADDR_MEM_RCD_NOADDR_FM_DT
001BZB00000110020240122
001BZB00000120020250122
52041700000110020190301
52041700000120020190301
52041700000210020210601
52041700000220020210601
52041700000230020220915

2How the ODS builds each row

  1. Find the member’s role. The address file has its own copy of the policy number and member number (ADDR_MEM_RCD_CASE, ADDR_MEM_RCD_NO). Match them to the member file (MIS_MEMBER_CASE_NO, MIS_MEMBER_NO) to find the role created in step 4. For example 520417 + 000002300 finds R8.
  2. Find the Address ID of the row’s cleaned address, for example A3.
  3. Add one row per role + address. No new ID is made: the two IDs together are the key.
  4. Address Type = ‘Provided Address’.
  5. Dates: no confirmed source yet. ADDR_FM_DT is the candidate start date.
Key
PMI Contract Role ID + Address IDExample: R8 + A3
Links
  • Points to one role and one address.
  • A role can have none, one or many addresses; an address can be shared by many roles.

3What the table holds

CONTRACT_ROLE_ADDRESS
PMI_CONTRACT_ROLE_IDPK, FK → PMI_CONTRACT_ROLEADDRESS_IDPK, FK → ADDRESSADDRESS_TYPESTART_DATEEND_DATE
R1A1Provided AddressTBCTBC
R2A1Provided AddressTBCTBC
R4A2Provided AddressTBCTBC
R5A2Provided AddressTBCTBC
R6A3Provided AddressTBCTBC
R7A3Provided AddressTBCTBC
R8A3Provided AddressTBCTBC

Still open: Start and end dates (Q-13); the same role using one address for two purposes (Q-31).

Load step 8 of 10

Contract Role Phone Number

One row for each phone number held for a member’s role.

1What the source sends

GMS_MEMBFILE

Same member records as in the PMI Contract Role section.

MIS_MEMBER_CASE_NOMIS_MEMBER_NOMIS_TELEPHONE
001BZB000001100—
001BZB00000120007700 900123
520417000001100—
520417000001200—
52041700000210007700 900456
520417000002200—
520417000002300—

2How the ODS builds each row

  1. Only rows with a phone number are used. Here there are two: 001BZB 000001200 and 520417 000002100.
  2. Find the role using the member file’s own policy and member number: R2 and R6.
  3. Clean each number to digits only, for example 07700 900123 becomes 07700900123.
  4. Create the Phone Number ID from the role + the number: T1, T2. A different number later gives a new row.
  5. Dates: no source yet.
Key
PMI Contract Role ID + Phone NumberExample: R2 + 07700900123
Links
  • Belongs to one role. A role can have none, one or many numbers over time.

3What the table holds

CONTRACT_ROLE_PHONE_NUMBER
CONTRACT_ROLE_PHONE_NUMBER_IDPKPMI_CONTRACT_ROLE_IDPK, FK → PMI_CONTRACT_ROLEPHONE_NUMBERSTART_DATEEND_DATE
T1R207700900123TBCTBC
T2R607700900456TBCTBC

Still open: Confirm MIS_TELEPHONE as the phone source (Q-11); start and end dates (Q-13).

Load step 9 of 10

Contract Role Email Address

One row for each email address held for a member’s role.

1What the source sends

GMS_BDPRCNAK1_MEMBER

Same rows as in the Address section.

ADDR_MEM_RCD_CASEADDR_MEM_RCD_NOADDR_EMAIL
001BZB000001100—
001BZB000001200Partner@Example.com
520417000001100Employee.One@Example.com
520417000001200—
520417000002100—
520417000002200—
520417000002300—

2How the ODS builds each row

  1. Only rows with an email are used. Here there are two: 001BZB 000001200 and 520417 000001100.
  2. Match each row to its member record in GMS_MEMBFILE (same policy and member number), as for addresses: R2 and R4.
  3. Clean each email: lower case, spaces trimmed.
  4. Create the Email Address ID from the role + the email: E1, E2. A different email later gives a new row.
  5. Dates: ADDR_FM_DT is the candidate start date; there is no end date source.
Key
PMI Contract Role ID + Email AddressExample: R2 + partner@example.com
Links
  • Belongs to one role. A role can have none, one or many emails over time.

3What the table holds

CONTRACT_ROLE_EMAIL_ADDRESS
CONTRACT_ROLE_EMAIL_ADDRESS_IDPKPMI_CONTRACT_ROLE_IDPK, FK → PMI_CONTRACT_ROLEEMAIL_ADDRESSSTART_DATEEND_DATE
E1R2partner@example.comTBCTBC
E2R4employee.one@example.comTBCTBC

Still open: Start and end dates (Q-13).

Load step 10 of 10

Claim

One row for each ACPM claim. A claim keeps its number and year for its whole life.

1What the source sends

ACPM_THI_CLAIM

The ACPM claim file: one row per claim.

CLAIM_NOCLAIM_NO_YRPOLICY_NOMEMBER_NOCLAIM_ENTER_DT
12345625001BZB00000120014/03/2025 10:22:05
2345672652041700000230005/02/2026 09:15:40

2How the ODS builds each row

  1. One row per claim number + claim year.
  2. Create the Claim ID from ‘ACPM’ + claim number + claim year: CL1, CL2.
  3. Find the claimant’s role using the claim’s own policy and member number, ‘GMS’ + POLICY_NO + MEMBER_NO (padded to 9 digits if shorter): CL1 finds R2; CL2 finds R8.
  4. Find that role’s cover in force on the day the claim was registered (the date part of CLAIM_ENTER_DT): CL1 on 2025-03-14 finds M2; CL2 on 2026-02-05 finds M7.
  5. Claim System = ‘ACPM’.
Key
Claim System + Claim Number + Claim YearExample: 'ACPM' + 234567 + 26
Links
  • Belongs to one member’s role. A role can have none, one or many claims.
  • Points to the cover in force when the claim was registered.

3What the table holds

CLAIM
CLAIM_IDPKCLAIM_SYSTEMCLAIM_NUMBERCLAIM_YEARPMI_CONTRACT_ROLE_IDFK → PMI_CONTRACT_ROLEMEMBER_COVER_IDFK → MEMBER_COVER
CL1ACPM12345625R2M2
CL2ACPM23456726R8M7

Still open: The claim year format, 2 or 4 digits (Q-15); which cover a claim should point to when it continues under a new plan code (Q-47); registration date or treatment date (Q-38).