T3.3: Handles Nulls

Knowledge Review - InterSystems ObjectScript Specialist

1. Comprende $CHAR(0) vs cadena vacía vs SQL NULL

Puntos Clave

  • Cadena vacía `""`: El valor por defecto "indefinido" en ObjectScript; no es lo mismo que SQL NULL
  • `$CHAR(0)` (o `$C(0)`): Una cadena de un solo carácter que contiene ASCII 0; se mapea a SQL NULL en InterSystems IRIS
  • SQL NULL: Significa "desconocido/ausente"; diferente de la cadena vacía en la semántica SQL
  • IS NULL vs = '': `WHERE col IS NULL` verifica SQL NULL (`$C(0)`); `WHERE col = ''` verifica cadena vacía
  • Puente objeto-SQL: Cuando una propiedad no tiene valor (cadena vacía en ObjectScript), se proyecta como cadena vacía en SQL, NO como NULL
  • NULL explícito: Para almacenar un verdadero SQL NULL vía ObjectScript, establecer la propiedad a `$C(0)`

Notas Detalladas

Descripción general

Uno de los temas más frecuentemente evaluados y comúnmente malentendidos en InterSystems IRIS es la relación entre cadenas vacías, $CHAR(0) y SQL NULL. Esta distinción de tres vías es única de InterSystems IRIS debido a su modelo de datos unificado objeto-SQL, y equivocarse conduce a errores sutiles en consultas y manejo de datos.

Cadena vacía en ObjectScript

En ObjectScript, la cadena vacía "" es el valor inicial por defecto de cualquier variable o propiedad no establecida. Es una cadena de longitud cero, no null, no indefinida en el sentido SQL. Cuando accede a una propiedad que nunca se ha establecido, obtiene "":

SET obj = ##class(MyApp.Patient).%New()
WRITE obj.MiddleName        // "" (cadena vacía - el valor por defecto)
WRITE $LENGTH(obj.MiddleName)  // 0
WRITE (obj.MiddleName = "")    // 1 (verdadero)

En SQL, cuando este objeto se guarda, la columna MiddleName contendrá una cadena vacía, no NULL:

-- Después de guardar el objeto anterior:
SELECT ID, MiddleName FROM MyApp.Patient WHERE ID = 1
-- Devuelve: MiddleName = '' (cadena vacía)

SELECT ID FROM MyApp.Patient WHERE MiddleName IS NULL
-- ¡NO devuelve esta fila!

SELECT ID FROM MyApp.Patient WHERE MiddleName = ''
-- SÍ devuelve esta fila

$CHAR(0) como SQL NULL

$CHAR(0) (abreviado $C(0)) es un solo carácter con código ASCII 0. InterSystems IRIS usa este valor especial como la representación en ObjectScript de SQL NULL. Cuando una propiedad se establece a $C(0), se proyecta como NULL en SQL:

// Establecer una propiedad a SQL NULL vía ObjectScript
SET obj.MiddleName = $CHAR(0)
SET sc = obj.%Save()

// Ahora en SQL:
// SELECT MiddleName FROM MyApp.Patient WHERE ID = 1
// Devuelve: NULL

// SELECT ID FROM MyApp.Patient WHERE MiddleName IS NULL
// SÍ devuelve esta fila

Verificar $CHAR(0) en ObjectScript

// Después de abrir un objeto que tiene NULL en SQL
SET obj = ##class(MyApp.Patient).%OpenId(1)

// Verificar si el valor es SQL NULL
IF obj.MiddleName = $C(0) {
    WRITE "Value is SQL NULL", !
}

// Verificar si el valor es cadena vacía
IF obj.MiddleName = "" {
    // Esto es FALSE para $C(0) — son cadenas diferentes
    // $C(0) es un solo carácter (ASCII 0), "" es longitud cero
    WRITE "Value is truly empty", !
}

// Para distinguir $C(0) de cadena vacía y valores reales:
IF obj.MiddleName = $C(0) {
    WRITE "This is $C(0) - SQL NULL marker", !
} ELSEIF obj.MiddleName = "" {
    WRITE "This is truly empty string", !
} ELSE {
    WRITE "This has a value: ", obj.MiddleName, !
}

Comportamiento de SQL NULL en consultas

SQL NULL sigue la lógica estándar de tres valores de SQL (TRUE, FALSE, UNKNOWN):

-- Comparaciones con NULL
SELECT * FROM MyApp.Patient WHERE MiddleName = NULL   -- ¡INCORRECTO! Siempre devuelve cero filas
SELECT * FROM MyApp.Patient WHERE MiddleName IS NULL   -- Forma correcta de verificar NULL

-- NULL en expresiones
SELECT Name, MiddleName || ' ' || LastName FROM MyApp.Patient
-- Si MiddleName es NULL, el resultado de la concatenación es NULL (NULL se propaga)

-- COALESCE / IFNULL para manejar NULLs
SELECT Name, COALESCE(MiddleName, 'N/A') AS MiddleName FROM MyApp.Patient
-- Devuelve 'N/A' si MiddleName es NULL

-- NULL en agregados
SELECT COUNT(MiddleName) FROM MyApp.Patient
-- COUNT(column) excluye valores NULL
-- COUNT(*) cuenta todas las filas incluyendo aquellas con NULLs

Resumen comparativo

ConceptoValor en ObjectScript$LENGTH()Proyección SQLPrueba SQL
Cadena vacía""0'' (cadena vacía)= '' o = ""
SQL NULL$C(0)1NULLIS NULL
Espacio" "1' ' (espacio)= ' '
Propiedad no establecida"" (por defecto)0'' (cadena vacía)= ''

Insertar NULL vía SQL

-- Inserción explícita de NULL
INSERT INTO MyApp.Patient (Name, MiddleName) VALUES ('Smith', NULL)
-- MiddleName será $C(0) cuando se acceda vía ObjectScript

-- Omitir una columna también inserta el valor por defecto (cadena vacía, NO NULL)
INSERT INTO MyApp.Patient (Name) VALUES ('Jones')
-- MiddleName será '' (cadena vacía), NO NULL

Error común: diferencias en cláusula WHERE

// Esta consulta encuentra filas con MiddleName como cadena vacía:
&sql(SELECT COUNT(*) INTO :cnt FROM MyApp.Patient WHERE MiddleName = '')
WRITE "Empty strings: ", cnt, !

// Esta consulta encuentra filas con MiddleName como NULL:
&sql(SELECT COUNT(*) INTO :cnt FROM MyApp.Patient WHERE MiddleName IS NULL)
WRITE "NULLs: ", cnt, !

// ¡Son conjuntos de resultados DIFERENTES!
// Un error común es usar = '' cuando se quería IS NULL, o viceversa

Referencias de Documentación

Resumen de Preparación para el Examen

Conceptos críticos a dominar:

  1. $C(0) = SQL NULL: Este es el hecho más importante; `$CHAR(0)` es cómo ObjectScript representa SQL NULL
  2. La cadena vacía NO es NULL: Una propiedad no establecida tiene por defecto `""`, que es cadena vacía en SQL, no NULL
  3. IS NULL vs = '': Estos verifican cosas completamente diferentes; `IS NULL` coincide con `$C(0)`, `= ''` coincide con cadena vacía
  4. Propagación de NULL: NULL en cualquier expresión aritmética o de cadena se propaga (el resultado es NULL)
  5. Comportamiento de COUNT: `COUNT(*)` cuenta todas las filas; `COUNT(column)` excluye NULLs
  6. Lógica de tres valores: Las comparaciones que involucran NULL devuelven UNKNOWN, no TRUE ni FALSE

Escenarios comunes de examen:

  • Dada una asignación de propiedad en ObjectScript, predecir si SQL ve NULL o cadena vacía
  • Escribir cláusulas WHERE correctas para encontrar valores NULL vs cadena vacía
  • Identificar errores donde se usa `= ''` en lugar de `IS NULL` (o viceversa)
  • Entender qué sucede cuando se hace INSERT sin especificar una columna (cadena vacía, no NULL)
  • Predecir resultados de COUNT cuando los datos contienen una mezcla de NULLs y cadenas vacías
  • Establecer una propiedad a `$C(0)` para crear un valor SQL NULL desde ObjectScript

Recomendaciones de práctica:

  • Crear una clase de prueba con propiedades de cadena, guardar objetos con `""`, `$C(0)` y valores reales
  • Consultar la tabla con tanto `IS NULL` como `= ''` para ver la diferencia
  • Usar `SELECT $LENGTH(col), $ASCII(col) FROM ...` para inspeccionar valores almacenados
  • Practicar COALESCE e IFNULL para manejar NULLs en consultas
  • Experimentar con propagación de NULL en expresiones: `NULL + 5`, `NULL || 'text'`
  • Probar COUNT(*) vs COUNT(column) con datos que contienen NULLs
  • Escribir código ObjectScript que distinga correctamente `$C(0)` de `""` usando `$ASCII`

Report an Issue