2010-03-04 12 views
5

Tengo una implementación para esto que usa un CTE recursivo súper velludo que es realmente difícil de seguir/mantener. Tenía la esperanza de que uno de los cerebros de hacerlo podría llegar a algún código de enfoque Tsql más sencillo para lograr lo siguiente:Necesita algo de Wizard de tSQL: Actualización SQL basada en Total de ejecución

Documentos Tabla

DocID SortOrder PageCount StartPgNum EndPgNum 
5  1   2    {1}   {2} 
8  2   7    {3}   {9} 
22  3   3    {10}   {12} 

Para la tabla dada anteriormente, necesito una consulta para poblar StartPgNum y EndPgNum (valores de muestra incluido en el ejemplo de {} para hacer más clara las intenciones para lo que necesito

Supuestos:.
* DocID, SortOrder y PageCount se rellenan previamente
01.* StartPgNum y EndgNum deben rellenarse con el código tSQL.
* SortOrder siempre comienza en 1, y es continuo sin espacios.
* Los documentos deben tener un esquema de numeración de páginas continua según lo ordenado por SortOrder

Respuesta

4

actualizado para que sea mejor :)

DECLARE @temp TABLE (DocID INT, SortOrder INT, PageCount INT) 

INSERT INTO @temp VALUES (5, 1, 2) 
INSERT INTO @temp VALUES (8, 2, 7) 
INSERT INTO @temp VALUES (22, 3, 3) 

SELECT 
    *, 
    StartPgNum + PageCount-1 AS EndPgNum 
FROM 
(SELECT 
    DocID, 
    SortOrder, 
    PageCount, 
    ISNULL((SELECT SUM(PageCount)+1 FROM @temp WHERE SortOrder < parent.SortOrder), 1) AS StartPgNum 
FROM 
    @temp parent) _temp 
+0

Subselección es exactamente lo que habría hecho. +1 –

+0

¡Buena respuesta! Estaba tan pendiente de que fuera un total acumulado que no pensé en sumar todos los recuentos de páginas de filas anteriores. BTW Lo puse para corregir el cálculo de endPgNum. Estaba agregando una página adicional en cada fila. – JohnFx

+0

Vi la edición ... gracias :) –

1

La forma más rápida de hacerlo sería con un Quirky Update. Depende de si caes en el 'Microsoft no dice explícitamente que funciona así que lo evitaré' acampar o no ...

De lo contrario, estás en CTE peluda recursiva (como ya has descubierto) o unión triangular (que podría convertirse en una pesadilla en un gran conjunto de datos) territorio.

+0

Si ayuda, el conjunto de datos que se va a ejecutar será típicamente más bien pequeño (menos de 50K filas) y casi nunca más de 500K filas. – JohnFx

1

SQL 2008 utilizando aplicar cruz (total acumulado)

/* 
DocID SortOrder PageCount StartPgNum EndPgNum 
5  1   2    {1}   {2} 
8  2   7    {3}   {9} 
22  3   3    {10}  {12} 
*/ 

Declare @MyTable TABLE(
DocID int, 
SortOrder int, 
PageCount int 
) 

Insert into @MyTable(DocID,SortOrder,PageCount) 
values (5,1,2), (8,2,7), (22,3,3) 

select 
    T1.docID, 
    T1.Sortorder, 
    T1.Pagecount, 
    (T.RunningTotal - T1.Pagecount) + 1 StartPgNum , 
    T.RunningTotal EndPgNum 

FROM @MyTable T1 
     CROSS APPLY (Select SUM(PageCount) RunningTotal FROM @MyTable where SortOrder <= T1.SortOrder) T 
order by T1.sortorder 
+0

Tengo que amar la CRUZ SOLICITAR. – JohnFx

+0

Este sería el enfoque de rbar de combinación triangular ... –

0

me eligió para hacer frente a estos dos problemas mediante la creación de funciones, una para conseguir la primera página de la segunda para conseguir la última pag mi. Aquí están las funciones y la consulta que funcionarán.

CREATE FUNCTION dbo.GetFirstPage(@SortOrder int) 
RETURNS int 
as 
BEGIN 
DECLARE @FirstPage int 
SET @FirstPage = 1 
IF(@SortOrder > 1) 
BEGIN 
SELECT @FirstPage = SUM(PageCount) + 1 
FROM Documents 
WHERE SortOrder < @SortOrder 
END 
RETURN @FirstPage 
END 

CREATE FUNCTION dbo.GetLastPage(@FirstPage int, @PageCount int) 
RETURNS int 
AS 
BEGIN 
RETURN (@FirstPage + @PageCount -1) 
END 

Y finalmente la consulta.

SELECT * , 
     dbo.GetFirstPage(SortOrder) AS FirstPage, 
     dbo.GetLastPage(dbo.GetFirstPage(SortOrder),Pagecount) AS LastPage 
FROM Documents 
3

Hice algunas pruebas en todas las soluciones proporcionadas aquí en las otras respuestas, mi opción original de "Hairy CTE recursiva" y en aras de la exhaustividad de un enfoque basado cursor simple.Para mi gran sorpresa, la opción del cursor realizó el mejor por un claro margen en todas mis pruebas (1K filas, 10KRows, 50K filas, 500K filas)

Estos son los tiempos promedio para cada enfoque de 10K registros:
Hairy Recursive CTE: 3 minutos 55 segundos
CROSS APPLY (Ben Dempsey): 21-25 segundos
subselects (Tim Khouri): 19-21 segundos
CURSOR: 1-2 segundos

Aquí está mi solución basada cursor:

Declare @temp TABLE(
DocID INT PRIMARY KEY NOT NULL, 
SortOrder INT NOT NULL, 
PageCount INT NOT NULL, 
BegPg int, 
EndPg int 
) 

Insert into @temp (DocID,SortOrder,PageCount) 
SELECT top 50000 docid, ROW_NUMBER() OVER (ORDER BY DOCID),Pages FROM tblDocuments 

DECLARE @PC int 
SET @PC=1 
DECLARE @FetchPageCount int 
DECLARE @FetchDocID int 

DECLARE myCursor CURSOR FOR 
SELECT DocID, PageCount FROM @temp ORDER BY SortOrder 

OPEN myCursor 
FETCH NEXT FROM myCursor INTO @FetchDocID,@FetchPageCount 

WHILE @@FETCH_STATUS = 0 
BEGIN 

    UPDATE @temp SET [email protected], [email protected]+ @FetchPageCount-1 
    WHERE ([email protected]) 

    SET @PC = @PC + @FetchPageCount 

    FETCH NEXT FROM myCursor INTO @FetchDocID,@FetchPageCount 
END 
CLOSE myCursor 
DEALLOCATE myCursor 

SELECT * FROM @temp 

¿Quién hubiera adivinado? Tal vez los cursores no son siempre malvados.

Una palabra de advertencia: para no tener la tentación de reemplazar la actualización a la sintaxis "WHERE CURRENT OF myCursor", se realizó mucho más lento que utilizando la versión actual con una cláusula where, aunque aún más rápido que la mayoría de los otros enfoques .

+0

Me interesaría ver los resultados de una tabla real en lugar de la variable de tabla que está en la memoria. Asegúrese de poner un índice en SORTORDER (opcionalmente incluya PAGECOUNT en el índice). Oops NM, acabo de notar que lo obtuviste de una tabla real, pero revisa el índice. Si estoy aburrido, quizás lo intente en casa :) –

+1

Los totales acumulados son uno de los pocos casos en que los cursores pueden mejorar el rendimiento sobre los métodos basados ​​en conjuntos (note que dije puedo, no lo hará), vale la pena intentarlos cuando necesite correr total. Me alegra que hayas probado todos los enfoques, ya que es lo único que debes saber para saber qué funciona mejor con tu diseño de db y las especificaciones del servidor. – HLGEM

Cuestiones relacionadas