2009-02-03 3 views
6

ich eine Beziehung Zuordnungstabelle wie dieses:SQL löschen Wo Not In

attributeId Bigint
productid Bigint

Beziehungen zu reinigen, die nicht mehr verwendet werden, ich will alle Recors löschen, wo productid = x und attributeId nicht in (@includedIds), wie das folgende Beispiel:

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


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

Wenn die SQL mit dem includedids param laufen mehr als 1-ID enthält - wie folgt aus: 25,26 - ich ein SqlException sagen:

Fehler beim Konvertieren des Datentyps varchar in bigint.

Und das ist natürlich aufgrund der in dieser varchar (max) param ...

Wie soll ich meine Delete-Anweisung konstruieren, damit es funktioniert?

Antwort

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 

ausführen, das Skript in SQL Server Datenbank zum Erstellen der Funktion ListToTable. Jetzt können Sie Ihre Abfrage neu schreiben, wie so:

@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)); 

Wo @includedids ist eine durch Kommata getrennte Liste, die Sie bereitstellen. Ich benutze diese Funktion immer, wenn ich mit Listen arbeite. Beachten Sie, dass diese Funktion nicht unbedingt Ihre Eingaben bereinigt. Sie sucht nur nach Zeichendaten in einer durch Kommas getrennten Liste und fügt jedes Element in einen Datensatz ein. Hoffe das hilft.

+0

Hinweis: Diese Funktion ist nicht für SQL Server 2005 optimiert, da ich die varchar-Größe auf 8000 begrenzt, um mit SQL Server 2000 kompatibel zu sein. Wenn Sie die MAX-Länge benötigen, suchen/ersetzen Sie 8000 für MAX im Skript . – karlgrz

+0

FYI Sie können Ntext als ein Parameter verwenden, die abwärtskompatibel mit SQL 2000 ist, siehe: http://www.sommarskog.se/arrays-in-sql-2000.html –

+0

@ Sambo99: Das ist ein großer Vorschlag. – karlgrz

1

Joel Spolsky beantwortet eine sehr ähnliche Frage hier: Parameterize an SQL IN clause

Sie etwas Ähnliches versuchen könnten, sicherstellen, dass Ihre attributetypeid als varchar werfen.

1

Sie können keine Liste als Parameter übergeben (AFAIK).

können Sie die SQL umschreiben eine Unterabfrage, um so etwas zu verwenden:

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

?

0

Diese durch Trennzeichen getrennte Liste kann an eine benutzerdefinierte Funktion gesendet werden, die sie als einfache Tabelle zurückgibt. Diese Tabelle kann dann von Ihrem NOT IN abgefragt werden. Wenn Sie die fn brauchen kann ich bieten .. Es ist schon über 5 Jahre, seit ich sql viel verwendet, und ich werde diesen Abschnitt meines Gehirns abstauben müssen ..

0

Erland hat die definitive guide für den Umgang mit Listen zu Tabelle in SQL 2005, SQL 2008 gibt Ihnen table based params.

Auf einer Randnotiz würde ich ein NOT-IN-Muster für große Listen vermeiden, weil es nicht skaliert, sondern mit linken Joins.

+0

@ sambo99: Erlands Artikel war eine tolle Lektüre. Danke für den Link, der den ganzen Morgen geholfen hat :-) – karlgrz