1

ユーザーのアクセス権を保持するテーブルがあります。

  Id  |  UserId  |  SectionId
  ---------------------------
  1   |  1       |  1
  2   |  1       |  2
  3   |  2       |  1
  4   |  1       |  3

このコードの使用:

CREATE FUNCTION dbo.Split (@List    NVARCHAR(2000), 
                       @SplitOn NVARCHAR(5)) 
returns @RtnValue TABLE ( 
   id    INT IDENTITY(1, 1), 
   value NVARCHAR(100)) 
AS 
BEGIN 
  WHILE ( Charindex(@SplitOn, @List) > 0 ) 
    BEGIN 
        INSERT INTO @RtnValue 
                    (value) 
        SELECT Value = Ltrim(Rtrim(Substring(@List, 1, Charindex(@SplitOn, 
                                                       @List) 
                                                       - 1))) 

        SET @List = Substring(@List, Charindex(@SplitOn, @List) + Len( 
                                     @SplitOn 
                                     ), 
                    Len 
                    (@List)) 
    END 

  INSERT INTO @RtnValue 
              (value) 
  SELECT Value = Ltrim(Rtrim(@List)) 

  RETURN 
END 

返す関数を作成しました(今のところ、特定のユーザーとセクションのすべてのレコード):

CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
AS
BEGIN
  SELECT * 
  FROM settings
  WHERE 
    UserId = @UserId AND 
    SectionId IN (SELECT convert(int,Value) FROM dbo.Split(@NewSettings,','))
END;

これは、http://sqlfiddle.com/#!3/79de7/4でテストできます。

この手順を変更して、存在するアイテムを削除し、存在しない新しいアイテムを追加したいと考えています。

ここに例があります。これを変更したい:

  Id  |  UserId  |  SectionId
  ---------------------------
  1   |  1       |  1
  2   |  1       |  2
  3   |  2       |  1
  4   |  1       |  3

の中へ:

  Id  |  UserId  |  SectionId
  ---------------------------
  1   |  1       |  1
  3   |  2       |  1
  4   |  1       |  3
  5   |  1       |  4

これは、次のように呼び出して行う必要があります。

EXEC UpdateSettings @UserId=1, @NewSettings='2,4'

UserId=1 と SectionId=2 の行が存在するため、プロシージャはそれを削除する必要があり、userId=1 と SectionId=4 の行は存在しないため、作成したいと思います。

私の最初のアイデアは、NewSettings のカーソルを作成し、その行が存在するかどうかを確認し、存在する場合は削除し、存在しない場合は追加することでした。

2 番目のアイデアは、次のように既存の行をすべて削除することでした。

CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
AS
BEGIN
  DELETE 
  FROM settings
  WHERE 
    UserId = @UserId AND 
    SectionId IN (SELECT convert(int,Value) FROM dbo.Split(@NewSettings,','))
  END;

このようにして、既存のレコードを削除できますが、新しいレコードを追加する方法はわかりません (私の例のように、テーブルに存在する行を 1 つ削除し、新しいレコードを 1 つ追加する必要があります)

カーソルを避けて何らかのJOINを行いたいのですが、これを行う方法がわかりません。

4

2 に答える 2

0

私がこれを行う場合、私はそれを単純に保ちます:

  1. ユーザーの既存のデータをすべて削除する
  2. ユーザーのすべての新しいデータを挿入します

利点は次のとおりです。

  • コーディングが簡単
  • わかりやすい
  • あなたが達成したいと望んでいる最適化はおそらく非常に小さいので、苦労する価値はありません
于 2012-11-22T17:50:55.083 に答える
0

SQL Server2005 では

CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
AS
BEGIN
  DECLARE @tmp TABLE(UserId int, SectionId int)
  DELETE s
  OUTPUT DELETED.UserId, DELETED.SectionId INTO @tmp
  FROM settings s JOIN (
                        SELECT @UserId AS UserId, CONVERT(int, Value) AS SectionId 
                        FROM dbo.Split(@NewSettings, ',')  
                        ) d ON s.UserId = d.UserId AND s.SectionId = d.SectionId 
  INSERT settings(UserId, SectionId)
  SELECT @UserId AS UserId, CONVERT(int,Value) AS SectionId
  FROM dbo.Split(@NewSettings, ',') d LEFT JOIN @tmp t ON CONVERT(int, d.Value) = t.SectionId 
                                      LEFT JOIN settings s ON @UserId = s.UserId AND CONVERT(int, d.Value) = s.SectionId
  WHERE t.UserId IS NULL AND s.UserId IS NULL
END

SQLServer 2008 では

CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
AS
BEGIN
  MERGE settings AS target
  USING (
         SELECT id, @UserID AS UserId, value AS SectionId 
         FROM dbo.Split(@NewSettings,',')
         ) AS source
  ON (target.UserId = source.UserId AND target.SectionId = source.SectionID)
  WHEN MATCHED
    THEN DELETE
  WHEN NOT MATCHED
    THEN INSERT (
                 UserId,
                 SectionId
                 )
         VALUES (
                 source.UserId,
                 source.SectionId
                 );  
END
于 2012-11-24T18:07:30.237 に答える