2011-03-04 19 views
19

Tengo una tabla que se ve algo como:de consulta MERGE y eliminar registros

AccountID, ItemID 
1, 100 
1, 200 
2, 300 

Tengo un proc que acepta un parámetro de valor de la tabla que actualiza los artículos asociados a una cuenta. Vamos a pasar algo como lo siguiente:

AccountID, ItemID 
3, 100 
3, 200 

El proc se ve algo como:

procedure dbo.MyProc(@Items as dbo.ItemListTVP READONLY) 
AS 
BEGIN 
    MERGE INTO myTable as target 
    USING @Items 
     on (Items.AccountId = target.AccountId) 
     AND (Items.ItemId = target.ItemId) 
    WHEN NOT MATCHED BY TARGET THEN 
     INSERT (AccountId, ItemId) 
     VALUES (Items.AccountId, Items.ItemId) 

    ; 

END 

Sobre la base de la aprobada en los datos que espero que añadir 2 nuevos registros a la tabla, lo que lo hace .

Lo que quiero es tener una cláusula WHEN NOT MATCHED BY SOURCE que elimine los elementos para la cuenta especificada que no coincidan.

Por ejemplo, si paso

AccountID, ItemID 
1, 100 
1, 400 

Entonces lo quiero para borrar el registro que tiene 1, 200; pero dejen TODOS los otros.

Si acabo de hacer:

WHEN NOT MATCHED BY SOURCE THEN 
    DELETE; 

entonces se eliminará todos los registros de cuentas no se hace referencia (es decir: los identificadores de la cuenta 2 y 3).

¿Cómo puedo hacer esto?

Gracias,

Respuesta

33

se me ocurren dos maneras obvias pero ambos suponer el tratamiento de la TVP de nuevo.

La primera es simplemente para cambiar la condición de DELETE

WHEN NOT MATCHED BY SOURCE 
    AND target.AccountId IN(SELECT AccountId FROM @Items) THEN 
     DELETE; 

La segunda es utilizar un CTE para restringir el objetivo

WITH cte as 
(
SELECT ItemId, AccountId 
FROM @myTable m 
WHERE EXISTS 
    (SELECT * FROM @Items i WHERE i.AccountId = m.AccountId) 
) 
     MERGE INTO cte as target 
     USING @Items Items 
      ON (Items.AccountId = target.AccountId) AND 
       (Items.ItemId = target.ItemId) 
     WHEN NOT MATCHED BY TARGET THEN 
      INSERT (AccountId, ItemId) 
      VALUES (Items.AccountId, Items.ItemId) 
     WHEN NOT MATCHED BY SOURCE THEN 
      DELETE; 
+0

El primero parece prometedor. Lo probaré y le haré saber. Por el momento, creo que preferiría tener una ejecución de consulta DELETE por separado en lugar de hacer un CTE. La consulta original es un poco más complicada que la muestra anterior. – NotMe

+1

tomó un tiempo para volver a esto. La primera opción en la condición DELETE funcionó perfectamente. Gracias, – NotMe

+1

First One funcionó para mí. +1. –

4

Espero que esto ayude.

-- myTable 
-- (
--  GroundID bigint, -- FK 
--  GroupID, bigint, -- FK 
--  AcceptingReservations bit 
-- ); 

merge into myTable as target 
using @tmpTable as source 
    on (source.GroundID = target.GroundID) 
    and (source.GroupID = target.GroupID) 
when 
    not matched by target 
    then 
     insert (GroundID, GroupID, AcceptingReservations) 
     values 
     (
      source.GroundID, 
      source.GroupID, 
      source.AcceptingReservations 
     ) 
-- If there is a row that matches, update values; 
when matched 
    then 
     update set 
      target.AcceptingReservations = source.AcceptingReservations 
-- If they do not match, delete for that GroundID only; 
when 
    not matched by source 
    and target.GroundID = @GroundID 
     then 
      delete; 
0

La respuesta anterior funciona en la situación que se describe.

Tengo una tabla de excepciones que uso para almacenar excepciones en las facturas. Solo quiero que contenga las excepciones actuales para la factura. Entonces, si arreglo algunas cosas en los datos de la factura y vuelvo a ejecutar el proceso, creará una nueva lista de excepciones. Quiero que agregue las nuevas excepciones, actualice las existentes y elimine las excepciones que ya no existen, SIEMPRE QUE PERTENECEN A LA MISMA FACTURA (o lo que sea).

El problema que tuve fue que la instrucción MERGE CUANDO NO ENCUENTRA CON EL ORIGEN LUEGO ELIMINAR eliminaría todo en la tabla TARGET; ¡no solo los elementos adicionales que ya no están en la FUENTE! No califiqué el enunciado CUANDO NO CONCUERDA POR FUENTE para que ELIMINAR solo afectara el mismo número de factura en el OBJETIVO que ya no estaba en FUENTE.

Me ha dicho un error "Solo se permiten columnas de destino en la cláusula 'CUANDO NO COINCIDE POR LA FUENTE' de una instrucción MERGE."

lo que tiene que calificar las filas de destino con una variable.

3

Crear una variable de tipo tabla en la base de datos SQL

CREATE TYPE [dbo].[YourTableType] AS TABLE(
    [AccountID] [int] NULL, 
    [ItemID] [int] NULL 
    ) 
    GO 

hacer cambios en su Procedimiento de actualización

ALTER PROCEDURE YourProcedure 
@Items YourTableType READONLY 
AS 
BEGIN 
    MERGE INTO [dbo].[YourTable] as Target 
    USING @Items as Source 
ON 
    Target.[AccountID]=Source.[AccountID] and 
    Target.[ItemID]=Source.[ItemID] 
    WHEN NOT MATCHED by TARGET THEN 
    INSERT 
     ([AccountID], 
     [ItemID]) 
    VALUES 
     (Source.[AccountID], 
     Source.[ItemID]) 

    WHEN NOT MATCHED BY SOURCE AND 
     target.[ItemID] IN(SELECT [ItemID] FROM @Items) 
THEN 
    DELETE; 

FIN

Cuestiones relacionadas