none
Filtrar información NOT BETWEEN RRS feed

  • Pregunta

  • Hola,

    Me gustaría saber si es posible filtrar datos que no tengan registro alguna después de determinada fecha, es decir tengo una base de datos de alumnos y mensualmente los alumnos se matriculan, pero no todos lo hacen de manera constante, ya que algunos puede estar en el mes de Marzo y no matricularse para Abril, pero pueden volver en Mayo por ejemplo. Lo que deseo lograr es poder filtrar a todos los alumnos que estudiaron por ejemplo hasta mayo del 2019, pero que no se encuentran matriculados en octubre de este año. Se me ocurrió que podría ayudarme con el between anteponiendo el NOT puesto que he visto algunos ejemplos en google, pero no sé si sea la mejor manera. Tengo SQL Server 2008 R2. Muchas gracias 

    Saludos

    martes, 1 de octubre de 2019 15:10

Respuestas

  • Otra opción:

    WITH mat
         AS (
    	/* recogemos el idalumno de matriculas para el periodo */
    	SELECT distinct m.idalumno
             FROM matriculas m
                  INNER JOIN alumnos a ON m.idalumno = A.id
             WHERE m.fechaMatricula >= '20190101'
                   AND m.fechaMatricula < '20190601'
        ), aus as  (
    /* segundo conjunto con los alumnos del segundo periodo */
             SELECT distinct m.idalumno
             FROM matriculas m
                  INNER JOIN alumnos a ON m.idalumno = A.id
             WHERE m.fechaMatricula >= '20191001'
                   AND m.fechaMatricula < '20191101')
    /* En la salida, mezclamos ambos conjuntos */
         SELECT m.idalumno, 
                a.nombre
         FROM mat m 
              INNER JOIN alumnos a ON a.id = m.idalumno
    		left join aus on m.idalumno = aus.idalumno
    	   where
    /* pero solo queremos, los que en el segundo conjunto no están */
     aus.idalumno is null
    

    • Marcado como respuesta Carlos Sk martes, 1 de octubre de 2019 20:19
    martes, 1 de octubre de 2019 19:27

Todas las respuestas

  •  todos los alumnos que estudiaron por ejemplo hasta mayo del 2019, pero que no se encuentran matriculados en octubre de este año

    Podrías meter una condición "exists" que filtre los registros anteriores al 1 de Mayo (o de Junio, dependiendo de que ese "hasta" sea o no inclusivo) y un "not exists" que suprima los registros que no existen en octubre. Te he agregado un "distinct" para evitar las repeticiones, ya que de lo contrario un mismo alumno podría aparecer varias veces si se matriculó varias veces antes de Mayo.

    Select distinct Alumno from laTabla as t1
    where EXISTS (select 1 from laTabla as t2 where t1.ClavePrimaria=t2.ClavePrimaria and Fecha < '20190501')
    and NOT EXISTS (select 1 from laTabla as t3 where t1.ClavePrimaria=t3.ClavePrimaria and Fecha between '20191001' and '20191031')
    
    

    martes, 1 de octubre de 2019 15:36
  • Hola Carlos Sk:

    No es una buena idea, de cara a rendimiento. Not significa que obligas al motor a leer todos los datos fila por fila, para saber si no esta incluido.

    Existen muchas alternativas, pero deberías de especificar muy bien tu escenario (modelo de tablas y sus relaciones).

    Un ejemplo

    CREATE TABLE alumnos
    (id     INT
    , nombre VARCHAR(15)
    );
    GO
    
    CREATE TABLE matriculas
    (id             INT IDENTITY(1, 1)
    , idalumno       INT
    , fechaMatricula DATETIME
    );
    GO
    insert into alumnos(id,nombre)
    values
    (1,'ana'),
    (2,'pedro'),
    (3, 'luisa'),
    (4,'jimena');
    go
    insert into matriculas (idalumno, fechaMatricula)
    values
    (1,'20190101'),
    (1,'20190201'),
    (1,'20190301'),
    (1,'20190401'),
    (1,'20190501'),
    (1,'20190601'),
    (2,'20190101'),
    (2,'20190201'),
    (2,'20190501'),
    (3,'20190101'),
    (3,'20190201'),
    (3,'20190301'),
    (3,'20190401'),
    (3,'20190601'),
    (4,'20190101'),
    (4,'20190201'),
    (4,'20190501');
    go

    Tengo 4 alumnos y se han matriculado alguna vez en los 6 meses.

    SELECT MONTH(m.fechaMatricula) AS mes
    	 , a.id
    	 , a.nombre
    	   FROM matriculas m
    			LEFT JOIN alumnos a ON a.id = m.idalumno
    	   GROUP BY MONTH(m.fechaMatricula)
    			  , a.id
    			  , a.nombre;

    Salida


    martes, 1 de octubre de 2019 15:53
  • Hola, veamos tengo una tabla alumno y una tabla matricula ambas unidas por el id de alumno. Ahora bien las matriculas son mensuales por lo que lo ideal sería que en un año el alumno presente 12 registros, pero esto no sucede puesto que los alumnos algunas veces estudian de corrido y otras no. Ahora bien para poder organizar una campaña para el próximo mes me pidieron que les brindara un listado de los alumnos que estudiaron de Enero a Mayo de este año y que no están matriculados en el mes de Octubre. Espero ahora si haberme dado a entender mejor.
    martes, 1 de octubre de 2019 17:15
  • Hola Carlos Sk:

    CREATE TABLE alumnos
    (id     INT
    , nombre VARCHAR(15)
    );
    GO
    
    CREATE TABLE matriculas
    (id             INT IDENTITY(1, 1)
    , idalumno       INT
    , fechaMatricula DATETIME
    );
    GO
    insert into alumnos(id,nombre)
    values
    (1,'ana'),
    (2,'pedro'),
    (3, 'luisa'),
    (4,'jimena');
    go
    
    insert into matriculas (idalumno, fechaMatricula)
    values
    (1,'20190101'),
    (1,'20190201'),
    (1,'20190301'),
    (1,'20190401'),
    (1,'20190501'),
    (1,'20190601'),
    (2,'20190101'),
    (2,'20190201'),
    (2,'20190501'),
    (3,'20190101'),
    (3,'20190201'),
    (3,'20190301'),
    (3,'20190401'),
    (3,'20190601'),
    (4,'20190101'),
    (4,'20190201'),
    (4,'20190501'),
    (1,'20190701'),
    (1,'20190901'),
    (2,'20190901'),
    (2,'20191001'),
    (2,'20191101'),
    (3,'20191001'),
    (3,'20191101'),
    (3,'20191201'),
    (4,'20190901'),
    (4,'20191001'),
    (4,'20191101');

    El alumno 1, 2, 3 y 4 estuvieron matriculados en ese periodo, pero en octubre están todos menos el 1.

    Una solución es:

    /* Todos los idalumno de matriculas para el periodo solicitado */
    SELECT m.idalumno, a.nombre
             FROM matriculas m
                  INNER JOIN alumnos a ON m.idalumno = A.id
             WHERE m.fechaMatricula >= '20190101'
                   AND m.fechaMatricula < '20190601'
             EXCEPT
    	    /* de los ids del primer conjunto excepto los del segundo periodo */
             SELECT m.idalumno, a.nombre
             FROM matriculas m
                  INNER JOIN alumnos a ON m.idalumno = A.id
             WHERE m.fechaMatricula >= '20191001'

    Salida

    idalumno    nombre
    ----------- ---------------
    1           ana
    (1 fila afectada)

    Except

    https://docs.microsoft.com/en-us/sql/t-sql/language-elements/set-operators-except-and-intersect-transact-sql?view=sql-server-2017


    martes, 1 de octubre de 2019 19:03
  • Otra opción:

    WITH mat
         AS (
    	/* recogemos el idalumno de matriculas para el periodo */
    	SELECT distinct m.idalumno
             FROM matriculas m
                  INNER JOIN alumnos a ON m.idalumno = A.id
             WHERE m.fechaMatricula >= '20190101'
                   AND m.fechaMatricula < '20190601'
        ), aus as  (
    /* segundo conjunto con los alumnos del segundo periodo */
             SELECT distinct m.idalumno
             FROM matriculas m
                  INNER JOIN alumnos a ON m.idalumno = A.id
             WHERE m.fechaMatricula >= '20191001'
                   AND m.fechaMatricula < '20191101')
    /* En la salida, mezclamos ambos conjuntos */
         SELECT m.idalumno, 
                a.nombre
         FROM mat m 
              INNER JOIN alumnos a ON a.id = m.idalumno
    		left join aus on m.idalumno = aus.idalumno
    	   where
    /* pero solo queremos, los que en el segundo conjunto no están */
     aus.idalumno is null
    

    • Marcado como respuesta Carlos Sk martes, 1 de octubre de 2019 20:19
    martes, 1 de octubre de 2019 19:27
  • Deleted
    martes, 1 de octubre de 2019 19:57