2016-11-16 4 views
1

Ich habe eine Tabelle UserPermission, die eine Anzahl von Spalten von TINYINT Typ hat. z. B. Lesen, Schreiben, Aktualisieren, Löschen, Zugriff usw.SQL dynamische Spalten und Update mehrere Spalten

Ich bekomme drei Parameter in der gespeicherten Prozedur: @UserId, @ColNames, @ColValues wobei @ColNames und @ColValues sind Komma getrennte Werte.

Wie kann ich die Tabellenzeile (falls bereits vorhanden) mit den übergebenen Spaltennamen und den entsprechenden Werten einfügen oder aktualisieren.

Ich versuche, die dynamische Abfrage zu schreiben, die für INSERT läuft, aber ich konnte die Abfrage UPDATE dynamisch nicht mit jeder Spalte und seinem Wert zu verketten schreiben.

Jede Antwort würde geschätzt werden

Vielen Dank im Voraus.

+2

Zeigen Sie Ihren Code. – Han

+1

Beispieldaten und erwartetes Ergebnis werden hilfreicher sein. Fügen Sie auch die Abfrage, die Sie bisher versucht haben –

+0

Wahrscheinlich wollen etwas wie MERGE zu verwenden – scsimon

Antwort

0

Dies ist eine etwas schmutzige Art zu tun, was Sie benötigen. Wenn Sie die folgende gespeicherte Prozedur jedoch erstellen:

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 
) 

Anschließend können Sie dieses Verfahren verwenden, um die Daten miteinander zu verbinden:

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 

Es ist nicht sehr effizient, aber es wird Ihnen die gewünschten Ergebnisse bringen.

Sie können dann die temporäre Tabelle zum Aktualisieren, Einfügen und Löschen nach Bedarf verwenden.

+0

Hallo cycling, Danke für die Antwort. Es werden jedoch die mehreren Zeilen anstelle der einzelnen Zeilen mit jedem Wert als Spaltenname zurückgegeben. Wie kann ich die Zeilen in Spalten umwandeln – Abdullah

0

Statt eine kommagetrennte Liste mit würde ich einen separaten Parameter für jede Spalte erstellen und den Standardwert mache auf NULL und im Code-Update nichts, wenn sein null oder einfügen 0. So etwas ....

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

Das Problem mit dieser Methode ist, wenn eine Spalte einen NULL-Wert erlaubt, gibt es keine Möglichkeit zu unterscheiden, ob der NULL der beabsichtigte Wert wäre oder einfach bedeutet, einen Wert zu verlieren soll nicht geändert werden. Ich versuche eine Antwort zu finden, die ich und ein paar andere auf diesem Post geschrieben haben, wenn ich finde. – Matt

+0

@Matt Da dies eine Berechtigungs-Tabelle ist, würde ich mir vorstellen, dass ein Benutzer entweder die Berechtigung oder NICHT hat, wir wollen keine unbekannte Berechtigung in die Berechtigungs-Tabelle einfügen, schließlich ist es die Sicherheit der Anwendung Wird im Code durch Entfernen der ISNULL-Funktion in der allerletzten Einfügung behandelt, bleibt der Rest gleich. Danke –

+0

Wenn Nullen sind nicht erlaubt in Spalten dann kein Problem, die Methode funktioniert gut, wenn nicht beide ISNULL und die DEFAULT Werte für die Parameter wäre notwendig, weil thew nicht mehr optional sein würde. Ich habe diese Frage gefunden, die auf diese Art von Struktur eingeht: http://stackoverflow.com/questions/38952832/sql-updating-optional-parameters-php – Matt