

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Amazon QLDB Python-Anleitung
<a name="getting-started.python.tutorial"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

In dieser Implementierung der Tutorial-Beispielanwendung verwenden Sie den Amazon QLDB-Treiber mit dem, um ein QLDB-Ledger AWS SDK für Python (Boto3) zu erstellen und es mit Beispieldaten zu füllen.

Während Sie dieses Tutorial durcharbeiten, können Sie in der API-Referenz für Verwaltungs-API-Operationen auf den [QLDB-Low-Level-Client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/qldb.html) in der *AWS SDK for Python (Boto3) -API-Referenz verweisen.* Informationen zu Transaktionsdatenoperationen finden Sie in der [QLDB-Treiber für](https://amazon-qldb-driver-python.readthedocs.io/en/stable/) Python-API-Referenz.

**Anmerkung**  
Gegebenenfalls enthalten einige Tutorial-Schritte unterschiedliche Befehle oder Codebeispiele für jede unterstützte Hauptversion des QLDB-Treibers für Python.

**Topics**
+ [Installation der Amazon QLDB Python-Beispielanwendung](sample-app.python.md)
+ [Schritt 1: Erstellen Sie ein neues Hauptbuch](getting-started.python.step-1.md)
+ [Schritt 2: Testen Sie die Konnektivität zum Ledger](getting-started.python.step-2.md)
+ [Schritt 3: Erstellen Sie Tabellen, Indizes und Beispieldaten](getting-started.python.step-3.md)
+ [Schritt 4: Fragen Sie die Tabellen in einem Hauptbuch ab](getting-started.python.step-4.md)
+ [Schritt 5: Dokumente in einem Ledger ändern](getting-started.python.step-5.md)
+ [Schritt 6: Den Revisionsverlauf für ein Dokument anzeigen](getting-started.python.step-6.md)
+ [Schritt 7: Überprüfen Sie ein Dokument in einem Hauptbuch](getting-started.python.step-7.md)
+ [Schritt 8 (optional): Ressourcen bereinigen](getting-started.python.step-8.md)

# Installation der Amazon QLDB Python-Beispielanwendung
<a name="sample-app.python"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

In diesem Abschnitt wird beschrieben, wie Sie die bereitgestellte Amazon QLDB-Beispielanwendung für das step-by-step Python-Tutorial installieren und ausführen. Der Anwendungsfall für diese Beispielanwendung ist eine Datenbank der Straßenverkehrsbehörde, mit der die vollständigen Verlaufsinformationen über Fahrzeugzulassungen nachverfolgt werden.

Die DMV-Beispielanwendung für Python ist Open Source im GitHub Repository [amazon-qldb-dmv-sampleaws-samples/](https://github.com/aws-samples/amazon-qldb-dmv-sample-python) -python.

## Voraussetzungen
<a name="sample-app.python.prereqs"></a>

Bevor Sie beginnen, stellen Sie sicher, dass Sie den QLDB-Treiber für Python fertiggestellt haben. [Voraussetzungen](getting-started.python.md#getting-started.python.prereqs) Dazu gehört die Installation von Python und die folgenden Schritte:

1. Melde dich an für AWS.

1. Erstellen Sie einen Benutzer mit den entsprechenden QLDB-Berechtigungen.

1. Gewähren Sie programmatischen Zugriff für die Entwicklung.

Um alle Schritte in diesem Tutorial ausführen zu können, benötigen Sie vollen Administratorzugriff auf Ihre Ledger-Ressource über die QLDB-API.

## Installation
<a name="sample-app.python.install"></a>

**So installieren Sie die Beispielanwendung**

1. Geben Sie den folgenden `pip` Befehl ein, um die Beispielanwendung von zu klonen und zu installieren. GitHub

------
#### [ 3.x ]

   ```
   pip install git+https://github.com/aws-samples/amazon-qldb-dmv-sample-python.git
   ```

------
#### [ 2.x ]

   ```
   pip install git+https://github.com/aws-samples/amazon-qldb-dmv-sample-python.git@v1.0.0
   ```

------

   Die Beispielanwendung packt den kompletten Quellcode aus diesem Tutorial und seine Abhängigkeiten, einschließlich des Python-Treibers und des [AWS SDK für Python (Boto3)](https://aws.amazon.com/sdk-for-python) zusammen.

1. Bevor Sie den Code an der Befehlszeile ausführen, ändern Sie Ihr aktuelles Arbeitsverzeichnis in den Speicherort, an dem das `pyqldbsamples`-Paket installiert ist. Geben Sie den folgenden Befehl ein.

   ```
   cd $(python -c "import pyqldbsamples; print(pyqldbsamples.__path__[0])")
   ```

1. Fahren Sie mit [Schritt 1: Erstellen Sie ein neues Hauptbuch](getting-started.python.step-1.md) fort, um das Tutorial zu starten und ein Ledger zu erstellen.

# Schritt 1: Erstellen Sie ein neues Hauptbuch
<a name="getting-started.python.step-1"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

In diesem Schritt erstellen Sie ein neues Amazon QLDB-Ledger mit dem Namen. `vehicle-registration`

**So erstellen Sie einen neuen Ledger**

1. Überprüfen Sie die folgende Datei (`constants.py`), die konstante Werte enthält, die von allen anderen Programmen in diesem Tutorial verwendet werden.

   ```
   # 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.
   
   
   class Constants:
       """
       Constant values used throughout this tutorial.
       """
       LEDGER_NAME = "vehicle-registration"
   
       VEHICLE_REGISTRATION_TABLE_NAME = "VehicleRegistration"
       VEHICLE_TABLE_NAME = "Vehicle"
       PERSON_TABLE_NAME = "Person"
       DRIVERS_LICENSE_TABLE_NAME = "DriversLicense"
   
       LICENSE_NUMBER_INDEX_NAME = "LicenseNumber"
       GOV_ID_INDEX_NAME = "GovId"
       VEHICLE_VIN_INDEX_NAME = "VIN"
       LICENSE_PLATE_NUMBER_INDEX_NAME = "LicensePlateNumber"
       PERSON_ID_INDEX_NAME = "PersonId"
   
       JOURNAL_EXPORT_S3_BUCKET_NAME_PREFIX = "qldb-tutorial-journal-export"
       USER_TABLES = "information_schema.user_tables"
       S3_BUCKET_ARN_TEMPLATE = "arn:aws:s3:::"
       LEDGER_NAME_WITH_TAGS = "tags"
   
       RETRY_LIMIT = 4
   ```

1. Verwenden Sie das folgende Programm (`create_ledger.py`), um einen Ledger mit dem Namen `vehicle-registration` zu erstellen.

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   from time import sleep
   
   from boto3 import client
   
   from pyqldbsamples.constants import Constants
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   qldb_client = client('qldb')
   
   LEDGER_CREATION_POLL_PERIOD_SEC = 10
   ACTIVE_STATE = "ACTIVE"
   
   
   def create_ledger(name):
       """
       Create a new ledger with the specified name.
   
       :type name: str
       :param name: Name for the ledger to be created.
   
       :rtype: dict
       :return: Result from the request.
       """
       logger.info("Let's create the ledger named: {}...".format(name))
       result = qldb_client.create_ledger(Name=name, PermissionsMode='ALLOW_ALL')
       logger.info('Success. Ledger state: {}.'.format(result.get('State')))
       return result
   
   
   def wait_for_active(name):
       """
       Wait for the newly created ledger to become active.
   
       :type name: str
       :param name: The ledger to check on.
   
       :rtype: dict
       :return: Result from the request.
       """
       logger.info('Waiting for ledger to become active...')
       while True:
           result = qldb_client.describe_ledger(Name=name)
           if result.get('State') == ACTIVE_STATE:
               logger.info('Success. Ledger is active and ready to use.')
               return result
           logger.info('The ledger is still creating. Please wait...')
           sleep(LEDGER_CREATION_POLL_PERIOD_SEC)
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Create a ledger and wait for it to be active.
       """
       try:
           create_ledger(ledger_name)
           wait_for_active(ledger_name)
       except Exception as e:
           logger.exception('Unable to create the ledger!')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```
**Anmerkung**  
Im `create_ledger`-Aufruf müssen Sie einen Ledger-Namen und einen Berechtigungsmodus angeben. Wir empfehlen, den `STANDARD` Berechtigungsmodus zu verwenden, um die Sicherheit Ihrer Ledger-Daten zu maximieren.
Wenn Sie einen Ledger erstellen, ist der *Löschschutz* standardmäßig aktiviert. Dies ist eine Funktion in QLDB, die verhindert, dass Ledger von Benutzern gelöscht werden. Sie haben die Möglichkeit, den Löschschutz bei der Ledger-Erstellung mithilfe der QLDB-API oder der () zu deaktivieren. AWS Command Line Interface AWS CLI
Optional können Sie auch Tags angeben, die Ihrem Ledger angefügt werden sollen.

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python create_ledger.py
   ```

Fahren Sie zum Überprüfen der Verbindung mit dem neuen Ledger mit [Schritt 2: Testen Sie die Konnektivität zum Ledger](getting-started.python.step-2.md) fort.

# Schritt 2: Testen Sie die Konnektivität zum Ledger
<a name="getting-started.python.step-2"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

In diesem Schritt überprüfen Sie, ob Sie über den Transaktionsdaten-API-Endpunkt eine Verbindung zum `vehicle-registration` Ledger in Amazon QLDB herstellen können.

**So testen Sie die Verbindung zum Ledger**

1. Verwenden Sie das folgende Programm (`connect_to_ledger.py`), um eine Datensitzungsverbindung mit dem Ledger `vehicle-registration` zu erstellen.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from botocore.exceptions import ClientError
   
   from pyqldb.driver.qldb_driver import QldbDriver
   from pyqldbsamples.constants import Constants
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def create_qldb_driver(ledger_name=Constants.LEDGER_NAME, region_name=None, endpoint_url=None, boto3_session=None):
       """
       Create a QLDB driver for executing transactions.
   
       :type ledger_name: str
       :param ledger_name: The QLDB ledger name.
   
       :type region_name: str
       :param region_name: See [1].
   
       :type endpoint_url: str
       :param endpoint_url: See [1].
   
       :type boto3_session: :py:class:`boto3.session.Session`
       :param boto3_session: The boto3 session to create the client with (see [1]).
   
       :rtype: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :return: A QLDB driver object.
   
       [1]: `Boto3 Session.client Reference <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html#boto3.session.Session.client>`.
       """
       qldb_driver = QldbDriver(ledger_name=ledger_name, region_name=region_name, endpoint_url=endpoint_url,
                                boto3_session=boto3_session)
       return qldb_driver
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Connect to a given ledger using default settings.
       """
       try:
           with create_qldb_driver(ledger_name) as driver:
               logger.info('Listing table names ')
               for table in driver.list_tables():
                   logger.info(table)
       except ClientError as ce:
           logger.exception('Unable to list tables.')
           raise ce
   
   
   if __name__ == '__main__':
       main()
   ```

**Anmerkung**  
Um Datentransaktionen in Ihrem Ledger auszuführen, müssen Sie ein QLDB-Treiberobjekt erstellen, um eine Verbindung zu einem bestimmten Ledger herzustellen. Dies ist ein anderes Client-Objekt als das `qldb_client`-Objekt, das Sie im vorherigen Schritt zum Erstellen des Ledgers verwendet haben. Dieser vorherige Client wird nur verwendet, um die in der aufgeführten Verwaltungs-API-Operationen auszuführen. [Amazon QLDB API-Referenz](api-reference.md)
Sie müssen einen Ledger-Namen angeben, wenn Sie dieses Treiberobjekt erstellen.

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from botocore.exceptions import ClientError
   
   from pyqldb.driver.pooled_qldb_driver import PooledQldbDriver
   from pyqldbsamples.constants import Constants
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def create_qldb_driver(ledger_name=Constants.LEDGER_NAME, region_name=None, endpoint_url=None, boto3_session=None):
       """
       Create a QLDB driver for creating sessions.
   
       :type ledger_name: str
       :param ledger_name: The QLDB ledger name.
   
       :type region_name: str
       :param region_name: See [1].
   
       :type endpoint_url: str
       :param endpoint_url: See [1].
   
       :type boto3_session: :py:class:`boto3.session.Session`
       :param boto3_session: The boto3 session to create the client with (see [1]).
   
       :rtype: :py:class:`pyqldb.driver.pooled_qldb_driver.PooledQldbDriver`
       :return: A pooled QLDB driver object.
   
       [1]: `Boto3 Session.client Reference <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html#boto3.session.Session.client>`.
       """
       qldb_driver = PooledQldbDriver(ledger_name=ledger_name, region_name=region_name, endpoint_url=endpoint_url,
                                      boto3_session=boto3_session)
       return qldb_driver
   
   
   def create_qldb_session():
       """
       Retrieve a QLDB session object.
   
       :rtype: :py:class:`pyqldb.session.pooled_qldb_session.PooledQldbSession`
       :return: A pooled QLDB session object.
       """
       qldb_session = pooled_qldb_driver.get_session()
       return qldb_session
   
   
   pooled_qldb_driver = create_qldb_driver()
   
   
   if __name__ == '__main__':
       """
       Connect to a session for a given ledger using default settings.
       """
       try:
           qldb_session = create_qldb_session()
           logger.info('Listing table names ')
           for table in qldb_session.list_tables():
               logger.info(table)
       except ClientError:
           logger.exception('Unable to create session.')
   ```

**Anmerkung**  
Um Datentransaktionen in Ihrem Ledger auszuführen, müssen Sie ein QLDB-Treiberobjekt erstellen, um eine Verbindung zu einem bestimmten Ledger herzustellen. Dies ist ein anderes Client-Objekt als das `qldb_client`-Objekt, das Sie im vorherigen Schritt zum Erstellen des Ledgers verwendet haben. Dieser vorherige Client wird nur verwendet, um die in der aufgeführten Verwaltungs-API-Operationen auszuführen. [Amazon QLDB API-Referenz](api-reference.md)
Erstellen Sie zunächst ein gepooltes QLDB-Treiberobjekt. Beim Erstellen dieses Treibers müssen Sie einen Ledger-Namen angeben.
Anschließend können Sie Sitzungen über dieses Treiberobjekt im Pool erstellen.

------

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python connect_to_ledger.py
   ```

Fahren Sie zum Erstellen von Tabellen im `vehicle-registration`-Ledger mit [Schritt 3: Erstellen Sie Tabellen, Indizes und Beispieldaten](getting-started.python.step-3.md) fort.

# Schritt 3: Erstellen Sie Tabellen, Indizes und Beispieldaten
<a name="getting-started.python.step-3"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Wenn Ihr Amazon QLDB-Ledger aktiv ist und Verbindungen akzeptiert, können Sie damit beginnen, Tabellen mit Daten über Fahrzeuge, deren Besitzer und deren Zulassungsinformationen zu erstellen. Nach dem Erstellen der Tabellen und Indizes können Sie Daten in diese laden.

In diesem Schritt erstellen Sie vier Tabellen im `vehicle-registration`-Ledger:
+ `VehicleRegistration`
+ `Vehicle`
+ `Person`
+ `DriversLicense`

Außerdem erzeugen Sie die folgenden Indizes.


****  

| Tabellenname | Feld | 
| --- | --- | 
| VehicleRegistration | VIN | 
| VehicleRegistration | LicensePlateNumber | 
| Vehicle | VIN | 
| Person | GovId | 
| DriversLicense | LicenseNumber | 
| DriversLicense | PersonId | 

Beim Einfügen von Beispieldaten fügen Sie zunächst Dokumente in die `Person`-Tabelle ein. Anschließend verwenden Sie die vom System zugewiesene `id` aus den `Person`-Dokumenten, um die entsprechenden Felder in den relevanten `VehicleRegistration`- und `DriversLicense`-Dokumenten auszufüllen.

**Tipp**  
Es hat sich bewährt, das vom System zugewiesene `id` Dokument als Fremdschlüssel zu verwenden. Sie können zwar Felder definieren, die eindeutige Kennungen (z. B. eine Kfz-VIN) sein sollen, die echte eindeutige Kennung eines Dokuments ist aber seine `id`. Dieses Feld ist in den Metadaten des Dokuments enthalten, die Sie in der *festgeschriebenen Ansicht* (d. h. in der vom System definierten Ansicht der Tabelle) abrufen können.  
Weitere Hinweise zu Ansichten in QLDB finden Sie unter. [Schlüsselkonzepte](ledger-structure.md) Weitere Informationen zu Metadaten finden Sie unter [Metadaten von Dokumenten werden abgefragt](working.metadata.md).

**So erstellen Sie Tabellen und Indizes**

1. Verwenden Sie das folgende Programm (`create_table.py`), um die oben genannten Tabellen zu erstellen.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def create_table(driver, table_name):
       """
       Create a table with the specified name.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type table_name: str
       :param table_name: Name of the table to create.
   
       :rtype: int
       :return: The number of changes to the database.
       """
       logger.info("Creating the '{}' table...".format(table_name))
       statement = 'CREATE TABLE {}'.format(table_name)
       cursor = driver.execute_lambda(lambda executor: executor.execute_statement(statement))
       logger.info('{} table created successfully.'.format(table_name))
       return len(list(cursor))
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Create registrations, vehicles, owners, and licenses tables.
       """
       try:
           with create_qldb_driver(ledger_name) as driver:
               create_table(driver, Constants.DRIVERS_LICENSE_TABLE_NAME)
               create_table(driver, Constants.PERSON_TABLE_NAME)
               create_table(driver, Constants.VEHICLE_TABLE_NAME)
               create_table(driver, Constants.VEHICLE_REGISTRATION_TABLE_NAME)
               logger.info('Tables created successfully.')
       except Exception as e:
           logger.exception('Errors creating tables.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def create_table(transaction_executor, table_name):
       """
       Create a table with the specified name using an Executor object.
   
       :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: Name of the table to create.
   
       :rtype: int
       :return: The number of changes to the database.
       """
       logger.info("Creating the '{}' table...".format(table_name))
       statement = 'CREATE TABLE {}'.format(table_name)
       cursor = transaction_executor.execute_statement(statement)
       logger.info('{} table created successfully.'.format(table_name))
       return len(list(cursor))
   
   
   if __name__ == '__main__':
       """
       Create registrations, vehicles, owners, and licenses tables in a single transaction.
       """
       try:
           with create_qldb_session() as session:
               session.execute_lambda(lambda x: create_table(x, Constants.DRIVERS_LICENSE_TABLE_NAME) and
                                      create_table(x, Constants.PERSON_TABLE_NAME) and
                                      create_table(x, Constants.VEHICLE_TABLE_NAME) and
                                      create_table(x, Constants.VEHICLE_REGISTRATION_TABLE_NAME),
                                      lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
               logger.info('Tables created successfully.')
       except Exception:
           logger.exception('Errors creating tables.')
   ```

------
**Anmerkung**  
Dieses Programm demonstriert, wie die Funktion verwendet wird`execute_lambda`. In diesem Beispiel führen Sie mehrere `CREATE TABLE`-PartiQL-Anweisungen mit einem einzelnen Lambda-Ausdruck aus.  
Diese Ausführungsfunktion startet implizit eine Transaktion, führt alle Anweisungen im Lambda aus und schreibt dann die Transaktion automatisch fest.

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python create_table.py
   ```

1. Verwenden Sie das folgende Programm (`create_index.py`), um wie zuvor beschrieben Indizes für die Tabellen zu erstellen.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def create_index(driver, table_name, index_attribute):
       """
       Create an index for a particular table.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type table_name: str
       :param table_name: Name of the table to add indexes for.
   
       :type index_attribute: str
       :param index_attribute: Index to create on a single attribute.
   
       :rtype: int
       :return: The number of changes to the database.
       """
       logger.info("Creating index on '{}'...".format(index_attribute))
       statement = 'CREATE INDEX on {} ({})'.format(table_name, index_attribute)
       cursor = driver.execute_lambda(lambda executor: executor.execute_statement(statement))
       return len(list(cursor))
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Create indexes on tables in a particular ledger.
       """
       logger.info('Creating indexes on all tables...')
       try:
           with create_qldb_driver(ledger_name) as driver:
               create_index(driver, Constants.PERSON_TABLE_NAME, Constants.GOV_ID_INDEX_NAME)
               create_index(driver, Constants.VEHICLE_TABLE_NAME, Constants.VEHICLE_VIN_INDEX_NAME)
               create_index(driver, Constants.VEHICLE_REGISTRATION_TABLE_NAME, Constants.LICENSE_PLATE_NUMBER_INDEX_NAME)
               create_index(driver, Constants.VEHICLE_REGISTRATION_TABLE_NAME, Constants.VEHICLE_VIN_INDEX_NAME)
               create_index(driver, Constants.DRIVERS_LICENSE_TABLE_NAME, Constants.PERSON_ID_INDEX_NAME)
               create_index(driver, Constants.DRIVERS_LICENSE_TABLE_NAME, Constants.LICENSE_NUMBER_INDEX_NAME)
               logger.info('Indexes created successfully.')
       except Exception as e:
           logger.exception('Unable to create indexes.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def create_index(transaction_executor, table_name, index_attribute):
       """
       Create an index for a particular 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: Name of the table to add indexes for.
   
       :type index_attribute: str
       :param index_attribute: Index to create on a single attribute.
   
       :rtype: int
       :return: The number of changes to the database.
       """
       logger.info("Creating index on '{}'...".format(index_attribute))
       statement = 'CREATE INDEX on {} ({})'.format(table_name, index_attribute)
       cursor = transaction_executor.execute_statement(statement)
       return len(list(cursor))
   
   
   if __name__ == '__main__':
       """
       Create indexes on tables in a particular ledger.
       """
       logger.info('Creating indexes on all tables in a single transaction...')
       try:
           with create_qldb_session() as session:
               session.execute_lambda(lambda x: create_index(x, Constants.PERSON_TABLE_NAME,
                                                             Constants.GOV_ID_INDEX_NAME)
                                      and create_index(x, Constants.VEHICLE_TABLE_NAME,
                                                       Constants.VEHICLE_VIN_INDEX_NAME)
                                      and create_index(x, Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                                                       Constants.LICENSE_PLATE_NUMBER_INDEX_NAME)
                                      and create_index(x, Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                                                       Constants.VEHICLE_VIN_INDEX_NAME)
                                      and create_index(x, Constants.DRIVERS_LICENSE_TABLE_NAME,
                                                       Constants.PERSON_ID_INDEX_NAME)
                                      and create_index(x, Constants.DRIVERS_LICENSE_TABLE_NAME,
                                                       Constants.LICENSE_NUMBER_INDEX_NAME),
                                      lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
               logger.info('Indexes created successfully.')
       except Exception:
           logger.exception('Unable to create indexes.')
   ```

------

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python create_index.py
   ```

**So laden Sie Daten in die Tabellen**

1. Überprüfen Sie die folgende Datei (`sample_data.py`), die Daten darstellt, die Sie in die `vehicle-registration`-Tabellen einfügen. Diese Datei wird ebenfalls aus dem `amazon.ion`-Paket importiert, um Hilfsfunktionen zum Konvertieren, Analysieren und Drucken von [Amazon Ion](ion.md)-Daten bereitzustellen. 

   ```
   # 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))
   ```
**Anmerkung**  
Die `get_document_ids` Funktion führt eine Abfrage aus, die ein vom System zugewiesenes Dokument aus einer Tabelle zurückgibt. IDs Weitere Informationen hierzu finden Sie unter [Verwenden der BY-Klausel zur Abfrage der Dokument-ID](working.metadata.by-clause.md).

1. Verwenden Sie das folgende Programm (`insert_document.py`), um Beispieldaten in Ihre Tabellen einzufügen.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.model.sample_data import convert_object_to_ion, SampleData, get_document_ids_from_dml_results
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def update_person_id(document_ids):
       """
       Update the PersonId value for DriversLicense records and the PrimaryOwner value for VehicleRegistration records.
   
       :type document_ids: list
       :param document_ids: List of document IDs.
   
       :rtype: list
       :return: Lists of updated DriversLicense records and updated VehicleRegistration records.
       """
       new_drivers_licenses = SampleData.DRIVERS_LICENSE.copy()
       new_vehicle_registrations = SampleData.VEHICLE_REGISTRATION.copy()
       for i in range(len(SampleData.PERSON)):
           drivers_license = new_drivers_licenses[i]
           registration = new_vehicle_registrations[i]
           drivers_license.update({'PersonId': str(document_ids[i])})
           registration['Owners']['PrimaryOwner'].update({'PersonId': str(document_ids[i])})
       return new_drivers_licenses, new_vehicle_registrations
   
   
   def insert_documents(driver, table_name, documents):
       """
       Insert the given list of documents into a table in a single transaction.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type table_name: str
       :param table_name: Name of the table to insert documents into.
   
       :type documents: list
       :param documents: List of documents to insert.
   
       :rtype: list
       :return: List of documents IDs for the newly inserted documents.
       """
       logger.info('Inserting some documents in the {} table...'.format(table_name))
       statement = 'INSERT INTO {} ?'.format(table_name)
       cursor = driver.execute_lambda(lambda executor: executor.execute_statement(statement,
                                                                                  convert_object_to_ion(documents)))
       list_of_document_ids = get_document_ids_from_dml_results(cursor)
   
       return list_of_document_ids
   
   
   def update_and_insert_documents(driver):
       """
       Handle the insertion of documents and updating PersonIds.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
       """
       list_ids = insert_documents(driver, Constants.PERSON_TABLE_NAME, SampleData.PERSON)
   
       logger.info("Updating PersonIds for 'DriversLicense' and PrimaryOwner for 'VehicleRegistration'...")
       new_licenses, new_registrations = update_person_id(list_ids)
   
       insert_documents(driver, Constants.VEHICLE_TABLE_NAME, SampleData.VEHICLE)
       insert_documents(driver, Constants.VEHICLE_REGISTRATION_TABLE_NAME, new_registrations)
       insert_documents(driver, Constants.DRIVERS_LICENSE_TABLE_NAME, new_licenses)
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Insert documents into a table in a QLDB ledger.
       """
       try:
           with create_qldb_driver(ledger_name) as driver:
               # An INSERT statement creates the initial revision of a document with a version number of zero.
               # QLDB also assigns a unique document identifier in GUID format as part of the metadata.
               update_and_insert_documents(driver)
               logger.info('Documents inserted successfully!')
       except Exception as e:
           logger.exception('Error inserting or updating documents.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.model.sample_data import convert_object_to_ion, SampleData, get_document_ids_from_dml_results
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def update_person_id(document_ids):
       """
       Update the PersonId value for DriversLicense records and the PrimaryOwner value for VehicleRegistration records.
   
       :type document_ids: list
       :param document_ids: List of document IDs.
   
       :rtype: list
       :return: Lists of updated DriversLicense records and updated VehicleRegistration records.
       """
       new_drivers_licenses = SampleData.DRIVERS_LICENSE.copy()
       new_vehicle_registrations = SampleData.VEHICLE_REGISTRATION.copy()
       for i in range(len(SampleData.PERSON)):
           drivers_license = new_drivers_licenses[i]
           registration = new_vehicle_registrations[i]
           drivers_license.update({'PersonId': str(document_ids[i])})
           registration['Owners']['PrimaryOwner'].update({'PersonId': str(document_ids[i])})
       return new_drivers_licenses, new_vehicle_registrations
   
   
   def insert_documents(transaction_executor, table_name, documents):
       """
       Insert the given list of documents into a table in a single transaction.
   
       :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: Name of the table to insert documents into.
   
       :type documents: list
       :param documents: List of documents to insert.
   
       :rtype: list
       :return: List of documents IDs for the newly inserted documents.
       """
       logger.info('Inserting some documents in the {} table...'.format(table_name))
       statement = 'INSERT INTO {} ?'.format(table_name)
       cursor = transaction_executor.execute_statement(statement, convert_object_to_ion(documents))
       list_of_document_ids = get_document_ids_from_dml_results(cursor)
   
       return list_of_document_ids
   
   
   def update_and_insert_documents(transaction_executor):
       """
       Handle the insertion of documents and updating PersonIds all in a single transaction.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
       """
       list_ids = insert_documents(transaction_executor, Constants.PERSON_TABLE_NAME, SampleData.PERSON)
   
       logger.info("Updating PersonIds for 'DriversLicense' and PrimaryOwner for 'VehicleRegistration'...")
       new_licenses, new_registrations = update_person_id(list_ids)
   
       insert_documents(transaction_executor, Constants.VEHICLE_TABLE_NAME, SampleData.VEHICLE)
       insert_documents(transaction_executor, Constants.VEHICLE_REGISTRATION_TABLE_NAME, new_registrations)
       insert_documents(transaction_executor, Constants.DRIVERS_LICENSE_TABLE_NAME, new_licenses)
   
   
   if __name__ == '__main__':
       """
       Insert documents into a table in a QLDB ledger.
       """
       try:
           with create_qldb_session() as session:
               # An INSERT statement creates the initial revision of a document with a version number of zero.
               # QLDB also assigns a unique document identifier in GUID format as part of the metadata.
               session.execute_lambda(lambda executor: update_and_insert_documents(executor),
                                      lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
               logger.info('Documents inserted successfully!')
       except Exception:
           logger.exception('Error inserting or updating documents.')
   ```

------
**Anmerkung**  
Dieses Programm veranschaulicht, wie die `execute_statement`-Funktion mit parametrisierten Werten aufgerufen wird. Zusätzlich zu der PartiQL-Anweisung, die Sie ausführen möchten, können Sie Datenparameter übergeben. Verwenden Sie ein Fragezeichen (`?`) als Variablenplatzhalter in Ihrer Anweisungszeichenfolge.
Wenn eine `INSERT`-Anweisung erfolgreich ist, wird die `id` jedes eingefügten Dokuments zurückgegeben.

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python insert_document.py
   ```

Als Nächstes können Sie mit `SELECT`-Anweisungen Daten aus den Tabellen im `vehicle-registration`-Ledger lesen. Fahren Sie mit [Schritt 4: Fragen Sie die Tabellen in einem Hauptbuch ab](getting-started.python.step-4.md) fort.

# Schritt 4: Fragen Sie die Tabellen in einem Hauptbuch ab
<a name="getting-started.python.step-4"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Nachdem Sie Tabellen in einem Amazon QLDB-Ledger erstellt und mit Daten geladen haben, können Sie Abfragen ausführen, um die gerade eingefügten Fahrzeugregistrierungsdaten zu überprüfen. QLDB verwendet [PartiQL](ql-reference.md) als Abfragesprache und [Amazon Ion](ion.md) als dokumentenorientiertes Datenmodell.

PartiQL ist eine SQL-kompatible Open-Source-Abfragesprache, die für die Verwendung mit Ion erweitert wurde. Mit PartiSQL können Sie Ihre Daten mit vertrauten SQL-Operatoren einfügen, abfragen und verwalten. Amazon Ion ist eine Obermenge von JSON. Ion ist ein dokumentenbasiertes Open-Source-Datenformat, das Ihnen die Flexibilität bietet, strukturierte, halbstrukturierte und verschachtelte Daten zu speichern und zu verarbeiten.

In diesem Schritt verwenden Sie `SELECT`-Anweisungen zum Lesen von Daten aus den Tabellen im `vehicle-registration`-Ledger.

**Warnung**  
Wenn Sie eine Abfrage in QLDB ohne indizierte Suche ausführen, wird ein vollständiger Tabellenscan aufgerufen. PartiQL unterstützt solche Abfragen, weil es SQL-kompatibel ist. Führen *Sie jedoch keine* Tabellenscans für Produktionsanwendungsfälle in QLDB aus. Tabellenscans können bei großen Tabellen zu Leistungsproblemen führen, einschließlich Parallelitätskonflikten und Transaktions-Timeouts.  
Um Tabellenscans zu vermeiden, müssen Sie Anweisungen mit einer `WHERE` Prädikatklausel mithilfe eines *Gleichheitsoperators* für ein indiziertes Feld oder eine Dokument-ID ausführen, z. B. oder. `WHERE indexedField = 123` `WHERE indexedField IN (456, 789)` Weitere Informationen finden Sie unter [Optimieren der Abfrageleistung](working.optimize.md).

**So fragen Sie die Tabellen ab**

1. Verwenden Sie das folgende Programm (`find_vehicles.py`), um alle Fahrzeuge abzufragen, die für eine Person in Ihrem Ledger zugelassen sind.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.model.sample_data import get_document_ids, print_result, SampleData
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def find_vehicles_for_owner(driver, gov_id):
       """
       Find vehicles registered under a driver using their government ID.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type gov_id: str
       :param gov_id: The owner's government ID.
       """
       document_ids = driver.execute_lambda(lambda executor: get_document_ids(executor, Constants.PERSON_TABLE_NAME,
                                                                              'GovId', gov_id))
   
       query = "SELECT Vehicle FROM Vehicle INNER JOIN VehicleRegistration AS r " \
               "ON Vehicle.VIN = r.VIN WHERE r.Owners.PrimaryOwner.PersonId = ?"
   
       for ids in document_ids:
           cursor = driver.execute_lambda(lambda executor: executor.execute_statement(query, ids))
           logger.info('List of Vehicles for owner with GovId: {}...'.format(gov_id))
           print_result(cursor)
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Find all vehicles registered under a person.
       """
       try:
           with create_qldb_driver(ledger_name) as driver:
               # Find all vehicles registered under a person.
               gov_id = SampleData.PERSON[0]['GovId']
               find_vehicles_for_owner(driver, gov_id)
       except Exception as e:
           logger.exception('Error getting vehicles for owner.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.model.sample_data import get_document_ids, print_result, SampleData
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def find_vehicles_for_owner(transaction_executor, gov_id):
       """
       Find vehicles registered under a driver using their government ID.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type gov_id: str
       :param gov_id: The owner's government ID.
       """
       document_ids = get_document_ids(transaction_executor, Constants.PERSON_TABLE_NAME, 'GovId', gov_id)
   
       query = "SELECT Vehicle FROM Vehicle INNER JOIN VehicleRegistration AS r " \
               "ON Vehicle.VIN = r.VIN WHERE r.Owners.PrimaryOwner.PersonId = ?"
   
       for ids in document_ids:
           cursor = transaction_executor.execute_statement(query, ids)
           logger.info('List of Vehicles for owner with GovId: {}...'.format(gov_id))
           print_result(cursor)
   
   
   if __name__ == '__main__':
       """
       Find all vehicles registered under a person.
       """
       try:
           with create_qldb_session() as session:
               # Find all vehicles registered under a person.
               gov_id = SampleData.PERSON[0]['GovId']
               session.execute_lambda(lambda executor: find_vehicles_for_owner(executor, gov_id),
                                      lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
       except Exception:
           logger.exception('Error getting vehicles for owner.')
   ```

------
**Anmerkung**  
Zunächst fragt dieses Programm die `Person`-Tabelle nach dem Dokument mit `GovId LEWISR261LL` ab, um sein `id`-Metadatenfeld abzurufen.  
Anschließend verwendet es dieses Dokument `id` als Fremdschlüssel, um die `VehicleRegistration`-Tabelle nach `PrimaryOwner.PersonId` abzufragen. Es tritt führt außerdem `VehicleRegistration` mit der `Vehicle`-Tabelle im `VIN`-Feld zusammen.

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python find_vehicles.py
   ```

Weitere Informationen zum Ändern von Dokumenten in den Tabellen im `vehicle-registration`-Ledger finden Sie unter [Schritt 5: Dokumente in einem Ledger ändern](getting-started.python.step-5.md).

# Schritt 5: Dokumente in einem Ledger ändern
<a name="getting-started.python.step-5"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Da Sie nun über Daten verfügen, mit denen Sie arbeiten können, können Sie damit beginnen, Änderungen an Dokumenten im `vehicle-registration` Hauptbuch in Amazon QLDB vorzunehmen. In diesem Schritt verdeutlichen die folgenden Codebeispiele, wie Sie Data Manipulation Language (DML)-Anweisungen ausführen. Diese Anweisungen aktualisieren den primären Eigentümer eines Fahrzeugs und fügen einem anderen Fahrzeug einen sekundären Eigentümer hinzu.

**So ändern Sie Dokumente**

1. Verwenden Sie das folgende Programm (`transfer_vehicle_ownership.py`), um den primären Besitzer des Fahrzeugs mit VIN `1N4AL11D75C109151` in Ihrem Ledger zu aktualisieren.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.add_secondary_owner import get_document_ids, print_result, SampleData
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.model.sample_data import convert_object_to_ion
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def find_person_from_document_id(transaction_executor, document_id):
       """
       Query a driver's information using the given ID.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type document_id: :py:class:`amazon.ion.simple_types.IonPyText`
       :param document_id: The document ID required to query for the person.
   
       :rtype: :py:class:`amazon.ion.simple_types.IonPyDict`
       :return: The resulting document from the query.
       """
       query = 'SELECT p.* FROM Person AS p BY pid WHERE pid = ?'
       cursor = transaction_executor.execute_statement(query, document_id)
       return next(cursor)
   
   
   def find_primary_owner_for_vehicle(driver, vin):
       """
       Find the primary owner of a vehicle given its VIN.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: The VIN to find primary owner for.
   
       :rtype: :py:class:`amazon.ion.simple_types.IonPyDict`
       :return: The resulting document from the query.
       """
       logger.info('Finding primary owner for vehicle with VIN: {}.'.format(vin))
       query = "SELECT Owners.PrimaryOwner.PersonId FROM VehicleRegistration AS v WHERE v.VIN = ?"
       cursor = driver.execute_lambda(lambda executor: executor.execute_statement(query, convert_object_to_ion(vin)))
       try:
           return driver.execute_lambda(lambda executor: find_person_from_document_id(executor,
                                                                                      next(cursor).get('PersonId')))
       except StopIteration:
           logger.error('No primary owner registered for this vehicle.')
           return None
   
   
   def update_vehicle_registration(driver, vin, document_id):
       """
       Update the primary owner for a vehicle using the given VIN.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: The VIN for the vehicle to operate on.
   
       :type document_id: :py:class:`amazon.ion.simple_types.IonPyText`
       :param document_id: New PersonId for the primary owner.
   
       :raises RuntimeError: If no vehicle registration was found using the given document ID and VIN.
       """
       logger.info('Updating the primary owner for vehicle with Vin: {}...'.format(vin))
       statement = "UPDATE VehicleRegistration AS r SET r.Owners.PrimaryOwner.PersonId = ? WHERE r.VIN = ?"
       cursor = driver.execute_lambda(lambda executor: executor.execute_statement(statement, document_id,
                                                                                  convert_object_to_ion(vin)))
       try:
           print_result(cursor)
           logger.info('Successfully transferred vehicle with VIN: {} to new owner.'.format(vin))
       except StopIteration:
           raise RuntimeError('Unable to transfer vehicle, could not find registration.')
   
   
   def validate_and_update_registration(driver, vin, current_owner, new_owner):
       """
       Validate the current owner of the given vehicle and transfer its ownership to a new owner.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: The VIN of the vehicle to transfer ownership of.
   
       :type current_owner: str
       :param current_owner: The GovId of the current owner of the vehicle.
   
       :type new_owner: str
       :param new_owner: The GovId of the new owner of the vehicle.
   
       :raises RuntimeError: If unable to verify primary owner.
       """
       primary_owner = find_primary_owner_for_vehicle(driver, vin)
       if primary_owner is None or primary_owner['GovId'] != current_owner:
           raise RuntimeError('Incorrect primary owner identified for vehicle, unable to transfer.')
   
       document_ids = driver.execute_lambda(lambda executor: get_document_ids(executor, Constants.PERSON_TABLE_NAME,
                                                                              'GovId', new_owner))
       update_vehicle_registration(driver, vin, document_ids[0])
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Find primary owner for a particular vehicle's VIN.
       Transfer to another primary owner for a particular vehicle's VIN.
       """
       vehicle_vin = SampleData.VEHICLE[0]['VIN']
       previous_owner = SampleData.PERSON[0]['GovId']
       new_owner = SampleData.PERSON[1]['GovId']
   
       try:
           with create_qldb_driver(ledger_name) as driver:
               validate_and_update_registration(driver, vehicle_vin, previous_owner, new_owner)
       except Exception as e:
           logger.exception('Error updating VehicleRegistration.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.add_secondary_owner import get_document_ids, print_result, SampleData
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.model.sample_data import convert_object_to_ion
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def find_person_from_document_id(transaction_executor, document_id):
       """
       Query a driver's information using the given ID.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type document_id: :py:class:`amazon.ion.simple_types.IonPyText`
       :param document_id: The document ID required to query for the person.
   
       :rtype: :py:class:`amazon.ion.simple_types.IonPyDict`
       :return: The resulting document from the query.
       """
       query = 'SELECT p.* FROM Person AS p BY pid WHERE pid = ?'
       cursor = transaction_executor.execute_statement(query, document_id)
       return next(cursor)
   
   
   def find_primary_owner_for_vehicle(transaction_executor, vin):
       """
       Find the primary owner of a vehicle given its VIN.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type vin: str
       :param vin: The VIN to find primary owner for.
   
       :rtype: :py:class:`amazon.ion.simple_types.IonPyDict`
       :return: The resulting document from the query.
       """
       logger.info('Finding primary owner for vehicle with VIN: {}.'.format(vin))
       query = "SELECT Owners.PrimaryOwner.PersonId FROM VehicleRegistration AS v WHERE v.VIN = ?"
       cursor = transaction_executor.execute_statement(query, convert_object_to_ion(vin))
       try:
           return find_person_from_document_id(transaction_executor, next(cursor).get('PersonId'))
       except StopIteration:
           logger.error('No primary owner registered for this vehicle.')
           return None
   
   
   def update_vehicle_registration(transaction_executor, vin, document_id):
       """
       Update the primary owner for a vehicle using the given VIN.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type vin: str
       :param vin: The VIN for the vehicle to operate on.
   
       :type document_id: :py:class:`amazon.ion.simple_types.IonPyText`
       :param document_id: New PersonId for the primary owner.
   
       :raises RuntimeError: If no vehicle registration was found using the given document ID and VIN.
       """
       logger.info('Updating the primary owner for vehicle with Vin: {}...'.format(vin))
       statement = "UPDATE VehicleRegistration AS r SET r.Owners.PrimaryOwner.PersonId = ? WHERE r.VIN = ?"
       cursor = transaction_executor.execute_statement(statement, document_id, convert_object_to_ion(vin))
       try:
           print_result(cursor)
           logger.info('Successfully transferred vehicle with VIN: {} to new owner.'.format(vin))
       except StopIteration:
           raise RuntimeError('Unable to transfer vehicle, could not find registration.')
   
   
   def validate_and_update_registration(transaction_executor, vin, current_owner, new_owner):
       """
       Validate the current owner of the given vehicle and transfer its ownership to a new owner in a single transaction.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type vin: str
       :param vin: The VIN of the vehicle to transfer ownership of.
   
       :type current_owner: str
       :param current_owner: The GovId of the current owner of the vehicle.
   
       :type new_owner: str
       :param new_owner: The GovId of the new owner of the vehicle.
   
       :raises RuntimeError: If unable to verify primary owner.
       """
       primary_owner = find_primary_owner_for_vehicle(transaction_executor, vin)
       if primary_owner is None or primary_owner['GovId'] != current_owner:
           raise RuntimeError('Incorrect primary owner identified for vehicle, unable to transfer.')
   
       document_id = next(get_document_ids(transaction_executor, Constants.PERSON_TABLE_NAME, 'GovId', new_owner))
   
       update_vehicle_registration(transaction_executor, vin, document_id)
   
   
   if __name__ == '__main__':
       """
       Find primary owner for a particular vehicle's VIN.
       Transfer to another primary owner for a particular vehicle's VIN.
       """
       vehicle_vin = SampleData.VEHICLE[0]['VIN']
       previous_owner = SampleData.PERSON[0]['GovId']
       new_owner = SampleData.PERSON[1]['GovId']
   
       try:
           with create_qldb_session() as session:
               session.execute_lambda(lambda executor: validate_and_update_registration(executor, vehicle_vin,
                                                                                        previous_owner, new_owner),
                                      retry_indicator=lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
       except Exception:
           logger.exception('Error updating VehicleRegistration.')
   ```

------

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python transfer_vehicle_ownership.py
   ```

1. Verwenden Sie das folgende Programm (`add_secondary_owner.py`), um dem Fahrzeug mit VIN `KM8SRDHF6EU074761` in Ihrem Ledger einen sekundären Besitzer hinzuzufügen.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.model.sample_data import to_ion_struct, get_document_ids, print_result, SampleData, \
       convert_object_to_ion
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def get_document_id_by_gov_id(driver, government_id):
       """
       Find a driver's person ID using the given government ID.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type government_id: str
       :param government_id: A driver's government ID.
   
       :rtype: list
       :return: A list of document IDs.
       """
       logger.info("Finding secondary owner's person ID using given government ID: {}.".format(government_id))
       return driver.execute_lambda(lambda executor: get_document_ids(executor, Constants.PERSON_TABLE_NAME, 'GovId',
                                                                      government_id))
   
   
   def is_secondary_owner_for_vehicle(driver, vin, secondary_owner_id):
       """
       Check whether a secondary owner has already been registered for the given VIN.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: VIN of the vehicle to query.
   
       :type secondary_owner_id: str
       :param secondary_owner_id: The secondary owner's person ID.
   
       :rtype: bool
       :return: If the driver has already been registered.
       """
       logger.info('Finding secondary owners for vehicle with VIN: {}...'.format(vin))
       query = 'SELECT Owners.SecondaryOwners FROM VehicleRegistration AS v WHERE v.VIN = ?'
       rows = driver.execute_lambda(lambda executor: executor.execute_statement(query, convert_object_to_ion(vin)))
   
       for row in rows:
           secondary_owners = row.get('SecondaryOwners')
           person_ids = map(lambda owner: owner.get('PersonId').text, secondary_owners)
           if secondary_owner_id in person_ids:
               return True
       return False
   
   
   def add_secondary_owner_for_vin(driver, vin, parameter):
       """
       Add a secondary owner into `VehicleRegistration` table for a particular VIN.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: VIN of the vehicle to add a secondary owner for.
   
       :type parameter: :py:class:`amazon.ion.simple_types.IonPyValue`
       :param parameter: The Ion value or Python native type that is convertible to Ion for filling in parameters of the
                         statement.
       """
       logger.info('Inserting secondary owner for vehicle with VIN: {}...'.format(vin))
       statement = "FROM VehicleRegistration AS v WHERE v.VIN = ? INSERT INTO v.Owners.SecondaryOwners VALUE ?"
   
       cursor = driver.execute_lambda(lambda executor: executor.execute_statement(statement, convert_object_to_ion(vin),
                                                                                  parameter))
       logger.info('VehicleRegistration Document IDs which had secondary owners added: ')
       print_result(cursor)
   
   
   def register_secondary_owner(driver, vin, gov_id):
       """
       Register a secondary owner for a vehicle if they are not already registered.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: VIN of the vehicle to register a secondary owner for.
   
       :type gov_id: str
       :param gov_id: The government ID of the owner.
       """
       logger.info('Finding the secondary owners for vehicle with VIN: {}.'.format(vin))
   
       document_ids = get_document_id_by_gov_id(driver, gov_id)
   
       for document_id in document_ids:
           if is_secondary_owner_for_vehicle(driver, vin, document_id):
               logger.info('Person with ID {} has already been added as a secondary owner of this vehicle.'.format(gov_id))
           else:
               add_secondary_owner_for_vin(driver, vin, to_ion_struct('PersonId', document_id))
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Finds and adds secondary owners for a vehicle.
       """
       vin = SampleData.VEHICLE[1]['VIN']
       gov_id = SampleData.PERSON[0]['GovId']
       try:
           with create_qldb_driver(ledger_name) as driver:
               register_secondary_owner(driver, vin, gov_id)
               logger.info('Secondary owners successfully updated.')
       except Exception as e:
           logger.exception('Error adding secondary owner.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.model.sample_data import to_ion_struct, get_document_ids, print_result, SampleData, \
       convert_object_to_ion
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def get_document_id_by_gov_id(transaction_executor, government_id):
       """
       Find a driver's person ID using the given government ID.
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
       :type government_id: str
       :param government_id: A driver's government ID.
       :rtype: list
       :return: A list of document IDs.
       """
       logger.info("Finding secondary owner's person ID using given government ID: {}.".format(government_id))
       return get_document_ids(transaction_executor, Constants.PERSON_TABLE_NAME, 'GovId', government_id)
   
   
   def is_secondary_owner_for_vehicle(transaction_executor, vin, secondary_owner_id):
       """
       Check whether a secondary owner has already been registered for the given VIN.
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
       :type vin: str
       :param vin: VIN of the vehicle to query.
       :type secondary_owner_id: str
       :param secondary_owner_id: The secondary owner's person ID.
       :rtype: bool
       :return: If the driver has already been registered.
       """
       logger.info('Finding secondary owners for vehicle with VIN: {}...'.format(vin))
       query = 'SELECT Owners.SecondaryOwners FROM VehicleRegistration AS v WHERE v.VIN = ?'
       rows = transaction_executor.execute_statement(query, convert_object_to_ion(vin))
   
       for row in rows:
           secondary_owners = row.get('SecondaryOwners')
           person_ids = map(lambda owner: owner.get('PersonId').text, secondary_owners)
           if secondary_owner_id in person_ids:
               return True
       return False
   
   
   def add_secondary_owner_for_vin(transaction_executor, vin, parameter):
       """
       Add a secondary owner into `VehicleRegistration` table for a particular VIN.
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
       :type vin: str
       :param vin: VIN of the vehicle to add a secondary owner for.
       :type parameter: :py:class:`amazon.ion.simple_types.IonPyValue`
       :param parameter: The Ion value or Python native type that is convertible to Ion for filling in parameters of the
                         statement.
       """
       logger.info('Inserting secondary owner for vehicle with VIN: {}...'.format(vin))
       statement = "FROM VehicleRegistration AS v WHERE v.VIN = '{}' INSERT INTO v.Owners.SecondaryOwners VALUE ?"\
           .format(vin)
   
       cursor = transaction_executor.execute_statement(statement, parameter)
       logger.info('VehicleRegistration Document IDs which had secondary owners added: ')
       print_result(cursor)
   
   
   def register_secondary_owner(transaction_executor, vin, gov_id):
       """
       Register a secondary owner for a vehicle if they are not already registered.
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
       :type vin: str
       :param vin: VIN of the vehicle to register a secondary owner for.
       :type gov_id: str
       :param gov_id: The government ID of the owner.
       """
       logger.info('Finding the secondary owners for vehicle with VIN: {}.'.format(vin))
       document_ids = get_document_id_by_gov_id(transaction_executor, gov_id)
   
       for document_id in document_ids:
           if is_secondary_owner_for_vehicle(transaction_executor, vin, document_id):
               logger.info('Person with ID {} has already been added as a secondary owner of this vehicle.'.format(gov_id))
           else:
               add_secondary_owner_for_vin(transaction_executor, vin, to_ion_struct('PersonId', document_id))
   
   
   if __name__ == '__main__':
       """
       Finds and adds secondary owners for a vehicle.
       """
       vin = SampleData.VEHICLE[1]['VIN']
       gov_id = SampleData.PERSON[0]['GovId']
       try:
           with create_qldb_session() as session:
               session.execute_lambda(lambda executor: register_secondary_owner(executor, vin, gov_id),
                                      lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
               logger.info('Secondary owners successfully updated.')
       except Exception:
           logger.exception('Error adding secondary owner.')
   ```

------

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python add_secondary_owner.py
   ```

Informationen zum Überprüfen dieser Änderungen im `vehicle-registration`-Ledger finden Sie unter [Schritt 6: Den Revisionsverlauf für ein Dokument anzeigen](getting-started.python.step-6.md).

# Schritt 6: Den Revisionsverlauf für ein Dokument anzeigen
<a name="getting-started.python.step-6"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Nach dem Bearbeiten der Zulassungsdaten für ein Fahrzeug im vorherigen Schritt können Sie den Verlauf aller registrierten Eigentümer und alle anderen aktualisierten Felder abfragen. In diesem Schritt führen Sie eine Abfrage des Revisionsverlaufs eines Dokuments in der `VehicleRegistration`-Tabelle in Ihrem `vehicle-registration`-Ledger durch.

**So zeigen Sie den Revisionsverlauf an**

1. Verwenden Sie das folgende Programm (`query_history.py`), um den Versionsverlauf des `VehicleRegistration`-Dokuments mit VIN `1N4AL11D75C109151` abzufragen.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from datetime import datetime, timedelta
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.model.sample_data import print_result, get_document_ids, SampleData
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def format_date_time(date_time):
       """
       Format the given date time to a string.
   
       :type date_time: :py:class:`datetime.datetime`
       :param date_time: The date time to format.
   
       :rtype: str
       :return: The formatted date time.
       """
       return date_time.strftime('`%Y-%m-%dT%H:%M:%S.%fZ`')
   
   
   def previous_primary_owners(driver, vin):
       """
       Find previous primary owners for the given VIN in a single transaction.
       In this example, query the `VehicleRegistration` history table to find all previous primary owners for a VIN.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: VIN to find previous primary owners for.
       """
       person_ids = driver.execute_lambda(lambda executor: get_document_ids(executor,
                                                                            Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                                                                            'VIN', vin))
   
       todays_date = datetime.utcnow() - timedelta(seconds=1)
       three_months_ago = todays_date - timedelta(days=90)
       query = 'SELECT data.Owners.PrimaryOwner, metadata.version FROM history({}, {}, {}) AS h WHERE h.metadata.id = ?'.\
           format(Constants.VEHICLE_REGISTRATION_TABLE_NAME, format_date_time(three_months_ago),
                  format_date_time(todays_date))
   
       for ids in person_ids:
           logger.info("Querying the 'VehicleRegistration' table's history using VIN: {}.".format(vin))
           cursor = driver.execute_lambda(lambda executor: executor.execute_statement(query, ids))
           if not (print_result(cursor)) > 0:
               logger.info('No modification history found within the given time frame for document ID: {}'.format(ids))
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Query a table's history for a particular set of documents.
       """
       try:
           with create_qldb_driver(ledger_name) as driver:
               vin = SampleData.VEHICLE_REGISTRATION[0]['VIN']
               previous_primary_owners(driver, vin)
               logger.info('Successfully queried history.')
       except Exception as e:
           logger.exception('Unable to query history to find previous owners.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from datetime import datetime, timedelta
   from logging import basicConfig, getLogger, INFO
   
   from pyqldbsamples.model.sample_data import print_result, get_document_ids, SampleData
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   
   
   def format_date_time(date_time):
       """
       Format the given date time to a string.
   
       :type date_time: :py:class:`datetime.datetime`
       :param date_time: The date time to format.
   
       :rtype: str
       :return: The formatted date time.
       """
       return date_time.strftime('`%Y-%m-%dT%H:%M:%S.%fZ`')
   
   
   def previous_primary_owners(transaction_executor, vin):
       """
       Find previous primary owners for the given VIN in a single transaction.
       In this example, query the `VehicleRegistration` history table to find all previous primary owners for a VIN.
   
       :type transaction_executor: :py:class:`pyqldb.execution.executor.Executor`
       :param transaction_executor: An Executor object allowing for execution of statements within a transaction.
   
       :type vin: str
       :param vin: VIN to find previous primary owners for.
       """
       person_ids = get_document_ids(transaction_executor, Constants.VEHICLE_REGISTRATION_TABLE_NAME, 'VIN', vin)
   
       todays_date = datetime.utcnow() - timedelta(seconds=1)
       three_months_ago = todays_date - timedelta(days=90)
       query = 'SELECT data.Owners.PrimaryOwner, metadata.version FROM history({}, {}, {}) AS h WHERE h.metadata.id = ?'.\
           format(Constants.VEHICLE_REGISTRATION_TABLE_NAME, format_date_time(three_months_ago),
                  format_date_time(todays_date))
   
       for ids in person_ids:
           logger.info("Querying the 'VehicleRegistration' table's history using VIN: {}.".format(vin))
           cursor = transaction_executor.execute_statement(query, ids)
           if not (print_result(cursor)) > 0:
               logger.info('No modification history found within the given time frame for document ID: {}'.format(ids))
   
   
   if __name__ == '__main__':
       """
       Query a table's history for a particular set of documents.
       """
       try:
           with create_qldb_session() as session:
               vin = SampleData.VEHICLE_REGISTRATION[0]['VIN']
               session.execute_lambda(lambda lambda_executor: previous_primary_owners(lambda_executor, vin),
                                      lambda retry_attempt: logger.info('Retrying due to OCC conflict...'))
               logger.info('Successfully queried history.')
       except Exception:
           logger.exception('Unable to query history to find previous owners.')
   ```

------
**Anmerkung**  
Sie können den Revisionsverlauf eines Dokuments anzeigen, indem Sie die integrierte [Funktion „Verlauf“](working.history.md#working.history.function) in der folgenden Syntax abfragen.  

     ```
     SELECT * FROM history( table_name [, `start-time` [, `end-time` ] ] ) AS h
     [ WHERE h.metadata.id = 'id' ]
     ```
*Die *Startzeit und die Endzeit sind beide optional*.* Es handelt sich um Amazon Ion-Literalwerte, die mit Backticks () bezeichnet werden können. ``...`` Weitere Informationen hierzu finden Sie unter [Abfragen von Ion mit PartiQL in Amazon QLDB](ql-reference.query.md).
Es hat sich bewährt, eine Verlaufsabfrage sowohl mit einem Datumsbereich (*Start- und *Endzeit*) als auch mit einer Dokument-ID* () zu qualifizieren. `metadata.id` QLDB verarbeitet `SELECT` Abfragen in Transaktionen, die einem [Transaktions-Timeout-Limit](limits.md#limits.fixed) unterliegen.  
Der QLDB-Verlauf wird nach Dokument-ID indexiert, und Sie können derzeit keine zusätzlichen Verlaufsindizes erstellen. Bei Verlaufsabfragen, die eine Start- und Endzeit enthalten, wird der Vorteil einer Qualifizierung nach einem bestimmten Zeitraum genutzt.

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python query_history.py
   ```

Fahren Sie zum kryptografischen Überprüfen einer Dokumentrevision im `vehicle-registration`-Ledger mit [Schritt 7: Überprüfen Sie ein Dokument in einem Hauptbuch](getting-started.python.step-7.md) fort.

# Schritt 7: Überprüfen Sie ein Dokument in einem Hauptbuch
<a name="getting-started.python.step-7"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Mit Amazon QLDB können Sie die Integrität eines Dokuments im Journal Ihres Hauptbuchs effizient überprüfen, indem Sie kryptografisches Hashing mit SHA-256 verwenden. Weitere Informationen darüber, wie Verifizierung und kryptografisches Hashing in QLDB funktionieren, finden Sie unter. [Datenüberprüfung in Amazon QLDB](verification.md)

In diesem Schritt überprüfen Sie eine Dokumentrevision in der Tabelle `VehicleRegistration` in Ihrem `vehicle-registration`-Ledger. Zuerst fordern Sie einen Digest an, der als Ausgabedatei zurückgegeben wird und als Signatur des gesamten Änderungsverlaufs Ihres Ledgers fungiert. Anschließend fordern Sie einen Nachweis für die Revision in Bezug auf diesen Digest an. Mit diesem Nachweis wird die Integrität Ihrer Revision verifiziert, wenn alle Validierungsprüfungen bestanden werden.

**So überprüfen Sie eine Dokumentrevision**

1. Sehen Sie sich die folgenden `.py` Dateien an, die QLDB-Objekte darstellen, die für die Überprüfung erforderlich sind, und ein Hilfsmodul mit Hilfsfunktionen zur Konvertierung von QLDB-Antworttypen in Zeichenketten.

   1. `block_address.py`

      ```
      # 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.
      
      
      def block_address_to_dictionary(ion_dict):
          """
          Convert a block address from IonPyDict into a dictionary.
          Shape of the dictionary must be: {'IonText': "{strandId: <"strandId">, sequenceNo: <sequenceNo>}"}
      
          :type ion_dict: :py:class:`amazon.ion.simple_types.IonPyDict`/str
          :param ion_dict: The block address value to convert.
      
          :rtype: dict
          :return: The converted dict.
          """
          block_address = {'IonText': {}}
          if not isinstance(ion_dict, str):
              py_dict = '{{strandId: "{}", sequenceNo:{}}}'.format(ion_dict['strandId'], ion_dict['sequenceNo'])
              ion_dict = py_dict
          block_address['IonText'] = ion_dict
          return block_address
      ```

   1. `verifier.py`

      ```
      # 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.
      #
      # This code expects that you have AWS credentials setup per:
      # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
      from array import array
      from base64 import b64encode
      from functools import reduce
      from hashlib import sha256
      from random import randrange
      
      from amazon.ion.simpleion import loads
      
      HASH_LENGTH = 32
      UPPER_BOUND = 8
      
      
      def parse_proof(value_holder):
          """
          Parse the Proof object returned by QLDB into an iterator.
      
          The Proof object returned by QLDB is a dictionary like the following:
          {'IonText': '[{{<hash>}},{{<hash>}}]'}
      
          :type value_holder: dict
          :param value_holder: A structure containing an Ion string value.
      
          :rtype: :py:class:`amazon.ion.simple_types.IonPyList`
          :return: A list of hash values.
          """
          value_holder = value_holder.get('IonText')
          proof_list = loads(value_holder)
          return proof_list
      
      
      def parse_block(value_holder):
          """
          Parse the Block object returned by QLDB and retrieve block hash.
      
          :type value_holder: dict
          :param value_holder: A structure containing an Ion string value.
      
          :rtype: :py:class:`amazon.ion.simple_types.IonPyBytes`
          :return: The block hash.
          """
          value_holder = value_holder.get('IonText')
          block = loads(value_holder)
          block_hash = block.get('blockHash')
          return block_hash
      
      
      def flip_random_bit(original):
          """
          Flip a single random bit in the given hash value.
          This method is used to demonstrate QLDB's verification features.
      
          :type original: bytes
          :param original: The hash value to alter.
      
          :rtype: bytes
          :return: The altered hash with a single random bit changed.
          """
          assert len(original) != 0, 'Invalid bytes.'
      
          altered_position = randrange(len(original))
          bit_shift = randrange(UPPER_BOUND)
          altered_hash = bytearray(original).copy()
      
          altered_hash[altered_position] = altered_hash[altered_position] ^ (1 << bit_shift)
          return bytes(altered_hash)
      
      
      def compare_hash_values(hash1, hash2):
          """
          Compare two hash values by converting them into byte arrays, assuming they are little endian.
      
          :type hash1: bytes
          :param hash1: The hash value to compare.
      
          :type hash2: bytes
          :param hash2: The hash value to compare.
      
          :rtype: int
          :return: Zero if the hash values are equal, otherwise return the difference of the first pair of non-matching bytes.
          """
          assert len(hash1) == HASH_LENGTH
          assert len(hash2) == HASH_LENGTH
      
          hash_array1 = array('b', hash1)
          hash_array2 = array('b', hash2)
      
          for i in range(len(hash_array1) - 1, -1, -1):
              difference = hash_array1[i] - hash_array2[i]
              if difference != 0:
                  return difference
          return 0
      
      
      def join_hash_pairwise(hash1, hash2):
          """
          Take two hash values, sort them, concatenate them, and generate a new hash value from the concatenated values.
      
          :type hash1: bytes
          :param hash1: Hash value to concatenate.
      
          :type hash2: bytes
          :param hash2: Hash value to concatenate.
      
          :rtype: bytes
          :return: The new hash value generated from concatenated hash values.
          """
          if len(hash1) == 0:
              return hash2
          if len(hash2) == 0:
              return hash1
      
          concatenated = hash1 + hash2 if compare_hash_values(hash1, hash2) < 0 else hash2 + hash1
          new_hash_lib = sha256()
          new_hash_lib.update(concatenated)
          new_digest = new_hash_lib.digest()
          return new_digest
      
      
      def calculate_root_hash_from_internal_hashes(internal_hashes, leaf_hash):
          """
          Combine the internal hashes and the leaf hash until only one root hash remains.
      
          :type internal_hashes: map
          :param internal_hashes: An iterable over a list of hash values.
      
          :type leaf_hash: bytes
          :param leaf_hash: The revision hash to pair with the first hash in the Proof hashes list.
      
          :rtype: bytes
          :return: The root hash constructed by combining internal hashes.
          """
          root_hash = reduce(join_hash_pairwise, internal_hashes, leaf_hash)
          return root_hash
      
      
      def build_candidate_digest(proof, leaf_hash):
          """
          Build the candidate digest representing the entire ledger from the Proof hashes.
      
          :type proof: dict
          :param proof: The Proof object.
      
          :type leaf_hash: bytes
          :param leaf_hash: The revision hash to pair with the first hash in the Proof hashes list.
      
          :rtype: bytes
          :return: The calculated root hash.
          """
          parsed_proof = parse_proof(proof)
          root_hash = calculate_root_hash_from_internal_hashes(parsed_proof, leaf_hash)
          return root_hash
      
      
      def verify_document(document_hash, digest, proof):
          """
          Verify document revision against the provided digest.
      
          :type document_hash: bytes
          :param document_hash: The SHA-256 value representing the document revision to be verified.
      
          :type digest: bytes
          :param digest: The SHA-256 hash value representing the ledger digest.
      
          :type proof: dict
          :param proof: The Proof object retrieved from :func:`pyqldbsamples.get_revision.get_revision`.
      
          :rtype: bool
          :return: If the document revision verify against the ledger digest.
          """
          candidate_digest = build_candidate_digest(proof, document_hash)
          return digest == candidate_digest
      
      
      def to_base_64(input):
          """
          Encode input in base64.
      
          :type input: bytes
          :param input: Input to be encoded.
      
          :rtype: string
          :return: Return input that has been encoded in base64.
          """
          encoded_value = b64encode(input)
          return str(encoded_value, 'UTF-8')
      ```

   1. `qldb_string_utils.py`

      ```
      # 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 amazon.ion.simpleion import dumps, loads
      
      
      def value_holder_to_string(value_holder):
          """
          Returns the string representation of a given `value_holder`.
      
          :type value_holder: dict
          :param value_holder: The `value_holder` to convert to string.
      
          :rtype: str
          :return: The string representation of the supplied `value_holder`.
          """
          ret_val = dumps(loads(value_holder), binary=False, indent='  ', omit_version_marker=True)
          val = '{{ IonText: {}}}'.format(ret_val)
          return val
      
      
      def block_response_to_string(block_response):
          """
          Returns the string representation of a given `block_response`.
      
          :type block_response: dict
          :param block_response: The `block_response` to convert to string.
      
          :rtype: str
          :return: The string representation of the supplied `block_response`.
          """
          string = ''
          if block_response.get('Block', {}).get('IonText') is not None:
              string += 'Block: ' + value_holder_to_string(block_response['Block']['IonText']) + ', '
      
          if block_response.get('Proof', {}).get('IonText') is not None:
              string += 'Proof: ' + value_holder_to_string(block_response['Proof']['IonText'])
      
          return '{' + string + '}'
      
      
      def digest_response_to_string(digest_response):
          """
          Returns the string representation of a given `digest_response`.
      
          :type digest_response: dict
          :param digest_response: The `digest_response` to convert to string.
      
          :rtype: str
          :return: The string representation of the supplied `digest_response`.
          """
          string = ''
          if digest_response.get('Digest') is not None:
              string += 'Digest: ' + str(digest_response['Digest']) + ', '
      
          if digest_response.get('DigestTipAddress', {}).get('IonText') is not None:
              string += 'DigestTipAddress: ' + value_holder_to_string(digest_response['DigestTipAddress']['IonText'])
      
          return '{' + string + '}'
      ```

1. Verwenden Sie zwei `.py`-Programme (`get_digest.py` und `get_revision.py`), um die folgenden Schritte auszuführen:
   + Fordern Sie einen neuen Digest aus dem Ledger `vehicle-registration` an.
   + Fordern Sie einen Nachweis für jede Revision des Dokuments mit VIN `1N4AL11D75C109151` aus der `VehicleRegistration`-Tabelle an.
   + Überprüfen Sie die Revisionen mit dem zurückgegebenen Digest und dem Nachweis, indem Sie den Digest neu berechnen.

   Das Programm `get_digest.py` enthält den folgenden Code.

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from boto3 import client
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.qldb.qldb_string_utils import digest_response_to_string
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   qldb_client = client('qldb')
   
   
   def get_digest_result(name):
       """
       Get the digest of a ledger's journal.
   
       :type name: str
       :param name: Name of the ledger to operate on.
   
       :rtype: dict
       :return: The digest in a 256-bit hash value and a block address.
       """
       logger.info("Let's get the current digest of the ledger named {}".format(name))
       result = qldb_client.get_digest(Name=name)
       logger.info('Success. LedgerDigest: {}.'.format(digest_response_to_string(result)))
       return result
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       This is an example for retrieving the digest of a particular ledger.
       """
       try:
           get_digest_result(ledger_name)
       except Exception as e:
           logger.exception('Unable to get a ledger digest!')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```
**Anmerkung**  
Verwenden Sie die `get_digest_result`-Funktion, um einen Digest anzufordern, der die aktuelle *Spitze* des Journals in Ihrem Ledger abdeckt. Der Tipp des Journals bezieht sich auf den letzten festgeschriebenen Block zu dem Zeitpunkt, zu dem QLDB Ihre Anfrage erhält.

   Das Programm `get_revision.py` enthält den folgenden Code.

------
#### [ 3.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from amazon.ion.simpleion import loads
   from boto3 import client
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.get_digest import get_digest_result
   from pyqldbsamples.model.sample_data import SampleData, convert_object_to_ion
   from pyqldbsamples.qldb.block_address import block_address_to_dictionary
   from pyqldbsamples.verifier import verify_document, flip_random_bit, to_base_64
   from pyqldbsamples.connect_to_ledger import create_qldb_driver
   from pyqldbsamples.qldb.qldb_string_utils import value_holder_to_string
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   qldb_client = client('qldb')
   
   
   def get_revision(ledger_name, document_id, block_address, digest_tip_address):
       """
       Get the revision data object for a specified document ID and block address.
       Also returns a proof of the specified revision for verification.
   
       :type ledger_name: str
       :param ledger_name: Name of the ledger containing the document to query.
   
       :type document_id: str
       :param document_id: Unique ID for the document to be verified, contained in the committed view of the document.
   
       :type block_address: dict
       :param block_address: The location of the block to request.
   
       :type digest_tip_address: dict
       :param digest_tip_address: The latest block location covered by the digest.
   
       :rtype: dict
       :return: The response of the request.
       """
       result = qldb_client.get_revision(Name=ledger_name, BlockAddress=block_address, DocumentId=document_id,
                                         DigestTipAddress=digest_tip_address)
       return result
   
   
   def lookup_registration_for_vin(driver, vin):
       """
       Query revision history for a particular vehicle for verification.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type vin: str
       :param vin: VIN to query the revision history of a specific registration with.
   
       :rtype: :py:class:`pyqldb.cursor.buffered_cursor.BufferedCursor`
       :return: Cursor on the result set of the statement query.
       """
       logger.info("Querying the 'VehicleRegistration' table for VIN: {}...".format(vin))
       query = 'SELECT * FROM _ql_committed_VehicleRegistration WHERE data.VIN = ?'
       return driver.execute_lambda(lambda txn: txn.execute_statement(query, convert_object_to_ion(vin)))
   
   
   def verify_registration(driver, ledger_name, vin):
       """
       Verify each version of the registration for the given VIN.
   
       :type driver: :py:class:`pyqldb.driver.qldb_driver.QldbDriver`
       :param driver: An instance of the QldbDriver class.
   
       :type ledger_name: str
       :param ledger_name: The ledger to get digest from.
   
       :type vin: str
       :param vin: VIN to query the revision history of a specific registration with.
   
       :raises AssertionError: When verification failed.
       """
       logger.info("Let's verify the registration with VIN = {}, in ledger = {}.".format(vin, ledger_name))
       digest = get_digest_result(ledger_name)
       digest_bytes = digest.get('Digest')
       digest_tip_address = digest.get('DigestTipAddress')
   
       logger.info('Got a ledger digest: digest tip address = {}, digest = {}.'.format(
           value_holder_to_string(digest_tip_address.get('IonText')), to_base_64(digest_bytes)))
   
       logger.info('Querying the registration with VIN = {} to verify each version of the registration...'.format(vin))
       cursor = lookup_registration_for_vin(driver, vin)
       logger.info('Getting a proof for the document.')
   
       for row in cursor:
           block_address = row.get('blockAddress')
           document_id = row.get('metadata').get('id')
   
           result = get_revision(ledger_name, document_id, block_address_to_dictionary(block_address), digest_tip_address)
           revision = result.get('Revision').get('IonText')
           document_hash = loads(revision).get('hash')
   
           proof = result.get('Proof')
           logger.info('Got back a proof: {}.'.format(proof))
   
           verified = verify_document(document_hash, digest_bytes, proof)
           if not verified:
               raise AssertionError('Document revision is not verified.')
           else:
               logger.info('Success! The document is verified.')
   
           altered_document_hash = flip_random_bit(document_hash)
           logger.info("Flipping one bit in the document's hash and assert that the document is NOT verified. "
                       "The altered document hash is: {}.".format(to_base_64(altered_document_hash)))
           verified = verify_document(altered_document_hash, digest_bytes, proof)
           if verified:
               raise AssertionError('Expected altered document hash to not be verified against digest.')
           else:
               logger.info('Success! As expected flipping a bit in the document hash causes verification to fail.')
   
           logger.info('Finished verifying the registration with VIN = {} in ledger = {}.'.format(vin, ledger_name))
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Verify the integrity of a document revision in a QLDB ledger.
       """
       registration = SampleData.VEHICLE_REGISTRATION[0]
       vin = registration['VIN']
       try:
           with create_qldb_driver(ledger_name) as driver:
               verify_registration(driver, ledger_name, vin)
       except Exception as e:
           logger.exception('Unable to verify revision.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

------
#### [ 2.x ]

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from amazon.ion.simpleion import loads
   from boto3 import client
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.get_digest import get_digest_result
   from pyqldbsamples.model.sample_data import SampleData, convert_object_to_ion
   from pyqldbsamples.qldb.block_address import block_address_to_dictionary
   from pyqldbsamples.verifier import verify_document, flip_random_bit, to_base_64
   from pyqldbsamples.connect_to_ledger import create_qldb_session
   from pyqldbsamples.qldb.qldb_string_utils import value_holder_to_string
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   qldb_client = client('qldb')
   
   
   def get_revision(ledger_name, document_id, block_address, digest_tip_address):
       """
       Get the revision data object for a specified document ID and block address.
       Also returns a proof of the specified revision for verification.
   
       :type ledger_name: str
       :param ledger_name: Name of the ledger containing the document to query.
   
       :type document_id: str
       :param document_id: Unique ID for the document to be verified, contained in the committed view of the document.
   
       :type block_address: dict
       :param block_address: The location of the block to request.
   
       :type digest_tip_address: dict
       :param digest_tip_address: The latest block location covered by the digest.
   
       :rtype: dict
       :return: The response of the request.
       """
       result = qldb_client.get_revision(Name=ledger_name, BlockAddress=block_address, DocumentId=document_id,
                                         DigestTipAddress=digest_tip_address)
       return result
   
   
   def lookup_registration_for_vin(qldb_session, vin):
       """
       Query revision history for a particular vehicle for verification.
   
       :type qldb_session: :py:class:`pyqldb.session.qldb_session.QldbSession`
       :param qldb_session: An instance of the QldbSession class.
   
       :type vin: str
       :param vin: VIN to query the revision history of a specific registration with.
   
       :rtype: :py:class:`pyqldb.cursor.buffered_cursor.BufferedCursor`
       :return: Cursor on the result set of the statement query.
       """
       logger.info("Querying the 'VehicleRegistration' table for VIN: {}...".format(vin))
       query = 'SELECT * FROM _ql_committed_VehicleRegistration WHERE data.VIN = ?'
       parameters = [convert_object_to_ion(vin)]
       cursor = qldb_session.execute_statement(query, parameters)
       return cursor
   
   
   def verify_registration(qldb_session, ledger_name, vin):
       """
       Verify each version of the registration for the given VIN.
   
       :type qldb_session: :py:class:`pyqldb.session.qldb_session.QldbSession`
       :param qldb_session: An instance of the QldbSession class.
   
       :type ledger_name: str
       :param ledger_name: The ledger to get digest from.
   
       :type vin: str
       :param vin: VIN to query the revision history of a specific registration with.
   
       :raises AssertionError: When verification failed.
       """
       logger.info("Let's verify the registration with VIN = {}, in ledger = {}.".format(vin, ledger_name))
       digest = get_digest_result(ledger_name)
       digest_bytes = digest.get('Digest')
       digest_tip_address = digest.get('DigestTipAddress')
   
       logger.info('Got a ledger digest: digest tip address = {}, digest = {}.'.format(
           value_holder_to_string(digest_tip_address.get('IonText')), to_base_64(digest_bytes)))
   
       logger.info('Querying the registration with VIN = {} to verify each version of the registration...'.format(vin))
       cursor = lookup_registration_for_vin(qldb_session, vin)
       logger.info('Getting a proof for the document.')
   
       for row in cursor:
           block_address = row.get('blockAddress')
           document_id = row.get('metadata').get('id')
   
           result = get_revision(ledger_name, document_id, block_address_to_dictionary(block_address), digest_tip_address)
           revision = result.get('Revision').get('IonText')
           document_hash = loads(revision).get('hash')
   
           proof = result.get('Proof')
           logger.info('Got back a proof: {}.'.format(proof))
   
           verified = verify_document(document_hash, digest_bytes, proof)
           if not verified:
               raise AssertionError('Document revision is not verified.')
           else:
               logger.info('Success! The document is verified.')
   
           altered_document_hash = flip_random_bit(document_hash)
           logger.info("Flipping one bit in the document's hash and assert that the document is NOT verified. "
                       "The altered document hash is: {}.".format(to_base_64(altered_document_hash)))
           verified = verify_document(altered_document_hash, digest_bytes, proof)
           if verified:
               raise AssertionError('Expected altered document hash to not be verified against digest.')
           else:
               logger.info('Success! As expected flipping a bit in the document hash causes verification to fail.')
   
           logger.info('Finished verifying the registration with VIN = {} in ledger = {}.'.format(vin, ledger_name))
   
   
   if __name__ == '__main__':
       """
       Verify the integrity of a document revision in a QLDB ledger.
       """
       registration = SampleData.VEHICLE_REGISTRATION[0]
       vin = registration['VIN']
       try:
           with create_qldb_session() as session:
               verify_registration(session, Constants.LEDGER_NAME, vin)
       except Exception:
           logger.exception('Unable to verify revision.')
   ```

------
**Anmerkung**  
Nachdem die `get_revision`-Funktion einen Nachweis für die angegebene Dokumentrevision zurückgibt, verwendet dieses Programm eine clientseitige API, um diese Revision zu überprüfen.

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python get_revision.py
   ```

Wenn Sie den `vehicle-registration`-Ledger nicht mehr verwenden müssen, fahren Sie mit [Schritt 8 (optional): Ressourcen bereinigen](getting-started.python.step-8.md) fort.

# Schritt 8 (optional): Ressourcen bereinigen
<a name="getting-started.python.step-8"></a>

**Wichtig**  
Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter [Migrieren eines Amazon QLDB-Ledgers zu Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Sie können den `vehicle-registration`-Ledger weiterhin verwenden. Wenn Sie ihn nicht mehr benötigen, sollten Sie ihn jedoch löschen.

**So löschen Sie den Ledger**

1. Verwenden Sie das folgende Programm (`delete_ledger.py`), um Ihren `vehicle-registration`-Ledger und all seine Inhalte zu löschen.

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   from time import sleep
   
   from boto3 import client
   
   from pyqldbsamples.constants import Constants
   from pyqldbsamples.describe_ledger import describe_ledger
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   qldb_client = client('qldb')
   
   LEDGER_DELETION_POLL_PERIOD_SEC = 20
   
   
   def delete_ledger(ledger_name):
       """
       Send a request to QLDB to delete the specified ledger.
   
       :type ledger_name: str
       :param ledger_name: Name for the ledger to be deleted.
   
       :rtype: dict
       :return: Result from the request.
       """
       logger.info('Attempting to delete the ledger with name: {}...'.format(ledger_name))
       result = qldb_client.delete_ledger(Name=ledger_name)
       logger.info('Success.')
       return result
   
   
   def wait_for_deleted(ledger_name):
       """
       Wait for the ledger to be deleted.
   
       :type ledger_name: str
       :param ledger_name: The ledger to check on.
       """
       logger.info('Waiting for the ledger to be deleted...')
       while True:
           try:
               describe_ledger(ledger_name)
               logger.info('The ledger is still being deleted. Please wait...')
               sleep(LEDGER_DELETION_POLL_PERIOD_SEC)
           except qldb_client.exceptions.ResourceNotFoundException:
               logger.info('Success. The ledger is deleted.')
               break
   
   
   def set_deletion_protection(ledger_name, deletion_protection):
       """
       Update an existing ledger's deletion protection.
   
       :type ledger_name: str
       :param ledger_name: Name of the ledger to update.
   
       :type deletion_protection: bool
       :param deletion_protection: Enable or disable the deletion protection.
   
       :rtype: dict
       :return: Result from the request.
       """
       logger.info("Let's set deletion protection to {} for the ledger with name {}.".format(deletion_protection,
                                                                                             ledger_name))
       result = qldb_client.update_ledger(Name=ledger_name, DeletionProtection=deletion_protection)
       logger.info('Success. Ledger updated: {}'.format(result))
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Delete a ledger.
       """
       try:
           set_deletion_protection(ledger_name, False)
           delete_ledger(ledger_name)
           wait_for_deleted(ledger_name)
       except Exception as e:
           logger.exception('Unable to delete the ledger.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```
**Anmerkung**  
Wenn der Löschschutz für Ihr Ledger aktiviert ist, müssen Sie ihn zuerst deaktivieren, bevor Sie das Ledger mithilfe der QLDB-API löschen können.

   Die Datei `delete_ledger.py` weist auch eine Abhängigkeit vom folgenden Programm (`describe_ledger.py`) auf.

   ```
   # 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.
   #
   # This code expects that you have AWS credentials setup per:
   # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
   from logging import basicConfig, getLogger, INFO
   
   from boto3 import client
   
   from pyqldbsamples.constants import Constants
   
   logger = getLogger(__name__)
   basicConfig(level=INFO)
   qldb_client = client('qldb')
   
   
   def describe_ledger(ledger_name):
       """
       Describe a ledger.
   
       :type ledger_name: str
       :param ledger_name: Name of the ledger to describe.
       """
       logger.info('describe ledger with name: {}.'.format(ledger_name))
       result = qldb_client.describe_ledger(Name=ledger_name)
       result.pop('ResponseMetadata')
       logger.info('Success. Ledger description: {}.'.format(result))
       return result
   
   
   def main(ledger_name=Constants.LEDGER_NAME):
       """
       Describe a QLDB ledger.
       """
       try:
           describe_ledger(ledger_name)
       except Exception as e:
           logger.exception('Unable to describe a ledger.')
           raise e
   
   
   if __name__ == '__main__':
       main()
   ```

1. Geben Sie den folgenden Befehl ein, um das Programm auszuführen.

   ```
   python delete_ledger.py
   ```