You get a bonus - 1 coin for daily activity. Now you have 1 coin

Developing a script for creating the objects of the data

Lecture



Это продолжение увлекательной статьи про физическая модель хранилища данных.

...

font-family: "lucida grande", tahoma, verdana, arial, sans-serif; font-size: 12px;">

  • Developing the physical model of the data warehouse:
    • identifying the base tables of the database;
    • identifying the columns in the tables;
    • determining the data types for the columns;
    • assigning primary keys to the tables;
    • defining NOT NULL constraints on column values;
    • creating relationships between the tables.
  • Developing the script to create the data warehouse:
    • forming the CREATE TABLE commands for the data warehouse's tables;
    • defining constraints on the columns of the data warehouse's tables;
    • creating additional indexes with the CREATE INDEX command.

Modeling the data warehouse tables

Identifying the base tables

As noted above, the first step in building the physical model of a data warehouse is identifying the database tables. In solving this task, the data warehouse designer takes as input the relations of the logical data model that represent the entities of the domain, and as output of this modeling stage must produce definitions of the tables, their columns, keys, indexes, and so on.

Base tables are created for each relation of the logical model and are the primary data-storage objects in the database. For each base table, a long identifier is defined that uniquely identifies the table within the database. This name should conform to the naming standards for domain entities, if such standards were developed by the data administrator during the domain analysis stage.

For our teaching example, let's create five tables: four dimension tables — "Time", "Customer", "Product", "Employee" — and one fact table, "Sale". The table names will match the entity names of the data warehouse's logical model (fig. 11.3).

The physical model of a data warehouse

Fig. 11.3. Creating the tables of the data warehouse's physical model

Once the designer has finished processing all the relations of the logical data model, they should double-check that the number of base tables matches the number of relations in the logical data model (i.e., no fewer than the number of entities in the domain). Thus, when creating base tables, the designer follows the principle: one base table per relation of the logical data model.

Identifying the columns in the tables

The next step for the data warehouse designer is identifying the columns for the base tables. Columns of a table should represent the attributes of the relations in the logical model of the relational data warehouse. These attributes must be converted into column specifications in the CREATE TABLE command. A column specification has the following syntax: column name, data type for the values stored in the column, and a list of constraints.

First, let's consider the task of adding columns. A column must have a name. The names of the attributes of the corresponding relations of the logical model are converted into column names according to the object-naming rules adopted in the specific DBMS. As noted above, this usually involves a restriction on name length and on the use of special characters in names. For example, some DBMSs allow a dollar sign in a name, but this character is often not recognized in data-retrieval commands – SELECT.

The physical model of a data warehouse

enlarge image
Fig. 11.4. Defining the column names of the data warehouse's physical model tables

There is one more issue with naming columns – column names must be interpreted unambiguously by users. For example, if the designer assigns the short name LN to an employee's last name, a comment will probably be needed to clarify that this stands for last name and not, say, a production line. If for some reason long field names cannot be used, a data dictionary should be used to interpret the abbreviations introduced.

For our teaching example, solving this task comes down to transferring the entities' attributes into the fields of the corresponding database tables. Note that attributes that are candidates for foreign keys are not carried over. Fig. 11.4 shows the result of this work.

Note that to maintain the principle of field-name uniqueness within the model when defining fields based on entity attribute names, we changed some names. For instance, the "Address" attribute of the "Employee" entity became "Employee address" (Empl_Address) in the corresponding "Employee" table of the physical model. Likewise, the "Address" attribute of the "Customer" entity became "Customer address" (Cust_Address) in the corresponding "Customer" table of the physical model.

Determining the data types for columns

After identifying the columns, their type must be set according to the data types supported by the given DBMS. This task is simplified if attribute domains have been defined in the relations of the logical model. Some domains may already be defined in terms of the DBMS. For such attributes, virtually nothing needs to be done: the domain definition in terms of the DBMS data type just needs to be carried over into the column specification. The designer may need to refine minor type parameters. For example, if a domain is specified as DEC(9,2), but the domain context indicates that this column will accumulate a running total of annual expenses, it may be advisable to define the type as DEC(15,2) to avoid possible overflow when the database applications run.

If a domain is not defined in terms of the DBMS, the database designer must convert it into a suitable data type. When performing such conversions, a number of factors should be taken into account.

  • You should clarify how the DBMS physically stores data of a given predefined type, and then clarify the range of values the column can take. For example, if a variable's type is varchar(3) and it holds a code whose value ranges from '10A' to '99Z', then from a storage standpoint it makes sense to change this variable's type to char(3). This is because the varchar type takes up one or two bytes more in physical storage than the char type for the same declared length.
  • For fixed-length numeric values, it is preferable to use the DEC type. It is processed faster by the CPU than the FLOAT type. The exception is data for scientific calculations, where representing numbers in exponential form is sometimes necessary.
  • Use INT and SMALLINT exclusively for counters.
  • Avoid using the CHAR type to represent numeric data. First, additional validation may be required, and second, problems can arise when sorting such columns, since a number stored as the string '11' will sort above a number stored as the string '9' in ascending order.
  • Use the DATE and TIME types only for storing chronological data.
  • Use the DATETIME type exclusively for data-management purposes.
The physical model of a data warehouse

enlarge image
Fig. 11.5. Determining the data types for the columns of the data warehouse's physical model tables

In our teaching example, a domain has been defined for every attribute. For the entities' surrogate primary identifiers, this is a numeric value. Given that the data warehouse will store large volumes of data, it makes sense to use the bigint data type to represent such attributes in the database, and the integer data type for the remaining attributes. The "Text" domain can be represented with the varchar(n) data type, and for representing decimal numbers, the numeric (p, s ) data type can be used.

The result of determining the column types for the data warehouse's physical model tables is shown in fig. 11.5.

Assigning primary keys to tables

After defining all the columns and their types, the next step is identifying the primary keys of the tables. According to the requirements of relational theory, every row (tuple) of a table must have a unique primary key. Usually, a good candidate for a table's primary key is the primary key of the corresponding relation in the logical model. Since the logical-model relation is assumed to already have a primary key possessing the property of minimality, it simply needs to be declared in the CREATE TABLE command. For many tables, this definition of the primary key is not final. The primary key may be redefined at later stages of physical database design.

In many DBMSs, including the MS SQL Server family, designating a column as a primary key is treated as a constraint on the column's value (see later in this lecture).

For our example, we have already defined the primary keys of the data warehouse's physical model tables as the primary keys of the corresponding entities.

After completing the steps above, the task of defining the primary keys of the base tables can be considered done as a first approximation, and we can move on to the next important table-definition task – defining constraints on column values.

Defining NOT NULL constraints on column values

When defining table column specifications, the designer must consider the constraints that can be imposed on column values. Relational DBMSs support quite a few such constraints. Here we will focus on one of the main ones – the requirement that a column always have a value. This constraint on a column's values is called a NOT NULL constraint.

A predefined column value of NULL means that, at a given moment, for a given row (an instance of a domain entity), the value is undefined, unknown, or absent. The database designer must identify whether a column can take NULL values, since users may run into problems when working with such columns.

One example of such a problem is a situation where a user needs to join two tables on columns that contain NULL values. When performing joins, any rows that have NULL values in the join columns in either table will not appear in the resulting query output. Such data loss can cause the user to get an incorrect result set for the query, especially if they need to see all rows from at least one of the tables.

When assigning NULL values to columns, the designer needs to take the following factors into account.

  • Columns that are part of a composite primary key must always have a NOT NULL constraint, since according to relational theory, the values of primary-key columns must be defined and unique for every tuple.
  • Foreign keys must also be defined as NOT NULL, and since a child table depends on its parent, the parent's foreign key cannot have NULL values. This follows from the fact that a child-table row existing without a corresponding parent-table row violates the relationship's dependency rule (foreign keys, parent and child tables are discussed further below).
  • Only foreign keys for a table with an optional relationship can be considered candidates for allowing NULL values, in order to show that, for a given combination of parent and child rows, there is no relationship between these tables.
  • Foreign keys with the delete rule SET NULL must be defined with the NULL specification.
  • Use the NOT NULL WITH DEFAULT specification for columns with DATE or TIME data types, so as to automatically store the current date and current time.
  • Allow NULL values only for columns that can genuinely have undefined values.
  • Use NOT NULL WITH DEFAULT for all columns that do not fall under the rules listed above.

For our teaching example, all columns of the data warehouse's physical model tables, perhaps with the exception of addresses, should have a NOT NULL constraint (fig. 11.6).

The physical model of a data warehouse

enlarge image
Fig. 11.6. Defining NOT NULL constraints on column values

Creating relationships between tables

The next step in modeling the physical model of the data warehouse is establishing relationships between the tables of the data warehouse model.

The dimension tables and the fact table in a multidimensional data model are in a "parent-child" relationship. The primary key and its corresponding foreign key implement the parent/child relationship between tables of a relational database. They reflect the relationship between objects of the domain (represented by table tuples) through the values of some of their attributes, following the principle of hierarchical subordination, whereby the parent object determines the existence of child objects. The child objects themselves may also act as parents for other objects (descendants).

A relational database table that contains the primary key is called the parent table, while the table containing the foreign key corresponding to that primary key is called the child table. In our teaching example, the "Product" dimension table is the parent table for the "Sale" fact table.

The "parent-child" relationship between tables is implemented through the key attributes of the corresponding rows. A row belonging to the parent table is called a parent row, while a row in the child table that is referenced by the parent row is called a child row. A child row must have at least one non-null foreign-key attribute.

The "parent-child" relationships between two tables reflect an inclusion relationship on the domains of the corresponding attributes.

Having established the "parent-child" relationship between the dimension tables and the fact table in our teaching example, we obtain the physical model of the data warehouse (fig. 11.7)

The physical model of a data warehouse

enlarge image
Fig. 11.7. Defining NOT NULL constraints on column values

A question that needs to be resolved when modeling the data warehouse is whether the dimensions' foreign keys should be elements of the fact table's composite primary key.

In our example, the fact table has a unique surrogate key, "Sale identifier" ( Sale_ID ), so the foreign keys implementing the "parent-child" relationship between the dimension tables and the fact table do not necessarily need to be included in the fact table's composite primary key. Any row of the fact table is already uniquely identified by the assigned primary key.

After creating the physical model of the data warehouse, the designer can move on to the task of developing the script to create the data warehouse. This task can be solved either manually, as we will do in the next section of this lecture, or with the help of CASE tools.

Developing a script for creating the objects of the data warehouse's physical model

SQL commands for creating database tables

SQL provides the CREATE TABLE command for defining and creating tables, which specifies the table name, the names and physical order of its columns, the type of each column, as well as various instructions for the DBMS, such as defining a primary or foreign key, requirements prohibiting undefined values in a table column, and so on.

The CREATE TABLE command creates a new table in the database. The syntax of this command for the SQL dialect (Transact-SQL) of the MS SQL Server family of DBMSs is given below.

CREATE TABLE
    [ database_name . [ schema_name ] . | schema_name . ] table_name
        ( {  | 
                |  }
        [  ] [ ,...n ] )
    [ ON { partition_scheme_name ( partition_column_name ) | filegroup
        | "default" } ]

    [ { TEXTIMAGE_ON { filegroup | "default" } ]
    [ FILESTREAM_ON { partition_scheme_name | filegroup
        | "default" } ]
    [ WITH (  [ ,...n ] ) ]
[ ; ]

 ::=
column_name 
    [ FILESTREAM ]
    [ COLLATE collation_name ]
    [ NULL | NOT NULL ]
    [
        [ CONSTRAINT constraint_name ] DEFAULT constant_expression ]
      | [ IDENTITY [ ( seed ,increment ) ] [ NOT FOR REPLICATION ]
    ]
    [ ROWGUIDCOL ] [  [ ...n ] ]
    [ SPARSE ]

 ::=
[ type_schema_name . ] type_name
    [ ( precision [ , scale ] | max |
        [ { CONTENT | DOCUMENT } ] xml_schema_collection ) ]

 ::=
[ CONSTRAINT constraint_name ]
{     { PRIMARY KEY | UNIQUE }
        [ CLUSTERED | NONCLUSTERED ]
        [
            WITH FILLFACTOR = fillfactor
          | WITH ( < index_option > [ , ...n ] )
        ]
        [ ON { partition_scheme_name ( partition_column_name )
            | filegroup | "default" } ]
  | [ FOREIGN KEY ]
        REFERENCES [ schema_name . ] referenced_table_name [ ( ref_column ) ]
        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ NOT FOR REPLICATION ]
  | CHECK [ NOT FOR REPLICATION ] ( logical_expression )
}
 ::=
column_name AS computed_column_expression
[ PERSISTED [ NOT NULL ] ]
[
    [ CONSTRAINT constraint_name ]
    { PRIMARY KEY | UNIQUE }
        [ CLUSTERED | NONCLUSTERED ]
        [
            WITH FILLFACTOR = fillfactor
          | WITH (  [ , ...n ] )
        ]
    | [ FOREIGN KEY ]
        REFERENCES referenced_table_name [ ( ref_column ) ]
        [ ON DELETE { NO ACTION | CASCADE } ]
        [ ON UPDATE { NO ACTION } ]
        [ NOT FOR REPLICATION ]
    | CHECK [ NOT FOR REPLICATION ] ( logical_expression )
    [ ON { partition_scheme_name ( partition_column_name )
        | filegroup | "default" } ]
]

 ::=
column_set_name XML COLUMN_SET FOR ALL_SPARSE_COLUMNS

< table_constraint > ::=
[ CONSTRAINT constraint_name ]
{
    { PRIMARY KEY | UNIQUE }
        [ CLUSTERED | NONCLUSTERED ]
                (column [ ASC | DESC ] [ ,...n ] )
        [
            WITH FILLFACTOR = fillfactor
           |WITH (  [ , ...n ] )
        ]
        [ ON { partition_scheme_name (partition_column_name)
            | filegroup | "default" } ]
    | FOREIGN KEY
                ( column [ ,...n ] )
        REFERENCES referenced_table_name [ ( ref_column [ ,...n ] ) ]
        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ NOT FOR REPLICATION ]
    | CHECK [ NOT FOR REPLICATION ] ( logical_expression )
}

 ::=
{
    DATA_COMPRESSION = { NONE | ROW | PAGE }
      [ ON PARTITIONS ( {  |  }
            [ , ...n ] ) ]
}

 ::=
{
    PAD_INDEX = { ON | OFF }
  | FILLFACTOR = fillfactor
  | IGNORE_DUP_KEY = { ON | OFF }
  | STATISTICS_NORECOMPUTE = { ON | OFF }
  | ALLOW_ROW_LOCKS = { ON | OFF}
  | ALLOW_PAGE_LOCKS ={ ON | OFF}
  | DATA_COMPRESSION = { NONE | ROW | PAGE }
       [ ON PARTITIONS ( {  |  }
       [ , ...n ] ) ]
}
 ::=
 TO 

Let's look at the elements and arguments of the CREATE TАBLE command.

  • database_name. The name of the database in which the table is created. The database_name argument must specify the name of an existing database. If the database_name argument is not specified, the table is created in the current database by default. The login name for the current connection must be associated with a user ID that exists in the database specified by the database_name argument, and this user must have CREATE TABLE permission.
  • schema_name. The name of the schema to which the new table belongs.
  • table_name. The name of the new table. Table names must comply with the rules for identifiers. The table_name argument can consist of up to 128 characters, except for the names of local temporary tables (names prefixed with a number sign #), whose length must not exceed 116 characters.
  • column_name. The name of a column in the table. Column names must comply with the rules for identifiers and be unique within the given table. The column_name argument can contain from 1 to 128 characters. When creating columns with the timestamp data type, the column_name argument can be omitted. If the column_name argument is not specified, a column of type timestamp is given the default name timestamp.
  • computed_column_expression. An expression that defines the value of a computed column. A computed column is a virtual column that is not physically stored in the table unless the PERSISTED flag is set for it. The column's value is computed from an expression that uses other columns of the same table. For example, a computed column could be defined as: cost AS price * qty. The expression can be the name of a non-computed column, a constant, a function, a variable, or any combination of these joined by one or more operators. The expression cannot be a subquery or contain "alias" data types.

Computed columns can be used in select lists, WHERE clauses, ORDER BY clauses, and anywhere else that ordinary expressions can be used, with the following exceptions.

  1. A computed column cannot be used as a DEFAULT or FOREIGN KEY constraint definition, nor together with a NOT NULL constraint definition. However, a computed column can be used as a key column of an index, or as part of a PRIMARY KEY or UNIQUE constraint, if the value of that computed column is determined by a deterministic expression and the resulting data type is allowed for index columns.
  2. For example, if a table contains the integer columns a and b, the computed column a+b can be included in an index, whereas the computed column a+DATEPART(dd, GETDATE()) cannot, since its value may change on subsequent calls.
  3. A computed column cannot be the target column of INSERT or UPDATE statements.
    • PERSISTED. Specifies that the SQL Server Database Engine will physically store the computed values in the table and update them whenever any column on which the computed column depends changes. Specifying PERSISTED for a computed column allows an index to be created on the computed column that is deterministic but imprecise. Any computed columns used as partitioning columns in a partitioned table must be explicitly marked with the PERSISTED flag. If PERSISTED is specified, the computed_column_expression argument must be deterministic.
    • ON { | filegroup | "default" }. Specifies the partition scheme or filegroup in which the table is stored. If the argument is specified, the table will be partitioned and stored in one or more filegroups specified by the argument. If the filegroup argument is specified, the table is stored in the filegroup with that name, which must be an existing filegroup in the database. If the value "default" is specified, or the ON parameter is not specified at all, the table is stored in the default filegroup. The storage mechanism for a table specified in the CREATE TABLE statement cannot be changed afterward.

The ON { | filegroup | "default"} parameter can also be specified in a PRIMARY KEY or UNIQUE constraint. These constraints create indexes. If the filegroup argument is specified, the index is stored in the filegroup with that name. If the value "default" is specified, or the ON parameter is not specified at all, the index is stored in the same filegroup as the table. If the PRIMARY KEY or UNIQUE constraint creates a clustered index, the table's data pages are stored in the same filegroup as the index. If the constraint creates a clustered index (via the CLUSTERED parameter or otherwise), and the specified argument differs from the and filegroup arguments in the table definition, or vice versa, only the constraint's definition is taken into account, and everything else is disregarded.

  • TEXTIMAGE_ON { filegroup | "default" }. Keywords indicating that columns of the types text, ntext, image, xml, varchar(max), nvarchar(max), varbinary(max), as well as CLR user-defined types, are stored in a specified filegroup.

The TEXTIMAGE_ON parameter is not allowed if the table has no large-value columns. The TEXTIMAGE_ON parameter cannot be specified together with the parameter. If the value "default" is specified, or the TEXTIMAGE_ON parameter is not specified at all, large-value columns are stored in the default filegroup. The storage method for any large-value column data, as determined by the CREATE TABLE statement, cannot be changed afterward.

  • FILESTREAM_ON { partition_scheme_name | filegroup | "default" }. Specifies the filegroup for FILESTREAM data.

If a table contains FILESTREAM data and is partitioned, the FILESTREAM_ON clause must be included, specifying the filegroup partition scheme for the FILESTREAM data. This partition scheme must use the same partitioning functions and columns as the partition scheme used for the table; otherwise an error occurs.

If the table is not partitioned, the FILESTREAM column cannot be partitioned either. FILESTREAM data for the table must be stored in a separate filegroup. This filegroup is specified in the FILESTREAM_ON clause.

If the table is not partitioned and the FILESTREAM_ON clause is not specified, the FILESTREAM filegroup marked with the DEFAULT property is used. If there is no FILESTREAM filegroup, an error occurs.

As with the ON and TEXTIMAGE_ON clauses, the value specified with the CREATE TABLE statement for the FILESTREAM_ON clause cannot be changed, except in the following situations.

  1. The CREATE INDEX statement converts a heap into a clustered index. In this case a different FILESTREAM filegroup, partition scheme, or the value NULL can be specified.
  2. The DROP INDEX statement converts a clustered index into a heap. In this case a different FILESTREAM filegroup, partition scheme, or the value "default" can be specified.
    • [ type_schema_name. ] type_name. Specifies the data type of the column and the schema it belongs to.

The data type can be one of the following.

  1. A system data type.
  2. A data type — an alias based on an SQL Server system data type. Before data type aliases can be used in a table definition, they must be created with the CREATE TYPE statement. The NULL or NOT NULL state for an alias data type can be overridden with the CREATE TABLE statement. However, its length cannot be changed; the length of an alias data type is not determined by the CREATE TABLE statement.
  3. A CLR user-defined type. Before CLR user-defined types can be used in a table definition, they must be created with the CREATE TYPE statement. Creating a column with a CLR user-defined type requires REFERENCES permission on that type.
    • precision. The precision of the specified data type.
    • Scale. The scale of the specified data type.
    • Max. Applies only to the varchar, nvarchar, and varbinary data types, for storing The physical model of a data warehouse bytes of character and binary data, or 2^30 bytes of Unicode data.
  • CONTENT. Specifies that each instance of the xml data type in the column_name column may contain multiple top-level elements. The CONTENT argument applies only to xml data and can be specified only if the xml_schema_collection argument is also specified. If this parameter is not specified, CONTENT is assumed as the default behavior.
  • DOCUMENT. Specifies that each instance of the xml data type in the column_name column may contain only one top-level element. The DOCUMENT argument applies only to xml data and can be specified only if the xml_schema_collection argument is also specified.
  • xml_schema_collection.. Applies only to the xml data type, for the XML schema collection associated with this type. Before an xml column can be added, the schema must be created in the database using the CREATE XML SCHEMA COLLECTION statement.
  • DEFAULT. Specifies the value assigned to the column when no value is explicitly supplied on insert. DEFAULT definitions can be applied to any columns except those of type timestamp or with the IDENTITY property. If a default value is specified for a column of a user-defined type, that type must support implicit conversion of the constant_expression expression to the user-defined type. DEFAULT definitions are removed when the table is dropped. Only constants (for example, character strings), scalar functions (system, user-defined, or CLR functions), or the value NULL can be used as a default value. For compatibility with earlier versions of SQL Server, the DEFAULT parameter can be assigned a constraint name.
  • constant_expression. A constant, the value NULL, or a system function used as the column's default value.
  • IDENTITY. Specifies that the new column is an identity column. When a new row is added to the table, the Database Engine generates a unique, sequential value for this column. Identity columns are typically used together with a PRIMARY KEY constraint to maintain the uniqueness of row identifiers in a table. The IDENTITY property can be assigned to columns of type tinyint, smallint, int, bigint, decimal(p,0), or numeric(p,0). Only one identity column can be created per table. Bound default values and DEFAULT constraints cannot be used on an identity column. Both the seed and the increment must be specified, or neither. If neither is specified, the default value (1,1) is used.
  • Seed. The value used for the very first row loaded into the table.
  • Increment. The increment value added to the identity value of the previously loaded row.
  • NOT FOR REPLICATION. In the CREATE TABLE statement, the NOT FOR REPLICATION clause can be specified for the IDENTITY property, as well as for FOREIGN KEY and CHECK constraints. If this clause is specified for the IDENTITY property, values in identity columns are not incremented when inserts are performed by replication agents. If a constraint is accompanied by this clause, it is not enforced when replication agents perform insert, update, or delete operations.
  • ROWGUIDCOL. Specifies that the new column is a GUID identifier column. Only one uniqueidentifier column in a table can be designated as the ROWGUIDCOL column. Applying the ROWGUIDCOL property allows the column to be referenced using the $ROWGUID keyword. The ROWGUIDCOL property can only be assigned to a column of type uniqueidentifier. The ROWGUIDCOL keyword is not allowed if the database compatibility level is 65 or lower. The ROWGUIDCOL keyword cannot be used to mark columns of user-defined data types.

продолжение следует...

Продолжение:


Часть 1 The physical model of a data warehouse
Часть 2 Developing a script for creating the objects of the data
Часть 3 Constraints and their use in a relational database - The
Часть 4 Summary - The physical model of a data warehouse

created: 2021-03-13
updated: 2026-03-09
555



Was this answer useful?
Choose a quick rating so we can improve the next answer for you.
How satisfied are you?


Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Databases, knowledge and data warehousing. Big data, DBMS and SQL and noSQL"

Terms: Databases, knowledge and data warehousing. Big data, DBMS and SQL and noSQL