Step 3: Create tables, indexes, and sample data
Important
End of support notice: Existing customers will be able to use Amazon QLDB until end of support on 07/31/2025. For more details, see
Migrate an Amazon QLDB Ledger to Amazon Aurora PostgreSQL
When your Amazon QLDB ledger is active and accepts connections, you can start creating tables for data about vehicles, their owners, and their registration information. After creating the tables and indexes, you can load them with data.
In this step, you create four tables in the vehicle-registration
ledger:
-
VehicleRegistration
-
Vehicle
-
Person
-
DriversLicense
You also create the following indexes.
Table name | Field |
---|---|
VehicleRegistration |
VIN |
VehicleRegistration |
LicensePlateNumber |
Vehicle |
VIN |
Person |
GovId |
DriversLicense |
LicenseNumber |
DriversLicense |
PersonId |
When inserting sample data, you first insert documents into the Person
table.
Then, you use the system-assigned id
from each Person
document to
populate the corresponding fields in the appropriate VehicleRegistration
and
DriversLicense
documents.
Tip
As a best practice, use a document's system-assigned id
as a foreign key.
While you can define fields that are intended to be unique identifiers (for example, a vehicle's
VIN), the true unique identifier of a document is its id
. This field is included in
the document's metadata, which you can query in the committed view (the
system-defined view of a table).
For more information about views in QLDB, see Core concepts. To learn more about metadata, see Querying document metadata.
To create tables and indexes
-
Use the following program (
create_table.py
) to create the previously mentioned tables.Note
This program demonstrates how to use the
execute_lambda
function. In this example, you run multipleCREATE TABLE
PartiQL statements with a single lambda expression.This execute function implicitly starts a transaction, runs all of the statements in the lambda, and then auto-commits the transaction.
-
To run the program, enter the following command.
python create_table.py
-
Use the following program (
create_index.py
) to create indexes on the tables, as previously described. -
To run the program, enter the following command.
python create_index.py
To load data into the tables
-
Review the following file (
sample_data.py
), which represents the sample data that you insert into thevehicle-registration
tables. This file also imports from theamazon.ion
package to provide helper functions that convert, parse, and print Amazon Ion data.# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # software and associated documentation files (the "Software"), to deal in the Software # without restriction, including without limitation the rights to use, copy, modify, # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. from datetime import datetime from decimal import Decimal from logging import basicConfig, getLogger, INFO from amazon.ion.simple_types import IonPyBool, IonPyBytes, IonPyDecimal, IonPyDict, IonPyFloat, IonPyInt, IonPyList, \ IonPyNull, IonPySymbol, IonPyText, IonPyTimestamp from amazon.ion.simpleion import dumps, loads logger = getLogger(__name__) basicConfig(level=INFO) IonValue = (IonPyBool, IonPyBytes, IonPyDecimal, IonPyDict, IonPyFloat, IonPyInt, IonPyList, IonPyNull, IonPySymbol, IonPyText, IonPyTimestamp) class SampleData: """ Sample domain objects for use throughout this tutorial. """ DRIVERS_LICENSE = [ { 'PersonId': '', 'LicenseNumber': 'LEWISR261LL', 'LicenseType': 'Learner', 'ValidFromDate': datetime(2016, 12, 20), 'ValidToDate': datetime(2020, 11, 15) }, { 'PersonId': '', 'LicenseNumber': 'LOGANB486CG', 'LicenseType': 'Probationary', 'ValidFromDate': datetime(2016, 4, 6), 'ValidToDate': datetime(2020, 11, 15) }, { 'PersonId': '', 'LicenseNumber': '744 849 301', 'LicenseType': 'Full', 'ValidFromDate': datetime(2017, 12, 6), 'ValidToDate': datetime(2022, 10, 15) }, { 'PersonId': '', 'LicenseNumber': 'P626-168-229-765', 'LicenseType': 'Learner', 'ValidFromDate': datetime(2017, 8, 16), 'ValidToDate': datetime(2021, 11, 15) }, { 'PersonId': '', 'LicenseNumber': 'S152-780-97-415-0', 'LicenseType': 'Probationary', 'ValidFromDate': datetime(2015, 8, 15), 'ValidToDate': datetime(2021, 8, 21) } ] PERSON = [ { 'FirstName': 'Raul', 'LastName': 'Lewis', 'Address': '1719 University Street, Seattle, WA, 98109', 'DOB': datetime(1963, 8, 19), 'GovId': 'LEWISR261LL', 'GovIdType': 'Driver License' }, { 'FirstName': 'Brent', 'LastName': 'Logan', 'DOB': datetime(1967, 7, 3), 'Address': '43 Stockert Hollow Road, Everett, WA, 98203', 'GovId': 'LOGANB486CG', 'GovIdType': 'Driver License' }, { 'FirstName': 'Alexis', 'LastName': 'Pena', 'DOB': datetime(1974, 2, 10), 'Address': '4058 Melrose Street, Spokane Valley, WA, 99206', 'GovId': '744 849 301', 'GovIdType': 'SSN' }, { 'FirstName': 'Melvin', 'LastName': 'Parker', 'DOB': datetime(1976, 5, 22), 'Address': '4362 Ryder Avenue, Seattle, WA, 98101', 'GovId': 'P626-168-229-765', 'GovIdType': 'Passport' }, { 'FirstName': 'Salvatore', 'LastName': 'Spencer', 'DOB': datetime(1997, 11, 15), 'Address': '4450 Honeysuckle Lane, Seattle, WA, 98101', 'GovId': 'S152-780-97-415-0', 'GovIdType': 'Passport' } ] VEHICLE = [ { 'VIN': '1N4AL11D75C109151', 'Type': 'Sedan', 'Year': 2011, 'Make': 'Audi', 'Model': 'A5', 'Color': 'Silver' }, { 'VIN': 'KM8SRDHF6EU074761', 'Type': 'Sedan', 'Year': 2015, 'Make': 'Tesla', 'Model': 'Model S', 'Color': 'Blue' }, { 'VIN': '3HGGK5G53FM761765', 'Type': 'Motorcycle', 'Year': 2011, 'Make': 'Ducati', 'Model': 'Monster 1200', 'Color': 'Yellow' }, { 'VIN': '1HVBBAANXWH544237', 'Type': 'Semi', 'Year': 2009, 'Make': 'Ford', 'Model': 'F 150', 'Color': 'Black' }, { 'VIN': '1C4RJFAG0FC625797', 'Type': 'Sedan', 'Year': 2019, 'Make': 'Mercedes', 'Model': 'CLK 350', 'Color': 'White' } ] VEHICLE_REGISTRATION = [ { 'VIN': '1N4AL11D75C109151', 'LicensePlateNumber': 'LEWISR261LL', 'State': 'WA', 'City': 'Seattle', 'ValidFromDate': datetime(2017, 8, 21), 'ValidToDate': datetime(2020, 5, 11), 'PendingPenaltyTicketAmount': Decimal('90.25'), 'Owners': { 'PrimaryOwner': {'PersonId': ''}, 'SecondaryOwners': [] } }, { 'VIN': 'KM8SRDHF6EU074761', 'LicensePlateNumber': 'CA762X', 'State': 'WA', 'City': 'Kent', 'PendingPenaltyTicketAmount': Decimal('130.75'), 'ValidFromDate': datetime(2017, 9, 14), 'ValidToDate': datetime(2020, 6, 25), 'Owners': { 'PrimaryOwner': {'PersonId': ''}, 'SecondaryOwners': [] } }, { 'VIN': '3HGGK5G53FM761765', 'LicensePlateNumber': 'CD820Z', 'State': 'WA', 'City': 'Everett', 'PendingPenaltyTicketAmount': Decimal('442.30'), 'ValidFromDate': datetime(2011, 3, 17), 'ValidToDate': datetime(2021, 3, 24), 'Owners': { 'PrimaryOwner': {'PersonId': ''}, 'SecondaryOwners': [] } }, { 'VIN': '1HVBBAANXWH544237', 'LicensePlateNumber': 'LS477D', 'State': 'WA', 'City': 'Tacoma', 'PendingPenaltyTicketAmount': Decimal('42.20'), 'ValidFromDate': datetime(2011, 10, 26), 'ValidToDate': datetime(2023, 9, 25), 'Owners': { 'PrimaryOwner': {'PersonId': ''}, 'SecondaryOwners': [] } }, { 'VIN': '1C4RJFAG0FC625797', 'LicensePlateNumber': 'TH393F', 'State': 'WA', 'City': 'Olympia', 'PendingPenaltyTicketAmount': Decimal('30.45'), 'ValidFromDate': datetime(2013, 9, 2), 'ValidToDate': datetime(2024, 3, 19), 'Owners': { 'PrimaryOwner': {'PersonId': ''}, 'SecondaryOwners': [] } } ] def convert_object_to_ion(py_object): """ Convert a Python object into an Ion object. :type py_object: object :param py_object: The object to convert. :rtype: :py:class:`amazon.ion.simple_types.IonPyValue` :return: The converted Ion object. """ ion_object = loads(dumps(py_object)) return ion_object def to_ion_struct(key, value): """ Convert the given key and value into an Ion struct. :type key: str :param key: The key which serves as an unique identifier. :type value: str :param value: The value associated with a given key. :rtype: :py:class:`amazon.ion.simple_types.IonPyDict` :return: The Ion dictionary object. """ ion_struct = dict() ion_struct[key] = value return loads(str(ion_struct)) def get_document_ids(transaction_executor, table_name, field, value): """ Gets the document IDs from the given table. :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor` :param transaction_executor: An Executor object allowing for execution of statements within a transaction. :type table_name: str :param table_name: The table name to query. :type field: str :param field: A field to query. :type value: str :param value: The key of the given field. :rtype: list :return: A list of document IDs. """ query = "SELECT id FROM {} AS t BY id WHERE t.{} = ?".format(table_name, field) cursor = transaction_executor.execute_statement(query, convert_object_to_ion(value)) return list(map(lambda table: table.get('id'), cursor)) def get_document_ids_from_dml_results(result): """ Return a list of modified document IDs as strings from DML results. :type result: :py:class:`pyqldb.cursor.buffered_cursor.BufferedCursor` :param: result: The result set from DML operation. :rtype: list :return: List of document IDs. """ ret_val = list(map(lambda x: x.get('documentId'), result)) return ret_val def print_result(cursor): """ Pretty print the result set. Returns the number of documents in the result set. :type cursor: :py:class:`pyqldb.cursor.stream_cursor.StreamCursor`/ :py:class:`pyqldb.cursor.buffered_cursor.BufferedCursor` :param cursor: An instance of the StreamCursor or BufferedCursor class. :rtype: int :return: Number of documents in the result set. """ result_counter = 0 for row in cursor: # Each row would be in Ion format. print_ion(row) result_counter += 1 return result_counter def print_ion(ion_value): """ Pretty print an Ion Value. :type ion_value: :py:class:`amazon.ion.simple_types.IonPySymbol` :param ion_value: Any Ion Value to be pretty printed. """ logger.info(dumps(ion_value, binary=False, indent=' ', omit_version_marker=True))
Note
The
get_document_ids
function runs a query that returns system-assigned document IDs from a table. To learn more, see Using the BY clause to query document ID. -
Use the following program (
insert_document.py
) to insert the sample data into your tables.Note
-
This program demonstrates how to call the
execute_statement
function with parameterized values. You can pass data parameters in addition to the PartiQL statement that you want to run. Use a question mark (?
) as a variable placeholder in your statement string. -
If an
INSERT
statement succeeds, it returns theid
of each inserted document.
-
-
To run the program, enter the following command.
python insert_document.py
Next, you can use SELECT
statements to read data from the tables in the
vehicle-registration
ledger. Proceed to Step 4: Query the tables in a ledger.