2013-08-20 9 views
2

Я хочу удалить строки в соответствии с номером строки, переданной из WinForm. Конечно, вывод вычисления ROW_NUMBER() всегда будет обновляться при удалении строки, поэтому число строк тоже изменится, поэтому я хочу сделать это одним выстрелом, а не циклом.Удаление нескольких строк на основе номеров строк

У меня есть этот код:

CREATE PROCEDURE Delete_Record (@RowNum INT) 
AS  
    ;WITH REC_ROW AS 
    (
    SELECT *, ROW_NUMBER() OVER (ORDER BY [Record Number]) AS RN 
     FROM User_Data 
) 
    DELETE 
    FROM REC_ROW 
    WHERE RN IN (@RowNum) 

И когда я типа:

exec Delete_Record @RowNum = '1,2' 

Он производит ошибку:

Error converting data type varchar to int.

Если изменить @RowNum INT к @RowNum varchar(max), это просто выдает сообщение об ошибке:

Error converting data type varchar to bigint.

Когда я жестко закодировать значения:

;WITH REC_ROW AS 
(
    SELECT *, ROW_NUMBER() OVER (ORDER BY [Record Number]) AS RN 
     FROM User_Data 
) 
DELETE 
    FROM REC_ROW 
    WHERE RN IN (1,2) 

Он успешно удалить строку 1 и 2. Вопрос заключается в том, как я могу интегрировать это в хранимой процедуре и ввода '1,2' передать к статье IN?

ответ

2

Если вы собираетесь передавать более сложные строки, чем 1,2, вы можете захотеть использовать параметр table-value (TVP).

CREATE TYPE dbo.Integers AS TABLE 
(
    RowNumber INT PRIMARY KEY 
); 

Теперь вы можете создать хранимую процедуру и передать в DataTable или другой коллекции из приложения, не потрудившись с построением разделенных запятыми строк или пытается разорвать их на части.

CREATE PROCEDURE dbo.Delete_Record 
    @RowNums dbo.Integers READONLY 
AS 
BEGIN 
    SET NOCOUNT ON; 

    ;WITH REC_ROW AS (...your CTE unchanged here...) 
    DELETE REC_ROW 
    FROM REC_ROW INNER JOIN @RowNums AS r 
    ON r.RowNumber = REC_ROW.RN; 
END 
GO 

Если вы действительно хотите использовать разделенную функцию:

CREATE FUNCTION dbo.SplitInts 
(
    @List  VARCHAR(MAX), 
    @Delimiter VARCHAR(255) 
) 
RETURNS TABLE WITH SCHEMABINDING 
AS 
    RETURN 
    ( 
    SELECT Item = y.i.value('(./text())[1]', 'int') 
    FROM (SELECT x = CONVERT(XML, '<i>' 
     + REPLACE(@List, @Delimiter, '</i><i>') 
     + '</i>').query('.')) AS a 
    CROSS APPLY x.nodes('i') AS y(i)); 
GO 

Теперь хранимая процедура:

CREATE PROCEDURE dbo.Delete_Record -- always use a schema prefix! 
    @RowNums VARCHAR(MAX) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    ;WITH REC_ROW AS 
    (
    SELECT *, ROW_NUMBER() OVER (ORDER BY [Record Number]) AS RN 
     FROM dbo.User_Data 
) 
    DELETE REC_ROW 
    FROM REC_ROW 
    INNER JOIN dbo.SplitInts(@RowNums, ',') AS r 
    ON r.Item = REC_ROW.RN; 
END 
GO 

Но я гарантировать вам TVP будет работать лучше.

+0

где я должен поставить часть CREATE TYPE dbo.Integers? Должно ли оно находиться внутри части «Создать процедуру»? Я попробовал, и он говорит о некорректном синтаксисе рядом с '('. –

+0

@ CaressCastañares, запускает его как отдельную отдельную команду. Он устанавливает «тип» параметра таблицы: 'dbo.Integers', который затем используется в вашей процедуре. –

+1

@Caress no, вы создаете TYPE * один раз *, а не внутри хранимой процедуры. Рассмотрим его эквивалентно созданию таблицы. –

0

Это выражение не делать то, что вы думаете, что делает:

WHERE RN IN (@RowNum) 

Он ищет те случаи, когда @RowNum является '1,2'. И это вызывает проблему, потому что '1,2' не может быть преобразован в целое. Вы объявили параметр integer, когда вы определяете процедуру, но затем вызываете ее со строкой.

Вы можете делать то, что вы хотите с:

WHERE ','[email protected]+',' like '%,'+RN+',%' 

Лишние запятые гарантировать, что «1» не соответствует «10».

EDIT:

Есть в основном три подхода (что я могу думать) для обработки строки через запятую целых чисел в качестве вещественных чисел (что лучше, потому что запрос будет использовать целые числа).

Один из них - использовать функцию split(), которая возвращает таблицу элементов разделительной строки. Вы можете использовать Google для различных реализаций.

Второй способ - использовать динамический SQL. Это нормально для запросов, которые не должны быть мгновенными. При компиляции запроса могут возникнуть дополнительные накладные расходы, что может быть заметно в транзакционных системах.

Третий способ использования рекурсивных CTE для синтаксического анализа строки. Я бы, вероятно, использовал этот метод для хранимой процедуры.

+0

это не сработает. строка «1» или «2» никогда не будет похожа на «%, 1,2,%». Ошибка состоит в том, что '1,2' не является' int'. сделайте параметр varchar и используйте на нем функцию split, затем присоедините свое удаление к этим разделенным строкам. –

+0

Да, это так. Я хотел бы использовать команду LIKE, но я вижу, что проблема будет создана. Есть ли способ, что он будет искать точные цифры, а не просто искать какие-либо сходства? –

+0

@KM, можете ли вы создать образец кода для этого? Даже если это функция Split, о которой вы говорите, это будет большой помощью. Благодаря! –

Смежные вопросы