Events – Add to all Children a Parent event shared with parents #facttypes #sharedevent #relationships #rm8

TBA: Rev 2021-03-0x above script adapted for RM8 by Tom Holden from the #RM7 script described below by the original author, Jerry Bryan. Note that the custom fact type ‘Parents’ and the role ‘Birth_of_Child’ must be created separately in advance of executing this script.

This is a query I wrote just for myself and I didn’t feel as if it were of sufficiently general interest to post here. Also, it is not as polished as I like queries to be that I share publicly. But a request came up on the RootsMagic forums, so here it is. The query adds a Parent fact to everyone in the database who is not a dummy person, who has parents, and who has a birth fact with a valid date. The dummy person definition is for my own database, where my dummy people have an asterisk somewhere in their name. The birth fact with a valid date is required because the Parent fact needs a valid date, and in my database at least it needs to be placed immediately after the Birth fact. The name of the fact is singular “Parent” but it supports both parents. As written, the parent information is placed two places: 1) in the Description field for the Parent fact, and 2) the Parent fact is shared with both parents.

My sentence template for the Parent fact itself is setup as follows:

<b>Parents:</b>< [Birth_of_Child].>

I use point form sentences with the sentence for each fact starting on a new line. The new line is a part of the template. Most RM users would need to set up the sentence template differently to meet their own needs. The [Birth_of_Child] variable looks funny, but that’s the role I share with the parents and it is what gets the parents listed in the sentence. Using the [Desc] variable would produce the same sentence, but using the [Birth_of_Child] variable causes the parents to be listed in the index for this page and the [Desc] variable does not. I mostly use Descendant Narrative reports. For the descendants, the parents appear in the report anyway, a generation earlier. The [Parent] variable makes the parents explicit. For the spouses of the descendant, their parents already appear by default in what I call the spouse sentence. So the [Parent] variable for the spouses represents a duplication. The spouse sentence is not under control of source templates (a major failing of RM), so I solve the problem by running a Notepad++ script on the RTF file to remove the parents from the spouse sentence before printing.

My sentence template for the [Birth_of_Child] role is as follows.

<b>Birth of Child:</b> <[Date:plain]><, [Person:Full]><, parent age: [ThisPerson:age:plain]>.

This has the salutatory effect of including the birth of each child on the timeline of each parent in a narrative report. Upon further review, I think the sentence would look better using a gender switch to say mother’s age or father’s age as appropriate. Gender switches work on the [Person] variable. I can’t remember if they work on the [ThisPerson] variable or not.

And here follows the script, warts and all

-- This script writ large creates a Parent
-- fact for every person in the RM database
-- who has parents. It loads the parents'
-- names into the Description field for the
-- Parent fact. It also shares the Parent
-- fact with the parents themselves where it
-- shows up as a Birth of Child event.
 
-- This script was not developed with the intent
-- of being generally distributed. Hence, it has
-- not been refined and tested the way I would do
-- for general distribution of a script. Please
-- use it and adapt it on an "as is" basis or for
-- ideas alone.
 
-- I can't remember for sure, but sometimes scripts
-- that insert this much data into into an RM data
-- base can create indexing errors. If so, run the
-- RM database tool in order immediately after running
-- this script.
 
-- Jerry Bryan 7/31/2018
 
 
-- Create a view of the EventTable
-- containing only Parents events.
-- This view will be used to prevent
-- creating a Parents event for
-- any individuals who already have
-- a Parents event. The main data needed
-- is the PersonID of the individuals
-- who already have a Parents event.
-- The PersonID manifests itself in
-- the EventTable as OwnerId.
 
 
DROP VIEW IF EXISTS ParentEventView;
CREATE TEMP VIEW ParentEventView AS
SELECT E.*
FROM EventTable AS E
       JOIN
     FactTypeTable AS FT  ON FT.FactTypeID = E.EventType
     WHERE FT.Name LIKE('Parents');
 
 
 
-- Create a view of the EventTable
-- containing only Birth events.
-- These events provides an initial list
-- of candidates of people to receive
-- a Parents event. Also, many of the
-- fields for newly created Parents
-- events will be replicated from the
-- corresponding Birth event.
 
DROP VIEW IF EXISTS BirthEventView;
CREATE TEMP VIEW BirthEventView AS
SELECT Birth.*
FROM EventTable AS Birth
       JOIN
     FactTypeTable AS FT  ON FT.FactTypeID = Birth.EventType
     WHERE FT.Name LIKE('Birth');
 
 
-- Create a view of Birth events for people
-- that don't have a Parent event. This is the
-- first filtering on the list of candidates
-- of people to receive a Parents event.
 
 
DROP VIEW IF EXISTS BirthWithoutParentsEventView;
CREATE TEMP VIEW BirthWithoutParentsEventView AS
SELECT Birth.*
FROM BirthEventView AS Birth
          LEFT JOIN
     ParentEventView AS Parent ON Parent.Ownerid = Birth.OwneriD
WHERE Parent.OwnerID IS NULL;
 
-- Create a view of the NameTable
-- containing only primary names.
-- This view will be a source of
-- the names needed for the newly
-- created Parents events and will
-- prevent any names other than the
-- primary ames from being loaded
-- into -- Parents events. This
-- view also prevents Parents events
-- from being created for any dummy
-- people, designated with an asterisk
-- in the name.
 
DROP VIEW IF EXISTS NameView;
CREATE TEMP VIEW NameView AS
SELECT N.*
FROM NameTable AS N
WHERE N.IsPrimary = 1
  AND N.Surname NOT LIKE('%*%')
  AND N.Given   NOT LIKE('%*%');
 
-- This view performs most of the
-- main processing for this project.
-- It determines which people actually
-- do have parents. Actually having
-- parents is based on being in the
-- ChildTable and has nothing to do
-- with whether a Parents event exists
-- or not. This list of people with parents
-- is then matched against people who are not
-- dummy people, who do have birth
-- events, and who don't already have
-- Parents events. This view also
-- develops the data that will need to
-- be stored in the newly created
-- Parents events.
 
 
DROP VIEW IF EXISTS ChildParentsView;
CREATE TEMP VIEW ChildParentsView AS
SELECT Child.ChildID,  Child.Given  || ' ' || Child.Surname  AS ChildName,
       Father.FatherID, Father.Given || ' ' || Father.Surname AS FatherName,
       Mother.MotherID, Mother.Given || ' ' || Mother.Surname AS MotherName,
       CASE
       WHEN Father.FatherID = 0 THEN Mother.Given || ' ' || Mother.Surname
       WHEN Mother.MotherID = 0 THEN Father.Given || ' ' || Father.Surname
       ELSE Father.Given || ' ' || Father.Surname || ' and ' || Mother.Given || ' ' || Mother.Surname
       END CombinedNames,
       B.Date,
       B.SortDate,
       B.EditDate
 
FROM  (  SELECT C.RecID,
                C.ChildID,
                N.Given,
                N.Surname
         FROM   ChildTable AS C
                  JOIN
                NameView AS N ON N.Ownerid = C.ChildID
      ) AS Child
 
           JOIN
 
      (  SELECT C.RecID,
                FM.FatherID,
                N.Given,
                N.Surname
         FROM ChildTable AS C
                JOIN
              FamilyTable AS FM ON C.FamilyID =  FM.FamilyID
                LEFT JOIN
              NameView AS N ON N.OwnerID = FM.FatherID
      ) AS Father ON Father.RecID = Child.RecID
 
           JOIN
 
      (  SELECT C.RecID,
                FM.MotherID,
                N.Given,
                N.Surname
         FROM   ChildTable AS C
                  JOIN
                FamilyTable AS FM ON C.FamilyID =  FM.FamilyID
                  LEFT JOIN
             NameView AS N ON N.OwnerID = FM.MotherID
       ) AS Mother ON Mother.RecID = Father.RecID
 
            JOIN
 
       BirthWithoutParentsEventView AS B ON B.OwnerID = Child.ChildID;
 
-- The data from the ChildParentsView needs to be used
-- twice, once to load Parents events into the EventTable
-- and again to load roles into the WitnessTable. The
-- Parents events have to be loaded into the EventsTable
-- first, and one Insert statment in SQLite cannot load
-- data into two tables. However, loading Parents Events
-- into the EventTable will cause the ChildParentsView
-- not to produce the correct results the second time it
-- is used. Therefore, the results from applying the
-- ChildParentsView will be saved into a temporary table
-- called ChildParentsTable. As a table instead of a view,
-- the data in ChildParentsTable can be used two different
-- times and remain the same data both times it is used.
 
DROP TABLE IF EXISTS ChildParentsTable;
CREATE TEMP TABLE ChildParentsTable
(ChildID,ChildName,FatherID,FatherName,MotherID,Mothername,CombinedNames,Date,SortDate,EditDate);
INSERT INTO ChildParentsTable
(ChildID,ChildName,FatherID,FatherName,MotherID,Mothername,CombinedNames,Date,SortDate,EditDate)
SELECT CP.*
FROM ChildParentsView AS CP;
 
 
 
-- Load new Parents facts into the EventTable.
 
INSERT OR ROLLBACK INTO EventTable
SELECT NULL AS EventID
    ,(SELECT FT.FactTypeID FROM FactTypeTable AS FT WHERE FT.Name LIKE('Parents') ) AS EventType
    ,0 AS OwnerType
    ,ChildID AS OwnerID
    ,0 AS FamilyID
    ,0 AS PlaceID
    ,0 AS SiteID
    ,Date AS Date
    ,SortDate AS SortDate
    ,0 AS IsPrimary
    ,0 AS IsPrivate
    ,0 AS Proof
    ,0 AS STATUS
    ,EditDate AS EditDate
    ,CAST('' AS TEXT) AS Sentence
    ,CAST(CombinedNames AS TEXT) AS Details
    ,CAST('' AS TEXT) AS Note
 FROM ChildParentsTable;
 
 
 
 --   ===========================================================================================================
 --     The following is adapted from Tom Holden to rank same date sort dates.
 --
 --     There are a number of changes by Jerry Bryan that are specific to his
 --     use case.
 --
 --        * The list of fact types which are supported is greatly increased.
 --        * Sort dates including ranked sort dates (date-n) are ranked and even re-ranked
 --          whether or not they match the date from from the fact itself, provided only
 --          that the sort dates in question match each other.
 --             . This allows same "ABT" dates to be ranked.
 --             . This allows same "year only" dates to be ranked if the sort date is
 --               1 July of the year.
 --             . This allows same "year and month only" dates to be ranked if the
 --             . sort date is the 15th of the month.
 --
 --   ===========================================================================================================
 
/* SortDateSameDayOrderCustom.sql
   2011-12-20 ve3meo
   Alters SortDates of any set of Fact types
   to a natural order when any pair or more occur on the same date.
   Could be extended to order other facts also. SortDates are effectively assigned
   (by arithmetical offsets) an absolute suffix -1, -2, ... related to the rank of the FactType.
   Affects only those events whose SortDates correspond to the Fact Date, as computed
   by a Date encoding algorithm. The algorithm does not handle Date modifiers so not all
   Event dates are handled, e.g. "Bef 1960".
*/
DROP TABLE IF EXISTS TmpFactOrder
;
CREATE TEMP TABLE IF NOT EXISTS TmpFactOrder
(Rank INTEGER PRIMARY KEY, FactName TEXT)
;
 
/* list of Fact Names, standard and custom, to be sorted, in rank order.
   Revise the list to suit your needs */
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Birth');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Parents');             -- added by JB
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Birth Certificate');   -- added by JB
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Christen');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Baptism');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Death');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Obituary');            -- moved up by JB
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Death Certificate');   -- added by JB
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Funeral');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Cremation');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Burial');
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Burial Inscription');  -- Added by JB
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Burial GPS');          -- Added by JB
INSERT INTO TmpFactOrder (Rank, FactName) VALUES (NULL, 'Memorial');
/* revise SortDates */
UPDATE EventTable
SET SortDate = SortDate
  -6692012023  -- this offset goes to Date-1 if the event is a ranked event
  *( (
      SELECT Rank
      FROM TmpFactOrder,
           FactTypeTable
      WHERE FactName LIKE Name
      AND FactTypeID = EventType
      )>0
    )
  +1048576  -- this offset adds steps of 1 to Date-1 multiplied by (rank-1)
  *( (
      SELECT Rank
      FROM TmpFactOrder,
           FactTypeTable
      WHERE FactName LIKE Name
      AND FactTypeID = EventType
      )-1
    ) -- maps the FactType to its order
WHERE EventID
IN (SELECT EventID FROM EventTable
    INNER JOIN
    (SELECT -- matching dates
     SortDate, OwnerID, COUNT()-1 AS Matches
     FROM EventTable
     INNER JOIN FactTypeTable
     ON EventType = FactTypeID
     WHERE EventTable.OwnerType = 0
     AND Name IN (SELECT FactName FROM TmpFactOrder)
/*     AND    -- commented out by JB to handle sort dates not matching fact date when sort dates are equal to each other.
     SortDate =   -- equals encoded event Date (if not a match, suggests that user has modified SortDate so don't touch it)
       (CASE
        WHEN DATE LIKE '.%'
        THEN 1
        ELSE Substr(DATE,3,5) END
        +10000
        )*562949953421312
        + Substr(DATE,8,2)*35184372088832
        + Substr(DATE,10,2)*549755813888
        + 17178820620 */
      GROUP BY SortDate, OwnerID, EventTable.OwnerType
     )
     USING (OwnerID, SortDate)
     INNER JOIN FactTypeTable
     ON EventType = FactTypeID
     WHERE Matches
     AND EventTable.OwnerType = 0
     AND Name IN (SELECT FactName FROM TmpFactOrder)
    )
;
 
 
-- We now add Parent roles to each Parents event.
-- It is most convenient to add the Parent role
-- for the father in one INSERT and to add the
-- Parent role for the mother as a separate insert.
-- So we first create a view that joins the
-- Parent events with the ChildTable and FamilyTable
-- to get a list of Parent events and their
-- respective fathers and mothers.
 
DROP VIEW IF EXISTS ParentRoleView;
CREATE TEMP VIEW ParentRoleView AS
SELECT PEV.*,
       FM.FatherID, FM.MotherID
FROM ParentEventView AS PEV
        JOIN
     ChildTable AS CT ON CT.ChildID = PEV.OwnerID
        JOIN
     FamilyTable AS FM ON CT.FamilyID =  FM.FamilyID;
 
 
-- Load Parents roles for fathers into the WitnessTable
 
INSERT OR ROLLBACK INTO WitnessTable
SELECT NULL AS WitnessID
    ,PE.EventID AS EventID
    ,Parents.FatherID AS PersonID
    ,0       AS WitnessOrder
    ,(SELECT R.RoleID FROM RoleTable AS R WHERE R.RoleName LIKE ('Parent') ) AS Role
    ,CAST('' AS TEXT) AS Sentence
    ,CAST('' AS TEXT) AS Note
    ,CAST('' AS TEXT) AS Given
    ,CAST('' AS TEXT) AS Surname
    ,CAST('' AS TEXT) AS Prefix
    ,CAST('' AS TEXT) AS Suffix
 FROM ChildParentsTable AS Parents
         JOIN
      ParentEventView AS PE ON PE.OwnerID =  Parents.ChildID AND PE.Details = Parents.CombinedNames;
 
-- Load Parents roles for mothers into the WitnessTable
 
INSERT OR ROLLBACK INTO WitnessTable
SELECT NULL AS WitnessID
    ,PE.EventID AS EventID
    ,Parents.MotherID AS PersonID
    ,0       AS WitnessOrder
    ,(SELECT R.RoleID FROM RoleTable AS R WHERE R.RoleName LIKE ('Parent') ) AS Role
    ,CAST('' AS TEXT) AS Sentence
    ,CAST('' AS TEXT) AS Note
    ,CAST('' AS TEXT) AS Given
    ,CAST('' AS TEXT) AS Surname
    ,CAST('' AS TEXT) AS Prefix
    ,CAST('' AS TEXT) AS Suffix
 FROM ChildParentsTable AS Parents
         JOIN
      ParentEventView AS PE ON PE.OwnerID =  Parents.ChildID AND PE.Details = Parents.CombinedNames;
;
 

8 Replies to “Events – Add to all Children a Parent event shared with parents #facttypes #sharedevent #relationships #rm8

  1. Jerry, if you see this, please let me know if this script is still useful. I thought I would adapt it to RM8 but am running into confusion between the text and the script. Having got past the expected SQL errors, there are unexpected results in the RM8 app.

    The custom fact and the custom roles must be set up manually before the script is run. The fact name/abbreviation appears to be ‘Parent’ in one place and ‘Parents’ in another. The sentence template “Parents:< [Birth_of_Child].>” is for the Principal? The text makes no mention of a custom role named ‘Parent’ but the script looks for it in RoleTable. The text does describe a ‘Birth_of_Child’ role. As no ‘Parent’ role has been defined, the Parents event remains unshared.

  2. I don’t know if I have changed things in my RM7 database since a wrote the script. But it presently is the case that the user defined fact is Parents and the role name is Birth_of_Child.

    • Sorry, was interrupted. The sentence template for the Parents fact using my point form sentence templates is

      {carriage return}
      Parents:

      I actually place the name of the parents into the Description field but I don’t use the [Desc] variable in the sentence template because using the role name instead causes the names of the parents to be included in the Person index in narrative reports. But if I transfer my data to a system that does not support RM’s shared facts, the inclusion of the data in the Descrption field means that the data is not lost.

      The sentence template for the Birth_of_Child role is

      {carriage return}
      Birth of Child: <, age of : [ThisPerson:age:plain]>.

      Certain aspects of this look backwards to me, as do many things when I use RM’s shared facts. But these sentences provide me with the information I need in reports.

  3. Was interrupted again.

    I haven’t gone back to look in detail, but I believe there is a bug in the script in that it sets a sort date for the Parents fact that has a bad date qualifier. In particular, it uses Since as a qualifier. My script is the only thing I can think of that might have put sort dates in the Parents facts with an incorrect Since qualifier. I’m fixing the bad sort dates by hand. I’m using the following script to find the bad sort dates that need to be fixed. The script is sort of a one off script for my use and it uses negative logic. Namely, it finds sort dates where I *don’t* find date qualifiers that I recognize.

    Jerry

    SELECT FT.Name,
    E.date, PRINTF(‘%08X’, E.SortDate) AS SD,
    (E.SortDate >> 49) – 10000 AS Y1,
    (E.SortDate >> 45) & 0xf AS M1,
    (E.SortDate >> 39) & 0x3f AS D1,
    (E.SortDate >> 20) & 0x3fff – 10000 AS Y2,
    (E.SortDate >> 16) & 0xf AS M2,
    (E.SortDate >> 10) & 0x3f AS D2,
    E.SortDate & 0x3ff AS F,
    E.OwnerID,
    E.OwnerType
    FROM EventTable AS E
    JOIN
    FactTypeTable AS FT ON FT.FactTypeID = E.EventType
    WHERE F NOT IN (0,8,9,12,15,18,21,24,31,40,1023)
    ORDER BY F, E.OwnerType, E.OwnerID;

  4. In reviewing what I wrote, the sentence template for the Parents fact was partially lost when I was interrupted. By interrupted, I mean that I was typing along in this forum and it suddenly saved what I had written thus far and kicked me out. The correct sentence template is as follows.

    {carriage return}
    Parents:

  5. It still didn’t take the sentence template. The html aspect of sentence template must be confusing this forum. There is are bold/unbold tags around Parents: Then there is a Birth_of_Child variable, bounded by square brackets and angle brackets.

  6. Yes, WordPress (or this WP Theme) is really bad at some things. The Post/Page editor offers a code block but the on-the-post Comments Editor does not. However, it allows HTML tags to be used, as you’ve discovered. So it is possible to produce this:

    Parents
    

    … by wrapping it the HTML PRE tag and class expression copied from the Post/Page editor:
    <pre class="EnlighterJSRAW" data-enlighter-language="generic"><b>Parents</b>
    <br>
    </pre>

    PRE without EnlighterJSRAW delivers this unhelpful result:

    Parents
    

    If you save the comment and then edit it, I think it will open a more powerful Comment Editor which helps some formatting. Here’s a code section, but HTML tags within are still interpreted:
    Parents

    Thus the only method that seems to work is PRE with class=”EnlighterJSRAW” data-enlighter-language=”generic”. Language could be “sql” or others.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.