- Preparation: Create database
- Create the Channel
- Tutorial Instructions
- Complete Sample Code
- More Information
This post was originally written for Iguana 5 so it contains version 5 screenshots, and may contain out of date references.
In this article we will use conn:query{}
and conn:execute{}
to retrieve patient data from a source database and insert it into a target database.
These are the steps:
- Read the unprocessed patient messages from the source database.
- Update the flag table to indicate the messages have been processed.
- Insert the data into the target database.
We recommend that you type in the code for each step, but we also include complete Sample Code if you prefer to paste it in and follow along.
Note: The code in this tutorial executes an INSERT statement for every message that is processed. It does not check if a record already exists, therefore if you attempt to insert duplicate records (with the same patient Id) the code will produce errors.
To handle duplicate messages you need to use conn:merge() or add logic to check for duplicates, see the Save to Database: DB to DB tutorial in the Interface Tutorials (Iguana 5 documentation) section.
Preparation: Create the “test” database [top]
If you do not already have a SQLite database called “test” in the Iguana install directory, then you can create it by following the instructions in the Create a SQLite DB to match your VMD tutorial.
Create the Channel [top]
- Create a Channel with the the following settings:
- Source = From Translator
- Destination = To Channel
- Channel name = Insert DB data into Database
- Click the Add Channel button to create the channel.
Ignore the red warning messages, see resolving the commit configuration error. - Open the Translator by clicking the Edit Script link at the bottom of the Source tab.
- Download and import the Insert_DB_data_into_Database_From_Translator.zip project file.
- Iguana will load the project and data into the Translator, your screen should look like this:
Tutorial Instructions [top]
- Pass the message data to the script.
- Iguana automatically passes the message data to the
main()
function - The message can be accessed using the
Data
parameter - No action is needed
- Iguana automatically passes the message data to the
- Create tables and data in the source database.
- Paste the following code into your script:
------------ START ADD TABLES AND DATA ------------ local ConnSource = db.connect{ api=db.SQLITE, name='test_source', user='', password='', live=true } local Sql = [[DROP TABLE IF EXISTS Patient]] ConnSource:execute{sql=Sql,live=true} Sql = [[CREATE TABLE IF NOT EXISTS Patient ( PatientId TEXT(255) NOT NULL PRIMARY KEY, Surname TEXT(255) NULL, FirstName TEXT(255) NULL, Ssn TEXT(255) NULL);]] ConnSource:execute{sql=Sql,live=true} Sql = [[DROP TABLE IF EXISTS ProcessPatient]] ConnSource:execute{sql=Sql,live=true} Sql = [[CREATE TABLE IF NOT EXISTS ProcessPatient ( PatientId TEXT(255) NOT NULL PRIMARY KEY, Processed TEXT(255) NULL );]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO Patient VALUES('4525285','Smith','Tracy','284-517-569')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO Patient VALUES('5488754','Smith','Fred','558-171-617')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO Patient VALUES('9639271','White','Tracy','571-349-734')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO Patient VALUES('2668844','Fitzgerald','Gary','957-321-126')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO Patient VALUES('9229102','Fitzgerald','Tracy','223-15-522')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO Patient VALUES('4101077','Adams','Jim','128-474-184')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO ProcessPatient VALUES('4525285','N')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO ProcessPatient VALUES('5488754','N')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO ProcessPatient VALUES('9639271','N')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO ProcessPatient VALUES('2668844','N')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO ProcessPatient VALUES('9229102','N')]] ConnSource:execute{sql=Sql,live=true} Sql = [[INSERT INTO ProcessPatient VALUES('4101077','N')]] ConnSource:execute{sql=Sql,live=true} -- check data ConnSource:query('SELECT * FROM Patient') ConnSource:query('SELECT * FROM ProcessPatient') ------------ END ADD TABLES AND DATA ------------
- Click on the two SELECT query results to confirm that six rows were added to each table:
- Delete the code that you inserted above.
- Paste the following code into your script:
- Create a database connection object for the source database, using the
db.connect{}
function
Add the following code to your script:
- Create a database connection object for the target database.
Add the following code to your script:
- Read the messages to be processed from the source database.
Add the following code:
- Click on the result set to view the retrieved messages:
- Use the data from the first sample message to hard-code a SQL INSERT statement.
Add the following code to your script:
Note: The double square brackets [[ ]] on lines 36 and 51 are the Lua terminators for a multi-line string. - Test that the query works by running it using
Conn:execute{}
and then viewing the inserted data.
Add the following code, then click on the result of the SELECT query to view the patient data:
As you can see the patient record has been inserted correctly. - Comment out the DELETE statement to see what happens when we try to insert a duplicate record:
The expanded message tells that a cryptic reference that a “constraint failed”, which basically means that we are not allowed to insert the same patient record twice.
Note: Technically the constraint is the primary key on the Id (which prevents duplicate patient records with the same Id), and the failure is because we tried to insert a patient record with a duplicate Id.
- Uncomment the DELETE statement.
- View the hard-coded SQL statement string in the
SqlInsert
variable.
Add atrace()
and click the string annotation to view it:
- Now we will reproduce the same INSERT query but replacing the hard-coded VALUES with concatenated data from the retrieved source DB messages.
- Make a second copy the
SqlInsert
immediately below the original. - Modify it as shown so the Id value is copied from the first record in the
r
variable (retrieved source DB messages). - Add a
trace()
and click the string annotation to view it:
Note: At this pointConn:execute{}
returns an error because the query is incomplete, this will disappear after we add the other VALUES. - Reproducing the other VALUES is just more of the same.
Add these three lines of code to code the query:
Note: The newline (\n) and 3 extra spaces at the start of lines 68 to 71 are only for formatting, so it is easy to compare the strings visually (the query will work equally well if they are removed). - View the query string to confirm that it matches the original query.
Add atrace()
and click the string annotation to view it:
- Add a for loop using an index “i” to process all the retrieved records.
Modify the code to look like this:
Note: We changed from brackets [[]] to quotes ” as string delimiters simply to keep the query string format the same as before. - View the query string for the first iteration of the for loop to confirm that it matches the original query.
Click the string annotation to view it:
- Navigate through the loop iterations to see the different queries for each record:
Note: The seventh repetition does no processing it just exits the loop. - Delete the trace() statement from the for loop:
- Delete the initial hard-coded
SqlInsert
string, and thetrace()
below it:
- Make a second copy the
- Add this test code before the for loop:
- Add this test code at the end of
main()
:
- Delete the old test code:
- Add the database insert statement, it needs to be moved inside the for loop so it processes all the messages.
Modify the code to look like this:
- Update the queue (ProcessPatient) in the source database after processing each record, to prevent trying to insert duplicate patients.
Add this code to the end of the for loop:
- Test that the code is adding the six messages to the target database.
Click the result set for the patient SELECT query:
As you can see the six records have been correctly inserted. - Check what happens when you try to insert duplicate patient records (with the same patient Id).
- Comment out the DELETE statement before the for loop:
The expanded message tells that a cryptic reference that a “constraint failed”, which basically means that we are not allowed to insert the same patient record twice.
Note: Technically the constraint is the primary key on the Id (which prevents duplicate patient records with the same Id), and the failure is because we tried to insert a patient record with a duplicate Id.
- Uncomment the DELETE statement.
- Comment out the DELETE statement before the for loop:
- Check that the queue (ProcessPatient) in the source database is correctly updated.
Click the result set for the ProcessPatient SELECT query:
Note: The UPDATE query on the next line resets the Processed field to reprocess the messages for testing. - Remove the test code.
- Comment out the UPDATE for the Processed field:
- Comment out the DELETE for the patient table before the for loop:
Note: If you reverse the order the code will try to insert duplicate records, and give this error:
If this occurs simply uncomment both lines and comment out the UPDATE first then the DELETE. - Delete all the test code:
- Comment out the UPDATE for the Processed field:
Note: If you attempt to insert duplicate patient records (with the same patient Id) this code will produce errors.
To handle duplicate messages you need to use conn:merge() or add logic to check for duplicates, see the Save to Database: DB to DB tutorial in the Interface Tutorials (Iguana 5 documentation) section.
Complete Sample Code [top]
Here is the completed code that you can cut and paste into your script:
function main(Data) -- (1) connect to the source database if not ConnSource or not ConnSource:check() then ConnSource = db.connect{ api=db.SQLITE, name='test_source', user='', password='', live=true } end -- (2) connect to the target database if not ConnTarget or not ConnTarget:check() then ConnTarget = db.connect{ api=db.SQLITE, name='test', user='', password='', live=true } end -- (3) create insert query string -- Read messages to process local Sql = [[ SELECT P.* FROM Patient P JOIN ProcessPatient PP WHERE P.PatientId = PP.PatientId AND PP.Processed = 'N' ]] local r = ConnSource:query(Sql) for i=1,#r do local SqlInsert = " INSERT INTO patient".. "\n (".. "\n Id,".. "\n LastName,".. "\n GivenName,".. "\n Ssn".. "\n )".. "\n VALUES".. "\n (".. "\n '"..r[i].PatientId.."',".. "\n '"..r[i].Surname.."',".. "\n '"..r[i].FirstName.."',".. "\n '"..r[i].Ssn.."'".. '\n )' -- (4) Insert data into database ConnTarget:execute{sql = SqlInsert, live = true} -- Update source DB queue to prevent re-processing Sql = [[ UPDATE ProcessPatient SET Processed = 'Y' WHERE PatientId = ']] ..r[i].PatientId.."'" ConnSource:execute{sql = Sql, live = true} end end
More Information [top]
- See our other interface tutorials (Iguana 5 documentation) in this section
- See our general tutorials (Iguana 5 documentation) section
- See our code samples (Iguana 5 documentation) section