Pulling data from a different db into a Text List

I am wanting to pull in selected records from a 2nd databse into a Text List in the primary database. In the Query Box for the Text List Options on the1st db, I am thinking that a ««LocationCode»» = «LocationCode» should work if the Database is set to the remote database. But nope. I was going to try
?(««LocationCode»» = «LocationCode»,ExportLine(),"")

A simple ExportLine() pulls in the current record as many times as there are records which makes sense but I want a specifc selection of record’s data.

Using the Relational Workshop, I can see the records and data that I want with the formula:
arraybuild(cr(),“Activity Log”,|||datepattern(Date,“MM/DD/YY”)+tab()+Time+tab()+User+tab()+Action+tab()+Purpose+tab()+Result+tab()+Unknown|||,|||««LocationCode»» = LocationCode|||)+ignore("",LocationCode)
but I can not see how to use that array as my datasource for the Text List. I haven’t been able to find anything in the Help with any example that would assist.

Text List objects do not support the double chevron syntax.

If you have set the Text List to scan another database, then all fields included in the query formula must be fields in the target database. You cannot directly reference fields in the current database. If you can get the values you want to search for into a variable, that would be one solution. Another would be to use the fieldvalue( function to peek back into the current database. (In fact, in situation where the double chevron syntax does work, Panorama actually converts the chevrons into a fieldvalue( function.)

fieldvalue("Primary Database","LocationCode") = LocationCode

I think you might be able to leave the database specification as "" instead of including the name of the current database, but I’m not 100% sure about that. Panorama might consider the database being scanned to be the target database at the time this formula is likely, in fact I think that is likely. So if that’s true, you will have to explicitly include the database name in the formula.

You could also use your arraybuild( formula. To do that, leave the Database and Query options blank, and put the formula into the Formula panel. You can use ANY formula as a data source for a Text List. The Database and Query options simply provide a convenient shortcut that makes the most common operations simpler to create.

1 Like

And the answer was…

Using the Relational Workshop to easily accomplish the arrayBuild that I already had and to simply empty the Database field.

I had imagined that the Database field needed to know where the source was. My arraryBuild did already indicate where the data was but I thought redundancy would be a good thing. I’m not really clear as to why the Database field needed to be empty for this to work, but alas, I am happy now.

This would be a convenient moment to perhaps suggest that Panorama X could assist the user when they are checking the ‘Database Navigator’ checkbox, that Panorama X is going to empty the Value entry (or perhaps ‘dim’ it.) That misleading item, and this hole where having to have the Database field empty for my needs to be achieved were not intuitive so anywhere that Panorama X can assist is always appreciated.

If the Database option is empty, the Text List simply evaluates the formula and displays the result.

If the Database option is not empty, the Text List scans the specified database, evaluating the formula once for each record in the specified database. An advantage of this method is that the Text List will update the display as the scan is in progress. If you use the arraybuild( method, the display will not update until the entire arraybuild( operation is complete.

Essentially, the Text List object has the arraybuild function built into it, and this is activated when you specify a database. The database, formula and query parameters of the arraybuild( statement correspond to the same options in the Text List object. However, there is one difference in that currently the Text List object does not support the double chevron trick.

Hearing that I might be able to get a faster result, I am going to put aside the fact that clearing the database does work. I really want to understand what is happening here.
I’ve re-entered the database name into the Database field. I’ve elminated the variable issue by hard coding the KeyData for the moment. The Query is now:

 lookupall("Activity Log",«LocationCode»,"OR:45426",«Result»,cr())

Because the Query is supposed to be running this for every record in the Activity db, I am expecting that I will only get 1 record back as there is only 1 record with the LocationCode of ‘OR:45426’ in the Activity db.
But I am now back to getting the correct data, repeated as many times as there are records in the database.

If LookupAll is acceptable for speed, I’ll actually use the very cool, LookupAllSextet( to get the 6 fields of data. :slight_smile:

How do I get just the single record only once using the Query box for maximum speed?

The query MUST be a formula that returns a true/false result. As I posted previously, based on your arraybuild( formula the query formula should be:

fieldvalue("Primary Database","LocationCode") = LocationCode

This will return TRUE for records in the “Activity Log” that have the same LocationCode as the current record in the database that contains the Text List (what I am calling the “primary database”). In my formula above, you need to change "Primary Database" to the actual name of the database that contains the Text List object. I would have put that in the code, but I don’t know the name of that database.

The Text List formula should be:

datepattern(Date,"MM/DD/YY")+tab()+Time+tab()+User+tab()+Action+tab()+Purpose+tab()+Result+tab()+Unknown

How do I know that is the formula? I got it from your arraybuild( formula in your first post!

For the future, I have added the lack of double chevron support in the Query formula to the issue tracker.

1 Like

The FieldValue is a wonderful answer for my needs.

I am not finding that the Construct List/Matrix option nor the ConstructListMatrix command allows for me to create a Query tag.

I am not finding that the Text List Options panel allows for me to enter the necessary <Code:xxx> tag that I need.

I am currently having to use the ConstructListMatrix command, then editing it via the Text List Options panel to add the Query formula. Am I overlooking either of these items that I can not find?

I am not finding that the Construct List/Matrix option nor the ConstructListMatrix command allows for me to create a Query tag.

You don’t set up the query tag directly using the Constructor. Instead you specify one or more searchable columns.

Of course there are possible searches you might want to set up that are more advanced than this. In that case, you have to set up the query manually, as you have been doing. The Constructor is intended as a shortcut to assist with the most common situations, not as an all inclusive alternate user interface for specifying any possible object.

I am not finding that the Text List Options panel allows for me to enter the necessary Code:xxx tag that I need.

Tags are only for the Constructor dialog. They are not used in the options panel itself.

When you do use the code tag, that allows you to set up the code that is associated with that object. When setting this up manually, the code is not in the Text List Options panel, it’s in the Code panel, just like any other graphic object.

Perhaps my needs are atypical?

I need the Query tag to declare the records that should be pulled from database B into the Text List. There are 80,000 records in database B and I only want to view those that are related to the single record that I am viewing in database A. There is no searching. It would be handy for the constructor to have a Query tag. The ConstructListMatrix also does not offer a Query option. I can understand that the Constructor dialog may not be able to do everything but certainly the ConstructListMatrix can offer that option.

My Query code:

IDNumber=FieldValue("100-Patients",«IDNumber»)

I can understand that the Constructor dialog may not be able to do everything but certainly the ConstructListMatrix can offer that option.

The only reason the ConstructListMatrix option exists is to be the back end for the Constructor dialog.

I’ll repeat - the purpose of these features is for an “EZ builder” for creation and layout of basic forms. It was always intended that for most applications you would start with a constructor dialog to save time getting started, and then customize from there.

Also, keep in mind that the constructor dialogs/statements are different from blueprints. Blueprints are feature complete, and include every single detailed option for every type of option (including the query formula). But blueprints aren’t designed to by “easy” - rather, they are to provide a complete textual specification of a form object, and for that matter an entire form, or even an entire database.

In addition, all object properties (including the query formula) can be dynamically accessed with the objectinfo( function and changed with the changeobject and changeobjects statement. In other words, you can access and modify the query formula (and anything else) on the fly in a procedure. This is completely independent from the constructor mechanism (though under the hood, these statements are how the constructor mechanism works).

I appreciate your time. Given that we are not able to have both the Data Sheet open while also having a Text List open, my first thought was to create the Text List ‘on demand’ with the ConstructListMatrix command (and then later deleting it) but the lack of creating the requisite Query through the use of that tool stopped that design path. Perhap I could create the Text List, then via Blueprint manipulation, add the Query and then refresh the Text List, or perhaps creating the Text List all via a Blueprint but all of this got too crazy so I gave up that path.

Down another path, I am finding that if I have multiple remote db records listed in my Text List, that they are all collectively selected if I select any one of them. (The Allow Multiple Rows checkbox is not checked in the Clicks/Selection area of the Options panel.) If I then interrogate the value of the Selected Value, the first time I interrogate the variable, I get a single row of data. If I then interrogate the variable a 2nd or 3rd time, I get the correct multiple rows of data. What’s up with that?

I’m going to give you a two part answer. For the first part, I’ll assume that your “creating the Text List” on demand idea is necessary (it’s not, but I’ll save that for the second part).

There are two ways you could could construct this object on demand:

  1. using constructlistmatrix
  2. using newformobject

You want to pick #2, for 2 reasons. First, as you have surmised, constructlistmatrix doesn’t give you complete detailed control over the object being created. Only basic options are available.

But more importantly, #1 is significantly slower. It works by first parsing and analyzing the tags you give it, and then building a blueprint. It then uses newformobject to actually create the object.

So by picking #2, you are skipping the parsing/analyzing of tags and going straight to the newformobject phase. You get all the power/flexibility of newformobject, and without the performance penalty. Win/win. The performance penalty is not too bad if you do it once when laying out a form, but it will be onerous creating a form dynamically over and over.

The easy way to use newformobject is to first create the object (either manually and/or with a constructor), and then right click on it and view the Blueprint. Then copy the blueprint code - that’s exactly the code you need to create the object dynamically! You don’t have to write any code at all - just copy and paste it into your procedure. This is the method that you say “got too crazy” but it’s actually simple as pie. (Of course a simpler solution is to just close the form, and only open it when the data sheet is closed. But in the next section you’ll see neither of these techniques are necessary.)

Now let’s revisit your assumption that “we are not able to have both the Data Sheet open while also having a Text List open”. This statement is far too broad, you can certainly have both open under many circumstances. What you don’t want to do is have a Text List that duplicates the navigation function of the data sheet. In other words it displays the same data as the data sheet in that database (not another database), and when you click on the Text List, it navigates to the clicked record. When all those conditions are met you’ll get spinning beachballs because the data sheet and the Text List will “fight” each other over who has control of the navigation of the database. But that’s not the situation you have. I think it would be fine in your case to have both the Text List and the database open at the same time. (By the way, in the situation where it’s not fine, the solution is not to create the Text List on the fly - simply make sure that the data sheet and the form containing the Text List aren’t open at the same time.)

As for your new problem, I can’t really analyze that too closely because you haven’t provided any code. So I have no idea what “interrogate” means. But your list has duplicate entries, so of course there’s going to be weird behavior around selection. In this case I believe the Text List is actually operating on an array, not the second database directly (the array is built from the second database, but once the array is built the second database is not involved further - this is why it works ok with the data sheet). The array has duplicate values, there is no way to tell them apart. You need to devise a method to have all unique values - perhaps by including the appointment time, or some other unique component of each appointment. Right now your system could never work because you don’t have a 1:1 relationship between the items in the list and the records in database B. I’m assuming that Jaxon Allen really had 3 appointments on March 9, and there are three records for those appointments in database B. You need to pull in additional data into the text list to be able to make a unique key.

Note that Panorama’s relational features are of no use to you here. Panorama knows how to set up a relation between two databases - but not how to set up a relation between a database and an arbitrary Text List. That can be done - but it has to be done by you.

1 Like

As for interrogating the variable: In the ConstructListMatrix, I have 2 pertinent lines of code…

<code:Call "Select an Echo">
<selection:SelectedEcho>

In the procedure ‘Select an Echo’, it has a single line of code

 Message SelectedEcho

As for the multiple rows being selected when I clicked on one row, regardless of what data is in the row, the Text List should be relating to a row number. The ‘Allow Multiple Rows’ checkbox was not selected.

That’s about what I figured. It doesn’t change anything in my earlier response.

I think you may be imagining that there is some sort of magic link between the text list and the second database. But the way you are using it, there isn’t (and you are using it correctly for your application). There’s just a list of text items, and if you want to be able to do selection, that list must not contain any duplicate items.

If you have no other way to do it, you can use the internal record id to make a unique item. Take the formula you are using now to build the list, and add this suffix to it.

... existing formula ...+chr(0)+str(info("serverrecordid"))

The chr(0) function tells the text list not to display anything afterwards (I assume you don’t want the record ID to display).

Sorry but I thought I was done with this. ;-( Apparently Panorama X does AI !

When my second database enlarges to 76,141 records, hallucinations are happening. Records that do not exist and incorrect records start showing up in my Text List. In my screenshot below, the first 2 records do not exist, and the last record’s IDNumber is actually 150981.

My query is simple but the db being queried (“701-Echos”) is large in record size.

Is there anything I can do to resolve this? It only appears to happen with the larger dataset.

IDNumber=FieldValue("100-Patients",«IDNumber»)

Another attempt brought up different hallucinogens with an arraryBuild( formula showing correct information.

Panorama does not use AI, it does not “hallucinate”, but does use simple deterministic algorithms. You’re going to investigate this further and find that the records in question actually do exist, most likely you didn’t understand some edge case of how your selection formula actually interacted with your data. Also note that since whatever selection formula you are using operates on only one record at a time, it doesn’t matter if the database contains 1 record or a million.

I did a side by side comparison of Text List vs an ArrayBuild( and the Text List consistently is creating records that do not exist. I tried doing a selection of the Pt records in the searched db and thought that by using Info(“Visible“) that it might fix the situation but the phony records continued to display in the Text List. My formulas are the same in each object. Pull every record that has a matching IDNumber. At the bottom of the Text List I have it displaying the number of Selected Records in database B. That number is correct and the Text List is displaying more than those 32 records. The ArrayBuild( display is correctly only showing me 32 records. The Text List in some cases is displaying incorrectly selected records with their appropriate IDNumber that does not match the Query. There is no record with IDNumber 985824 on 11/14/2012 for Quiroz, Giovany and thus that is a hallucinogen.

IDNumber=FieldValue(“100-Patients”,«IDNumber») AND Info(“Visible”)
arraybuild("
","701-Echos","DatePattern(DtOfExam,'mm/dd/yyyy')","IDNumber=fieldValue('100-Patients',«IDNumber»)")

I‘ve found that the maximum number of records that I need to select from for any single Pt is 32. Using a tall form, I can display a fixed height list of the dates and put Invisible buttons on top of the dates. Then reading from Info(“Trigger’“) I can determine the date that the user selected. While I can get away from needing a scrolling list this time, in a few years I’ll be back hoping that this will have been fixed.

Robert, Panorama has ONE unified engine for scanning a database and determining which records match a formula. This same engine is used for selecting, finding, arraybuild, text lists, and anything else along these lines. These operations do not have separate code - they all use the exact same code to scan the database. So when you tell me you do a side-by-side comparison and get different results, that tells me that you are doing something different, even if we don’t know what it is. If you want to continue this conversation, we need to focus on what the difference could possibly be.

If I had the database here, I would try experimenting by simplifying as much as possible, and then trying to change one thing at a time. Since I don’t have it here, you’ll have to do that.

I would start by simplifying as far as possible. I would suggest that you try changing the Text List query formula to:

IDNumber = "985824"

If that works, then there is some problem with the use of the fieldvalue( function. Off the top of my head I can’t think of any reason why fieldvalue( would work differently in a Text List than in arraybuild(, but I think we need to rule this out.

Also, I’m wondering why you are using chevrons in the fieldvalue( function. It seems like that is working for you, but they certainly aren’t necessary. I think the best approach would be to use quotes, for example

IDNumber=FieldValue("100-Patients”,"IDNumber")

That makes it absolutely unequivocal that we are talking about a text string containing a field name, and not looking up the name from a variable named IDNumber. Though in the latter case I would expect it to always fail completely.

Using a tall form, I can display a fixed height list of the dates and put Invisible buttons on top of the dates. Then reading from Info(“Trigger’“) I can determine the date that the user selected.

This is a separate, different issue, right? Using invisible buttons sounds like a terrible idea. If you use a text list you can find out what row was clicked on. This eliminates a huge amount of setup work and also will work fine with scrolling.

Invisible buttons were a commonly needed tool in earlier versions of Panorama, so many long time Panorama developers tend to reach for them instinctively. But in a dozen years of Panorama X development, I’ve never needed to use an invisible button even once. If you’re thinking of using an invisible button, there is almost certainly a better approach if you give it a bit more thought.

I am using FieldValue( in both the Text List and also the ArrayBuild( as each of them must be doing the search in another db. Thus if it was a problem with FieldValue( that would show in each of the results.

I use the Chevrons because it is not supposed to matter and I later unequivocally always know that it is a field and not a variable.

I tried the fixed value in the Query of the Text List and the results continue to be incorrect.

Dropbox link for a gif of the incorrect results when using a fixed value in the Query.

Yes, Invisible Buttons are a terrible idea but I can not come up with a better alternative as the Text List is not working.