Encontrar

Artigo
· Ago. 15 3min de leitura

A beginner's guide to creating SQL tables and seeing them as classes

The August Article Bounty on the Global Masters article caught my attention, and one of the proposed topics sounded quite interesting in regard to its future use in my teaching. So, here's what I'd like to tell my students about tables in IRIS and how they correlate with the object model. 

First of all, InterSystems IRIS boasts a unified data model. This means that when you work with data, you are not locked into a single paradigm. The same data can be accessed and manipulated as a traditional SQL table, as a native object, or even as a multidimensional array (a global). It means that when you create an SQL table, IRIS automatically creates a corresponding object class. When you define an object class, IRIS automatically makes it available as an SQL table. The data itself is stored only once in IRIS's efficient multidimensional storage engine. The SQL engine and the object engine are simply different "lenses" to view and work with the same data.

First, let's look at the correlation between the relational model and the object model:

Relational Object
Table Class
Column Property
Row Object
Primary key Object Identifier

It's not always a 1:1 correlation, as you may have several tables represent one class, for example. But it's a general rule of thumb. 

In this article, I will discuss creating a table by listing its columns. 

The most basic approach:

CREATE TABLE [IF NOT EXISTS] table (
   column1 type1 [NOT NULL], 
   column2 type2 [UNIQUE], 
   column3 type3 [PRIMARY KEY]
   ...
   [CONSTRAINT fKeyName FOREIGN KEY (column) REFERENCES refTable (refColumn)]
)

[ ] designate the optional parts.

Let's create a table DC.PostType, which consists of three columns: TypeID(primary key), Name, and Description:

CREATE TABLE DC.PostType (
  TypeID        INT NOT NULL,
  Name          VARCHAR(20), 
  Description   VARCHAR(500),
  CONSTRAINT Type_PK PRIMARY KEY (TypeID)
)

As a result, we will get the following class after executing the SQL statement above:

/// 
Class DC.PostType Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {UnknownUser}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = PostType ]
{

Property TypeID As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ Required, SqlColumnNumber = 2 ];
Property Name As %Library.String(MAXLEN = 20) [ SqlColumnNumber = 3 ];
Property Description As %Library.String(MAXLEN = 500) [ SqlColumnNumber = 4 ];
Parameter USEEXTENTSET = 1;
/// Bitmap Extent Index auto-generated by DDL CREATE TABLE statement.  Do not edit the SqlName of this index.
Index DDLBEIndex [ Extent, SqlName = "%%DDLBEIndex", Type = bitmap ];
/// DDL Primary Key Specification
Index TypePK On TypeID [ PrimaryKey, SqlName = Type_PK, Type = index, Unique ];
Storage Default
{
<Data name="PostTypeDefaultData">
<Value name="1">
<Value>TypeID</Value>
</Value>
<Value name="2">
<Value>Name</Value>
</Value>
<Value name="3">
<Value>Description</Value>
</Value>
</Data>
<DataLocation>^B3xx.DXwO.1</DataLocation>
<DefaultData>PostTypeDefaultData</DefaultData>
<ExtentLocation>^B3xx.DXwO</ExtentLocation>
<IdFunction>sequence</IdFunction>
<IdLocation>^B3xx.DXwO.1</IdLocation>
<Index name="DDLBEIndex">
<Location>^B3xx.DXwO.2</Location>
</Index>
<Index name="IDKEY">
<Location>^B3xx.DXwO.1</Location>
</Index>
<Index name="TypePK">
<Location>^B3xx.DXwO.3</Location>
</Index>
<IndexLocation>^B3xx.DXwO.I</IndexLocation>
<StreamLocation>^B3xx.DXwO.S</StreamLocation>
<Type>%Storage.Persistent</Type>
}

}

Key Observations:

  • TABLE DC.PostType became Class DC.PostType.
  • The class Extends %Persistent, which is what tells IRIS to store its data in the database.
  • VARCHAR became %String.
  • INT became %Integer.
  • The PRIMARY KEY constraint created an Index with the PrimaryKey keyword.

You can now use this table/class from either side, for example, using SQL:

INSERT INTO DC.PostType (TypeID, Name, Description) VALUES (1, 'Question', 'Ask a question from the Community')

There's a lot more to creating tables using SQL, please read the documentation provided below.

7 Comments
Discussão (7)3
Entre ou crie uma conta para continuar
Anúncio
· Ago. 15

[Vidéo] HL7 FHIR et l’Espace Européen des Données de Santé, accélérateurs d’innovation au CHU de Toulouse

Salut la Communauté!

Profitez de regarder la nouvelle vidéo sur la chaîne Youtube d'InterSystems France :

📺 HL7 FHIR et l’Espace Européen des Données de Santé, accélérateurs d’innovation au CHU de Toulouse

Découvrez le retour d’expérience sur l’implémentation d’une plateforme FHIR au CHU de Toulouse :

  • Facilitation et accélération de l’intégration d’applications innovantes au service de la prise en charge des patients en mutualisant les interfaces
  • Réflexion et collaboration avec la communauté européenne Hospitals On FHIR pour implémenter l’EEDS/EHDS

Intervenants : 
🗣 Paul Ortega, Ingénieur Hospitalier FHIR, CHU Toulouse
🗣  Luc Chatty, Expert FHIR, Fondateur CEO de Fyrstain et Ambassadeur de la Communauté européenne Hospitals On FHIR en France
🗣  @Guillaume Rongier, Expert en plateforme de données, InterSystems France

Abonnez-vous à notre chaîne youtube pour plus de vidéos !

Discussão (0)0
Entre ou crie uma conta para continuar
Pergunta
· Ago. 14

Any Better Way to Strip the Fractions of Seconds from a Posix Time?

Is there a better way (i.e., without string commands) to remove the fractions of seconds from a %Library.PosixTime value?

This works, but seems inefficient:

set posix = 1154669852181849976
w ##class(%Library.PosixTime).LogicalToTimeStamp(posix)
2025-05-27 12:06:15.003
set str = ##class(%Library.PosixTime).LogicalToTimeStamp(posix)
set stripped = $P(str,".",1)
w ##class(%Library.PosixTime).TimeStampToLogical(stripped)
1154669852181846976
set newposix = ##class(%Library.PosixTime).TimeStampToLogical(stripped)
w ##class(%Library.PosixTime).LogicalToTimeStamp(newposix)
2025-05-27 12:06:15

Note that I don't need the last string output; the value stored in "newposix" is what I want to retain.

Thanks in advance

9 Comments
Discussão (9)3
Entre ou crie uma conta para continuar
Pergunta
· Ago. 14

ZenPage Table not Updating

Hi all,

I’m running into an issue with a %ZEN.Component.tablePane in a Zen page.

We have:

  • A fully styled table with all columns defined
  • A backend query (SearchMessages) that accepts multiple filter parameters
  • A set of input fields at the top of the page for filtering (text, date, and checkboxes)

We’re trying to run the query from a button click using a client-side method (runSearch()) that collects the filter values, sets them as parameters, and calls executeQuery().

The problem is that the table does not update at all. Old rows remain, or sometimes nothing appears. I am struggling to debug this issue and anyone with experience making zen tables and updating them using queries would be extremely helpful. Below is a bit of my code

<!-- Filters -->
    <hgroup id="filtersContainer">
      <group id="filter-group-documents">
        <text label="DocumentID:" id="filterDocumentID"/>
        <text label="DocumentSource:" id="filterDocumentSource"/>
      </group>
 
      <group id="filter-group-session-message">
        <text label="SessionID:" id="filterSessionID"/>
        <text label="MessageControlID:" id="filterMessageControlID"/>
      </group>
 
      <group id="filter-group-person-facility">
        <text label="PersonID:" id="filterPersonID"/>
        <text label="SourceFacility:" id="filterSourceFacility"/>
      </group>
 
      <group id="filter-group-event-encounter">
        <text label="EventType:" id="filterEventType"/>
        <text label="EncounterNumber:" id="filterEncounterNumber"/>
      </group>
 
      <group id="filter-group-message-date">
        <dateText label="Message Date From:" id="filterMessageDateFrom"/>
        <dateText label="Message Date To:" id="filterMessageDateTo"/>
      </group>
 
      <group id="filter-group-send-time">
        <dateText label="Send Time From:" id="filterSendTimeFrom"/>
        <dateText label="Send Time To:" id="filterSendTimeTo"/>
      </group>
 
    <!-- Active / Duplicate -->
    <group id="filter-group-checkboxes">
        <checkbox label="Is Active" id="filterIsActive"/>
        <checkbox label="Is Duplicate" id="filterIsDuplicate"/>
    </group>
 
    <!-- Last Update -->
    <group id="filter-group-last-update">
        <dateText label="Last Update From:" id="filterLastUpdateFrom"/>
        <dateText label="Last Update To:" id="filterLastUpdateTo"/>
    </group>
    <group id="filter-group-message-id">
        <text label="OriginalMessageID:" id="filterOriginalMessageID"/>
    </group>
    <group id="filter-group-search">
        <button caption="Search" onclick="zenPage.runSearch();"/>
    </group>
    </hgroup>
 
    <!-- Results Table -->
    <tablePane id="resultsTable"
               autoExecute="true"
               queryClass="MD.UI.MessageTrackingQuery"
               queryName="SearchMessages">
        <column colName="DocumentID" cellTitle="DocumentID" filterQuery="SearchMessages"/>
        <column colName="DocumentSource" cellTitle="DocumentSource" filterQuery="SearchMessages"/>
        <column colName="SessionID" cellTitle="SessionID" filterQuery="SearchMessages"/>
        <column colName="MessageControlID" cellTitle="MessageControlID" filterQuery="SearchMessages"/>
        <column colName="PersonID" cellTitle="PersonID" filterQuery="SearchMessages"/>
        <column colName="SourceFacility" cellTitle="SourceFacility" filterQuery="SearchMessages"/>
        <column colName="EventType" cellTitle="EventType" filterQuery="SearchMessages"/>
        <column colName="EncounterNumber" cellTitle="EncounterNumber" filterQuery="SearchMessages"/>
        <column colName="MessageDate" cellTitle="MessageDate" filterQuery="SearchMessages"/>
        <column colName="SendTime" cellTitle="SendTime" filterQuery="SearchMessages"/>
        <column colName="IsActive" cellTitle="IsActive" filterQuery="SearchMessages"/>
        <column colName="IsDuplicate" cellTitle="IsDuplicate" filterQuery="SearchMessages"/>
        <column colName="LastUpdateTime" cellTitle="LastUpdateTime" filterQuery="SearchMessages"/>
        <column colName="OriginalMessageID" cellTitle="OriginalMessageID" filterQuery="SearchMessages"/>
    </tablePane>
 
/// JS to run the search
ClientMethod runSearch() [ Language = javascript ]
{
    function normalize(value) {
        return (value === "" || value === undefined) ? null : value;
    }
 
    function normalizeDate(value, endOfDay) {
        if (!value) return null;
        // Otherwise append start or end of day
        return endOfDay ? value + " 23:59:59" : value + " 00:00:00";
    }
 
    var params = {
        DocumentID:        normalize(zenPage.getComponentById('filterDocumentID').getValue()),
        DocumentSource:    normalize(zenPage.getComponentById('filterDocumentSource').getValue()),
        SessionID:         normalize(zenPage.getComponentById('filterSessionID').getValue()),
        MessageControlID:  normalize(zenPage.getComponentById('filterMessageControlID').getValue()),
        PersonID:          normalize(zenPage.getComponentById('filterPersonID').getValue()),
        SourceFacility:    normalize(zenPage.getComponentById('filterSourceFacility').getValue()),
        EventType:         normalize(zenPage.getComponentById('filterEventType').getValue()),
        EncounterNumber:   normalize(zenPage.getComponentById('filterEncounterNumber').getValue()),
        MessageDateFrom:   normalizeDate(zenPage.getComponentById('filterMessageDateFrom').getValue(), false),
        MessageDateTo:     normalizeDate(zenPage.getComponentById('filterMessageDateTo').getValue(), true),
        SendTimeFrom:      normalizeDate(zenPage.getComponentById('filterSendTimeFrom').getValue(), false),
        SendTimeTo:        normalizeDate(zenPage.getComponentById('filterSendTimeTo').getValue(), true),
        IsActive:          zenPage.getComponentById('filterIsActive').getValue() ? 1 : null,
        IsDuplicate:       zenPage.getComponentById('filterIsDuplicate').getValue() ? 1 : null,
        LastUpdateFrom:    normalizeDate(zenPage.getComponentById('filterLastUpdateFrom').getValue(), false),
        LastUpdateTo:      normalizeDate(zenPage.getComponentById('filterLastUpdateTo').getValue(), true),
        OriginalMessageID: normalize(zenPage.getComponentById('filterOriginalMessageID').getValue())
    };
 
    console.log("Starting to get results");
    console.log("Filters:");
    console.log("------------------------");
    for (var key in params) {
        if (params[key] != null && params[key] !== "") {
            console.log(key + ": " + params[key]);
        }
    }
 
    // Assign to tablePane parameters and run query
    var table = zenPage.getComponentById('resultsTable');
    table.parameters = params;
    console.log(table.parameters);
    table.executeQuery(true, true);
    console.log(table.getColumnFilters());
}
Query SearchMessages(DocumentID, DocumentSource, SessionID, MessageControlID, PersonID, SourceFacility, EventType, EncounterNumber, MessageDateFrom, MessageDateTo, SendTimeFrom, SendTimeTo, IsActive, IsDuplicate, LastUpdateFrom, LastUpdateTo, OriginalMessageID) As %SQLQuery
{
    SELECT DocumentID, DocumentSource, SessionID, MessageControlID, PersonID, SourceFacility, EventType, EncounterNumber, MessageDate, SendTime,
           IsActive, IsDuplicate, LastUpdateTime, OriginalMessageID
    FROM MD.MessageTracking
    WHERE (DocumentID = :DocumentID OR :DocumentID IS NULL)
      AND (DocumentSource = :DocumentSource OR :DocumentSource IS NULL)
      AND (SessionID = :SessionID OR :SessionID IS NULL)
      AND (MessageControlID = :MessageControlID OR :MessageControlID IS NULL)
      AND (PersonID = :PersonID or :PersonID IS NULL)
      AND (SourceFacility = :SourceFacility or :SourceFacility IS NULL)
      AND (EventType = :EventType or :EventType IS NULL)
      AND (EncounterNumber = :EncounterNumber or :EncounterNumber IS NULL)
      AND (MessageDate >= :MessageDateFrom OR :MessageDateFrom IS NULL)
      AND (MessageDate <= :MessageDateTo OR :MessageDateTo IS NULL)
      AND (SendTime >= :SendTimeFrom OR :SendTimeFrom IS NULL)
      AND (SendTime <= :SendTimeTo OR :SendTimeTo IS NULL)
      AND (IsActive = :IsActive OR :IsActive IS NULL)
      AND (IsDuplicate = :IsDuplicate OR :IsDuplicate IS NULL)
      AND (LastUpdateTime >= :LastUpdateFrom OR :LastUpdateFrom IS NULL)
      AND (LastUpdateTime <= :LastUpdateTo OR :LastUpdateTo IS NULL)
      AND (OriginalMessageID = :OriginalMessageID OR :OriginalMessageID IS NULL)
}


 
Discussão (0)1
Entre ou crie uma conta para continuar
Anúncio
· Ago. 14

[Video] Testing Non-functional Requirements in Applications

Hi, Community!

Looking for ways to improve your application testing? See how to build requirements such as performance and scalability into your development workflow:

Testing Non-functional Requirements in Applications

InterSystems experts @Erik Hemdal, @Matthew Giesmann, and @Chad Severtson discuss the benefits of testing these requirements, and how it can be done!

Discussão (0)1
Entre ou crie uma conta para continuar