I’ve discussed this query before, but this is my first attempt to post a real, live query in both MS Access and SQLite formats. At the present time, my To Do grid only includes 17 rows and 2 columns but I will be adding additional rows and additional columns. I should mention up front that this query does not use RM4’s To Do list feature in any way. It establishes To Do items in a different way.
The rows in the grid correspond to individuals in my RM4 database, and at the present time I have 17 individuals who are of active research interest. The list of individuals who are of active research interest will grow quickly. The list of individuals of active research interest is maintained as a Named Group in my RM4 database. If I add individuals to that named group, those individuals immediately show up in my query. I hardwired group #6 into my query rather than hardwiring the name of the group into my query because it’s easier to deal with numbers in a way that’s compatible between MS Access and SQLite than it is to deal with text strings. Indeed, my query started out by using a text string to reference the name of the group, but it was just too clumsy keeping the MS Access and the SQLite versions of the query in sync, so I switched to the group number rather than the group name.
The columns in the grid correspond to items from my own personal To Do list. These are items that are not very amenable to tools such as RM4’s own To Do list or to the automated tools provided by GenSmarts. Most of my personal To Do items have to do with getting my database in good enough shape that a narrative report produced by RM4 is as nearly camera ready as possible, and that such a report needs little or no additional editing with a word processor before publishing. The first column is labeled PrgraphOk, and if it is checked off that means that I have verified that all my notes end with the appropriate carriage returns (or not) to producing the paragraphing that I want to see in a narrative report. The second column is labeled CensusOk, and if it is checked off that means that I have verified that all my census facts print out as I wish them to do – sentence templates are what I want and the fact notes are what I want. I primarily use GenSmarts as my To Do list to be sure that I get the 1850 census for John Doe who was born in 1845 and died in 1905, for example. So my To Do item of CensusOk is related only to how the census facts print out, and to be sure that they are camera ready.
I started out with the idea of storing my PrgraphOk and my CensusOk items in an MS Access table that would be joined with my RM4 database. But I later decided that I wanted RM4 to be my one and only official record, so I’m storing the information directly in RM4. I chose to use the existing Reference Number fact. After verifying that my To Do item is done, I then add facts to RM4 such as Reference Number PrgraphOk or Reference Number CensusOk. My query is robust enough that the PrgraphOk and CensusOk items can be entered on the same Reference Number fact or on separate Reference Number facts.
The design of the query is basically (list of individuals in the group) LEFT JOIN (list of individuals with the required Reference Numbers). Essentially, group membership constitutes the To Do list and the Reference Numbers constitute the To Done list. I don’t print the Reference Numbers in any reports, nor do I export them in any GEDCOM. The Reference Number facts are just for my own internal use.
Here is the query for SQLite.

SELECT L.RecNo AS RecNo, L.Surname AS Surname, L.Given AS Given, R.PrgraphOK AS PrgraphOK, R.CensusOk AS CensusOk
FROM
(SELECT
N.OwnerID AS RecNo,
N.Surname COLLATE NOCASE AS Surname,
N.Given COLLATE NOCASE AS Given
FROM
GroupTable AS G,
NameTable AS N
WHERE N.NameType=0 AND N.OwnerID>=G.StartID AND N.OwnerID<=G.EndID AND G.GroupID=6
) AS L
LEFT JOIN
(SELECT
E.OwnerID AS RecNo,
MAX(CAST(E.Details AS TEXT) LIKE 'PrgraphOk') AS PrgraphOk,
MAX(CAST(E.Details AS TEXT) LIKE 'CensusOk') AS CensusOk
FROM
EventTable AS E
INNER JOIN
FactTypeTable AS F ON E.EventType=F.FactTypeID
WHERE F.FactTypeID=35
GROUP BY E.OwnerID
) AS R ON R.RecNo = L.RecNo
ORDER BY Surname, Given
Here is the query for MS Access.
SELECT L.RecNo AS RecNo, LEFT(L.Surname,50) AS Surname, LEFT(L.Given,50) AS Given, R.PrgraphOK AS PrgraphOK, R.CensusOk AS CensusOk
FROM
(SELECT
N.OwnerID AS RecNo,
N.Surname AS Surname,
N.Given AS Given
FROM
GroupTable AS G,
NameTable AS N
WHERE N.NameType=0 AND N.OwnerID>=G.StartID AND N.OwnerID<=G.EndID AND G.GroupID=6
) AS L
LEFT JOIN
(SELECT
E.OwnerID AS RecNo,
MAX(Abs(StrConv(E.Details,64) LIKE "*PrgraphOk*")) AS PrgraphOk,
MAX(Abs(StrConv(E.Details,64) LIKE "*CensusOk*")) AS CensusOk
FROM
EventTable AS E
INNER JOIN
FactTypeTable AS F ON E.EventType=F.FactTypeID
WHERE F.FactTypeID=35
GROUP BY E.OwnerID
) AS R ON R.RecNo = L.RecNo
ORDER BY Surname, Given
Here is some further discussion of the scripts.
- MS Access does not support comments. SQLite does. At the present time, my comments therefore will be narrative such as this which is outside the SQL script. This is not good programming practice, but it feels enforced upon me by MS Access.
- In the outer SELECT statement, the Left function is used in MS Access for the sole purpose of making the columns sortable as a part of the MS Access filtering mechanism. I believe that it is the RMNOCASE problem that makes this necessary. The results of the SQLite query are not filterable and sortable after the fact, anyway. With the SQLite approach, all filtering and sorting has to be included in the body of the SQL. But MS Access supports filtering and supporting of the results of the query.
- SQLite requires COLLATE NOCASE for columns that are text strings in the first sub-query. This is a part of the RMNOCASE problem. If you run the inner SELECT as a free standing query rather than as sub-query, the COLLATE NOCASE is not required. I’m not sure of the proper language to describe the problem, but it’s like passing subroutine or function arguments work in some programming languages, and the RMNOCASE values from the inner SELECT cannot be passed out to the outer SELECT without first removing the RMNOCASE characteristic.
- In the second sub-query, MS Access uses StrConv to gain access to the content of a BLOB and SQLite uses CAST to gain access to the contents of a BLOB. MS Access uses double quotes, and SQLite uses single quotes. In MS Access, the LIKE operator won’t find my character strings unless I precede and follow them with * as a wild card character, and SQLite won’t work with the * as a part of the string.
- MS Access returns -1 for true and 0 for false on a compare. SQLite returns 1 for true and 0 for false. So with MS Access I used absolute value to convert -1 to 1.
- The maximum function (the name of the function is MAX) is used in association with the GROUP BY operator to allow PrgraphOk and CensusOk to be specified on the same or different Reference Number facts. And in association with the fact that the two sub-queries are connected with a LEFT JOIN, the query works correctly, showing blanks for the PrgraphOk and CensusOk fields for everybody in the group even when the Reference Number fact is omitted completely.
- I would much prefer to show blanks for “not completed” and an X for “completed”, rather than 0 and 1. But I couldn’t find any way to do so that would work for both MS Access and for SQLite. The basic problem is that MS Access doesn’t seem to support CASE or anything like CASE. There are numerous examples of CASE on the Internet for MS Access, but I couldn’t get any of them to work.
- I hard coded the Reference Number fact as fact #35 for the same reason I hard coded my group as group #6.
- This problem is pretty subtle, but it drove me crazy for a long time. I would have preferred not having text columns such as Surname and Given appearing in sub-queries at all, given the RMNOCASE and other problems with text columns. I would have preferred just having the text columns appearing as a part of the very original SELECT. And indeed, there is nothing in the sub-queries that needs any text columns. But keeping Surname and Given only in the main SELECT would have meant a three way JOIN (something JOIN something else JOIN still something else) rather than a two way JOIN because I would have had to JOIN the NameTable with the two sub-queries. But the MS Access way of doing JOINS of three items or more is very different than the SQLite way of doing JOINS of three items or more. Both MS Access and SQLite will only associate multiple JOINS from the left. So far, so good. But MS Access insists that the multiple JOINS include appropriate parentheses, even though there is only one way it will allow the parentheses to be placed – namely the placement of the parentheses must correspond to associating the multiple JOINS from the left. And SQLite insists that the parentheses not be there. (By associating from the left, in math the equivalent is (x+y)+z for the left and x+(y+z) for the right). If that’s all there was to it, I would probably just add and remove the parentheses as required in switching back and forth between MS Access and SQLite. But when you add and remove the parentheses to reflect the left-to-right association of the JOIN’s as being explicit with parentheses vs. implicit without the parentheses, the physical placement of the ON clauses also has to change. So I’m trying to formulate all my queries not to require more than one JOIN of two items within any particular query or sub-query. For this particular query, the only way I could think of to do so was to have text columns in one of the sub-queries that got passed back out to the main query. Oh, the joys of SQL standards (not!).
Here’s the way my report looks at the present time in MS Access. The report looks substantially the same with an SQLite manager such as SQLiteSpy.
Jerry

Added 7/29/2011
Here is a slightly modified version of the query for MS Access. It uses the IIF function to convert the 1’s and 0’s into X’s and blanks. IIF is another one of those non-standard MS Access features that make it difficult to create a query compatible between various versions of SQL. I’ve also added additional individuals to the named group for the list of individuals of active research interest, and I’ve added additional columns. I’ve been calling the columns a “to do list”, but I think that it would be more appropriate to call them a checklist.
SELECT
L.RecNo AS RecNo,
LEFT(L.Surname,50) AS Surname,
LEFT(L.Given,50) AS Given,
R.PrgraphOK AS PrgraphOK,
R.CensusOk AS CensusOk,
R.ObitOk AS ObitOk,
R.SourceOk AS SourceOk,
R.TombStoneOk AS TombStoneOk,
R.SSDI_Ok AS SSDI_Ok
FROM
(
SELECT
N.OwnerID AS RecNo,
N.Surname AS Surname,
N.Given AS Given
FROM
GroupTable AS G,
NameTable AS N
WHERE N.NameType=0 AND N.OwnerID>=G.StartID AND N.OwnerID<=G.EndID AND G.GroupID=6
) AS L
LEFT JOIN
(
SELECT
E.OwnerID AS RecNo,
IIF(MAX(Abs(StrConv(E.Details,64) LIKE "*PrgraphOk*"))=1," X",NULL) AS PrgraphOk,
IIF(MAX(Abs(StrConv(E.Details,64) LIKE "*CensusOk*"))=1," X",NULL) AS CensusOk,
IIF(MAX(Abs(StrConv(E.Details,64) LIKE "*ObitOk*"))=1," X",NULL) AS ObitOk,
IIF(MAX(Abs(StrConv(E.Details,64) LIKE "*SourceOk*"))=1," X",NULL) AS SourceOk,
IIF(MAX(Abs(StrConv(E.Details,64) LIKE "*TombstoneOk*"))=1," X",NULL) AS TombstoneOk,
IIF(MAX(Abs(StrConv(E.Details,64) LIKE "*SSDI_Ok*"))=1," X",NULL) AS SSDI_Ok
FROM
EventTable AS E
WHERE
E.EventType=35
GROUP BY
E.OwnerID
) AS R ON L.RecNo = R.RecNo
ORDER BY L.Surname, L.Given
Here’s a screen shot of the query when it is run against my live RM4 database.

thejerrybryan
19 June 2013 01:22:18
Thanks for the update. The newest version appears to be 1.9.3. However, I seem to have created a problem for myself. Namely, there is something wrong with RMNOCASE and SourceTable. Something so simple as “SELECT SourceID from SourceTable” throws the RMNOCASE error, and SourceID is a numeric field. I can’t even double click on the SourceTable just to view the whole thing. It appears to be the case that SourceTable is the only table with this problem.
Jerry
thejerrybryan
19 June 2013 01:25:24
SELECT * FROM SourceTable does work, however.
ve3meo
19 June 2013 02:27:25
This does not make sense – something is royally screwed up. Even a SELECT of a field defined with the RMNOCASE collation should not throw the error unless it is sorted. And under Options > Options > Extensions, do you have RMNOCASE_fake-SQLiteSpy.dll? If so, then there should be no such errors on any RMNOCASE defined field. In SQLiteSpy, run REINDEX and see if that clears the problem. When you return to RootsMagic, use its Rebuild Indexes tool before resuming normal operations.
Tom
thejerrybryan
19 June 2013 03:17:48
I hadn’t applied the fake RMNOCASE since I upgraded to 1.9.3. I have now done so, and the problem is solved. But as you say, there should be no error unless something is sorted. It’s almost like 1.9.3 is sorting something behind the scenes that we don’t know about. And the error is thrown even if I explicitly override the collation with NOCASE.
Also, I was wrong about it being just SourceTable. The error also occurs in AddressTable, MediaLinkTable, ResearchTable, and SourceTemplateTable. These are tables I never run queries against, so the problem could have been there forever. And I didn’t even try to run against SourceTable after I realized that INSTR wouldn’t work with my current version of SQLiteSpy.
If you have 1.9.3, you might try temporarily taking away the fake RMNOCASE collation to see if you also have the problem. Indeed, if you widen the window pane that contains the list of tables on the left side of the screen, the tables in question all have an error message beside them. You don’t even have to run a query or double click one of the tables to see the problem.
After removing the fake RMNOCASE collation, you will have to shut down SQLiteSpy and restart it to see the effect, and vice versa when you put it back.
Jerry
thejerrybryan
19 June 2013 03:43:58
On a lark, I restored 1.9.0. It does not have the RMNOCASE problem when the fake RMNOCASE collation is not installed. Which is to say you can access all the tables if you don’t sort. Without the fake RMNOCASE collation, you obviously have to do something to deal with RMNOCASE if you do sort. But the problem I’m describing was definitely introduced sometime between 1.9.0 and 1.9.3.
Jerry
ve3meo
19 June 2013 03:56:06
Too late for me now to do the testing you suggest. Between SQLiteSpy 1.9.0 and 1.9.3, SQLite itself has changed and I would suspect the problem or effect of a missing collation lies there. That should also manifest itself in the DOS executable of SQLite.
ve3meo
19 June 2013 14:13:26
The behaviour you describe is now inherent in SQLite itself (I see it in the Windows command line shell) and is not the fault of SQLiteSpy. ‘Why’ is a mystery but it may have something to do with query optimisation or auto-indexing. Or maybe it is an unwarranted bug.
thejerrybryan
19 June 2013 18:27:12
So I guess the fake RMNOCASE collation is now the only RMNOCASE solution for those tables that have the problem I’m describing. Even explicitly overriding the collation in a query does not take care of the problem. So I’ll probably just go with the fake RMNOCASE from now on and not even try to influence collation explicitly in my queries.
Jerry
ve3meo
19 June 2013 18:42:24
And don’t update your odbc connection between Access and SQLite databases. Even though a later version might resolve some issues, maybe it will be unusable. I’m now pretty sure this problem has to do with SQLite’s query optimiser trying to use an Index that is on a field having the RMNOCASE collation. I don’t see any way of turning off the optimiser. Dropping the index might clear that problem but introduce others such as loss of speed and the need to regenerate the index for ongoing use by RootsMagic.
Tom
thejerrybryan
19 June 2013 19:58:07
I had wondered what might happen with ODBC and Access. So far, nothing bad has happened to me.
It is the case that Access suffers from the RMNOCASE problem just like SQLiteSpy does. There not being a fake RMNOCASE solution available to Access, the trick that has worked for me 100% of the time is to substring out any RMNOCASE field that I need to sort on, and do the “substring out” thing in a subquery that passes the substring up to the next higher level of subquery. The substring operation I perform makes a “substring” of the whole field without dropping any characters.
There is more information about this issue with RMNOCASE and Access elsewhere in the Wiki. Because of the nature of Access, it’s often the case that your query does not actually need to sort directly on one of the RMNOCASE fields. But you will still want to use a trick to make the field sortable anyway. That’s because of the visual nature of Access where you can click on the column headers of the result of a query and sort by that column even though the column wasn’t sorted in the original query. The ability to sort in this fashion is lost unless you suppress the RMNOCASE problem.
Jerry
ve3meo
21 June 2013 03:28:46
I rejoined the sqlite-users list and posted the problem. I have had replies from both D. Richard Hipp, lead developer of SQLite, and Ralf Junker, developer of SQLiteSpy. I have a better understanding of what’s going on, a partial work-around but concluding that any recent SQLite manager must have at least the fake RMNOCASE collation for it to be able to use any of the queries and scripts developed for the RootsMagic4+ databases. Now if only Bruce would reveal the real RMNOCASE (are you reading this, Bruce?). The discussion begins at [sqlite] False Error ‘no such collation sequence’ http://sqlite.org:8080/cgi-bin/mailman/private/sqlite-users/2013-June/046965.html
Tom
ve3meo
21 June 2013 03:36:20
The current version of the ODBC driver from http://www.ch-werner.de/sqliteodbc/ wraps the (current) SQLIte 3.7.17 library. Since the command line version sqlite3.exe is built from 3.7.17 and exhibits the same problems as SQLiteSpy 1.9.3, built from 3.7.16.1, I would not be surprised if the current ODBC introduced some sort of problem in your MS Access interface.
Tom