SQL Удалить где не в - PullRequest
       18

SQL Удалить где не в

6 голосов
/ 04 февраля 2009

У меня есть таблица сопоставления отношений:

атрибут Бигинт
продукция bigint

Чтобы очистить отношения, которые больше не используются, я хочу удалить все записи, у которых productid = x и attributeid нет в (@includedIds), как в следующем примере:

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


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

При запуске SQL с параметром includeids, содержащим более 1 id - например: 25,26 - я получаю SqlException, говорящее:

Ошибка преобразования типа данных varchar в bigint.

И это, конечно, связано с тем, что в этом параметре varchar (max) ...

Как мне создать оператор удаления, чтобы он работал?

Ответы [ 5 ]

2 голосов
/ 04 февраля 2009
  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)-@pos)
          INSERT INTO @ListTable (seqid,entry)  VALUES (@seqid,@this)
          SET @pos= PATINDEX('%,%', @rest)
          SET @seqid=@seqid+1
      END
      set @this=@rest
      INSERT INTO @ListTable (seqid,entry) VALUES (@seqid,@this)
      RETURN 
  END

Запустите этот скрипт в базе данных SQL Server, чтобы создать функцию ListToTable. Теперь вы можете переписать ваш запрос следующим образом:

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

Где @includedids - это список с разделителями-запятыми, который вы предоставляете. Я использую эту функцию все время при работе со списками. Имейте в виду, что эта функция не обязательно очищает ваши входные данные, она просто ищет символьные данные в списке через запятую и помещает каждый элемент в запись. Надеюсь, это поможет.

1 голос
/ 04 февраля 2009

Нельзя передать список в качестве параметра (AFAIK).

Можете ли вы переписать sql, чтобы использовать подзапрос, что-то вроде этого:

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

1 голос
/ 04 февраля 2009

Джоэл Спольски ответил на очень похожий вопрос: Параметризация предложения SQL IN

Вы можете попробовать нечто подобное, убедившись, что ваш атрибутtypetype указан как varchar.

0 голосов
/ 04 февраля 2009

Эрланд имеет полное руководство для работы со списками в таблице в SQL 2005, SQL 2008 предоставляет вам основанные на таблице параметры .

В примечании к сторонам я бы не использовал шаблон NOT IN для больших списков, потому что он не масштабируется, а вместо этого рассмотрим использование левых объединений.

0 голосов
/ 04 февраля 2009

Этот список с разделителями-запятыми может быть отправлен определенной пользователем функции, которая вернет его в виде простой таблицы. Эта таблица может быть запрошена вашим NOT IN. Если вам нужен фн, который я могу предоставить ... Прошло около 5 лет с тех пор, как я много использовал sql, и мне придется стереть эту часть моего мозга ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...