• Inner Harbour Software

    Inner Harbour Software consists of a dedicated team of .Net programmers whose mission is to create exceptional and affordable HL7 products. Please email us at support@HL7Spy.com to contact us with questions regarding our products or services.

Q&A

Code Snippets, FAQs and Prodduct Support

How do I remove PR1 segments?

Question:
Let’s say that I have a particular interface that is shipping me bad PR1 transactions, which is killing my interface. The vendor on the other side can’t make a change to his interface just yet, and I want to drop all those bad PR1s and let the vendor catch them up for me at a later date when he’s cleaned his data up. Is there a function that deals with including or deleting particular segments?

Answer:
If you create a new Custom Function and paste this code in, load up some messages with PR1 segments, and press “Run”, the PR1 segments will get stripped out.

 public override void Run()
 {
    // Get an HL7 Message in parsed format
    Hl7Message message = GetParsedMessage();
    // remove any segment with name PR1"
    message.RemoveAll(s=>s.SegmentName=="PR1");
    // save the message into an new tab called No PR1s
    SaveMessage(message, "NO PR1s");
 }

Capture EVN-1, PID-3, PV1-2, FT1-2 to file

Question:
How can I capture a list of the following fields: EVN-1, PID-3, PV1-2, FT1-2 in a comma delimited list?
Answer:
Custom code is the best approach if you are expecting repeated FT1 segments. The following code will create a file in the c:\temp directory containing the specified list, and will display in Notepad upon completion.

string _fileName = @"c:\temp\_test.txt";
StreamWriter _file;

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  // Get the first FT1 segment
  EVN evn = message.Segments.OfType<EVN>().FirstOrDefault();
  PID pid = message.Segments.OfType<PID>().FirstOrDefault();
  PV1 pv1 = message.Segments.OfType<PV1>().FirstOrDefault();
  foreach(FT1 ft1 in message.Segments.OfType<FT1>())
  {
    _file.Write("{0},",evn != null ? evn.EventTypeCode_01.Value : null);
    _file.Write("{0},",pid != null ? pid.PatientIdentifierList_03.First.Value : null);
    _file.Write("{0},",pv1 != null ? pv1.PatientClass_02.Value : null);
    _file.Write("{0},",ft1 != null ? ft1.TransactionID_02.Value : null);
    _file.WriteLine();
  }
}

public override void OnStart()
{
  // create the file to be written out
  _file = new StreamWriter(_fileName,false);
  _file.WriteLine("EVN_EVENT_TYPE, PID_MRN, PV1_PATIENTCLAS", "FT1_TRANS_ID");
}

// Called once after the last message has been processed.
// It is a good place to perform cleanup and to report information.
// Always called from the UI thread.
public override void OnFinish() {
  // sort the data
  _file.Close();
  // launch notepad to display the file.
  System.Diagnostics.Process.Start("Notepad",_fileName);
}

Messages with duplicate OBR-3.1 to a new tab

Question:
I’m looking the way to get “DISTINCT” OBR-3.1 value messages. How can I do this in custom code. I want to show any messages that have duplicate OBR-3.1 values to a new tab. Please note we have multiple OBR segments per message.

Answer:
The following code should do the trick.

private class TrackedItem
{
   public List<IMessageData> Messages=new List<IMessageData>();
   public int Index {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);

public override void OnStart() {
  _knownValues.Clear();
}

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  OBR obr = message.Segments.First<OBR>();
  if(obr != null && !string.IsNullOrEmpty(obr.FillerOrderNumber_03.Value))
  {
    string obrIdentifier = obr.FillerOrderNumber_03.Value;
    TrackedItem item;
    if(!_knownValues.TryGetValue(obrIdentifier,out item))
    {
       item = new TrackedItem();
       _knownValues.Add(obrIdentifier,item);
    } else
    {
       Log(Severity.Informational,string.Format("duplicates found at index",MessageIndex));
       if(item.Index==0)
        item.Index = MessageIndex;
    }
    item.Messages.Add(Message);
  }
}

public override void OnFinish() {
  var list = _knownValues.Values.Where(i=>i.Messages.Count>1).ToList();
  Log(Severity.Informational,string.Format("{0} duplicates found",list.Count));
  foreach(TrackedItem item in list)
  {
    SaveMessage(item.Messages,"Duplicates");
  }
}

How do I create test data from a set of messages?

Question:
I would like to book some of you and or your teams time to develop or enhance HL7spy custom codes or product for my team. We would like the custom code to do the following:

  1. Take HL7 transactions (loaded in the Query Results tab)
  2. Append “-” + OBR-2.1 … to OBR-3.1 + “-” + some variable, ‘date yyyymmdd’
  3. Append “-” + some variable like “TEST” to OBR-3.2
  4. Delete the contents of OBR-2

Answer:
No need to hire us. This is pretty easy to do. There are two ways of accomplishing this: using type safe classes, and using field position specifications. Type safe classes provide the benefit of automatically documenting the code.

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  string today=DateTime.Today.ToString("yyyyMMdd");
  // loop through all the OBR segments in the message
  foreach(OBR obr in message.GetSegments<OBR>())
  {
    //(2) Append "-" + OBR-2.1 ... to OBR-3.1 + "-" + some variable, 'date yyyymmdd'
    obr.FillerOrderNumber_03.EntityIdentifier_01.Value = obr.PlacerOrderNumber_02.EntityIdentifier_01.Value + "-V" + today; 
    //(3) Append "-" + some variable like "TEST" to OBR-3.2
    obr.FillerOrderNumber_03.NamespaceID_02.Value = obr.FillerOrderNumber_03.NamespaceID_02.Value + "-TEST";
    //(4) Delete the contents of OBR-2
    obr.PlacerOrderNumber_02.Value = "";
    // save the message out to a new tab
    SaveMessage(message, "Modified Messages");
  }
}
public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  string today=DateTime.Today.ToString("yyyyMMdd");
  foreach(OBR obr in message.GetSegments<OBR>())
  {
    //(2) Append "-" + OBR-2.1 ... to OBR-3.1 + "-" + some variable, 'date yyyymmdd'
    obr[3,1,1] = obr[2,1,1] + "-V" + today;
    //(3) Append "-" + some variable like "TEST" to OBR-3.2
    obr[3,1,2] = obr[3,1,2] + "-TEST";
    //(4) Delete the contents of OBR-2
    obr[2] = "";
    // save the message out to a new tab
    SaveMessage(message, "Modified Messages");
  }
}

Find all unique OBX-3/OBR-3 values

Question:
Hi, I am using HL7Spy HL7 SQL for the first time and am trying to pull the values stored in obx-3.1.1 for repeating obx segments but it seems to be only pulling the first value. I thought that this query would accomplish what I needed but I do not believe it is.

SELECT OBx[*]-3.1.1,OBx[*]-3.2.1 WHERE OBx[*]-3.1.1 IS NOT NULL

I would also like to find all unique OBR-4 values too.

Answer:

The HL7 SQL function will only return one result per message, so it probably not what you are looking for.

It would be quite easy to write a Custom Function to do what you are looking for. Is your goal to get a list of OBX-3.1, OBX-3.2 pairs with perhaps a count of how many times each pair occurred? If so, here is some code that will do just that.

private class TrackedItem
{
   public string Key {get; set;}
   public string Value {get;set;}
   public int Counter {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);


public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  foreach(OBX obx in message.Segments.OfType<OBX>())
  {  
    string key = obx.ObservationIdentifier_03.Identifier_01.Value;   
    TrackedItem item;
    if(!_knownValues.TryGetValue(key,out item))
    {
       item = new TrackedItem {Key=key, Value=obx.ObservationIdentifier_03.Text_02.Value};
       _knownValues.Add(key,item);
    }
    item.Counter = item.Counter + 1;
  }
}

private string _fileName = @"C:\temp\_test.txt";
public override void OnFinish() {
  using(var stream = new System.IO.StreamWriter(_fileName))
  {
    stream.WriteLine("OBX-3.1, OBX-3.2, Count");
    foreach(TrackedItem item in _knownValues.Values.OrderByDescending(i=>i.Counter))
    {
      stream.Write(item.Key);    
      stream.Write("\t");
      stream.Write(item.Value);
      stream.Write("\t");
      stream.WriteLine(item.Counter.ToString());
    }
  }
 
  try{
    System.Diagnostics.Process.Start("Notepad",_fileName);
  } catch{}
}

And, a variation on the same theme for OBR-4

private class TrackedItem
{
   public string Key {get; set;}
   public string Value {get;set;}
   public int Counter {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  foreach(OBR obr in message.Segments.OfType<OBR>())
  {  
    string key = obr.universalServiceIdentifier_04.Identifier_01.Value;   
    TrackedItem item;
    if(!_knownValues.TryGetValue(key,out item))
    {
       item = new TrackedItem {Key=key, Value=obr.UniversalServiceIdentifier_04.Text_02.Value};
       _knownValues.Add(key,item);
    }
    item.Counter = item.Counter + 1;
  }
}

private string _fileName = @"C:\temp\_test.txt";
public override void OnFinish() {
  using(var stream = new System.IO.StreamWriter(_fileName))
  {
    stream.WriteLine("OBR-4.1, OBR-4.2, Count");
    foreach(TrackedItem item in _knownValues.Values.OrderByDescending(i=>i.Counter))
    {
      stream.Write(item.Key);    
      stream.Write("\t");
      stream.Write(item.Value);
      stream.Write("\t");
      stream.WriteLine(item.Counter.ToString());
    }
  }

  try{
    System.Diagnostics.Process.Start("Notepad",_fileName);
  } catch{}
}

Find all Unique OBR-4 – OBX-3 pairs in a message stream

Question:
Here is some custom code that you wrote for as a while back. The code exports a row for every unique OBR 4 and OBX 3 pair, and a count of the occurrences. This report is used by our lab mappers during the mapping process for a new laboratory. The lab mappers are requesting that the report contain additional information. Below is what they are requesting, with the more important item on top:

Include a full message with each OBR 4 – OBX 3 pair. It could be the 1st message for this pair, the last message for this pair, or any other message for this pair. Which message isn’t as import as actually having a message that contains the OBR 4 – OBX 3 pair. They plan to visually review this message as they are doing the mapping to resolve any issues with method, units, reference range, etc.

Include a list of OBR 4 terms only without any OBX information. They plan to use this for mapping the OBR 4 term, which we do for radiology and text reports.

Answer:
The following code will create a

private class TrackedItem
{
   public string Value {get;set;}
   public int Counter {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);
private string _fileName = @"C:\temp\data.hl7";

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  foreach(OBX obx in message.GetSegments<OBX>())
  {
    string obrIdentifier = message["OBR-4.1.1"];
    string obxIdentifier = obx.ObservationIdentifier_03.Identifier_01.Value;
    string key = (obrIdentifier + "-" + obxIdentifier).Trim();
    TrackedItem item;
    if(key=="-")
      continue;
    
    if(!_knownValues.TryGetValue(key,out item))
    {
       item = new TrackedItem();
       item.Value = string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}",message["OBR-4.1"],message["OBR-4.2"],message["OBR-4.3"],obx.ObservationIdentifier_03.Identifier_01, obx.ObservationIdentifier_03.Text_02, obx.ObservationIdentifier_03.NameOfCodingSystem_03,obx.Units_06,obx.ReferencesRange_07);
       _knownValues.Add(key,item);
    }
    item.Counter = item.Counter + 1;
  }
}

public override void OnFinish() {
  using(var stream = new System.IO.StreamWriter(_fileName))
  {
    foreach(TrackedItem item in _knownValues.Values.OrderByDescending(i=>i.Counter))
    {
      stream.Write(item.Counter.ToString());
      stream.Write("|");
      stream.WriteLine(item.Value);
    }
  }
  
  try{
   // System.Diagnostics.Process.Start("Notepad",_fileName);
  } catch{}
}

Find all CPT codes for each patient

Question:
What I want to do is for each of the three accounts contained in PID-18, show all PR1-3 fields for all PR1 segments. Typically, these are sequential segments, e.g., PR1|1…, PR1|2…, etc. The purpose is to generate a list of all procedure and CPT codes for each of the patients.

Answer:
please try the following code:

make sure you can access the c:\temp directory, that is where the file is being stored.

To narrow the search, use HL7 SQL to filter for the patient accounts you are interested in, into a separate tab (SELECT INTO).

or, modify the _patientAccount list below to include the patients you want included, and uncomment the code with the // (1) “Uncomment me” comment

string _fileName = @"c:\temp\_test.txt";
private StreamWriter _writer;

// patient Identifiers
private string[] _patientAccounts = new string[]{"952-11-3088", "H000759100", "H000759092", "H000759118"};

public override void OnStart() {
  _writer = new StreamWriter(_fileName);
}

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
 
  PID pid = message.Segments.First<PID>();
  if(pid==null)
    return; // no pid segment
 
  // (1) Uncomment me
  //if(!_patientAccounts.Contains(pid[18,1,1]))
  //  return;
   
  foreach(var pr1 in message.Segments.OfType<PR1>())
  {
    if(pr1[3]!="")
    {
    _writer.WriteLine("{0},{1},{2},{3},{4},{5}",this.MessageIndex, pid[18], message.MSH[7], message.MSH[10], pid[5], pr1[3]);
    }
  }
}

// Called once after the last message has been processed.
// It is a good place to perform cleanup and to report information.
// Always called from the UI thread.
public override void OnFinish()
{
  if(_writer!=null)
  {
    _writer.Close();
    _writer = null;
  }
  // launch notepad to display the file.
  System.Diagnostics.Process.Start("Notepad",_fileName);
}
  • Page 2 of 2
  • 1
  • 2