dba sql-server – Intentando encontrar la última vez que ha cambiado un valor

Pregunta:

Tengo una tabla que tiene una identificación, un valor y una fecha. Hay muchos ID, valores y fechas en esta tabla.

Los registros se insertan en esta tabla periódicamente. El ID siempre será el mismo, pero ocasionalmente el valor cambiará.

¿Cómo puedo escribir una consulta que me dé la ID más la hora más reciente en que ha cambiado el valor? Nota: el valor siempre aumentará.

A partir de estos datos de muestra:

  Create Table Taco
 (  Taco_ID int,
    Taco_value int,
    Taco_date datetime)

Insert INTO Taco 
Values (1, 1, '2012-07-01 00:00:01'),
        (1, 1, '2012-07-01 00:00:02'),
        (1, 1, '2012-07-01 00:00:03'),
        (1, 1, '2012-07-01 00:00:04'),
        (1, 2, '2012-07-01 00:00:05'),
        (1, 2, '2012-07-01 00:00:06'),
        (1, 2, '2012-07-01 00:00:07'),
        (1, 2, '2012-07-01 00:00:08')

El resultado debería ser:

Taco_ID      Taco_date
1            2012-07-01 00:00:05

(Porque 00:05 fue la última vez que Taco_Value cambió).

Respuesta:

Estas dos consultas se basan en el supuesto de que Taco_value siempre aumenta con el tiempo.

;WITH x AS
(
  SELECT Taco_ID, Taco_date,
    dr = ROW_NUMBER() OVER (PARTITION BY Taco_ID, Taco_Value ORDER BY Taco_date),
    qr = ROW_NUMBER() OVER (PARTITION BY Taco_ID ORDER BY Taco_date)
  FROM dbo.Taco
), y AS
(
  SELECT Taco_ID, Taco_date,
    rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID, dr ORDER BY qr DESC)
  FROM x WHERE dr = 1
)
SELECT Taco_ID, Taco_date
FROM y 
WHERE rn = 1;

Una alternativa con menos locura por la función de ventana:

;WITH x AS
(
  SELECT Taco_ID, Taco_value, Taco_date = MIN(Taco_date)
  FROM dbo.Taco
  GROUP BY Taco_ID, Taco_value
), y AS
(
  SELECT Taco_ID, Taco_date, 
    rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID ORDER BY Taco_date DESC)
  FROM x
)
SELECT Taco_ID, Taco_date FROM y WHERE rn = 1;

Ejemplos en SQLfiddle


Actualizar

Para aquellos que Taco_value registro, hubo controversia sobre lo que Taco_value si Taco_value pudiera repetirse alguna vez. Si pudiera ir de 1 a 2 y luego volver a 1 para cualquier Taco_ID dado, las consultas no funcionarán. Aquí hay una solución para ese caso, incluso si no es la técnica de espacios e islas que alguien como Itzik Ben-Gan puede soñar, e incluso si no es relevante para el escenario del OP, puede ser relevante para un futuro lector. Es un poco más complejo y también agregué una variable adicional: un Taco_ID que solo tiene un Taco_value .

Si desea incluir la primera fila para cualquier ID donde el valor no cambió en absoluto en todo el conjunto:

;WITH x AS
(
  SELECT *, rn = ROW_NUMBER() OVER 
    (PARTITION BY Taco_ID ORDER BY Taco_date DESC)
  FROM dbo.Taco
), rest AS (SELECT * FROM x WHERE rn > 1)
SELECT  
  main.Taco_ID, 
  Taco_date = MIN(CASE 
    WHEN main.Taco_value = rest.Taco_value 
    THEN rest.Taco_date ELSE main.Taco_date 
  END)
FROM x AS main LEFT OUTER JOIN rest
ON main.Taco_ID = rest.Taco_ID AND rest.rn > 1
WHERE main.rn = 1
AND NOT EXISTS 
(
  SELECT 1 FROM rest AS rest2
   WHERE Taco_ID = rest.Taco_ID
   AND rn < rest.rn
   AND Taco_value <> rest.Taco_value
) 
GROUP BY main.Taco_ID;

Si desea excluir esas filas, es un poco más complejo, pero aún cambios menores:

;WITH x AS
(
  SELECT *, rn = ROW_NUMBER() OVER 
    (PARTITION BY Taco_ID ORDER BY Taco_date DESC)
  FROM dbo.Taco
), rest AS (SELECT * FROM x WHERE rn > 1)
SELECT 
  main.Taco_ID, 
  Taco_date = MIN(
  CASE 
    WHEN main.Taco_value = rest.Taco_value 
    THEN rest.Taco_date ELSE main.Taco_date 
  END)
FROM x AS main INNER JOIN rest -- ***** change this to INNER JOIN *****
ON main.Taco_ID = rest.Taco_ID AND rest.rn > 1
WHERE main.rn = 1
AND NOT EXISTS
(
  SELECT 1 FROM rest AS rest2
   WHERE Taco_ID = rest.Taco_ID
   AND rn < rest.rn
   AND Taco_value <> rest.Taco_value
)
AND EXISTS -- ***** add this EXISTS clause ***** 
(
  SELECT 1 FROM rest AS rest2
   WHERE Taco_ID = rest.Taco_ID
   AND Taco_value <> rest.Taco_value
)
GROUP BY main.Taco_ID;

Ejemplos actualizados de SQLfiddle

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım