1. Comprende $CHAR(0) vs cadena vacía vs SQL NULL
Puntos Clave
- Cadena vacía `""`: El valor por defecto "indefinido" en ObjectScript; `$LENGTH = 0`; es la representación en ObjectScript de SQL NULL
- `$CHAR(0)` (o `$C(0)`): Cadena de un solo carácter con ASCII 0; `$LENGTH = 1`; es la representación en ObjectScript de la cadena de longitud cero SQL `''`
- SQL NULL: Significa "desconocido/ausente"; distinto de la cadena de longitud cero SQL `''`
- IS NULL vs = '': `WHERE col IS NULL` coincide con valores almacenados como `""` en ObjectScript; `WHERE col = ''` coincide con valores almacenados como `$CHAR(0)`
- Puente objeto-SQL: Cuando una propiedad no tiene valor (por defecto `""` en ObjectScript), se proyecta como SQL NULL, no como cadena vacía
- Cadena vacía SQL explícita: Para almacenar la cadena SQL `''` (longitud cero, no-NULL) desde ObjectScript, establecer la propiedad a `$CHAR(0)`
Notas Detalladas
Descripción general
Uno de los temas más frecuentemente evaluados y malentendidos en InterSystems IRIS es la relación entre la cadena vacía de ObjectScript, $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 en la dirección lleva a errores sutiles.
Las dos reglas a recordar (según la referencia SQL oficial de InterSystems):
1. ObjectScript "" ↔ SQL NULL — "Use NULL para representar la ausencia de un valor de datos, lo cual corresponde a la cadena vacía de ObjectScript ("")." 2. ObjectScript $CHAR(0) ↔ SQL '' — "La cadena de longitud cero de SQL (cadena vacía) se especifica con dos comillas simples. En ObjectScript, esto corresponde a una cadena de longitud uno que contiene el carácter $CHAR(0)."
La cadena vacía en ObjectScript es SQL NULL
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. Cuando se accede a una propiedad nunca establecida, se obtiene "":
SET obj = ##class(MyApp.Patient).%New()
WRITE obj.MiddleName // "" (cadena vacía - valor por defecto)
WRITE $LENGTH(obj.MiddleName) // 0
WRITE (obj.MiddleName = "") // 1 (verdadero)
En SQL, cuando este objeto se guarda, la columna MiddleName es NULL, no una cadena de longitud cero:
-- Después de guardar el objeto anterior:
SELECT ID, MiddleName FROM MyApp.Patient WHERE ID = 1
-- Devuelve: MiddleName = NULL
SELECT ID FROM MyApp.Patient WHERE MiddleName IS NULL
-- SÍ devuelve esta fila
SELECT ID FROM MyApp.Patient WHERE MiddleName = ''
-- NO devuelve esta fila (= '' prueba la cadena de longitud cero, no NULL)
$CHAR(0) es la cadena de longitud cero SQL
$CHAR(0) (abreviado $C(0)) es un solo carácter con código ASCII 0. Es un valor distinto, no-NULL, de longitud 1. InterSystems IRIS usa $CHAR(0) como la representación en ObjectScript de la cadena de longitud cero SQL ''. Cuando una propiedad se establece a $C(0), se proyecta como '' (cadena vacía, no-NULL) en SQL — nunca como NULL:
// Almacenar una cadena de longitud cero SQL vía ObjectScript
SET obj.MiddleName = $CHAR(0)
SET sc = obj.%Save()
// Ahora en SQL:
// SELECT MiddleName FROM MyApp.Patient WHERE ID = 1
// Devuelve: '' (cadena de longitud cero), NO NULL
// SELECT ID FROM MyApp.Patient WHERE MiddleName IS NULL
// NO devuelve esta fila
// SELECT ID FROM MyApp.Patient WHERE MiddleName = ''
// SÍ devuelve esta fila
Verificación en ObjectScript
SET obj = ##class(MyApp.Patient).%OpenId(1)
// Verificar si el valor es SQL NULL
IF obj.MiddleName = "" {
WRITE "El valor es SQL NULL (cadena vacía en ObjectScript)", !
}
// Verificar si el valor es la cadena de longitud cero SQL
IF obj.MiddleName = $C(0) {
// Solo verdadero si la columna almacena '' (longitud cero, no-NULL)
// FALSO para la cadena vacía "" — son cadenas diferentes
WRITE "El valor es la cadena de longitud cero SQL ''", !
}
// Distinguir los tres casos:
IF obj.MiddleName = "" {
WRITE "SQL NULL", !
} ELSEIF obj.MiddleName = $C(0) {
WRITE "SQL '' (longitud cero, no-NULL)", !
} ELSE {
WRITE "Valor real: ", 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
| Concepto | Valor en ObjectScript | $LENGTH() | Proyección SQL | Prueba SQL |
|---|---|---|---|---|
| SQL NULL | "" (también el valor por defecto) | 0 | NULL | IS NULL |
| Cadena de longitud cero SQL | $C(0) | 1 | '' | = '' |
| Espacio | " " | 1 | ' ' | = ' ' |
| Propiedad no establecida | "" (por defecto) | 0 | NULL | IS NULL |
Insertar vía SQL
-- Inserción explícita de NULL
INSERT INTO MyApp.Patient (Name, MiddleName) VALUES ('Smith', NULL)
-- MiddleName será "" (cadena vacía) cuando se acceda vía ObjectScript
-- Cadena de longitud cero explícita
INSERT INTO MyApp.Patient (Name, MiddleName) VALUES ('Smith', '')
-- MiddleName será $C(0) (longitud 1) cuando se acceda vía ObjectScript
-- Omitir una columna inserta el valor por defecto de ObjectScript (""), que es SQL NULL
INSERT INTO MyApp.Patient (Name) VALUES ('Jones')
-- MiddleName será NULL en SQL
Error común: diferencias en cláusula WHERE
// Esta consulta encuentra filas cuyo valor es la cadena de longitud cero '':
&sql(SELECT COUNT(*) INTO :cnt FROM MyApp.Patient WHERE MiddleName = '')
WRITE "'' longitud cero: ", cnt, !
// Esta consulta encuentra filas cuyo valor es SQL NULL (ObjectScript ""):
&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:
- `""` = SQL NULL: Este es el hecho más importante. La cadena vacía de ObjectScript es cómo IRIS representa SQL NULL, y es el valor por defecto de las propiedades no establecidas.
- `$CHAR(0)` = SQL `''`: La cadena NUL de un carácter en ObjectScript es cómo IRIS representa la cadena SQL de longitud cero (no-NULL). Es un valor no-NULL válido.
- IS NULL vs = '': `IS NULL` coincide con `""` en ObjectScript; `= ''` coincide con `$CHAR(0)`. Prueban valores almacenados completamente distintos.
- Propagación de NULL: NULL en cualquier expresión aritmética o de cadena se propaga (el resultado es NULL).
- Comportamiento de COUNT: `COUNT(*)` cuenta todas las filas; `COUNT(column)` excluye NULLs.
- 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 la cadena de longitud cero `''`
- Escribir cláusulas WHERE correctas para encontrar valores NULL (`IS NULL`) vs longitud cero (`= ''`)
- Identificar errores donde se usa `= ''` en lugar de `IS NULL` (o viceversa)
- Entender qué sucede cuando se hace INSERT sin especificar columna (por defecto `""` en ObjectScript → SQL NULL)
- Predecir resultados de COUNT cuando los datos contienen una mezcla de NULLs y cadenas de longitud cero
- Establecer una propiedad a `$C(0)` para crear una cadena SQL de longitud cero, o dejarla en `""` para crear SQL NULL
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 qué fila coincide con cuál
- 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
- Verificar el mapeo empíricamente: `obj.Email = ""` → la fila coincide con `IS NULL`; `obj.Email = $C(0)` → la fila coincide con `= ''`