@Ivony
2015-02-03T23:21:29.000000Z
字数 7304
阅读 2414
DbUtility
QuickQuery 是 SQL 查询语句的简化形式,致力于简化 SELECT 语句繁琐的语法格式。
一个最简单的 QuickQuery 查询像下面这样:
users.username
这表示取出 users 表所有记录的的username字段,其等价于:
SELECT users.username FROM users
既然是要取出 users 表的 username 字段,所以 FROM users 就是完全多余的语法,QuickQuery就是致力于免去这些多余的语法。
接下来逐一介绍 QuickQuery 的具体语法
要取出某个字段,只需要简单地使用字段名称即可,格式是:tablename.fieldname
,像下面这样:
users.username
要取出多个字段,则直接写出多个字段即可:
users.username, users.email
或
users.username users.email
可以为查询字段指定别名,格式是:alias : tablename.fieldname
,像这样:
name: users.username
也可以对查询的表指定别名,格式是:alias: @tablename
或alias: @tablename
,像这样:
u: @users name: u.username
一般我们可以插入换行让格式更清晰:
u: @users
name: u.username
也可以指定默认表名,格式是:@tablename
,指定了默认表名后,字段表达式可以简化为fieldname
,像这样:
@users
name: username
值得注意的是,别名的定义需要在使用这个别名之前,像下面的查询就是错误的:
name : username
@users
name : u.usrename
u : @users
如果需要将别名放到后面,则可以使用反向别名标识符:>
,如:
users.username :> name
等价于:
name : users.username
对于表名也是一样:
@users :> u
等价于
u : @users
QuickQuery 使用 ? 开头的条件子句来表示查询条件,例如要取出 userid == 1 的 username 可以用下面这样的语法:
@users username?userid==1
这等价于:
SELECT username FROM users WHERE userid = 1
在QuickQuery中,子句的先后顺序没有关系,=和==是同样的意思,上面的查询也可以写为:
@users ?userid=1 username
在不造成歧义的情况下,可以插入任意多个空白字符:
@users
? userid = 1
username
当有多个查询条件时,可以简单地直接用多个筛选子句
@users
? userid = 1
? vip = 1
username
多个查询条件自动是与的关系,即上面的QuickQuery等价于下面的SQL:
SELECT users.username FROM users WHERE users.userid = 1 AND users.vip = 1
如果要表示或的关系,可以在一个 ? 后面写多个条件,例如:
@users
?userid > 100 | vip = 1
username
分隔符可以选用||和|中的任何一个
当然,如果你使用&或者&&作为分隔符,那么这些条件就是与的关系:
@users
?userid > 100 & vip = 1
username
这个和下面的表达式是一样的
@users
?userid > 100 ?vip = 1
username
在一个条件子句中同时出现 | 和 & 的时候,& 的优先级高于 | :
@users username ?userid > 100 & level > 5 | vip = 1
等价于:
@users username ?(userid > 100 & level > 5) | vip = 1
我们可以用括号来改变这个优先级:
@users username ?userid > 100 & (level > 5 | vip = 1)
但是更简单的办法是写成两个子句:
@users username ?userid > 100 ?level > 5 | vip = 1
灵活运用这一特性,便能避免括号的出现。
排序子句用 $ 标识,例如我们要取出所有 username 并按照 userid 排序users:
@users
username
$userid
多个排序条件可以使用多个排序子句:
@users
username
$level $userid
默认排序方式是正序,若要倒序排,则使用两个 $ 符号标识:
@users
username
$$level $userid
和条件子句一样,排序子句可以出现在任何地方:
@users
username
$userid
?level > 5
但值得注意的是,要对多个字段排序的时候,多个排序子句之间是不能插入任何别的子句的,像下面这样就是错误的
@users
username $$level ?level>5 $userid
必须把两个排序字段写在一起:
@users
username $$level $userid ?level > 5
若需要限制结果集的数量,可以使用分页函数,其用 >> 调用,例如只取出前 100 条记录
@users
username
>> 100
取出第100-200条记录:
@users
username
>> 100,200
在 QuickQuery 中要插入外部的参数有两种形式,命名参数和顺序参数,我们先看顺序参数。
顺序参数指从0开始的数字表示的参数,当创建 QuickQuery 时,可以提供一个参数列表,然后在 QuickQuery 中便会使用指定位置的参数值来作为顺序参数的值。
顺序参数的表达方式是 #+数字,像下面这样:
@users
?userid = #0
username
大多数时候,命名参数可以带来更好的可读性,命名参数的表达方式是#+参数名+#,像下面这样:
@users
?userid = #id#
username
命名参数甚至可以选择参数的某个属性,例如:
@users
?userid = #UserCondition.ID#
username
这表示取出userCondition这个参数的id属性作为参数的值
在 QuickQuery 中,用单引号或双引号括起一个字符串:
@users
userid ?username = "Ivony"
@users
userid ?username = 'Ivony'
可以用 null 关键字来表示 null 值。
@users
username ?type != null
在字段列表中,可以对字段进行简单的运算,但必须指定别名。
对于数值的字段,可以进行+、-、*、/四种运算:
level : users.level - 5
level : users.level - 1
level : users.level * 100
对于字符串字段,则可以进行串联运算:
@users
name : "@" + username
这个查询会取出所有的用户名,并在前面加上"@"字符
逻辑表达式只能用于条件子句,由前面所说的逻辑运算符以及比较运算符组成。
用于数值的比较运算符有>、<、>=、<=、=/==和!=,见下:
@users username ?level > 5
@users username ?level <= 5
用于字符串的比较运算符有=/==、!=以及~/~=和!~/!~=,最后两个是LIKE和NOT LIKE
@users username ?username ~ '%Ivony%'
@users username ?username !~= '%Ivony%'
!用于对逻辑运算结果取否,如下所示:
@users username ? !(username ~ '%Ivony%' | level > 5)
SELECT username WHERE NOT ( username LIKE '%Ivony%' AND level > 5 )
当要对整个条件子句取否时,可以直接用 !? 代替 ? ,这样整个表达式就会变得非常简洁:
@users username !?username ~ '%Ivony%' | level > 5
有时候字段名或者表名可能包含特殊字符,或者与现有的关键字,如 null 等冲突,此时应用反引号(`)将名称括起来,例如:
@users
`member.users`.username ?name = `null`
此处的member.users因为用反引号括起来了,所以被视为完整的名称,即member.users视为一个整体的表名,而null也被反引号扩住,则不会被视为代表 null 值,而是一个名为 null 的字段
若在特殊名称中包含反引号(`),则应当双写反引号,如:
@users
`user-name``1`
多表查询时,一般情况下不需要任何额外的语法,可以直接进行查询,表与表之间的连接关系,可以事先指定:
users.username, profile.firstName, profile.lastName
假设我们users表和profile表已经建立了外键关系,users.userid和profile.userid是一对一的关系,则该查询等价于:
SELECT users.username, profile.firstName, profile.lastName
FROM users INNER JOIN profile ON users.userid = profile.userid
也可以在查询中直接指定表和表之间的连接关系,例如要指定 inner join 关系,用等号
@users.userid = @profile.userid
users.username, profile.firstName, profile.lastName
如果是 left join 则用:
@users.userid > @profile.userid
users.username, profile.firstName, profile.lastName
如果是 full join 则写为:
@users.userid >< @profile.userid
users.username, profile.firstName, profile.lastName
如果没有事先指定表连接关系,也没有在查询中进一步指定,则使用 cross join。
在字段列表中为字段指定的别名,只会影响到查询结果中的字段名称,不会影响到其他查询子句中的名称,考虑如下的查询:
@users
name : username ?name != null
此处条件子句中的name,视为users表的name字段,而不受前面的别名定义影响,即这个查询等价于:
@users
usrname : name ?users.name != null
如果我们需要对某个表的字段重新指定一个简洁的名字,可以使用字段重命名语法:
其语法形式为@tablename.fieldname -> alias
:
@users.userid -> userid
profile.username, profile.firstName, profile.lastName ?userid = #id# $userid
当对字段重命名后,若别名和字段名不同,那么根据别名取得字段名的时候,输出的时候用的是别名而非字段本名,考虑下面的查询:
@users.userid -> id
id, profile.username, profile.firstName, profile.lastName ?id = #id# $id
其等价于:
@users @profile
id : users.userid, username, firstName, lastName ?users.userid = #id# $users.userid
两个字段重命名为同一个名称或者为一个字段重命名两次是错误的,所以如下的查询都是错误的:
@users @profile @users.userid -> userid @profile.userid -> userid
userid, firstName, lastName ?userid = #id#
@users @profile @users.userid -> userid @users.userid -> id
userid, firstName, lastName ?userid = #id#
使用重命名后的字段,也可以在查询时再指定别名:
@users.userid -> userid
userid: id, username, firstName, lastName ?userid = #id# $userid
我们也可以简略的声明一个字段属于某个表,即将字段重命名为字段名本身,语法形式为@tablename.fieldname
,即:
@users.userid
等价于
@users.userid -> userid
可以用分号隔开多个查询:
users.username?users.level>5;users.email
如果将表的连接关系和别名定义当做一个查询,那么这些设置会应用到后面所有的查询:
@users.userid = @profile.userid @users @profile;
username, firstName, lastName ?level>5;
username, email ?userid=1;
但是写成这样是不合法的:
@users.userid = @profile.userid @users @profile
username, firstName, lastName ?level>5;
username, email ?userid=1;
由于第一行的最后没有分号,所以这些设置只能用在第一个查询里,第二个查询会因为username和email以及userid没有指定表名而报错。
用下面的语法可以定义一个子查询:
@u { users.username ?users.level>5 }
u 是这个子查询的名字,然后可以将这个子查询当做一个表来使用:
@u { @users username, email ?level>5 }
u.username?u.email!=null
在使用子查询之前,必须先对其进行定义,所以下面的表达式是不合法的:
u.username?u.email!=null
@u { @users username, email ?level>5 }
定义好子查询后,可以在子查询和子查询之间,或者子查询和现有表之间建立连接关系:
@u { @users username userid ?level>5 }
@u.userid = @profile.userid
u.username, profile.firstName
等价的SQL为:
SELECT u.username, profile.firstName FROM
( SELECT username, userid FROM users WHERE level > 5 ) AS u
INNER JOIN profile ON u.userid = profile.userid
子查询的名称必须是唯一的,如果子查询的名称与现有表名相同,则会覆盖现有表名。
可以直接在QuickQuery中嵌入一个SQL语句作为子查询,在花括号前面加上#标识:
@u #{ SELECT username, userid FROM users WHERE level > 5 }
u.username ? u.email != null
在SQL子查询中如果出现 { 或者 }, 则必须双写,即使出现在字符串中:
@u #{ SELECT username, userid FROM users WHERE username LIKE '%}}%' }
u.username ? u.email != null
注意:在SQL子查询中是不允许使用参数的。
QuickQuery 支持在字段列表中使用常见的一些聚合函数,例如COUNT、SUM、AVG等,当进行聚合查询时,没有出现在聚合函数的字段则成为分组依据。
调用聚合函数必须在函数名前面加上^标识,的具体语法如下:
^group-function( expression )
或者
expression |> ^group-function
参考下面的例子:
@users
score : ^sum( score ), level
或
@users
score : users.score |> ^sum, users.level
等价SQL:
SELECT SUM( score ) AS score, level FROM users GROUP BY level
若一个查询条件包含聚合函数,则该查询条件自动被解释为HAVING子句:
@users
score : ^sum( score ), level ?^sum( score ) > 0
等价的 SQL 为:
SELECT SUM( score ) AS score, level FROM users GROUP BY level HAVING SUM( score ) > 0
若查询条件未包含聚合函数,则该查询条件被解释为WHERE子句:
@users
score: score |> ^sum, level ?level > 3
等价的 SQL 为:
SELECT SUM( score ) AS score, level FROM users WHERE level > 3 GROUP BY level
子查询、表,或者查询结果都可以进行集合运算,主要有并集:|,交集:&,差集:-,三种运算:
两个表直接运算并集:
@users | @users1
等价于:
SELECT * FROM users
UNION
SELECT * FROM users1
子查询或者查询结果运算并集:
@a{@users username?level=3 }
@b{@users username?level=5 }
@a | @b
等价于
SELECT username FROM users WHERE level = 3
UNION
SELECT username FROM users WHERE level = 5
@a{@users username?level=3 }
@a | {@users username?level=5 }
{@users username?vip = 1 }
&
{@users username?level>3 }
等价于
SELECT username FROM users WHERE level = 3
INTERSECT
SELECT username FROM users WHERE level = 5