Home Chi sono Portfolio 177 Laboratorio Contatti

Laboratorio · case study

Funnel di selezione: cosa dicono 10.000 candidature

L'export grezzo dell'ATS di una scale-up HR tech, pulito in SQL Server, verificato in Excel e letto con una dashboard. Dati fittizi.

1,3%
tasso di assunzione: 117 assunti su 8.999 candidature chiuse
CV 1 = CV 5
allo screening il voto del CV non cambia chi passa
61%
offerte rifiutate in un ruolo, dopo un task e tre colloqui
45–60 gg
per qualsiasi esito, anche un rifiuto sul CV
Il problema e l'approccio
Dati fittizi, forniti per un esercizio di selezione

Come esercizio di selezione ho ricevuto l'export grezzo dell'ATS di una scale-up HR tech: quasi 10.000 candidature su 7 ruoli, da gennaio 2025 a giugno 2026. La domanda era semplice: cosa funziona e cosa no nel processo di selezione?

Prima di rispondere ho dovuto sistemare i dati. Il 43% delle righe aveva almeno un problema: ruoli scritti in due modi, date con giorno e mese invertiti, bocciature registrate come ritiri, nessun ID candidato. Senza pulizia i due processi più grandi sarebbero risultati divisi a metà.

Ho usato l'AI per una prima lettura del file. Poi ho rifatto io, in SQL Server, la pulizia e i calcoli chiave, e li ho confrontati con l'analisi in Excel: un numero entra nel racconto solo quando i due strumenti danno lo stesso risultato. Una regola mi ha accompagnato dall'inizio: le colonne originali non si toccano, ogni correzione va in una colonna nuova, così ogni anomalia resta tracciabile fino all'origine.

Il video

I risultati e il funnel che proporrei, raccontati sulla dashboard in pochi minuti.

La dashboard

Cosa ho trovato

Scegli un tema: grafico, lettura e cosa cambierei.

Cosa significa

Cosa farei

Esplora il funnel per ruolo

Solo processi chiusi. Ogni barra è uno step: chi passa, chi viene bocciato, chi si ritira.

StepEntratiPassaRitiro

Il funnel che propongo

Meno step, ognuno con uno scopo, un criterio e un tempo massimo.

  1. Candidatura + knock-out

    Lingua, sede, disponibilità, RAL: domande sì/no automatiche.

    immediato
  2. Screening CV o portfolio

    Scorecard con 3 criteri, scala 1–4 descritta, passa con 3 o più.

    3 gg lavorativi
  3. Call di 20 minuti

    Motivazione, aspettative economiche e tempi, allineate prima di investire colloqui.

    entro 5 gg
  4. Task breve o test tecnico

    Massimo 3 ore, rubrica con soglia. Per i designer un case study, per gli engineer un test asincrono.

    correzione 48 h
  5. Colloquio competenze

    Con l'hiring manager, sul task e con la stessa rubrica: il voto motiva la decisione.

    feedback 48 h
  6. Colloquio finale

    Team o founder, due valutatori, una sola volta. Sostituisce Interview 2 e 3.

    feedback 48 h
  7. Offerta

    Già allineata dalla call iniziale, inviata subito dopo il colloquio finale.

    entro 48 h
Scala 1–4 descrittaNiente punto centrale: il 3 oggi è una zona grigia decisa caso per caso.
Calibrazione mensileConfronto tra voti e performance degli assunti a 6 mesi.
Processo in 21 giorniSLA per step e alert sui candidati fermi oltre la soglia.
ATS con dati pulitiRuoli da menu, ID univoco, date standard, motivo d'uscita obbligatorio.

Dati: export ATS di una scale-up HR tech (dati fittizi forniti per la selezione). Coorte chiusa = candidature 2025, tutte concluse; coorte aperta = candidature 2026, tutte ancora attive. Mediane dei tempi calcolate escludendo 353 righe con data di fine precedente alla candidatura. Analisi in SQL Server (script 01–03) ed Excel.

Tre query che raccontano l'analisi

Insieme alla dashboard ho consegnato tre script SQL commentati, dall'importazione alla verifica dei numeri. Qui sotto i tre passaggi più significativi.

1. Correggere solo le date sbagliate

Excel aveva già convertito una parte delle date leggendole come mese/giorno. In Excel ho marcato quelle celle con un flag, prima di qualsiasi modifica; in SQL inverto giorno e mese solo dove il flag vale 1.

-- In Excel, prima di toccare le date:  FlagIn = SE(VAL.NUMERO(C2);1;0)
-- 1 = cella che Excel aveva già trasformato in data (giorno e mese invertiti)

UPDATE dbo.[ATS Data]
SET DataIn = DATEFROMPARTS(YEAR(DataIn), DAY(DataIn), MONTH(DataIn))
WHERE FlagIn = 1;                   -- 3951 righe interessate

UPDATE dbo.[ATS Data]
SET DataOut = DATEFROMPARTS(YEAR(DataOut), DAY(DataOut), MONTH(DataOut))
WHERE FlagOut = 1;                  -- 3528 righe interessate

2. Il funnel per ruolo e step

Solo i processi chiusi: per ogni step conto chi ci è arrivato, chi è passato oltre e come sono finiti gli altri. Il numero dello step viene da una tabella di riferimento, perché ogni ruolo ha un percorso diverso.

WITH chiusi AS (
    SELECT * FROM dbo.[ATS Data] WHERE Status_Pulito <> 'Active'
)
SELECT o.Ruolo, o.N_Step, o.Step,
       SUM(CASE WHEN c.N_Step >= o.N_Step THEN 1 ELSE 0 END) AS entrati,
       SUM(CASE WHEN c.N_Step >  o.N_Step THEN 1 ELSE 0 END) AS passati,
       SUM(CASE WHEN c.N_Step =  o.N_Step AND c.Status_Pulito = 'Rejected' THEN 1 ELSE 0 END) AS rifiutati,
       SUM(CASE WHEN c.N_Step =  o.N_Step AND c.Status_Pulito = 'Dropped'  THEN 1 ELSE 0 END) AS ritirati,
       SUM(CASE WHEN c.N_Step =  o.N_Step AND c.Status_Pulito = 'Hired'    THEN 1 ELSE 0 END) AS assunti,
       CAST(100.0 * SUM(CASE WHEN c.N_Step > o.N_Step THEN 1 ELSE 0 END)
            / NULLIF(SUM(CASE WHEN c.N_Step >= o.N_Step THEN 1 ELSE 0 END), 0) AS DECIMAL(5,1)) AS pass_rate_pct
FROM dbo.Ordine_Step o
JOIN chiusi c ON c.Ruolo_Pulito = o.Ruolo
WHERE o.Step <> 'Call con team'
GROUP BY o.Ruolo, o.N_Step, o.Step
ORDER BY o.Ruolo, o.N_Step;

3. Il voto spiega la decisione?

Per ogni step confronto il voto medio di chi passa con quello di chi viene bocciato. Se le due medie coincidono, la decisione è stata presa fuori dal voto.

WITH valutati AS (
    SELECT o.Ruolo, o.N_Step, o.Step,
           CASE o.Col_Voto
                WHEN 'Val_CV'   THEN a.Val_CV
                WHEN 'Val_Task' THEN a.Val_Task
                WHEN 'Val_Int1' THEN a.Val_Int1
                WHEN 'Val_Int2' THEN a.Val_Int2
                WHEN 'Val_Int3' THEN a.Val_Int3
           END AS voto,
           CASE WHEN a.N_Step > o.N_Step THEN 1 ELSE 0 END AS passato
    FROM dbo.Ordine_Step o
    JOIN dbo.[ATS Data] a ON a.Ruolo_Pulito = o.Ruolo
    WHERE o.Col_Voto IS NOT NULL
      AND o.Step <> 'Call con team'
      AND a.Status_Pulito <> 'Active'
      AND (a.N_Step > o.N_Step
           OR (a.N_Step = o.N_Step AND a.Status_Pulito = 'Rejected'))
)
SELECT Ruolo, N_Step, Step,
       COUNT(*) AS valutati,
       CAST(AVG(CASE WHEN passato = 1 THEN voto * 1.0 END) AS DECIMAL(3,2)) AS media_passati,
       CAST(AVG(CASE WHEN passato = 0 THEN voto * 1.0 END) AS DECIMAL(3,2)) AS media_bocciati,
       SUM(CASE WHEN passato = 0 AND voto >= 4 THEN 1 ELSE 0 END) AS bocciati_con_4_5,
       SUM(CASE WHEN passato = 1 AND voto <= 2 THEN 1 ELSE 0 END) AS passati_con_1_2
FROM valutati
WHERE voto IS NOT NULL
GROUP BY Ruolo, N_Step, Step
ORDER BY Ruolo, N_Step;

-- Screening Software Engineer: passati 2,95 / bocciati 2,90  -> il voto CV non conta
-- Tech Interview SWE:          passati 3,76 / bocciati 3,76  -> si decide fuori dal voto
Cosa ho imparato
  • Il tentativo sbagliato sulle date è stato il più utile. La prima idea era una funzione SQL che riconoscesse le date invertite dal formato del testo. Non ha funzionato: nel CSV tutte le date erano uscite nello stesso formato, e l'informazione “questa cella era già una data” si era persa nell'esportazione. Una query di controllo sulle lunghezze lo ha dimostrato. Da lì la soluzione: marcare il dato dove l'informazione è ancora visibile, cioè in Excel, e correggere in SQL solo le righe marcate.
  • Prima pulire, poi analizzare. Senza unificare i ruoli, i due processi più grandi sarebbero risultati divisi a metà; senza correggere gli status, il Web Designer sarebbe sembrato un problema di abbandoni, mentre il suo task boccia 2 candidati su 3.
  • Un numero, due strumenti. Rifare i calcoli chiave in SQL e confrontarli con Excel richiede più tempo, ma è quello che permette di presentare un risultato senza dubbi. L'AI mi ha aiutato a partire in fretta; la verifica l'ho tenuta per me.

Aiuto le aziende a pulire i dati e a costruire dashboard e report che si possono verificare, numero per numero. Se hai un export che non torna, raccontamelo.