Dieses Blog durchsuchen

Mittwoch, 24. Oktober 2018

Mapping mit Regeltabelle und Prioritätslevel

Mittlerweile schon mehrmals hatte ich die Aufgabe Geschäfte anhand einer sehr variablen Regeltabelle inkl. Prioritätslevel zu mappen.
Da sich diese Regeltabelle regelmäßig ändern kann und nicht jedesmal Adaptierungen im Code notwendig sind, baue ich mir das Mapping-SQL dynamisch anhand der Tabelle auf.
Im unten angeführten Beispiel wird standardmäßig ein Vergleich mit = durchgeführt, jedoch bietet es auch die Funktionalität mehrere Werte mit "incl." bzw "excl." ein-/auszuschließen.
Die Sortierung dieser Regeln wird anhand der Spalte "Priority" vorgenommen. Beim ersten Treffer wird der Wert aus "Category" dem Geschäft zugewiesen. Weiters gibt es noch ein Auffangelement, bei dem alle Bedingungen auf "NULL" gesetzt wurden. Dieses wird für den ELSE-Zweig des CASE-WHEN-Konstrukts genutzt.


    CREATE TABLE [dbo].[PrioritySetup](
 [Priority]   [int]     NULL,
 [Product]   [varchar](255) NULL,
 [AccountType]  [varchar](255) NULL,
 [AssetLiability] [varchar](255) NULL,
 [BusinessUnit]  [varchar](255) NULL,
 [Category]   [varchar](255) NOT NULL
) ON [PRIMARY]


INSERT INTO dbo.PrioritySetup VALUES
(1,'Giro','ABC','A','Unit1','1000'),
(2,'Giro','ABC','P','Unit1','1001'),
(3,'Giro','ABC','A','excl. |Unit2|Unit3|Unit4|','1003'),
(4,'Giro',NULL,'P',NULL,'1100'),
(5,'Giro',NULL,NULL,NULL,'1200'),
(6,'Saving',NULL,'A',NULL,'2000'),
(7,'Saving',NULL,'P','incl. |Unit2|Unit3|','2100'),
(8,'Saving',NULL,'P',NULL,'2200'),
(8,'Credit',NULL,'A',NULL,'3000'),
(9,'Credit',NULL,'P',NULL,'3100'),
(10,NULL,NULL,'A',NULL,'5000'),
(11,NULL,NULL,'P',NULL,'5000'),
(12,NULL,NULL,NULL,NULL,'9000')

DECLARE @Priority      int
    ,@Product      varchar(255) 
    ,@AccountType     varchar(255) 
    ,@AssetLiability     varchar(255)
    ,@BusinessUnit     varchar(255) 
    ,@Category      varchar(255) 
DECLARE @query       varchar(max)
DECLARE @helper       int 
DECLARE @EmptyPrioTable     int = 0



DECLARE C_Prio CURSOR FOR
    SELECT   [Priority]
      ,RTRIM([Product])
      ,RTRIM([AccountType])
      ,RTRIM([AssetLiability])
      ,RTRIM([BusinessUnit])
      ,[Category]
     FROM [dbo].[PrioritySetup]

 -- Open - Fetch - While - Close - Deallocate
 OPEN C_Prio
 FETCH NEXT FROM C_Prio INTO  @Priority      
        ,@Product     
        ,@AccountType     
        ,@AssetLiability  
        ,@BusinessUnit    
        ,@Category    
 
        
 SET @query = 'ALTER PROCEDURE [dbo].[PriorityMapper] AS BEGIN ' + CHAR(13)+CHAR(10) 
 IF @@FETCH_STATUS = 0
 BEGIN
  SET @query = @query + 'INSERT INTO dbo.MappedResult (PositionKey,Planungskategorie) ' + CHAR(13)+CHAR(10) 
  SET @query = @query + ' SELECT A.PositionKey ' + CHAR(13)+CHAR(10) 
  SET @query = @query + '       ,CASE ' + CHAR(13)+CHAR(10)          
 END
 ELSE
 BEGIN
  -- Falls Tabelle Planungskategorie_Prio leer ist
  SET @query = @query + 'PRINT  ''Planungskategorietabelle leer!'' ' + CHAR(13)+CHAR(10)  
  SET @EmptyPrioTable = 1
 END
                
 WHILE @@FETCH_STATUS = 0
 BEGIN
     SET @helper = 0
  SET @query = @query + ' WHEN '
     IF (@Product IS NOT NULL) 
     BEGIN
   IF @helper = 1 
    SET @query = @query + ' AND '
      IF CHARINDEX('excl.', @Product) > 0 OR CHARINDEX('incl.', @Product) > 0
   BEGIN
    IF CHARINDEX('excl.', @Product) > 0
    BEGIN
     SET @Product = REPLACE(REPLACE(@Product,'excl. ',''),' ','')
     SET @Product = SUBSTRING(@Product, 2, (LEN(@Product) - 2)) 
     SET @Product = '''' + REPLACE(@Product,'|',''',''') + ''''
     SET @query = @query + 'A.Product NOT IN ( ' + @Product + ')'
    END
    IF CHARINDEX('incl.', @Product) > 0
    BEGIN
     SET @Product = REPLACE(REPLACE(@Product,'incl. ',''),' ','')
     SET @Product = SUBSTRING(@Product, 2, (LEN(@Product) - 2)) 
     SET @Product = '''' + REPLACE(@Product,'|',''',''') + ''''
     SET @query = @query + 'A.Product IN ( ' + @Product  + ')'
    END
   END
   ELSE
   BEGIN
    SET @query = @query + 'A.Product = ''' + @Product + ''' '
   END
         SET @helper = 1
        END         
     IF (@AccountType IS NOT NULL) 
     BEGIN
   IF @helper = 1 
    SET @query = @query + ' AND '
      IF CHARINDEX('excl.', @AccountType) > 0 OR CHARINDEX('incl.', @AccountType) > 0
   BEGIN
    IF CHARINDEX('excl.', @AccountType) > 0
    BEGIN
     SET @AccountType = REPLACE(REPLACE(@AccountType,'excl. ',''),' ','')
     SET @AccountType = SUBSTRING(@AccountType, 2, (LEN(@AccountType) - 2)) 
     SET @AccountType = '''' + REPLACE(@AccountType,'|',''',''') + ''''
     SET @query = @query + 'A.AccountType NOT IN ( ' + @AccountType   + ')'
    END
    IF CHARINDEX('incl.', @AccountType) > 0
    BEGIN
     SET @AccountType = REPLACE(REPLACE(@AccountType,'incl. ',''),' ','')
     SET @AccountType = SUBSTRING(@AccountType, 2, (LEN(@AccountType) - 2)) 
     SET @AccountType = '''' + REPLACE(@AccountType,'|',''',''') + ''''
     SET @query = @query + 'A.AccountType IN ( ' + @AccountType  + ')'
    END
   END
   ELSE
   BEGIN
    SET @query = @query + 'A.AccountType = ''' + @AccountType + ''' '
   END
         SET @helper = 1
        END   
     IF (@AssetLiability IS NOT NULL) 
     BEGIN
   IF @helper = 1 
    SET @query = @query + ' AND '
      IF CHARINDEX('excl.', @AssetLiability) > 0 OR CHARINDEX('incl.', @AssetLiability) > 0
   BEGIN
    IF CHARINDEX('excl.', @AssetLiability) > 0
    BEGIN
     SET @AssetLiability = REPLACE(REPLACE(@AssetLiability,'excl. ',''),' ','')
     SET @AssetLiability = SUBSTRING(@AssetLiability, 2, (LEN(@AssetLiability) - 2)) 
     SET @AssetLiability = '''' + REPLACE(@AssetLiability,'|',''',''') + ''''
     SET @query = @query + 'A.AssetLiability NOT IN ( ' + @AssetLiability   + ')'
    END
    IF CHARINDEX('incl.', @AssetLiability) > 0
    BEGIN
     SET @AssetLiability = REPLACE(REPLACE(@AssetLiability,'incl. ',''),' ','')
     SET @AssetLiability = SUBSTRING(@AssetLiability, 2, (LEN(@AssetLiability) - 2)) 
     SET @AssetLiability = '''' + REPLACE(@AssetLiability,'|',''',''') + ''''
     SET @query = @query + 'A.AssetLiability IN ( ' + @AssetLiability  + ')'
    END
   END
   ELSE
   BEGIN
    SET @query = @query + 'A.AssetLiability = ''' +@AssetLiability + ''' '
   END
         SET @helper = 1
        END            
     IF (@BusinessUnit IS NOT NULL) 
     BEGIN
   IF @helper = 1 
    SET @query = @query + ' AND '
      IF CHARINDEX('excl.', @BusinessUnit) > 0 OR CHARINDEX('incl.', @BusinessUnit) > 0
   BEGIN
    IF CHARINDEX('excl.', @BusinessUnit) > 0
    BEGIN
     SET @BusinessUnit = REPLACE(REPLACE(@BusinessUnit,'excl. ',''),' ','')
     SET @BusinessUnit = SUBSTRING(@BusinessUnit, 2, (LEN(@BusinessUnit) - 2)) 
     SET @BusinessUnit = '''' + REPLACE(@BusinessUnit,'|',''',''') + ''''
     SET @query = @query + 'A.BusinessUnit NOT IN ( ' + @BusinessUnit  + ')'
    END
    IF CHARINDEX('incl.', @BusinessUnit) > 0
    BEGIN
     SET @BusinessUnit = REPLACE(REPLACE(@BusinessUnit,'incl. ',''),' ','')
     SET @BusinessUnit = SUBSTRING(@BusinessUnit, 2, (LEN(@BusinessUnit) - 2)) 
     SET @BusinessUnit = '''' + REPLACE(@BusinessUnit,'|',''',''') + ''''
     SET @query = @query + 'A.BusinessUnit IN ( ' + @BusinessUnit  + ')'
    END
   END
   ELSE
   BEGIN
    SET @query = @query + 'A.BusinessUnit = ''' + @BusinessUnit  + ''' '
   END
         SET @helper = 1
        END   
 
  SET @query = @query + ' THEN ''' + @Category + '''' + CHAR(13)+CHAR(10)
  
  FETCH NEXT FROM C_Prio INTO  @Priority      
         ,@Product     
         ,@AccountType     
         ,@AssetLiability  
         ,@BusinessUnit    
         ,@Category  
 END;
 CLOSE C_Prio
 DEALLOCATE C_Prio

 IF @EmptyPrioTable = 0
 BEGIN
  SET @query = REPLACE(@query,'WHEN  THEN', 'ELSE')
  SET @query = @query + '             END AS MappedCategory'+ CHAR(13)+CHAR(10) 

  SET @query = @query + '           FROM (  ' + CHAR(13)+CHAR(10)  
  SET @query = @query + '                 SELECT PositionKey, AssetLiability, Product, AccountType, BusinessUnit FROM EXP.GiroAccounts'  + CHAR(13)+CHAR(10)
  SET @query = @query + '           UNION SELECT PositionKey, AssetLiability, Product, AccountType, BusinessUnit FROM EXP.SavingAccounts'  + CHAR(13)+CHAR(10)
  SET @query = @query + '           UNION SELECT PositionKey, AssetLiability, Product, AccountType, BusinessUnit FROM EXP.LoanAccounts'  + CHAR(13)+CHAR(10)
  SET @query = @query + '           UNION SELECT PositionKey, AssetLiability, Product, AccountType, BusinessUnit FROM EXP.TreasuryAccounts ' + CHAR(13)+CHAR(10)
  SET @query = @query + '           UNION SELECT PositionKey, AssetLiability, Product, AccountType, BusinessUnit FROM EXP.OtherAccounts'  + CHAR(13)+CHAR(10)
  SET @query = @query + '                ) A' + CHAR(13)+CHAR(10) 
 END

 SET @query = @query + CHAR(13)+CHAR(10)  + ' END'
 
 -- Absetzen des dynamisch generierten UPDATE-SQLs
 PRINT @query
 EXEC (@query) 



Freitag, 19. Oktober 2018

Sätze verdoppeln bzw. vervielfältigen mit Kriterien

Habe wieder mal eine interessante Anfrage bekommen, die recht einfach umsetzbar war:
Es müssen einige Sätze einer Tabelle im Zuge eines SELECTs verdoppelt, einige jedoch verdreifacht werden. Abhängig von dem Wert einer Spalte in der Basistabelle.

    SELECT A.*
      FROM Basistabelle A
 LEFT JOIN (values (1), (2), (3)) X(valueID)
        ON A.CODE = 3
 LEFT JOIN (values (1), (2), (3)) Y(valueID)
        ON A.CODE != 3
       AND Y.valueID <= 2


Der erste LEFT JOIN ist für die SatzverDREIfachung zuständig. Nur Sätze mit dem Kriterium "A.CODE = 3" werden verdreifacht.
Alle anderen Sätze - also "A.CODE != 3" werden nur verDOPPELT - ("Y.valueID <= 2").
Natürlich könnte man beim zweiten Join auch einfach weniger Werte in die Tabelle Y schreiben. Diese Lösung dient nur zur Veranschaulichung.