【问题标题】:Database design - Storing Condition rules? [closed]数据库设计 - 存储条件规则? [关闭]
【发布时间】:2013-01-12 22:16:35
【问题描述】:

版本 1:我有一个“FEE”表

FEE
-Id
-VariableAmount
-FixedAmount
-CurrencyCode

当执行提款,从系统中取出资金到用户的银行账户等时,每笔交易收取可变金额+固定金额的费用。

Version2:我想通过一套收费规则满足指定条件时收费,示例

Charge $0 when < $200 

Charge $3 when >= $200

Charge $x when >= $Y

我可以在我的网络应用程序中对其进行硬编码,这会起作用,但我希望以后能够更改它,在将这些条件存储在数据库中时你会如何设计它?

FEE 1.* FEE_RULE??你在数据库中存储了什么?

【问题讨论】:

  • 当规则改变时,我会改变我的代码并重新部署。这对你来说可能吗?
  • @usr 现在可以使用是的 :)

标签: sql-server database database-design architecture


【解决方案1】:

您所描述的是一个规则引擎。 SQL Server 没有内置的,但 MSDN 上有一篇文章描述了如何构建自己的。对于一个规则,它可能看起来有点过度设计,但也许您的应用程序也有其他规则。 Find out more.

【讨论】:

    【解决方案2】:

    您始终可以将此业务逻辑放在负责执行提款的存储过程中。这样,当您想要更改逻辑时,您不必重新部署 Web 应用程序。

    【讨论】:

      【解决方案3】:

      我的方法最简单的形式如下所示。

      USE tempdb
      GO
      IF OBJECT_ID('tempdb.dbo.Transactions') IS NOT NULL DROP TABLE Transactions
      
      SELECT TOP 500 TxnVal = ABS(CHECKSUM(NEWID())) % 1000
      INTO Transactions
      FROM sys.columns
      
      ;WITH Fee (Id, VariableAmountFloor, VariableAmountCeiling, VariableAmount, FixedAmount, CurrencyCode) AS
      (
          SELECT 1, 0,    200,        0.8,    0.1, 'x'    UNION ALL
          SELECT 2, 201,  300,        0.65,   0.1, 'x'    UNION ALL
          --  NB: have chosen 2147483647 as the ceiling because it is the maximum value of the INT type
          --  You will probably have some sort of float
          SELECT 3, 301,  2147483647, 0.4,    0.1, 'x'
      )
      SELECT   T.TxnVal
              ,VariableFee    = F.VariableAmount
              ,FixedFee       = F.FixedAmount
              ,TxnPlusCosts   = T.TxnVal + F.VariableAmount + F.FixedAmount
      FROM Transactions   T
      JOIN Fee            F ON T.TxnVal BETWEEN F.VariableAmountFloor AND F.VariableAmountCeiling
      

      【讨论】:

        【解决方案4】:
        SET ANSI_WARNINGS ON;
        GO
        
        --DROP TABLE dbo.FeeInterval
        CREATE TABLE dbo.FeeInterval (
            FeeIntervalID INT IDENTITY(1,1),    
                CONSTRAINT PK_FeeInterval PRIMARY KEY (FeeIntervalID),
        
            StartValue NUMERIC(18,2) NOT NULL,
                CONSTRAINT CK_FeeInterval_StartValue CHECK (StartValue > 0),
            -- If EndValue IS NOT NULL Then the interval is TxValue BETWEEN [StartValue, EndValue]
            -- Else (EndValue IS NULL) Then the interval is TxValue >= StartValue
            -- Also, you should check is this intervals are continuous (using a trigger)
            -- and only the last EndValue IS NULL
            EndValue NUMERIC(18,2) NULL, -- Allow null,
                CONSTRAINT CK_FeeInterval_StartDate_EndDate CHECK (StartValue < EndValue),
            VariableAmount NUMERIC(18,2) NOT NULL, 
            FixedAmount NUMERIC(18,2) NOT NULL
        );
        -- + CREATE INDEX ...
        GO
        
        --DROP TABLE dbo.[Transaction] 
        CREATE TABLE dbo.[Transaction] (
            TransactionID INT IDENTITY(1,1),
                CONSTRAINT PK_Transaction PRIMARY KEY (TransactionID),
            TransactionDate DATE NOT NULL
                CONSTRAINT DF_Transaction_TransactionDate DEFAULT GETDATE(),
            -- You should check (using a trigger) if there is an applicable fee for this TxnValue 
            --      If the last EndValue IS NOT NULL Then TxnValue BETWEEN MIN(StartDate) AND MAX(EndValue) 
            --      Else (the last Endvalue IS NULL Then TxnValue >= MIN(StartDate)
            TxnValue NUMERIC(18,2) NOT NULL
            -- Also, you should store the FeeIntervalID used for every transaction
            -- FeeIntervalID INT NOT NULL 
            -- and (maybe) VariableAmount/FixedAmount/TxnPlusCosts NUMERIC(18,2) NOT NULL
        )
        GO
        
        INSERT dbo.FeeInterval (StartValue, EndValue, VariableAmount, FixedAmount)
        SELECT 0.01, 200,       0.8,    0.1    UNION ALL -- 0.01 because data type is NUMERIC(,2)
        SELECT 201,  300,       0.65,   0.1    UNION ALL
        SELECT 301,  NULL,      0.4,    0.1;
        GO
        
        INSERT dbo.[Transaction] (TxnValue)
        SELECT 0.01 UNION ALL
        SELECT 50 UNION ALL
        SELECT 200 UNION ALL
        SELECT 250 UNION ALL
        SELECT 350 UNION ALL
        SELECT -0.01; -- Wrong value
        GO
        
        --DROP FUNCTION dbo.GetApplicableFee
        CREATE FUNCTION dbo.GetApplicableFee(@TxnValue NUMERIC(18,2))
        RETURNS TABLE
        AS
        RETURN
        SELECT  s.FeeIntervalID, s.VariableAmount, s.FixedAmount, @TxnValue + s.VariableAmount + s.FixedAmount AS TxnPlusCosts
        FROM (
            SELECT  i.FeeIntervalID, i.VariableAmount, i.FixedAmount,
                    i.StartValue, i.EndValue,
                    ROW_NUMBER() OVER(ORDER BY i.StartValue DESC) RowNum
            FROM    dbo.FeeInterval i
        ) s
        WHERE   @TxnValue BETWEEN s.StartValue AND s.EndValue AND s.RowNum > 1
        OR      @TxnValue >= s.StartValue AND s.RowNum = 1
        GO
        
        SELECT  *,
                CASE WHEN f.FeeIntervalID IS NOT NULL THEN 'TxnValue with applicable fee' ELSE 'Wrong TxnValue' END AS [Description]
        FROM    dbo.[Transaction] txn
        OUTER APPLY dbo.GetApplicableFee(txn.TxnValue) f
        -- or
        SELECT  *, 
                (SELECT f.TxnPlusCosts FROM dbo.GetApplicableFee(txn.TxnValue) f) AS TxnPlusCosts
        FROM    dbo.[Transaction] txn
        

        如果您有任何问题,请随时提出。

        【讨论】:

          【解决方案5】:

          我认为您可以使用 oracle 过滤器表达式来实现您通过数据库提出的建议,而无需更改应用程序... 本教程将帮助您实现此目的 http://docs.oracle.com/cd/B12037_01/server.101/b10821/expressionconcepts.htm

          【讨论】:

            猜你喜欢
            • 2010-09-22
            • 2010-10-07
            • 1970-01-01
            • 2019-03-19
            • 2011-05-22
            • 2019-02-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多