用任何编程语言编写的业务逻辑都可以用于生成报告。并且可以使用数据库中的数据生成报告。
反对将业务逻辑存储在数据库中
我非常重视表达的力量,而且我并不认为SQL空间具有很强的表达能力。为最适当的任务使用你手头最好的工具。与逻辑和高级概念的纠缠最好在最高层次上完成。因此,存储和大规模数据操作最好在服务器层面上完成,可能是在存储过程中。
但这取决于情况。如果您有多个应用程序与一个存储机制交互,并且您希望确保它保持完整性和工作流程,那么您应该将所有逻辑卸载到数据库服务器中。或者,准备管理多个应用程序中的并发开发。
来源: 存储过程中业务逻辑的支持和反对
另请参阅:
CREATE TABLE businessRule (
id INT NOT NULL ,
name VARCHAR(32) NOT NULL ,
description VARCHAR(255) NULL ,
statement VARCHAR(255) NOT NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;
CREATE TABLE leftOperand (
id INT NOT NULL ,
value VARCHAR(255) NOT NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;
CREATE TABLE ruleItem (
id INT NOT NULL ,
businessRuleId INT NOT NULL ,
operator ENUM('if','and','or','not') NOT NULL ,
loperand INT NOT NULL ,
comparator ENUM('<','=','>') NOT NULL ,
roperand VARCHAR(255) NOT NULL ,
roperand_ispercentage TINYINT(1) NOT NULL ,
PRIMARY KEY (id) ,
INDEX businessRule_FK (businessRuleId ASC) ,
INDEX leftOperand_FK (loperand ASC) ,
CONSTRAINT businessRule_FK
FOREIGN KEY (businessRuleId )
REFERENCES mydb.businessRule (id )
ON DELETE CASCADE
ON UPDATE RESTRICT,
CONSTRAINT leftOperand_FK
FOREIGN KEY (loperand )
REFERENCES mydb.leftOperand (id )
ON DELETE RESTRICT
ON UPDATE RESTRICT)
ENGINE = InnoDB;
批评“软编码”商业逻辑的一个观点:http://thedailywtf.com/Articles/Soft_Coding.aspx
我们发现自己在进行软编码的原因是因为我们害怕改变。不是普通的对改变的恐惧,而是害怕我们编写的代码将必须由于业务规则的更改而进行更改。这是一个相当愚蠢的恐惧。软件的整个意义(也就是“软件”的意思)就是它可以改变,而且它确实会改变。唯一保护你的软件免受业务规则更改的影响的方法是构建一个完全通用的程序,该程序没有任何业务规则,但可以实现任何规则。哦,他们已经建立了这个工具。它被称为C++、Java、C#、Basic和COBOL。”
a + b * -c
存储到数据库中,它可以被翻译成以下插入操作:-- c
INSERT INTO statement (statement_id) VALUES (1);
INSERT INTO operand (statement_id, type) VALUES (1, 'double');
-- - (minus)
INSERT INTO statement (statement_id) VALUES (2);
INSERT INTO operator (statement_id, type) VALUES (2, 'minus');
-- -c
INSERT INTO binary (operator_statement_id, operand_statement_id) VALUES (2, 1);
-- b
INSERT INTO statement (statement_id) VALUES (3);
INSERT INTO operand (statement_id, type) VALUES (3, 'double');
-- * (multiply)
INSERT INTO statement (statement_id) VALUES (4);
INSERT INTO operator (statement_id, type) VALUES (4, 'multiply');
-- b * -c
INSERT INTO unary (operator_statement_id, operand_statement_id1, operand_statement_id2) VALUES (4, 3, 2);
-- a
INSERT INTO statement (statement_id) VALUES (5);
INSERT INTO operand (statement_id, type) VALUES (5, 'double');
-- + (plus)
INSERT INTO statement (statement_id) VALUES (6);
INSERT INTO operator (statement_id, type) VALUES (6, 'sum');
-- a + b * -c
INSERT INTO unary (operator_statement_id, operand_statement_id1, operand_statement_id2) VALUES (6, 5, 4);
SELECT
查询。你需要做的是提取与你的语句相关的所有记录(使用 statement_id),并在应用程序层面(使用任何编程语言)重构语句对象,然后对语句进行评估。 - MehranSELECT * FROM <table name> WHERE statement_id = ?
。 - Mehran如果您不需要根据规则的组件执行搜索,则可以将规则存储在数据库中的两个字段中。一个字段用于执行语句的条件,另一个字段用于执行语句本身。
id, name, description, condition, statement
{ var: varName, comp: comparison, value: numberOrString }
// Conjunction
{ op: "and", terms: [ term, ..., term ] }
// Disjunction
{ op: "or", terms: [ term, ..., term ] }
// Negation
{ op: "not", term: term }
{ op: "and", terms: [
{op "or", terms: [
{ field: "numVisitors", comp: ">", value: 1000 },
{ field: "numUniqueVisitors", comp: ">=" 100 }
]},
{ op: "not", term: {
{ field: "numVisitors", comp: "<", value: 500 }
}}
]}
以上示例在访问者数量大于1000或独特访问者数量大于等于100,且访问者数量不少于500时等同于true。
当规则评估为true时,您可以执行所谓的“语句”。
ID | RuleSetName | Table | Column | Comparison | Value | Percentage | Notes | CreatedDate | Created By
1 | 'VisitorAnalytics' | Visitors | SUM(Views) | > | null | 10 | n/a | 1/1/2012 | JohnDoe
一旦这些记录被创建,您将通过将表格注入到from子句中,将列注入到where子句中来使用它们以用于动态sql。
我知道这可能听起来很困惑,但是您所要求的是一个相当复杂的解决方案。 但最终,您只需要在一个地方存储规则,以便可以循环通过并动态生成和执行SQL来生成报告。 希望这能为您指明正确的方向。
(rule :name "RuleName"
:description "Some description"
:body (if (and (< (change-in total-visitor) (percent 10))
(> (change-in unique-visitors) (percent 2)))
(do-something)))
insert into rules (id,expression) values (42,"(rule :name \"RuleName\"
:description \"Some description\"
:body (if (and (< (change-in total-visitor) (percent 10))
(> (change-in unique-visitors) (percent 2)))
(do-something)))");
;; with the right DSL written:
(eval (read-from-string (sql-select (expression) :where (= id 42))))
使用存储过程的唯一可能好处是可以从使用不同技术(如Python和Java)的应用程序访问数据库。