Friday, December 13, 2013

Jugando con el schema flexibility en SAP HANA

El otro día, un colega del Labs me hizo una pregunta muy interesante..."Digamos que tenemos una tabla con schema flexibility...con muchos campos que podrían estar vacíos...como sabes cuales son los campos que tienen por lo menos un valor?"...por supuesto...no tenía idea de como resolver esto...así que por supuesto...me puse a trabajar...como era de esperarse -;)

Primero...vamos a crear nuestra tabla con algunos valores y con algunos valores nulos...

Crear tabla Products
DROP TABLE Products;

CREATE COLUMN TABLE Products(
PRODUCT_CODE VARCHAR(3),
PRODUCT_NAME NVARCHAR(20),
PRICE DECIMAL(5,2)
) WITH SCHEMA FLEXIBILITY;

INSERT INTO Products values ('001','Blag Stuff', 100.99);
INSERT INTO Products (PRODUCT_CODE,PRODUCT_NAME,PRICE,COLOR) 
values ('002','More Blag Stuff',100.99,'Black');
INSERT INTO Products (PRODUCT_CODE,PRODUCT_NAME,PRICE,COLOR,TYPES) 
values ('003','More Blag Stuff',100.99,null,null);

Cuando revisamos el contenido de la tabla, tendremos esto...


Como podemos ver...el último registro no tiene valores...así que deberemos obtener el nombre de los otros campos...para esto...vamos a crear una tabla para almacenarlos...luego...vamos a crear un Procedimiento para obtenerlos...

Crear tabla FIELDS_RECORDS
DROP TABLE Fields_Records;

CREATE COLUMN TABLE FIELDS_RECORDS(
FIELD_NAME VARCHAR(256)
);

Para el procedimiento...vamos a leer todos los campos que componen la tabla...luego vamos a contar todos los valores que no son nulos por cada campo...para esto...vamos a utilizar la ayuda de una tabla temporal y SQL dinámico puesto que por lástima...SQLScript no soporta aún asignación de escalares...

GET_FIELDS_WITH_RECORDS
DROP PROCEDURE GET_FIELDS_WITH_RECORDS;

CREATE PROCEDURE GET_FIELDS_WITH_RECORDS(IN TableName VARCHAR(256))
LANGUAGE SQLSCRIPT AS
v_column_name VARCHAR(256);
v_select VARCHAR(256);
v_count INTEGER := 0;
CURSOR c_cursor(v_column_name VARCHAR(256)) FOR
SELECT COLUMN_NAME FROM SYS.CS_COLUMNS_ A inner join SYS.CS_TABLES_ B
on A.table_oid = B.table_oid where schema_name = 'SYSTEM'
and table_name = :TableName
and internal_column_id > 200
order by internal_column_id;
BEGIN
FOR cur_row AS c_cursor(v_column_name) DO
create local temporary table #temptable(found INTEGER);

v_select := 'INSERT INTO #temptable (SELECT COUNT(' || cur_row.column_name || ') 
             FROM ' || :TableName || ' WHERE ' || cur_row.column_name || ' IS NOT NULL)'; 
exec v_select;

SELECT found INTO v_count FROM #temptable;
IF v_count > 0 THEN
v_select := 'INSERT INTO FIELDS_RECORDS VALUES(''' || cur_row.column_name || ''')';
drop table #temptable;
exec v_select;
END IF;
END FOR;
END;

Cuando llamamos a nuestro procedimiento, simplemente debemos pasar el nombre de la tabla...y luego leet su contenido...

Llamar al procedimiento y obtner la información
CALL GET_FIELDS_WITH_RECORDS('PRODUCTS');

SELECT * FROM FIELDS_RECORDS;

Veamos que tenemos en FIELDS_RECORDS -;)


Justo como lo esperabamos -:) Interesante, no?

Saludos,

Blag.
Developer Empowerment and Culture.

No comments: