2016-11-16 58 views
1

我有一個表UserPermission其中有多列TINYINT類型。例如讀,寫,更新,刪除,訪問等。SQL動態列和更新多列

我在存儲過程中得到三個參數:@UserId, @ColNames, @ColValues其中@ColNames@ColValues是逗號分隔值。

如何使用傳遞的列名和相應的值插入或更新錶行(如果已經存在)。

我試着編寫對INSERT正常運行的動態查詢,但我無法動態編寫UPDATE查詢,每列和它的值要連接起來。

任何反應,將不勝感激

在此先感謝。

+2

顯示您的代碼。 – Han

+1

樣本數據和預期結果將會更有幫助。另外添加你到目前爲止嘗試的查詢 –

+0

可能想要使用像'MERGE' – scsimon

回答

0

這是一種有點骯髒的方式來做你所需要的。但是,如果您創建以下存儲過程:

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 
) 

然後,您可以使用該程序攜起手來數據:

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 

這不是很有效,但它會給你帶來預期的效果。

然後,您可以使用臨時表來根據需要更新,插入和刪除。

+0

嗨cyclington,謝謝你的迴應。但是它返回多行而不是單行,每個值都作爲列名。如何將行轉換爲列 – Abdullah

0

而不必逗號分隔列表的我會創建一個單獨的參數爲每個列並使其默認值設置爲NULL,並在代碼更新什麼,如果它的空或插入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

如果列中不允許有空值,那麼這個方法沒有問題,如果不刪除ISNULL和參數​​的DEFAULT值,那麼這個方法就行得通,因爲這個w不再是可選的。我發現這個問題深入到這種類型的結構:http://stackoverflow.com/questions/38952832/sql-updating-optional-parameters-php – Matt