2010-11-03 16 views
6

Estoy a punto de cambiar un procedimiento almacenado basado en cursor a basado en conjunto. Casi, porque solo me queda una cosa por descubrir.La instrucción UPDATE utiliza EXEC para ejecutar un procedimiento almacenado para ESTABLECER un valor de columna

Utilizan un procedimiento almacenado llamado GetSequence para consultar una tabla, actualizarla con un nuevo número de secuencia (antiguo + 1) y devolver el nuevo valor de número de secuencia. Esto no era un problema cuando usaban cursores porque asignaban el valor de salida a una variable, luego usaban la variable.

La única forma en que puedo pensar para mantener el nuevo procedimiento almacenado basado en el conjunto es ejecutar GetSequence en una instrucción INSERT o UPDATE. Sin embargo, obtengo ese error maravillosamente específico, "Sintaxis incorrecta cerca de la palabra clave 'EXEC'", cuando intento eso.

Este es el código antiguo:

DECLARE @new_UD_campaignID BIGINT -- Get the new ud_lead_id for the new lead set 
    EXEC ppGlobal.dbo.Getsequence 
    'ud_campaign_id', 
    @new_UD_campaignID OUTPUT 
    DECLARE @OrderNum VARCHAR(9); 
    IF @corpCamp LIKE '%LEP%' 
    BEGIN 
     SELECT @OrderNum = ('L' + RIGHT('00000000' + CAST(@new_UD_campaignID AS VARCHAR(8)), 8)) 
    END 
    ELSE 
    BEGIN 
     SELECT @OrderNum = ('C' + RIGHT('00000000' + CAST(@new_UD_campaignID AS VARCHAR(8)), 8)) 
    END 

Esto funciona, pero es muy lento porque está en un cursor y actualización de más de dos millones de filas.

miradas

El nuevo código que estoy tratando como este:

UPDATE @List 
    SET OrderNumBigInt = EXEC (ipCore.dbo.Getsequence 
            'ud_campaign_id', 
            @new_UD_campaignID OUTPUT) 

no puedo encontrar ninguna documentación específica que indica que no se puede ejecutar un procedimiento almacenado dentro de una instrucción SELECT o UPDATE para establecer un valor de columna.

¿Alguien ha intentado algo similar, pero con éxito?

+0

¿Qué versión de SQL Server? – JNK

+1

¿Existe alguna razón por la que no pueda crear un UDF para su proceso getsequence para devolver los valores? – JNK

+0

SQL Server 2008 R2 – JerryK

Respuesta

2

Lo que estás sugiriendo no se puede hacer en MSSQL (AFAIK). De hecho, dudo que las sugerencias para convertir GetSequence en una función probablemente tampoco funcionen, ya que la última ud_campaing_id probablemente esté almacenada en alguna tabla "global" ...

Suponiendo que el procedimiento almacenado GetSequence es llamado por diferentes procesos "simultáneamente", sugeriría que le sea

  • necesidad de adaptar según la SP para que pueda pedir un montón de códigos a la vez (extra parámetro, por ej. @number_of_ids que se establece de manera predeterminada en 1) para que el parámetro de salida devuelva la primera identificación solicitada pero internamente también reserva las siguientes n para usted que luego puede usar para actualizar su lista @
  • necesidad de crear un ciclo cerrado eso te da el número de una identificación y luego aplicarlos de una vez a tu mesa objetivo.

Aunque estoy absolutamente a favor de la solución anterior, requiere cambios en lo que parece ser un procedimiento almacenado muy básico, algo que los dba no les gustaría o no permiten. Sin embargo, haría que las cosas MUCHO más rápido. La segunda solución todavía requiere algunos bucles, y también tiene algunos requisitos de indexación importantes al aplicar los datos resultantes a la tabla final, por lo que está lejos de ser perfecto, pero podría ser un poco más rápido que pasar directamente sobre la tabla de destino y buscando y aplicando el nuevo registro de datos por registro.

A juzgar por el enfoque de la ACTUALIZACIÓN @list que está utilizando creo que ya está encaminado para la segunda sugerencia. Asumiendo que tiene un campo de identidad en @List (con una restricción UNIQUE o PK en él y sin espacios), puede intentar algo como lo siguiente:

DECLARE @RecordID, @LastRecordID int 
DECLARE @new_UD_campaignID bigint 

SELECT @RecordID = Min(RecordID), 
     @LastRecordID = Max(RecordID) 
    FROM @list 

DECLARE @newCampaingIDs TABLE (RecordID int PRIMARY KEY, new_UD_campaignID varchar(8)) 

WHILE @RecordID <= @LastRecordID 
    BEGIN 

     EXEC ppGlobal.dbo.Getsequence 'ud_campaign_id', @new_UD_campaignID OUTPUT 

     INSERT @newCampaingIDs (RecordID, new_UD_campaignID) VALUES (@RecordID, RIGHT('00000000' + CAST(@new_UD_campaignID AS VARCHAR(8)), 8)) 

     SELECT @RecordID = @RecordID + 1 
    END 

UPDATE @list 
    SET OrderNum = (CASE WHEN corpCamp LIKE '%LEP%' THEN 'L' ELSE 'C' END) + new_UD_campaignID 
    FROM @list upd 
    JOIN @newCampaingIDs new 
    ON new.RecordID = upd.RecordID 

La razón por la que creo esto será más rápido es porque las inserciones secuenciales tendrán (¿mucho?) menos gastos generales que la actualización del registro de la tabla original por registro. Por otra parte, todavía está atrapado detrás de la llamada repetida del procedimiento almacenado GetSequence que podría ser su principal consumidor de tiempo.

De todos modos, la única manera de saber con certeza es probándola =)

Buena suerte.

2

Esto está documentado - el BNF para UPDATEin BOL (extracto) lee

... 
UPDATE 
    ... 
    SET 
     { column_name = { expression | DEFAULT | NULL } 
    ... 

La definición para expression ser:

expresión

es una variable, valor literal, expresión, o una declaración de subselección (encerrada entre paréntesis) que devuelve un único valor. El valor devuelto por expresión reemplaza el valor existente en column_name o @variable.

una ejecución de SP no es ninguna de estas.

Necesita encontrar otra forma de aplicar la lógica: como sugiere JNK en un comentario, es posible que pueda convertir la lógica SP en una función para usarla en una actualización.

Como alternativa, ¿podría volverse a escribir el SP (o un nuevo SP escrito) para trabajar en un conjunto basado en un grupo de registros?

+0

¿Podría usar el proceso almacenado para llenar una tabla temporal y obtener valores de la tabla temporal para su consulta? – JNK

+0

El SP actualiza una tabla, por lo que una función no es una opción. Debido a que el SP devuelve un valor escalar, una tabla temporal sería inútil. Puede que tenga que volver con el arquitecto y ver si puedo cambiarlo para quizás aceptar un parámetro que indique cuántas secuencias necesito. La tabla SequenceNumbers se usa para evitar duplicar números de secuencia, por lo que es algo importante. – JerryK

+0

@JerryK - Creo que una re-escritura del SP es su única opción (ya sea para manejar múltiples filas, o para dividir la lógica en un TVF para calcular los nuevos valores y una actualización para almacenarlos en una tabla). –

Cuestiones relacionadas