2011-08-08 38 views
0

在我(C# + SQL Server)应用程序,用户可以定义规则,对诸如数据:将规则应用于数据

ITEM_ID = 1 
OR (ITEM_NAME LIKE 'something' AND ITEM_PRICE > 123 
AND (ITEM_WEIGHT = 456 OR ITEM_HEIGHT < 789)) 

的一组项目,以验证将永远是不同的,但他们是不是一个巨大的数。然而,规则的数量很高(比方说,100000)。

如何检查哪些规则已验证(考虑到帐户性能)给定的一组数字?

+0

所以你要检查每个验证的100,000条规则......? – Chains

+2

问题有点含糊,你的“规则”只是一系列的WHERE子句吧?你究竟想要测试什么(每个where子句返回0?)。另外,你说你有1000多条规则(where子句),你的目标是运行它们并验证它们全都返回0结果吗?你希望/计划如何处理失败? – Zachary

+0

我们在讨论where子句中的约束条件吗? –

回答

1

您可以使用Microsoft自己的一些T-SQL解析引擎。

您可以在程序集Microsoft.Data.Schema.ScriptDom.dllMicrosoft.Data.Schema.ScriptDom.Sql.dll中找到它们。

TSql100Parser parser = new TSql100Parser(false); 

IList<ParseError> errors; 
Expression expr = parser.ParseBooleanExpression(
     new StringReader(condition), 
     out errors 
    ); 

if (errors != null && errors.Count > 0) 
{ 
    // Error handling 
    return; 
} 

如果您没有收到任何错误,则该字符串是一个有效的过滤器表达式。虽然可能会有一些有害的表达。

如果您愿意,您可以通过自己的访问者运行表达式来检测任何不需要的构造(如子查询)。但请注意,对于Visit(...)ExplicitVisit(...),您都必须覆盖几乎所有650个过载。部分班会在这里很好。然后

当您满意,可以建立一个完整的SELECT声明,所有的表达式:

var schemaObject = new SchemaObjectName(); 
schemaObject.Identifiers.Add(new Identifier {Value = "MyTable"}); 

var queryExpression = new QuerySpecification(); 
queryExpression.FromClauses.Add(
    new SchemaObjectTableSource {SchemaObject = schemaObject}); 

// Add the expression from before (repeat as necessary) 
Literal zeroLiteral = new Literal 
{ 
    LiteralType = LiteralType.Integer, 
    Value = "0", 
}; 
Literal oneLiteral = new Literal 
{ 
    LiteralType = LiteralType.Integer, 
    Value = "1", 
}; 
WhenClause whenClause = new WhenClause 
{ 
    WhenExpression = expr, // <-- here 
    ThenExpression = oneLiteral, 
}; 
CaseExpression caseExpression = new CaseExpression 
{ 
    ElseExpression = zeroLiteral, 
}; 
caseExpression.WhenClauses.Add(whenClause); 
queryExpression.SelectElements.Add(caseExpression); 

var selectStatement = new SelectStatement {QueryExpression = queryExpression}; 

...并把它所有回字符串:

var generator = new Sql100ScriptGenerator(); 
string query; 
generator.GenerateScript(selectStatement, out query); 

Console.WriteLine(query); 

输出:

SELECT CASE WHEN ITEM_ID = 1 
       OR (ITEM_NAME LIKE 'something' 
        AND ITEM_PRICE > 123 
        AND (ITEM_WEIGHT = 456 
          OR ITEM_HEIGHT < 789)) THEN 1 ELSE 0 END 
FROM MyTable 

如果这种表达变得太大来处理,你总是可以分裂的规则成块,运行在几时间。


虽然,被允许重新分配Microsoft.Data.Schema.ScriptDom.*.dll文件,你必须将自己的Visual Studio Team System中的许可证(这是包含在至少VS专业版/旗舰版?)

链接:http://blogs.msdn.com/b/gertd/archive/2008/08/22/redist.aspx

2

这看起来像你的“规则”或条件应该在C#中执行。

如果您真的要将100,000个OR和AND输入到SQL语句的WHERE子句中,那么您将很难扩展您的应用程序。我只能想象一下,如果任意一组100,000条件适用于数据集,并且每个排列都能很好地执行,那么这些索引就会混乱不堪。相反,我会运行一个基本的选择查询并读取每一行,然后用C#过滤它。然后,您可以通过单独应用每个规则并跟踪合格/不合格来跟踪哪些条件/规则针对每行进行传递和传递。当然,如果你查询的是一个非常大的表格,那么表现可能会成为一个问题,但是你说“要验证的项目集合不是一个庞大的数字”,所以我认为它会可以相对快速地为表格返回所有数据并在代码中执行规则,或者先应用一些基本过滤,然后再在代码中进行更具体的过滤。


出于好奇,是如何进入这些“规则”,喜欢的网友:

ITEM_ID = 1 
OR (ITEM_NAME LIKE 'something' AND ITEM_PRICE > 123 
AND (ITEM_WEIGHT = 456 OR ITEM_HEIGHT < 789)) 

请请请告诉我,他们没有进入实际的SQL查询(以文本形式)而你只是追加在一起,如:

var sql = "select * from myTable where "; 
foreach(var rule in rules) 
    sql += rule; 

也许有的那种建立起这些SQL的前瞻性陈述规则生成器的用户界面?

相关问题