Children – Set Lineage to Birth #birth #ancestors #lineage

RootsMagic 7 and prior has the peculiar shortcoming that ancestral lineage reports, charts and other important functions follow the lineage set by the parent family displayed in the last view of each person in one of the Main screens. If the last time you viewed your mother showed her stepfather as her father, then her birth father’s line is completely omitted while the stepfather’s line is included. This affects several reports and charts:

  • Ancestor narratives
  • Ahnentafel
  • Ancestor Box Chart
  • Pedigree Chart
  • Photo Tree
  • Ancestor Wall Chart

Moreover, it also affects the filter for selecting ancestors of the highlighted person in RootsMagic Explorer’s Mark/Unmark Group functions used for

  • other reports
  • GEDCOM export
  • colour coding
  • Named Groups

RootsMagic provides no option for any of these to be directed to follow the birth line despite having the feature in the Edit Person window to set the type of relationship between a child and a parent couple to other kinds such as adoptive or step. There seems to be little point to the Relationship setting because it is visible only in the Edit Person screen and is otherwise totally ignored. There has been a long outstanding Wish List item for the system to put the relationship setting to effective use.

Meanwhile, here is a potentially useful script if you have the typical family tree with several people having more than one parent couple and want to restore the focus to the birth line without having to manually search for those with other relationships to ensure that their Main View is set to the birth parents. It has been tested on a small trial database so, as always, be sure you have a backup before using it on your database or try it on a copy of your database. If you have the same database open in both RootsMagic and the SQLite manager from which you ran the script, you will not see any effect in RootsMagic until you refresh the Main Screen by switching to a different View.

Children-SetLineage2Birth.sql

-- Children-SetLineage2Birth.sql
/*
2015-10-18 Tom Holden ve3meo
 
Sets the displayed lineage to that of the Birth parents so that
lineage views and reports follow the birth line.
In the case of multiple birth parents (permitted by RootsMagic),
sets the birth family to the one with the highest Proof setting,
else to the lowest FamilyID.
 
It does not (or cannot?) cover all possible combinations that
a user might wish to allow or consider to be the preferred lineage
because a parent family (couple) may have only one member (mother
or father) and each spouse of a couple may have any of the four
proof settings for the birth relationship (0-undefined, 1-proven,
2-disproven, 3-disputed).
 
*/
 
DROP VIEW IF EXISTS BirthCouple
;
-- this view of the parents includes only birth parents in descending order of proof
CREATE TEMP VIEW BirthCouple AS
SELECT  ChildID, FamilyID FROM ChildTable
WHERE RelFather = 0 AND RelMother = 0  -- birth relationships
AND ProofFather < 2 AND ProofMother < 2  -- relationship proof is proven or undefined
ORDER BY ChildID, ProofFather DESC, ProofMother DESC -- priority to 'proven' relationships
;
 
-- set the display lineage to the birth parents with highest level of proof and
-- do not touch persons with no parents
UPDATE PersonTable
  SET ParentID =
    (SELECT FamilyID FROM BirthCouple BC
       WHERE PersonID = BC.ChildID)
  WHERE PersonID IN (SELECT ChildID FROM BirthCouple)
;
 
-- the temporary SQLite View BirthCouple will be deleted when the SQLite
-- manager closes the database

Ancestry.com and RootsMagic 5 #ancestrycom #sources #update #gedcom

Problems with GEDCOM

In my experience, building an evidence-driven Family Tree on Ancestry.com
from evidence found in its databases is faster and easier than extracting
the evidence from Ancestry.com and building the documented tree in
RootsMagic. But my RootsMagic database remains superior in other respects
and is my master database for reporting. So I have a number of problems
marrying my Ancestry and RootsMagic family trees and synchronizing them:

  • excessive exception report from the GEDCOM import
  • no images downloaded and linked
  • verbose footnotes

Avoid Glut of
Unknown Info _APID on Import

When you import into a RootsMagic database a GEDCOM downloaded from an
Ancestry Family Tree, RootsMagic generates an exception report file with the
.LST extension and with the same name and the same location as the database.
It is filled with a glut of exceptions of the form:

Unknown info (line 28)
    3 _APID 1,8944::212

These obscure the more interesting exceptions. Since RootsMagic does not
import these _APID lines, deleting them from the GEDCOM prior to import is
harmless while clarifying the LST resport. I use this regular expression
global search and replace in PSPad to clean them out:

Find: ^.+_APID.+$
Replace:

For the tree that is the subject of this page, it deleted 4461 occurrences
of the _APID tag from the GEDCOM.

Getting
Source and Other Images from Ancestry.com

The GEDCOM that you download from an Ancestry Family Tree does not contain
any images but it does include a URL to the Source page for each citation
that RootsMagic imports into its Citation Comments field. Conversely, Family
Tree Maker 2012 can synchronise with the Ancestry Family Tree and downloads
all the images; however, it is a bloated, slow program and does not include
the Ancestry source page URL in its export to GEDCOM 5.5 despite providing
the path to the local image file. Importing both GEDCOMs into a common
database and merging duplicate persons sounds plausible and easy but proved
useless. To re-marry the URLs
and the media items in a RootsMagic database, I developed the following
merging procedure which appears to be about 95% successful.

  1. Import the GEDCOM from the Ancestry Family Tree (optionally cleaned of
    _APID tags) to a new RootsMagic database named “AncestryGED.rmgc” (or
    whatever suits you).
  2. Optionally, inspect the corresponding LST file and make any changes in
    the RM database that you feel are important. However, these may be lost
    as this database is secondary in the merging process that follows.
  3. Using Family Tree Maker 2012, create a FTM database by synchronising
    to the Ancestry Family Tree.
  4. Export from FTM a GEDCOM 5.5, choosing FTM 2012 as the output format.
  5. Import the FTM GEDCOM into a new RootsMagic database named to suit
    you.
  6. Optionally, inspect the corresponding LST file for exceptions and make
    possible corrections in the RM database. This will be the primary
    database in the merge so these corrections should be preserved.
  7. Open SQLiteSpy with the fake RMNOCASE extension and open the primary
    database, the one created from importing the FTM2012 GEDCOM.
  8. In SQLiteSpy open the following SQL file which you will have
    downloaded to your scripts folder. MergeAncestryURLsToFTM.sql
  9. Edit the ATTACH command line so that the path and filename corresponds
    to that of your secondary database, the one created by importing the
    GEDCOM downloaded from Ancestry.com.
  10. Execute the script. It is slow because of the many matches and string
    processing to be done and the final status report is misleading as it
    only reports the number of records converted from Name citations unused
    by RM to Personal ones.
  11. Inspect your primary database to see that your citations now include
    the URL to the Ancestry source page in the Detail Comments and that the
    media item, if it existed before, is still there.
  12. You may now proceed to Shrinking
    Verbose Master Sources from Ancestry.com

The media are all stored in one folder under the Documents > Family Tree
Maker folder (assuming a default installation). Should you relocate them,
you will need to use RM’s global Search and Replace on multimedia filenames
or its Repair Broken Media Links tool to restore connections. I’m unsure of
the implications for the longterm if you wish to continue terr-building and
synchronising on Ancestry. Will existing names be preserved? Note that a
typical name is 1891 England Census-14.jpg or
1900 United States Federal Census-2.jpg, i.e., the source name with
a serial suffix when there is more than one image from the master source.
I’m inclined to leave them where they are, names unchanged, in the hope that
FTM will download only new images and continue the serial numbers.

Shrinking
Verbose Master Sources from Ancestry.com

One problem is that citations from Ancestry are extremely verbose. So I
tackled this one first. Having examined both the GEDCOM from Ancestry and
the imported results in RootsMagic, I elected to make the revisions
post-import as that had a more obvious solution for the tools and knowledge
I have.
My strategy is to replace the RootsMagic Footnote field value with the
ShortFootnote field value and the latter with the Master Source name. The
Bibliography value remains untouched and provides the same detail as the
original Footnote. Below is a comparison of a revised Master Source with its
original. Note that both exhibit a truncation that is the fault of
Ancestry.com.

Master
Source imported from Ancestry.com

Footnote:
Ancestry.com,
1870 United States Federal Census (Online publication – Provo, UT, USA:
Ancestry.com Operations, Inc., 2009. Images reproduced by
FamilySearch..Original data – 1870 U.S. census, population schedules. NARA
microfilm publication M593, 1,761 rolls. Washington, D.C.: National
Archives and Recor)

Short
Footnote:
Ancestry.com,
1870 United States Federal Census

Bibliography:
Ancestry.com.
1870 United States Federal Census. Online publication – Provo, UT, USA:
Ancestry.com Operations, Inc., 2009. Images reproduced by
FamilySearch..Original data – 1870 U.S. census, population schedules. NARA
microfilm publication M593, 1,761 rolls. Washington, D.C.: National
Archives and Recor.

Repository:

Ancestry.ca

http://www.Ancestry.ca

Master
Source after SQLite procedure

Footnote:
Ancestry.com,
1870 United States Federal Census

Short
Footnote:
1870
United States Federal Census

Bibliography:
Ancestry.com.
1870 United States Federal Census. Online publication – Provo, UT, USA:
Ancestry.com Operations, Inc., 2009. Images reproduced by
FamilySearch..Original data – 1870 U.S. census, population schedules. NARA
microfilm publication M593, 1,761 rolls. Washington, D.C.: National
Archives and Recor.

Repository:

Ancestry.ca

http://www.Ancestry.ca

Procedure

This involves multiple steps and tools:

  • SQLiteSpy
  • PSPad or other text editor with sorting capability
  • MS Excel or, possibly, other spreadsheet program, using AncestrySourceConverter.xlsx

The steps comprise:

  1. 1. Download the Ancestry GEDCOM or export it from the synchronised
    Family Tree Maker database in GEDCOM for FTM16 format.
  2. 2. Import the GEDCOM to a new RM database.
  3. 3. Backup your database.
  4. 4. Make a copy of your database with a different name.
  5. 5. Open the new database with SQLiteSpy.
  6. 6. Run the following
    query: SELECT SourceID, Name,
    SUBSTR(CAST(Fields AS TEXT),41) AS Fields FROM SourceTable;
  7. 7. Select all results and copy to the clipboard (select a cell,
    Ctrl-A, Ctrl-C)
  8. 8. Paste into a new text file in PSPad
  9. 9. Sort and/or edit so that the headings are at the top and the
    results are contiguous with no intervening blank lines. Copy all.
  10. 10. Open AncestrySourceConverter.xslx with MS Excel.
  11. 11. Delete all from sheet Source.
  12. 12. Paste from clipboard into the 1st cell of sheet Source.
  13. 13. Copy all UPDATE queries from sheet SQL. Note that just the first
    100 queries are created. If what you pasted into sheet Source is more
    than 100 rows, you will either have to do the UPDATEs in multiple
    batches or extend the rows of formulae in sheets Extract, Replace and
    SQL.
  14. 14. Paste into a new SQL window in SQLiteSpy.
  15. 15. Check through to the end that syntax colouring is correct. If
    there was an apostrophe in the original source it will need to be
    escaped with a second so that it is not interpreted as a text delimiter.
  16. 16. Execute the batch of UPDATE queries. This may take some 20 seconds
    – I do not know why it is so slow.
  17. 17. Open both the unprocessed and revised RootsMagic databases with RM
    and inspect the Master Source list to satisfy yourself with the results
    and make any other edits required.

To abbreviate the Short Footnote more, I think requires manual editing of
each citation, most effectively done by converting the sources to the !MyFreeForm3 source template.

Images of Results

MergedURLs&Images-CitationScreen.PNGMergedURLs&Images-MediaScreen.PNG

Generate WebTags from
the Citations

This applies to RootsMagic 6 which first introduced WebTags. The Ancestry
GEDCOM passes the URL (hyperlink) of each online citation in the citation
Comments field. For convenient access to these online sources, it is
desirable to make a Citation WebTag with that URL. That’s what is described
in WebTags
– from Ancestry.com and FTM
. And then to make it even more convenient,
copy those citation WebTags to person WebTags using WebTags
– Consolidate
.

Revealing
Citations from Ancestry that Disappeared

We think that citations in support of a Name in an Ancestry tree disappear
on import to RootsMagic in certain cases. See Citations
Invisible Revealed
for further details and how to reveal them to
RootsMagic.

Discussions & comments from Wikispaces site


ve3meo

Comment: “Open SQLiteSpy with the fake
RMNOCASE extension”

ve3meo
03
September 2018 19:40:01
ve3meo Sep 28, 2015
A Mac user encountering an error “LIKE pattern too large” or
words to that effect wanted to know if there was a way to run
the script without the RMNOCASE collation (on his own build of
sqlite3). The answer is a qualified “maybe” and it will take
trial and error. Wherever there is a field that is compared to
a value and that field has been defined to use the RMNOCASE
collation, it is probable that an error will result.
It is possible in some cases to override the defined collation
with a COLLATE NOCASE suffix wherever the field is named in a
SQL SELECT statement. However, you cannot UPDATE such a field.
Fortunately, the script does not UPDATE a field using the
RMNOCASE collation so any collation error must stem from a
comparison.
However, looking into this question raised some others. A
field that is UPDATEd is CitationTable.Comments and a puzzling
thing was observed. The script assumes that it is a TEXT field
which is what is contained in a number of databases inspected
yet in the table definition it is supposed to be type BLOB.
SQLite3 does not enforce field types and it appears that
RootsMagic does not follow its own field spec. This may be a
red herring but it could give rise to unexpected results if
some databases or rows within a database were not
type-consistent with others.

Places – Conversion of Place Details to Places #places #placedetails #update

Still works with versions up to and including #RM10. See Notes. 2025-08-04.

So you have your Place List all nicely structured having worked through and split Places into Places and Place Details and it all seems ticketyboo. Now you need to export your database to some other website or software which does not support the way RootsMagic exports Place Details and POOF! – you’ve been caught in another proprietary feature trap. Wouldn’t it be nice if RootsMagic had an option in Export for Place Details and Place to be combined and outputted as standard GEDCOM PLACes recognised by every GEDCOM compliant program? Until that happens, here is a possible workaround that modifies the data in your database.

Places-ConvertPlaceDetailsToPlaces.sql rev 2015-05-15 changed EventTable.SiteId backfill from -1 to 0 and test from <>-1 to >0; correcting either an original error or responding to a change in the RootsMagic value for an event not having a Place Detail.

Combines Place Details and Master Place into Places. This script should run with any SQLite3 manager having a (fake) RMNOCASE collation. One of its effects is to set a flag in the combined Places that the following script can use to reverse the combination.

Places-UnConvertPlaceDetailsConvertedToPlaces.sql
For those combined Places with the flag set by the first script, this one splits the Place into Place Detail and Master Place. The flag disappears if the combined Place has been edited so such Places can only be split manually. Also, if the Master Place has been deleted or its name modified, then the Combined Place is not split by the script, except, possibly for those Master Places that are a substring of the original, in which case, the result will be a bit of a mess. This script is really an UNDO to provide an escape if you inadvertently ran the first script on your master database, not on a copy, and have no backup.

Notes:

  1. Preserves the geo-coordinates and Note from original Place Detail in its conversion to Place.
  2. Original Place remains as-is but may become unused if, previously, it had a Detail for every use.
  3. The original Place Note is left with the original Place and not combined with the Notes from the Place Details that have been converted.
  4. The newly converted Places may not have Standard or Abbreviated Names. RM’s Geo-code function can be used to generate coordinates and Standard Names.
  5. Later versions of RM have Reverse Place Names in the PlaceTable for speedy display in the Places view. The Convert script does not generate them but RM’s Geo-coding function does appear to. Reports create their own reversals for Indexes and do not rely on that table’s column.
  6. Remember to REINDEX in SQLite on leaving RM to execute one of the above scripts on a RM database and to Rebuild Indexes in RM when you return to it.

TMG to RootsMagic Migration #tmg

This page provides an overview of the utilities available on this wiki that may help you with your migration of a TMG Project to a RootsMagic database. An example of what TMG Refugee Mike James did is described at https://lists.rootsweb.com/hyperkitty/list/tmg-refugees.rootsweb.com/thread/199856/. It is important to note that there may be considerable cleanup and data manipulation to be done in TMG first in order to have as complete a data transfer as possible because RootsMagic does not replicate all the features of TMG.

These pages have been tagged “TMG” because they apply to artefacts in databases imported from TMG:

Of course, once your TMG data is in a RootsMagic database, you are able to apply any of the 200-some SQLite queries available here and to develop your own.

Marriages, Length of #marriage

This script answers the question, “How long have marriages lasted?”. For each Marriage and corresponding Annulment or Divorce event for a couple,
it extracts the year of the events and also gets the year of the death of the earlier of the two to have died. It then calculates the length in time between the year of the marriage event and the earliest of the years of the Annulment, Divorce and Death events as the length of the marriage. In the absence of a year for any of these terminal events, it uses the current year from system time. Results are limited to 99 years max.

MarriageLength.PNG
Screen clip of results of query on a small test database in SQLiteSpy.

The second last row in the example is the special case of a couple that divorces and remarries each other; the Length of the second marriage is correct but the Divorced year throws a curve visually. It could be suppressed with a some more coding but is a rare state.

The Died year comes from the Person’s DeathYear field in the NameTable, not directly from the Death or Burial facts, so it is advisable to use File > Database Tools > Rebuild Indexes before running the script to ensure that the DeathYear is sync’d to the latest edits or additions of Death/Burial events.

When there are multiple events of a given type, this script probably extracts the year of the first entered; it could be enhanced to select the Primary.

MarriageLength.sql

Ancestors Query #pedigree

Intro

This query lists all the ancestral lines for a given RIN in your database out to the 13th generation. It is just a table of RINs but could be extended to provide names et al. More significantly, it can be the basis of other queries that need to follow ancestral lines. One of these, already developed is Ancestors Named Group which refreshes the membership of a specially named group in a RM4 database.

AncestorsScreenshot-Spy.PNG
From SQLiteSpy showing the full ancestral lines for three persons plus part of a fourth. Use SQLite Developer or Expert Personal to specify the starting person’s RIN when the query is run – absolutely necessary for large databases.

There was earlier discussion about the need for program recursion for ancestral lines in Set Living Flag and in Another version of a Set Living query. This query does not achieve recursion as it seems quite likely that it cannot be accomplished within SQLite; a higher level language making calls to SQLite seems necessary. However, the script appears amenable to programmatic generation so that instead of recursive calls to SQLite, a dynamic script itself could be written to cover the desired number of generations. RootsMagic 4 may do it either way as the number of generations is a required input.

No attempt was made to filter on the type of relationship (blood, adoptive) between child and parent so the results include all kinds of ancestry.

Download

Ancestors.sql

Usage

This query uses a runtime parameter for the entry of the RIN of the person whose ancestral lines are to be generated. If left blank, or if your SQLite manager does not support runtime parameters, it will attempt to generate the ancestral lines for EVERYONE in your database. This will be very sloooow and may crash the program. SQLite Expert Personal and SQLite Developer ($29 version) do work with the runtime parameter; SQLite Spy skips over it.

Discussions & comments from Wikispaces site

ve3meo

Comment: “…the need for program recursion for ancestral lines …”

ve3meo
03 September 2018 19:37:05

ve3meo Mar 28, 2014

SQLite 3.8.4.1 and somewhat earlier introduced the WITH clause with the RECURSIVE option which should allow ancestral queries in a tree. The current version of SQLite Expert Personal supports this new clause but SQLite Spy does not.
ve3meo Mar 28, 2014

My first success with recursion in SQLite: Ancestors+Query+-+Recursive

Children – Set Order by Birth SortDate #child #family #sortdate #update

There have been recurring wishes expressed in the RootsMagic Forums for an enhancement to globally sort each family of children in the order they were born. For example, have a look at this thread, Sorting all children in the database by birth order. Expressed there are good reasons to be cautious about such an operation but, for some users, the possibility of adverse positioning of children without dates is outweighed by the time saved in organizing those who do. Until RootsMagic does offer such a feature, here is a script that sorts children by birth date.

While executing the script is straightforward, the underlying procedures involve several temporary SQlite Views and a temporary Table. It tries to pick out the dominant event for a person from his/her collection of Primary and non-Primary Birth and Christening events. A single Primary Birth with date is handled best; multiple Primaries or multiple events of the same type in the absence of a Primary may give an undesired order if dates overlap with another child.

The script only updates the child-sorting value (ChildTable.ChildOrder) of those children with a birth-type event having a SortDate and only for those families in which all children have said SortDate. The ChildOrder value of other families is left unchanged. Thus, it should be safe to use this script on a database for which some families have children lacking a birth-type fact or a SortDate for same; it will not affect the order of children whether they are still in the sequence they were added to the family or were subsequently manually rearranged.

To find families which still need to be rearranged manually after having run this script, see Children – Needing Manual Arranging.

It is the SortDate of the birth-type event which is the sorting key, not the Date. This means that users can enter a Birth fact without a Date or with a text Date (unrecognised date format) but with a SortDate estimated to be appropriate and what they might have in mind were they manually rearranging the children. The child order would then be reconstructed correctly by the script.

Almost any SQLite3 manager should be capable of executing this script. As usual, make a backup or work on a copy of your database file so you can get back to where you were before the script executes if you don’t like the outcome.

Children-SetOrderByBirthSortDate.sql
2015-01-22 1st release
2015-01-22 rev to preserve the order of children in families where 1 or more have no birth sortdate or no birth fact.
2015-01-24 rev to correct the override of valid Christen SortDates by empty Birth SortDates

Children – Needing Manual Arranging #child #family #sortdate

After running the query Children-SetOrderByBirthSortDate.sql, there may remain families that need to be manually arranged because one or more of the children has no birth-type fact or has a dominant birth-type fact with no date. This query produces a list of the parents who have such children. Look up and select one of the parents in the Sidebar Index with Family as the Main View and edit as needed.

This query also returns families with a single child; it is helpful in TimeLine and other views and reports to have at least an estimated date of Birth, even just a sort date.

Children-NeedingManualArranging-2.sql

2015-01-23 1st release
2015-01-24 rev to show count of children in family
2015-01-24 rev2 to make standalone, using the WITH syntax with Common Table Expressions for brevity

Discussions & comments from Wikispaces site


thejerrybryan

Bug?

thejerrybryan
19 August 2016 14:16:54

There seems to be something wrong with the script. It begins with WITH statement instead of with a SELECT statement. It may be a valid construction, but if so then I’m not familiar with it. And any case, it fails when run with SQLiteSpy.

Jerry


thejerrybryan

thejerrybryan
19 August 2016 14:19:11

Oops, I see that rev2 changed it to use the WITH syntax with which I’m not familiar. So I guess the syntax is valid. But it doesn’t seem to work with SQLiteSpy.

Set Living Flag #update #living

Superseded 2015-01-25. See Living Flag – Set Globally.

Discussion in RootsMagic-Users pointed out some limitations with the Set Living tool in RootsMagic and the risk of unsetting persons that have been previously set correctly. This page discusses how SQLite might help and is intended to start the development of some useful queries.

The Living flag is stored in the PersonTable in the column named ‘Living’. It has two values: 1=True (Alive), 0=False (Dead).

This query can set all persons to the same state:

UPDATE PersonTable
 SET Living=0; -- Dead 0, Living 1

This query can find all persons with a Death fact:

     -- Persons with death facts
     SELECT PersonID FROM PersonTable, EventTable
      WHERE PersonID=OwnerID
      AND EventType=2;

This query can find all persons with an Individual fact (excluding Family facts) before a given year (1906, in this example):

     -- Persons with any Individual facts dated earlier than 1906
     SELECT PersonID FROM PersonTable, EventTable
      WHERE PersonID=OwnerID
      AND OwnerType=0
      AND DATE LIKE 'D%'
      AND substr(DATE,4,4)<'1906';

We can combine these into one query that will set the Living flag to False for persons with a Death fact or having an individual fact dated earlier than 1906:

UPDATE PersonTable
 SET Living=0 -- Dead 0, Living 1
 WHERE PersonID
 IN (
     -- Persons with death facts
     SELECT PersonID FROM PersonTable, EventTable
      WHERE PersonID=OwnerID
      AND EventType=2
     UNION
     -- Persons with any Individual facts dated earlier than 1906
     SELECT PersonID FROM PersonTable, EventTable
      WHERE PersonID=OwnerID
      AND OwnerType=0
      AND DATE LIKE 'D%'
      AND substr(DATE,4,4)<'1906'
     )
;

This query can be extended to include Family facts (Marriage, Divorce, etc.) older than the given year. We’ll leave that to later or for someone else to add.

So that’s all well and good but for a lot of ancestors, there may be no events, let alone dates. If no Death fact has been entered, then the above queries will leave the Living flag alone; if it was set to True, that’s the way it will stay. It would be great, therefore, to set the Living flag to false for all ancestors and children of some person whose events occurred before the trigger year of, say, 1906. This is probably not readily done within SQLite because it requires a recursion routine through PersonTable and FamilyTable. It can readily be done in a high level programming language that calls SQLite and operates on the results with additional calls. You can see the problem of doing what is essentially the Pedigree tree by examining this 5-generation paternal line query:

SELECT P1.PersonID||','||P1.FatherID||ifnull(','||P2.FatherID,'')||ifnull(','||P3.FatherID,'')||ifnull(','||P4.FatherID,'') AS Pedigree
FROM
(SELECT P.PersonID, F.FatherID FROM PersonTable P , FamilyTable F
 INNER JOIN PersonTable H ON(F.FatherID=H.PersonID)
 WHERE P.ParentID=F.FamilyID) AS P1
LEFT JOIN
(SELECT P.PersonID, F.FatherID FROM PersonTable P , FamilyTable F
 INNER JOIN PersonTable H ON(F.FatherID=H.PersonID)
 WHERE P.ParentID=F.FamilyID) AS P2
ON (P1.FatherID=P2.PersonID)
LEFT JOIN
(SELECT P.PersonID, F.FatherID FROM PersonTable P , FamilyTable F
 INNER JOIN PersonTable H ON(F.FatherID=H.PersonID)
 WHERE P.ParentID=F.FamilyID) AS P3
ON (P2.FatherID=P3.PersonID)
LEFT JOIN
(SELECT P.PersonID, F.FatherID FROM PersonTable P , FamilyTable F
 INNER JOIN PersonTable H ON(F.FatherID=H.PersonID)
 WHERE P.ParentID=F.FamilyID) AS P4
ON (P3.FatherID=P4.PersonID)
;

It produces results like this:

Pedigree
1,116
4,7
5,7
6,254,155,829,138
8,829,138,821
11,829,138,821

A starting person’s RIN is on the left, father next to the right, grandfather next, etc. Results could be constrained to those first persons having old event dates and an UPDATE of the Living flag to 0 for each PersonID (RIN) in that person’s list of paternal parents. However, we would need to grow the query with another LEFT JOIN for each additional generation, hence the need for a recursive routine that would re-use the same core query for each generation until the last ancestor was found. And this was just the paternal line – to add the maternal line and each set of grandparents at each generation is unwieldy without recursion.

If someone can find a way to recurse using SQLite, that would be great; otherwise, some high-level programming is required.
[inline comment: “find a way to recurse using SQLite”

external image user_none_lg.jpg ve3meo Apr 13, 2014

It is now possible: Ancestors+Query+-+Recursive

]

Discussions & comments from Wikispaces site


thejerrybryan

Recursive Query

thejerrybryan
04 July 2011 02:23:38

I have been away from the computer most of the day, but prior to that I had already completed a series of queries that are very similar to the ones you you just posted. I was planning to post them when I got back on the computer tonight. I’ll try to get mine posted as soon as I can, just as a way to compare notes.

I don’t know of any way to do the kind of recursion with SQL that would be required to do something to “all ancestors”, but my update to “set parents of those born before 1906 to not living” can be run multiple times, and each time it would pick up at least one new generation. So we can sort of fake out a recursion simply by running the same update a bunch of times.

It will probably be tomorrow before I get anything else posted.

Jerry


ve3meo

ve3meo
14 April 2014 02:34:12

Have a look at Ancestors+Query+-+Recursive

Tom

Inline comments


ve3meo

Comment: It is now possible: http://sqlitetool…

ve3meo
14 April 2014 02:40:35

It is now possible: Ancestors+Query+-+Recursive

Another version of a Set Living query #living

Superseded 2015-01-25. See Living Flag – Set Globally.


I’m posting my version of SQL for Set Living. It proves to be remarkably similar to Tom’s.

SQL #1, we turn on the Living Flag for everybody in the database. Essentially, we make everybody private and then followup later by setting individuals as not private when they don’t need to be.

--                             Start by privatizing everyone in the database
 
UPDATE PersonTable
  SET Living = 1     -- 0 is not living, 1 is living
  WHERE Living != 1  -- In case it's faster not to update the ones that are already set to living
;

This code differs from Tom’s in that it includes the WHERE Living != 1 clause. The idea is to improve performance slightly by only setting to 1 those flags that are not already 1. In most programming contexts, this would be a silly distinction to make. In a procedural language such as C/C++, I would never consider code such as if (x != 1) x = 1 when a simple x = 1 would do, and indeed the simple form would run faster. But disks are vastly slower than main computer memory and it seems to me that avoiding the write operation associated with SET LIVING = 1 whenever possible might improve performance. But this case the UPDATE runs so quickly either way that I can’t prove which is faster. However, in later queries in this sequence it turns out that it’s important to keep the number of rows being operated on as small as possible, not so much for performance reasons as for other reasons.

SQL #2, we turn off the Living Flag for everyone whose birth date is before 1906.

--                             Unprivatize everyone born before 1906
 
UPDATE PersonTable
  SET Living = 0
  WHERE PersonID IN
    (
     SELECT P.PersonID
       FROM PersonTable AS P
              INNER JOIN
            NameTable AS N ON ( (P.PersonID = N.OwnerID) AND (N.NameType = 0) )  -- Use only the primary name table entry
       WHERE N.BirthYear > 0     --  BirthYear Exists
                AND
             N.BirthYear < 1906
    )
;

This is a case where I like Tom’s code much better than mine. Mine uses the birth year from the NameTable, which is not as reliable as using the EventTable as does Tom. Also, mine only uses the birth date, whereas Tom’s code uses any fact date from the EventTable. So his code is going to detect more people who should have the Living Flag turned off than mine. I had intended my code as a quick and dirty proof of concept, and I had intended to go back and reference the EventTable later with my final code. In looking Tom’s code to fully interpret dates, it seemed more complicated than I wanted to deal with until I had completed my proof of concept. But Tom already wrote very simple code to interpret dates as needed by this query.

However, Tom’s code at this point also includes turning off the the Living Flag for every individual who has a Death Fact, irrespective of what date (if any) is associated with the Death Fact. That’s an important item to accomplish, but my overall process requires that it be left until last.

SQL #3, we turn off the Living Flag for the parents of everyone whose Living Flag has already been turned off. It’s essential at this point in the process that the only reason the Living Flag has been turned off for anybody is because they have an Event Date (any event) prior to 1906. The parents of any such individuals are guaranteed to be deceased. But if the Living Flag is turned off for somebody because they have a Death Fact and the Death Date is 2007, then there is no guarantee that the parents are deceased.

--                             Unprivatize parents of everyone who is already unprivatized
 
UPDATE PersonTable
  SET Living = 0
  WHERE PersonID IN
    (
          SELECT PP.PersonID
            FROM PersonTable AS P
                   INNER JOIN
                 FamilyTable AS F ON (F.FamilyID = P.ParentID)
                   INNER JOIN
                 PersonTable AS PP ON (F.FatherID = PP.PersonID)
           WHERE ( (P.Living = 0) AND (PP.Living = 1) )
 
          UNION
 
          SELECT PP.PersonID
            FROM PersonTable AS P
                   INNER JOIN
                 FamilyTable AS F ON (F.FamilyID = P.ParentID)
                   INNER JOIN
                 PersonTable AS PP ON (F.MotherID = PP.PersonID)
           WHERE ( (P.Living = 0) AND (PP.Living = 1) )
    )
;

A UNION is required to get both the father and the mother. But once you figure out how to do the father, you just clone the father code to make it into the mother code and combine the two with UNION.

It took me a long time to figure out how to do this UPDATE. The primary conceptual problem was understanding how to reference both the PersonTable.PersonID of the person and the PersonTable.PersonID of the parents in the same sub-query, and then how to pass the correct PersonID out of the sub-query back to the query on the outside of the sub-query. In retrospect, it seems obvious and simple. But before I figured it out, it seemed almost impossible. I plan to post a separate "lessons learned" page about just that issue.

Note that contrary to intuition, SQL #3 doesn’t need to look at any dates whatsoever because the heavy lifting on dates has already been completed in SQL #2. And if I were to change SQL #2 to look at the dates of all fact types as in Tom’s code, I still would not need to change SQL #3 at all.

As Tom pointed out, the problem at this point is that you really need to run a recursion on this query, and to run the recursion enough labels deep to get all the ancestors, not just the parents. I can’t think of any way to accomplish such a recursion within a single UPDATE. But SQL #3 can be run as many times as you wish, and each time it is run it will get one additional generation of ancestors. But how many times should you run it? To that end, we can do the following.

SQL #4, for which individuals (or for how many) could we turn off the Living Flag if we ran SQL #3 again.

SELECT Z.PersonID           -- or SELECT COUNT(Z.PersonID)
  FROM
    (
          SELECT PP.PersonID
            FROM PersonTable AS P
                   INNER JOIN
                 FamilyTable AS F ON (F.FamilyID = P.ParentID)
                   INNER JOIN
                 PersonTable AS PP ON (F.FatherID = PP.PersonID)
           WHERE ( (P.Living = 0) AND (PP.Living = 1) )
 
          UNION
 
          SELECT PP.PersonID
            FROM PersonTable AS P
                   INNER JOIN
                 FamilyTable AS F ON (F.FamilyID = P.ParentID)
                   INNER JOIN
                 PersonTable AS PP ON (F.MotherID = PP.PersonID)
           WHERE ( (P.Living = 0) AND (PP.Living = 1) )
    ) AS Z
;

So we can run SQL #3 and SQL #4, followed by SQL #3 and SQL #4, over and over again until SQL #4 yields no rows. At that point, SQL #3 will have done all it can do and we can proceed to SQL #5.

For this query, P.Living in the sub-query is the Living Flag for the individual, and PP.Living in the sub-query is the Living Flag for the parent of the individual. The WHERE statement is coded as WHERE ( (P.Living = 0) AND (PP.Living = 1) ), which tests for situations where the individual is not living but the parent is still flagged as living. And remember that the not living condition at this point is strictly due to event dates, not yet on the presence of a death fact. So it would be sufficient to code the WHERE simply as WHERE P.Living = 0 in the SQL #3. But writing the WHERE statement as it was written is more efficient than just testing for P.Living because it keeps the number of rows in the sub-query as small as possible. And more importantly, SQL #4 will not produce the correct results without testing both P.Living and PP.Living.

SQL #5, turn off the Living Flag for all individuals who have a death fact. It is now safe to do so because we have done everything we can do with ancestors.

--                             Unprivatize everyone with a valid death date
--
--   We separate the processing of the death year from the processing of the birth year because
--   we need to process ancestors before we unprivatize based on the existence of a death date
 
UPDATE PersonTable
  SET Living = 0
  WHERE PersonID IN
    (
     SELECT P.PersonID
       FROM PersonTable AS P
              INNER JOIN
            NameTable AS N ON ( (P.PersonID = N.OwnerID) AND (N.NameType = 0) )  -- Use only the primary name table entry
       WHERE
         N.DeathYear > 0         -- Death year exists, doesn't matter what it is if it exists
     )
;

My code tests for the presence of a death date, whereas Tom’s code tests for the presence of a death fact. Tom’s code is complete and mine is not. I need to change mine to match Tom’s.

Jerry

Discussions & comments from Wikispaces site


ve3meo

Comment: “…really need to run a recursion on this query…”

ve3meo
03 September 2018 19:43:31

ve3meo Apr 13, 2014

Maybe there is now a way: Ancestors+Query+-+Recursive