2.1.0-SNAPSHOT 及以上版本可用
MLSQL 在设计之初,并没打算支持分支语句,比如典型的分支语句if/else,或者for之类的。原因在于我们希望MLSQL尽可能的简单。然而,作为一个编程语言,终究难以逃脱if/else。最后我不得不安慰自己说,鼓励大家尽量不要去用就可以了,但无论如何,在语言级别应该还要支持的。
下面是分支语句的一个典型语法:
set a = "wow,jack";
!if ''' split(:a,",")[0] == "jack" ''';
select 1 as a as b;
!else;
select 2 as a as b;
!fi;
select * from b as output;在MLSQL中,if/else并非关键字,都是一个命令。既然是一个命令,那么为了符合MLSQL语法规范,那么每个命令后面都需要添加';'表示这个命令的结束。
我们来看看if 语句:
!if ''' split(:a,",")[0] == "jack" ''';!if 命令后面接一个文本参数,该文本的内容是一个表达式。在表达式里,我们可以使用大部分SQL支持的函数。比如上面的例子是split函数。 我们使用":"来标识一个变量。变量来源于set语法。比如示例中表达式的:a变量对应的值为"wow,jack",他是通过set语法来设置的。
从上面的例子可以看到,MLSQL的条件判断语句具有以下特色:
&&,||.使用select语句做变量赋值下面是一个更复杂的例子:
set a="jack,2";
!if ''' select split(:a,",")[0] as :name, split(:a,",")[1] as :num;
:name == "jack" and :num == 3
''';
select 0 as a as b;
!elif ''' select split(:a,",")[1] as :num; :num==2 ''';
!if ''' 2==1 ''';
select 1.1 as a as b;
!else;
select 1.2 as a as b;
!fi;
!else;
select 2 as a as b;
!fi;
select * from b as output;我们再来看 !if 语句
!if ''' select split(:a,",")[0] as :name, split(:a,",")[1] as :num;
:name == "jack" and :num == 3
''';和上个例子有些不同,因为我们要对:a变量进行多次处理,为了使得最后的表达式更加简单,MLSQL支持通过select语法来做变量赋值。语句
select split(:a,",")[0] as :name, split(:a,",")[1] as :num;通过该语句,我们得到了:name 和:num两个变量。之后通过";"表示该语句的结束。在后续的语句中我们就可以引用对应的变量了:
:name == "jack" and :num == 3MLSQL会对:num自动进行类型转换。
在if/elif里申明的变量有效范围是整个!if/!fi区间。子if/else语句可以看到上层if/else语句的变量。 比如:
set name = "jack";
!if '''select :name as :newname ;:name == "jack" ''';
!if ''' :newname == "jack" ''';
!println '''====1''';
!else;
!println '''====2 ''';
!fi;
!else;
!println '''=====3''';
!fi;该语句输出为====1,我们在子if语句中使用了上面的 select产生的:newname变量。
同样的,我们可以在子语句里方便的使用变量:
set name = "jack";
!if '''select concat(:name,"dj") as :newname ;:name == "jack" ''';
!if ''' :newname == "jackdj" ''';
!println '''====${newname}''';
select "${newname}" as a as b;
!else;
!println '''====2 ''';
!fi;
!else;
!println '''=====3''';
!fi;
select * from b as output;我们可以在if/else的子语句里,比如select,!println等语句里通过原先的'${}'符号引用!if或者!elif里申明的变量。
条件分支语句结合强大的set语法,其实可以做很多有意思的事情,比如:
set a = "wow,jack" where type="defaultParam";
!if ''' split(:a,",")[0] == "jack" ''';
select 1 as a as b;
!else;
select 2 as a as b;
!fi;
select * from b as output;此时他的输出会是2。 但是如果你在前面加一句:
set a = "jack,";
set a = "wow,jack" where type="defaultParam";
!if ''' split(:a,",")[0] == "jack" ''';
select 1 as a as b;
!else;
select 2 as a as b;
!fi;
select * from b as output;这个时候会输出1. 也就是用户可以通过添加set变量覆盖已经存在的变量从而控制脚本的执行。
另外,MLSQL也支持使用自定义UDF函数,并且在if语句中也是可以使用的。比如:
register ScriptUDF.`` as title where
lang="scala"
and code='''def apply()={
"jack"
}'''
and udfType="udf";
!if ''' title() == "jack" ''';
select 1 as a as b;
!else;
select 2 as a as b;
!fi;
select * from b as output;这意味着你可以通过代码获取某个接口的值(或者特定的处理逻辑),来决定脚本的最后执行情况。有木有很强大。
因为在MLSQL里有session的概念。当一个表被使用过后,系统会自动记住。这样可以很方便的用户进行调试。 但是当使用if/else的时候则会有困惑发生。
我们来看下面这个例子:
!if ''' 2==1 ''';
select 1 as a as b;
!else;
!fi;
select * from b as output;当一次运行的时候,系统会报错,因为没有表b. 如果我们将2==1 修改为 1==1 时,则系统正常运行。 然后我们将1==1 再次修改为2==1 此时系统依然正常运行。 因为系统记住了上次运行的b,所以虽然当前没有执行select语句,但是依然有输出,从而造成错误。解决办法有两个:
set __table_name_cache__ = "false"; 让系统不要记住表名。第二种方式我们推荐,使用如下:
set __table_name_cache__ = "false";
!if ''' 2==1 ''';
select 1 as a as b;
!else;
!fi;
select * from b as output;