
This content was created by Cristian Camps. This content was uploaded by Cristian Camps. This is a YouTube video titled "KQL desde cero: aprende Kusto Query Language!" (uploaded 2026-08-06). The title indicates a Spanish-language tutorial/presentation teaching Kusto Query Language (KQL) from the basics — likely a step-by-step instructional video covering KQL concepts and examples. Metadata available: content_type=YOUTUBE and a thumbnail URL; no transcript excerpt provided.
Chapters
Buenas, bienvenidos un día más a un nuevo vídeo. En el día de hoy paramos un poco todo lo que es la creación de la infraestructura para hacer una cosa que creo que es bastante útil y que os ayudará un montón, que es una guía sobre KQL. Este vídeo está destinado sobre todo a la gente que nunca lo ha tocado, que no sabe lo que es y no sabe para lo que sirve, y que quizá lo necesita porque, oye, han encontrado trabajo de analista o por lo que sea. Entonces empezaremos desde cero, el nivel más básico, y bueno, lo complicaremos hasta cierto punto, hasta joins y unions. Y nada, quiero separar el vídeo por capítulos para que sea más fácil que encontréis lo que buscáis en este vídeo. Entonces seguramente aquí abajo, en, digamos, en la timeline del vídeo, tendréis todos los capítulos, vale. Es igual que el post del blog. Que lo tendréis abajo en la descripción. Lo iremos separando por capítulos y cada capítulo explicaré pues lo equivalente en el blog. Entonces nada, vamos allá. Muy bien, pues como siempre empezamos desde el post. Aquí lo tenéis. Os recuerdo, aunque tapo un poco con la cámara, siempre os podéis suscribir a la newsletter. Ahí os aviso de los posts, los vídeos, cualquier actividad. No hago spam, intento no hacerlo, solo envío correo cuando de verdad creo algo. Entonces, oye, siempre es útil, ¿no? Entonces, si podéis suscribiros, pues oye, me haríais un favor y suscribíos al canal también. El link de este post lo tenéis abajo en la descripción del vídeo, vale. Entonces, esto es un ejercicio, este vídeo quiero que lo hagáis, sobre todo, ¿cómo lo explico? Este vídeo está enfocado a la persona que no sabe KQL. Por lo tanto, voy a recomendar encarecidamente que abráis el post porque os va a hacer falta, vale, porque hacemos ejemplos, porque ahí lo tenéis todo mucho más documentado. Entonces os recomiendo muy fuerte abrir el post y seguir los pasos. De entrada, lo primero que vamos a hacer es explicar el ecosistema, no, la plataforma donde hacemos las queries. En este caso lo tenemos aquí al principio, lo tenemos en Also known as Microsoft LA Demo, Log Analytics Demo. Entonces, si clicáis aquí, yo ya lo tengo abierto, os abrirá esta pestaña. Aquí tendréis la zona donde nosotros podremos buscar logs, es decir, el Log Analytics Workspace. Para ello, bueno, nos dan varios avisos. Donde yo los voy a ignorar porque ya os explicaré yo. Pero bueno, lo primero que os tenéis que quedar, y este es como el capítulo 0, es en lo siguiente. Tenemos el Simple Mode, que en mi opinión no me— para análisis de seguridad no me es muy útil. Siempre buscaremos el KQL Mode. Entonces clicamos aquí y como veis ya se nos abre para hacer la query. En la banda lateral tenemos las tablas Tendremos las queries, tendremos las funciones que hoy no las tocaremos, y tendremos el query history, el historial de queries que hemos hecho. Entonces yo lo que recomiendo siempre es Kaggle mode, luego abrir cualquiera de estas y pinear, vale. Que en este caso no sé por qué hay un bug y no me está cargando esto. Dadme un segundo y lo arreglo. Muy bien, pues ya he conseguido arreglarlo. Entonces vamos con lo que sería el capítulo 0 del post. Que es cómo se estructuran los datos dentro de un Log Analytics Workspace. Para ello, como podréis ver aquí, tendremos varios conjuntos de tablas. Esto pueden ser tipos de conectores, soluciones, conjuntos de conectores, dependerá, ¿no? Pero en este caso, en este ejemplo de test, tendremos, por ejemplo, en Log Management, tendremos todos estos tipos de tablas. Dentro de las tablas lo que tendremos serán los campos de las tablas. Entonces, si desplegamos, por ejemplo, la tabla App Events, pues tendremos los campos, no sé, AppVersion, ClientBrowser, y al lado del campo tendremos el tipo de campo: string en caso de texto, tendremos, a ver si encuentro uno más, dynamic en caso de que, por ejemplo, sea un JSON, tendremos campos de tiempo, a ver si encuentro alguno, mira, estos son reales, Debería haber alguno que sea de campo tiempo en algún sitio. Mira, aquí tenemos de tipo integer. Bueno, tenemos diferentes tipos. Entonces, esto es muy importante, es como declarar variables en cualquier código de programación. Como veréis, este código KQL se parece mucho a SQL. La principal diferencia es que SQL sirve tanto como para consultar datos como también para editar, añadir, borrar datos. En el caso de KQL es un lenguaje, digamos, que solo para buscar datos. Nosotros no vamos a intentar añadir datos, crear, borrar, modificar. Solo es un lenguaje que se dice de consulta. Por lo tanto, nuestro objetivo siempre va a ser consultar los datos que ya están en el Log Analytics Workspace. Dicho esto, ¿cómo llegan los datos aquí? A través de conectores. Esto ya será otro tema que trataremos en el futuro, pero tenéis que quedaros con que el Log Analytics Workspace es una piscina donde están todos los logs. Y dentro de tantos logs y tanta información, nosotros utilizaremos un lenguaje que se llama KQL, que está basado en tablas y campos, con el que nosotros accederemos a esa información. Por cierto, paréntesis, antes de pasar al tema 1, añadir que aquí podremos crear varias queries, varias tabs simultáneas, como podéis ver. De todas formas, tampoco es muy útil porque veréis que se pueden ejecutar queries parcialmente y se pueden apilar queries una encima de otra. Entonces no es necesario tener las tabs, es por un tema de organización, pero no es estrictamente necesario. Ya eso ahora lo veremos en un los siguientes temas. Pero bueno, que sepáis también que están pues todas las tabs. Además podemos seleccionar por tiempo, aunque también lo podremos hacer dentro de la query, y la cantidad de resultados que queremos, que también lo podremos seleccionar dentro de la query. Que sepáis que existe, vale. Pues sigamos. Los temas 1 y 2 del post los voy a hacer juntos porque son muy básicos. Entonces vamos a empezar con el tema 1, que son los comentarios, porque cuando tienes queries largas, a ti lo que te interesa es pues enterarte de lo que estás haciendo. Y si alguien necesita acceder a tu query, pues saber cómo lo hiciste, ¿no? Entonces, para insertar comentarios es con la doble barra. Entonces, como veis, la doble barra hace que el código pase a ser de color verde, y entonces pues podemos escribir un comentario. De esta forma, esto de aquí no se ejecuta, no sirve para nada, sirve solo como comentarios a la query que nosotros queremos hacer, para nosotros enterarnos de lo que estamos haciendo. Luego, pasando al tema 2 del POST, pues si queremos mostrar una tabla, yo qué sé, por ejemplo la tabla de app requests, pues simplemente con escribir el número, el nombre de la tabla, que como veis tenemos un chivado, yo lo llamo chivado, pero bueno, asistente, solo con poner el nombre de la tabla, si le damos a correr, lo que va a hacer es mostrarnos todos los resultados de la tabla. Aquí veis que en la tabla app requests, que de hecho voy a cambiar el comentario, por ejemplo, vamos a poner mostramos la tabla app requests. Aquí como veis tenemos arriba todos los campos de la tabla, que de hecho si los desplegamos aquí para que lo tengáis un poco más visible, pues aquí los tenéis con toda la información, ¿no? Y cada línea de estas es un log, es decir, esto de aquí es un log, esto de aquí es otro log, esto de aquí es otro. Y los logs pues los podemos desplegar individualmente para ver todos los campos. En lugar de ir desplazando así, pues podemos abrirlos. Pero bueno, aquí tenemos toda la tabla con toda la información de AppliQuest de este test de prueba. Bueno, este, este tenant de prueba. Muy bien, pasamos al capítulo 3, que básicamente resuelve un problema que tenemos aquí, ¿no? Que es, claro, aquí tenemos mucha información. ¿Y cómo puedo encontrar lo que yo quiero? No sé, imaginaros que yo lo que quiero es ver de todos estos logs, quiero saber cuáles no han sido success, por ejemplo, ¿no? Que aquí vemos pues que hay algunos que sí que son success porque es true, es de tipo booleano, y hay que son false, por lo tanto no ha sido exitoso, no ha sido exitosa la request. Pongamos que yo quiero saber solo los que no han sido success porque estoy buscando, no sé, me invento, el fallo en sí, porque fallan, ¿no? ¿Qué tienen en común todos los logs que fallan? Para ello vamos a utilizar el WHERE, que es como sería un filtro. Entonces, para ello tenemos que insertar una nueva línea, agregaremos una barra vertical, espacio, y como veis aquí ya nos chiva varias órdenes que podemos dar. Entonces elegimos WHERE y después del WHERE irá la condición. En este caso buscaremos que el campo success sea false, sea igual a false. En este caso, si ejecutamos esta query, como veréis, únicamente nos muestra los logs donde este campo es igual a false. Como podéis ver, y además esto se puede concatenar, esto podemos añadir otro campo más donde además de que esto sea false, de que es access sea false, el result code sea igual a 0. Me invento. En este caso filtrará y solo nos dará los logs donde success sea false y result code sea 0. Y de esta forma podemos ir filtrando sobre todos los datos que tenemos. Es muy importante, y esto para el futuro será, vamos, primordial, que esto de aquí devuelve una tabla. Es decir, mira, ahora voy a ejecutar la query. Como he dicho antes, voy a ejecutar la query por partes. Esta parte de aquí devuelve una tabla que es la tabla AppRequest con este filtro, y al resultado de este filtro se le vuelve a filtrar. Esto será muy importante para luego, es, es, hay que entenderlo. Entonces, ¿cómo funciona? La tabla que devuelve esta query es el input para la siguiente línea. Entonces, la tabla request queda filtrada en esta línea, y el resultado que devuelve esta tabla, que como veis la he ejecutado aquí parcialmente, lo que hace es volverla a filtrar bajo esta condición. Entonces, es como que se le añade Bueno, el segundo filtro se le añade, obviamente, pero qué hace es el resultado del primer filtro lo mete como input al segundo filtro. Esto va a ser importante para los join, sobre todo. Además, para complementar todo lo que es el WHERE, pongamos que yo lo quiero hacer todo en una línea, pues podríamos utilizar los comandos AND o OR para combinar condiciones. Es decir, si yo quiero que el success sea false y además el result code sea 0, lo podemos combinar de esta forma. Y entonces el resultado debería ser el mismo, que sea success false y que el result code sea 0. También lo podemos hacer con un OR, con, bueno, con el comando OR. En este caso, lo que hará será mostrarnos cualquier log que combine una de las dos opciones, es decir, o que success sea false, pero que también success pueda ser true con result code 0. Veis como en este caso, aunque success es false, como result code es 0, pues también lo muestra, y viceversa, como aquí el result code es 500, pero como el access es false, pues como cumple una de las dos condiciones, pues te lo muestra igualmente. Esto es muy útil también para, pues eso, para combinar condiciones a la hora de filtrar, que sepáis que también se puede hacer. Muy bien, pues yendo al capítulo 4 del post, vamos a mirar el comando ago. Esto básicamente es un filtro de tiempo, por así decir. Ago lo que hace es devolver el día de hoy. Entonces aquí, como veis, tenemos el time generated, cuando se generó el log. Entonces, si queremos saber cuál es la actividad de los últimos 20 minutos o en las últimas 2 horas, lo podemos hacer con un filtro. En este caso sería when el time generated sea mayor, o en este caso igual, a mí me gusta siempre poner mayor o igual, a ago, y dentro del ago vamos a poner, me invento, 24 horas. ¿Qué significa esta línea de aquí? Lo que hacemos es coger los logs donde el tiempo que se generó es mayor a hoy, bueno, hace 24 horas, por así decir. Entonces básicamente nos quedamos con los logs de las últimas 24 horas. Aquí si lo corremos pues tendremos todos los logs de las últimas 24 horas. Sí, que sepáis que se puede cambiar, se puede poner 30 días, se puede poner un minuto. No sé si en algún minuto nos dará un resultado. Sí, pues como podéis ver, al ser logs de muestra te lo va a dar, pero como podéis ver, todos los logs es de hace un minuto. Dicho esto, también se puede combinar fechas, es decir, en lugar de este de aquí podemos poner un between y que sea entre hace, me invento, 2 días y hace, no sé, bueno, esto sería ago 2 días y ago 2 horas. Esto cogería cualquier log de entre hace 2 días y hace 2 horas en esta ventana de tiempo. Si lo corremos pues nos dará hace 2 horas o antes, hasta llegar a hace 2 días, que sepáis que también se puede hacer. Y de la misma forma podéis coger los logs que sean más nuevos o que sean más antiguos, de hace, no sé, 15 días. Bueno, sería ago, perdón, 15 días. Esto lo que hace es coger de los logs más antiguos de 15 días. Veis, el 17 del 7, etcétera. Es básicamente para filtrar por tiempo este comando. Eso es bastante útil. Así que como veis aquí en el time range, ahora pone setting query. ¿Por qué? Porque aquí está. Aquí de hecho podríamos añadir un comentario que fuera filtramos por tiempo. Y ya lo tenemos. Muy bien, vamos al capítulo 5 del post. Este es un comando que vais a usar siempre en GraphQL, igual que el where. Estos son los comandos más, más famosos. Entonces, como veis en esta tabla, quiero poner un ejemplo real. En App Requests tengo muchos campos, ¿no? Y obviamente yo puedo filtrar por, no sé, por por valores dentro de cada log, no, pero también, y si no me interesa ver todos los campos cada vez que busco algo, entonces para ello está el comando project o project away incluso, si queremos quitarlos, pero nos interesará más project. En este caso, en project lo que hace es mostrarnos los campos que a nosotros nos interesan. Es decir, si yo estoy analizando, me invento, a la request en sí, pues lo que yo querré ver es el name de la request, la URL de la request, me invento, y si es success. Entonces, filtrando, y aunque esto es case sensitive, entonces con cuidado. Entonces, una vez proyecto estos 3 campos, cuando yo ejecuto sobre la tabla, lo que nos va a devolver es solo estos datos. No hemos filtrado, no hemos filtrado nada. Los resultados son exactamente los mismos. Es decir, si antes la tabla me devolvía 1000 logs, ahora me va a devolver los 1000 logs igual, solo que me va a devolver una tabla nueva con los 3 campos que he seleccionado. Básicamente es para quitar la información de la tabla que no necesito en este momento. Pongamos que he filtrado, yo qué sé, por success igual a false. Pongamos que al ser booleano no hace falta ponerlo con comillas para hacer string. Entonces, en este caso, como veis, nos lo va a mostrar todo false, pero nos va a mostrar solo los campos que hemos pedido. Si hacemos un Project Away para que comparéis, Project Away, ya veréis lo que va a pasar. Vamos a poner los mismos, name, URL y success, para que comparéis. Lo que hace es devolvernos la misma tabla quitando los campos que hemos dicho. Veis, en este caso no están. Si ahora añadiésemos operation name y volvemos a ejecutar, ya veréis cómo esta columna desaparece. Veis, ya no está esta operation ID, pero no operation name. Entonces es una forma de mostrar únicamente los datos que a nosotros nos interese. Esto es, pues, como entendéis, muy útil, ¿no? Porque al final te quitas el máximo ruido posible cuando estás buscando datos y te quedan las tablas pues lo más pequeñas posibles, que eso también ayuda luego a la performance de las queries. Una query funciona mucho mejor con tablas pequeñas y bien filtradas y y bien proyectadas que no con tablas masivas con millones de datos y miles de columnas. Además, que se me olvidaba, porque tengo una chuleta aquí, también podemos renombrar los campos. Es decir, no solo nos muestra los campos que queremos, sino que además, por ejemplo, si quisiéramos traducir esto al español, pues podríamos hacer nombre es igual a name, URL la dejaríamos igual. Aquí diríamos satisfactorio, me invento, Igual a success, y operation name, operación, operación, vamos a llamarlo, o nombre, vamos a decir nombre operación. Este caso, cuando volvemos a ejecutar, como veis, los campos, los nombres de los campos han cambiado. Es una tabla completamente diferente traducida al español, vale, que también sepáis que se puede hacer. Y para reportes, para workbooks en Sentinel, pues puede ser muy útil esto, vale. Tema 6 del post, la cosa se empieza a complicar, os aviso. Como he dicho antes, había campos que eran de tipo dinámico, que en muy resumidas cuentas suelen ser JSON. Y aquí tengo un ejemplo en otra tabla completamente diferente, en la tabla App Events. Entonces he hecho un project para que veáis pues 3 campos en concreto, porque no me interesan el resto. El que me interesa de hecho es el campo properties, que lo tengo aquí, que al desplegar cualquier log, como veis, el campo properties tiene muchos datos dentro porque es de tipo dinámico. Entonces, al desplegar dentro del log, desplegamos el campo properties, propiedades, y tendremos pues varias cosas, vale. Yo me voy a centrar en el subcampo level para hacerlo más fácil, pero bueno, imaginad que yo quiero acceder a este campo porque claro yo aquí en properties no puedo hacer que properties sea igual a info, no, o que no puedo, como veis, no puedo filtrar por level dentro de properties porque no es un campo en sí, es un subcampo dentro de properties. ¿Cómo puedo acceder yo a este subcampo? Pues no sé si habréis hecho programación, pero como las clases madre y las clases hijas Bueno, toda la herencia de clases, ¿no? Que sí, que sería a través de un punto. Pues es básicamente así. Si yo pongo un punto, lo que estoy queriendo decir es que accedo a los campos dentro de esa clase, dentro de ese campo dinámico. Entonces yo aquí buscaría pues level. Ojo, que aquí el chivato ya no, ya no está, y es case sensitive. Entonces con mucho cuidado. Entonces, si yo hiciera properties.level, estoy entrando dentro de properties y yendo al campo level. Entonces, como veréis ahora mismo, enlace, cuando le dé a run, esta tabla desaparecerá porque la estoy proyectando y proyectaré solo el level dentro de properties. Veréis, aquí lo tenéis. Entonces, dentro de level, pues ahora ya sí ya podré filtrar, pero claro, ¿Cómo lo hacemos? Imaginad que yo lo que quiero hacer ahora es filtrar que properties, me invento, properties level, que es el nuevo campo que tenemos aquí, sea igual a, no sé, o que sea diferente, por hacerlo, por variar un poco, a info. Lo tendremos que hacer con la barra baja, no, porque es como se ha llamado al nuevo campo. Entonces ahora en esta tabla sí podremos filtrar. Como veis, es diferente, es vacío, pero bueno, ya podemos utilizarlo. Claro, esto es un poco follón, ¿no? Porque imaginad que yo no quiero trabajar todo el rato con acceder a subclases, sino entonces, ¿qué podemos hacer para estandarizar esto de alguna forma? Podemos crear una nueva columna. Ya sé que antes he dicho que no se podían crear datos en KQL, y de hecho no se puede. Lo que sí que podemos es modificar la estructura de las columnas y de las tablas. Entonces, lo que no podemos es crear logs. Crear logs los crearemos a través de los Data Connectors. Pero en este caso, lo que sí que podemos hacer es un extend. Básicamente es extender la tabla una columna más. Tenéis aquí la columna, la vamos a llamar, me invento, level. Y si no recuerdo más, es igualando, pues, level, ¿a qué será igual? Properties.level. O sea, estamos igualando esa columna a la columna generada del campo level dentro de properties. Entonces, si en el project ahora mismo lo quitamos, ya veréis que podemos adjuntar el nuevo campo que hemos creado, que es level. Y entonces, en este caso, si vamos a correr, pasará lo mismo. En lugar de properties.level, ahora nos hemos creado nuestra propia columna llamada level que contiene los mismos datos y funciona de la misma forma. Aquí podemos filtrar otra vez, o el level no sea info. Bueno, perdón, tengo que poner las comillas. O el level no sea info, pues nos dará los resultados. Ahora imaginad, yo qué sé, que aparte voy a correr esto de aquí un segundo para que me muestre todo. Y dentro de properties queremos crear, bueno, queremos filtrar, me invento, qué más hay, vamos a ir a message, por ejemplo, ¿no? Pues lo que vamos a hacer es otro extend, la vamos a llamar message, que sea properties punto message. Y ojito, vuelvo a decir que es case sensitive. Y aquí pues lo volveremos a mostrar en el proyecto. El field me lo cargo porque ya no me interesa. Y aquí lo tenéis, message. Entonces ahora podemos trabajar con esto como cualquier, como con cualquier tabla. Aquí podremos decir, me invento, ahora, where message contains, contiene no sé, config, por poner algo. Entonces aquí veréis que cualquier, o sea, solo nos muestra los datos donde message contiene config dentro del texto. Entonces que sepáis que los campos dinámicos, que voy a proyectarlo aquí otra vez, properties, podemos acceder a los subcampos dentro de ese campo dinámico Y no solo eso, sino que podemos crear columnas nuevas, asignarles esos valores y además trabajar con ellos como con cualquier otro campo. No hay ningún problema. Simplemente eso, hacer un extend para crear la columna nueva y hacer la asignación, que en este caso se haría con el nombre de la tabla punto y el campo. Muy bien, pues vamos ya con el capítulo 7 del post de los 13, creo que era. O sea que ya hemos pasado la mitad del post. Este vídeo es denso, ya lo sé, pero bueno. Quien esté aprendiendo, pues oye, bien le vendrá. En este caso, ¿qué queremos hacer? Pues creo que esto es más útil si os explico primero el problema y luego os doy la solución. En este caso, como podéis ver aquí, un segundo, que la cámara esté bien. Sí, imaginad que yo quiero saber pues los result code, ¿no? De la tabla app request otra vez. Pues como veis, aquí me devuelve la lista de todos los valores hechos en el proyecto. Por lo tanto, solo me muestra el campo result code. Y aquí pues tengo toda la lista, pero claro, esto es un follón. Yo ahora mismo no tengo ni idea, yo no sé cómo interpretar estos datos, no, porque cuántos diferentes hay, cuántos, no sé cómo sé, cómo interpreto estos datos, no, cuántos tipos hay, cuántos de cada. Pues esto se hace con el comando summarize, aquí lo tenéis, y aquí Utilizando summarize, summarize, lo que, lo que podéis hacer es operaciones matemáticas, vamos a decir, para interpretar los datos. Por ejemplo, si en summarize le pongo count, llamo a la función count by, cuento por result code, que es el único campo, como veréis, lo que me da es los diferentes tipos de result code. Me genera una tabla con los diferentes tipos de result code y cuántas veces salen presentes en los logs. Ojo, no es la suma de todos ellos, cuenta en todos los logs de la tabla cuántas veces el result code es 200, cuántas veces es 0, cuántas veces es 404. Entonces te va dando, pues, pues de tantos, de estos hay tantos, de estos Tantos, vale. Hay más, por ejemplo, yo qué sé, dejadme un segundo que miro la chuleta. Se puede hacer average, se puede hacer sumatorios, vale. Importante también que, un segundo, que miro la chuleta. Podemos renombrarlo. Aquí, como veis, el campo se llama count, pero yo puedo llamarlo cuenta Bueno, vamos a llamarlo cuenta, y la cuenta va a ser igual a esto de aquí. Entonces, cuando volvemos a correrlo, nos devuelve, en lugar de count, pues cuenta, para renombrarlo. De esta forma podemos interpretar los datos, es decir, y se puede combinar. De hecho, podemos hacer un summarize, me invento, peticiones, peticiones será igual a count, o sea, contará todos los logs para saber cuántas peticiones han habido. Luego duración media, media será igual, un segundo que miro la chuleta, al average duration. Ah, bueno, claro, es que estoy haciendo un proyecto, un segundo. Pues mira, copio la tabla, bueno, copio la línea y acabamos juntos. Que si no es que claro, acordarme de todo es imposible. Entonces aquí lo veréis, dentro de app request tendremos las peticiones, que será simplemente un count de todas las peticiones. Luego tendremos la duración media, que será la media pues de la duración en milisegundos del result code, y luego el client country o region. Entonces cuando ejecutamos esto lo veréis aquí. Serán pues las peticiones desde United States y la duración media de este result code. Para este result code, el count, la región y las peticiones y la duración media. Entonces esto va muy bien para interpretar los datos, para saber pues, de hecho los puedes ordenar, luego miraremos en el siguiente, la siguiente sección lo veréis, cómo ordenar estos datos por orden alfabético, etcétera. Ahora lo vemos, vale. Pues vamos al tema, bueno, al capítulo 8 del post. Y esto va a ser muy, este de hecho es bastante facilito, ya lo veréis. Son varias órdenes que son muy sencillas, muy fáciles de ejecutar. Me veréis ver la chuleta porque, porque hay varias para no dejarme ninguna. Pero, pero bueno, vamos, vamos al lío. En la tabla Abricuest, como siempre, vamos a poner, me invento, que success sea falso. Bueno, de hecho, como es booleano, no hace falta esto. Entonces aquí lo tenemos, ¿no? Todos los logs donde success es falso. Ahora imaginad que yo lo que quiero es contarlos, contar cuántos de ellos son falsos. Pues simplemente con una nueva entry, una nueva línea, y count me va a dar cuántos logs de todos la cantidad de que success es falso, por así decir, cuéntalos, por así decir. Ahora imaginad que lo que quiero es, un segundo que miro la chuleta, si yo hago un project, me invento, de result_code igual, me va a dar todos estos, ¿no? Imaginad que yo no quiero como antes saber cuántos había de cada, sino simplemente quiero saber cuántos diferentes hay. Pues simplemente con poner aquí distinct me va a decir qué ha pasado. Distinct, ah, distinct result code, perdón. Lo que me va a dar es cuántos diferentes hay de ellos, no como en el summarize que me va a contar también cuántos hay o la operación matemática que hayáis hecho. En este caso simplemente me dice que cuántos diferentes hay. No me da más información, simplemente es eso. Oye, pues en este campo tienes estos datos. Obviamente, si es un campo de tipo texto, vas a tener, no sé, me invento, en caso de nombres, pues vas a tener una lista enorme, ¿no? Pero en este caso, mira, 1, 2, 3, 4, 5, 6, 7 y 8. Y de hecho, aquí lo que podríamos hacer es count. Oye, quiero que me cuentes cuántos en este, en el campo result code, cuántos datos hay diferentes. Me debería devolver una tabla que sea 8, pues tienes 8 tipos de result codes en todos estos logs. Se pueden combinar también. Vamos al next, pues imaginad que yo, que sé que estáis testeando, y Estoy ejecutando la query. Aquí tenéis muchos logs, como veis, tenéis un montón. Pero yo, por lo que sea, no necesito ver tanto porque no necesito una muestra tan grande. Entonces lo que puedo hacer es, oye, de todos los logs que me puedes dar, dame solo 10 logs. Entonces esto se hace con take, y como veis, pues me va a dar 10. Esto también es un sinónimo, se puede decir como limit, limítame lo que me vas a dar a 10 logs. Y entonces te va a dar 10. Esto de aquí, como veis, ha cambiado esto de aquí, el show. Entonces esto básicamente es un límite. Si nosotros borramos esta línea, ahora lo tenemos aquí arriba. Es como el ago, que cuando ponías ago el time range deja de tener sentido. Pues ahora esto igual, es para filtrar cuántos logs te va a dar la búsqueda. Luego, siguiendo, imaginad, yo qué sé, voy a buscar algún campo que me interese con texto. A ver si algún campo con texto más o menos así, yo qué sé, app role instance, que tiene texto y tiene números, ¿no? Pues vamos a hacer un project por app role instance. Si vamos a correr, nos va a dar todo esto. Buah, pero claro, aquí hay mucha información. Y yo quiero ordenarla. Pues, ¿cómo podemos hacer esto? Con un ORDER BY. Si nosotros hacemos ORDER BY AbroadInstance, porque es la única columna que tenemos ascendiente, pues nos lo va a filtrar por orden alfabético ascendiente. Entonces empezará con números y luego, a ver si encontramos algún Algún texto, no, porque llegamos al límite. Si lo ponemos descendiente, ahora nos debería dar por orden alfabético, empezando por la P, que será la última letra, luego F, etcétera, etcétera. Claro, porque siempre tengo que poner el campo, porque imaginamos que aquí tengo otro, no sé, tengo el campo name, no sé si existía. Pues entonces yo estoy ordenando igualmente por esta columna. Si yo cambio la columna por la cual estoy ordenando a name, pues ahora veréis que el orden cambia. La primera entry es por orden alfabético inverso en relación al campo name, vale. Esto tiene un sinónimo también, que en lugar de order es sort, sort by name descendiente, vale, que sepáis es lo mismo, order by, sort by. Es exactamente lo mismo. Y de la misma forma tenemos también el top que me da— un segundo que vuelvo. Puedo elegir top 10 name. No, mentira, esto era para íntegros. Dame un segundo y lo compruebo. Vale, sí, perdonadme, a estas horas ya no funciono bien. Sí, el top 10, lo que, bueno, he puesto top 10, pero el top lo que hace es Es como una combinación de order by y take o limit, vale. De lo que va a hacer es ordenártelos y además solo te va a seleccionar los que tú quieras. Entonces, si lo hacemos por nombre, te lo va a hacer alfabéticamente. Y los 10, si aquí le meto top 1000, pues lo mismo, me va a dar los primeros 1000. Es eso, una combinación de order by y el límite. Vale, capítulo 9, el extend. Aunque ya lo hemos visto en el capítulo 6 del post, o bueno, o aquí abajo donde te marquen la timeline, capítulo 6, que era los campos dinámicos y cómo acceder a ellos. Vamos a profundizar un poco más en el extend. Recuerdo, el extend lo que hace es crear una nueva columna dentro de la tabla. OK, dicho esto, por ejemplo, tenemos el campo duración en milisegundos, ¿no? Si no me equivoco, en la tabla app request. OK, entonces imaginad que yo quiero el mismo campo extend, pero lo voy a hacer en duración sin milisegundos. Y esto entonces, ¿cómo lo calculo? Pues va a ser el campo duración, o sea, los datos van a ser los mismos que en el campo duración, pero los voy a dividir entre 1000. En este caso me debería dar pues las dos, la duración y la duración en milisegundos. Entonces yo tengo la duración en segundos, así que lo llamo duración S de segundos, duración S. Y duración en milisegundos. Y como veis, es la traducción. Entonces se pueden hacer cálculos matemáticos, como he dicho antes, no hay ningún problema. Dicho esto, también, bueno, se pueden hacer varias cosas, que es asignar valores dependiendo del resultado. Eso se hace con la función case. Ahora, ahora os la explico. Un segundo, vale, ya está. Perdonad que lo tenía que repasar. Bueno, pues imaginad que yo ahora lo que quiero es añadir una etiqueta en función de cuánto dura la app request. En este caso utilizaremos el extend igual, lo que, bueno, vamos a llamarlo, me invento, performance, performance, y la igualaremos a un case. El case, pues igual os acordáis del switch case en programación, pues es más o menos lo mismo. Entonces el case, pues vamos a abrir los paréntesis igual que siempre, y aquí dentro, a mí me gusta intentarlo, no es necesario, pero a mí me gusta siempre intentar el valor. Pondremos los casos. El primer caso será, pues por ejemplo, que la duración en milisegundos sea menor 250, lo separamos por una coma, y esto le asignaremos la etiqueta de rápida. La duración ha sido una duración rápida, y coma para el siguiente campo. Se pueden combinar, entonces esto de aquí también podría ser, podríamos combinarlo con una duración de milisegundos que sea mayor a 0, por ejemplo. Pero bueno, se entiende que esto es un poco redundante. Entonces, en el siguiente campo, si la duración en milisegundos es mayor a 250, bueno, mayor o igual, para no excluir 250, mayor o igual a 250, y la duración en milisegundos es menor a 700, por ejemplo, lo vamos a llamar que es una performance normal. Y para el resto, como valor por defecto, ya ponemos el resultado, que será una duración lenta. Entonces esto de aquí ya lo cerraríamos, quedaría así. Y cuando lo corremos, como veis, en base, en función de cuánto ha durado, pues tendréis la performance. Aquí tendréis una normal por ejemplo, que está entre 250 y 700. Luego aquí tendréis una lenta que es mayor de 700, porque es el por defecto, por así decir. Dicho esto, también esto lo podéis combinar, como antes he dicho, con un summarize count by performance, por ejemplo. Entonces te va a decir el cuánto de performance hay en cada, en cada petición. Pues mira, de normales tenemos estas, de rápidas tenemos estas, y de lentas tenemos estas. Y de hecho lo podemos ordenar, sort by performance, y lo vamos a hacer en orden alfabético. Entonces pues lentas, normal y rápida. Entonces es una forma pues de ordenar los datos, que sepáis que se puede hacer. Muy bien, siguiendo con el mismo ejemplo, vamos al capítulo 10 del post, que son los renders. Entonces Este capítulo es bastante sencillito, como veréis. Imaginad que nosotros queremos visualizar los datos, no tenerlos en una tabla. Pues simplemente con añadir una línea más que sea render, y aquí tendréis pues todas las opciones, podéis visualizar los datos. Por ejemplo, si pongo pie chart y le doy a run, pues te va a mostrar pues los datos visualizados. Para que os hagáis una idea de otro, pues yo qué sé, el área chart, me invento. Aquí lo tenéis. Y uno más, no sé, el de columnas, column chart. Pues aquí tendréis las columnas. Estaba muy bien para las workbooks de Sentinel. Esto es lo bueno para crear las gráficas y todo de forma automática, es lo que se usa, la KQL con un render al final. Importante para el render, obviamente necesitáis tener como mínimo dos columnas, la de valores y la del nombre, si no, no funcionará. Es decir, si yo aquí me invento a un Project y le pongo solo performance, es decir, que me dé las performance, y yo aquí hago un render, esto no funcionará, Ya veréis, si yo le doy ves, te va a dar un error porque necesita saber los números para hacer el gráfico. Entonces, que tengáis en cuenta eso. Muy bien, pues siguiendo con el capítulo 11 del post, vamos a explicar qué son las variables. Las variables, pues como en programación, nos permiten asignar un valor a una variable y trabajar con ella. ¿Cómo se definen? Pues con el comando let. Aquí podremos asignar una variable, por ejemplo, la variable número y asignarle el valor 10. Y muy importante, el punto y coma después. En este caso, para asignar variables, siempre, siempre, siempre después va un punto y coma. Hay varios tipos, podemos hacer textos también, podemos crear la variable texto y asignarle el valor texto, por ejemplo. Entonces ya tendríamos dos variables y con esto podemos trabajar, compararlas, podemos utilizarlas como, pues eso, como thresholds o lo que necesitemos. Muy importante también y muy curioso que también podemos asignar variables de tipo tabla. Por ejemplo, si yo me voy a la tabla App Events, events, y vamos a ver qué campos tiene para quedarnos con, ah, mira, lo tenía antes de aquí del ejemplo. Tenemos los campos name y app version. Como veréis, me devuelve la misma tabla, que es esta de aquí. Todo esto lo podemos asignar a una variable. Es decir, nosotros aquí podríamos, editando un poco el código, podríamos crear la variable mi invento tabla e igualarla. Y aquí sí que tendríamos que abrir paréntesis. A mí personalmente me gusta intentarlo todo para que, para que quede bien, para que quede bonito a la vista. Entonces ahora mismo, con el punto y coma, súper importante, ya tendríamos asignada una variable tabla. ¿Cómo la mostraríamos? Pues como siempre, pues escribiendo tabla, que es el nombre de nuestra variable, y como veréis, pues nos va a añadir pues la variable tabla. Aquí dentro también podemos hacer más cosas, podemos coger y, yo qué sé, extend, me invento, No sé, ahora mismo, nombre, nombre es igual a name, por hacer algo. Entonces duplico el campo name con, y lo llamo nombre. Entonces aquí veréis que la tabla pasa a tener otro campo nombre que es igual al campo name, para que veáis que también se puede trabajar con ellas. Otra cosa curiosa de las variables es que también las podemos definir para fechas y para días, bueno, para tiempos mejor dicho. Es un tipo también que podemos utilizar, por ejemplo, let inicio y va a ser ago hace, yo qué sé, 30 días para el inicio de la query, punto y coma, que siempre me lo dejo. Let final y va a ser ago un segundo, me invento. Entonces nosotros si queremos mirar, yo qué sé, la tabla app_events, where time generated, cuando el log se generó, between, y aquí podremos poner inicio. Bueno, espera, claro, si dejamos un espacio La definición de variables no sirve. Inicio, dos puntos, final. Y en este caso pues sería como buscar entre los últimos 30 días que hemos definido y hace un segundo. Porque antes no me salía porque tenía el espacio. Entonces, claro, esto de aquí es como tener una nueva tab, recordad. Entonces esto de aquí son dos queries completamente diferentes, independientes entre sí. Para que sean la misma query y las variables funcionen, tienen que estar juntas dentro de la misma query. Esto es importante también tenerlo en cuenta. Vale, el siguiente capítulo del POST, lo que voy a hacer es saltarme el 12, que considero que es un poco más complicado, e ir directamente al 13, y después haremos el 12. En este caso trataremos el UNION, que es pues apilar tablas como esperaríamos que se apilan, ¿no? Una encima de la otra. Coger una tabla y pegarle otra. Si las tablas tienen los mismos campos, todo queda igual. Es decir, una tabla se pone debajo de la otra y todo funciona como esperaríamos. Y si las tablas, perdón, no tienen los mismos campos, entonces se van a combinar todos los campos de todas las tablas y donde no haya datos pues estará vacío. Vamos a hacer un ejemplo. Como podéis ver aquí, he definido dos variables que serán request, que será un project del tiempo, el tipo y el nombre de la tabla app requests, y luego lo mismo con eventos, app events. Pues tengo los mismos campos que comparten campos, entonces tengo dos tablas de tres campos cada una. Y lo que hago, bueno, si queréis, aquí podemos ver cómo son cada tabla. Entonces, la tabla request quedaría con estos 3 campos, como he dicho, con unos GETs por aquí, con un tipo. Y luego la tabla events la tenemos aquí, la ejecutamos de forma parcial, y lo tenemos aquí con Application Monitor. Y como veis, los campos no tienen los mismos datos, comparten los campos, pero dentro de esos campos no tienen los mismos datos. Entonces, perdón, me voy a cargar esto porque claro, no queremos mostrar estas tablas. Ahora vamos a combinar, apilar estas dos tablas. Más que combinar, apilar, porque combinar será el join. Entonces, ¿cómo se hace esto? Pues muy fácil, con el comando union. Y aquí vamos a poner qué tablas queremos apilar una encima de la otra. En este caso pues será la tabla, bueno, la variable tabla request y la variable tabla events. A ver si me sale events con ese. En este caso ya veréis que el resultado va a ser muy parecido porque tendremos una combinación de las dos tablas, de los datos mezclados de ambas tablas porque comparten los campos. Veis, aquí tenemos Application Monitoring y aquí tenemos los GET de App Request. Entonces, como veis, estos datos son de App Events y estos datos de aquí son de App Request. Lo que ha pasado es que las dos tablas se han combinado, se han apilado, y luego pues dentro internamente se ordenan y todo. No es que se apilen directamente una encima de la otra, depende de cómo esté ordenado todo. Y en este caso podemos seguir trabajando, podemos hacer un project de lo que queramos. O sea, esto es el resultado queda, el union es una tabla más con la que podemos trabajar, o incluso podemos asignarle una variable. Sería pues en este caso, yo qué sé, podríamos hacer el let union, bueno, unión no porque compartiría el nombre, pero let apilación, por así decir, la combinación de tablas, y luego trabajar con esa variable. Entonces es eso. ¿Qué pasa cuando no comparten los mismos campos? Aquí vamos a hacer un rename. Por ejemplo, y vamos a decir nombre es igual a name. En este caso, déjame, en este caso, en lugar de name va a ser nombre, ¿no? Como hemos visto antes, pues si hacemos el union, lo que veremos es que se crean dos campos en la apilación, y en cada tabla veremos los datos diferentes. No sé si en este caso, dejadme un segundo, que esto no lo tengo muy fresco. Where name no sea vacío. Aquí está, aquí tenemos, ya decía yo, aquí tenemos los resultados de la otra tabla. Es decir, los valores de esta tabla se han guardado en el campo name. Como podemos ver aquí. Y los valores de esta tabla se han guardado en el campo nombre, como podréis ver aquí. Entonces se han apilado, pero en la apilación cada una ha elegido un camino, una, una, un campo. Entonces que sepáis que esto también se puede hacer en función de, bueno, dónde os interesa guardar los datos en cada query. Vale, pues por último vamos al capítulo número 13, donde podemos ver el join. El join lo que hace es combinar tablas en base a un campo común que tengan entre ellas. Es decir, pongamos un ejemplo, este de aquí, donde la tabla app_request tiene el campo— uy, perdón, ahora vuelvo a ejecutar— tiene un campo URL, y la tabla app_pageviews tiene un campo URL también. Aquí lo tenéis, vale. Pues en torno a ese campo vamos a combinar las dos tablas. Para que se combine, pues ahora como lo explico, la combinación puede ser de distintos tipos, ahora entraremos, pero es muy importante que quede claro que la combinación se hace en torno a un campo. Entonces, como veréis, la sintaxis es la siguiente, es pues una nueva línea Y en este caso aquí iría URL porque vamos a hacer un join en base a URL. Entonces primero va el join, luego el tipo de join, que si no se especifica por defecto es inner join. Entonces esto es un poco redundante, se podría poner así, pero bueno. Y entonces luego la tabla, ojito, que aquí podríamos poner un WHERE o lo que sea, podríamos trabajar con la tabla otra vez. Pero bueno, en este caso vamos a usar las tablas completas. Y luego, ¿sobre qué se hace el join? ¿Sobre qué campo va a girar el join? Que en este caso va a ser en torno al campo variable URL. Entonces, una vez se ejecuta esto, como veis, ambas comparten el mismo campo. Una vez se ejecuta, lo que veremos es que se crea una entry para cada URL donde ambos logs que tienen la misma URL se combinan. Es decir, cada log que contenga la misma URL se va a ir combinando. No se combinan las tablas, no se apilan las tablas, sino que se combinan. ¿Qué pasa en este caso? Si, por ejemplo, en este caso hay un caso donde la URL de apprequest no está en pageviews, lo que va a pasar es que ese log no se va a tener en cuenta y se va a descartar porque este, en este caso, es un join inner. Solo va a mostrar los datos que compartan ambas tablas, es decir, las URLs que tengan en común, y en base a esas URLs que tengan en común se van a mostrar el resto de datos. No sé si me estoy explicando bien. Entonces, aquí tengo en el blog, tenéis un link a la documentación oficial de Microsoft donde podréis ver los diferentes tipos de joins. Que están pues en esta imagen de aquí. Si hago un poco de zoom, aquí los tendréis, vale. Teniendo en cuenta que cada círculo son dos tablas, el left outer se quedará con la tabla izquierda más lo que tenga en común con la tabla derecha. Full outer se queda con las dos tablas, es prácticamente un union, por así decir. El right outer pues lo contrario. El left semi se va a quedar solo con lo de la tabla izquierda que contenga también la tabla derecha. Y bueno, aquí tenéis un ejemplo, no voy a explicar todos, pero bueno, el que hemos hecho ahora es el inner join, que es solo lo que ambas tablas tienen en común. Ok, y bueno, luego tenemos el anti o inner unique. Right anti, por ejemplo, sería lo que tiene la tabla derecha que no tiene la tabla izquierda. Vale, esto ya depende de cada caso, pero tenéis que quedaros con la idea esa de que para el join, uy, un segundo que quito esto, para el join lo que hace es no apila las tablas como el union, sino que en base a un campo en común que tienen, esto es como en SQL, exactamente igual. Lo que hace es, en campo, ese, en torno a ese campo común que tienen, lo que va a hacer es buscar los logs que compartan ese campo y entonces rellenar la tabla campo por campo o línea por línea, por así decir. Es una combinación, dependerá del tipo de join, pero una combinación en torno al identificador, que en este caso es el campo URL, vale. No es una apilación, no es lo mismo. Entonces, esto es un poco lo más complicado de entender. Tampoco voy a profundizar mucho porque tengo pendiente hacer otro vídeo sobre este tema, lo acabaré haciendo. Entonces creo que por hoy suficiente. Recordaros que en el post, aquí lo tenéis, tenéis todos los links a la documentación, tenéis todos los links, absolutamente todo. Y nada, seguramente los siguientes vídeos sean de cómo configurar Defender for XDR y cómo ya acabar con todo con toda la configuración del ecosistema, que es algo que necesitamos hacer para empezar y hacer cosas chulas. Ya sé que los vídeos de infraestructura a veces se pueden hacer un poco pesados, pero luego acabaremos haciendo cosas muy chulas, ya veréis. Entonces nada, cualquier duda, como he dicho, estoy en la caja de comentarios o por privado en la sección de contacto del blog. Y nada, que vaya muy bien. Chao. ¡Hola!
More from Cristian

How AI Is Redefining Corporate Security — Empower Conference 2026 (Zurich) [ENGLISH]

Onboarding de dispositivos en Intune y Defender for Endpoint (tutorial paso a paso)

Licencias Microsoft para ciberseguridad: ¿Business Premium, E3 o E5? (comparativa 2026)


