Предположение, что мы говорим о лексикографическом порядке по переставляемым значениям, существует два общих подхода, которые можно использовать:
n
th перестановка, при подсчете n
от 0 вверх. Для тех (как я;-), кто не говорит C++ как собственные компоненты, приблизьтесь 1, может быть реализован от следующего псевдокода, приняв основанную на нуле индексацию массива с индексным нулем на "левом" (заменяющий некоторой другой структурой, такой как список, "оставлен как осуществление";-):
1. scan the array from right-to-left (indices descending from N-1 to 0)
1.1. if the current element is less than its right-hand neighbor,
call the current element the pivot,
and stop scanning
1.2. if the left end is reached without finding a pivot,
reverse the array and return
(the permutation was the lexicographically last, so its time to start over)
2. scan the array from right-to-left again,
to find the rightmost element larger than the pivot
(call that one the successor)
3. swap the pivot and the successor
4. reverse the portion of the array to the right of where the pivot was found
5. return
Вот пример, запускающийся с текущей перестановки CADB:
1. scanning from the right finds A as the pivot in position 1
2. scanning again finds B as the successor in position 3
3. swapping pivot and successor gives CBDA
4. reversing everything following position 1 (i.e. positions 2..3) gives CBAD
5. CBAD is the next permutation after CADB
Для второго подхода (прямое вычисление n
th перестановка), помните, что существует N!
перестановки N
элементы. Поэтому, если Вы переставляете N
элементы, первое (N-1)!
, перестановки должны начаться с самого маленького элемента, следующее (N-1)!
, перестановки должны начаться со второго самого маленького и так далее. Это приводит к следующему рекурсивному подходу (снова в псевдокоде, нумеруя перестановки и положения от 0):
To find permutation x of array A, where A has N elements:
0. if A has one element, return it
1. set p to ( x / (N-1)! ) mod N
2. the desired permutation will be A[p] followed by
permutation ( x mod (N-1)! )
of the elements remaining in A after position p is removed
Так, например, 13-я перестановка ABCD найдена следующим образом:
perm 13 of ABCD: {p = (13 / 3!) mod 4 = (13 / 6) mod 4 = 2; ABCD[2] = C}
C followed by perm 1 of ABD {because 13 mod 3! = 13 mod 6 = 1}
perm 1 of ABD: {p = (1 / 2!) mod 3 = (1 / 2) mod 2 = 0; ABD[0] = A}
A followed by perm 1 of BD {because 1 mod 2! = 1 mod 2 = 1}
perm 1 of BD: {p = (1 / 1!) mod 2 = (1 / 1) mod 2 = 1; BD[1] = D}
D followed by perm 0 of B {because 1 mod 1! = 1 mod 1 = 0}
B (because there's only one element)
DB
ADB
CADB
Кстати, "удаление" элементов может быть представлено параллельным массивом булевских переменных, который указывает, какие элементы все еще доступны, таким образом, не необходимо создать новый массив на каждом рекурсивном вызове.
Так, для итерации через перестановки ABCD, просто количество от 0 до 23 (4!-1), и непосредственно вычисляют соответствующую перестановку.
Да, используйте TRY / CATCH, но после этого убедитесь, что вы освободили и т. Д. К сожалению, в SQL Server нет finally.
Однако я предлагаю обернуть это в другой try / catch
CREATE TRIGGER trigger1 ON [dbo].[table1] AFTER UPDATE
AS
BEGIN
--declare some vars
DECLARE @Col1 SMALLINT, @Col1 TINYINT
BEGIN TRY
--declare cursor
DECLARE Cursor1 CURSOR FOR
SELECT Col1, Col2 FROM INSERTED
--do the job
OPEN Cursor1
FETCH NEXT FROM Cursor1 INTO @Col1, @Col2
WHILE @@FETCH_STATUS = 0
BEGIN
IF ...something...
EXEC myProc1 @param1 = @Col1, @Param2 = @Col2
ELSE
IF ...something else...
EXEC myProc2 @param1 = @Col1, @Param2 = @Col2
FETCH NEXT FROM Cursor1 INTO @Col1, @Col2
END
END TRY
BEGIN CATCH
--do what you have to
END CATCH
BEGIN TRY
--clean it up
CLOSE Cursor1
DEALLOCATE Cursor1
END TRY
BEGIN CATCH
--do nothing
END CATCH
END
Другой вопрос, является ли курсор в триггере хорошей идеей ...
Что вам следует делать, так это никогда не использовать курсор в триггере. Вместо этого напишите правильный код на основе набора. Если бы кто-то импортировал данные в вашу таблицу из 100 000 новых записей, вы бы заблокировали таблицу на несколько часов и остановили бы вашу базу данных. Использование курсора в триггере - очень плохая практика.
Вы можете использовать функцию Cursor_Status ().
if CURSOR_STATUS('global','cursor_name') >= 0
begin
close cursor_name
deallocate cursor_name
end
Ссылка : : http://msdn.microsoft.com/en-us/library/ms177609.aspx