Pregunta

Tengo una tabla de historial en SQL Server que básicamente rastrea un elemento a través de un proceso.El elemento tiene algunos campos fijos que no cambian durante el proceso, pero tiene algunos otros campos, incluidos el estado y la identificación, que aumentan a medida que aumentan los pasos del proceso.

Básicamente, quiero recuperar el último paso para cada elemento con una referencia de lote.Entonces si hago un

Select * from HistoryTable where BatchRef = @BatchRef

Devolverá todos los pasos para todos los artículos del lote, por ejemplo

ID Estado Referencia de lote Número de elementos
1       1       Batch001        100
1       2       Batch001        110
2       1       Batch001        60
2       2       Batch001        100

Pero lo que realmente quiero es:

ID Estado Referencia de lote Número de elementos
1       2       Batch001        110
2       2       Batch001        100

Editar:Disculpas: parece que no puedo hacer que las etiquetas TABLE funcionen con Markdown; seguí la ayuda al pie de la letra y se ve bien en la vista previa.

¿Fue útil?

Solución

Es un poco difícil entender el diseño de su tabla; creo que SO se comió sus delimitadores.

La forma básica de manejar esto es AGRUPAR POR sus campos fijos y seleccionar un MÁXIMO (o MIN) para algún valor único (una fecha y hora generalmente funciona bien).En tu caso yo pensar que GROUP BY sería BatchRef y ItemCount, y Id será su columna única.

Luego, vuelva a unirse a la tabla para obtener todas las columnas.Algo como:

SELECT * 
FROM HistoryTable
JOIN (
   SELECT 
       MAX(Id) as Id.
       BatchRef,
       ItemCount
   FROM HsitoryTable
   WHERE
       BacthRef = @batchRef
   GROUP BY
       BatchRef,
       ItemCount
 ) as Latest ON
   HistoryTable.Id = Latest.Id

Otros consejos

Suponiendo que tiene una columna de identidad en la tabla...

select 
    top 1 <fields> 
from 
    HistoryTable 
where 
    BatchRef = @BatchRef 
order by 
    <IdentityColumn> DESC

Suponiendo que los ID de los artículos estén numerados de forma incremental:

--Declare a temp table to hold the last step for each item id
DECLARE @LastStepForEach TABLE (
Id int,
Status int,
BatchRef char(10),
ItemCount int)

--Loop counter
DECLARE @count INT;
SET @count = 0;

--Loop through all of the items
WHILE (@count < (SELECT MAX(Id) FROM HistoryTable WHERE BatchRef = @BatchRef))
BEGIN
    SET @count = @count + 1;

    INSERT INTO @LastStepForEach (Id, Status, BatchRef, ItemCount)
        SELECT Id, Status, BatchRef, ItemCount
        FROM HistoryTable 
        WHERE BatchRef = @BatchRef
        AND Id = @count
        AND Status = 
        (
            SELECT MAX(Status) 
            FROM HistoryTable 
            WHERE BatchRef = @BatchRef 
            AND Id = @count
        )

END

SELECT * 
FROM @LastStepForEach
SELECT id, status, BatchRef, MAX(itemcount) AS maxItemcount 
FROM HistoryTable GROUP BY id, status, BatchRef 
HAVING status > 1 

Es un poco difícil descifrar sus datos de la forma en que WMD los ha formateado, pero puede realizar el tipo de truco que necesita con expresiones de tabla comunes en SQL 2005:

with LastBatches as (
    select Batch, max(Id)
    from HistoryTable
    group by Batch
)
select *
from HistoryTable h
    join LastBatches b on b.Batch = h.Batch and b.Id = h.Id

O una subconsulta (suponiendo que el grupo by en la subconsulta funcione, no lo recuerdo):

select *
from HistoryTable h
    join (
        select Batch, max(Id)
        from HistoryTable
        group by Batch
    ) b on b.Batch = h.Batch and b.Id = h.Id

Editar:Estaba asumiendo que querías el último artículo para cada lote.Si solo lo necesita para un lote, entonces las otras respuestas (hacer un top 1 y ordenar descendente) son el camino a seguir.

Como ya se sugirió, probablemente desee reordenar su consulta para ordenarla en la otra dirección para obtener la primera fila.Entonces probablemente quieras usar algo como

SELECT TOP 1 ...

si está utilizando MSSQL 2k o anterior, o la variante compatible con SQL

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber = n

para cualquier otra versión (o para otros sistemas de bases de datos que admitan la notación estándar), o

SELECT ... LIMIT 1 OFFSET 0

para algunas otras variantes sin el soporte SQL estándar.

Ver también este pregunta para una discusión adicional sobre la selección de filas.El uso de la función agregada max() puede ser más rápido o no dependiendo de si el cálculo del valor requiere un escaneo de la tabla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top