2016-11-16 5 views
1

TINYINT型の列数を持つテーブルUserPermissionがあります。SQL動的列と複数の列を更新

@UserId, @ColNames, @ColValues@ColNames@ColValuesは、カンマで区切られた値です。

渡された列名と対応する値を持つテーブル行(すでに存在する場合)を挿入または更新する方法を教えてください。

INSERTで正常に動作する動的クエリを作成しようとしましたが、各列とその値を連結して動的にUPDATEクエリを書き込むことができませんでした。

ありがとうございます。

+2

コードを表示します。 – Han

+1

サンプルデータと期待される結果がより役立ちます。また、これまでに試したクエリを追加してください –

+0

おそらく 'MERGE' – scsimon

答えて

0

これは、あなたが必要とすることをやや汚い方法です。

DECLARE @TotalCols INT 
DECLARE @TotalVals INT 

SET @TotalCols = (
     SELECT COUNT(ID) AS Total 
     FROM dbo.stringSplit('department, teamlead', ',') 
     ); 
SET @TotalVals = (
     SELECT COUNT(ID) AS Total 
     FROM dbo.stringSplit('IT, Bob', ',') 
     ); 

IF @TotalCols = @TotalVals 
BEGIN 
    IF OBJECT_ID('tempdb..#temptable') IS NOT NULL 
     DROP TABLE #temptable 

    CREATE TABLE #temptable (
     ColName VARCHAR(MAX) NULL 
     ,ColValue VARCHAR(MAX) NULL 
     ) 

    INSERT INTO #temptable 
    SELECT a.DATA 
     ,b.DATA 
    FROM dbo.stringSplit('department, teamlead', ',') AS a 
    INNER JOIN dbo.stringSplit('IT, Bob', ',') AS b ON a.Id = b.Id 

    SELECT * 
    FROM #temptable; 
END 

それは非常に効率的ではないが、それはあなたの望ましい結果をもたらす:

CREATE FUNCTION [dbo].[stringSplit] 
(
    @String NVARCHAR(4000), 
    @Delimiter NCHAR(1) 
) 
RETURNS TABLE 
AS 
RETURN 
(
    WITH Split(stpos,endpos) 
    AS(
     SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos 
     UNION ALL 
     SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1) 
      FROM Split 
      WHERE endpos > 0 
    ) 
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), 
     'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos) 
    FROM Split 
) 

その後、一緒にデータを結合するためにその手順を使用することができます。ただし、次のストアドプロシージャを作成する場合。

これで、tempテーブルを使用して、必要に応じて更新、挿入、および削除を行うことができます。代わりに、私は列ごとに別々のパラメータを作成し、NULLとコード更新何でそのnullの場合は、このような0何かを挿入するために、デフォルト値になるだろう、カンマ区切りのリストを持っていることの

+0

こんにちは、cyclington、応答をありがとう。ただし、列名として各値を持つ単一の行ではなく、複数の行を戻します。行を列に変換するにはどうすればいいですか – Abdullah

0

....

CREATE PROCEDURE usp_UserPermissions 
@UserID INT 
,@Update INT = NULL --<-- Make default values NULL 
,@Delete INT = NULL 
,@Read INT = NULL 
,@Write INT = NULL 
,@Access INT = NULL 
AS 
BEGIN 
    SET NOCOUNT ON; 

Declare @t TABLE (UserID INT, [Update] INT,[Read] INT 
       ,[Write] INT,[Delete] INT,[Access] INT) 

INSERT INTO @t (Userid, [Update],[Read],[Write],[Delete],[Access]) 
VALUES (@UserID , @Update , @Read, @Write , @Delete, @Access) 


IF EXISTS (SELECT 1 FROM UserPermission WHERE UserID = @UserID) 
    BEGIN 
     UPDATE up  -- Only update if a value was provided else update to itself 
     SET up.[Read] = ISNULL(t.[Read] , up.[Read]) 
      ,up.[Write] = ISNULL(t.[Write] , up.[Write]) 
      ,up.[Update] = ISNULL(t.[Update] , up.[Update]) 
      ,up.[Delete] = ISNULL(t.[Delete] , up.[Delete]) 
      ,up.[Access] = ISNULL(t.[Access] , up.[Access]) 
     FROM UserPermission up 
     INNER JOIN @t t ON up.UserID = t.UserID 
    END 
ELSE 
    BEGIN 
     -- if already no row exists for that User add a row 
     -- If no value was passed for a column add 0 as default 
    INSERT INTO UserPermission (Userid, [Update],[Read],[Write],[Delete],[Access]) 
    SELECT Userid 
     , ISNULL([Update], 0) 
     , ISNULL([Read], 0) 
     , ISNULL([Write], 0) 
     , ISNULL([Delete], 0) 
     , ISNULL([Access], 0) 
    FROM @t 
    END 

END 
+0

この方法の問題は、列がNULL値を許可する場合、NULLが意図した値かどうかを区別する方法がないか、単に値が欠落していることが変更されないことを意味します。私は私と私が見つけたときにこれが投稿されると書いたいくつかの答えを見つけることを試みています。 – Matt

+0

@Mattこれはパーミッションテーブルなので、ユーザがパーミッションを持っているかどうかは分かりませんが、パーミッションテーブルに不明なパーミッションを入れたいのであれば、それはアプリケーションのセキュリティです。最後のインサートでISNULL関数を削除することでコード内で処理されますが、残りは同じままです。ありがとう –

+0

列にNULLが許可されていない場合は問題はありません。メソッドがうまくいけば、ISNULLとDEFAULTの両方の値を削除する必要があります。私はこのタイプの構造について深く掘り下げている質問を見つけました:http://stackoverflow.com/questions/38952832/sql-updating-optional-parameters-php – Matt