none
Sumatorio filtrando numero de repeticiones RRS feed

  • Pregunta

  • Buenos días a todos,

    Tengo un problema con una query y no se como solucionarlo. Tengo unos reportes y necesito sumar los datos de los reportes, el problema está en que los reportes los hacen unos operarios y más de un operario puede hacer reporte para el mismo dato y el mismo periodo de tiempo. Eso me da datos erroneos. Voy a explicarlo en detalle.

    Tabla Reporte

    ID-Capitulo-Operario-Periodo
    1-A-001-11/2016
    2-A-001-12/2016
    3-A-003-1/1017
    4-A-002-1/1017
    5-A-003-2/1017
    6-A-001-3/1017
    7-A-001-4/1017
    8-A-002-4/1017
    9-A-004-5/1017
    10-A-005-5/1017
    11-A-001-6/1017
    12-A-001-7/1017

    Tabla DatosReporte

    ID-idReporte-DatoASumar
    X-1-3
    X-2-4
    X-3-2
    X-4-2
    X-5-3
    X-6-5
    X-7-8
    X-8-8
    X-9-1
    X-10-1
    X-11-1
    X-12-4

    Entonces necesito sumar todos los valores de la columna la DatosASumar de la tabla DatosReporte. 

    El filtro es por Año (todos los reportes del 2017 por ejemplo), Capitulo (Todos los A por ejemplo, esto ya lo he puesto filtrado en el ejemplo para no liar mucho). Ahora viene lo complicado. Si por ejemplo 2 operarios han rellenado el DatoASumar para el mismo capitulo y el mismo periodo necesito que solo se sume una vez (Si os fijáis los valores de DatoASumar se repiten si pertenecen a un reporte del mismo periodo, por eso necesito que solo se sumen 1 vez).

    He probado de hacer un having count = 1 pero eso no tiene mucho sentido porque te coge las filas que se repitan una vez, yo en realidad necesito que en el caso de que se repitan solo me sume el dato 1 vez, seria algo así como hacer un TOP(1) de cada mes y luego sumarlo... Pero entiendo que debe de haber formas mas elegantes de solucionar este problema.

    Muchas gracias.


    Animo!




    jueves, 23 de febrero de 2017 8:34

Respuestas

  • Marc,

    Seria de mucha ayuda si tambien posteas la DDL, data de ejemplo en forma de sentencias INSERT, asi como el resultado esperado. De esa forma tendremos un script con que probar y ahorrar nuestro tiempo (valioso).

    Pudieras intentar resolver el problema usando funciones de rango (ranking functions). Si unes ambas tablas por las columnas con las que se relacionan y enumeras las filas basandonos en el criterio dado (Capitulo, Periodo, DatoASumar) entonces puedes filtar mas adelante solo para la fila con enumeracion igual a uno.

    DECLARE @T1 table (
    ID char(1) NOT NULL,
    idReporte int NOT NULL,
    DatoASumar int NOT NULL,
    PRIMARY KEY (ID, idReporte)
    );
    
    INSERT INTO @T1
    	(ID, idReporte, DatoASumar)
    VALUES
    	('X', 1, 3),
    	('X', 2, 4),
    	('X', 3, 2),
    	('X', 4, 2),
    	('X', 5, 3),
    	('X', 6, 5),
    	('X', 7, 8),
    	('X', 8, 8),
    	('X', 9, 1),
    	('X', 10, 1),
    	('X', 11, 1),
    	('X', 12, 4);
    
    DECLARE @T2 table (
    ID int NOT NULL,
    Capitulo char(1) NOT NULL,
    Operario char(3) NOT NULL,
    Periodo char(7) NOT NULL,
    PRIMARY KEY (ID)
    );
    
    INSERT INTO @T2
    	(ID, Capitulo, Operario, Periodo)
    VALUES
    	(1, 'A', '001', '11/2016'),
    	(2, 'A', '001', '12/2016'),
    	(3, 'A', '003', '01/2017'),
    	(4, 'A', '002', '01/2017'),
    	(5, 'A', '003', '02/2017'),
    	(6, 'A', '001', '03/2017'),
    	(7, 'A', '001', '04/2017'),
    	(8, 'A', '002', '04/2017'),
    	(9, 'A', '004', '05/2017'),
    	(10, 'A', '005', '05/2017'),
    	(11, 'A', '001', '06/2017'),
    	(12, 'A', '001', '07/2017');
    
    SELECT * FROM @T1;
    SELECT * FROM @T2;
    
    DECLARE
    	@Periodo char(4) = '2017',
    	@Capitulo char(1) = 'A';
    
    WITH R AS (
    SELECT
    	A.ID AS A_ID,
        A.Capitulo,
        A.Operario,
        A.Periodo,
    	ROW_NUMBER() OVER(PARTITION BY A.Capitulo, A.Periodo, B.DatoASumar ORDER BY A.ID) AS rn,
    	B.ID AS B_ID,
        B.idReporte,
        B.DatoASumar
    FROM
    	@T2 AS A
    	INNER JOIN
        @T1 AS B
    	ON B.idReporte = A.ID
    WHERE
    	Periodo LIKE '%/' + @Periodo
    	AND Capitulo = @Capitulo
    	
    )
    SELECT
    	*
    FROM
    	R
    WHERE
    	rn = 1
    ORDER BY
    	R.Capitulo,
    	R.Periodo,
    	R.A_ID;
    GO

    En el query final puedes hacer la suna u operacion deseada.

    Como te das cuenta, filtrar para un anio dado indica tener que manipular la columna [Periodo] en la clausula WHERE lo cual no es recomendable. Si Periodo indica un mes en especifico entonces usa un dato tipo fecha para que puedes usar aritmetica de fechas en su lugar.


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas


    jueves, 23 de febrero de 2017 14:04

Todas las respuestas

  • Marc,

    Seria de mucha ayuda si tambien posteas la DDL, data de ejemplo en forma de sentencias INSERT, asi como el resultado esperado. De esa forma tendremos un script con que probar y ahorrar nuestro tiempo (valioso).

    Pudieras intentar resolver el problema usando funciones de rango (ranking functions). Si unes ambas tablas por las columnas con las que se relacionan y enumeras las filas basandonos en el criterio dado (Capitulo, Periodo, DatoASumar) entonces puedes filtar mas adelante solo para la fila con enumeracion igual a uno.

    DECLARE @T1 table (
    ID char(1) NOT NULL,
    idReporte int NOT NULL,
    DatoASumar int NOT NULL,
    PRIMARY KEY (ID, idReporte)
    );
    
    INSERT INTO @T1
    	(ID, idReporte, DatoASumar)
    VALUES
    	('X', 1, 3),
    	('X', 2, 4),
    	('X', 3, 2),
    	('X', 4, 2),
    	('X', 5, 3),
    	('X', 6, 5),
    	('X', 7, 8),
    	('X', 8, 8),
    	('X', 9, 1),
    	('X', 10, 1),
    	('X', 11, 1),
    	('X', 12, 4);
    
    DECLARE @T2 table (
    ID int NOT NULL,
    Capitulo char(1) NOT NULL,
    Operario char(3) NOT NULL,
    Periodo char(7) NOT NULL,
    PRIMARY KEY (ID)
    );
    
    INSERT INTO @T2
    	(ID, Capitulo, Operario, Periodo)
    VALUES
    	(1, 'A', '001', '11/2016'),
    	(2, 'A', '001', '12/2016'),
    	(3, 'A', '003', '01/2017'),
    	(4, 'A', '002', '01/2017'),
    	(5, 'A', '003', '02/2017'),
    	(6, 'A', '001', '03/2017'),
    	(7, 'A', '001', '04/2017'),
    	(8, 'A', '002', '04/2017'),
    	(9, 'A', '004', '05/2017'),
    	(10, 'A', '005', '05/2017'),
    	(11, 'A', '001', '06/2017'),
    	(12, 'A', '001', '07/2017');
    
    SELECT * FROM @T1;
    SELECT * FROM @T2;
    
    DECLARE
    	@Periodo char(4) = '2017',
    	@Capitulo char(1) = 'A';
    
    WITH R AS (
    SELECT
    	A.ID AS A_ID,
        A.Capitulo,
        A.Operario,
        A.Periodo,
    	ROW_NUMBER() OVER(PARTITION BY A.Capitulo, A.Periodo, B.DatoASumar ORDER BY A.ID) AS rn,
    	B.ID AS B_ID,
        B.idReporte,
        B.DatoASumar
    FROM
    	@T2 AS A
    	INNER JOIN
        @T1 AS B
    	ON B.idReporte = A.ID
    WHERE
    	Periodo LIKE '%/' + @Periodo
    	AND Capitulo = @Capitulo
    	
    )
    SELECT
    	*
    FROM
    	R
    WHERE
    	rn = 1
    ORDER BY
    	R.Capitulo,
    	R.Periodo,
    	R.A_ID;
    GO

    En el query final puedes hacer la suna u operacion deseada.

    Como te das cuenta, filtrar para un anio dado indica tener que manipular la columna [Periodo] en la clausula WHERE lo cual no es recomendable. Si Periodo indica un mes en especifico entonces usa un dato tipo fecha para que puedes usar aritmetica de fechas en su lugar.


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas


    jueves, 23 de febrero de 2017 14:04
  • Gracias! Fue de infinita ayuda!

    Animo!

    miércoles, 8 de marzo de 2017 10:10