有的,我就在干这事儿。
看了你的语法之后,第一反应是完全看不懂,从补充说明才明白过来这个语法竟然是依赖于字段的顺序的?!
依赖于字段顺序使得这种语法的可读性和可移植性都非常的差,这大大的限制了其实用性,我们为什么要给字段取名字就是为了可读性,而你现在等于完全放弃了字段的名称。
由于位置相关,不需要的字段需要_来填位,且不说数_是个相当容易出错的事情,_ _ _这样的输入也非常麻烦好不?如果一个表有20多个字段,要取最后一个还不想死啊?
这是最大的槽点。其他的诸如$student自动映射到student表之类的约定语法中没有说明,常量出现在字段占位处表示等于,第二部分既承担条件定义又承担字段和变量的映射等等,不过比起字段顺序依赖来说却不算是什么大的问题。
我的 SQL 简化方案:
QuickQuery我发明一套新的语法的主要原因是SQL过于啰嗦而且关键字太多不利于凸显其结构化,而LINQ对强类型的要求,以及在SQL之上的抽象使得最终生成的SQL有可能超出使用者(初级程序员)的掌控。
在这个背景下,QuickQuery被设计来解决这两个问题,所以首先QuickQuery尽可能简洁,并且大量使用符号来代替关键字,获得更清晰的结构化呈现。其次QuickQuery被设计为与SQL语法一一对应,任何人能轻松地直接将QuickQuery翻译成最终的 SQL 形式。
你最后一个需求的文字描述说明你的问题可能出在思路限制上而非语言上。
用更好理解一点的语言来描述就是:
查询,所有课程成绩都达到89分,并且选择了所有课程的,学生的学号。
所以其实是两个集合的一个交集:
1、所有课程成绩都达到89分的学生
2、选择了所有课程的学生
两者之交集的学号。
第一个集合:
SELECT sno FROM SC GROUP BY sno HAVING MIN( GRADE ) >= 89
第二个集合:
SELECT sno FROM SC GROUP BY sno HAVING COUNT(*) == ( SELECT COUNT(*) FROM Course )
然后算这两个集合的交集就完了:
SELECT sno FROM SC GROUP BY sno HAVING MIN( GRADE ) >= 89 INTERSECT SELECT sno FROM SC GROUP BY sno HAVING COUNT(*) == ( SELECT COUNT(*) FROM Course )
不过写成SQL的复杂度主要来自于所谓的选择了所有课程的学生,这种需求过于罕见而导致没有合适的聚合函数。
============================================================
@vczh大大目光如炬的指出了我的QuickQuery小把戏并没有简化SQL的学习曲线,反而功能更弱了,所以在这边申辩一下,,,
QuickQuery其实是为了解决一些非常现实的问题,这是在没有LINQ的时代:
string sql = "SELECT username FROM users"; sql += "WHERE 1 = 1"; //... sql += " AND userid = " + userid; //... sql += "order by a";
经典的WHERE 1 = 1,这种语句出现毫无意义,仅仅是为了后面拼接的时候可以不想事的"AND xxx",而且这种拼接很容易被注入。
当然注入的问题我已经解决了,但是诸如WHERE 1=1,定义子查询各种语法拼接噪音却很难去除。
有了LINQ的时代,这种问题缓解了很多,因为LINQ的语法就是把一个集合不断地修饰得到最终的结果,所以要附加条件只需要把原来的IQueryable再Where一次就好了,排序分页都可以后附加。
但LINQ的时代出现了另一个问题:
products = EntityContext.Products.Include("ProductCategory").Include("ProductReviewTexts").Where(t => skus.Contains(t.SKU)).OrderByDescending(t => items.IndexOf(t.SKU)).Skip(0).Take(5).ToList();
以上摘自真实代码。
一次性连三张表,然后取出三张表所有字段,,,,还好有Take,还有没有Take取几万条记录的,连接五六张表取几百个字段的,,,,,我直接给跪了。。。
QuickQuery这不是一个最好的方案,是一个比较取巧的方案。
Why?很简单,QuickQuery语法的设计既避免了这些家伙懒得写ViewModel或者匿名对象,又可以像LINQ一样的不断修饰查询结果:
QuickQuery query = "users.username"; //... query += Db.Q("?users.userid=#0", userid); //... query += "$users.a";
当然,因为语法简单许多的缘故,QuickQuery的Parser也会比SQL的简单许多,这样一来,每次通过QuickQuery查询的时候,我可以把QuickQuery格式化后记录日志和查询时间。格式化后的QuickQuery结构要比SQL清晰得多。
最后,为什么QuickQuery只提供了SQL的功能子集,因为:
如果你提供了一个功能足够强大的语言,那么就一定会有一个白痴用它 来写出你看不懂的东西