Andy’s Neural Works

A wise folly can lead to great things!


The All Roads Project – Ingesting the Bible

Published by

on

Introduction

It’s Easter Time! This is the perfect time to get back to the All Roads Project. For those new to this project, it is a combination of analytics and Religious Research specifically related Catechism of the Catholic Church (CCC). The idea is to be able to develop a database that contains the texts and the references. 

These components can then be linked or networked together to show a lineage. Questions can be asked to determine the source of each teaching within the CCC. Like previously mentioned, these roads lead to God.

In this article, I will focus on the Bible texts. The steps will take us from data acquisition through to the data loading/ingestion process. The end result is the database will contain all text and references/citations from the Bible.

Data Acquisition 

The previous time I talked about data acquisition for the Bible1, I noted how I would use the source from the United States Conference of Catholic Bishops (USCCB). Unfortunately, I hit a roadblock when parsing out the references. Thankfully, the Vatican has a copy of the same New American Bible located on their website. This will actually be an easier effort since we used the Vatican’s website format for the CCC.

The acquisition of the text was done using the same “Low Code” method using Apple Shortcuts discussed in a previous article. It worked very well and produced a nice list of URLs that were scraped into text files.

Parsing the Bible Texts

As with the CCC, I used the awk language to parse out the headers, pages, and references. The code is in the appendix section below and it is very similar to what I did with the CCC. Here is the format for the output files (pipe delimited).

Headers File

  1. File Name
  2. Group Name
  3. Book Name
  4. Chapter Name
  5. Page Line #
  6. Header line #
  7. Header Text

Pages File

  1. File Name
  2. Group Name
  3. Book Name
  4. Chapter Name
  5. Page Line #
  6. Paragraph line #
  7. Paragraph Id
  8. Text
  9. References

References

  1. File Name
  2. Group Name
  3. Book Name
  4. Chapter Name
  5. Page line number
  6. Paragraph Id
  7. Reference line number
  8. Reference Id from text
  9. References

With the text in a format that can be read into a database, let’s stage everything into tables.

Staging

Because the Bible data is formatted differently than the CCC, I decided to create separate staging tables. These tables are: 

  1. Bible_Pages_Stage_T
  2. Bible_Header_Stage_T
  3. Bible_Paragraphs_Stage_T
  4. Bible_References_Stage_T

The following are the Source To Target Mappings (STTM) for each stage table:

STTM For Bible_Pages_Stage_T

Source FileSource Field PositionTransformationTarget DatabaseTarget TableTarget Field
extracted_urls.vatican.Bible.all.txt1NoneAllRoadsBible_Pages_Stage_TFile_Name
extracted_urls.vatican.Bible.all.txt2NoneAllRoadsBible_Pages_Stage_TTitle
extracted_urls.vatican.Bible.all.txt3NoneAllRoadsBible_Pages_Stage_TURL

STTM For Bible_Header_Stage_T

Source FileSource Field PositionTransformationTarget DatabaseTarget TableTarget Field
Bible.all.h.txt1NoneAllRoadsBible_Header_Stage_TFile_Name
Bible.all.h.txt2NoneAllRoadsBible_Header_Stage_TGroup_Name
Bible.all.h.txt3NoneAllRoadsBible_Header_Stage_TBook_Name
Bible.all.h.txt4NoneAllRoadsBible_Header_Stage_TChapter_Name
Bible.all.h.txt5NoneAllRoadsBible_Header_Stage_TPage_Line_Number
Bible.all.h.txt6NoneAllRoadsBible_Header_Stage_THeader_Line_Number
Bible.all.h.txt7NoneAllRoadsBible_Header_Stage_THeader_Text

STTM for Bible_Paragraphs_Stage_T

Source FileSource Field PositionTransformationTarget DatabaseTarget TableTarget Field
Bible.all.p.txt1NoneAllRoadsBible_Paragraphs_Stage_TFile_Name
Bible.all.p.txt2NoneAllRoadsBible_References_Stage_TGroup_Name
Bible.all.p.txt3NoneAllRoadsBible_References_Stage_TBook_Name
Bible.all.p.txt4NoneAllRoadsBible_References_Stage_TChapter_Name
Bible.all.p.txt5NoneAllRoadsBible_Paragraphs_Stage_TPage_Line_Number
Bible.all.p.txt6NoneAllRoadsBible_Paragraphs_Stage_TParagraph_Line_Number
Bible.all.p.txt7NoneAllRoadsBible_Paragraphs_Stage_TParagraph_Id
Bible.all.p.txt8NoneAllRoadsBible_Paragraphs_Stage_TParagraph_Text
Bible.all.p.txt9NoneAllRoadsBible_Paragraphs_Stage_TReferences

STTM for Bible_References_Stage_T

Source FileSource Field PositionTransformationTarget DatabaseTarget TableTarget Field
Bible.all.r.txt1NoneAllRoadsBible_References_Stage_TFile_Name
Bible.all.r.txt2NoneAllRoadsBible_References_Stage_TGroup_Name
Bible.all.r.txt3NoneAllRoadsBible_References_Stage_TBook_Name
Bible.all.r.txt4NoneAllRoadsBible_References_Stage_TChapter_Name
Bible.all.r.txt5NoneAllRoadsBible_References_Stage_TPage_Line_Number
Bible.all.r.txt6NoneAllRoadsBible_References_Stage_TParagraph_Id
Bible.all.r.txt7NoneAllRoadsBible_References_Stage_TReference_Line_Number
Bible.all.r.txt8NoneAllRoadsBible_References_Stage_TReference_Id
Bible.all.r.txt9NoneAllRoadsBible_References_Stage_TReference_Text

Remember to always check counts from local file to staging at this point. You can do that through your favorite tool of choice for the command line (or loading into an editor) then comparing that to counts using SQL.

Loading from Staging

With the data staged, we can write SQL to do the loads to the final table. Remember, the landing tables already include the CCC data. So, don’t truncate the tables if you hit an error. You will have to excise any erroneous records with DELETE statements if necessary. That said, you shouldn’t have to do that if you properly design and test your loads out of staging.

For design, remember the STTMs are essential! Always think and write out your process before building the load. Here are the STTMs for each table.

STTM for Texts_T

Source TableSource FieldData TypeTransformationTarget TableTarget FieldDate Type



System Generated IdTexts_TText_Idinteger
Bible_Header_Stage_TTitle
N/ATexts_TTitlecharacter varying (1000)
Bible_Header_Stage_TTitle
N/ATexts_TDescriptiontext
Bible_Pages_Stage_TURL
N/ATexts_TURLcharacter varying (2048)
Bible_Header_Stage_TGroup_Name
N/ATexts_TGroupcharacter varying (50)



Set to “Bible”Texts_TTypecharacter varying (50)



Set to CURRENT_DATETexts_TAudit_Create_Datetimestamp



Set to “Andy”Texts_TAudit_Create_Usercharacter varying (100)



N/ATexts_TAudit_Update_Datetimestamp



N/ATexts_TAudit_Update_Usercharacter varying (100)
*Note: JoinHeader and Pages stage tables by File_Name





Sort Group_Name according to the following rules: when ‘The Pentateuch’ then 1 when ‘The Historical Books’ then 2 when ‘The Wisdom Books’ then 3 when ‘The Prophetic Books’ then 4 when ‘The Gospels’ then 5 when ‘New Testament Letters’ then 6 when ‘The Catholic Letters’ then 7





STTM for Chapters_T

Source TableSource FieldData TypeTransformationTarget TableTarget FieldDate Type



System Generated IdChapters_TChapter_Idinteger
Bible_Pages_Stage_TURL

Chapters_TURLcharacter varying (2048)
Bible_Header_Stage_T and Bible_Pages_Stage_TBook_Name (from headers) and Title (from pages)
h.”Book_Name” || ‘ ‘ || pg.”Title”Chapters_TTitlecharacter varying (1000)
Bible_Header_Stage_TBook_Name and Chapter_Name
h.”Book_Name” || ‘ – ‘ || h.”Chapter_Name”Chapters_TDescriptiontext
Texts_TText_id

Chapters_TText_IdInteger



Set to CURRENT_DATEChapters_TAudit_Create_Datetimestamp



Set to “Andy”Chapters_TAudit_Create_Usercharacter varying (100)



N/AChapters_TAudit_Update_Datetimestamp



N/AChapters_TAudit_Update_Usercharacter varying (100)
Join 1: header to pages by File_Name





Join 2: header to Texts_T by Group and Title





STTM for Pages_T

Source TableSource FieldData TypeTransformationTarget TableTarget FieldDate Type



System Generated IdPages_TPage_Idinteger



Set to ROW_NUMBER() by sorting on the File_Name.Pages_TPage_Sequence_Idinteger
Bible_Header_Stage_T and Bible_Pages_Stage_TTItlecharacter varying (1000)COALESCE(h.”Book_Name” || ‘ ‘ || pg.”Title”, pg.”Title”)Pages_TTitlecharacter varying (1000)
Bible_Pages_Stage_T and Chapters_T
textCOALESCE(c.”Description”, pg.”Title”)Pages_TDescriptiontext
Bible_Pages_Stage_TURLcharacter varying (2048)N/APages_TURLcharacter varying (2048)
Bible_Pages_Stage_TFile_Namecharacter varying (1000)N/APages_TFile_Namecharacter varying (1000)
Texts_TText_IdintegerSet to default value (-1) if nullPages_TText_Idinteger
Chapters_TChapter_IdintegerSet to default value (-1) if nullPages_TChapter_Idinteger



Set to CURRENT_DATEPages_TAudit_Create_Datetimestamp



Set to “Andy”Pages_TAudit_Create_Usercharacter varying (100)



N/APages_TAudit_Update_Datetimestamp



N/APages_TAudit_Update_Usercharacter varying (100)
Join 1: LEFT OUTER between header and pages according to File_Name





Join 2: LEFT OUTER between chapters and pages according to URL





Join 3: LEFT OUTER between chapters and texts according to Text_Id





STTM for References_T

Source TableSource FieldData TypeTransformationTarget TableTarget FieldDate Type



System Generated IdReferences_TReference_Idinteger
Bible_References_Stage_TReference_Idtext
References_TReference_Sequence_Idcharacter varying (1000)
Bible_References_Stage_TReference_TexttextIf no text, set to “No Reference Text”References_TReference_Texttext



Set to NULLReferences_TURLcharacter varying (2048)
Pages_TPage_IdintegerN/AReferences_TPage_Idinteger
Pages_TText_IdintegerN/AReferences_TText_Idinteger



Set to CURRENT_DATEReferences_TAudit_Create_Datetimestamp



Set to “Andy”References_TAudit_Create_Usercharacter varying (100)



N/AReferences_TAudit_Update_Datetimestamp



N/AReferences_TAudit_Update_Usercharacter varying (100)
Join: references to pages by File_Name





*Note: Sort by Text_id, Page_Id and Reference_Id in an ascending order





STTM for Paragraphs_T

Source TableSource FieldData TypeTransformationTarget TableTarget FieldDate Type



System Generated IdParagraphs_TParagraph_Idinteger
Bible_Paragraphs_Stage_TParagraph_IdbigintWhen Paragraph_Id = ‘-1’ then set to NULLParagraphs_TParagraph_Sequence_Idcharacter varying (1000)
Bible_Paragraphs_Stage_TParagraph_Texttext
Paragraphs_TParagraph_Texttext
Pages_TURLcharacter varying (2048)
Paragraphs_TURLcharacter varying (2048)
Bible_Paragraphs_Stage_TReferencestextConvert comma delimited string to json using to_jsonParagraphs_TReference_Sequence_Idsjson
Pages_TText_Idinteger
Paragraphs_TText_Idinteger
Pages_TPage_idinteger
Paragraphs_TPage_Idinteger



Set to CURRENT_DATEParagraphs_TAudit_Create_Datetimestamp



Set to “Andy”Paragraphs_TAudit_Create_Usercharacter varying (100)



N/AParagraphs_TAudit_Update_Datetimestamp



N/AParagraphs_TAudit_Update_Usercharacter varying (100)
Join: paragraphs to pages according to File_Name





*NOTE: Sort by Paragraph_Line_Number in an ascending order





We have now loaded the Bible into the landing tables. Again, please remember that you must run data checks at this point. Ensure that the counts between the staging tables and the landing tables match. There should be a 1:1 in terms of counts between them for the Bible. If you have discrepancies, then go back and double check the loading SQL for accuracy.

Next Steps

With the CCC and Bible data now loaded, we have a very good start for analysis. It is a great success at this point but much more work is needed. There will also need to be further data sources for future work.

In the next article, I will go through some introductory analysis of creating relationships between paragraphs and references. This will be challenging as it is across more than 1 text as opposed to looking up the citations/references within same text.

Happy Easter! He is Risen!

References

[1] God. The New American Bible. Distributed by Vatican. Retrieved from: https://www.vatican.va/archive/ENG0839/_INDEX.HTM

Appendix

ALL CODE IS CONSIDERED IN AS-IS CONDITION. USE AT YOUR OWN CAUTION.

awk Script

# Author: Andy Della Vecchia
# Purpose: Parse out Bible text into header, paragraphs, and reference files
BEGIN {
# these are used to track where the read is in the file
section_number = 0
blank_line_count = 0
subsection_number = 0
page_line_number = 0
paragraph_id = -1
h_line_number = 0
p_line_number = 0
r_line_number = 0
# get the file name being processed
split(ARGV[1], file_pieces, ".")
split(file_pieces[length(file_pieces)-2], file_number, "/")
fn = "Bible." file_number[length(file_number)]
# build out the individual file names (h=header; p=paragraph; r=references)
out_path = "./out/"
header_file = out_path fn ".h.txt"
paragraph_file = out_path fn ".p.txt"
reference_file = out_path fn ".r.txt"
}
{
# track line number for debugging purposes
page_line_number++
# when the "Previous - Next" is found
if ($0 ~ /Previous - Next/ || $0 ~ /IntraText - Text/) {
# Track the section
section_number++
} else {
# section 1 is the header section
if (section_number == 1 && NF != 0) {
# 1 - File Name
# 2 - Group Name
# 3 - Book Name
# 4 - Chapter Name
# 5 - Page Line # (sequential for each page)
# 6 - Header line # (sequential for each header line #)
# 7 - Header Text
h_line_number++
gsub(/[^a-zA-Z0-9 ]/, "")
if (h_line_number == 1) {
group_name = $0
} else if (h_line_number == 2) {
book_name = $0
} else if (h_line_number == 3) {
chapter_name = $0
}
print fn "|" group_name "|" book_name "|" chapter_name "|" page_line_number "|" h_line_number "|" $0 > header_file
# section 2 is the main section with the paragraph and references
} else if (section_number == 2) {
# if not a blank line and numbers or text exist
if (NF != 0 && ($0~/[0-9]+/ || $0~/[A-Za-z+]/)) {
#print $0 > paragraph_file
# subsection 1 is the paragraphs
if (subsection_number == 0 && !($0 ~ /Click here to show the links to concordance/) && !($0==group_name) && !($0==book_name) && !($0==chapter_name)) {
# split the line
# 1 - File Name
# 2 - Group Name
# 3 - Book Name
# 4 - Chapter Name
# 5 - Page Line # (sequential for each page)
# 6 - Paragraph line # (sequential for each paragraph #)
# 7 - Paragraph Id (if doesn't exist, -1)
# 8 - Text (including reference #s)
# 9 - References - comma delimited
p_line_number++
ref_nums = ""
#if the entire line is a number only, save it as the paragraph line number
if ($0 ~ /[0-9]+/ && !($0 ~/[A-Za-z+]/)) {
paragraph_id = $0
} else {
# find any numeric values and pull out as reference Ids
for (i=1; i<=NF; i++) {
if ($i ~ /[0-9]+/) {
bkp_fld = $i
gsub(/[^0-9+]/, "", $i)
if (ref_nums != "") {
ref_nums = ref_nums "," $i
} else {
ref_nums = $i
}
# make sure original field is restored
#$i = bkp_fld
}
}
# add on the reference numbers and print out to file
print fn "|" group_name "|" book_name "|" chapter_name "|" page_line_number "|" p_line_number "|" paragraph_id "|" $0 "|" ref_nums > paragraph_file
}
# subsection 2 is where the references are stored
} else if (subsection_number >= 1) {
# 1 - File Name
# 2 - Group Name
# 3 - Book Name
# 4 - Chapter Name
# 5 - Page line number
# 6 - Paragraph Id
# 7 - reference line number
# 8 - Reference Id from text
# 9 - References
r_line_number++
$1 = $1 "|"
print fn "|" group_name "|" book_name "|" chapter_name "|" page_line_number "|" p_line_number "|" paragraph_id "|" $0 > reference_file
}
# remember that there are no blank lines
blank_line_count = 0
# blank line condition
} else {
#print "blank Line" > paragraph_file
blank_line_count++
if (blank_line_count >= 4) {
subsection_number++
#print "subsection hit" subsection_number > paragraph_file
blank_line_count = 0
}
}
}
}
}

DDL for Staging Tables

BEGIN;


CREATE TABLE IF NOT EXISTS "AllRoads"."Bible_Header_Stage_T"
(
    "File_Name" character varying(1000) NOT NULL,
    "Group_Name" text,
    "Book_Name" text,
    "Chapter_Name" text,
    "Page_Line_Number" bigint NOT NULL,
    "Header_Line_Number" bigint NOT NULL,
    "Header_Text" text NOT NULL
);

CREATE TABLE IF NOT EXISTS "AllRoads"."Bible_Paragraphs_Stage_T"
(
    "File_Name" character varying(1000) NOT NULL,
    "Group_Name" text,
    "Book_Name" text,
    "Chapter_Name" text,
    "Page_Line_Number" bigint NOT NULL,
    "Paragraph_Line_Number" bigint NOT NULL,
    "Paragraph_Id" bigint NOT NULL,
    "Paragraph_Text" text NOT NULL,
    "References" text
);

CREATE TABLE IF NOT EXISTS "AllRoads"."Bible_References_Stage_T"
(
    "Book_Name" text,
    "Group_Name" text,
    "File_Name" character varying(1000) NOT NULL,
    "Chapter_Name" text,
    "Page_Line_Number" bigint NOT NULL,
    "Reference_Line_Number" bigint NOT NULL,
    "Reference_Id" text NOT NULL,
    "Reference_Text" text NOT NULL
);

CREATE TABLE IF NOT EXISTS "AllRoads"."Bible_Pages_Stage_T"
(
    "File_Name" character varying(1000) NOT NULL,
    "Title" character varying(1000) NOT NULL,
    "URL" character varying(2048) NOT NULL
);
END;

SQL for Load

Texts_T

INSERT INTO "AllRoads"."Texts_T"
("Title"
 ,"Description"
 ,"URL"
 ,"Group"
 ,"Type"
 ,"Audit_Create_Date"
 ,"Audit_Create_User"
)
SELECT h."Book_Name" as "Title"
	   ,h."Book_Name" as "Description" --duplicate book name rather than put a null in it
	   ,pg."URL" as "URL"
	   ,h."Group_Name" as "Group"
	   ,'Bible' as "Type"
	   ,CURRENT_DATE as "Audit_Create_Date"
	   ,'Andy' as "Audit_Create_User"
FROM (
		SELECT *
		  FROM (
			SELECT distinct row_number() over (partition by "Group_Name", "Book_Name" order by cast(substr("File_Name",7,100) as numeric)) as rn,
					"File_Name", 
					"Group_Name", 
					"Book_Name"  
			FROM "AllRoads"."Bible_Header_Stage_T" h1
			WHERE "Book_Name" is not null
		) hdr
		where hdr.rn = 1
	 ) as h
     inner join
	 "AllRoads"."Bible_Pages_Stage_T" as pg on (h."File_Name" = 'Bible.' || pg."File_Name")-- and trim(h."Group_Name") = trim(p."Title"))
ORDER BY case h."Group_Name"
		     when 'The Pentateuch' then 1
			 when 'The Historical Books' then 2
			 when 'The Wisdom Books' then 3
			 when 'The Prophetic Books' then 4
			 when 'The Gospels' then 5
			 when 'New Testament Letters' then 6
			 when 'The Catholic Letters' then 7
		 end
		 ,cast(pg."File_Name" as numeric)
		 , pg."Title"
;

Paragraphs_T

INSERT INTO "AllRoads"."Paragraphs_T"
(
	"Paragraph_Sequence_Id"
	,"Paragraph_Text"
	,"URL"
	,"Reference_Sequence_Ids"
	,"Text_Id"
	,"Page_Id"
	,"Audit_Create_Date"
	,"Audit_Create_User"
)
SELECT case 
			when p."Paragraph_Id" = '-1' then null
			else p."Paragraph_Id"
		end as Paragraph_Sequence_Id
	   ,p."Paragraph_Text"
	   ,pg."URL"
	   ,to_json(string_to_array(p."References",',')) as Reference_Sequence_Ids
	   ,pg."Text_Id"
	   ,pg."Page_Id"
	   ,CURRENT_DATE AS Audit_Create_Date
	   ,'Andy' as Audit_Create_User
  FROM "AllRoads"."Bible_Paragraphs_Stage_T" as p
       INNER JOIN
	   "AllRoads"."Pages_T" as pg on (p."File_Name" = pg."File_Name")
ORDER BY pg."Page_Id", p."Paragraph_Line_Number"
;

Pages_T

INSERT INTO "AllRoads"."Pages_T"
(
	"Page_Sequence_Id"
	,"Title"
	,"Description"
	,"URL"
	,"File_Name"
	,"Text_Id"
	,"Chapter_Id"
	,"Audit_Create_Date"
	,"Audit_Create_User"
)
SELECT ROW_NUMBER() OVER(PARTITION BY pg1."Text_Id" ORDER BY CAST(pg1."File_Name" as INTEGER)) AS Page_Sequence_Id
	   ,pg1."Title"
	   ,pg1."Description"
	   ,pg1."URL"
	   ,pg1."Bible_File_Name"
	   ,pg1."Text_Id"
	   ,pg1."Chapter_Id"
	   ,pg1."Audit_Create_Date"
	   ,pg1."Audit_Create_User"
  FROM (

	SELECT COALESCE(h."Book_Name" || ' ' || pg."Title", pg."Title") as "Title"
		   ,COALESCE(c."Description", pg."Title") as "Description"
		   ,pg."URL"
	  	   ,pg."File_Name"
		   ,('Bible.' || pg."File_Name") as "Bible_File_Name"
		   ,COALESCE(t."Text_Id", 78) as "Text_Id" --78 is the default record in the Texts_T table for general Bible data.
		   ,COALESCE(c."Chapter_Id", 2770) as "Chapter_Id" --2770 is the default record in the Chapters_T for general Bible data.
		   ,CURRENT_DATE as "Audit_Create_Date"
		   ,'Andy' as "Audit_Create_User"
	  FROM "AllRoads"."Bible_Pages_Stage_T" as pg 
		   LEFT OUTER JOIN
		   (SELECT "File_Name", "Group_Name", "Book_Name", "Chapter_Name" from "AllRoads"."Bible_Header_Stage_T" WHERE "Chapter_Name" IS NOT NULL) as h on (h."File_Name" = 'Bible.' || pg."File_Name")	   
		   LEFT OUTER JOIN -- take into consideration that the preface doesn't have a chapter Id
		   "AllRoads"."Chapters_T" as c on (c."URL" = pg."URL") 
		   LEFT OUTER JOIN
		   "AllRoads"."Texts_T" as t on (t."Text_Id" = c."Text_Id")
) pg1
;

References_T

INSERT INTO "AllRoads"."References_T"
(
	"Reference_Sequence_Id"
	,"Reference_Text"
	,"Page_Id"
	,"Text_Id"
	,"Audit_Create_Date"
	,"Audit_Create_User"
)
SELECT (case when r."Reference_Id"~ '^[0-9]+$' = TRUE THEN r."Reference_Id" ELSE '-1' END) as Reference_Sequence_Id
       ,(case when r."Reference_Id"~ '^[0-9]+$' = FALSE THEN r."Reference_Id" ELSE '' END) || COALESCE(r."Reference_Text", 'No Reference Text') as Reference_Text
	   ,pg."Page_Id"
	   ,pg."Text_Id"
	   ,CURRENT_DATE AS Audit_Create_Date
	   ,'Andy' as Audit_Create_User
  FROM "AllRoads"."Bible_References_Stage_T" as r
       INNER JOIN
	   "AllRoads"."Pages_T" as pg on (r."File_Name" = pg."File_Name")
ORDER BY cast(pg."Text_Id" as numeric)
		 ,cast(pg."Page_Id" as numeric)
         ,cast((case when r."Reference_Id"~ '^[0-9]+$' = TRUE THEN r."Reference_Id" ELSE NULL END) as numeric)

Chapters_T

INSERT INTO "AllRoads"."Chapters_T"
("URL"
,"Title"
,"Description"
,"Text_Id"
 ,"Audit_Create_Date"
 ,"Audit_Create_User"
)
SELECT pg."URL"
       ,h."Book_Name" || ' ' || pg."Title" as "Title"
	   ,h."Book_Name" || ' - ' || h."Chapter_Name" as "Description"
	   ,tt."Text_Id"
	   ,CURRENT_DATE as "Audit_Create_Date"
	   ,'Andy' as "Audit_Update_User"
  FROM "AllRoads"."Bible_Pages_Stage_T" as pg
       INNER JOIN
	   (SELECT "File_Name", "Group_Name", "Book_Name", "Chapter_Name" from "AllRoads"."Bible_Header_Stage_T" WHERE "Chapter_Name" IS NOT NULL) as h on (h."File_Name" = 'Bible.' || pg."File_Name")	   
	   INNER JOIN
	   "AllRoads"."Texts_T" as tt on (h."Group_Name" = tt."Group" and h."Book_Name" = tt."Title")
;