> *A REVANCHA: EXAME TÉCNICO (BLOQUE 2)*

# I. DESENVOLVEMENTO E LÓXICA (C# / Python)

## 1. O Filtro de Seguridade (Tema 1 e 5):

Imagina que recibes una lista de "IDs de empleados" como un array de strings. Algunos pueden ser nulos o estar vacíos.

- Escribe una función/método que recorra la lista y solo imprima los IDs que tengan exactamente 5 caracteres y no sean nulos.
- Reto Extra: Usa un bloque try-catch (C#) o try-except (Python) para evitar que el programa explote si algún elemento de la lista da problemas.

### Respuesta

En C#:

```cs
using System.Collections.Generic;
using System;

namespace Examen{
    class Empleado{

        public string? id;

        public Empleado(string? id = null){
            this.id = id;
        }

        public static List<string> filtrar(List<Empleado> empleados){

            List<Empleado> filtrados = new List<Empleado>();

            foreach(Empleado empleado in empleados)
                if(empleado.id != null && empleado.id.Length == 5){
                    Console.WriteLine(empleado.id);
                    filtrados.Add(empleado);
                }

            return filtrados;
        }

    }
}

```

En Python:

```py
from typing import Self, Optional, Sequence

class Empleado:

    def __init__(self:Self, id:Optional[str] = None) -> None:
        self.id:str|None = id

    @staticmethod
    def filtrar(empleados:Sequence[type[Self]]) -> list[type[Self]]:

        filtrados:list[Empleado] = []
        empleado:Empleado

        for empleado in empleados:
            if empleado.id is not None and len(empleado.id) == 5:
                print(empleado.id)
                filtrados.append(empleado)

        return filtrados
```

Para los SQL hay que hacer uso de Procedimientos y no de funciones pues las funciones pueden retornar un valor, pero no pueden alterar ni mostrar selecciones.

En SQL Server:

```sql
use Examen

if object_id(N'dbo.crear_tablas', N'P') is not null drop procedure dbo.crear_tablas
go
create procedure dbo.crear_tablas as begin 

    set nocount on

    if object_id(N'dbo.Empleados', N'U') is null create table dbo.Empleados(
        id varchar(16) not null, 
        constraint empleados_id primary key(id), 
        constraint empleados_uq_id index unique(id)
    )

end
go

if object_id(N'dbo.filtrar_empleados', N'P') is not null drop procedure dbo.filtrar_empleados
go
create procedure dbo.filtrar_empleados 
    @filtrados varchar(max) output 
as begin 

    set nocount on

    select id from dbo.Empleados where id is not null and len(id) = 5
    set @filtrados = (select top 1 stuff((select ',' + id from dbo.Empleados where id is not null and len(id) = 5), 1, 1, '') as ids)

end
go

```

En MySQL/MariaDB:

```sql
use Examen;

delimiter ;^

    drop procedure if exists crear_tablas;^
    create procedure crear_tablas() begin 

        create table if not exists Empleados(
            id varchar(16) not null, 
            constraint empleados_id primary key(id)
        );

    end;^

    drop procedure if exists dbo.filtrar_empleados;^
    create procedure dbo.filtrar_empleados(
        out $filtrados text  
    ) begin 
        select id from Empleados where id is not null and lenght(id) = 5;
        set $filtrados := (select substring(ids, 1, length(ids)) as ids from (
            select group_concat(',', id) from Empleados where id is not null and lenght(id) = 5 as ids
        ) limit 1);
    end;^

delimiter ;

```

En SQLite no se puede de forma nativa, requerirías de estructuras que lo acompañen en otros lenguajes.

### Corrección

- **C#**: Muy buena implementación. Solo un detalle de "profesor tiquismiquis": en la clase `TicketUrxente` del ejercicio siguiente intentas acceder a `this.id`, pero en la clase base `Ticket` lo definimos como `private`. Para que la clase hija lo vea, debería ser `protected`.
- **Python**: Perfecto el uso de `@staticmethod` y `Optional`.
- **SQL Pro**: Me has dejado loco con el procedimiento de filtrado. Usar `STUFF` para quitar la primera coma es de nivel experto en oposiciones de sistemas.

## 2. Herdanza e Métodos (Tema 4):

Si la clase Ticket de antes era la base, ahora crea una clase TicketUrxente que herede de Ticket.

- Esta clase hija debe tener un constructor que pase el id a la clase padre (base).
- Sobreescribe o añade un método para que, además de lo anterior, devuelva un mensaje que diga: "Prioridade Máxima asignada ao Ticket [ID]".

### Respuesta

En C#:

```cs
using Examen;

namespace Examen{
    class TicketUrxente:Ticket{

        public TicketUrxente(int id):base(id){}

        public string coger_mensaje_completo(){
            return "Prioridade Máxima asinada ao Ticket [" + this.id + "]";
        }
        
    }
}
```

En Python:

```py
from typing import Self
from Examen import Ticket

class TicketUrxente(Ticket):

    def __init__(self:Self, id:int) -> None:
        super().__init__(id)

    def coger_mensaje_completo(self:Self) -> str:
        return "Prioridade Máxima asinada ao Ticket [" + str(self.id) + "]"

```

### Correción

- **C#**: Como te decía arriba, solo recuerda cambiar `private int id` por `protected int id` en la base para que el `TicketUrxente` pueda hacer el `+ this.id`.
- **Python**: Uso de `super().__init__(id)` perfecto.

# II. SQL SERVER: O RETORNO DO "FROM" (Tema 7)

3. A Consulta de Equipos:

Tenemos dos tablas:

- Equipos (id_equipo, nome_equipo, id_responsable)
- Responsables (id_responsable, nome_persona)

Escribe una consulta SQL que devuelva:

- El nome_equipo y el nome_persona del responsable.
- Pista: Necesitarás un JOIN. No te olvides del FROM.

## Respuesta

En SQL Server:

```sql
select 
    equipos.nome_equipo as equipo, 
    responsables.nome_persoa as responsable 
from dbo.Equipos equipos 
join dbo.Responsables resonsables on equipos.id_responsable = responsables.id_responsable
```

En MySQL/MariaDB y SQLite:

```sql
select 
    equipos.nome_equipo as equipo, 
    responsables.nome_persoa as responsable 
from Equipos equipos 
join Responsables resonsables on equipos.id_responsable = responsables.id_responsable
```

## Corrección

- **¡Objetivo cumplido!** El `FROM` está donde debe estar.
- **Ojo con los alias**: En el `JOIN` de SQL Server escribiste `resonsables` (te faltó la 'p') pero luego llamaste a `responsables.id_responsable`. Es un error de escritura (typo) típico del cansancio, pero la lógica del `ON` es impecable.

# III. PREGUNTA TRAMPA DE SISTEMAS (Tema 27)

4. Scripting en Bash:

Tienes que crear un script de una sola línea (o muy breve) que verifique si un archivo llamado backup_diario.sql existe en la carpeta actual. Si existe, que imprima "Ficheiro atopado".

## Respuesta

```bash
#!/bin/bash
[ -f backup_diario.sql ] && echo "Fichero atopado"
```

## Corrección

- **Perfecto**. El uso del operador AND lógico `&&` es la forma más profesional y rápida de hacer un "one-liner" en Bash para oposiciones.