sábado, 30 de noviembre de 2024

Lenguaje de programación D: katas

Dlang o D es un lenguaje de programación similar al clásico C. Mucha de su sintaxis nos recordará a dicho lenguaje. En esta entrega haremos varios ejercicios con funciones. Para instalar este lenguaje ve a este sitio:

https://dlang.org/

Si solo quieres probar el lenguaje, ve este sitio:

https://run.dlang.io/

Para compilar y ejecutar un programa en Dlang(D):

dmd programa.d

Ejercicios en Dlang

Ejercicio 1. Crear funciones para sumar, restar, multiplicar y dividir dos números enteros.

basicas.d

import std.stdio;

int sumar(int x, int y)
{
    return x + y;
}

int restar(int x, int y)
{
    return x - y;
}

int multiplicar(int x, int y)
{
    return x * y;
}

int dividir(int x, int y)
{
    if (y == 0)
    {
        return x;
    }
    return x / y;
}

void main(string[] args)
{
    int x = 45;
    int y = 21;

    int suma = sumar(x, y);
    int resta = restar(x, y);
    int producto = multiplicar(x, y);
    int division = dividir(x, y);
    writeln("\t === Operaciones aritméticas básicas ===");
    writef("La suma de %d y %d es: %d\n", x, y, suma);
    writef("La resta de %d y %d es: %d\n", x, y, resta);
    writef("La multiplicación de %d y %d es: %d\n", x, y, producto);
    writef("La división de %d y %d es: %d\n", x, y, division);
}

D nos permite crear funciones "tipo flecha", por lo que podemos editar el código y quedaría de la siguiente manera:

import std.stdio;

int sumar(int x, int y)=> x+y;

int restar(int x, int y)=>x-y;

int multiplicar(int x, int y)=>x*y;

int dividir(int x, int y)=>y==0?0:x/y;

void main(string[] args)
{
    int x = 45;
    int y = 21;

    int suma = sumar(x, y);
    int resta = restar(x, y);
    int producto = multiplicar(x, y);
    int division = dividir(x, y);
    writeln("\t === Operaciones aritméticas básicas ===");
    writef("La suma de %d y %d es: %d\n", x, y, suma);
    writef("La resta de %d y %d es: %d\n", x, y, resta);
    writef("La multiplicación de %d y %d es: %d\n", x, y, producto);
    writef("La división de %d y %d es: %d\n", x, y, division);
}

Ejercicio 2. Programa que calcule el factorial de un número entero.

factorial.d

import std.stdio;

int factorial(int num)
{
    if (num == 0)
    {
        return 1;
    }
    return num * factorial(num - 1);
}

void main(string[] args)
{
    int numero = 6;
    writeln("\t === Factorial de un número ===");
    writef("El factorial de %d es: %d\n", numero, factorial(numero));
}

El clásico programa del Factorial de un número en Dlang.

Ejercicio 3. Crear un programa que divida un número entre 2. Si el resultado del residuo de esa división es 0, el programa terminará. En otro caso el programa se ciclará.

ciclar.d

import std.stdio;

void mientras(int num)
{
    const int MAX = 100;
    while(num  < MAX ){
        writef("Número : %d\n", num);
        if(num%2==0){
            break;
        }else{
           continue;
        }
        ++num;
    }
}

void main(string[] args)
{
    int numero = 8;
    mientras(numero);
}

La entrada es 8. Si se divide entre 2 dará un residuo de 0 y entonces el programa terminará. Si fuese un número cuya división diera un residuo distinto de 0, entonces el programa se ciclará (un ciclo infinito). Será necesario matar el proceso.

Nota: El operador continue es una instrucción que se utiliza en programación para omitir la iteración actual de un bucle y pasar a la siguiente. En este caso, provocará que se muestre constanteente la entrada que no termina el ciclo, creando un ciclo infinito. Este ejercicio solo es didáctico y no tiene otro propósito.

Ejercicio 4. Este es un ejercicio propuesto en la página de Project Euler:

Si enumeramos todos los números naturales menores de 10 que sean múltiplos de 3 o 5, obtenemos 3, 5, 6 y 9. La suma de estos múltiplos es 23. Halla la suma de todos los múltiplos de 3 o 5 menores de 1000.

multiplos3o5.d

void main()
{
    import std.stdio : writefln;
    const MAX = 1000;
    int counter = 1;
    int suma = 0;
    while(counter < MAX){
        if(counter%3==0 || counter%5==0){
           suma+=counter;
           writefln("Suma = %d, Counter: %d",suma,counter);
        }
        ++counter;
    }
    writefln("Suma final= %d",suma);
}

Como detalles:

// Se puede crear una constante de esta forma:
const int MAX = 1000;

// Y de esta:
const MAX = 1000;

Además podemos hacer importaciones desde el cuerpo del método principal del programa (main).

Ejercicio 5. Crear una clase llamada Punto con propiedades x, y de tipo ``int``. Agregaremos una clase hija denominada PuntoColor, con un campo color de tipo ``string``.

clases.d

 import std.stdio : writeln;

void main()
{    
    Punto myPunto = new Punto(3,4);
    writeln("x:", myPunto.x);
    writeln("y:", myPunto.y);
    PuntoColor myPuntoColor = new PuntoColor("Rojo");
    writeln("color:", myPuntoColor.color);
}

class Punto{
   public int x;
   public int y;
    
   
    this(int x, int y) {
        writeln("Se ha creado una instancia de la clase Punto");
        this.x = x;
        this.x = x;
    }
}

class PuntoColor: Punto{
   public string color;
    this(string color){
      super(0,0);
      writeln("Se ha creado una instancia de la clase PuntoColor");
      this.color = color;
    }
}

Dlang es un lenguaje de programación que ha aprendido de los errores y aciertos de otros lenguajes como C, Java y C++, entre otros más.

Hasta otra entrega más.

Enlaces:

https://codemonkeyjunior.blogspot.com/2024/06/el-lenguaje-de-programacion-d.html
https://projecteuler.net/

domingo, 24 de noviembre de 2024

GCP: creando nuestras propias funciones

Las funciones contienen bloques de código que, al contrario de un procedimiento, devuelven valores o resultado de algún cálculo u operación. Y éstos valores pueden ser asignados variables con las que podemos realizar más operaciones.

Ejercicio 1. Crear una función que use la condición CASE expr para devolver un número si el valor introducido la función coincide con una letra en específico.

CREATE OR REPLACE FUNCTION `myproject.mydataset.getNumero`(orden STRING)
RETURNS INT64 AS(
  (
      CASE orden
      WHEN 'A' THEN 12
      WHEN 'B' THEN 23
      WHEN 'C' THEN 34
      WHEN 'D' THEN 45
      ELSE 0  END
  )
)

La podemos usar de la siguiente forma:

DECLARE orden STRING DEFAULT 'X';
DECLARE id_num INT64;

SET id_num = 56;

UPDATE `myproject.mydataset.numeros` 
SET numero = (SELECT `myproject.mydataset.getNumero`(orden)) 
WHERE id = id_num;

Asignamos dos variables: orden e id_num, de tipo STRING e INT64, respectivamente. Se les asigna un valor ("X" y 56). La función se encargará de devolver el número de acuerdo a la letra introducida a la función.

Para eliminar la función:

DROP FUNCTION `myproject.mydataset.getNumero`;

Ejercicio 2. Crear una función para determinar la diferencia entre 2 fechas. Las fechas serán introducidas como tipo STRING.

CREATE OR REPLACE FUNCTION `myproject.mydataset.getDifference`(day1 STRING, day2 STRING)
RETURNS NUMERIC AS(
  (SELECT DATE_DIFF(day1, day2, DAY))
)

Empleamos la función de DATE_DIFF para hacer la operación.

La podemos ocupar de la siguiente forma:

DECLARE dia1 STRING DEFAULT '2024-04-05';
DECLARE dia2 STRING DEFAULT '2024-04-02';
DECLARE resultado NUMERIC DEFAULT 0;

SET resultado = (SELECT  `myproject.mydataset.getDifference`(dia1, dia2));

SELECT 'Resultado: '||resultado;

Ejercicio 3. Crear tres funciones para sumar, restar y multiplicar.

-- Suma
CREATE OR REPLACE FUNCTION `myproject.mydataset.suma`(num1 NUMERIC, num2, NUMERIC)
RETURNS NUMERIC AS(
   (num1 + num2)
)

-- Resta
CREATE OR REPLACE FUNCTION `myproject.mydataset.resta`(num1 NUMERIC, num2, NUMERIC)
RETURNS NUMERIC AS(
   (num1 - num2)
)

-- Multiplicación
CREATE OR REPLACE FUNCTION `myproject.mydataset.multiplicacion`(num1 NUMERIC, num2, NUMERIC)
RETURNS NUMERIC AS(
   (num1 * num2)
)

Y las podemos emplear de la siguiente forma:

DECLARE x NUMERIC DEFAULT 34.0;
DECLARE y NUMERIC DEFAULT 8.430;

-- Suma
SELECT `myproject.mydataset.suma`(x,y) AS sumar; -- 42.43


-- Resta
SELECT `myproject.mydataset.resta`(x,y) AS restar; -- 25.57

-- Multiplicación
SELECT `myproject.mydataset.multiplicacion`(x,y) AS producto;-- 286.62

Ejercicio 4. Teniendo el siguiente pseudo código. Crear una función que calcule el factorial de un número

Pseudocódigo:

FUNCTION FACT(N)
IF N = 0 THEN 
  RETURN 1;
ELSE 
  RETURN N * FACT(N - 1)
END FUNCTION

Función en BigQuery:

CREATE OR REPLACE FUNCTION `myproject.mydataset.FACT`(N INT64)
RETURNS INT64
AS (
  CASE 
    WHEN N = 0 THEN 1
    ELSE N * `myproject.mydataset.FACT`(N - 1)
  END
);

Uso:

DECLARE numero INT64;

SET numero = 5;
SELECT `myproject.mydataset.FACT`(numero) AS factorial; -- 120

Imaginemos que tenemos un vector. Así podríamos obtener el factorial de cada uno de sus elementos:

WITH numeros AS (
  SELECT num
  FROM UNNEST([2, 3, 4, 5, 6]) AS num
)
SELECT 
  num,
  `myproject.mydataset.FACT`(num) AS factorial
FROM 
  numeros ;


Ejercicio 5. Crear tres funciones en la cual:

  • Una obtenga el IMC. 
  • Otra obtenga el diagnóstico de sobrepeso de acuerdo al IMC. 
  • Y la final, que que nos devuelva el resultado.

Función que calcula el IMC:

CREATE OR REPLACE FUNCTION `myproject.mydataset.IMC`(PESO FLOAT64, TALLA FLOAT64)
RETURNS FLOAT64
AS (
  PESO / (TALLA * TALLA)
);


Función que obtiene el diagnóstico de acuerdo al IMC obtenido:

CREATE OR REPLACE FUNCTION `myproject.mydataset.DIAGNOSTICO`(IMC FLOAT64)
RETURNS STRING
AS (
  CASE
    WHEN IMC < 18.5 THEN 'Bajo peso'
    WHEN IMC BETWEEN 18.5 AND 24.9 THEN 'Normal'
    WHEN IMC BETWEEN 25.0 AND 29.9 THEN 'Sobrepeso'
    WHEN IMC BETWEEN 30.0 AND 34.9 THEN 'Obesidad grado 1'
    WHEN IMC BETWEEN 35.0 AND 39.9 THEN 'Obesidad grado 2'
    ELSE 'Obesidad grado 3'
  END
);



Función que devuelve el resultado final:

CREATE OR REPLACE FUNCTION `myproject.mydataset.OBTENER_MASA`(PESO FLOAT64, TALLA FLOAT64)
RETURNS STRUCT<IMC FLOAT64, DIAGNOSTICO STRING>
AS (
  STRUCT(
    `myproject.mydataset.IMC`(PESO, TALLA) AS IMC,
    `myproject.mydataset.DIAGNOSTICO`(`myproject.mydataset.IMC`(PESO, TALLA)) AS DIAGNOSTICO
  )
);

La usamos de la siguiente forma:

SELECT 
  resultado.IMC AS imc,
  resultado.DIAGNOSTICO AS diagnostico
FROM (
  SELECT `myproject.mydataset.OBTENER_MASA`(70, 1.75) AS resultado
);

¡Hemos visto como crear nuestras propias funciones en BigQuery!

Más sobre este tema en próximas entregas.

Enlaces:

https://codemonkeyjunior.blogspot.com/2024/11/gcp-funciones-condicionales-en-bigquery.html
https://codemonkeyjunior.blogspot.com/2024/10/gcp-bigquery-funciones-de-cadena-y.html
https://cloud.google.com/bigquery/docs/user-defined-functions

lunes, 18 de noviembre de 2024

Stored procedures Oracle PL/SQL / GCP BigQuery

Haciendo un poco de memoria, recordaremos lo que es un Stored Procedure.

Un Stored Procedure (procedimiento almacenado) es:

  • Un subprograma que ejecuta una acción específica.
  • No devuelve valor alguno (pero mediante un mecanismo podemos recuperar valores).
  • Posee un nombre y puede o no tener parámetros y un bloque donde se efectuarán las acciones a realizar.
  • Se puede llamar desde otros Stored Procedures y/o consultas SQL.

Si usamos Oracle, está será será su sintaxis:

CREATE {OR REPLACE} PROCEDURE nombre_proc( param1 [IN | OUT | IN OUT] tipo,... )
IS
  -- Declaración de variables locales
  BEGIN
  -- Instrucciones de ejecución
  [EXCEPTION]
  -- Instrucciones de excepción
END;

En BigQuery, sería de esta forma:

CREATE PROCEDURE dataset_name.procedure_name(OUT param1 TYPE, ...)
BEGIN
-- statements here
  [EXCEPTION]
  -- statements here
END

La forma de invocar un Stored Procedure en Oracle:

CALL miprocedimiento();

En BigQuery:

CALL mydataset.miprocedimiento();

Lenguaje procedimental

Tanto GCP BigQuery como Oracle PL/SQL poseen sus propias peculiaridades. Empecemos con los bloques.

En PL/SQL:

DECLARE
BEGIN
   dbms_output.put_line('Hola, mundo');
END;
/

En BigQuery:

BEGIN
   SELECT FORMAT('Hola, mundo');
END;

También podemos hacer esto:

DECLARE saludo STRING DEFAULT 'Hola, mundo';
SELECT FORMAT(saludo);

Para declarar variables en PL/SQL:

DECLARE 
   entero integer := 10;
   numero NUMBER(3):= 123;
   nombre VARCHAR2(45);
   flotante real;
   tiempo_salida TIMESTAMP(3):= '23-JUL-2024 07:22:53.175';
   verdadero BOOLEAN:= FALSE;
   fecha DATE;
   ...
BEGIN
 -- SENTENCIAS
END;
/
     
   

En BigQuery:

DECLARE nombre STRING DEFAULT 'MARIA';
DECLARE fecha DATE;
DECLARE verdadero BOOL DEFAULT TRUE;
DECLARE numero INT64;
DECLARE otro_num NUMERIC DEFAULT 12.0;

SET numero = 9;
SET fecha = '2024-09-12';

...    
   

Es muy parecida la forma en que se declaran las variables.

Al ser lenguajes procedimentales tendrán:

  1. Sentencias Top-Down o de arriba hacia abajo. 
  2. Sentencias iterativas o repetitivas. 
  3. Sentencias selectivas o condicionales.

Sentencias Top-Down

Sentencias de arriba hacia abajo. No hay mucha ciencia e ello. Comencemos con PL/SQL:

DECLARE
-- Declaramos las variables
numero INTEGER;
verdadero BOOLEAN;
fecha DATE;
presente NUMBER;

BEGIN
-- Seteamos sus valores
numero := 33;
verdadero := FALSE;
fecha := TO_DATE('2024/07/09', 'yyyy/mm/dd');
presente := 2300.23;


--
END;
/

En BigQuery:

BEGIN
DECLARE numero INT64;
DECLARE verdadero BOOL;
DECLARE fecha DATE;
DECLARE presente NUMERIC;

-- Seteamos sus valores
SET numero = 33;
SET verdadero = FALSE;
SET fecha = FORMAT_DATE("%Y-%d-%m",'2024/07/09');
SET presente = 2300.23;


--
END;

Sentencias iterativas o repetitivas

Bucle FOR en PL/SQL

FOR contador IN 1..20
LOOP
   contador := contador + 1;
END LOOP;

Bucle WHILE en PL/SQL

WHILE contador <= 100
LOOP
   contador := contador + 1;
END LOOP;

Bucle FOR en BigQuery

DECLARE vector_a ARRAY<STRING>;
SET vector_a = ['_01', '_02', '_03'];

FOR loop_variable_name IN (SELECT * FROM UNNEST(vector_a))
DO
  -- Hacer algo aquí;
END FOR;

Bucle WHILE en BigQuery

declare cont int64 default 0;
set TAM = (select count(*) from `project.dataset.tabla1`);
set cont = 1;

while cont <= TAM do
   -- 
   SET cont = cont + 1;
end while;

Solo son algunas sentencias repetitivas. Ambos incluyen otras como: LOOP.

Sentencias selectivas o condicionales

IF en PL/SQL

DECLARE 
  numero INTEGER;
  titulo VARCHAR2(5):="ABCD";

BEGIN
  numero:=33;
IF numero = 33 THEN
   SELECT "Hola, "||numero FROM dual;
END IF;

IF LENGTH(titulo) = 5 THEN
   SELECT 'La cadena tiene una longitud de 5';
ELSE 
   SELECT 'La cadena tiene una longitud de '||LENGTH(titulo);
END IF;

END;
/

IF en BigQuery

DECLARE numero INT64;
DECLARE titulo DEFAULT 'ABCD';
SET numero = 33;

IF numero = 33 THEN
   SELECT FORMAT('Hola, ', CAST(numero AS STRING));
END IF;

IF LENGTH(titulo) = 5 THEN
   SELECT 'La cadena tiene una longitud de 5';
ELSE 
   SELECT 'La cadena tiene una longitud de '||LENGTH(titulo);
END IF;

Solo mostramos algunas sentencias. Si quieres ver sentencias condicionales en BigQuery, puedes echar un vistazo en este link:

https://codemonkeyjunior.blogspot.com/2024/11/gcp-funciones-condicionales-en-bigquery.html

Continuaremos con este tema en siguientes posts.

Enlaces:

https://elbauldelprogramador.com/plsql-procedimientos-y-funciones/
https://docs.oracle.com/cd/B28359_01/appdev.111/b28843/tdddg_procedures.htm