I've noticed a few examples of MEL code that uses functions like getrow() and getrowcount() , which is similar to SQL query functions in Java and PHP. However, I don't see any help info on using these functions in Centricity. Anyone have some solid experience querying databases using these functions, or know where I could go to learn more?
I have never found a place that documents these, but I use them quite a bit and can try to share what i have figured out.
Both functions along with the find() function are great for writing custom functions. They query objects that GE defines seperately from the sql tables, the names and defintions are in the mldefs.txt files in the client folder. One of the most difficult parts about writing these functions is choosing the correct object. I dont really have any great advice for choosing these, you will just have to read the descriptions and try to figure out which one best fits your needs.
GETROWCOUNT() takes a single argument, which has to be the name of an object defined in meldefs, it is used to determine the size of a loop for the getrow function
GETROW() requires at least three arguments, I don't believe there is a maximum. The first argument is the object name, the second is the row number (usually i for the loop) and then every other argument is a field or formula name in the object
find() is defined in the data symbols reference, for these functions we will use the four argument version.
Examples:
local a = GETROWCOUNT("_MasterRx")
a is now a number representing the number of items in the object named "_MasterRx", this object is defined in mldefs.txt and is a subset of the PRESCRIB table
for i = 0, i < a, i = i + 1 do
b = getrow("_MasterRx",i,"MID","Quantity","Refills")
//Do something here
endfor
b is now an array with three elements, MID, Quantity, and Refills, representing a row i in the object "_MasterRx"
the for loop will return an array for every row in this object.
find("_MasterMed","Description","MID",b[1])
Find is used to link objects together. This find statement reads find in the mastermed object the description field where the MID is equal to the first element of the MasterRx array (which we defined as the MID).
So putting it together -
{fn Custom_Med_Array(){
local a = GETROWCOUNT("_MasterRx")
local b = ""
local result = ""
for i = 0, i < a, i = i + 1 do
b = getrow("_MasterRx",i,"MID","Quantity","Refills")
if result <> "" then
result = result + "|"
endif
result = result + find("_MasterMed","Description","MID",b[1]) + "^" + find("_MasterMed","Instructions","MID",b[1]) + "^" + b[3] + "^" + b[4]
endfor
return result
}}
So this example counts the rows, loops through each row collecting MID, Quantity, and Refills, uses the MID to find the description and instructions for each med, and then puts in into string delimited by carrots and pipes that you could use for something else, the formatting is ultimately up you. Hope this helps
Mike
This is a great write-up, Mike!
Do you (or anyone) happen to know how to create new objects? I've had times where the objects in the mldef files didn't have what I needed. A step by step process for creating these would be helpful.
I do not know how to create objects or fields, I saw it mentioned in thread earlier though. I would like to add med class code somewhere that I can access it, but I havent found an object that has it.
Functions utilizing getrow() are more fragile than the built in GE functions, because we have to maintain them as we upgrade. For vendors operating over multiple platforms I can see where this can cause a headache. If you try to pass a field that doesn't exist in a certain version, getrow() will return nothing at all. If you were determined to use it as a vendor you could use this function VER_EMR() and conditional statements to control for different database structures.
That said all of my practices are on the same version. We use a usrlib file to store all of the general or shared functions, including all of the getrow functions, keeping them in one place makes it easier to test them all when upgrading. We have only been on CPS (previously had just PM) for a year and half, but I have not had any issues with these functions.
Mike, thanks for explaining this! Super helpful.
You said you store all your general functions in a userlib. When I've tried storing functions in our userlib and then try access them from forms, I have zero luck. When I place functions in mellib, however, no problem. What's the secret? Is the formatting different?
Thanks again!
It has to named usrlib.txt and placed in the client folder to open. Centricity reads it when you launch the chart.
Right. I confirmed that usrlib.txt is located in my client folder. Functions are still not working when called in the chart, but they do when I place then in mellib.txt (also in client folder).
Wierd, right?
Do I need to wrap my functions in "{}" ? My function definitions are not enclosed in braces, but their arguments are. example of how they look now in mellib.txt:
fn fnTest(anyArgsHere){more stuff here}
Currently, this is all that's in my usrlib.txt and the formatting looks different:
// CLINICFOLDERNAME Clinic userlib.txt // Network path fn ccc_net_path() {DIR_EMR()} // Path for system files: fn ccc_sys_path() {"R:\CCC"} load("R:\usrlibccc-V8.txt") // Path for supplemental folder: fn supplement_path() {"R:\CLINICFOLDERNAME"} /* 9-11-06 */ load(supplement_path() + "\CCC-fndef-Load-supplemental.ccc")
any ideas, Mike?
The problem may be with the path you chose. I tried to set up my load functions to access a centrally located path but I never figured out how to make it work, so anytime we need to update the files we have to manually copy it to the Thin client servers (which isn't too bad because we only have a few servers, if you run thick client you might look into jobs.txt but I have no experience with that process). The load files I use look like
load(".\\fnutility.txt")
meaning look in the client folder for the file name fnutility.txt
You could drop them in a subfolder of client using this method but I do not think load will allow you to use a seperate directory.
don't use a "mapped" drive name; it could be different client to client. Use a "hard" network path eg:
////////////////
// DO NOT EDIT THIS !!!
//
load("\\opemrdev\Logician\XXXX\my_fn_lib.txt")
load("\\opemrdev\Logician\XXXX\my_global_lib.txt")
//load("\\opemrdev\Logician\XXXX\extra.txt")
//
////////////////
we have used this strategy for years without problems. You don't need a fn or anything.
RE the getrow() question, you can't create an object. The objects are all defined in the mellib files. Look in the mellib.txt and there are a list of objects that are "globalized" and "safe" to access. You should be OK creating custom fns here. We have done many.
for the other objects, it's strictly trial and error. If you think that the object has something you might use, first try getrowcount() with that object of interest as the argument. If it returns a number that is about what you'd expect, then start trying fields as defined in the mellib*.txt file in to a getrow() command. Use some of the programming in the mellib.txt as example. Do these initially in quicktext until you figure out what you are getting, then build an array and work it like any other data element.
the editor keeps removing my whacks. For some reason here you need to escape each whack so that instead of 2 leading whacks you need four, etc. \\\\ instead of \\. \\ instead of \