2009-02-03 15 views
6

Tengo una tabla de asignación relación así:SQL Táchese lo que no En

attributeId bigint
idproducto bigint

Para limpiar las relaciones que no se utilizan más, quiero borrar todos los recors donde ProductID = x y no en attributeId (@includedIds), como en el siguiente ejemplo:

@attributetypeid bigint, 
@productid bigint, 
@includedids varchar(MAX) 


DELETE FROM reltable 
WHERE productid = @productid AND 
attributetypeid = @attributetypeid AND 
attributeid NOT IN (@includedids); 

al ejecutar el SQL con el parámetro includedids que contiene más de 1 id - como esto: 25,26 - consigo un SqlException diciendo:

Error que convierte el tipo de datos varchar a bigint.

Y eso es, por supuesto, debido a la, en ese parámetro varchar (max) ...

¿Cómo debo construir mi declaración de borrar para hacer que funcione?

Respuesta

2
SET QUOTED_IDENTIFIER ON 
    GO 
    CREATE FUNCTION [dbo].[ListToTable] (
    /* 
    FUNCTION ListToTable 
    Usage: select entry from listtotable('abc,def,ghi') order by entry desc 
    PURPOSE: Takes a comma-delimited list as a parameter and returns the values of that list into a table variable. 
    */ 
    @mylist varchar(8000) 
) 
    RETURNS @ListTable TABLE (
    seqid int not null, 
    entry varchar(255) not null) 

    AS 

    BEGIN 
     DECLARE 
      @this varchar(255), 
      @rest varchar(8000), 
      @pos int, 
      @seqid int 

     SET @this = ' ' 
     SET @seqid = 1 
     SET @rest = @mylist 
     SET @pos = PATINDEX('%,%', @rest) 
     WHILE (@pos > 0) 
     BEGIN 
      set @this=substring(@rest,1,@pos-1) 
      set @rest=substring(@rest,@pos+1,len(@rest)[email protected]) 
      INSERT INTO @ListTable (seqid,entry) VALUES (@seqid,@this) 
      SET @pos= PATINDEX('%,%', @rest) 
      SET @[email protected]+1 
     END 
     set @[email protected] 
     INSERT INTO @ListTable (seqid,entry) VALUES (@seqid,@this) 
     RETURN 
    END 

Ejecutar esa secuencia de comandos en el servidor SQL Server base de datos para crear la función ListToTable. Ahora, se puede reescribir la consulta de este modo:

@attributetypeid bigint, 
@productid bigint, 
@includedids varchar(MAX) 


DELETE FROM reltable 
WHERE productid = @productid AND 
attributetypeid = @attributetypeid AND 
attributeid NOT IN (SELECT entry FROM ListToTable(@includedids)); 

Dónde @includedids es una lista separada por comas, que proporcione. Uso esta función todo el tiempo cuando trabajo con listas. Tenga en cuenta que esta función no necesariamente desinfecta sus entradas, solo busca datos de caracteres en una lista delimitada por comas y coloca cada elemento en un registro. Espero que esto ayude.

+0

Nota: Esta función no está optimizada para SQL Server 2005, ya que he limitado el tamaño varchar a 8000 para que sea compatible con SQL Server 2000. Si necesita la longitud MAX, simplemente busque/reemplace 8000 para MAX en la secuencia de comandos . – karlgrz

+0

FYI puede usar ntext como un parámetro que es compatible con versiones anteriores de sql 2000, consulte: http://www.sommarskog.se/arrays-in-sql-2000.html –

+0

@ sambo99: esa es una gran sugerencia. – karlgrz

1

Joel Spolsky respondido a una pregunta muy similar aquí: Parameterize an SQL IN clause

Usted podría intentar algo similar, asegurándose de emitir su attributetypeid como varchar.

1

no se puede pasar una lista como un parámetro (que yo sepa).

¿Se puede volver a escribir el código SQL para utilizar una subconsulta, algo como esto:

delete from reltable 
WHERE productid = @productid AND 
attributetypeid = @attributetypeid AND 
attributeid NOT IN (select id from ... where ...); 

?

0

Esa lista delimitada por comas se puede enviar a una función definida por el usuario que la devolverá como una tabla simple. Esa tabla puede ser consultada por tu NOT IN. Si necesita el fn puedo proporcionar .. Ha sido cerca de 5 años desde que se usa SQL mucho y voy a tener que desempolvar esa parte de mi cerebro ..

0

Erland tiene el definitive guide para tratar las listas de la tabla en SQL 2005, SQL 2008 le da table based params.

Como nota al margen, evitaría un patrón NOT IN para listas grandes, porque no tiene escala, en cambio, use las combinaciones a la izquierda.

+0

@ sambo99: el artículo de Erland fue una gran lectura. Gracias por el enlace, eso definitivamente ayudó a la mañana :-) – karlgrz

Cuestiones relacionadas