Skip to content

SQL - DataVault example

In this example we create a DataVault structure. If you haven't done already, please read the Simple staging example first for a basic explanation of concepts used in the template and config. The tables implemented in this example are used in the SSIS DataVault example.

Model

In this example we will be generating DataVault tables for each entity and relation defined in the DWH model.

Templates

For generating DataVault tables we need multiple templates, namely a SQL template file for each table type (Hub, Link, Hub-Sat and Link-Sat) since each table type is a different technical pattern.

Entity_owner.H_Entity_name.sql

In the Hub template a section KeyAttribute is defined and used for column specification as well as for the unique constraint.

CREATE TABLE [Entity_owner].[H_Entity_name] (
  [H_Entity_name_SQN]        BIGINT NOT NULL IDENTITY(1,1),
  -- @XGenTextSection(name="KeyAttribute")
  [KeyAttribute_name]        KeyAttribute_fulldatatype    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  CONSTRAINT [PK_Entity_owner_H_Entity_name] PRIMARY KEY NONCLUSTERED ([H_Entity_name_SQN]),
  CONSTRAINT [UK_Entity_owner_H_Entity_name] UNIQUE(
    -- @XGenTextSection(name="KeyAttribute" suffix=",")
    [KeyAttribute_name]
  )
);
GO

Entity_owner.HS_Entity_name.sql

The Hub-Sat template has a section defined named NonKeyAttribute that is used to apply the non-key columns to the sattelite table.

CREATE TABLE [Entity_owner].[HS_Entity_name] (
  [H_Entity_name_SQN]        BIGINT NOT NULL,
  -- @XGenTextSection(name="NonKeyAttribute") 
  [NonKeyAttribute_name]     NonKeyAttribute_fulldatatype    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  [EndDateTime]              datetime2(2) NOT NULL,
  [RecordHash] VARBINARY(16) NOT NULL, 
  CONSTRAINT [PK_Entity_owner_HS_Entity_name] PRIMARY KEY NONCLUSTERED ([H_Entity_name_SQN], [LoadDateTime]),
  CONSTRAINT [FK_Entity_owner_HS_Entity_name_Entity_owner_H_Entity_name] FOREIGN KEY ([H_Entity_name_SQN]) REFERENCES [Entity_owner].[H_Entity_name] ([H_Entity_name_SQN])
);
GO

Relation_owner.L_Relation_name.sql

The Link table template has a section RelatedEntity that is used to define the appropriate technical Hub keys as columns to the table as well as to the unique constraint.

CREATE TABLE [Relation_owner].[L_Relation_name] (
  [L_Relation_name_SQN]      BIGINT NOT NULL IDENTITY(1,1),
  -- @XGenTextSection(name="RelatedEntity") 
  [H_RelatedEntity_parentReferenceName_SQN] BIGINT    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  CONSTRAINT [PK_Relation_owner_H_Relation_name] PRIMARY KEY NONCLUSTERED ([L_Relation_name_SQN]),
  CONSTRAINT [UK_Relation_owner_H_Relation_name] UNIQUE(
    -- @XGenTextSection(name="RelatedEntity" suffix=",")
    [H_RelatedEntity_parentReferenceName_SQN]
  )
);
GO

Relation_owner.LS_Relation_name.sql

Similar to the Hub-Sat table, the Link-Sat template also has a section named NonKeyAttribute.

CREATE TABLE [Relation_owner].[LS_Relation_name] (
  [L_Relation_name_SQN]      BIGINT NOT NULL,
  -- @XGenTextSection(name="NonKeyAttribute") 
  [NonKeyAttribute_name]     NonKeyAttribute_fulldatatype    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  [EndDateTime]              datetime2(2) NOT NULL,
  [RecordHash] VARBINARY(16) NOT NULL, 
  CONSTRAINT [PK_Relation_owner_LS_Relation_name] PRIMARY KEY NONCLUSTERED ([L_Relation_name_SQN], [LoadDateTime]),
  CONSTRAINT [FK_Relation_owner_LS_Relation_name_Relation_owner_L_Relation_name] FOREIGN KEY ([L_Relation_name_SQN]) REFERENCES [Relation_owner].[L_Relation_name] ([L_Relation_name_SQN])
);
GO

Documentation

For documentation on templates, please see Template.

Config

To generate the DataVault structure we need two configurations, one for the Hub and Hub-Sat tables that binds on entity and one for the Link and Link-Sat tables that binds on relation.

Config for Hub and Hub-Sat tables

The config is very similar to the one used to generate the staging table, however note that in this config multiple SectionModelBinding entries are added to bind NonKeyAttribute to attributes that have not been marked as primary and KeyAttribute to the attributes that are marked as primary. In other words, SectionModelBinding is used to route parts of the model to the appropriate sections in a template. In this case this enables creating a DataVault structure from a relational model (the model itself not being in DataVault structure).

<?xml version="1.0" encoding="UTF-8"?>
<XGenConfig>
  <Model/>
  <TextTemplate rootSectionName="Entity">
    <FileFormat currentAccessor="_" childAccessor="$" singleLineCommentPrefix="--" annotationPrefix="@XGen" annotationArgsPrefix="(" annotationArgsSuffix=")" />
    <Output type="output_per_element" />
  </TextTemplate>
  <Binding>
        <SectionModelBinding section="Entity" modelXPath="/modeldefinition/system/mappableObjects/entity" placeholderName="Entity">
            <Placeholders>
                <Placeholder name="System" modelXPath="../.." />
            </Placeholders>
            <SectionModelBinding section="Attribute" modelXPath="attributes/attribute" placeholderName="Attribute" />
            <SectionModelBinding section="NonKeyAttribute" modelXPath="attributes/attribute[not(boolean(@primary))]" placeholderName="NonKeyAttribute" />
            <SectionModelBinding section="KeyAttribute" modelXPath="attributes/attribute[boolean(@primary)]" placeholderName="KeyAttribute" />
        </SectionModelBinding>
  </Binding>
</XGenConfig>

The config for Link and Link-Sat is similar to the config for Hub and Hub-Sat tables. The differences are that in this config, the sections are bound to relation instead of entity and an additional SectionModelBinding is defined for binding RelatedEntity to the references within a relation.

<?xml version="1.0" encoding="UTF-8"?>
<XGenConfig>
  <Model/>
  <TextTemplate rootSectionName="Relation">
    <FileFormat currentAccessor="_" childAccessor="$" singleLineCommentPrefix="--" annotationPrefix="@XGen" annotationArgsPrefix="(" annotationArgsSuffix=")" />
    <Output type="output_per_element" />
  </TextTemplate>
  <Binding>
        <SectionModelBinding section="Relation" modelXPath="/modeldefinition/system/mappableObjects/relation" placeholderName="Relation">
            <Placeholders>
                <Placeholder name="System" modelXPath="../.." />
            </Placeholders>
            <SectionModelBinding section="Attribute" modelXPath="attributes/attribute" placeholderName="Attribute" />
            <SectionModelBinding section="NonKeyAttribute" modelXPath="attributes/attribute[not(boolean(@primary))]" placeholderName="NonKeyAttribute" />
            <SectionModelBinding section="KeyAttribute" modelXPath="attributes/attribute[boolean(@primary)]" placeholderName="KeyAttribute" />
            <SectionModelBinding section="RelatedEntity" modelXPath="references/reference" placeholderName="RelatedEntity" />
        </SectionModelBinding>
  </Binding>
</XGenConfig>

Documentation

For documentation on the configuration, please see Config.

Output

When running CrossGenerate the output using the given Model, Templates and Configs will be as follows:

Hub tables

The Hub tables generated using the Hub template and Hub/Hub-Sat config.

BusinessVault.H_Country.sql

CREATE TABLE [BusinessVault].[H_Country] (
  [H_Country_SQN]        BIGINT NOT NULL IDENTITY(1,1),
  [Code]        nvarchar(3)    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  CONSTRAINT [PK_BusinessVault_H_Country] PRIMARY KEY NONCLUSTERED ([H_Country_SQN]),
  CONSTRAINT [UK_BusinessVault_H_Country] UNIQUE(
    [Code]
  )
);
GO

BusinessVault.H_Customer.sql

CREATE TABLE [BusinessVault].[H_Customer] (
  [H_Customer_SQN]        BIGINT NOT NULL IDENTITY(1,1),
  [Id]        int    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  CONSTRAINT [PK_BusinessVault_H_Customer] PRIMARY KEY NONCLUSTERED ([H_Customer_SQN]),
  CONSTRAINT [UK_BusinessVault_H_Customer] UNIQUE(
    [Id]
  )
);
GO

BusinessVault.H_Order.sql

CREATE TABLE [BusinessVault].[H_Order] (
  [H_Order_SQN]        BIGINT NOT NULL IDENTITY(1,1),
  [Id]        int    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  CONSTRAINT [PK_BusinessVault_H_Order] PRIMARY KEY NONCLUSTERED ([H_Order_SQN]),
  CONSTRAINT [UK_BusinessVault_H_Order] UNIQUE(
    [Id]
  )
);
GO

Hub-Sat tables

Generated using the Hub-Sat template and Hub/Hub-Sat config.

BusinessVault.HS_Country.sql

CREATE TABLE [BusinessVault].[HS_Country] (
  [H_Country_SQN]        BIGINT NOT NULL,
  [Description]     nvarchar(100)    NULL,
  [Continent]     nvarchar(100)    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  [EndDateTime]              datetime2(2) NOT NULL,
  [RecordHash] VARBINARY(16) NOT NULL, 
  CONSTRAINT [PK_BusinessVault_HS_Country] PRIMARY KEY NONCLUSTERED ([H_Country_SQN], [LoadDateTime]),
  CONSTRAINT [FK_BusinessVault_HS_Country_BusinessVault_H_Country] FOREIGN KEY ([H_Country_SQN]) REFERENCES [BusinessVault].[H_Country] ([H_Country_SQN])
);
GO

BusinessVault.HS_Customer.sql

CREATE TABLE [BusinessVault].[HS_Customer] (
  [H_Customer_SQN]        BIGINT NOT NULL,
  [FirstName]     varchar(50)    NULL,
  [LastName]     varchar(100)    NULL,
  [City]     varchar(50)    NULL,
  [Country_Code]     varchar(3)    NULL,
  [Country_Description]     nvarchar(100)    NULL,
  [Country_Continent]     nvarchar(100)    NULL,
  [Phone]     varchar(20)    NULL,
  [FullName]     varchar(151)    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  [EndDateTime]              datetime2(2) NOT NULL,
  [RecordHash] VARBINARY(16) NOT NULL, 
  CONSTRAINT [PK_BusinessVault_HS_Customer] PRIMARY KEY NONCLUSTERED ([H_Customer_SQN], [LoadDateTime]),
  CONSTRAINT [FK_BusinessVault_HS_Customer_BusinessVault_H_Customer] FOREIGN KEY ([H_Customer_SQN]) REFERENCES [BusinessVault].[H_Customer] ([H_Customer_SQN])
);
GO

BusinessVault.HS_Order.sql

CREATE TABLE [BusinessVault].[HS_Order] (
  [H_Order_SQN]        BIGINT NOT NULL,
  [OrderDate]     datetime    NULL,
  [OrderNumber]     varchar(50)    NULL,
  [CustomerId]     int    NULL,
  [TotalAmount]     decimal(12,2)    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  [EndDateTime]              datetime2(2) NOT NULL,
  [RecordHash] VARBINARY(16) NOT NULL, 
  CONSTRAINT [PK_BusinessVault_HS_Order] PRIMARY KEY NONCLUSTERED ([H_Order_SQN], [LoadDateTime]),
  CONSTRAINT [FK_BusinessVault_HS_Order_BusinessVault_H_Order] FOREIGN KEY ([H_Order_SQN]) REFERENCES [BusinessVault].[H_Order] ([H_Order_SQN])
);
GO

Generated using the Link template and Link/Link-Sat config.

BusinessVault.L_Order_Customer.sql

CREATE TABLE [BusinessVault].[L_Order_Customer] (
  [L_Order_Customer_SQN]      BIGINT NOT NULL IDENTITY(1,1),
  [H_Customer_SQN] BIGINT    NULL,
  [H_Order_SQN] BIGINT    NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  CONSTRAINT [PK_BusinessVault_H_Order_Customer] PRIMARY KEY NONCLUSTERED ([L_Order_Customer_SQN]),
  CONSTRAINT [UK_BusinessVault_H_Order_Customer] UNIQUE(
    [H_Customer_SQN],
    [H_Order_SQN]
  )
);
GO

Generated using the Link-Sat template and the Link/Link-Sat config.

BusinessVault.LS_Order_Customer.sql

CREATE TABLE [BusinessVault].[LS_Order_Customer] (
  [L_Order_Customer_SQN]      BIGINT NOT NULL,
  [LoadDateTime]             datetime2(2) NOT NULL,
  [EndDateTime]              datetime2(2) NOT NULL,
  [RecordHash] VARBINARY(16) NOT NULL, 
  CONSTRAINT [PK_BusinessVault_LS_Order_Customer] PRIMARY KEY NONCLUSTERED ([L_Order_Customer_SQN], [LoadDateTime]),
  CONSTRAINT [FK_BusinessVault_LS_Order_Customer_BusinessVault_L_Order_Customer] FOREIGN KEY ([L_Order_Customer_SQN]) REFERENCES [BusinessVault].[L_Order_Customer] ([L_Order_Customer_SQN])
);
GO

Attachments

The entire DataVault example, including SQL and SSIS templates, can be found in the SSIS DataVault example.