Funciones de Data Extension — referencia de Marketing Cloud AMPscript
Las funciones de read y write de DE — Lookup, LookupRows, LookupOrderedRows, Row, Field, RowCount, InsertData, UpdateData, UpsertData, ClaimRow. La superficie más safety-critical del lenguaje: los writes pueden fallar en silencio, los lookups pueden truncar en 2000, y un par de argumentos mal alineado aterriza el valor equivocado en la columna equivocada.
Las funciones de Data Extension son la superficie más safety-critical en AMPscript. Leen y escriben data de producción; un par de argumentos mal alineado aterriza el valor equivocado en la columna equivocada sin error. Las funciones de write son silenciosas en cada falla interesante (PK equivocada → duplicados, nombre de columna equivocado → write salteado, type mismatch → coerción). Las funciones de read capean en 2000 filas sin warning. Y los lookups per-destinatario en el cuerpo de un email corren una vez por destinatario — un send de 50.000 filas corre 50.000 reads contra tu DE.
Esta página es el inventario + los patrones. Los dos items del gotchas page que se disparan más seguido (cap de LookupRows en 2000 y duplicados silenciosos de UpsertData) están cubiertos en detalle; el snippet hermano de SSJS debugging recorre la misma forma de falla con las queries SQL que la detectan después del hecho.
Sintaxis oficial
Reads — valor único
%%[
/* Lookup — devuelve el valor de una columna, o NULL cuando no hay match */
SET @tier = Lookup("master_segments", "Tier", "SubscriberKey", _subscriberKey)
/* Siempre defaulteá el resultado si puede no encontrar */
IF Empty(@tier) THEN
SET @tier = "Standard"
ENDIF
]%%Reads — múltiples filas
%%[
/* LookupRows — capeado en 2000 filas, silenciosamente */
SET @rows = LookupRows("active_promos", "Region", "LATAM")
SET @n = RowCount(@rows)
/* Iterar — Row() es 1-based, como todo lo demás */
FOR @i = 1 TO @n DO
SET @r = Row(@rows, @i)
SET @id = Field(@r, "PromoId")
SET @label = Field(@r, "Label")
NEXT @i
/* LookupOrderedRows — paginado + ordenado. El 4to arg es la cantidad
de filas (0 = todas hasta el cap de 2000), el 5to es la columna de
orden con sufijo "asc" / "desc" */
SET @latest = LookupOrderedRows("orders", 1, "OrderDate desc",
"SubscriberKey", _subscriberKey)
IF RowCount(@latest) > 0 THEN
SET @lastOrder = Row(@latest, 1)
SET @amount = Field(@lastOrder, "Amount")
ENDIF
/* LookupRowsCS — variante case-sensitive */
SET @exact = LookupRowsCS("master_subs", "Status", "Active")
]%%Writes
%%[
/* InsertData — pares variádicos después del nombre del DE.
Siempre pareá (columnName, value) — la mala alineación es silenciosa. */
InsertData(
"de_log_writes",
"RunId", @runId,
"Step", "process",
"Message", "completed",
"Ts", Now()
)
/* UpdateData — pares de (keyCol, keyVal) seguidos por pares de
(setCol, setVal). El conteo de args le dice a AMPscript cuál es
cuál: los primeros N pares son keys, los restantes son valores a setear. */
UpdateData(
"master_subs",
1, /* cantidad de key pairs */
"SubscriberKey", @subKey, /* key pair */
"Status", "Inactive", /* set pair */
"UpdatedAt", Now() /* set pair */
)
/* UpsertData — misma firma que UpdateData, pero inserta si la key
no matchea. Devuelve 1 en éxito, 0 en falla. Duplicados silenciosos
si la PK del destino está mal — ver gotcha #4. */
SET @result = UpsertData(
"master_subs",
1,
"SubscriberKey", @subKey,
"Status", @status,
"UpdatedAt", Now()
)
/* DeleteData — solo match-pair, sin set-pair */
DeleteData("de_stg_temp", "RunId", @runId)
]%%Claim atómico — ClaimRow
%%[
/* ClaimRow — read + flag atómico de la primera fila que matchea.
Usado para patrones de giveaway one-of-N / first-come-first-served
(gift cards, códigos, ofertas limitadas). Atómico en el backend de MC. */
SET @row = ClaimRow(
"de_gift_codes",
"Code", /* columna a devolver */
"IsClaimed", /* columna de status a flagear */
"true", /* valor a escribir */
"IsClaimed", "false", /* filtro: solo no-claimed */
"Region", "LATAM" /* filtro adicional */
)
IF NOT Empty(@row) THEN
SET @giftCode = @row
ELSE
/* No quedan códigos — manejá con gracia */
SET @giftCode = "SORRY-OUT-OF-STOCK"
ENDIF
]%%El set soportado:
| Función | Propósito | Notas |
|---|---|---|
| Lookup(de, returnCol, filterCol, filterVal) | Leer el valor de una columna | Devuelve NULL si no encuentra — sin error |
| LookupRows(de, filterCol, filterVal) | Leer todas las filas que matchean | Capeado en 2000 silenciosamente |
| LookupRowsCS(de, filterCol, filterVal) | LookupRows case-sensitive | Mismo cap de 2000 |
| LookupOrderedRows(de, count, orderBy, filterCol, filterVal) | Leer N filas en orden | count=0 significa todas hasta 2000; orderBy como "Date desc" |
| LookupOrderedRowsCS(de, count, orderBy, filterCol, filterVal) | LookupOrderedRows case-sensitive | Mismo cap |
| Row(rowset, n) | Conseguir la fila n-ésima del resultado de LookupRows | 1-based |
| Field(row, columnName) | Conseguir columna de una fila | Devuelve NULL si la columna falta — sin error |
| RowCount(rowset) | Contar filas en un resultado | Conteo top-level, nunca excede 2000 |
| InsertData(de, col1, val1, col2, val2, ...) | Insertar una fila | Args pareados; la mala alineación es silenciosa |
| UpdateData(de, nKeys, key1, kval1, ..., set1, sval1, ...) | Actualizar filas que matchean | Requiere el conteo de key pairs como 2do arg |
| UpsertData(de, nKeys, key1, kval1, ..., set1, sval1, ...) | Update o insert | Devuelve 1/0; duplicados silenciosos si la PK está mal |
| DeleteData(de, col1, val1, ...) | Borrar filas que matchean | Solo match-pairs |
| ClaimRow(de, returnCol, flagCol, flagVal, filterCol, filterVal, ...) | Read + flag atómico | Usado para patrones de giveaway one-of-N |
Referencia:
- AMPscript Guide — referencia de funciones (sección Data Extension) ↗
- Salesforce Developer — funciones AMPscript ↗
Lo que sobrevive en producción
LookupRows capea en 2000 filas — silenciosamente
Misma forma que el cap de Platform.Function.LookupRows en SSJS en 2500. Lógica de email que itera sobre el resultado pierde a todos los que pasan la fila 2000 sin warning.
%%[
SET @rows = LookupRows("active_promotions", "Region", "LATAM")
SET @n = RowCount(@rows)
/* @n es como máximo 2000 — afirmá y alertá cuando pegue el cap */
IF @n == 2000 THEN
/* O alertás vía un write a DE de log, o ya pivoteaste a un DE
de staging pre-formateado upstream. La regla Cleon es la segunda. */
InsertData("de_log_alerts",
"JobID", jobid,
"Source", "AMPscript LookupRows",
"Issue", "Hit 2000-row cap",
"Ts", Now())
ENDIF
]%%La defensa correcta es upstream: una SQL Activity escribe un DE de_email_<proposito> con las filas ya capeadas, ordenadas, y formateadas para las necesidades del email. AMPscript lee ese DE con una llamada LookupRows donde 2000 no es una restricción. Ver gotchas — #3.
UpsertData inserta duplicados silenciosos cuando la PK del destino está mal
UpsertData es upsert solo de nombre — el backend de MC chequea la primary key del DE destino. Si la PK falta o está sobre la columna equivocada, cada llamada se vuelve un insert y los duplicados se acumulan. La función devuelve 1 (success) de cualquier manera.
%%[
/* EN RIESGO — asume que el DE destino tiene SubscriberKey como PK.
Si no, cada corrida del script agrega una fila en vez de actualizar. */
SET @result = UpsertData(
"master_subs",
1,
"SubscriberKey", _subscriberKey,
"Status", "Active",
"UpdatedAt", Now()
)
/* @result = 1 → "success" — pero la fila pudo haber sido INSERTADA
cuando pretendías UPDATE. Verificá la PK del destino antes de live. */
]%%La defensa es la misma que la regla de SSJS: verificá la configuración de primary key del DE destino en la UI de MC antes de que cualquier UpsertData llegue a producción. El snippet hermano de SSJS debugging recorre las queries SQL que detectan la falla después del hecho — mismo diagnóstico aplica a writes drived-por-AMPscript contra los mismos DEs. Ver gotchas — #4.
La mala alineación de pares de argumentos es silenciosa
InsertData / UpdateData / UpsertData toman pares de (columnName, value). Olvidarse un elemento corre cada par siguiente una posición, y los writes aterrizan en columnas equivocadas. AMPscript no valida la alineación.
%%[
/* EN RIESGO — falta el nombre de columna Message; "completed" aterriza
en Step, Now() aterriza en Message, RunId se vuelve "RunId" literal */
InsertData(
"de_log_writes",
"RunId", @runId,
"Step", /* ← falta el valor acá */
"completed",
"Message",
Now()
)
/* DURABLE — formateado verticalmente con par-por-línea alinea visualmente,
y la próxima persona leyendo el código nota un par faltante */
InsertData(
"de_log_writes",
"RunId", @runId,
"Step", "process",
"Message", "completed",
"Ts", Now()
)
]%%La convención Cleon: cada llamada InsertData / UpdateData / UpsertData usa formateo par-por-línea con columnas alineadas. La estructura visual es la validación — el code review detecta un valor faltante inmediatamente.
Acceso a Row y columnas — 1-based, NULL en miss
%%[
SET @rows = LookupRows("orders", "SubscriberKey", _subscriberKey)
SET @n = RowCount(@rows)
IF @n > 0 THEN
/* 1-based — Row(@rows, 0) es comportamiento indefinido; Row(@rows, 1) es la primera */
SET @first = Row(@rows, 1)
SET @amount = Field(@first, "Amount")
/* Si el DE no tiene una columna "Amount", @amount es NULL — silencioso */
IF Empty(@amount) THEN
SET @amount = 0
ENDIF
ENDIF
]%%Field(row, "wrongColumnName") devuelve NULL sin error. Siempre defaulteá el resultado de un acceso Field si la columna podría no existir o no tener un valor para esta fila. Ver gotchas — #2.
LookupRows per-destinatario a escala = N reads por send
%%[
/* EN RIESGO — corre una vez por destinatario. En un send de 50k, son
50.000 reads contra active_promos. El DE se pega duro durante el send. */
SET @promos = LookupRows("active_promos", "Region", @region)
SET @n = RowCount(@promos)
]%%Para audiencias de más de algunos miles, el costo per-destinatario se acumula — tanto en carga al DE como en latencia del send-time. El patrón: hacer una sola SQL Activity upstream que joinea audience × promos en un DE de_email_<send>_promos con clave por SubscriberKey. AMPscript lee ese DE una vez por destinatario con un Lookup fino (o sin lookup para nada si las columnas ya están en el DE sendable).
%%[
/* DURABLE — el DE sendable ya tiene el data joineado;
no hace falta LookupRows en render time */
SET @promoLabel = AttributeValue("PromoLabel")
SET @promoCode = AttributeValue("PromoCode")
]%%El principio Cleon: AMPscript debería ser fino. El trabajo de data pasa upstream; el cuerpo del email interpola.
ClaimRow es el único write atómico — usalo para first-come-first-served
ClaimRow es raro en catálogos AMPscript pero crítico para patrones de giveaway one-of-N (códigos de regalo de stock limitado, "los primeros 100 que cliquean reciben X"). El backend de MC maneja la atomicidad, así que dos destinatarios pegando al mismo código al mismo momento no obtienen el mismo valor.
%%[
/* El DE de supply tiene filas (Code, IsClaimed); la función encuentra
la primera fila con IsClaimed=false matcheando los filtros extra,
setea IsClaimed=true, y devuelve el Code. */
SET @giftCode = ClaimRow(
"de_gift_codes",
"Code",
"IsClaimed",
"true",
"IsClaimed", "false",
"Region", @region
)
IF Empty(@giftCode) THEN
/* Supply agotado */
SET @giftCode = ""
ENDIF
]%%El detalle no-obvio: la garantía "atómica" solo se mantiene cuando el DE de supply tiene una primary key sobre la columna Code (o lo que sea el return-column). Sin PK, la función puede entregar el mismo código dos veces. Misma disciplina de primary-key que UpsertData. Ver gotchas — #4.
Las funciones de write devuelven 1/0 — loggeá el resultado cada vez
Mismo patrón que el item #10 del gotchas page para funciones de Cloud-write: las funciones de write de DE de AMPscript devuelven un resultado numérico, no una excepción. Un retorno 0 significa que el write no pasó, el cuerpo del email igual renderea, y te enterás una semana después cuando el DE de log al que estabas escribiendo está vacío.
%%[
SET @result = UpsertData(
"de_log_engagement",
1,
"SubscriberKey", _subscriberKey,
"LastEmailOpened", Now()
)
/* Loggear el outcome — un segundo write a un DE más confiable */
InsertData(
"de_log_writes",
"JobID", jobid,
"SubscriberKey", _subscriberKey,
"Operation", "de_log_engagement.upsert",
"Result", @result,
"Ts", Now()
)
]%%Si el segundo write es al mismo grupo de DE que está fallando, el logging en sí puede fallar en silencio — escribí el log a un DE distinto en un schema distinto (sin columnas exóticas, sin PK compleja), para que el log sea más probable que aterrice incluso cuando el write primario no lo hizo.
Decisión rápida
Usá Lookup cuando:
- Necesitás el valor de una columna para el destinatario actual. Siempre defaulteá el resultado con
Empty().
Usá LookupRows (o LookupOrderedRows) cuando:
- Necesitás múltiples filas y verificaste que el resultado va a estar bajo 2000. Si no, pre-formateá upstream en SQL.
Usá LookupOrderedRows cuando:
- Necesitás "los últimos N" o "los top N por score". El sufijo
"asc"/"desc"del 5to arg es la sintaxis más limpia para ordenar.
Usá Field(Row(@rs, n), "col") cuando:
- Accedés una columna específica en una fila específica de un rowset. Defaulteá el resultado; los typos de nombre de columna devuelven NULL silenciosamente.
Usá InsertData cuando:
- Escribís una fila de log, una submission de form de CloudPage, una fila de evento. Formateá args par-por-línea.
Usá UpdateData cuando:
- La fila destino está garantizada de existir por otro paso upstream. Si no, usá
UpsertData.
Usá UpsertData cuando:
- Se necesita semántica insert-or-update. Siempre verificá la PK del destino primero.
Usá ClaimRow cuando:
- Patrón de giveaway one-of-N. El DE de supply tiene que tener PK sobre la columna de retorno. Atómico en el backend.
Pre-computá en SQL upstream cuando:
- La personalización tiene la misma forma para cada destinatario. Una pasada SQL le gana a N reads de AMPscript.
- El lookup involucra joins multi-DE, agregaciones, o límites de row count más allá de 2000.
- El write es parte de un paso de audience-build. Usá SQL Activity (
INSERT INTO ... SELECT) en vez de writes per-destinatario de AMPscript.
Relacionado
- Basics — superficie del lenguaje soportada
- Funciones de validación —
Empty()para defaultear resultados de Lookup - Gotchas de MC AMPscript — ver #2 (NULL silencioso de
Lookup), #3 (cap de 2000 deLookupRows), #4 (duplicados silenciosos deUpsertData), #10 (patrón de falla silenciosa de las funciones de write) - MC SSJS — Debugging de duplicados de UpsertData — las queries de diagnóstico SQL que detectan writes con duplicados silenciosos desde cualquier fuente, AMPscript o SSJS
- MC SQL — INSERT INTO — el patrón upstream para formatear DEs
de_email_*que finan las lecturas de AMPscript - MC SQL Style Guide — la disciplina upstream que previene la mayoría de las formas de falla de esta página
Más páginas de referencia AMPscript en camino: Subscriber/Profile · Cloud-write · Encoding/Hashing · Style Guide.