0

カスタムストアドプロシージャの作成を任されました:

exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=0

これは、テーブルの行が更新された後に実行されます。

残念ながら、それは私を本当に困惑させました(それが可能かどうかさえわからないという点まで)私は自分がしていることを単純化しようとしており、コード自体だけでボードに支援を求めることができるかどうか疑問に思っていました...

そのため、ストアド プロシージャ/コードの目的は、アイテムのリストを一般的に順番に並べ替えることです。並べ替えは、渡されたパラメーターに基づいて変更されます。ユーザーとその周りのリストの残りを並べ替えるか、シーケンスの次の番号として番号を付け直します。ほとんどの場合、UPDATEMODE=0 がデフォルトになると想定できると思います。

次のようなテーブルがあります。

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     1        |             |
|   11   |     2        |             |
|   12   |     3        |             |
|   13   |     4        |             |
---------------------------------------

ユーザーが ID 12 (ID はストアド プロシージャで渡されます) のレコードに高い優先度 (たとえば 1) を与えることにした場合、他のレコード (10 / 11 / 13) を順番に再設定する必要があります。フロントエンドでの表示方法に影響します (2 / 3 / 4)。

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     2        |      1      |
|   11   |     3        |      2      |
|   12   |     1        |      3      |
|   13   |     4        |      4      |
---------------------------------------

これの別の例は、レコード ID 12 の位置が 1 から 7 に変更されるため、このデータ セットは次のようになります。

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     2        |      1      |
|   11   |     3        |      2      |
|   12   |     1/7      |      3      |
|   13   |     4        |      4      |
---------------------------------------

位置データは次のように並べ替えられます。

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     1        |      2      |
|   11   |     2        |      3      |
|   12   |     7        |      1      |
|   13   |     3        |      4      |
---------------------------------------

前述のように、ストアド プロシージャでは、関数の動作を変更する別のパラメータ (0 または 1 の @UPDATEMODE) を渡す必要があります。これにより、ユーザーは必要な位置を指定して順序を変更できます。たとえば、行 3 の優先順位を値 1 から値 7 に更新します。

このデータ セットの行 12 の位置の値は 1 ですが、UPDATEMODE を 1 に指定して 7 に変更されています。

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     2        |      1      |
|   11   |     3        |      2      |
|   12   |     1/7      |      3      |
|   13   |     4        |      4      |
---------------------------------------

次のようにリストを並べ替えます。

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     1        |      2      |
|   11   |     2        |      3      |
|   12   |     4        |      1      |
|   13   |     3        |      4      |
---------------------------------------

この例では、ストアド プロシージャは次のように呼び出されます。

exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=1

これは私が取り組んできたSQLコードです:

-- Declare variables
DECLARE @PROJECTID INTEGER
DECLARE @CURRENTPOSITION INTEGER
DECLARE @ROLLBACKPOSITION INTEGER
DECLARE @STARTPOSITION INTEGER
DECLARE @ENDPOSITION INTEGER

-- For testing hardcode a REQUEST ID
SET @PROJECTID = 12

-- Start Position value
SET @STARTPOSITION = 1

-- End Position value
SELECT @ENDPOSITION = COUNT(ID) FROM PROJECT WHERE PROJECT_ORDER IS NOT NULL

-- Update Rollback column with current value    
UPDATE PROJECT SET OLD_POS = POSITION WHERE POSITION IS NOT NULL

DECLARE cursorProjectPositionUpdate CURSOR fast_forward
FOR 
    SELECT ID, POSITION, OLD_POS
    FROM PROJECT 
    WHERE ID = @PROJECTID
    AND POSITION IS NOT NULL
OPEN cursorProjectPositionUpdate
FETCH NEXT FROM cursorProjectPositionUpdate INTO @PROJECTID, @CURRENTPOSITION, @ROLLBACKPOSITION

WHILE @@FETCH_STATUS = 0
    BEGIN   
        WHILE (@STARTPOSITION <= @ENDPOSITION)
            IF @STARTPOSITION = 1
                UPDATE PROJECT
                SET POSITION = @STARTPOSITION
                WHERE ID = @PROJECTID
                    AND OLD_POSITION = @ROLLBACKPOSITION

            ELSE
                UPDATE PROJECT
                SET POSITION = @STARTPOSITION
                WHERE OLD_POS = @ROLLBACKPOSITION
                    AND ID <> @PROJECTID
        SET @STARTPOSITION = @STARTPOSITION + 1
        FETCH NEXT FROM cursorProjectPositionUpdate INTO @PROJECTID, @CURRENTPOSITION, @ROLLBACKPOSITION
    END
CLOSE cursorProjectPositionUpdate
DEALLOCATE cursorProjectPositionUpdate

再注文できる最大レコード数は 25 という厳しい制限があるため、カーソルを使用したので、パフォーマンスについて過度に心配する必要はありません。テーブルには 25 を超えるレコードがある可能性がありますが、AND POSITION IS NOT NULL 句を使用してレコードを除外しようとしたのはそのためです。これが受け入れられることを願っています。

私の頭の中の考えは、位置を持つレコードの合計数を数え、最初のレコードを位置 1 に設定し、その後残りを次の順序に設定することをループすることです。

私が見つけた最大の問題は、レコードの一致、つまり WHERE 句にあります。ストアド プロシージャによって渡される唯一のものは、位置 1 に設定したい ID であるため、どのレコードが次に来るかをどのように知ることができますか? ...ロジックは、リストを下っていく次に小さいID番号でなければならないということです。

これは、MS SQL Server で行われています。

一時テーブルの作成を避けようとしているので、これをすべて 1 つにできるかどうかを確認する必要があります。

これが誰かにとって何らかの意味をなすことを願っています.私は解決策を受け入れており、できるだけ多くの情報を共有します.

どうもありがとう!


追加

以下の回答に基づいて、これについてもう少し考えてきました。これも、最初からできるだけ単純にしようとしているので、PROJECT ID値を渡したストアドプロシージャがあるので、すべてをループするとどうなりますか?私のプロジェクトIDと一致しない値のうち、2から始まり、私が持っているレコードの数に基づいたエンドポイントまでそれらをリセットし、それらが順番にあると、渡されたプロジェクトの位置を1に設定します. これが更新モードのオプションに対応していないことはわかっていますが、複雑さが増しているのではないかと心配しています。

コードに関する限り、次のようなことについてどう思いますか。

-- Declare variables
DECLARE @PROJECTID INTEGER
DECLARE @STARTPOSITION INTEGER
DECLARE @ENDPOSITION INTEGER

-- Hardcoded for testing
SET @PROJECTID = 25061

-- Start Position value
SET @STARTPOSITION = 2

-- End Position value
SELECT @ENDPOSITION = COUNT(ID) FROM PROJECT WHERE PROJECT_ORDER IS NOT NULL AND ID <> @PROJECTID 

-- Update Rollback column with current value    
UPDATE PROJECT SET PROJECT_ORDER_RB = PROJECT_ORDER WHERE PROJECT_ORDER IS NOT NULL

-- Loop other records
WHILE (@STARTPOSITION <= @ENDPOSITION)
    UPDATE PROJECT SET PROJECT_ORDER = @STARTPOSITION WHERE ID <> @PROJECTID 
        AND PROJECT_ORDER IS NOT NULL AND (PROJECT_ORDER = 1 OR PROJECT_ORDER => @STARTPOSITION OR PROJECT_ORDER <= @ENDPOSITION)
SET @STARTPOSITION = @STARTPOSITION + 1

-- Finally set passed in Project to Position 1
UPDATE PROJECT SET PROJECT_ORDER = 1 WHERE ID = @PROJECTID
4

5 に答える 5

3

モードは必要ありません。デフォルトの新しい位置 = 1 を設定するだけでよいため、最初のモードを実行する場合は ID のみを入力し、2 番目のモードを実行する場合は追加の変数を指定します。

Create  Proc update_project_order (@ID Int, @NewPosition Int = 1)
As

Declare @OldPosition Int,
        @Direction Int

Select  @OldPosition = Position
From    tableName
Where   ID = @ID

Set     @Direction =    Case 
                        When    @OldPosition < @NewPosition Then 0
                        When    @OldPosition > @NewPosition Then 1
                        Else    -1
                        End

Update  t
Set     Old_Pos =   Position,
        Position =  Case
                    When    ID = @ID Then @NewPosition
                    When    @Direction = 0 And 
                            Position Between @OldPosition And @NewPosition Then Position - 1
                    When    @Direction = 1 And 
                            Position Between @NewPosition And @OldPosition Then Position + 1
                    Else    Position
                    End
From    tableName t
于 2013-01-16T21:51:42.033 に答える
2

これを 2 段階のプロセスとして実装できるようです。

  1. 目標位置以上で元の位置より小さい位置を持つすべてのアイテムの位置の値を増やします
  2. 移動する必要があるアイテムをターゲット位置に更新します

CASEこれは、2 つの update ステートメントで実行できます。少しのロジックを詰め込めば、1 つのステートメントで実行することもできます。

于 2013-01-16T21:43:56.660 に答える
1

これは、OLD_POS 列などを必要とせず、ループ、カーソル、またはその他の非セット指向のアーティファクトなしで、単一の更新ステートメントで実行できます。

CREATE Proc UPDATE_PROJECT_ORDER 
(
    @ProjectID      As INT, 
    @StartPosition  As INT,
    @EndPosition    As INT
) As

;With
  cteProjectOld As
(
    SELECT  ID, 
            POSITION,
            Case WHEN POSITION = @StartPosition 
                THEN @EndPosition 
                ELSE POSITION       END As TempPosition,
            Case WHEN POSITION = @StartPosition 
                THEN 1 
                ELSE 0              END As Moved
    FROM    PROJECT
)
, cteProjectNew As
(
    SELECT  *,
            ROW_NUMBER() OVER(PARTITION BY ID ORDER BY TempPosition, Moved) As NewPosition
    FROM    cteProjectOld
)
UPDATE  cteProjectNew
SET     POSITION = NewPosition
WHERE   ID = @ProjectID
于 2013-01-16T22:29:13.920 に答える
0

これは、リストを上に移動するか下に移動するかの 2 つの別々の可能性と考えています。残りは、単一の update ステートメント内で実行できる位置の算術演算です。

create procedure update_project_order (@ProjectId int, @UpdateMode int default 1)
begin

    declare @ProjectIdPosition int;
    select @ProjectIdPostion = Position
    from t
    where ProjectId = @ProjectId;

    if (@UpdateMode < @ProjectIdPosition)  -- Moving up the list
        update t
            set position = (case when position < @UpdateMode
                                 then position
                                 when position < @ProjectIdPosition
                                 then position + 1
                                 when ProjectId = @ProjectId
                                 then @UpdateMode
                                 when position
                            end);
    else if @UpdateMode > @ProjectIdPosition  -- Moving down the list
        update t
            set position = (case when position < @ProjectIdPostion
                                 then position
                                 when position < @UpdateMode
                                 then position - 1
                                 when ProjectId = @ProjectId
                                 then @UpdateMode
                                 else position
                            end);
end;

注:私はこれをテストしていません。それをどのように実装するかについてのアイデアです。

于 2013-01-16T21:45:15.700 に答える
0
Create Procedure UPDATE_PROJECT_ORDER (@ID int,@Posi int) as
begin

Select Cast(ID as int) as ID,POSITION,Identity(int ,1,1) as NewPos
into #tmp
from Project
where POSITION<=@Posi 
order by POSITION

Select Cast(ID as int) as ID,POSITION,Identity(int ,1,1)   as NewPos
into #tmp2
from Project
where POSITION>=@Posi 
order by POSITION



Update Project set Project.POSITION=#tmp.NewPos 
from #tmp 
where #tmp.ID=Project.ID

Update Project set Project.POSITION=#tmp2.NewPos + @Posi
from #tmp2 
where #tmp2.ID=Project.ID


Update Project set POSITION=@Posi where ID=@ID

Drop table #tmp
Drop table #tmp2
end
于 2013-01-16T22:03:58.690 に答える