2ebc9efeb2
- scratchpad/gen_docs.py - scratchpad/gen_intel.py - scratchpad/gen_verify.py - scratchpad/intel_build.json - scratchpad/intel_lineage.json - scratchpad/lineage_graph.json - scratchpad/trace_intel.py - scratchpad/trace_lineage.py Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
472 lines
130 KiB
JSON
472 lines
130 KiB
JSON
{
|
|
"_margen_rate_producto": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel._margen_rate_producto` AS\n WITH clean AS (\n SELECT prod_nav_id, venta_n, compra_n, tasas\n FROM `autingo-159109.anjana_bi_amg.base_margenes_aa`\n WHERE venta_n > 0 AND compra_n <= 3 * venta_n\n )\n SELECT\n prod_nav_id,\n ROUND((SUM(venta_n) - SUM(compra_n) - SUM(tasas)) / SUM(venta_n), 4) AS margen_rate\n FROM clean\n GROUP BY prod_nav_id\n HAVING SUM(venta_n) > 0",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 09:42:03.770000+00:00",
|
|
"refs": [
|
|
"anjana_bi_amg.margenes_mat"
|
|
]
|
|
},
|
|
"_persona_records": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel._persona_records` AS\n WITH records AS (\n \n SELECT 'tpv' AS src, CAST(id AS STRING) AS source_id,\n document_number AS doc_raw, entity_email AS email_raw, entity_phone_number AS phone_raw,\n TRIM(CONCAT(COALESCE(entity_name,''),' ',COALESCE(entity_last_name,''))) AS name,\n CAST(NULL AS STRING) AS cp, customer_type,\n salesforce_customer_id AS salesforce_id, nav_id,\n CAST(NULL AS BOOL) AS email_optout, CAST(NULL AS BOOL) AS sms_optout,\n CAST(NULL AS BOOL) AS wa_optout, CAST(NULL AS BOOL) AS donotcall\n FROM `autingo-159109.psql_dcpublic.tpv_customers`\n WHERE deleted_at IS NULL\n \nUNION ALL\n\n SELECT 'web', CAST(id AS STRING),\n document, CAST(NULL AS STRING), phone_number,\n name, postal_code, CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS STRING),\n NULL, NULL, NULL, NULL\n FROM `autingo-159109.psql_dcpublic.customers`\n WHERE deleted_at IS NULL AND document != CAST(id AS STRING)\n \nUNION ALL\n\n SELECT 'otr', CAST(id AS STRING),\n dni, CAST(NULL AS STRING), telephone,\n full_name, CAST(NULL AS STRING), CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS STRING),\n NULL, NULL, NULL, NULL\n FROM `autingo-159109.psql_dcpublic.otr_customers`\n \nUNION ALL\n\n SELECT 'navision', no_,\n no_ AS doc_raw, e_mail, movil,\n name, post_code, CAST(NULL AS INT64),\n CAST(NULL AS STRING), no_,\n NULL, NULL, NULL, NULL\n FROM `autingo-159109.mssql2022_dbo.anjana_customer`\n WHERE _fivetran_deleted IS NOT TRUE\n \nUNION ALL\n\n SELECT 'citaprevia', CAST(id AS STRING),\n numero_doc_identidad, email, telefono1,\n nombre, codigo_postal, CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS STRING),\n NULL, NULL, NULL, NULL\n FROM `autingo-159109.citaprevia_aurphcp.clientes`\n WHERE _fivetran_deleted IS NOT TRUE\n \nUNION ALL\n\n SELECT 'users', CAST(id AS STRING),\n CAST(NULL AS STRING), email, CAST(NULL AS STRING),\n CAST(NULL AS STRING), CAST(NULL AS STRING), CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS STRING),\n NULL, NULL, NULL, NULL\n FROM `autingo-159109.psql_dcpublic.users`\n \nUNION ALL\n\n SELECT 'salesforce', ContactId,\n CAST(NULL AS STRING), Email, Phone,\n TRIM(CONCAT(COALESCE(FirstName,''),' ',COALESCE(LastName,''))), CAST(NULL AS STRING), CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS STRING),\n SAFE_CAST(EmailOptOut AS BOOL), SAFE_CAST(SMSOptOut AS BOOL),\n SAFE_CAST(WhatsappOptOut AS BOOL), SAFE_CAST(DoNotCall AS BOOL)\n FROM `autingo-159109.salesforce_ew1.contacts_latest`\n \n ),\n norm AS (\n SELECT\n src, source_id, name, cp, customer_type, salesforce_id, nav_id,\n email_optout, sms_optout, wa_optout, donotcall,\n IF(((REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, r'^[0-9]{8}[A-Z]$') AND SUBSTR('TRWAGMYFPDXBNJZSQVHLCKE', MOD(CAST(SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 1, 8) AS INT64), 23) + 1, 1) = SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 9, 1)) OR (REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, r'^[XYZ][0-9]{7}[A-Z]$') AND SUBSTR('TRWAGMYFPDXBNJZSQVHLCKE', MOD(CAST(CONCAT(CASE SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 1, 1) WHEN 'X' THEN '0' WHEN 'Y' THEN '1' ELSE '2' END, SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 2, 7)) AS INT64), 23) + 1, 1) = SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 9, 1)) OR (REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, r'^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$'))), CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, NULL) AS doc,\n IF(REGEXP_CONTAINS(LOWER(TRIM(email_raw)), r'^[a-z0-9._%+\\-]+@[a-z0-9.\\-]+\\.[a-z]{2,}$')\n AND NOT REGEXP_CONTAINS(SPLIT(LOWER(TRIM(email_raw)),'@')[OFFSET(0)], r'(noquiere|nokiere|sincorreo|scorreo|nocorreo|sinemail|noemail|nomail|sinmail|notiene|notengo|nofacilita|nointeresa|noprocede|nocliente|nocomras|nodispone|sininformar|sinnombre|sinquerer|^no(lo|se|me|le)?(sabe|desea|quiere|quiero|quier|posee|hay|usa|da|tien|tine|tene|consta|aporta|facilita|funciona|informa|movil|telefono|contesta|contacto|email|mail|correo))')\n AND NOT REGEXP_CONTAINS(SPLIT(LOWER(TRIM(email_raw)),'@')[OFFSET(0)], r'^(no|nose|nada|ninguno|ninguna|test|prueba|asdf|qwerty|xxx+|aaa+|na|nn|n)$')\n AND SPLIT(LOWER(TRIM(email_raw)),'@')[OFFSET(1)] NOT IN ('correo.es','correo.com','no.com','no.es','no.no','notiene.com','notiene.es','noquiere.com','noquiere.es','sincorreo.es','sincorreo.com','tiene.com','n.com','nop.com','nmo.com','noi.com','x.com','xxx.com','test.com','prueba.com','email.com','aurgi.com','nodesea.com')\n AND NOT REGEXP_CONTAINS(SPLIT(LOWER(TRIM(email_raw)),'@')[OFFSET(1)], r'^(aurgi\\.com|correo\\.|no\\.|notiene\\.|noquiere\\.|sincorreo\\.|nodesea\\.)'),\n LOWER(TRIM(email_raw)), NULL) AS email,\n IF(REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^0034[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 5) WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^34[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 3) ELSE REGEXP_REPLACE(phone_raw, r'[^0-9]', '') END, r'^[6789][0-9]{8}$') AND REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^0034[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 5) WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^34[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 3) ELSE REGEXP_REPLACE(phone_raw, r'[^0-9]', '') END, r'^[67][0-9]{8}$'), CASE WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^0034[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 5) WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^34[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 3) ELSE REGEXP_REPLACE(phone_raw, r'[^0-9]', '') END, NULL) AS phone_fuse,\n IF(REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^0034[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 5) WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^34[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 3) ELSE REGEXP_REPLACE(phone_raw, r'[^0-9]', '') END, r'^[6789][0-9]{8}$'), CASE WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^0034[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 5) WHEN REGEXP_CONTAINS(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), r'^34[6789][0-9]{8}$') THEN SUBSTR(REGEXP_REPLACE(phone_raw, r'[^0-9]', ''), 3) ELSE REGEXP_REPLACE(phone_raw, r'[^0-9]', '') END, NULL) AS phone_any,\n CASE WHEN REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, r'^[0-9]{8}[A-Z]$') AND SUBSTR('TRWAGMYFPDXBNJZSQVHLCKE', MOD(CAST(SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 1, 8) AS INT64), 23) + 1, 1) = SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 9, 1) THEN 'DNI' WHEN REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, r'^[XYZ][0-9]{7}[A-Z]$') AND SUBSTR('TRWAGMYFPDXBNJZSQVHLCKE', MOD(CAST(CONCAT(CASE SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 1, 1) WHEN 'X' THEN '0' WHEN 'Y' THEN '1' ELSE '2' END, SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 2, 7)) AS INT64), 23) + 1, 1) = SUBSTR(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, 9, 1) THEN 'NIE' WHEN REGEXP_CONTAINS(CASE WHEN REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')), r'^[0-9]{7}[A-Z]$') THEN CONCAT('0', UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', ''))) ELSE UPPER(REGEXP_REPLACE(TRIM(doc_raw), r'[\\s\\.\\-]', '')) END, r'^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$') THEN 'CIF' ELSE 'INVALIDO' END AS doc_kind\n FROM records\n ),\n email_stats AS (\n SELECT email, COUNT(DISTINCT doc) AS ndoc, MIN(doc) AS doc1, COUNT(*) AS nrec\n FROM norm WHERE email IS NOT NULL GROUP BY email\n ),\n phone_stats AS (\n SELECT phone_fuse, COUNT(DISTINCT doc) AS ndoc, MIN(doc) AS doc1, COUNT(*) AS nrec\n FROM norm WHERE phone_fuse IS NOT NULL GROUP BY phone_fuse\n ),\n assigned AS (\n SELECT\n n.*,\n CASE\n WHEN n.doc IS NOT NULL THEN CONCAT('DOC:', n.doc)\n WHEN n.email IS NOT NULL AND es.ndoc = 1 THEN CONCAT('DOC:', es.doc1)\n WHEN n.phone_fuse IS NOT NULL AND ps.ndoc = 1 THEN CONCAT('DOC:', ps.doc1)\n WHEN n.email IS NOT NULL AND es.ndoc = 0 AND es.nrec <= 5\n THEN CONCAT('EMAIL:', n.email)\n WHEN n.phone_fuse IS NOT NULL AND ps.ndoc = 0 AND ps.nrec <= 5\n THEN CONCAT('PHONE:', n.phone_fuse)\n ELSE CONCAT('REC:', n.src, ':', n.source_id)\n END AS persona_key,\n CASE\n WHEN n.doc IS NOT NULL THEN 'alta'\n WHEN (n.email IS NOT NULL AND es.ndoc = 1)\n OR (n.phone_fuse IS NOT NULL AND ps.ndoc = 1) THEN 'media'\n WHEN (n.email IS NOT NULL AND es.ndoc = 0 AND es.nrec <= 5)\n OR (n.phone_fuse IS NOT NULL AND ps.ndoc = 0 AND ps.nrec <= 5)\n THEN 'media'\n ELSE 'baja'\n END AS confianza\n FROM norm n\n LEFT JOIN email_stats es ON n.email = es.email\n LEFT JOIN phone_stats ps ON n.phone_fuse = ps.phone_fuse\n )\n SELECT\n FARM_FINGERPRINT(persona_key) AS persona_id,\n persona_key, confianza,\n src, source_id,\n doc, doc_kind, email, phone_fuse, phone_any,\n name, cp, customer_type, salesforce_id, nav_id,\n email_optout, sms_optout, wa_optout, donotcall\n FROM assigned",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:47:03.046000+00:00",
|
|
"refs": [
|
|
"citaprevia_aurphcp.clientes",
|
|
"mssql2022_dbo.anjana_customer",
|
|
"psql_dcpublic.customers",
|
|
"psql_dcpublic.otr_customers",
|
|
"psql_dcpublic.tpv_customers",
|
|
"psql_dcpublic.users",
|
|
"salesforce_ew1.contacts_latest"
|
|
]
|
|
},
|
|
"_plate_year_calib": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel._plate_year_calib` AS\n WITH raw AS (\n SELECT ((STRPOS('BCDFGHJKLMNPRSTVWXYZ', SUBSTR(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')),5,1))-1)*400 + (STRPOS('BCDFGHJKLMNPRSTVWXYZ', SUBSTR(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')),6,1))-1)*20 + (STRPOS('BCDFGHJKLMNPRSTVWXYZ', SUBSTR(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')),7,1))-1)) AS ord, year\n FROM `autingo-159109.clientes_intel.dim_vehiculo`\n WHERE REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') AND year BETWEEN 1998 AND EXTRACT(YEAR FROM CURRENT_DATE())\n ),\n per_ord AS (\n SELECT ord, APPROX_QUANTILES(year, 2)[OFFSET(1)] AS y, COUNT(*) AS n\n FROM raw GROUP BY ord\n ),\n grid AS (SELECT ord FROM UNNEST(GENERATE_ARRAY(0, 7999)) AS ord),\n smooth AS (\n SELECT g.ord,\n (SELECT SUM(p.y * p.n) / SUM(p.n) FROM per_ord p\n WHERE p.ord BETWEEN g.ord - 150 AND g.ord + 150) AS y_smooth\n FROM grid g\n ),\n filled AS (\n SELECT ord,\n COALESCE(\n y_smooth,\n LAST_VALUE(y_smooth IGNORE NULLS) OVER (ORDER BY ord ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),\n FIRST_VALUE(y_smooth IGNORE NULLS) OVER (ORDER BY ord ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)\n ) AS y_fill\n FROM smooth\n )\n SELECT\n ord AS serie_ord,\n CAST(ROUND(MAX(y_fill) OVER (ORDER BY ord ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) AS INT64) AS anio_estimado\n FROM filled",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 09:42:19.481000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_vehiculo"
|
|
]
|
|
},
|
|
"_presupuesto_persona": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel._presupuesto_persona` AS\nWITH x AS (\n SELECT TRIM(nav) AS nav_id, customer_id\n FROM `autingo-159109.claude_bi.conversion_cqg_base_mat`,\n UNNEST(SPLIT(origin_otr_nav_ids, ',')) AS nav\n WHERE origin_otr_nav_ids IS NOT NULL AND customer_id IS NOT NULL\n)\nSELECT DISTINCT x.nav_id, m.persona_id\nFROM x JOIN `autingo-159109.clientes_intel.map_persona_fuente` m\n ON m.fuente='tpv' AND m.source_id = CAST(x.customer_id AS STRING)\nWHERE x.nav_id != ''",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-09 11:15:04.102000+00:00",
|
|
"refs": [
|
|
"claude_bi.conversion_cqg_base_mat",
|
|
"clientes_intel.map_persona_fuente"
|
|
]
|
|
},
|
|
"_veh_cluster_feat": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel._veh_cluster_feat` AS\nSELECT\n vehiculo_id,\n COALESCE(antiguedad_anios, 15) AS antiguedad_anios,\n COALESCE(n_visitas, 0) AS n_visitas,\n LN(1 + GREATEST(COALESCE(importe_total, 0), 0)) AS log_importe,\n COALESCE(recency_days, 3650) AS recency_days,\n COALESCE(n_categorias, 0) AS n_categorias,\n COALESCE(pct_servicio, 0) AS pct_servicio,\n COALESCE(combustible, 'Desconocido') AS combustible\nFROM `autingo-159109.clientes_intel.feat_cliente_vehiculo`",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:46:06.819000+00:00",
|
|
"refs": [
|
|
"clientes_intel.feat_cliente_vehiculo"
|
|
]
|
|
},
|
|
"_veh_km_k5": {
|
|
"query": "DROP MODEL IF EXISTS `autingo-159109.clientes_intel._veh_km_k5`",
|
|
"stmt": "DROP_MODEL",
|
|
"last_run": "2026-06-11 14:57:01.905000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_km_k6": {
|
|
"query": "DROP MODEL IF EXISTS `autingo-159109.clientes_intel._veh_km_k6`",
|
|
"stmt": "DROP_MODEL",
|
|
"last_run": "2026-06-11 14:57:02.308000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_km_k7": {
|
|
"query": "CREATE OR REPLACE MODEL `autingo-159109.clientes_intel._veh_km_k7`\n OPTIONS(model_type='kmeans', num_clusters=7,\n standardize_features=TRUE, kmeans_init_method='KMEANS++') AS\n SELECT * EXCEPT(vehiculo_id) FROM `autingo-159109.clientes_intel._veh_cluster_feat`",
|
|
"stmt": "CREATE_MODEL",
|
|
"last_run": "2026-06-11 14:38:19.112000+00:00",
|
|
"refs": [
|
|
"clientes_intel._veh_cluster_feat"
|
|
]
|
|
},
|
|
"_veh_km_k8": {
|
|
"query": "DROP MODEL IF EXISTS `autingo-159109.clientes_intel._veh_km_k8`",
|
|
"stmt": "DROP_MODEL",
|
|
"last_run": "2026-06-11 14:57:02.709000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_km_tec_k4": {
|
|
"query": "CREATE OR REPLACE MODEL `autingo-159109.clientes_intel._veh_km_tec_k4`\n OPTIONS(model_type='kmeans', num_clusters=4,\n standardize_features=TRUE, kmeans_init_method='KMEANS++') AS\n SELECT * EXCEPT(vehiculo_id) FROM `autingo-159109.clientes_intel._veh_tec_feat`",
|
|
"stmt": "CREATE_MODEL",
|
|
"last_run": "2026-06-11 14:52:15.736000+00:00",
|
|
"refs": [
|
|
"clientes_intel._veh_tec_feat"
|
|
]
|
|
},
|
|
"_veh_km_tec_k5": {
|
|
"query": "DROP MODEL IF EXISTS `autingo-159109.clientes_intel._veh_km_tec_k5`",
|
|
"stmt": "DROP_MODEL",
|
|
"last_run": "2026-06-11 14:57:03.402000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_km_tec_k6": {
|
|
"query": "DROP MODEL IF EXISTS `autingo-159109.clientes_intel._veh_km_tec_k6`",
|
|
"stmt": "DROP_MODEL",
|
|
"last_run": "2026-06-11 14:57:03.789000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_km_tec_k7": {
|
|
"query": "DROP MODEL IF EXISTS `autingo-159109.clientes_intel._veh_km_tec_k7`",
|
|
"stmt": "DROP_MODEL",
|
|
"last_run": "2026-06-11 14:57:04.478000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_tec_assign": {
|
|
"query": "DROP TABLE IF EXISTS `autingo-159109.clientes_intel._veh_tec_assign`",
|
|
"stmt": "DROP_TABLE",
|
|
"last_run": "2026-06-11 14:57:05.227000+00:00",
|
|
"refs": []
|
|
},
|
|
"_veh_tec_feat": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel._veh_tec_feat` AS\nWITH med AS (\n SELECT APPROX_QUANTILES(tec_potencia_kw, 2)[OFFSET(1)] AS kw_med,\n APPROX_QUANTILES(tec_co2, 2)[OFFSET(1)] AS co2_med\n FROM `autingo-159109.clientes_intel.feat_cliente_vehiculo`\n WHERE tec_cilindrada IS NOT NULL\n)\nSELECT\n f.vehiculo_id,\n f.antiguedad_anios,\n f.tec_cilindrada,\n COALESCE(f.tec_potencia_kw, med.kw_med) AS potencia_kw,\n COALESCE(f.tec_co2, med.co2_med) AS co2,\n f.tec_plazas,\n COALESCE(f.combustible, 'Desconocido') AS combustible,\n COALESCE(f.tec_segmento, 'Desconocido') AS segmento,\n COALESCE(f.tec_tipo, 'Desconocido') AS tipo\nFROM `autingo-159109.clientes_intel.feat_cliente_vehiculo` f, med\nWHERE f.tec_cilindrada IS NOT NULL",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:46:08.832000+00:00",
|
|
"refs": [
|
|
"clientes_intel.feat_cliente_vehiculo"
|
|
]
|
|
},
|
|
"_xr_test": {
|
|
"query": "DROP TABLE `autingo-159109.clientes_intel._xr_test`",
|
|
"stmt": "DROP_TABLE",
|
|
"last_run": "2026-06-17 13:36:12.380000+00:00",
|
|
"refs": []
|
|
},
|
|
"audit_persona_divergencias": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.audit_persona_divergencias` AS\n WITH dim_docs AS (\n SELECT DISTINCT document_number AS doc FROM `autingo-159109.clientes_intel.dim_persona` WHERE document_number IS NOT NULL\n ),\n uni_docs AS (\n SELECT DISTINCT UPPER(REGEXP_REPLACE(TRIM(document_number), r'[\\s\\.\\-]', '')) AS doc\n FROM `autingo-159109.claude_bi.unified_customers`\n WHERE document_number IS NOT NULL AND TRIM(document_number) != ''\n )\n SELECT\n COALESCE(d.doc, u.doc) AS doc,\n d.doc IS NOT NULL AS en_dim_persona,\n u.doc IS NOT NULL AS en_unified\n FROM dim_docs d\n FULL OUTER JOIN uni_docs u USING (doc)",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:47:31.137000+00:00",
|
|
"refs": [
|
|
"claude_bi.unified_customers",
|
|
"clientes_intel.dim_persona"
|
|
]
|
|
},
|
|
"calidad_email_snapshot": {
|
|
"query": "MERGE `autingo-159109.clientes_intel.calidad_email_snapshot` T\nUSING (\n SELECT CURRENT_DATE() AS fecha,\n COUNT(*) AS total_clientes,\n COUNTIF(email IS NOT NULL) AS email_validos,\n COUNTIF(contactable_email) AS email_contactables,\n COUNTIF(email IS NOT NULL AND email_optout) AS email_optout,\n COUNTIF(email IS NULL) AS sin_email,\n ROUND(COUNTIF(email IS NOT NULL)/COUNT(*),4) AS pct_email_valido,\n ROUND(COUNTIF(contactable_email)/COUNT(*),4) AS pct_email_contactable,\n COUNTIF(phone IS NOT NULL) AS tel_validos,\n COUNTIF(contactable_telefono) AS tel_contactables\n FROM `autingo-159109.clientes_intel.seg_cliente_360`\n) S\nON T.fecha = S.fecha\nWHEN MATCHED THEN UPDATE SET\n total_clientes=S.total_clientes, email_validos=S.email_validos,\n email_contactables=S.email_contactables, email_optout=S.email_optout,\n sin_email=S.sin_email, pct_email_valido=S.pct_email_valido,\n pct_email_contactable=S.pct_email_contactable,\n tel_validos=S.tel_validos, tel_contactables=S.tel_contactables\nWHEN NOT MATCHED THEN INSERT ROW;\n",
|
|
"stmt": "MERGE",
|
|
"last_run": "2026-07-01 08:40:01.538000+00:00",
|
|
"refs": [
|
|
"clientes_intel.seg_cliente_360"
|
|
]
|
|
},
|
|
"data_points_contacto": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.data_points_contacto`\n CLUSTER BY es_b2c, persona_id AS\n WITH\n src_agg AS (\n SELECT persona_id,\n COUNT(DISTINCT IF(email IS NOT NULL, src, NULL)) AS n_src_email,\n COUNT(DISTINCT IF(phone_any IS NOT NULL, src, NULL)) AS n_src_phone,\n LOGICAL_OR(phone_fuse IS NOT NULL) AS tiene_movil\n FROM `autingo-159109.clientes_intel._persona_records` GROUP BY persona_id\n ),\n email_share AS (\n SELECT email, COUNT(DISTINCT persona_id) AS np\n FROM `autingo-159109.clientes_intel._persona_records` WHERE email IS NOT NULL GROUP BY email\n ),\n phone_share AS (\n SELECT phone_any, COUNT(DISTINCT persona_id) AS np\n FROM `autingo-159109.clientes_intel._persona_records` WHERE phone_any IS NOT NULL GROUP BY phone_any\n ),\n veh AS (SELECT persona_id, COUNT(*) AS nv FROM `autingo-159109.clientes_intel.map_persona_vehiculo` GROUP BY persona_id),\n feat AS (\n SELECT persona_id, NOT es_excluido AS es_b2c, canal_preferido AS canal_entrada,\n CAST(NULL AS STRING) AS tipo_entrada,\n COALESCE(frequency, 0) AS frequency\n FROM `autingo-159109.clientes_intel.feat_cliente_persona`\n ),\n base AS (\n SELECT\n dp.persona_id,\n dp.document_number IS NOT NULL AS punto_dni,\n dp.email IS NOT NULL AS punto_email,\n dp.phone IS NOT NULL AS punto_telefono,\n dp.full_name IS NOT NULL AS punto_nombre,\n dp.postal_code IS NOT NULL AS punto_cp,\n COALESCE(v.nv, 0) > 0 AS punto_vehiculo,\n f.canal_entrada IS NOT NULL AS punto_canal,\n dp.num_fuentes >= 2 AS punto_multifuente,\n COALESCE(f.frequency, 0) >= 1 AS punto_historial,\n COALESCE(f.es_b2c, FALSE) AS es_b2c,\n f.canal_entrada, f.tipo_entrada,\n COALESCE(v.nv, 0) AS n_vehiculos,\n dp.document_kind, dp.confianza AS confianza_identidad, dp.num_fuentes,\n COALESCE(sa.n_src_email, 0) AS n_src_email,\n COALESCE(sa.n_src_phone, 0) AS n_src_phone,\n COALESCE(sa.tiene_movil, FALSE) AS tiene_movil,\n COALESCE(es.np, 0) AS email_n_personas,\n COALESCE(ps.np, 0) AS phone_n_personas,\n dp.email_optout, dp.sms_optout, dp.whatsapp_optout, dp.do_not_call\n FROM `autingo-159109.clientes_intel.dim_persona` dp\n LEFT JOIN src_agg sa USING (persona_id)\n LEFT JOIN email_share es ON dp.email = es.email\n LEFT JOIN phone_share ps ON dp.phone = ps.phone_any\n LEFT JOIN veh v USING (persona_id)\n LEFT JOIN feat f USING (persona_id)\n ),\n scored AS (\n SELECT *,\n CASE WHEN NOT punto_email THEN 0.0 ELSE ROUND(LEAST(1.0,\n 0.5 + 0.25*IF(n_src_email >= 2, 1, 0) + 0.25*IF(email_n_personas <= 1, 1, 0)), 2) END AS fiabilidad_email,\n CASE WHEN NOT punto_telefono THEN 0.0 ELSE ROUND(LEAST(1.0,\n 0.4 + 0.3*IF(tiene_movil, 1, 0) + 0.15*IF(n_src_phone >= 2, 1, 0)\n + 0.15*IF(phone_n_personas <= 1, 1, 0)), 2) END AS fiabilidad_telefono,\n CAST(punto_dni AS INT64) + CAST(punto_email AS INT64) + CAST(punto_telefono AS INT64) + CAST(punto_nombre AS INT64) + CAST(punto_cp AS INT64) + CAST(punto_vehiculo AS INT64) + CAST(punto_canal AS INT64) + CAST(punto_multifuente AS INT64) + CAST(punto_historial AS INT64) AS data_points\n FROM base\n )\n SELECT\n *,\n ROUND(0.4*CAST(punto_dni AS INT64) + 0.3*fiabilidad_email + 0.3*fiabilidad_telefono, 3) AS score_confianza_norm,\n CAST(ROUND(40*CAST(punto_dni AS INT64) + 30*fiabilidad_email + 30*fiabilidad_telefono) AS INT64) AS score_confianza,\n -- contactable (headline): B2C con EMAIL fiable y sin opt-out (canal de marketing\n -- escaso y accionable). El movil es casi universal -> se reporta aparte, no infla.\n es_b2c AND punto_email AND fiabilidad_email >= 0.75 AND NOT email_optout AS contactable,\n es_b2c AND punto_email AND fiabilidad_email >= 0.75 AND NOT email_optout AS contactable_email,\n es_b2c AND tiene_movil AND fiabilidad_telefono >= 0.75 AND NOT do_not_call AS contactable_telefono\n FROM scored;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 16:23:09.214000+00:00",
|
|
"refs": [
|
|
"clientes_intel._persona_records",
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.feat_cliente_persona",
|
|
"clientes_intel.map_persona_vehiculo"
|
|
]
|
|
},
|
|
"dim_cp_provincia": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.dim_cp_provincia` AS\nSELECT * FROM UNNEST([STRUCT<cp2 STRING, provincia STRING, ccaa STRING>('01','Araba/Alava','Pais Vasco'),('02','Albacete','Castilla-La Mancha'),('03','Alicante','Comunidad Valenciana'),('04','Almeria','Andalucia'),('05','Avila','Castilla y Leon'),('06','Badajoz','Extremadura'),('07','Illes Balears','Illes Balears'),('08','Barcelona','Cataluna'),('09','Burgos','Castilla y Leon'),('10','Caceres','Extremadura'),('11','Cadiz','Andalucia'),('12','Castellon','Comunidad Valenciana'),('13','Ciudad Real','Castilla-La Mancha'),('14','Cordoba','Andalucia'),('15','A Coruna','Galicia'),('16','Cuenca','Castilla-La Mancha'),('17','Girona','Cataluna'),('18','Granada','Andalucia'),('19','Guadalajara','Castilla-La Mancha'),('20','Gipuzkoa','Pais Vasco'),('21','Huelva','Andalucia'),('22','Huesca','Aragon'),('23','Jaen','Andalucia'),('24','Leon','Castilla y Leon'),('25','Lleida','Cataluna'),('26','La Rioja','La Rioja'),('27','Lugo','Galicia'),('28','Madrid','Comunidad de Madrid'),('29','Malaga','Andalucia'),('30','Murcia','Region de Murcia'),('31','Navarra','Navarra'),('32','Ourense','Galicia'),('33','Asturias','Asturias'),('34','Palencia','Castilla y Leon'),('35','Las Palmas','Canarias'),('36','Pontevedra','Galicia'),('37','Salamanca','Castilla y Leon'),('38','Santa Cruz de Tenerife','Canarias'),('39','Cantabria','Cantabria'),('40','Segovia','Castilla y Leon'),('41','Sevilla','Andalucia'),('42','Soria','Castilla y Leon'),('43','Tarragona','Cataluna'),('44','Teruel','Aragon'),('45','Toledo','Castilla-La Mancha'),('46','Valencia','Comunidad Valenciana'),('47','Valladolid','Castilla y Leon'),('48','Bizkaia','Pais Vasco'),('49','Zamora','Castilla y Leon'),('50','Zaragoza','Aragon'),('51','Ceuta','Ceuta'),('52','Melilla','Melilla')])",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-09 11:09:15.055000+00:00",
|
|
"refs": []
|
|
},
|
|
"dim_persona": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.dim_persona` AS\n WITH r AS (\n SELECT *, CASE src WHEN 'tpv' THEN 1 WHEN 'web' THEN 2 WHEN 'citaprevia' THEN 3 WHEN 'otr' THEN 4 WHEN 'navision' THEN 5 WHEN 'salesforce' THEN 6 WHEN 'users' THEN 7 ELSE 99 END AS prio, CASE confianza WHEN 'alta' THEN 1 WHEN 'media' THEN 2 WHEN 'baja' THEN 3 ELSE 9 END AS crank FROM `autingo-159109.clientes_intel._persona_records`\n )\n SELECT\n persona_id,\n CASE MIN(crank) WHEN 1 THEN 'alta' WHEN 2 THEN 'media' ELSE 'baja' END AS confianza,\n CASE\n WHEN STARTS_WITH(ANY_VALUE(persona_key), 'DOC:') THEN 'documento'\n WHEN STARTS_WITH(ANY_VALUE(persona_key), 'EMAIL:') THEN 'email'\n WHEN STARTS_WITH(ANY_VALUE(persona_key), 'PHONE:') THEN 'telefono'\n ELSE 'singleton'\n END AS metodo_match,\n ANY_VALUE(doc) AS document_number,\n ANY_VALUE(doc_kind) AS document_kind,\n ARRAY_AGG(name IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS full_name,\n ARRAY_AGG(email IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS email,\n ARRAY_AGG(phone_any IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS phone,\n ARRAY_AGG(cp IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS postal_code,\n LOGICAL_OR(customer_type = 1) OR ANY_VALUE(doc_kind) = 'CIF' AS es_empresa,\n ARRAY_AGG(salesforce_id IGNORE NULLS LIMIT 1)[SAFE_OFFSET(0)] AS salesforce_customer_id,\n ARRAY_AGG(nav_id IGNORE NULLS LIMIT 1)[SAFE_OFFSET(0)] AS tpv_nav_id,\n COALESCE(LOGICAL_OR(email_optout), FALSE) AS email_optout,\n COALESCE(LOGICAL_OR(sms_optout), FALSE) AS sms_optout,\n COALESCE(LOGICAL_OR(wa_optout), FALSE) AS whatsapp_optout,\n COALESCE(LOGICAL_OR(donotcall), FALSE) AS do_not_call,\n COUNT(DISTINCT src) AS num_fuentes,\n LOGICAL_OR(src = 'tpv') AS in_tpv,\n LOGICAL_OR(src = 'web') AS in_web,\n LOGICAL_OR(src = 'otr') AS in_otr,\n LOGICAL_OR(src = 'navision') AS in_navision,\n LOGICAL_OR(src = 'citaprevia') AS in_citaprevia,\n LOGICAL_OR(src = 'salesforce') AS in_salesforce,\n LOGICAL_OR(src = 'users') AS in_users\n FROM r\n GROUP BY persona_id",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:47:15.836000+00:00",
|
|
"refs": [
|
|
"clientes_intel._persona_records"
|
|
]
|
|
},
|
|
"dim_vehiculo": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.dim_vehiculo` AS\n WITH\n veh_tpv AS (\n SELECT\n UPPER(REGEXP_REPLACE(TRIM(v.license_plate), r'[\\s\\-]', '')) AS plate_norm, v.license_plate,\n cm.name AS make, cmod.name AS model, cmf.name AS model_family,\n cv.name AS version,\n -- v.fuel mezcla texto ('Diesel'...) y codigos numericos; nos quedamos solo el texto\n IF(REGEXP_CONTAINS(v.fuel, r'^[0-9]+$'), NULL, NULLIF(v.fuel,'')) AS fuel,\n SAFE_CAST(v.year AS INT64) AS year,\n v.car_frame, CAST(NULL AS INT64) AS km,\n cv.original_tyre_size AS tyre_size,\n 1 AS prio, 'tpv' AS src, v.created_at\n FROM `autingo-159109.psql_dcpublic.tpv_vehicles_vehicle` v\n LEFT JOIN `autingo-159109.psql_dcpublic.car_makes` cm ON v.car_make_id = cm.id\n LEFT JOIN `autingo-159109.psql_dcpublic.car_models` cmod ON v.car_model_id = cmod.id\n LEFT JOIN `autingo-159109.psql_dcpublic.car_model_families` cmf ON v.car_model_family_id = cmf.id\n LEFT JOIN `autingo-159109.psql_dcpublic.car_versions` cv ON v.car_version_id = cv.id\n WHERE (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(v.license_plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(v.license_plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n ),\n veh_otr AS (\n SELECT\n UPPER(REGEXP_REPLACE(TRIM(ov.license_plate), r'[\\s\\-]', '')) AS plate_norm, ov.license_plate,\n COALESCE(ov.brand_description, ov.brand) AS make,\n COALESCE(ov.model_description, ov.model) AS model,\n CAST(NULL AS STRING) AS model_family, CAST(NULL AS STRING) AS version,\n CAST(NULL AS STRING) AS fuel,\n SAFE_CAST(ov.year AS INT64) AS year,\n CAST(NULL AS STRING) AS car_frame, SAFE_CAST(ov.km AS INT64) AS km,\n CAST(NULL AS STRING) AS tyre_size,\n 2 AS prio, 'otr' AS src, ov.created_at\n FROM `autingo-159109.psql_dcpublic.otr_vehicles` ov\n WHERE (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(ov.license_plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(ov.license_plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n ),\n veh_lineas AS (\n SELECT\n UPPER(REGEXP_REPLACE(TRIM(otrs_unicas_por_order__plate), r'[\\s\\-]', '')) AS plate_norm,\n ANY_VALUE(otrs_unicas_por_order__plate) AS license_plate,\n CAST(NULL AS STRING), CAST(NULL AS STRING), CAST(NULL AS STRING), CAST(NULL AS STRING),\n CAST(NULL AS STRING), CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS INT64), CAST(NULL AS STRING),\n 3, 'lineas', MAX(fecha)\n FROM `autingo-159109.claude_bi.todos_datos_lineas_mat`\n WHERE (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(otrs_unicas_por_order__plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(otrs_unicas_por_order__plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n GROUP BY plate_norm\n ),\n veh_citaprevia AS (\n SELECT\n UPPER(REGEXP_REPLACE(TRIM(cm.matricula), r'[\\s\\-]', '')) AS plate_norm,\n ANY_VALUE(cm.matricula) AS license_plate,\n CAST(NULL AS STRING), CAST(NULL AS STRING), CAST(NULL AS STRING), CAST(NULL AS STRING),\n CAST(NULL AS STRING), CAST(NULL AS INT64),\n CAST(NULL AS STRING), CAST(NULL AS INT64), CAST(NULL AS STRING),\n 4, 'citaprevia', MAX(CAST(NULL AS TIMESTAMP))\n FROM `autingo-159109.citaprevia_aurphcp.clientes_matriculas` cm\n WHERE cm._fivetran_deleted IS NOT TRUE AND (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(cm.matricula), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(cm.matricula), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n GROUP BY plate_norm\n ),\n todos AS (\n SELECT * FROM veh_tpv\n UNION ALL SELECT * FROM veh_otr\n UNION ALL SELECT * FROM veh_lineas\n UNION ALL SELECT * FROM veh_citaprevia\n ),\n agg AS (\n SELECT\n plate_norm,\n ARRAY_AGG(license_plate IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS license_plate,\n ARRAY_AGG(make IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS make,\n ARRAY_AGG(model IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS model,\n ARRAY_AGG(model_family IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS model_family,\n ARRAY_AGG(version IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS version,\n ARRAY_AGG(fuel IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS fuel,\n ARRAY_AGG(year IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS year,\n ARRAY_AGG(car_frame IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS car_frame,\n MAX(km) AS km,\n ARRAY_AGG(tyre_size IGNORE NULLS ORDER BY prio LIMIT 1)[SAFE_OFFSET(0)] AS tyre_size,\n LOGICAL_OR(src = 'tpv') AS in_tpv,\n LOGICAL_OR(src = 'otr') AS in_otr,\n LOGICAL_OR(src = 'lineas') AS in_lineas,\n LOGICAL_OR(src = 'citaprevia') AS in_citaprevia\n FROM todos\n GROUP BY plate_norm\n ),\n tecrmi AS (\n -- 1 fila por matricula: aglutina el mejor vin (no nulo), el mejor vin_data (con tech_data)\n -- y el mejor license_plate_data (con .data > make_text), aunque vengan de consultas TecRMI distintas.\n -- vin_data/lpd se guardan como STRING JSON (ARRAY_AGG de JSON no soportado); JSON_VALUE acepta STRING.\n SELECT\n plate_norm,\n ARRAY_AGG(vin IGNORE NULLS ORDER BY vin_rank LIMIT 1)[SAFE_OFFSET(0)] AS vin,\n ARRAY_AGG(vd_str IGNORE NULLS ORDER BY vd_rank LIMIT 1)[SAFE_OFFSET(0)] AS vin_data,\n ARRAY_AGG(lpd_str IGNORE NULLS ORDER BY lpd_rank LIMIT 1)[SAFE_OFFSET(0)] AS lpd\n FROM (\n SELECT\n UPPER(REGEXP_REPLACE(TRIM(license_plate), r'[\\s\\-]', '')) AS plate_norm,\n NULLIF(TRIM(vin), '') AS vin,\n IF(vin_data IS NULL, NULL, TO_JSON_STRING(vin_data)) AS vd_str,\n IF(license_plate_data IS NULL, NULL, TO_JSON_STRING(license_plate_data)) AS lpd_str,\n IF(NULLIF(TRIM(vin), '') IS NOT NULL, 0, 1) AS vin_rank,\n IF(JSON_EXTRACT(vin_data, '$.tech_data') IS NOT NULL, 0, 1) AS vd_rank,\n CASE\n WHEN JSON_EXTRACT(license_plate_data, '$.data') IS NOT NULL THEN 0\n WHEN JSON_VALUE(license_plate_data, '$.make_text') IS NOT NULL THEN 1\n WHEN license_plate_data IS NOT NULL THEN 2\n ELSE 3\n END AS lpd_rank\n FROM `autingo-159109.psql_dcpublic.tecrmi_license_plates`\n )\n GROUP BY plate_norm\n )\n SELECT\n agg.*,\n COALESCE(NULLIF(TRIM(agg.car_frame), ''), t.vin) AS vin,\n CASE\n WHEN agg.car_frame IS NOT NULL AND TRIM(agg.car_frame) != '' THEN 'tpv'\n WHEN t.vin IS NOT NULL THEN 'tecrmi'\n ELSE NULL\n END AS vin_source,\n -- Ficha del vehiculo: TODO lo extraible de las DOS columnas JSON de TecRMI.\n -- vin_data.tech_data: \"DATOS TÉCNICOS DGT\" / \"IDENTIFICACIÓN VEHÍCULO\" (claves acentuadas)\n -- license_plate_data.data: DATOSTECNICOSDGT / IDENTIFICACION_VEHICULO / MATRICULA (claves sin acentos)\n -- license_plate_data flat: make_text / model_text / fuel / date\n COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".MARCA'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.MARCA'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.MARCA'),\n JSON_VALUE(t.lpd, '$.data.MATRICULA.Marca'),\n JSON_VALUE(t.lpd, '$.make_text')\n ) AS tec_marca,\n COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".MODELO'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.MODELO'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.MODELO'),\n JSON_VALUE(t.lpd, '$.data.MATRICULA.Modelo'),\n JSON_VALUE(t.lpd, '$.model_text')\n ) AS tec_modelo,\n NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".\"MODELO GENÉRICO\"'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.\"MODELO GENÉRICO\"')\n ), '-'), '') AS tec_modelo_generico,\n COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".COMBUSTIBLE'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.COMBUSTIBLE'),\n JSON_VALUE(t.lpd, '$.data.MATRICULA.Carburante'),\n JSON_VALUE(t.lpd, '$.fuel')\n ) AS tec_combustible,\n SAFE_CAST(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".CILINDRADA'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.CILINDRADA')\n ), '-') AS INT64) AS tec_cilindrada,\n NULLIF(SAFE_CAST(NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".KW'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.KW')\n ), '-'), '*******') AS FLOAT64), 0) AS tec_potencia_kw,\n SAFE_CAST(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".\"POTENCIA FISCAL\"'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.\"POTENCIA FISCAL\"')\n ), '-') AS FLOAT64) AS tec_potencia_fiscal,\n SAFE_CAST(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".CO2'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.CO2')\n ), '-') AS FLOAT64) AS tec_co2,\n SAFE_CAST(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".PLAZAS'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.PLAZAS')\n ), '-') AS INT64) AS tec_plazas,\n SAFE_CAST(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".\"PESO MAXIMO\"'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.\"PESO MAXIMO\"')\n ), '-') AS INT64) AS tec_peso_maximo,\n SAFE_CAST(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".TARA'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.TARA')\n ), '-') AS INT64) AS tec_tara,\n NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"DATOS TÉCNICOS DGT\".TIPO'),\n JSON_VALUE(t.lpd, '$.data.DATOSTECNICOSDGT.TIPO')\n ), '-'), '') AS tec_tipo,\n NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".SEGMENTO'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.SEGMENTO')\n ), '-'), '') AS tec_segmento,\n NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".MERCADO'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.MERCADO')\n ), '-'), '') AS tec_mercado,\n NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".PROCEDENCIA'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.PROCEDENCIA')\n ), '-'), '') AS tec_procedencia,\n NULLIF(NULLIF(COALESCE(\n JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".\"PROVINCIA MATRÍCULA\"'),\n JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.\"PROVINCIA MATRÍCULA\"')\n ), '-'), '') AS tec_provincia_matricula,\n COALESCE(\n SAFE.PARSE_DATE('%d/%m/%Y', NULLIF(JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".\"FECHA 1ª MATRÍCULA\"'), '00/00/0000')),\n SAFE.PARSE_DATE('%d/%m/%Y', NULLIF(JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.\"FECHA 1ª MATRÍCULA\"'), '00/00/0000'))\n ) AS tec_fecha_1a_matricula,\n COALESCE(\n SAFE.PARSE_DATE('%d/%m/%Y', NULLIF(JSON_VALUE(t.vin_data, '$.tech_data.\"IDENTIFICACIÓN VEHÍCULO\".\"FECHA MATRÍCULA\"'), '00/00/0000')),\n SAFE.PARSE_DATE('%d/%m/%Y', NULLIF(JSON_VALUE(t.lpd, '$.data.IDENTIFICACION_VEHICULO.\"FECHA MATRÍCULA\"'), '00/00/0000')),\n SAFE_CAST(JSON_VALUE(t.lpd, '$.date') AS DATE)\n ) AS tec_fecha_matricula,\n JSON_EXTRACT_STRING_ARRAY(t.vin_data, '$.ktypes') AS ktypes,\n JSON_EXTRACT_STRING_ARRAY(t.lpd, '$.car_versions') AS car_versions\n FROM agg\n LEFT JOIN tecrmi t USING (plate_norm)",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 15:00:13.035000+00:00",
|
|
"refs": [
|
|
"citaprevia_aurphcp.clientes_matriculas",
|
|
"claude_bi.todos_datos_lineas_mat",
|
|
"psql_dcpublic.car_makes",
|
|
"psql_dcpublic.car_model_families",
|
|
"psql_dcpublic.car_models",
|
|
"psql_dcpublic.car_versions",
|
|
"psql_dcpublic.otr_vehicles",
|
|
"psql_dcpublic.tecrmi_license_plates",
|
|
"psql_dcpublic.tpv_vehicles_vehicle"
|
|
]
|
|
},
|
|
"fact_campana_respuesta": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.fact_campana_respuesta`\n CLUSTER BY canal, persona_id AS\n WITH\n sent AS (\n SELECT CAST(SubscriberKey AS STRING) AS sk, EmailName AS campana,\n COUNT(*) AS n_enviados,\n COUNTIF(DateUndeliverable IS NOT NULL AND CAST(DateUndeliverable AS STRING) != '') AS n_rebotados,\n COUNTIF(DateUnsubscribed IS NOT NULL AND CAST(DateUnsubscribed AS STRING) != '') AS n_baja,\n MIN(DATE(SENT_Eventdate)) AS primera_fecha,\n MAX(DATE(SENT_Eventdate)) AS ultima_fecha\n FROM `autingo-159109.salesforce_ew1.email_sent`\n WHERE SubscriberKey IS NOT NULL\n GROUP BY sk, campana\n ),\n opened AS (\n SELECT CAST(SubscriberKey AS STRING) AS sk, EmailName AS campana, COUNT(*) AS n_abiertos\n FROM `autingo-159109.salesforce_ew1.email_opened` WHERE SubscriberKey IS NOT NULL GROUP BY sk, campana\n ),\n clicked AS (\n SELECT CAST(SubscriberKey AS STRING) AS sk, EmailName AS campana, COUNT(*) AS n_clicados\n FROM `autingo-159109.salesforce_ew1.email_clicked` WHERE SubscriberKey IS NOT NULL GROUP BY sk, campana\n ),\n email AS (\n SELECT 'EMAIL' AS canal, s.sk, s.campana, s.n_enviados,\n COALESCE(o.n_abiertos, 0) AS n_abiertos,\n COALESCE(c.n_clicados, 0) AS n_clicados,\n s.n_enviados - s.n_rebotados AS n_entregados, s.n_rebotados, s.n_baja,\n s.primera_fecha, s.ultima_fecha\n FROM sent s\n LEFT JOIN opened o USING (sk, campana)\n LEFT JOIN clicked c USING (sk, campana)\n ),\n sms AS (\n SELECT 'SMS' AS canal, CAST(SubscriberKey AS STRING) AS sk,\n campana,\n COUNTIF(Sent) AS n_enviados, 0 AS n_abiertos, 0 AS n_clicados,\n COUNTIF(Delivered) AS n_entregados, COUNTIF(Undelivered) AS n_rebotados, 0 AS n_baja,\n MIN(DATE(CreateDateTime)) AS primera_fecha, MAX(DATE(CreateDateTime)) AS ultima_fecha\n FROM `autingo-159109.salesforce_ew1.sms`\n WHERE SubscriberKey IS NOT NULL AND Outbound\n GROUP BY sk, campana\n ),\n eventos AS (\n SELECT * FROM email\n UNION ALL SELECT * FROM sms\n )\n SELECT\n p.persona_id,\n e.canal, e.campana,\n e.n_enviados, e.n_entregados, e.n_rebotados, e.n_baja,\n e.n_abiertos, e.n_clicados,\n SAFE_DIVIDE(e.n_abiertos, e.n_enviados) AS tasa_apertura,\n SAFE_DIVIDE(e.n_clicados, e.n_enviados) AS tasa_click,\n e.n_abiertos > 0 AS abrio,\n e.n_clicados > 0 AS clico,\n e.n_baja > 0 AS baja,\n e.primera_fecha, e.ultima_fecha\n FROM eventos e\n JOIN `autingo-159109.clientes_intel.dim_persona` p ON p.salesforce_customer_id = e.sk;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 10:28:04.473000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_persona",
|
|
"salesforce_ew1.email_clicked",
|
|
"salesforce_ew1.email_opened",
|
|
"salesforce_ew1.email_sent",
|
|
"salesforce_ew1.sms"
|
|
]
|
|
},
|
|
"fact_campana_respuesta__sfnew": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.fact_campana_respuesta__sfnew`\n CLUSTER BY canal, persona_id AS\n WITH\n sent AS (\n SELECT CAST(SubscriberKey AS STRING) AS sk, EmailName AS campana,\n COUNT(*) AS n_enviados,\n COUNTIF(DateUndeliverable IS NOT NULL AND CAST(DateUndeliverable AS STRING) != '') AS n_rebotados,\n COUNTIF(DateUnsubscribed IS NOT NULL AND CAST(DateUnsubscribed AS STRING) != '') AS n_baja,\n MIN(DATE(SENT_Eventdate)) AS primera_fecha,\n MAX(DATE(SENT_Eventdate)) AS ultima_fecha\n FROM `autingo-159109.salesforce_ew1.email_sent`\n WHERE SubscriberKey IS NOT NULL\n GROUP BY sk, campana\n ),\n opened AS (\n SELECT CAST(SubscriberKey AS STRING) AS sk, EmailName AS campana, COUNT(*) AS n_abiertos\n FROM `autingo-159109.salesforce_ew1.email_opened` WHERE SubscriberKey IS NOT NULL GROUP BY sk, campana\n ),\n clicked AS (\n SELECT CAST(SubscriberKey AS STRING) AS sk, EmailName AS campana, COUNT(*) AS n_clicados\n FROM `autingo-159109.salesforce_ew1.email_clicked` WHERE SubscriberKey IS NOT NULL GROUP BY sk, campana\n ),\n email AS (\n SELECT 'EMAIL' AS canal, s.sk, s.campana, s.n_enviados,\n COALESCE(o.n_abiertos, 0) AS n_abiertos,\n COALESCE(c.n_clicados, 0) AS n_clicados,\n s.n_enviados - s.n_rebotados AS n_entregados, s.n_rebotados, s.n_baja,\n s.primera_fecha, s.ultima_fecha\n FROM sent s\n LEFT JOIN opened o USING (sk, campana)\n LEFT JOIN clicked c USING (sk, campana)\n ),\n sms AS (\n SELECT 'SMS' AS canal, CAST(SubscriberKey AS STRING) AS sk,\n CAST(NULL AS STRING) AS campana,\n COUNTIF(Sent) AS n_enviados, 0 AS n_abiertos, 0 AS n_clicados,\n COUNTIF(Delivered) AS n_entregados, COUNTIF(Undelivered) AS n_rebotados, 0 AS n_baja,\n MIN(DATE(CreateDateTime)) AS primera_fecha, MAX(DATE(CreateDateTime)) AS ultima_fecha\n FROM `autingo-159109.salesforce_ew1.sms`\n WHERE SubscriberKey IS NOT NULL AND Outbound\n GROUP BY sk\n ),\n eventos AS (\n SELECT * FROM email\n UNION ALL SELECT * FROM sms\n )\n SELECT\n p.persona_id,\n e.canal, e.campana,\n e.n_enviados, e.n_entregados, e.n_rebotados, e.n_baja,\n e.n_abiertos, e.n_clicados,\n SAFE_DIVIDE(e.n_abiertos, e.n_enviados) AS tasa_apertura,\n SAFE_DIVIDE(e.n_clicados, e.n_enviados) AS tasa_click,\n e.n_abiertos > 0 AS abrio,\n e.n_clicados > 0 AS clico,\n e.n_baja > 0 AS baja,\n e.primera_fecha, e.ultima_fecha\n FROM eventos e\n JOIN `autingo-159109.clientes_intel.dim_persona` p ON p.salesforce_customer_id = e.sk;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-18 08:23:23.300000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_persona",
|
|
"salesforce_ew1.email_clicked",
|
|
"salesforce_ew1.email_opened",
|
|
"salesforce_ew1.email_sent",
|
|
"salesforce_ew1.sms"
|
|
]
|
|
},
|
|
"fact_impacto_campana": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.fact_impacto_campana`\nCLUSTER BY canal AS\nWITH resp AS (\n SELECT persona_id, canal, campana, ultima_fecha AS fecha_envio, abrio\n FROM `autingo-159109.clientes_intel.fact_campana_respuesta` WHERE ultima_fecha IS NOT NULL\n),\nper AS (\n SELECT r.canal, r.campana, r.persona_id, ANY_VALUE(r.abrio) AS abrio,\n MAX(IF(t.fecha > r.fecha_envio AND t.fecha <= DATE_ADD(r.fecha_envio, INTERVAL 30 DAY), 1, 0)) AS compro,\n SUM(IF(t.fecha > r.fecha_envio AND t.fecha <= DATE_ADD(r.fecha_envio, INTERVAL 30 DAY), t.importe, 0)) AS eur\n FROM resp r\n LEFT JOIN `autingo-159109.clientes_intel.fact_transaccion` t\n ON t.persona_id = r.persona_id AND t.fecha >= '2025-01-01'\n GROUP BY r.canal, r.campana, r.persona_id\n)\nSELECT canal, campana, COUNT(*) AS personas, COUNTIF(compro = 1) AS compradores,\n ROUND(AVG(CAST(abrio AS INT64)), 4) AS pct_abrio, ROUND(AVG(compro), 4) AS conversion,\n ROUND(AVG(IF(abrio, compro, NULL)), 4) AS conv_abridores,\n ROUND(AVG(IF(NOT abrio, compro, NULL)), 4) AS conv_no_abridores,\n ROUND(SUM(eur), 0) AS eur_atribuido,\n ROUND(SAFE_DIVIDE(SUM(eur), COUNT(*)), 2) AS eur_por_persona\nFROM per GROUP BY canal, campana;\n",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-18 09:42:09.008000+00:00",
|
|
"refs": [
|
|
"clientes_intel.fact_campana_respuesta",
|
|
"clientes_intel.fact_transaccion"
|
|
]
|
|
},
|
|
"fact_transaccion": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.fact_transaccion`\n PARTITION BY fecha\n CLUSTER BY persona_id, centro_nav_id AS\n WITH tpv_map AS (\n SELECT source_id, persona_id FROM `autingo-159109.clientes_intel.map_persona_fuente` WHERE fuente='tpv'\n ),\n base AS (\n SELECT\n l.orderitem_id AS transaccion_id,\n m.persona_id AS persona_orig, -- << era: AS persona_id\n IF((REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(l.otrs_unicas_por_order__plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(l.otrs_unicas_por_order__plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$')), UPPER(REGEXP_REPLACE(TRIM(l.otrs_unicas_por_order__plate), r'[\\s\\-]', '')), NULL) AS vehiculo_id,\n l.Tpv_Customers___Customer__id AS customer_id_tpv,\n DATE(l.fecha) AS fecha,\n l.Centros___Center__nav_id AS centro_nav_id,\n l.Centros___Center__name AS centro_nombre,\n l.Centros___Center__Companies__name AS empresa,\n l.Centros___Center__Zones__name AS zona,\n IF(l.Centros___Center__Companies__name LIKE 'Digital%', 'web', 'tienda') AS canal,\n l.Productos___Product__Producto___Nav__idCategoria AS categoria,\n l.Productos___Product__Producto___Nav__idGrupo AS grupo,\n l.Productos___Product__nav_id AS producto_nav_id,\n l.Productos___Product__description AS producto_desc,\n l.Tpv_Orders_Orderitem__quantity AS cantidad,\n l.valor_linea AS importe,\n l.Total_Linea_con_Iva AS importe_con_iva,\n l.Coste_medio_de_producto_en_la_venta AS coste_unitario,\n ROUND(l.Coste_medio_de_producto_en_la_venta * l.Tpv_Orders_Orderitem__quantity, 4) AS coste_linea_aprox,\n l.otrs_unicas_por_order__Id_de_OTR AS id_otr,\n l.otrs_unicas_por_order__Status_de_Otr AS otr_status,\n l.nav_id AS id_factura_nav,\n l.otrs_unicas_por_order__nav_id AS otr_nav_id,\n 'TPV' AS origen\n FROM `autingo-159109.claude_bi.todos_datos_lineas_mat` l\n LEFT JOIN tpv_map m\n ON CAST(l.Tpv_Customers___Customer__id AS STRING) = m.source_id\n WHERE l.fecha IS NOT NULL\n )\n SELECT\n b.* EXCEPT(persona_orig),\n COALESCE(mm.particular_persona_id, b.persona_orig) AS persona_id -- << reasignacion solo-mutua\n FROM base b\n LEFT JOIN `autingo-159109.clientes_intel.map_mutualista_particular` mm\n ON mm.agregador_persona_id = b.persona_orig\n AND mm.plate_norm = b.vehiculo_id\n AND mm.es_mutualista",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 15:14:05.960000+00:00",
|
|
"refs": [
|
|
"claude_bi.todos_datos_lineas_mat",
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.map_persona_fuente",
|
|
"clientes_intel.map_persona_vehiculo"
|
|
]
|
|
},
|
|
"fact_transaccion_test": {
|
|
"query": "DROP TABLE IF EXISTS `autingo-159109.clientes_intel.fact_transaccion_test`",
|
|
"stmt": "DROP_TABLE",
|
|
"last_run": "2026-06-08 15:41:28.750000+00:00",
|
|
"refs": []
|
|
},
|
|
"fact_visita": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.fact_visita`\n PARTITION BY fecha\n CLUSTER BY persona_id AS\n SELECT\n persona_id,\n fecha,\n SUM(importe) AS importe_dia,\n COUNT(*) AS n_lineas,\n COUNT(DISTINCT id_otr) AS n_otr,\n COUNT(DISTINCT centro_nav_id) AS n_centros,\n COUNT(DISTINCT vehiculo_id) AS n_vehiculos,\n ARRAY_AGG(vehiculo_id IGNORE NULLS ORDER BY importe DESC LIMIT 1)[SAFE_OFFSET(0)] AS vehiculo_principal,\n ARRAY_AGG(centro_nav_id IGNORE NULLS ORDER BY importe DESC LIMIT 1)[SAFE_OFFSET(0)] AS centro_principal,\n ARRAY_AGG(empresa IGNORE NULLS ORDER BY importe DESC LIMIT 1)[SAFE_OFFSET(0)] AS empresa_principal\n FROM `autingo-159109.clientes_intel.fact_transaccion`\n WHERE persona_id IS NOT NULL\n GROUP BY persona_id, fecha",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 15:14:28.749000+00:00",
|
|
"refs": [
|
|
"clientes_intel.fact_transaccion"
|
|
]
|
|
},
|
|
"feat_cliente_persona": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.feat_cliente_persona`\n CLUSTER BY rfm_segment, persona_id AS\n WITH\n excluir_tpv AS (\n SELECT CAST(id AS STRING) AS source_id\n FROM `autingo-159109.psql_dcpublic.tpv_customers`\n WHERE id = 1 OR REGEXP_CONTAINS(\n UPPER(COALESCE(CASE WHEN id=12 THEN 'GESCAB' END, entity_name, '')), r'MUTUAMAD SHARING SLU|MOOVE|CENTAURO RENT|BOVIO|TELEFURGO|FLEXICAR|BANCO SANTANDER, S.A.|TALRENT|ARAIZ|AYVENS|SANTANDER DE LEASE|MUYCAR|GESCAB|NORDIC BUS|PIRELLI|ALPESUR|PANORAMA|OCASION PLUS|CAB CAR')\n ),\n excluir_personas AS (\n SELECT DISTINCT m.persona_id\n FROM `autingo-159109.clientes_intel.map_persona_fuente` m JOIN excluir_tpv e ON m.fuente='tpv' AND m.source_id = e.source_id\n UNION DISTINCT\n -- PARCHE solo-mutua: excluir las cuentas-paraguas de mutua de la base B2C\n SELECT DISTINCT agregador_persona_id\n FROM `autingo-159109.clientes_intel.map_mutualista_particular` WHERE tipo_origen='MUTUA'\n ),\n rfm AS (\n SELECT\n persona_id,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), MAX(fecha), DAY) AS recency_days,\n COUNT(*) AS frequency,\n ROUND(SUM(importe_dia), 2) AS monetary_total,\n ROUND(AVG(importe_dia), 2) AS ticket_medio,\n ROUND(STDDEV(importe_dia), 2) AS ticket_std,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), MIN(fecha), DAY) AS tenure_days,\n MIN(fecha) AS primera_compra,\n MAX(fecha) AS ultima_compra,\n ROUND(SUM(importe_dia * POW(0.5, SAFE_DIVIDE(DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), fecha, DAY), 548))), 2) AS valor_ponderado\n FROM `autingo-159109.clientes_intel.fact_visita`\n GROUP BY persona_id\n ),\n inter AS (\n SELECT persona_id,\n ROUND(AVG(gap), 2) AS mean_inter_visit_days,\n ROUND(STDDEV(gap), 2) AS std_inter_visit_days\n FROM (\n SELECT persona_id,\n DATE_DIFF(fecha, LAG(fecha) OVER (PARTITION BY persona_id ORDER BY fecha), DAY) AS gap\n FROM `autingo-159109.clientes_intel.fact_visita`\n )\n WHERE gap IS NOT NULL GROUP BY persona_id\n ),\n lineas AS (SELECT * FROM `autingo-159109.clientes_intel.fact_transaccion` WHERE persona_id IS NOT NULL),\n mix AS (\n SELECT persona_id,\n COUNT(DISTINCT categoria) AS n_categorias,\n COUNT(DISTINCT centro_nav_id) AS n_centros,\n ROUND(SAFE_DIVIDE(COUNTIF(empresa LIKE 'Aurgi%'), COUNT(*)), 4) AS pct_aurgi,\n ROUND(SAFE_DIVIDE(COUNTIF(empresa LIKE 'MotorTown%'), COUNT(*)), 4) AS pct_motortown,\n ROUND(SAFE_DIVIDE(COUNTIF(canal='web'), COUNT(*)), 4) AS pct_web,\n ROUND(SAFE_DIVIDE(\n SUM(IF(categoria IN ('SERV RAPID', 'REVISION', 'MECANICA'), importe, 0)),\n NULLIF(SUM(IF(categoria NOT IN ('DEVOLUCION') AND NOT (grupo LIKE 'TASA%'), importe, 0)), 0)\n ), 4) AS pct_servicio\n FROM lineas GROUP BY persona_id\n ),\n top_cat AS (\n SELECT persona_id, categoria AS categoria_top, ROUND(monto / NULLIF(tot, 0), 4) AS pct_top_cat\n FROM (\n SELECT persona_id, categoria, SUM(importe) AS monto,\n SUM(SUM(importe)) OVER (PARTITION BY persona_id) AS tot,\n ROW_NUMBER() OVER (PARTITION BY persona_id ORDER BY SUM(importe) DESC) AS rn\n FROM lineas GROUP BY persona_id, categoria\n ) WHERE rn = 1\n ),\n centro_top AS (\n SELECT persona_id, centro_nav_id AS centro_principal, empresa AS empresa_principal\n FROM (\n SELECT persona_id, centro_nav_id, ANY_VALUE(empresa) AS empresa, SUM(importe) AS s,\n ROW_NUMBER() OVER (PARTITION BY persona_id ORDER BY SUM(importe) DESC) AS rn\n FROM lineas GROUP BY persona_id, centro_nav_id\n ) WHERE rn = 1\n ),\n mes_top AS (\n SELECT persona_id, mes AS mes_top_compra FROM (\n SELECT persona_id, EXTRACT(MONTH FROM fecha) AS mes, SUM(importe) AS s,\n ROW_NUMBER() OVER (PARTITION BY persona_id ORDER BY SUM(importe) DESC) AS rn\n FROM lineas GROUP BY persona_id, mes\n ) WHERE rn = 1\n ),\n margen AS (\n SELECT l.persona_id,\n ROUND(SUM(l.importe * COALESCE(r.margen_rate, gf.g)), 2) AS margen_total\n FROM lineas l\n LEFT JOIN `autingo-159109.clientes_intel._margen_rate_producto` r ON l.producto_nav_id = r.prod_nav_id\n CROSS JOIN (SELECT AVG(margen_rate) AS g FROM `autingo-159109.clientes_intel._margen_rate_producto`) gf\n GROUP BY persona_id\n ),\n veh AS (\n SELECT persona_id, COUNT(*) AS n_vehiculos FROM `autingo-159109.clientes_intel.map_persona_vehiculo` GROUP BY persona_id\n ),\n feats AS (\n SELECT\n rfm.persona_id,\n rfm.recency_days, rfm.frequency, rfm.monetary_total, rfm.ticket_medio, rfm.ticket_std,\n rfm.tenure_days, rfm.primera_compra, rfm.ultima_compra, rfm.valor_ponderado,\n iv.mean_inter_visit_days, iv.std_inter_visit_days,\n mix.n_categorias, mix.n_centros, mix.pct_aurgi, mix.pct_motortown, mix.pct_web, mix.pct_servicio,\n tc.categoria_top, tc.pct_top_cat,\n cp.centro_principal, cp.empresa_principal,\n mt.mes_top_compra,\n mg.margen_total,\n COALESCE(v.n_vehiculos, 0) AS n_vehiculos,\n rfm.persona_id IN (SELECT persona_id FROM excluir_personas) AS es_excluido\n FROM rfm\n LEFT JOIN inter iv USING (persona_id)\n LEFT JOIN mix USING (persona_id)\n LEFT JOIN top_cat tc USING (persona_id)\n LEFT JOIN centro_top cp USING (persona_id)\n LEFT JOIN mes_top mt USING (persona_id)\n LEFT JOIN margen mg USING (persona_id)\n LEFT JOIN veh v USING (persona_id)\n ),\n scored AS (\n SELECT persona_id,\n NTILE(5) OVER (ORDER BY recency_days DESC) AS r_score,\n NTILE(5) OVER (ORDER BY frequency ASC) AS f_score,\n NTILE(5) OVER (ORDER BY monetary_total ASC) AS m_score\n FROM feats\n WHERE NOT es_excluido AND frequency >= 1\n )\n SELECT\n f.*,\n s.r_score, s.f_score, s.m_score,\n s.r_score * 100 + s.f_score * 10 + s.m_score AS rfm_score,\n s.r_score + s.f_score + s.m_score AS rfm_sum,\n \n CASE\n WHEN f.recency_days > 730 THEN 'Dormidos perdidos'\n WHEN f.recency_days > 548 AND s.m_score >= 3 THEN 'Dormidos valiosos'\n WHEN f.recency_days > 548 THEN 'Dormidos perdidos'\n WHEN f.recency_days > 243 THEN 'En riesgo / necesitan atencion'\n WHEN s.f_score >= 4 AND s.m_score >= 4 THEN 'Campeones'\n WHEN s.f_score >= 3 THEN 'Fieles'\n WHEN f.tenure_days <= 180 THEN 'Nuevos'\n ELSE 'Ocasional'\n END\n AS rfm_segment,\n ROUND(SAFE_DIVIDE(f.margen_total, NULLIF(f.monetary_total, 0)), 4) AS margen_pct,\n IF(f.pct_web > 0.5, 'web', 'tienda') AS canal_preferido,\n -- contactabilidad / RGPD (de dim_persona)\n dp.full_name, dp.email, dp.phone, dp.es_empresa, dp.confianza AS confianza_identidad,\n dp.num_fuentes,\n dp.email IS NOT NULL AS tiene_email,\n dp.phone IS NOT NULL AS tiene_telefono,\n dp.email_optout, dp.sms_optout, dp.whatsapp_optout, dp.do_not_call,\n (dp.email IS NOT NULL AND NOT dp.email_optout) OR (dp.phone IS NOT NULL AND NOT dp.do_not_call) AS contactable\n FROM feats f\n LEFT JOIN scored s USING (persona_id)\n LEFT JOIN `autingo-159109.clientes_intel.dim_persona` dp USING (persona_id)",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 09:42:05.485000+00:00",
|
|
"refs": [
|
|
"clientes_intel._margen_rate_producto",
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.fact_transaccion",
|
|
"clientes_intel.fact_visita",
|
|
"clientes_intel.map_persona_fuente",
|
|
"clientes_intel.map_persona_vehiculo",
|
|
"psql_dcpublic.tpv_customers"
|
|
]
|
|
},
|
|
"feat_cliente_vehiculo": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.feat_cliente_vehiculo`\n CLUSTER BY make, vehiculo_id AS\n WITH dimv AS (\n SELECT *, IF(REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$'), ((STRPOS('BCDFGHJKLMNPRSTVWXYZ', SUBSTR(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')),5,1))-1)*400 + (STRPOS('BCDFGHJKLMNPRSTVWXYZ', SUBSTR(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')),6,1))-1)*20 + (STRPOS('BCDFGHJKLMNPRSTVWXYZ', SUBSTR(UPPER(REGEXP_REPLACE(TRIM(plate_norm), r'[\\s\\-]', '')),7,1))-1)), NULL) AS serie_ord FROM `autingo-159109.clientes_intel.dim_vehiculo`\n ),\n tx AS (\n SELECT\n vehiculo_id,\n COUNT(DISTINCT fecha) AS n_visitas,\n COUNT(*) AS n_lineas,\n ROUND(SUM(importe), 2) AS importe_total,\n MIN(fecha) AS primera_fecha,\n MAX(fecha) AS ultima_fecha,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), MAX(fecha), DAY) AS recency_days,\n COUNT(DISTINCT categoria) AS n_categorias,\n ROUND(SAFE_DIVIDE(\n SUM(IF(categoria IN ('SERV RAPID', 'REVISION', 'MECANICA'), importe, 0)),\n NULLIF(SUM(IF(categoria NOT IN ('DEVOLUCION') AND NOT (grupo LIKE 'TASA%'), importe, 0)), 0)\n ), 4) AS pct_servicio,\n MAX(IF(categoria='NEUMATICOS', fecha, NULL)) AS ult_neumatico,\n MAX(IF(categoria='REVISION', fecha, NULL)) AS ult_revision,\n MAX(IF(categoria='BATERIAS', fecha, NULL)) AS ult_bateria,\n MAX(IF(categoria='LUBRICA', fecha, NULL)) AS ult_aceite,\n MAX(IF(categoria='FRICCION', fecha, NULL)) AS ult_frenos,\n MAX(IF(REGEXP_CONTAINS(UPPER(producto_desc), r'ITV'), fecha, NULL)) AS ult_preitv,\n COUNTIF(categoria='NEUMATICOS') AS n_lineas_neumatico\n FROM `autingo-159109.clientes_intel.fact_transaccion` WHERE vehiculo_id IS NOT NULL\n GROUP BY vehiculo_id\n ),\n owners AS (\n -- PARCHE solo-mutua: en matriculas de mutua, el dueno es el conductor real recuperado\n SELECT o.vehiculo_id, o.n_personas,\n COALESCE(mm.particular_persona_id, o.persona_actual_orig) AS persona_actual\n FROM (\n SELECT plate_norm AS vehiculo_id,\n COUNT(DISTINCT persona_id) AS n_personas,\n ARRAY_AGG(persona_id ORDER BY ultima_fecha DESC NULLS LAST LIMIT 1)[SAFE_OFFSET(0)] AS persona_actual_orig\n FROM `autingo-159109.clientes_intel.map_persona_vehiculo` GROUP BY plate_norm\n ) o\n LEFT JOIN `autingo-159109.clientes_intel.map_mutualista_particular` mm\n ON mm.plate_norm = o.vehiculo_id AND mm.es_mutualista\n ),\n feat AS (\n SELECT\n d.plate_norm AS vehiculo_id, d.license_plate,\n -- marca/modelo/combustible: TPV/OTR rellenado con TecRMI (tec_*)\n COALESCE(d.make, d.tec_marca) AS make,\n COALESCE(d.model, d.tec_modelo) AS model,\n d.model_family,\n COALESCE(d.fuel, d.tec_combustible) AS fuel,\n d.tyre_size,\n -- year declarado (saneado): year crudo es escaso (~13%) y con basura\n IF(d.year BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)), d.year, NULL) AS year_declarado,\n -- year estimado desde la serie de la matricula (cubre ~97% de modernas)\n pyc.anio_estimado AS anio_estimado_matricula,\n -- year real de matriculacion (TecRMI: 1a matricula, fallback matricula)\n IF(EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)) BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)), EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)), NULL) AS anio_real_matricula,\n -- year final: real TecRMI > declarado > estimado por matricula\n COALESCE(\n IF(EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)) BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)), EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)), NULL),\n IF(d.year BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)), d.year, NULL),\n pyc.anio_estimado\n ) AS anio_matricula,\n CASE\n WHEN EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)) BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) THEN 'tecrmi'\n WHEN d.year BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) THEN 'declarado'\n WHEN pyc.anio_estimado IS NOT NULL THEN 'estimado_matricula'\n ELSE NULL\n END AS fuente_anio,\n EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - COALESCE(\n IF(EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)) BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)), EXTRACT(YEAR FROM COALESCE(d.tec_fecha_1a_matricula, d.tec_fecha_matricula)), NULL),\n IF(d.year BETWEEN 1950 AND EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)), d.year, NULL),\n pyc.anio_estimado\n ) AS antiguedad_anios,\n tx.n_visitas, tx.n_lineas, tx.importe_total,\n tx.primera_fecha, tx.ultima_fecha, tx.recency_days,\n tx.n_categorias, tx.pct_servicio, tx.n_lineas_neumatico,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), tx.ult_neumatico, DAY) AS dias_desde_neumatico,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), tx.ult_revision, DAY) AS dias_desde_revision,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), tx.ult_bateria, DAY) AS dias_desde_bateria,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), tx.ult_aceite, DAY) AS dias_desde_aceite,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), tx.ult_frenos, DAY) AS dias_desde_frenos,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), tx.ult_preitv, DAY) AS dias_desde_preitv,\n COALESCE(o.n_personas, 0) AS n_personas,\n o.persona_actual,\n -- Ficha tecnica TecRMI (ejes de targeting de promos personalizadas)\n d.vin,\n d.tec_combustible,\n d.tec_modelo_generico,\n d.tec_cilindrada, d.tec_potencia_kw, d.tec_potencia_fiscal, d.tec_co2,\n d.tec_segmento, d.tec_tipo, d.tec_plazas,\n d.tec_fecha_matricula, d.tec_fecha_1a_matricula\n FROM dimv d\n LEFT JOIN tx ON tx.vehiculo_id = d.plate_norm\n LEFT JOIN owners o ON o.vehiculo_id = d.plate_norm\n LEFT JOIN `autingo-159109.clientes_intel._plate_year_calib` pyc ON pyc.serie_ord = d.serie_ord\n )\n SELECT\n feat.*,\n -- combustible normalizado para targeting (unifica casing TPV 'DIESEL' vs TecRMI 'Diesel')\n CASE\n WHEN UPPER(feat.fuel) LIKE '%DIESEL%' OR UPPER(feat.fuel) LIKE '%GASOLEO%' OR UPPER(feat.fuel) LIKE '%GASÓLEO%' OR UPPER(feat.fuel) = 'IESEL' THEN 'Diesel'\n WHEN UPPER(feat.fuel) LIKE '%GASOLINA%' OR UPPER(feat.fuel) = 'ASOLINA' OR UPPER(feat.fuel) = 'ETANOL' THEN 'Gasolina'\n WHEN UPPER(feat.fuel) LIKE '%HIBRID%' OR UPPER(feat.fuel) LIKE '%HÍBRID%' THEN 'Hibrido'\n WHEN UPPER(feat.fuel) LIKE '%ELECTRIC%' OR UPPER(feat.fuel) LIKE '%ELÉCTRIC%' THEN 'Electrico'\n WHEN UPPER(feat.fuel) LIKE '%LICUADO DE PETRO%' OR UPPER(feat.fuel) LIKE '%GLP%' OR UPPER(feat.fuel) LIKE '%BUTANO%' THEN 'GLP'\n WHEN UPPER(feat.fuel) LIKE '%GAS NATURAL%' OR UPPER(feat.fuel) LIKE '%GNC%' THEN 'GNC'\n ELSE NULL\n END AS combustible,\n -- ITV (calendario legal turismos): exento <4 anios, bienal 4-10, anual >10\n CASE\n WHEN anio_matricula IS NULL THEN NULL\n WHEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula < 4 THEN 'exento'\n WHEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula < 10 THEN 'bienal'\n ELSE 'anual'\n END AS itv_periodicidad,\n -- anio estimado de la proxima ITV (resolucion anual)\n CASE\n WHEN anio_matricula IS NULL THEN NULL\n WHEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula <= 4 THEN anio_matricula + 4\n WHEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula < 10 THEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) + MOD(EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula, 2)\n ELSE EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`))\n END AS proxima_itv_anio,\n CASE\n WHEN anio_matricula IS NULL THEN NULL\n WHEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula < 4 THEN FALSE\n WHEN EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula < 10 THEN MOD(EXTRACT(YEAR FROM (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)) - anio_matricula, 2) = 0\n ELSE TRUE\n END AS itv_due_este_anio\n FROM feat",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 09:42:22.391000+00:00",
|
|
"refs": [
|
|
"clientes_intel._plate_year_calib",
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.dim_vehiculo",
|
|
"clientes_intel.fact_transaccion",
|
|
"clientes_intel.map_persona_vehiculo"
|
|
]
|
|
},
|
|
"map_mutualista_particular": {
|
|
"query": "CREATE OR REPLACE VIEW `autingo-159109.clientes_intel.map_mutualista_particular`\nOPTIONS(\n description=\"Mapeo matricula -> conductor particular real para coches cuya persona principal es una cuenta agregadora (mutua/flota: es_empresa en dim_persona y >=20 matriculas en map_persona_vehiculo). Recupera al particular via citaprevia/otr/visita, eligiendo el de actividad mas reciente. es_mutualista=TRUE si el agregador es una mutua/aseguradora. NO depende de seg_cliente_360 (se puede usar dentro de F8). Generado a mano.\"\n) AS\nWITH veh_count AS (\n -- propiedad TPV cruda (estable: la construye F2 desde origen, NO la tocan los parches F3/F4).\n -- Evita la dependencia circular: si contaramos persona_actual, la reasignacion se autodesharia.\n SELECT persona_id, COUNTIF(via_owner_tpv) AS nveh\n FROM `autingo-159109.clientes_intel.map_persona_vehiculo`\n GROUP BY persona_id\n),\nagg AS (\n SELECT dp.persona_id AS agg_id, dp.full_name AS agg_nombre,\n CASE WHEN REGEXP_CONTAINS(UPPER(dp.full_name), r'MUTUA|ASEGURAD|\\bSEGUROS\\b|MAPFRE|ALLIANZ|\\bAXA\\b|GENERALI|ZURICH|REALE|ASITUR|MULTIASIST|LINEA DIRECTA|PELAYO SEG|CATALANA OCC') THEN 'MUTUA' ELSE 'FLOTA' END AS tipo_origen\n FROM `autingo-159109.clientes_intel.dim_persona` dp\n JOIN veh_count vc ON dp.persona_id = vc.persona_id\n WHERE dp.es_empresa AND vc.nveh >= 20\n),\nplates AS (\n SELECT DISTINCT m.persona_id AS agg_id, m.plate_norm\n FROM `autingo-159109.clientes_intel.map_persona_vehiculo` m\n JOIN agg ON m.persona_id = agg.agg_id\n),\ncand AS (\n SELECT\n p.agg_id, p.plate_norm,\n dp.persona_id AS particular_persona_id,\n dp.full_name AS particular_nombre,\n m.ultima_fecha,\n dp.phone IS NOT NULL AS tiene_tel,\n dp.email IS NOT NULL AS tiene_email,\n ROW_NUMBER() OVER (\n PARTITION BY p.plate_norm\n ORDER BY m.ultima_fecha DESC NULLS LAST, m.n_visitas DESC\n ) AS rn\n FROM plates p\n JOIN `autingo-159109.clientes_intel.map_persona_vehiculo` m USING(plate_norm)\n JOIN `autingo-159109.clientes_intel.dim_persona` dp ON m.persona_id = dp.persona_id\n WHERE m.persona_id <> p.agg_id\n AND NOT dp.es_empresa\n AND (m.via_citaprevia OR m.via_otr OR m.via_visita)\n AND dp.full_name IS NOT NULL\n AND TRIM(dp.full_name) NOT IN ('', '.', '-')\n)\nSELECT\n c.plate_norm,\n a.tipo_origen,\n c.agg_id AS agregador_persona_id,\n a.agg_nombre AS agregador_nombre,\n c.particular_persona_id,\n c.particular_nombre,\n c.ultima_fecha AS ultima_actividad_particular,\n c.tiene_tel,\n c.tiene_email,\n (a.tipo_origen = 'MUTUA') AS es_mutualista\nFROM cand c\nJOIN agg a ON c.agg_id = a.agg_id\nWHERE c.rn = 1\n",
|
|
"stmt": "CREATE_VIEW",
|
|
"last_run": "2026-06-08 15:38:24.674000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.map_persona_vehiculo"
|
|
]
|
|
},
|
|
"map_persona_canal8": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.map_persona_canal8` AS\nWITH cc_presup AS (\n SELECT DISTINCT RIGHT(REGEXP_REPLACE(telefonos, r'[^0-9]', ''), 9) AS tel9\n FROM `autingo-159109.psql_dcpublic.call_transactions`\n WHERE telefonos IS NOT NULL\n AND LENGTH(REGEXP_REPLACE(telefonos, r'[^0-9]', '')) >= 9\n AND LOWER(campaign_name) LIKE '%presupuesto%'\n),\nglass AS (\n SELECT DISTINCT persona_id\n FROM `autingo-159109.clientes_intel.fact_transaccion`\n WHERE empresa IN ('Aurgi Glass', 'MotorTown Glass')\n),\nautingoc AS ( -- compra real en el centro web Autingo\n SELECT DISTINCT persona_id\n FROM `autingo-159109.clientes_intel.fact_transaccion`\n WHERE centro_nombre = 'Autingo'\n),\nbase AS (\n SELECT s.persona_id, s.es_empresa, s.empresa_principal, s.es_mutualista,\n dp.in_web, dp.in_citaprevia,\n g.persona_id IS NOT NULL AS is_glass,\n au.persona_id IS NOT NULL AS is_autingo,\n RIGHT(REGEXP_REPLACE(COALESCE(s.phone, ''), r'[^0-9]', ''), 9) AS tel9\n FROM `autingo-159109.clientes_intel.seg_cliente_360` s\n LEFT JOIN `autingo-159109.clientes_intel.dim_persona` dp USING (persona_id)\n LEFT JOIN glass g USING (persona_id)\n LEFT JOIN autingoc au USING (persona_id)\n)\nSELECT b.persona_id,\n CASE\n WHEN b.es_empresa THEN 'B2B'\n WHEN b.is_glass THEN 'Lunas'\n WHEN b.es_mutualista = 'Mutualista' OR b.empresa_principal = 'Autoclub' THEN 'Mutuamas/AC'\n -- Autingo: registrado en web (definicion amplia, la mas parecida a la imagen: Drive-in 51 / Autingo 12,6)\n WHEN b.in_web THEN 'Autingo'\n WHEN b.empresa_principal = 'Digital' THEN 'Web'\n WHEN c.tel9 IS NOT NULL AND b.tel9 != '' THEN 'Call Center'\n WHEN b.empresa_principal IN ('Aurgi', 'MotorTown', 'Franquicia') THEN 'Drive-in'\n WHEN b.in_citaprevia THEN 'Citas'\n ELSE 'Drive-in'\n END AS canal8\nFROM base b\nLEFT JOIN cc_presup c ON c.tel9 = b.tel9 AND b.tel9 != ''",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 12:03:06.171000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.fact_transaccion",
|
|
"clientes_intel.seg_cliente_360",
|
|
"psql_dcpublic.call_transactions"
|
|
]
|
|
},
|
|
"map_persona_fuente": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.map_persona_fuente` AS\n SELECT DISTINCT persona_id, src AS fuente, source_id FROM `autingo-159109.clientes_intel._persona_records`",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:47:27.004000+00:00",
|
|
"refs": [
|
|
"clientes_intel._persona_records"
|
|
]
|
|
},
|
|
"map_persona_vehiculo": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.map_persona_vehiculo` AS\n WITH\n tpv_map AS (SELECT source_id, persona_id FROM `autingo-159109.clientes_intel.map_persona_fuente` WHERE fuente='tpv'),\n otr_map AS (SELECT source_id, persona_id FROM `autingo-159109.clientes_intel.map_persona_fuente` WHERE fuente='otr'),\n cp_map AS (SELECT source_id, persona_id FROM `autingo-159109.clientes_intel.map_persona_fuente` WHERE fuente='citaprevia'),\n rel AS (\n -- 1) Visitas (lineas de venta): la mejor fuente de vigencia\n SELECT m.persona_id, UPPER(REGEXP_REPLACE(TRIM(l.otrs_unicas_por_order__plate), r'[\\s\\-]', '')) AS plate_norm,\n DATE(l.fecha) AS fecha, 'visita' AS origen\n FROM `autingo-159109.claude_bi.todos_datos_lineas_mat` l\n JOIN tpv_map m ON CAST(l.Tpv_Customers___Customer__id AS STRING) = m.source_id\n WHERE l.fecha IS NOT NULL AND (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(l.otrs_unicas_por_order__plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(l.otrs_unicas_por_order__plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n UNION ALL\n -- 2) Propiedad TPV\n SELECT m.persona_id, UPPER(REGEXP_REPLACE(TRIM(v.license_plate), r'[\\s\\-]', '')), DATE(vo.created_at), 'owner_tpv'\n FROM `autingo-159109.psql_dcpublic.tpv_vehicles_vehicleowner` vo\n JOIN `autingo-159109.psql_dcpublic.tpv_vehicles_vehicle` v ON v.id = vo.vehicle_id\n JOIN tpv_map m ON CAST(vo.customer_id AS STRING) = m.source_id\n WHERE (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(v.license_plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(v.license_plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n UNION ALL\n -- 3) OTR\n SELECT m.persona_id, UPPER(REGEXP_REPLACE(TRIM(ov.license_plate), r'[\\s\\-]', '')), DATE(ov.created_at), 'otr'\n FROM `autingo-159109.psql_dcpublic.otr_customers` oc\n JOIN `autingo-159109.psql_dcpublic.otr_vehicles` ov ON oc.car_id = ov.car_id\n JOIN otr_map m ON CAST(oc.id AS STRING) = m.source_id\n WHERE (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(ov.license_plate), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(ov.license_plate), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n UNION ALL\n -- 4) Cita previa (sin fecha)\n SELECT m.persona_id, UPPER(REGEXP_REPLACE(TRIM(cm.matricula), r'[\\s\\-]', '')), CAST(NULL AS DATE), 'citaprevia'\n FROM `autingo-159109.citaprevia_aurphcp.clientes_matriculas` cm\n JOIN cp_map m ON CAST(cm.cliente_id AS STRING) = m.source_id\n WHERE cm._fivetran_deleted IS NOT TRUE AND (REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(cm.matricula), r'[\\s\\-]', '')), r'^[0-9]{4}[BCDFGHJKLMNPRSTVWXYZ]{3}$') OR REGEXP_CONTAINS(UPPER(REGEXP_REPLACE(TRIM(cm.matricula), r'[\\s\\-]', '')), r'^[A-Z]{1,2}[0-9]{4}[A-Z]{1,2}$'))\n )\n SELECT\n persona_id, plate_norm,\n MIN(fecha) AS primera_fecha,\n MAX(fecha) AS ultima_fecha,\n COUNTIF(fecha IS NOT NULL AND origen='visita') AS n_visitas,\n COUNT(*) AS n_eventos,\n LOGICAL_OR(origen='visita') AS via_visita,\n LOGICAL_OR(origen='owner_tpv') AS via_owner_tpv,\n LOGICAL_OR(origen='otr') AS via_otr,\n LOGICAL_OR(origen='citaprevia') AS via_citaprevia\n FROM rel\n GROUP BY persona_id, plate_norm",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 15:00:21.242000+00:00",
|
|
"refs": [
|
|
"citaprevia_aurphcp.clientes_matriculas",
|
|
"claude_bi.todos_datos_lineas_mat",
|
|
"clientes_intel.map_persona_fuente",
|
|
"psql_dcpublic.otr_customers",
|
|
"psql_dcpublic.otr_vehicles",
|
|
"psql_dcpublic.tpv_vehicles_vehicle",
|
|
"psql_dcpublic.tpv_vehicles_vehicleowner"
|
|
]
|
|
},
|
|
"reco_acciones": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.reco_acciones`\n CLUSTER BY accion, persona_id AS\n WITH\n -- CAR: check rojo/amarillo no resuelto, 1 accion por matricula (Rojo>Amarillo, mas reciente)\n car_dedup AS (\n SELECT * EXCEPT(rn) FROM (\n SELECT\n UPPER(REGEXP_REPLACE(TRIM(license_plate), r'[\\s\\-]','')) AS vehiculo_id,\n check_color, subcat_cgq, check_subcats, origin_invoice_date,\n ROW_NUMBER() OVER (\n PARTITION BY UPPER(REGEXP_REPLACE(TRIM(license_plate), r'[\\s\\-]',''))\n ORDER BY CASE check_color WHEN 'Rojo' THEN 1 ELSE 2 END, origin_invoice_date DESC\n ) AS rn\n FROM `autingo-159109.claude_bi.conversion_cqg_base_mat`\n WHERE check_color IN ('Rojo','Amarillo') AND converted = 0\n AND origin_invoice_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 6 MONTH)\n ) WHERE rn = 1\n ),\n car AS (\n SELECT\n v.persona_actual AS persona_id, v.vehiculo_id, v.license_plate,\n IF(c.check_color = 'Rojo', 'CAR_ROJO', 'CAR_NARANJA') AS accion,\n c.subcat_cgq AS motivo,\n ARRAY_TO_STRING(c.check_subcats, ', ') AS motivo_subcat,\n c.check_color, c.origin_invoice_date AS fecha_senal\n FROM car_dedup c\n JOIN `autingo-159109.clientes_intel.feat_cliente_vehiculo` v ON v.vehiculo_id = c.vehiculo_id\n WHERE v.persona_actual IS NOT NULL\n ),\n -- ITV: due este anio sin pre-ITV previo (o pre-ITV de hace mas de 1 anio)\n itv AS (\n SELECT persona_actual AS persona_id, vehiculo_id, license_plate,\n 'ITV' AS accion,\n CONCAT('ITV ', CAST(proxima_itv_anio AS STRING)) AS motivo,\n CAST(NULL AS STRING) AS motivo_subcat,\n CAST(NULL AS STRING) AS check_color,\n CAST(NULL AS DATE) AS fecha_senal\n FROM `autingo-159109.clientes_intel.feat_cliente_vehiculo`\n WHERE persona_actual IS NOT NULL AND itv_due_este_anio\n AND (dias_desde_preitv IS NULL OR dias_desde_preitv > 365)\n ),\n -- Recencias de servicio (1 fila por servicio vencido)\n recencias AS (\n SELECT persona_actual AS persona_id, vehiculo_id, license_plate,\n s.accion, s.motivo, CAST(NULL AS STRING) AS motivo_subcat, CAST(NULL AS STRING) AS check_color,\n DATE_SUB(CURRENT_DATE(), INTERVAL s.dias DAY) AS fecha_senal\n FROM `autingo-159109.clientes_intel.feat_cliente_vehiculo` v,\n UNNEST([\n STRUCT('REVISION' AS accion, 'Revision general' AS motivo, v.dias_desde_revision AS dias),\n STRUCT('ACEITE', 'Cambio de aceite', v.dias_desde_aceite),\n STRUCT('FRENOS', 'Frenos', v.dias_desde_frenos),\n STRUCT('NEUMATICO', 'Neumaticos', v.dias_desde_neumatico),\n STRUCT('BATERIA', 'Bateria', v.dias_desde_bateria)\n ]) s\n WHERE v.persona_actual IS NOT NULL AND s.dias > CASE s.accion\n WHEN 'REVISION' THEN 365\n WHEN 'ACEITE' THEN 365\n WHEN 'FRENOS' THEN 730\n WHEN 'NEUMATICO' THEN 1095\n WHEN 'BATERIA' THEN 1095\n END\n ),\n -- Win-back: cliente valioso en riesgo de fuga (churn XGB) -> a nivel persona\n winback AS (\n SELECT\n m.persona_id, CAST(NULL AS STRING) AS vehiculo_id, CAST(NULL AS STRING) AS license_plate,\n 'WINBACK' AS accion,\n CONCAT('Riesgo de fuga ', c.segmento_riesgo) AS motivo,\n CAST(NULL AS STRING) AS motivo_subcat,\n CAST(NULL AS STRING) AS check_color, CAST(NULL AS DATE) AS fecha_senal\n FROM `autingo-159109.claude_bi.churn_scores_current` c\n JOIN `autingo-159109.clientes_intel.map_persona_fuente` m ON m.fuente='tpv' AND m.source_id = CAST(c.customer_id AS STRING)\n JOIN `autingo-159109.clientes_intel.score_clv` clv ON clv.persona_id = m.persona_id\n WHERE c.segmento_riesgo IN ('muy_alto', 'alto')\n AND clv.clv_norm >= 0.5\n ),\n senales AS (\n SELECT * FROM car\n UNION ALL SELECT * FROM itv\n UNION ALL SELECT * FROM recencias\n UNION ALL SELECT * FROM winback\n )\n SELECT\n s.persona_id, s.vehiculo_id, s.license_plate,\n s.accion, s.motivo, s.motivo_subcat, s.check_color, s.fecha_senal,\n COALESCE(clv.clv_norm, 0.0) AS clv_norm,\n clv.clv_score,\n CASE accion WHEN 'CAR_ROJO' THEN 100 WHEN 'WINBACK' THEN 90 WHEN 'ITV' THEN 80 WHEN 'CAR_NARANJA' THEN 60 WHEN 'REVISION' THEN 45 WHEN 'ACEITE' THEN 42 WHEN 'FRENOS' THEN 35 WHEN 'NEUMATICO' THEN 32 WHEN 'BATERIA' THEN 25 ELSE 0 END AS peso_accion,\n ROUND(CASE accion WHEN 'CAR_ROJO' THEN 100 WHEN 'WINBACK' THEN 90 WHEN 'ITV' THEN 80 WHEN 'CAR_NARANJA' THEN 60 WHEN 'REVISION' THEN 45 WHEN 'ACEITE' THEN 42 WHEN 'FRENOS' THEN 35 WHEN 'NEUMATICO' THEN 32 WHEN 'BATERIA' THEN 25 ELSE 0 END * (0.5 + 0.5 * COALESCE(clv.clv_norm, 0.0)), 4) AS prioridad_score,\n dp.canal_entrada,\n dp.contactable_email, dp.contactable_telefono,\n dp.email_optout, dp.sms_optout, dp.do_not_call\n FROM senales s\n JOIN `autingo-159109.clientes_intel.data_points_contacto` dp ON dp.persona_id = s.persona_id AND dp.es_b2c\n LEFT JOIN `autingo-159109.clientes_intel.score_clv` clv ON clv.persona_id = s.persona_id;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 15:36:04.548000+00:00",
|
|
"refs": [
|
|
"claude_bi.churn_scores_current",
|
|
"claude_bi.conversion_cqg_base_mat",
|
|
"clientes_intel.data_points_contacto",
|
|
"clientes_intel.feat_cliente_vehiculo",
|
|
"clientes_intel.map_persona_fuente",
|
|
"clientes_intel.score_clv"
|
|
]
|
|
},
|
|
"reco_promo_cluster": {
|
|
"query": "DROP TABLE IF EXISTS clientes_intel.reco_promo_cluster",
|
|
"stmt": "DROP_TABLE",
|
|
"last_run": "2026-06-03 12:00:25.955000+00:00",
|
|
"refs": []
|
|
},
|
|
"reco_promo_personalizada": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.reco_promo_personalizada`\n CLUSTER BY categoria_objetivo, persona_id AS\n WITH acciones AS (\n SELECT\n r.persona_id, r.vehiculo_id, r.license_plate,\n r.accion, r.motivo, r.motivo_subcat,\n r.prioridad_score, r.clv_norm,\n r.contactable_email, r.contactable_telefono, r.do_not_call,\n \n CASE\n WHEN r.accion = 'NEUMATICO' THEN 'NEUMATICOS'\n WHEN r.accion = 'FRENOS' THEN 'FRICCION'\n WHEN r.accion = 'ACEITE' THEN 'LUBRICA'\n WHEN r.accion = 'REVISION' THEN 'REVISION'\n WHEN r.accion = 'BATERIA' THEN 'BATERIAS'\n WHEN r.accion = 'ITV' THEN 'REVISION'\n WHEN r.accion IN ('CAR_ROJO','CAR_NARANJA') THEN CASE\n WHEN r.motivo = 'Neumaticos' THEN 'NEUMATICOS'\n WHEN r.motivo = 'Lunas' THEN 'LUNAS'\n WHEN r.motivo_subcat LIKE '%Friccion%' THEN 'FRICCION'\n WHEN r.motivo_subcat LIKE '%Iluminacion%' THEN 'ILUMINACIO'\n WHEN r.motivo IN ('Mantenimiento','Tienda') THEN 'LUBRICA'\n ELSE NULL\n END\n ELSE NULL\n END\n AS categoria_objetivo\n FROM `autingo-159109.clientes_intel.reco_acciones` r\n WHERE r.contactable_email OR r.contactable_telefono\n ),\n -- mejor promo activa por (segmento RFM, categoria), no colectiva.\n -- match_fuerte = el nombre contiene la palabra canonica de su categoria (evita\n -- falsos positivos del etiquetado por keyword, ej. 'FIBRA NATURAL' -> REVISION).\n promo_cat AS (\n SELECT segmento AS rfm_segment, categoria_promo, promo_id, promo_name, label AS promo_label,\n fin_promo, afinidad, palanca,\n ROW_NUMBER() OVER (\n PARTITION BY segmento, categoria_promo\n ORDER BY match_fuerte DESC, afinidad DESC, fin_promo\n ) AS rk\n FROM (\n SELECT *,\n CASE categoria_promo\n WHEN 'NEUMATICOS' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'NEU|RUEDA|EQUILIBRAD|VALVULA'), 1, 0)\n WHEN 'REVISION' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'REVISION|MANTENIMIENTO|ITV|TODO INCLUIDO'), 1, 0)\n WHEN 'LUBRICA' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'ACEITE|LUBRICA'), 1, 0)\n WHEN 'FRICCION' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'FRENO|PASTILLA|FRICCION|DISCO'), 1, 0)\n WHEN 'BATERIAS' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'BATERIA'), 1, 0)\n WHEN 'ILUMINACIO' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'ILUMINAC|BOMBILLA|FARO|LED'), 1, 0)\n WHEN 'LUNAS' THEN IF(REGEXP_CONTAINS(UPPER(promo_name), r'LUNA|CRISTAL|PARABRISA'), 1, 0)\n ELSE 0\n END AS match_fuerte\n FROM `autingo-159109.clientes_intel.reco_promo_segmento`\n WHERE esquema = 'RFM' AND NOT es_colectivo\n )\n ),\n base AS (\n SELECT\n a.persona_id, a.vehiculo_id, a.license_plate,\n a.accion, a.motivo, a.motivo_subcat, a.categoria_objetivo,\n a.prioridad_score, a.clv_norm,\n s.rfm_segment, s.full_name, s.email, s.phone,\n v.make, v.model, v.model_family, v.fuel, v.tyre_size, v.anio_matricula,\n pc.promo_id, pc.promo_name, pc.promo_label, pc.fin_promo, pc.afinidad, pc.palanca,\n a.contactable_email, a.contactable_telefono,\n CASE\n WHEN a.contactable_email THEN 'EMAIL'\n WHEN a.contactable_telefono AND NOT a.do_not_call THEN 'SMS'\n ELSE NULL\n END AS canal_recomendado,\n ROW_NUMBER() OVER (PARTITION BY a.persona_id ORDER BY a.prioridad_score DESC) AS rk_persona\n FROM acciones a\n JOIN `autingo-159109.clientes_intel.seg_cliente_360` s ON s.persona_id = a.persona_id\n LEFT JOIN `autingo-159109.clientes_intel.feat_cliente_vehiculo` v ON v.vehiculo_id = a.vehiculo_id\n LEFT JOIN promo_cat pc ON pc.rfm_segment = s.rfm_segment\n AND pc.categoria_promo = a.categoria_objetivo AND pc.rk = 1\n WHERE a.categoria_objetivo IS NOT NULL\n )\n SELECT\n * EXCEPT(rk_persona),\n rk_persona = 1 AS top_persona,\n CONCAT(\n accion, ' / ', categoria_objetivo,\n IF(make IS NOT NULL, CONCAT(' (', make, ' ', COALESCE(model, ''), ')'), ''),\n ' -> ', COALESCE(promo_name, 'sin promo activa de esta categoria')\n ) AS mensaje,\n TRUE AS envio_habilitado,\n CAST(NULL AS STRING) AS bloqueo_motivo\n FROM base\n WHERE canal_recomendado IS NOT NULL;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 08:21:04.866000+00:00",
|
|
"refs": [
|
|
"clientes_intel.feat_cliente_vehiculo",
|
|
"clientes_intel.reco_acciones",
|
|
"clientes_intel.reco_promo_segmento",
|
|
"clientes_intel.seg_cliente_360"
|
|
]
|
|
},
|
|
"reco_promo_segmento": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.reco_promo_segmento`\n CLUSTER BY esquema, segmento AS\n WITH seg_long AS (\n SELECT persona_id, 'RFM' AS esquema, rfm_segment AS segmento FROM `autingo-159109.clientes_intel.seg_cliente_360` WHERE rfm_segment IS NOT NULL\n UNION ALL\n SELECT persona_id, 'CLV', clv_nivel FROM `autingo-159109.clientes_intel.seg_cliente_360` WHERE clv_nivel IN ('Alto','Medio','Bajo')\n UNION ALL\n SELECT persona_id, 'CL', \n CASE cluster\n WHEN '0' THEN 'Generalista gasto medio'\n WHEN '1' THEN 'Fieles alto valor'\n WHEN '2' THEN 'Coche reciente bajo gasto'\n WHEN '3' THEN 'Coche antiguo bajo gasto'\n WHEN '4' THEN 'Coche premium (lujo)'\n END\n FROM `autingo-159109.clientes_intel.seg_cliente_360` WHERE cluster IS NOT NULL\n ),\n afinidad AS (\n SELECT sl.esquema, sl.segmento, t.categoria,\n SAFE_DIVIDE(SUM(t.importe), SUM(SUM(t.importe)) OVER (PARTITION BY sl.esquema, sl.segmento)) AS pct_gasto\n FROM `autingo-159109.clientes_intel.fact_transaccion` t\n JOIN seg_long sl USING (persona_id)\n WHERE t.categoria IS NOT NULL AND t.importe > 0\n GROUP BY sl.esquema, sl.segmento, t.categoria\n ),\n segmentos AS (SELECT DISTINCT esquema, segmento FROM seg_long WHERE segmento IS NOT NULL),\n promos AS (\n SELECT id AS promo_id, name AS promo_name, label, DATE(ending_date) AS fin_promo,\n \n CASE\n WHEN REGEXP_CONTAINS(UPPER(name), r'ESCOBILLA') THEN 'ESCOBILLAS'\n WHEN REGEXP_CONTAINS(UPPER(name), r'NEU|NEUMATIC|EQUILIBRAD|VALVULA|RUEDA') THEN 'NEUMATICOS'\n WHEN REGEXP_CONTAINS(UPPER(name), r'REVISION|MANTENIMIENTO|TODO INCLUIDO|INFINITY|ADVANCE|NATURA') THEN 'REVISION'\n WHEN REGEXP_CONTAINS(UPPER(name), r'FILTRO') THEN 'FILTROS'\n WHEN REGEXP_CONTAINS(UPPER(name), r'BATERIA') THEN 'BATERIAS'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ACEITE|LUBRICA') THEN 'LUBRICA'\n WHEN REGEXP_CONTAINS(UPPER(name), r'FRENO|PASTILLA|FRICCION|DISCO') THEN 'FRICCION'\n WHEN REGEXP_CONTAINS(UPPER(name), r'LUNA|LLUVIA|CRISTAL|PARABRISA') THEN 'LUNAS'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ILUMINAC|BOMBILLA|FARO|LED') THEN 'ILUMINACIO'\n ELSE 'GENERAL'\n END\n AS categoria_promo, \n CASE\n WHEN REGEXP_CONTAINS(UPPER(name), r'PINCHAZO') THEN 'Pinchazo'\n WHEN REGEXP_CONTAINS(UPPER(name), r'PASTILLA') THEN 'Pastillas'\n WHEN REGEXP_CONTAINS(UPPER(name), r'DISCO') THEN 'Discos'\n WHEN REGEXP_CONTAINS(UPPER(name), r'LIQUIDO FRENO|DOT4|DOT 4') THEN 'Liquido de frenos'\n WHEN REGEXP_CONTAINS(UPPER(name), r'EQUILIBRAD|VALVULA|MONTAJE') THEN 'Montaje/equilibrado'\n WHEN REGEXP_CONTAINS(UPPER(name), r'NEUMATIC|RUEDA') THEN 'Neumaticos'\n WHEN REGEXP_CONTAINS(UPPER(name), r'BATERIA') THEN 'Bateria'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ILUMINAC|BOMBILLA|FARO|\\bLED\\b') THEN 'Iluminacion'\n WHEN REGEXP_CONTAINS(UPPER(name), r'LAVAPARABRISAS|PARABRISA|\\bLUNA|CRISTAL') THEN 'Lunas/cristales'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ESCOBILLA') THEN 'Escobillas'\n WHEN REGEXP_CONTAINS(UPPER(name), r'FILTRO') THEN 'Filtros'\n WHEN REGEXP_CONTAINS(UPPER(name), r'CARGA AIRE|R1234|R134|AIRE ACOND|CLIMA') THEN 'Aire acondicionado'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ANTICONGELANTE') THEN 'Anticongelante'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ACEITE|LUBRICA') THEN 'Aceite'\n WHEN REGEXP_CONTAINS(UPPER(name), r'ITV') THEN 'ITV'\n WHEN REGEXP_CONTAINS(UPPER(name), r'REVISION|\\bREV\\b|REVISIONE') THEN 'Revision'\n WHEN REGEXP_CONTAINS(UPPER(name), r'CUPON|PROXIMA COMPRA') THEN 'Cupon/fidelizacion'\n WHEN REGEXP_CONTAINS(UPPER(name), r'GRATIS|REGALO|CAMISETA|AMBIENTADOR|CUBREASIENTO|OZONO') THEN 'Regalo/obsequio'\n ELSE 'Otros'\n END\n AS subcategoria_promo, REGEXP_CONTAINS(UPPER(name), r'COLECTIVO|FLOTA|EMPLEAD|GESCAB|TALRENT|INTERDATA|CARREFOUR|GRUPO COLECTIVO') AS es_colectivo\n FROM `autingo-159109.psql_dcpublic.promotions`\n WHERE status = 1 AND starting_date <= CURRENT_TIMESTAMP() AND ending_date >= CURRENT_TIMESTAMP()\n ),\n cruce AS (\n SELECT s.esquema, s.segmento, p.promo_id, p.promo_name, p.label, p.fin_promo,\n p.categoria_promo, p.subcategoria_promo, p.es_colectivo,\n CASE WHEN p.categoria_promo = 'GENERAL' THEN 0.10 ELSE COALESCE(a.pct_gasto, 0.0) END AS afinidad\n FROM segmentos s\n CROSS JOIN promos p\n LEFT JOIN afinidad a ON a.esquema = s.esquema AND a.segmento = s.segmento AND a.categoria = p.categoria_promo\n )\n SELECT *,\n -- palanca de comunicacion del arquetipo (deck Ciclo de vida); solo aplica al esquema CL\n CASE WHEN esquema = 'CL' THEN CASE segmento\n WHEN 'Generalista gasto medio' THEN 'RETENCION'\n WHEN 'Fieles alto valor' THEN 'VOLUMEN'\n WHEN 'Coche reciente bajo gasto' THEN 'FRECUENCIA'\n WHEN 'Coche antiguo bajo gasto' THEN 'PREVENCION'\n WHEN 'Coche premium (lujo)' THEN 'DIFERENCIACION'\n END END AS palanca,\n ROW_NUMBER() OVER (PARTITION BY esquema, segmento, es_colectivo ORDER BY afinidad DESC, fin_promo) AS rank_en_segmento\n FROM cruce;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 11:58:03.947000+00:00",
|
|
"refs": [
|
|
"clientes_intel.fact_transaccion",
|
|
"clientes_intel.seg_cliente_360",
|
|
"psql_dcpublic.promotions"
|
|
]
|
|
},
|
|
"rpt_campana": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.rpt_campana` CLUSTER BY canal AS\n WITH \n resp AS (\n SELECT persona_id, canal, campana, ultima_fecha AS fecha_envio,\n abrio, clico, n_enviados, n_entregados, n_rebotados, n_baja\n FROM `autingo-159109.clientes_intel.fact_campana_respuesta` WHERE ultima_fecha IS NOT NULL\n ),\n lines AS (\n SELECT r.*, t.fecha AS tx_fecha, t.importe,\n (t.fecha > r.fecha_envio AND t.fecha <= DATE_ADD(r.fecha_envio, INTERVAL 30 DAY)) AS in_win\n FROM resp r\n LEFT JOIN `autingo-159109.clientes_intel.fact_transaccion` t ON t.persona_id = r.persona_id AND t.fecha >= '2025-01-01'\n ),\n ranked AS (\n SELECT *,\n MIN(IF(in_win, tx_fecha, NULL)) OVER (PARTITION BY canal, campana, persona_id) AS first_buy\n FROM lines\n ),\n per AS (\n SELECT canal, campana, persona_id,\n ANY_VALUE(abrio) AS abrio, ANY_VALUE(clico) AS clico,\n ANY_VALUE(n_enviados) AS n_enviados, ANY_VALUE(n_entregados) AS n_entregados,\n ANY_VALUE(n_rebotados) AS n_rebotados, ANY_VALUE(n_baja) AS n_baja,\n ANY_VALUE(fecha_envio) AS fecha_envio,\n MAX(IF(in_win, 1, 0)) AS compro,\n COUNTIF(in_win) AS compras,\n SUM(IF(in_win, importe, 0)) AS eur,\n SUM(IF(in_win AND tx_fecha = first_buy, importe, 0)) AS eur_primera,\n SUM(IF(in_win AND tx_fecha > first_buy, importe, 0)) AS eur_siguientes\n FROM ranked\n GROUP BY canal, campana, persona_id\n )\n SELECT\n canal, campana,\n MAX(fecha_envio) AS fecha_campana,\n COUNT(*) AS personas_impactadas,\n SUM(n_enviados) AS enviados,\n SUM(n_entregados) AS entregados,\n SUM(n_rebotados) AS rebotados,\n SUM(n_baja) AS bajas,\n COUNTIF(abrio) AS personas_abrio,\n COUNTIF(clico) AS personas_clico,\n ROUND(AVG(CAST(abrio AS INT64)), 4) AS tasa_or,\n ROUND(AVG(CAST(clico AS INT64)), 4) AS tasa_ctr,\n ROUND(SAFE_DIVIDE(SUM(n_entregados), SUM(n_enviados)), 4) AS tasa_entregas,\n ROUND(SAFE_DIVIDE(SUM(n_rebotados), SUM(n_enviados)), 4) AS tasa_rebote,\n COUNTIF(compro = 1) AS personas_conversion,\n ROUND(AVG(compro), 4) AS tasa_conversion,\n SUM(compras) AS compras_totales,\n ROUND(SUM(eur), 0) AS ingresos,\n ROUND(SUM(eur_primera), 0) AS ingresos_primera_compra,\n ROUND(SUM(eur_siguientes), 0) AS ingresos_siguientes,\n ROUND(SAFE_DIVIDE(SUM(eur), COUNT(*)), 2) AS ingreso_por_impactado\n FROM per GROUP BY canal, campana",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 11:07:07.488000+00:00",
|
|
"refs": [
|
|
"clientes_intel.fact_campana_respuesta",
|
|
"clientes_intel.fact_transaccion"
|
|
]
|
|
},
|
|
"rpt_campana_lift": {
|
|
"query": "-- rpt_campana_lift: conversion incremental de campanas email (Salesforce) sobre venta TPV.\n-- Universo de medida = ABRIDORES (entraron a verlo). Ventana 30 dias antes/despues del envio.\n-- Outcome producto = compra de la categoria de la campana (clasificada por nombre).\n-- Outcome compra = compra de cualquier cosa (sirve para campanas genericas sin producto).\n-- Ingreso 1a compra = FACTURA COMPLETA del primer dia de compra post-envio.\n-- DiD = (abr_post - abr_pre) - (noabr_post - noabr_pre) en puntos porcentuales.\nCREATE OR REPLACE TABLE `autingo-159109.clientes_intel.rpt_campana_lift`\nCLUSTER BY ambito, tema AS\nWITH cls0 AS (\n SELECT DISTINCT campana,\n UPPER(REGEXP_REPLACE(NORMALIZE(campana, NFD), r'\\p{Mn}', '')) AS n\n FROM `autingo-159109.clientes_intel.fact_campana_respuesta`\n WHERE campana IS NOT NULL\n),\ncls AS (\n SELECT campana,\n REGEXP_CONTAINS(n, r'NEUMATIC|PIRELLI|CEAT|MICHELIN|BRIDGESTONE|GOODYEAR|CONTINENTAL|HANKOOK|DUNLOP|FIRESTONE|KUMHO|NEXEN|4X3|RUEDA') AS t_neum,\n REGEXP_CONTAINS(n, r'BATERIA') AS t_bat,\n REGEXP_CONTAINS(n, r'AIRE ACOND|CLIMATIZ|A/A') AS t_aa,\n REGEXP_CONTAINS(n, r'REVISION|ESENCIA|MANTENIMIENTO|PUESTA A PUNTO|ITV') AS t_rev,\n REGEXP_CONTAINS(n, r'ACEITE|LUBRIC') AS t_ace,\n REGEXP_CONTAINS(n, r'ESCOBILLA|LIMPIAPARABRISA') AS t_esc,\n REGEXP_CONTAINS(n, r'FRENO|PASTILLA') AS t_fre,\n REGEXP_CONTAINS(n, r'LUNA|PARABRISAS|CARGLASS|CRISTAL') AS t_lun,\n REGEXP_CONTAINS(n, r'BOMBILLA|FARO|ILUMINAC') AS t_ilu,\n REGEXP_CONTAINS(n, r'(^|[^A-Z])MT([^A-Z]|$)|MOTORTOWN|MOTOR TOWN') AS es_mt,\n REGEXP_CONTAINS(n, r'REMINDER|RECORDATORIO|ULTIMA HORA|ULTIMAS HORAS') AS es_reminder\n FROM cls0\n),\nclassified AS (\n SELECT campana,\n ARRAY_CONCAT(\n IF(t_neum, ['NEUMATICOS'], CAST([] AS ARRAY<STRING>)),\n IF(t_bat, ['BATERIAS'], CAST([] AS ARRAY<STRING>)),\n IF(t_rev, ['REVISION','LUBRICA','FILTROS'], CAST([] AS ARRAY<STRING>)),\n IF(t_ace AND NOT t_rev, ['LUBRICA'], CAST([] AS ARRAY<STRING>)),\n IF(t_esc, ['ESCOBILLAS'], CAST([] AS ARRAY<STRING>)),\n IF(t_fre, ['FRICCION'], CAST([] AS ARRAY<STRING>)),\n IF(t_lun, ['LUNAS','SERV LUNAS'], CAST([] AS ARRAY<STRING>)),\n IF(t_ilu, ['ILUMINACIO'], CAST([] AS ARRAY<STRING>))\n ) AS cats,\n t_aa AS aa,\n IF(es_mt, 'MotorTown', 'Aurgi') AS ambito,\n es_reminder,\n TRIM(CONCAT(\n IF(t_neum,'neumatico ',''), IF(t_bat,'bateria ',''), IF(t_aa,'aire ',''),\n IF(t_rev,'revision ',''), IF(t_ace AND NOT t_rev,'aceite ',''),\n IF(t_esc,'escobilla ',''), IF(t_fre,'freno ',''), IF(t_lun,'luna ',''),\n IF(t_ilu,'iluminacion ',''))) AS tema_raw\n FROM cls\n),\nclassified2 AS (\n SELECT campana, cats, aa, ambito, es_reminder,\n (ARRAY_LENGTH(cats) > 0 OR aa) AS has_product,\n IF(tema_raw = '', 'generico', tema_raw) AS tema\n FROM classified\n),\nrecip AS (\n SELECT f.campana, f.persona_id,\n MAX(CAST(f.abrio AS INT64)) = 1 AS abrio,\n MAX(f.ultima_fecha) AS fe\n FROM `autingo-159109.clientes_intel.fact_campana_respuesta` f\n WHERE f.ultima_fecha IS NOT NULL AND f.ultima_fecha >= '2025-03-01'\n AND f.persona_id != -4712881641624161506 -- excluir generico TPV \"No identificado\"\n GROUP BY f.campana, f.persona_id\n),\nr AS (\n SELECT recip.campana, recip.persona_id, recip.abrio, recip.fe,\n c.cats, c.aa\n FROM recip JOIN classified2 c USING (campana)\n),\ntx AS (\n SELECT r.campana, r.persona_id, r.abrio, r.fe,\n t.fecha, t.importe,\n (t.categoria IN UNNEST(r.cats) OR (r.aa AND t.grupo IN ('SERVICO AA','PROMO AA'))) AS is_rel\n FROM r JOIN `autingo-159109.clientes_intel.fact_transaccion` t\n ON t.persona_id = r.persona_id\n AND t.fecha BETWEEN DATE_SUB(r.fe, INTERVAL 30 DAY) AND DATE_ADD(r.fe, INTERVAL 30 DAY)\n AND t.fecha >= '2025-01-01'\n),\nper AS (\n SELECT campana, persona_id, ANY_VALUE(abrio) AS abrio, ANY_VALUE(fe) AS fe,\n MAX(IF(fecha > fe AND fecha <= DATE_ADD(fe, INTERVAL 30 DAY), 1, 0)) AS post_any,\n MAX(IF(fecha > fe AND fecha <= DATE_ADD(fe, INTERVAL 30 DAY) AND is_rel, 1, 0)) AS post_rel,\n MAX(IF(fecha <= fe AND fecha > DATE_SUB(fe, INTERVAL 30 DAY), 1, 0)) AS pre_any,\n MAX(IF(fecha <= fe AND fecha > DATE_SUB(fe, INTERVAL 30 DAY) AND is_rel, 1, 0)) AS pre_rel,\n MIN(IF(fecha > fe AND fecha <= DATE_ADD(fe, INTERVAL 30 DAY), fecha, NULL)) AS first_day\n FROM tx GROUP BY campana, persona_id\n),\nrev AS (\n SELECT tx.campana, tx.persona_id, ANY_VALUE(per.abrio) AS abrio,\n SUM(IF(tx.fecha = per.first_day, tx.importe, 0)) AS ing_1a_factura,\n SUM(IF(tx.fecha = per.first_day AND tx.is_rel, tx.importe, 0)) AS imp_prod_1a,\n SUM(IF(tx.fecha > per.first_day AND tx.fecha <= DATE_ADD(per.fe, INTERVAL 30 DAY), tx.importe, 0)) AS ing_siguientes\n FROM tx JOIN per USING (campana, persona_id)\n WHERE per.first_day IS NOT NULL\n GROUP BY tx.campana, tx.persona_id\n),\ndenom AS (\n SELECT campana, COUNT(*) AS impactados, COUNTIF(abrio) AS abridores,\n COUNTIF(NOT abrio) AS noab, MAX(fe) AS envio\n FROM recip GROUP BY campana\n),\nstats AS (\n SELECT campana,\n COUNTIF(abrio AND post_any = 1) AS compradores,\n COUNTIF(abrio AND post_rel = 1) AS abr_post_rel,\n COUNTIF(abrio AND pre_rel = 1) AS abr_pre_rel,\n COUNTIF(NOT abrio AND post_rel = 1) AS noabr_post_rel,\n COUNTIF(NOT abrio AND pre_rel = 1) AS noabr_pre_rel,\n COUNTIF(abrio AND pre_any = 1) AS abr_pre_any,\n COUNTIF(NOT abrio AND post_any = 1) AS noabr_post_any,\n COUNTIF(NOT abrio AND pre_any = 1) AS noabr_pre_any\n FROM per GROUP BY campana\n),\nrevagg AS (\n SELECT campana,\n ROUND(SUM(IF(abrio, ing_1a_factura, 0)), 2) AS ing_1a_factura,\n ROUND(SUM(IF(abrio, imp_prod_1a, 0)), 2) AS imp_prod_1a,\n ROUND(SUM(IF(abrio, ing_siguientes, 0)), 2) AS ing_siguientes\n FROM rev GROUP BY campana\n)\nSELECT\n d.campana, c.ambito, c.tema, c.es_reminder, c.has_product, d.envio,\n d.impactados, d.abridores, s.compradores,\n ROUND(SAFE_DIVIDE(d.abridores, d.impactados), 4) AS tasa_apertura,\n ROUND(SAFE_DIVIDE(s.compradores, d.abridores), 4) AS tasa_conversion,\n -- DiD (puntos porcentuales)\n ROUND(((SAFE_DIVIDE(s.compradores, d.abridores) - SAFE_DIVIDE(s.abr_pre_any, d.abridores))\n - (SAFE_DIVIDE(s.noabr_post_any, d.noab) - SAFE_DIVIDE(s.noabr_pre_any, d.noab))) * 100, 3) AS did_compra_pp,\n IF(c.has_product,\n ROUND(((SAFE_DIVIDE(s.abr_post_rel, d.abridores) - SAFE_DIVIDE(s.abr_pre_rel, d.abridores))\n - (SAFE_DIVIDE(s.noabr_post_rel, d.noab) - SAFE_DIVIDE(s.noabr_pre_rel, d.noab))) * 100, 3),\n NULL) AS did_producto_pp,\n -- compradores incrementales (usa DiD producto si hay, si no DiD compra)\n ROUND(IF(c.has_product,\n ((SAFE_DIVIDE(s.abr_post_rel, d.abridores) - SAFE_DIVIDE(s.abr_pre_rel, d.abridores))\n - (SAFE_DIVIDE(s.noabr_post_rel, d.noab) - SAFE_DIVIDE(s.noabr_pre_rel, d.noab))),\n ((SAFE_DIVIDE(s.compradores, d.abridores) - SAFE_DIVIDE(s.abr_pre_any, d.abridores))\n - (SAFE_DIVIDE(s.noabr_post_any, d.noab) - SAFE_DIVIDE(s.noabr_pre_any, d.noab)))\n ) * d.abridores, 1) AS compradores_increm,\n ra.ing_1a_factura,\n ra.imp_prod_1a AS importe_solo_producto,\n ra.ing_siguientes,\n ROUND(SAFE_DIVIDE(ra.imp_prod_1a, ra.ing_1a_factura), 4) AS pct_producto,\n ROUND(1 - SAFE_DIVIDE(ra.imp_prod_1a, ra.ing_1a_factura), 4) AS pct_upselling,\n ROUND(SAFE_DIVIDE(ra.ing_siguientes, ra.ing_1a_factura + ra.ing_siguientes), 4) AS pct_siguientes\nFROM denom d\nJOIN classified2 c USING (campana)\nJOIN stats s USING (campana)\nLEFT JOIN revagg ra USING (campana)\nWHERE d.impactados >= 1000;\n",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 16:21:06.258000+00:00",
|
|
"refs": [
|
|
"clientes_intel.fact_campana_respuesta",
|
|
"clientes_intel.fact_transaccion"
|
|
]
|
|
},
|
|
"rpt_campana_usuario": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.rpt_campana_usuario` CLUSTER BY persona_id AS\n WITH \n resp AS (\n SELECT persona_id, canal, campana, ultima_fecha AS fecha_envio,\n abrio, clico, n_enviados, n_entregados, n_rebotados, n_baja\n FROM `autingo-159109.clientes_intel.fact_campana_respuesta` WHERE ultima_fecha IS NOT NULL\n ),\n lines AS (\n SELECT r.*, t.fecha AS tx_fecha, t.importe,\n (t.fecha > r.fecha_envio AND t.fecha <= DATE_ADD(r.fecha_envio, INTERVAL 30 DAY)) AS in_win\n FROM resp r\n LEFT JOIN `autingo-159109.clientes_intel.fact_transaccion` t ON t.persona_id = r.persona_id AND t.fecha >= '2025-01-01'\n ),\n ranked AS (\n SELECT *,\n MIN(IF(in_win, tx_fecha, NULL)) OVER (PARTITION BY canal, campana, persona_id) AS first_buy\n FROM lines\n ),\n per AS (\n SELECT canal, campana, persona_id,\n ANY_VALUE(abrio) AS abrio, ANY_VALUE(clico) AS clico,\n ANY_VALUE(n_enviados) AS n_enviados, ANY_VALUE(n_entregados) AS n_entregados,\n ANY_VALUE(n_rebotados) AS n_rebotados, ANY_VALUE(n_baja) AS n_baja,\n ANY_VALUE(fecha_envio) AS fecha_envio,\n MAX(IF(in_win, 1, 0)) AS compro,\n COUNTIF(in_win) AS compras,\n SUM(IF(in_win, importe, 0)) AS eur,\n SUM(IF(in_win AND tx_fecha = first_buy, importe, 0)) AS eur_primera,\n SUM(IF(in_win AND tx_fecha > first_buy, importe, 0)) AS eur_siguientes\n FROM ranked\n GROUP BY canal, campana, persona_id\n ),\n agg AS (\n SELECT persona_id,\n COUNT(*) AS n_campanas_impactadas,\n COUNTIF(compro = 1) AS n_conversiones,\n ROUND(SAFE_DIVIDE(COUNTIF(compro = 1), COUNT(*)), 4) AS tasa_conversion,\n SUM(n_enviados) AS n_enviados,\n LOGICAL_OR(abrio) AS abrio_alguna,\n LOGICAL_OR(clico) AS clico_alguna,\n SUM(n_baja) AS n_bajas,\n ROUND(SUM(eur), 2) AS importe_total,\n ROUND(SUM(eur_primera), 2) AS importe_primera,\n ROUND(SUM(eur_siguientes), 2) AS importe_siguientes\n FROM per GROUP BY persona_id\n )\n SELECT\n a.*, p.full_name AS nombre, p.salesforce_customer_id AS salesforce_id,\n p.es_empresa, p.email IS NOT NULL AS tiene_email\n FROM agg a JOIN `autingo-159109.clientes_intel.dim_persona` p USING (persona_id)",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 11:07:23.245000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.fact_campana_respuesta",
|
|
"clientes_intel.fact_transaccion"
|
|
]
|
|
},
|
|
"rpt_impacto_persona": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.rpt_impacto_persona`\n CLUSTER BY compro AS\n -- Atribucion UNICA a nivel persona: cada compra se cuenta UNA vez aunque caiga\n -- en la ventana de varias campanas (evita el inflado del SUM por campana).\n WITH resp AS (\n SELECT persona_id, ultima_fecha AS fecha_envio\n FROM `autingo-159109.clientes_intel.fact_campana_respuesta`\n WHERE ultima_fecha IS NOT NULL\n ),\n tx AS (\n SELECT DISTINCT r.persona_id, t.transaccion_id, t.fecha AS tx_fecha, t.importe\n FROM resp r\n JOIN `autingo-159109.clientes_intel.fact_transaccion` t\n ON t.persona_id = r.persona_id\n AND t.fecha > r.fecha_envio\n AND t.fecha <= DATE_ADD(r.fecha_envio, INTERVAL 30 DAY)\n AND t.fecha >= '2025-01-01'\n ),\n firstbuy AS (\n SELECT persona_id, MIN(tx_fecha) AS first_buy FROM tx GROUP BY persona_id\n ),\n imp AS (\n SELECT x.persona_id,\n SUM(x.importe) AS eur_unico,\n SUM(IF(x.tx_fecha = f.first_buy, x.importe, 0)) AS eur_primera,\n SUM(IF(x.tx_fecha > f.first_buy, x.importe, 0)) AS eur_siguientes\n FROM tx x JOIN firstbuy f USING (persona_id)\n GROUP BY x.persona_id\n )\n SELECT\n r.persona_id,\n imp.persona_id IS NOT NULL AS compro,\n COALESCE(imp.eur_unico, 0) AS eur_unico,\n COALESCE(imp.eur_primera, 0) AS eur_primera,\n COALESCE(imp.eur_siguientes, 0) AS eur_siguientes\n FROM (SELECT DISTINCT persona_id FROM resp) r\n LEFT JOIN imp USING (persona_id)",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 11:07:41.285000+00:00",
|
|
"refs": [
|
|
"clientes_intel.fact_campana_respuesta",
|
|
"clientes_intel.fact_transaccion"
|
|
]
|
|
},
|
|
"seg_audiencia": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.seg_audiencia`\n CLUSTER BY accion, persona_id AS\n WITH base AS (\n SELECT\n r.persona_id, r.vehiculo_id, r.license_plate,\n r.accion, r.motivo, r.motivo_subcat, r.prioridad_score, r.peso_accion, r.clv_norm,\n r.canal_entrada,\n r.contactable_email, r.contactable_telefono,\n r.email_optout, r.sms_optout, r.do_not_call,\n p.salesforce_customer_id AS salesforce_contact_id,\n p.full_name, p.email, p.phone,\n -- canal recomendado respetando consentimiento\n CASE\n WHEN r.contactable_email THEN 'EMAIL'\n WHEN r.contactable_telefono AND NOT r.do_not_call THEN 'SMS'\n ELSE NULL\n END AS canal_recomendado,\n ROW_NUMBER() OVER (\n PARTITION BY r.persona_id ORDER BY r.prioridad_score DESC, r.peso_accion DESC\n ) AS rk_persona\n FROM `autingo-159109.clientes_intel.reco_acciones` r\n JOIN `autingo-159109.clientes_intel.dim_persona` p USING(persona_id)\n WHERE r.contactable_email OR r.contactable_telefono\n )\n SELECT\n * EXCEPT(rk_persona),\n rk_persona = 1 AS top_persona,\n TRUE AS envio_habilitado,\n CAST(NULL AS STRING) AS bloqueo_motivo\n FROM base\n WHERE canal_recomendado IS NOT NULL;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 15:54:04.407000+00:00",
|
|
"refs": [
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.reco_acciones"
|
|
]
|
|
},
|
|
"seg_cliente_360": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.seg_cliente_360`\n CLUSTER BY rfm_segment, cluster AS\n WITH veh AS (\n SELECT persona_actual AS persona_id,\n COUNT(*) AS n_vehiculos_propios,\n LOGICAL_OR(itv_due_este_anio) AS itv_due_este_anio,\n ROUND(AVG(antiguedad_anios), 1) AS antiguedad_media\n FROM `autingo-159109.clientes_intel.feat_cliente_vehiculo`\n WHERE persona_actual IS NOT NULL GROUP BY persona_actual\n ),\n reco AS (\n SELECT persona_id,\n COUNT(*) AS n_acciones_reco,\n ARRAY_AGG(accion ORDER BY prioridad_score DESC LIMIT 1)[OFFSET(0)] AS top_accion,\n ARRAY_AGG(motivo ORDER BY prioridad_score DESC LIMIT 1)[OFFSET(0)] AS top_motivo,\n ARRAY_AGG(motivo_subcat ORDER BY prioridad_score DESC LIMIT 1)[OFFSET(0)] AS top_submotivo\n FROM `autingo-159109.clientes_intel.reco_acciones` GROUP BY persona_id\n ),\n mut AS (\n SELECT persona_id, MIN(flag) AS flag FROM (\n SELECT DISTINCT agregador_persona_id AS persona_id, 'Cuenta agregadora' AS flag\n FROM `autingo-159109.clientes_intel.map_mutualista_particular`\n UNION ALL\n SELECT particular_persona_id, 'Mutualista'\n FROM `autingo-159109.clientes_intel.map_mutualista_particular` WHERE es_mutualista\n ) GROUP BY persona_id\n ),\n geo AS (\n SELECT d.persona_id, pr.provincia, pr.ccaa\n FROM `autingo-159109.clientes_intel.dim_persona` d\n LEFT JOIN `autingo-159109.clientes_intel.dim_cp_provincia` pr\n ON pr.cp2 = SUBSTR(REGEXP_REPLACE(COALESCE(d.postal_code, ''), r'[^0-9]', ''), 1, 2)\n ),\n cit AS (\n SELECT m.persona_id, COUNT(*) AS n_citas, MAX(a.fec_fecha_cita) AS ultima_cita\n FROM `autingo-159109.ontologia.aurgiCitas_mat` a\n JOIN `autingo-159109.clientes_intel.map_persona_fuente` m\n ON m.fuente = 'tpv' AND m.source_id = a.id_cliente\n WHERE a.id_cliente IS NOT NULL AND a.id_cliente != ''\n AND NOT COALESCE(a.flag_fivetran_deleted, FALSE)\n AND a.fec_fecha_cita <= (SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`)\n GROUP BY m.persona_id\n ),\n promo_mut AS (\n SELECT DISTINCT persona_id\n FROM `autingo-159109.clientes_intel.fact_transaccion`\n WHERE persona_id IS NOT NULL\n AND producto_nav_id IN ('190471','190472','190473','190474','190475','190476','190680','190988')\n )\n SELECT\n p.persona_id, p.full_name, p.es_empresa,\n NOT p.es_excluido AS es_b2c,\n -- ejes de segmentacion\n p.rfm_segment,\n CAST(c.cluster AS STRING) AS cluster,\n t.tipo_cliente, t.clv_nivel,\n p.r_score, p.f_score, p.m_score, p.rfm_score,\n clv.clv_score, clv.clv_decil, clv.clv_norm,\n -- valor / comportamiento\n p.recency_days, p.frequency, p.monetary_total, p.valor_ponderado, p.ticket_medio,\n p.mean_inter_visit_days,\n p.margen_total, p.margen_pct, clv.clv_12m_margen, clv.clv_12m_ingreso, clv.prob_activo,\n p.n_categorias, p.categoria_top, p.n_centros, p.centro_principal,\n p.empresa_principal, COALESCE(dp.canal_entrada, p.canal_preferido) AS canal_entrada,\n -- vehiculo / ITV\n COALESCE(v.n_vehiculos_propios, 0) AS n_vehiculos,\n COALESCE(v.itv_due_este_anio, FALSE) AS itv_due_este_anio,\n v.antiguedad_media,\n -- contactabilidad / RGPD\n dp.score_confianza_norm, dp.data_points,\n COALESCE(dp.contactable_email, FALSE) AS contactable_email,\n COALESCE(dp.contactable_telefono, FALSE) AS contactable_telefono,\n p.email_optout, p.sms_optout, p.do_not_call,\n -- contacto directo (para exportar audiencia)\n p.email, p.phone,\n -- enlace a activacion\n COALESCE(r.n_acciones_reco, 0) AS n_acciones_reco,\n r.top_accion AS top_accion_reco,\n r.top_motivo, r.top_submotivo,\n -- mutualistas: conductor real recuperado tras cuenta agregadora (mutua/flota)\n CASE\n WHEN COALESCE(mut.flag, 'No') = 'Cuenta agregadora' THEN 'Cuenta agregadora'\n WHEN mut.flag = 'Mutualista' OR pm.persona_id IS NOT NULL THEN 'Mutualista'\n ELSE 'No'\n END AS es_mutualista,\n -- geografia del cliente (por CP) y actividad en citas / inactividad\n g.provincia, g.ccaa,\n COALESCE(ci.n_citas, 0) AS n_citas,\n DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), ci.ultima_cita, DAY) AS dias_sin_cita,\n LEAST(p.recency_days, COALESCE(DATE_DIFF((SELECT MAX(fecha) FROM `autingo-159109.clientes_intel.fact_transaccion`), ci.ultima_cita, DAY), p.recency_days)) AS dias_inactivo\n FROM `autingo-159109.clientes_intel.feat_cliente_persona` p\n LEFT JOIN `autingo-159109.clientes_intel.score_clv` clv USING (persona_id)\n LEFT JOIN `autingo-159109.clientes_intel.seg_cluster_persona` c USING (persona_id)\n LEFT JOIN `autingo-159109.clientes_intel.tipologia_cliente` t USING (persona_id)\n LEFT JOIN `autingo-159109.clientes_intel.data_points_contacto` dp USING (persona_id)\n LEFT JOIN veh v USING (persona_id)\n LEFT JOIN reco r USING (persona_id)\n LEFT JOIN mut USING (persona_id)\n LEFT JOIN promo_mut pm USING (persona_id)\n LEFT JOIN geo g USING (persona_id)\n LEFT JOIN cit ci USING (persona_id)\n WHERE NOT p.es_excluido;",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 11:34:06.221000+00:00",
|
|
"refs": [
|
|
"clientes_intel.data_points_contacto",
|
|
"clientes_intel.dim_cp_provincia",
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.fact_transaccion",
|
|
"clientes_intel.feat_cliente_persona",
|
|
"clientes_intel.feat_cliente_vehiculo",
|
|
"clientes_intel.map_persona_fuente",
|
|
"clientes_intel.map_persona_vehiculo",
|
|
"clientes_intel.reco_acciones",
|
|
"clientes_intel.score_clv",
|
|
"clientes_intel.seg_cluster_persona",
|
|
"clientes_intel.tipologia_cliente",
|
|
"ontologia.aurgiCitas_mat"
|
|
]
|
|
},
|
|
"seg_cluster_persona": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.seg_cluster_persona` AS\nWITH pv AS (\n SELECT m.persona_id, s.cluster, v.importe_total,\n ROW_NUMBER() OVER (PARTITION BY m.persona_id ORDER BY v.importe_total DESC NULLS LAST) AS rn\n FROM `autingo-159109.clientes_intel.map_persona_vehiculo` m\n JOIN `autingo-159109.clientes_intel.seg_cluster_vehiculo` s ON s.plate_norm = m.plate_norm\n LEFT JOIN `autingo-159109.clientes_intel.feat_cliente_vehiculo` v ON v.vehiculo_id = m.plate_norm\n)\nSELECT persona_id, cluster FROM pv WHERE rn = 1",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-09 07:41:53.575000+00:00",
|
|
"refs": [
|
|
"clientes_intel.feat_cliente_vehiculo",
|
|
"clientes_intel.map_persona_vehiculo",
|
|
"clientes_intel.seg_cluster_vehiculo"
|
|
]
|
|
},
|
|
"seg_vega_persona": {
|
|
"query": "-- Tabla companera del segmentador (dash 1067 / tab 450). Una fila por persona (B2C+B2B\n-- igual que seg_cliente_360) con las variables estilo \"segmentador Vega\" pedidas, todas\n-- alimentadas desde NUESTRO pipeline clientes_intel + maestro crudo aurgiClientes (por DNI).\n-- Se une con LEFT JOIN v USING(persona_id) en las cards 11196-11202.\n-- Refresco: scheduled query cada 6h.\nCREATE OR REPLACE TABLE `autingo-159109.clientes_intel.seg_vega_persona`\nCLUSTER BY persona_id AS\nWITH base AS (\n SELECT persona_id, tenure_days, ultima_compra\n FROM `autingo-159109.clientes_intel.feat_cliente_persona`\n WHERE NOT es_excluido\n),\ndp AS (\n SELECT persona_id, UPPER(TRIM(document_number)) AS dni, postal_code,\n COALESCE(whatsapp_optout, FALSE) AS whatsapp_optout\n FROM `autingo-159109.clientes_intel.dim_persona`\n),\n-- maestro crudo de clientes, por DNI (pk_dni es unico): edad, poblacion, tipo, franquiciado,\n-- flags de canal cliente y fechas de aceptacion RGPD.\nac AS (\n SELECT UPPER(TRIM(pk_dni)) AS dni,\n ANY_VALUE(num_edad) AS edad,\n ANY_VALUE(desc_poblacion) AS poblacion,\n ANY_VALUE(desc_tipo_cliente) AS tipo_cliente_real,\n LOGICAL_OR(COALESCE(flag_cliente_franquisiado_navision, FALSE)) AS franquiciado_navision,\n LOGICAL_OR(COALESCE(flag_aurgi, FALSE)) AS flag_aurgi,\n LOGICAL_OR(COALESCE(flag_autingo, FALSE)) AS flag_autingo,\n LOGICAL_OR(COALESCE(flag_motortown, FALSE)) AS flag_motortown,\n LOGICAL_OR(COALESCE(flag_cliente_online, FALSE)) AS flag_web,\n DATE(MAX(ts_fecha_aceptacion_privacidad)) AS fecha_acept_privacidad,\n DATE(MAX(ts_fecha_aceptacion_tyc)) AS fecha_acept_tyc\n FROM `autingo-159109.ontologia.aurgiClientes`\n WHERE pk_dni IS NOT NULL AND pk_dni != ''\n GROUP BY dni\n),\nveh AS (\n SELECT persona_actual AS persona_id,\n LOGICAL_OR(UPPER(make) IN (\n 'AUDI','BMW','MERCEDES','MERCEDES-BENZ','VOLVO','LEXUS','JAGUAR','LAND ROVER','PORSCHE',\n 'MASERATI','BENTLEY','FERRARI','LAMBORGHINI','ROLLS-ROYCE','ASTON MARTIN','TESLA','MINI',\n 'ALFA ROMEO','DS','INFINITI','CADILLAC','LINCOLN','JEEP')) AS tiene_vehiculo_lujo\n FROM `autingo-159109.clientes_intel.feat_cliente_vehiculo`\n WHERE persona_actual IS NOT NULL\n GROUP BY persona_actual\n),\nlim AS (SELECT DATE_SUB(MAX(fecha), INTERVAL 365 DAY) AS d FROM `autingo-159109.clientes_intel.fact_transaccion`),\ntx AS (\n SELECT t.persona_id,\n COUNT(DISTINCT NULLIF(t.otr_nav_id, '')) AS n_documentos,\n COUNT(DISTINCT NULLIF(t.id_factura_nav, '')) AS n_facturas,\n ARRAY_AGG(DISTINCT t.categoria IGNORE NULLS) AS cat_comprado,\n ARRAY_AGG(DISTINCT t.grupo IGNORE NULLS) AS grupo_comprado,\n ARRAY_AGG(DISTINCT t.canal IGNORE NULLS) AS canal_comprado,\n ARRAY_AGG(DISTINCT IF(t.fecha >= lim.d, t.categoria, NULL) IGNORE NULLS) AS cat_ultimo_ano,\n ARRAY_AGG(DISTINCT IF(t.fecha >= lim.d, t.grupo, NULL) IGNORE NULLS) AS grupo_ultimo_ano,\n ARRAY_AGG(DISTINCT IF(t.fecha >= lim.d, t.canal, NULL) IGNORE NULLS) AS canal_ultimo_ano\n FROM `autingo-159109.clientes_intel.fact_transaccion` t CROSS JOIN lim\n WHERE t.persona_id IS NOT NULL\n GROUP BY t.persona_id\n)\nSELECT\n b.persona_id,\n ac.edad,\n ac.poblacion,\n ac.tipo_cliente_real,\n COALESCE(ac.franquiciado_navision, FALSE) AS franquiciado_navision,\n ac.fecha_acept_privacidad,\n ac.fecha_acept_tyc,\n dp.postal_code AS codigo_postal,\n dp.whatsapp_optout,\n b.tenure_days AS antiguedad_cliente_dias,\n b.ultima_compra AS fecha_ultimo_mov,\n COALESCE(v.tiene_vehiculo_lujo, FALSE) AS tiene_vehiculo_lujo,\n COALESCE(tx.n_documentos, 0) AS n_documentos,\n COALESCE(tx.n_facturas, 0) AS n_facturas,\n IFNULL(tx.cat_comprado, []) AS cat_comprado,\n IFNULL(tx.grupo_comprado, []) AS grupo_comprado,\n IFNULL(tx.canal_comprado, []) AS canal_comprado,\n IFNULL(tx.cat_ultimo_ano, []) AS cat_ultimo_ano,\n IFNULL(tx.grupo_ultimo_ano, []) AS grupo_ultimo_ano,\n IFNULL(tx.canal_ultimo_ano, []) AS canal_ultimo_ano,\n ARRAY(SELECT x FROM UNNEST([\n IF(COALESCE(ac.flag_aurgi, FALSE), 'Aurgi', NULL),\n IF(COALESCE(ac.flag_web, FALSE), 'Web', NULL),\n IF(COALESCE(ac.flag_autingo, FALSE), 'Autingo', NULL),\n IF(COALESCE(ac.flag_motortown, FALSE), 'MotorTown', NULL)\n ]) x WHERE x IS NOT NULL) AS canales_cliente\nFROM base b\nLEFT JOIN dp USING (persona_id)\nLEFT JOIN ac ON ac.dni = dp.dni\nLEFT JOIN veh v ON v.persona_id = b.persona_id\nLEFT JOIN tx ON tx.persona_id = b.persona_id;\n",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:39:10.071000+00:00",
|
|
"refs": [
|
|
"citaprevia_aurphcp.clientes",
|
|
"clientes_intel.dim_persona",
|
|
"clientes_intel.fact_transaccion",
|
|
"clientes_intel.feat_cliente_persona",
|
|
"clientes_intel.feat_cliente_vehiculo",
|
|
"mssql2022_dbo.anjana_customer",
|
|
"postal_codes.postal_codes",
|
|
"psql_dcpublic.addresses",
|
|
"psql_dcpublic.channels",
|
|
"psql_dcpublic.companies",
|
|
"psql_dcpublic.customers",
|
|
"psql_dcpublic.otr_customers",
|
|
"psql_dcpublic.tpv_customers",
|
|
"psql_dcpublic.tpv_customers_companies",
|
|
"psql_dcpublic.tpv_persons"
|
|
]
|
|
},
|
|
"tipologia_cliente": {
|
|
"query": "\n CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.tipologia_cliente` AS\n SELECT\n f.persona_id,\n f.rfm_segment,\n COALESCE(CONCAT('C', CAST(s.cluster AS STRING)), 'sin cluster') AS cluster,\n c.clv_norm,\n CASE\n WHEN c.clv_norm IS NULL THEN 'n/d'\n WHEN c.clv_norm >= 0.66 THEN 'Alto'\n WHEN c.clv_norm >= 0.33 THEN 'Medio'\n ELSE 'Bajo'\n END AS clv_nivel,\n f.monetary_total,\n -- tipo de cliente = RFM segment x Cluster (el CLV se reporta como atributo)\n CONCAT(\n f.rfm_segment, ' | ',\n COALESCE(CONCAT('C', CAST(s.cluster AS STRING)), 'sin cluster')\n ) AS tipo_cliente\n FROM `autingo-159109.clientes_intel.feat_cliente_persona` f\n LEFT JOIN `autingo-159109.clientes_intel.seg_cluster_persona` s USING (persona_id)\n LEFT JOIN `autingo-159109.clientes_intel.score_clv` c USING (persona_id)\n WHERE NOT f.es_excluido AND f.rfm_segment IS NOT NULL\n ",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-09 11:11:43.092000+00:00",
|
|
"refs": [
|
|
"clientes_intel.feat_cliente_persona",
|
|
"clientes_intel.score_clv",
|
|
"clientes_intel.seg_cluster_persona"
|
|
]
|
|
},
|
|
"tipologia_cliente_resumen": {
|
|
"query": "\n CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.tipologia_cliente_resumen` AS\n SELECT\n tipo_cliente, rfm_segment, cluster,\n COUNT(*) AS n_personas,\n ROUND(COUNT(*) / SUM(COUNT(*)) OVER (), 4) AS pct,\n ROUND(AVG(monetary_total), 0) AS gasto_medio,\n ROUND(SUM(monetary_total), 0) AS gasto_total,\n ROUND(AVG(clv_norm), 3) AS clv_norm_medio,\n COUNTIF(clv_nivel = 'Alto') AS n_clv_alto,\n COUNTIF(clv_nivel = 'Medio') AS n_clv_medio,\n COUNTIF(clv_nivel = 'Bajo') AS n_clv_bajo\n FROM `autingo-159109.clientes_intel.tipologia_cliente`\n GROUP BY tipo_cliente, rfm_segment, cluster\n ORDER BY n_personas DESC\n ",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-06-09 11:11:48.450000+00:00",
|
|
"refs": [
|
|
"clientes_intel.tipologia_cliente"
|
|
]
|
|
},
|
|
"veh_cluster": {
|
|
"query": "CREATE OR REPLACE TABLE `autingo-159109.clientes_intel.veh_cluster` AS\nSELECT\n m.vehiculo_id,\n m.CENTROID_ID AS cluster,\n CASE m.CENTROID_ID\n WHEN 1 THEN 'Servicio puntual gasto bajo'\n WHEN 2 THEN 'Flota / alto valor fiel'\n WHEN 3 THEN 'Coche viejo dormido'\n WHEN 4 THEN 'Coche nuevo activo'\n WHEN 5 THEN 'Coche nuevo inactivo'\n WHEN 6 THEN 'Recurrentes valor medio'\n WHEN 7 THEN 'Coche viejo activo'\n END AS cluster_nombre,\n t.cluster_tecnico,\n t.cluster_tecnico_nombre\nFROM ML.PREDICT(MODEL `autingo-159109.clientes_intel._veh_km_k7`,\n (SELECT * FROM `autingo-159109.clientes_intel._veh_cluster_feat`)) m\nLEFT JOIN (\n SELECT\n vehiculo_id,\n CENTROID_ID AS cluster_tecnico,\n CASE CENTROID_ID\n WHEN 1 THEN 'Monovolumen diésel 7 plazas'\n WHEN 2 THEN 'Utilitario moderno pequeño'\n WHEN 3 THEN 'Compacto familiar diésel antiguo'\n WHEN 4 THEN 'SUV 4x4 potente'\n END AS cluster_tecnico_nombre\n FROM ML.PREDICT(MODEL `autingo-159109.clientes_intel._veh_km_tec_k4`,\n (SELECT * FROM `autingo-159109.clientes_intel._veh_tec_feat`))\n) t USING (vehiculo_id)",
|
|
"stmt": "CREATE_TABLE_AS_SELECT",
|
|
"last_run": "2026-07-01 14:46:10.517000+00:00",
|
|
"refs": [
|
|
"clientes_intel._veh_cluster_feat",
|
|
"clientes_intel._veh_km_k7",
|
|
"clientes_intel._veh_km_tec_k4",
|
|
"clientes_intel._veh_tec_feat"
|
|
]
|
|
}
|
|
} |