2009-02-03 7 views
6

Ho una tabella di mappatura relazione come questa:SQL Cancellare la dicitura inutile In

AttributeID bigint
productid bigint

Per pulire le relazioni che non vengono utilizzati più, voglio cancellare tutti recors dove productid = x e AttributeID non in (@includedIds), come il seguente esempio:

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


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

Quando si esegue il codice SQL con il parametro includedids contenente più dell'1 id - come questo: 25,26 - ho uno SqlException dicendo:

Errore durante la conversione del tipo di dati varchar in bigint.

E questo è, naturalmente, a causa della, in quel varchar (max) param ...

Come devo costruire la mia dichiarazione di eliminazione per farlo funzionare?

risposta

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 

Run quello script in SQL Server database per creare la funzione ListToTable. Ora, è possibile riscrivere la query in questo 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)); 

Dove @includedids è un elenco delimitato da virgole che fornite. Io uso questa funzione tutto il tempo quando lavoro con le liste. Tieni presente che questa funzione non necessariamente disinfetta i tuoi input, ma cerca solo i dati dei personaggi in un elenco delimitato da virgole e inserisce ciascun elemento in un record. Spero che questo ti aiuti.

+0

Sidenote: questa funzione non è ottimizzata per SQL Server 2005, in quanto ho limitato la dimensione varchar a 8000 per essere compatibile con SQL Server 2000. Se si richiede la lunghezza MAX, solo Trova/Sostituisci 8000 per MAX nello script . – karlgrz

+0

FYI puoi usare ntext come parametro che è retrocompatibile con sql 2000, vedi: http://www.sommarskog.se/arrays-in-sql-2000.html –

+0

@ sambo99: Questo è un grande suggerimento. – karlgrz

1

Joel Spolsky ha risposto ad una domanda molto simile qui: Parameterize an SQL IN clause

Si potrebbe provare qualcosa di simile, facendo attenzione a lanciare la vostra attributetypeid come varchar.

1

Non è possibile passare un elenco come parametro (AFAIK).

Puoi riscrivere l'SQL per usare una sottoquery, qualcosa di simile:

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

?

0

Questa lista delimitata da virgole può essere inviata a una funzione definita dall'utente che la restituirà come una semplice tabella. Quella tabella può quindi essere interrogata dal tuo NON IN. Se avete bisogno di FN posso fornire .. È stato circa 5 anni da quando ho usato sql molto e dovrò rispolverare quella sezione del mio cervello ..

0

Erland ha lo definitive guide per gestire gli elenchi da elaborare in SQL 2005, SQL 2008 fornisce table based params.

In una nota a margine eviterei un pattern NOT IN per elenchi di grandi dimensioni, in quanto non si ridimensiona, ma si utilizza invece i join di sinistra.

+0

@ sambo99: l'articolo di Erland è stato un'ottima lettura. Grazie per il collegamento, che sicuramente ha aiutato la mattina :-) – karlgrz

Problemi correlati