UReport2 表達(dá)式

2023-01-05 16:03 更新
UReport2教學(xué)視頻http://pan.baidu.com/s/1boWTxF5,密碼:98hj

       在報表使用過程當(dāng)中,不可避免的要使用函數(shù)及表達(dá)式實現(xiàn)一些數(shù)據(jù)的計算,在 UReport2 當(dāng)中,很多地方都支持編寫表達(dá)式,比如最典型的我們可以將單元格類型改為“表達(dá)式”,這樣就可以在下面的表達(dá)式編輯器里輸入相應(yīng)的表達(dá)式與函數(shù),除此之外,UReport2 還允許我們在條件、圖片來源、二維碼數(shù)據(jù)來源等地方使用表達(dá)式,所以學(xué)習(xí)并掌握 UReport2 中提供的表達(dá)式,是制作復(fù)雜報表的前提。

基本語法

       與一般的編程語言類似,UReport2 中的表達(dá)式也有一些基本的數(shù)據(jù)類型,比如數(shù)字、字符串等,如下表所示:

表達(dá)式類型
描述
示例
數(shù)字 可以是一個整數(shù),也可以是一個小數(shù) 1、123、0.121331,這些都是合法的數(shù)字
字符串 字符串需要用單引號或雙引號包裹 'ureport2'、"UReport2"、‘UReport2教程’,這些都是合法的字符串
布爾值 布爾值表示是或否 布爾就兩個:true 和 false

       上述的有三種基本的數(shù)據(jù)類型,可以單獨使用,也可以用“+”、"-"、"*"、"/"、"%"連接,進(jìn)行組合運算,如下表所示:

操作符
描述
示例
+ 求兩個數(shù)的和,或者是連接兩個值 21+31,這就表示求這兩個數(shù)的和,結(jié)果就是 52,“值:”+331則表示連接兩個值,其結(jié)果就是“值:331”
- 求兩個數(shù)差 21 - 31,這就表示求這兩個數(shù)的差,結(jié)果就是-10
* 求兩個數(shù)的乘積 3*6,結(jié)果就是18
/ 求兩個數(shù)除的結(jié)果 6/3,結(jié)果就是2,如果除不盡,則會保留8位小數(shù)
% 求兩個數(shù)除的余值 5%3,結(jié)果是2;6%2結(jié)果是0

       UReport2 中還提供了幾種類型的條件判斷運算符,我們首先來看一下三元表達(dá)式。

三元表達(dá)式

       基本所有的語言都支持三元表達(dá)式判斷,它的特點是簡潔明晰,可以用最少的代碼進(jìn)行條件判斷,UReport2 中的三元表達(dá)式語法結(jié)構(gòu)如下圖所示:

ternaryexpr

       可以看到,和普通的三元表達(dá)式一樣,它的第一部分是條件部分,條件部分可以有多個條件(用and或or連接),“?”后面是條件滿足后執(zhí)行并返回的表達(dá)式部分,“:”后面則是條件不滿足時執(zhí)行返回的表達(dá)式部分。

三元表達(dá)式示例
說明
A1>1000 ? "正常值" : "低值" 表達(dá)式計算時,先取到A1單元格的值,判斷值是否大于1000,如果是返回“正常值”字符串,否則返回“低值”字符串
A1>1000 and A1<20000 ? "正常值" : "修正值:"+(A1+100) 條件部分,判斷A1值是否大于1000 且小于20000,如果是返回"正常值",否則返回字符串”修正值“與A1值加100后結(jié)果連接的值,如果A1是2000,那么就返回”修正值:2100“

if判斷

       UReport2 中 if 判斷表達(dá)式語法結(jié)構(gòu)如下圖所示:

ifexpr

       從圖中可以看到,if 判斷表達(dá)式則一個if條件判斷部分加若干個可選的 elseif 條件判斷部分,最后再加一個可選的 else 部分構(gòu)成,語法結(jié)構(gòu)類似 java 或 javascript。

if判斷表達(dá)式示例
說明

if(A1>1000){

return "正常值"

}

判斷A1單元格的值是不是大于1000,如果是返回”正常值“字符串,否則什么都不做

if(A1>1000){

return "正常值"

}else{

"低值";

}

判斷 A1 單元格的值是不是大于1000,如果是返回”正常值“字符串,否則返回”低值“字符串。

這里需要注意的是,在if表達(dá)式中,return 關(guān)鍵字是可選的,同是行尾添加';'也是可選的,這主要是為了照顧一些 java 及 javascript 程序的習(xí)慣

if(A1>1000 and A1<20000){

return "正常值:"+A1

}else if(A>20000 and A1<40000){

return "超高值"

}else{

"低值"

}

在這個例子當(dāng)中,條件部分添加了多個組合條件,同時 else if 多重判斷

case判斷

       case 判斷是 UReport2 中提供的另一種條件判斷形式,與if判斷有些類似,但 case 判斷看起來更為簡潔,其語法結(jié)構(gòu)圖如下所示:

caseexpr

       可以看到,case 判斷要由 case{...}包裹,然后是若干條件加返回值。

case表達(dá)式示例
說明

case{
A1==100 
return "正常值",
A1>100 and A1<1000
return '偏高'
}

有兩個條件,分別返回不同的值
case{
A1==100 
return "正常值",
A1>100 and A1<1000
'偏高'
}
在 case 表達(dá)式中,return 關(guān)鍵字同樣是可選的

單元格引用

       在報表當(dāng)中,大多數(shù)的計算都是針對單元格或與單元格有關(guān),因為報表中單元格多數(shù)都與數(shù)據(jù)綁定,而數(shù)據(jù)往往又是多條,所以計算后的報表一個單元格會產(chǎn)生多個,這樣對于單元格的引用就變的比較復(fù)雜。在 UReport2 中,引用的目標(biāo)單元格是相對當(dāng)前單元格來進(jìn)行計算的,引用方法就是直接在表達(dá)式里書寫單元格名稱,比如引用 A1 單元格,就直接寫 A1 即可,如下面的例子:

s1

       在上圖當(dāng)中,我們在 D1 單元格中輸入表達(dá)式 A1,這就表示,在 D1 單元格里填入相對當(dāng)前 D1 單元格的 A1 單元格的值,運行后的效果如下:

s1-runtime

       可以看到,因為 D1 是 A1 的子格,A1 單元格綁定的數(shù)據(jù)就是分組結(jié)構(gòu),根據(jù)當(dāng)前 D1 單元格的位置,就產(chǎn)生的上圖所示的結(jié)果。如果在 D1 單元格中輸入 B1,那么運行后的效果又是下圖的樣子:

s1-runtime1

       同樣,如果在 D1 中輸入表達(dá)式 C1,那么運行后將會在每個 D1 單元格中填入與 D1 單元格位于同一行的 C1 單元格的值,運行結(jié)果這里就不再貼出來了。

       通過上面的例子我們可以看到,UReport2 中某個單元格的表達(dá)式引用目標(biāo)單元格,首先判斷的是目標(biāo)單元格與其所在單元格是否位于同一行或列,如果是則直接取對應(yīng)行或列上目標(biāo)單元格的值。如果當(dāng)前單元格與目標(biāo)單元格不在同一行或列,那情況又不一樣了,我們來看下一個例子。

s2

       在上面的例子中,我們在 C2 單元格的表達(dá)式中輸入 B1,表示取 B1 單元格的值,但 B1 單元格又和 C2 不在同一行或列上,同時 B1 單元格展開后會有多個值,但 B1 單元格和 C2 單元格都擁有一個共同的父格或間接父格 A1(C2 單元格的左父格是 B2,而 B2 單元格的左父格又是 A1,所以 A1 是 C2 單元格的間接左父格),所以它會取他們共同父格 A1 下所有 B1 的值,運行結(jié)果如下圖所示:

s2-runtime

多個值的輸出在 UReport2 中,如果取到值超過一個,輸出時多個值間以“,”分隔,如上圖所示
目標(biāo)格獲取原則由上面的例子可以看出,UReport2 中單元格表達(dá)式在取目標(biāo)格值時,優(yōu)先考慮的是目標(biāo)格是否與其位于同一行或列,如果是則取與其位于同一行或列的目標(biāo)單元格,如果不是,則取與當(dāng)前單元格有共同父格的所有目標(biāo)單元格,如果他們有共同的上父格或共同的左父格,那么就取共同上父格與共同左格交集部分的目標(biāo)單元格;如果他們沒有共同的父格,那么就取迭代后所有的目標(biāo)單元格。

       針對上面的例子,如果我們在上面的單元格中輸入 C1,那結(jié)果又不一樣;因為 C1 是 C2 的上父格,所以將直接取與其位于同一列的上父格單元格的值,運行效果如下圖所示:

s2-runtime1

       再看下面的報表示例:

s3

       在上面的例子中,B2 單元格表達(dá)里輸入 C1,因為 B2 和 C2 既不在同一行或列,也沒有共同的父格,所以 B2 中將取到所有的 C1 單元格的值,如下圖所示:

s3-runtime

更改父格實現(xiàn)單元格取值在之前的視頻教程中,在介紹報表計算模型時,我們多次利用更改當(dāng)前單元格的上父格或左父格使得當(dāng)前單元格與目標(biāo)格處于某個特定的父格下,其原理就來自于此。

單元格坐標(biāo)

       為了實現(xiàn)更為復(fù)雜的單元格引用,UReport2 引用了單元格坐標(biāo)的概念。單元格坐標(biāo),也是相對于當(dāng)前單元格來進(jìn)行計算的,同樣遵循上面的介紹的優(yōu)先取同行、同列或共同父格的原則,一個標(biāo)準(zhǔn)的單元格坐標(biāo)格式如下:

單元格坐標(biāo)格式單元格名稱[Li:li,Li-1:li-1,…;Ti:ti,Ti-1:ti-1…]{條件...}

       L 表示左父格,l 表示左父格展示后的序號,序號為負(fù)值,表示向上位移;T 表示上父格,t 表示上父格展開后的序號,序號為負(fù)值,表示相對于當(dāng)前單元格向上位移,正值則表示向下位移,如果只有左父格,那么直接寫 L 部分即可;如果只是上父格,那么前面需要加上“;”號,然后寫 T 部分,后面的大括號中是條件部分,多個條件之間用 and/or 連接,表示對通過坐標(biāo)取到的單元格進(jìn)行條件過濾(如果取到多個單元格的話),條件部分是可選的,相關(guān)示例如下:

單元格坐標(biāo)示例
說明

C1[A1:2,B1:1]

在找 C1 時先找單元格 A1 展開后的第2格;再找第二個 A1 下的 B1 單元格展開后的第一個單元格,然后再找這個 B1 單元格對應(yīng)的 C1 單元格

C2[A1:2,B1:2;C1:3] 在找 C2 時,先找 A1 單元格展開后的第二格,再找第二個 A1 單元格下 B2 單元格展開后的第二格,再根據(jù)第二個展開的 B2 單元格找其下名為 C2 單元格的左子格;然后再找到 C1 單元格展開后的第三格,再看其下的 C2 單元格,取 C2 單元格的交集
C2[A1:2,B2:2]{C2>1000} 表示取 A2 單元格展開后的第二格,再取其下 B2 單元格展開后第二格,再取 B2 下所有的 C2 單元格,最后再對取到的 C2 單元格進(jìn)行條件過濾,只取出 C2 單元格值大于1000的所有 C2 單元格。
C2[A1:2,B2:2]{C2>1000 and C2<10000} 表示取 A2 單元格展開后的第二格,再取其下 B2 單元格展開后第二格,再取 B2 下所有的 C2 單元格,最后再對取到的 C2 單元格進(jìn)行條件過濾,只取出 C2 單元格值大于1000且小于10000的所有 C2 單元格的值。

       我們來看一個具體的示例,報表模版如下:

s4

       在上面的報表模版中,在 B2 單元格表達(dá)式里,我們輸入了 C1[A1:2,B1:1],這就表示取 A1 單元格展開后第二格下 B1 單元格展開后第一格下對應(yīng)的 C1 單元格的值,所以運行后我們可以看到如下圖所示效果:

s4-runtime

       當(dāng)然,我們可以做一個交叉表,然后通過添加左父格和上父格約束坐標(biāo)來定位某個特定單元格,這里就不再演示了。在實際應(yīng)用當(dāng)中,單元格坐標(biāo)可以用在諸如同比,環(huán)比之類的統(tǒng)計報表當(dāng)中,這時單元格坐標(biāo)序號會用一些負(fù)值相對當(dāng)前單元格進(jìn)行位移,從而實現(xiàn)各種比值的計算。

引用所有單元格如果我們需要引用所有單元格時,那么只需要在單元格名稱后跟”[]“即可,如 A1[],表達(dá)引用所有 A1 單元格,而不管當(dāng)前引用格所在位置,同時在引用所有單元格時,還可以后跟條件,以對引用格做進(jìn)一步條件限制,如 A1[]{@>1000 and @<10000},表示要引用所有的 A1 單元格,但要求引用的 A1 單元格值要大于1000同時小于10000,這里的@符號是2.2.3及以后版本新增加的一個表達(dá)式符號,專門用于取條件循環(huán)中當(dāng)前循環(huán)對象。

       我們首先來看一個環(huán)比的例子。

環(huán)比

       報表模版如下圖所示:

s5

       在上面的報表模版中,D2 單元格中的表達(dá)式為 C2 - C2[A2:-1] ,這就表示在D2單元格中首先取到 C2 單元格的值, 因為 C2 單元格與 D2 位于同一行,所以可以直接取到,且只有一個;下一個C2采用了坐標(biāo)A2:-1,那就表示取相對于當(dāng)前單元格的 A2 單元格上一格(負(fù)值表示向上位移)的A2單元格所對應(yīng)的 C2 單元格,運行后的效果如下圖所示:

s5-runtime

       從運行結(jié)果中可以看到,第一行環(huán)比的值為0,這是因為對于第一行的 D2 單元格來說,其上一行其實是不存在的,所以 UReport2 默認(rèn)就取了第一個 C2 單元格的值,所以兩個值減下來就是0。

       下一個例子我們來看看同比。

同比

       報表模版如下圖所示:

s6

       在上面的模版當(dāng)中,D2 單元格中首先取到與其同行的 C2 單元格的值,然后利用單元格坐格,先取到當(dāng)前 D2 單元格所在行的 A2 單元格的上一條 A2 單元格記錄(-1表示坐標(biāo)上移),然后再取這個 A2 下對應(yīng)的 C2 單元格,但由于其下 C2 單元格還是有多個,所以這里加了個條件B2==$B2,這里的第一個 B2 表示當(dāng)前單元格所在行對應(yīng)的 B2 的值,$B2 表示坐標(biāo)定位后 C2 單元格對應(yīng)的 B2 單元格的值,條件就是他們倆要相等,實際上就是月份相等,這樣就達(dá)到了我們要實現(xiàn)的同比的目的,運行后的效果如下:

s6-runtime

關(guān)于$B2在UReport2當(dāng)中,在單元格名稱前加$符號,表示取相對于目標(biāo)單元格的單元格的值,多用在條件比較當(dāng)中,比如上面的C2[A2:-1]{B2==$B2},這里的$B2就是指取到的C2單元格對應(yīng)的B2單元格的值。

       在上面的例子中,第一個分組2000下,所有的同比值都為0,這是因為這個分組下不存在 A2:-1 這個坐標(biāo),沒法上移,所以系統(tǒng)默認(rèn)取了當(dāng)前記錄自身,所以計算后的值都是0。如果我們不希望顯示0,那么可以加個 if 條件判斷表達(dá)式,如果當(dāng)前位于第一個分組,就輸出空字符串,否則輸出實際計算后的值,修改后的報表模版如下圖所示:

s7

       D2 單元格對應(yīng)的表達(dá)內(nèi)容如下圖所示:

s7-expr

       運行后的效果如下圖所示:

s7-runtime

       在上面的例子中,我們使用了 if 判斷表達(dá)式,當(dāng)然你也可以換成三元表達(dá)式判斷或 case 判斷,在這個 if 判斷中,首先我們判斷的是 &A2==1 是否成立,這里的 &A2 指的是相對于當(dāng)前單元格 A2 單元格展開后的序號,在 UReport2 中,可以采用“&單元格名稱”的方式標(biāo)記某個單元格展開后的序號,需要注意的是,使用“&單元格名稱”來標(biāo)記目標(biāo)單元格展開后的序號時,當(dāng)前單元格必須是目標(biāo)單元格的子格或間接子格;比如,在上面的例子中,使用 &A2 的單元格是 D2,D2 是 A2 單元格的間接子格,這樣就可以正確取到 A2 展開后的序號值。

關(guān)于&標(biāo)記的使用

在使用“&單元格名稱”來標(biāo)記目標(biāo)單元格展開后的序號時,除上需要注意上面描述的內(nèi)容外,還需要注意,取序號將以他們共同的父格為基準(zhǔn),如果他們有共同的父格,那么將以這個父格里目標(biāo)單元格的數(shù)量來進(jìn)行序號編排,這在之前視頻教程介紹報表計算模型中,實現(xiàn)明細(xì)型主從報表,對從表數(shù)據(jù)進(jìn)行編號時就有體現(xiàn)。

逐層累加

       報表模版如下圖所示:

s8

       D2 單元格對應(yīng)的表達(dá)式如下:

s8-expr

       在上面的表達(dá)式中,我們采用了 if 判斷(同樣你可以換成三元判斷或 case 判斷),當(dāng)相對當(dāng)前單元格A2展開后的序號為1時,那么直接取當(dāng)前行的 C2 單元格值,否則就拿當(dāng)前行的 C2 單元格值加上,上一行D2 單元格值,這樣就實現(xiàn)了逐層累加的需求,運行后的效果如下:

s8-runtime

數(shù)據(jù)集表達(dá)式

       數(shù)據(jù)集是報表展示數(shù)據(jù)的來源,一般情況,定義好數(shù)據(jù)集后,在數(shù)據(jù)集對應(yīng)的字段上雙擊即可在目標(biāo)單元格上添加對應(yīng)的數(shù)據(jù)綁定信息,然后在其屬性面板設(shè)置聚合方式、迭代方向等。實際上,在 UReport2中,還允許我們在單元格表達(dá)式里通過書寫表達(dá)式來實現(xiàn)單元格與數(shù)據(jù)集字段的綁定,其語法結(jié)構(gòu)如下:

數(shù)據(jù)集名稱.聚合方式(字段名[,條件,排序方式])

       聚合方式與我們雙擊添加字段綁定后在屬性面板上看到的聚合方式基本一致,具體有以下幾種類型。

select(羅列數(shù)據(jù))

       語法格式如下:

       datasetName.select(propertyName[,filter,order])

       filter 為條件部分,條件可以有多個,多個條件之間用 and 或 or 連接,order 為是否對當(dāng)前的 propertyName 進(jìn)行排序,可選值有兩個 desc 和 asc,既正序和倒序。

示例
說明
ds1.select(username) 取數(shù)據(jù)集 ds1 中所有的 username 字段信息
ds1.select(username,age>18) 取數(shù)據(jù)集 ds1 中所有的 age 屬性大于18的 username 字段信息

ds1.select(username,age>18, desc)

取數(shù)據(jù)集 ds1中所有的 age 屬性大于18的 username 字段信息,同時對 username 字段做倒排序

ds1.select(username,age>18 and age<60, asc)

取數(shù)據(jù)集 ds1中所有的 age 屬性大于18且小于60的 username 字段信息,同時對 username 字段做正排序

group(分組羅列數(shù)據(jù))

       語法格式如下:

       datasetName.group(propertyName[,filter,order])

       filter 為條件部分,條件可以有多個,多個條件之間用 and 或 or 連接,order 為是否對當(dāng)前的 propertyName 進(jìn)行排序,可選值有兩個 desc 和 asc,既正序和倒序。

示例
說明
ds1.group(degree) 對數(shù)據(jù)集 ds1 中 degree 字段進(jìn)行分組
ds1.group(degree,age>18) 對數(shù)據(jù)集 ds1 中 age 屬性大于18的所有的 degree 字段進(jìn)行分組

ds1.group(degree,age>18, asc)

對數(shù)據(jù)集 ds1 中 age 屬性大于18的所有的 degree 字段進(jìn)行分組,同時對分組后的 degree 字段進(jìn)行正排序

sum(累加數(shù)據(jù))

       sum 是對數(shù)據(jù)集目標(biāo)字段進(jìn)行累加,所以目標(biāo)字段一定要是一個數(shù)字類型,否則就會產(chǎn)生錯誤,其語法格式如下:

       datasetName.sum(propertyName,filter)

      與之前函數(shù)不同之處在于,sum 函數(shù)沒有 order,也就是說不需要排序,原因很簡單,因為累加后的值只有一個,所以無需排序。

示例
說明
ds1.sum(salary) 對于數(shù)據(jù)集 ds1 中的 salary 字段進(jìn)行累加
ds1.sum(salary, age>30) 對數(shù)據(jù)集 ds1 中 age 屬性大于30的所有對象的 salary 字段進(jìn)行累加

count(統(tǒng)計數(shù)量)

       count 是對數(shù)據(jù)集對象數(shù)量進(jìn)行統(tǒng)計,其語法格式如下:

       datasetName.count(filter)

       統(tǒng)計數(shù)量不需要指定 propertyName 及 order。

示例
說明
ds1.count() 對 ds1 數(shù)據(jù)集中對象數(shù)量進(jìn)行統(tǒng)計

ds1.count(age>30)

統(tǒng)計數(shù)據(jù)集 ds1 中對象屬性 age 值大 30 的所有對象的數(shù)量

max(取最大值)

       max 語法格式如下:

       datasetName.max(propertyName,filter)

       取最大值沒有 order。

示例
說明
ds1.max(salary) 對于數(shù)據(jù)集 ds1 中的 salary 字段進(jìn)行比較,取最大值
ds1.max(salary, age>30) 對數(shù)據(jù)集 ds1中 age 屬性大于30的所有對象的 salary 字段進(jìn)行比較,取最大值

min(取最小值)

       min 的語法格式如下:

       datasetName.min(propertyName,filter)

       取最小值沒有 order。

示例
說明
ds1.min(salary) 對于數(shù)據(jù)集 ds1 中的 salary 字段進(jìn)行比較,取最小值
ds1.min(salary, age>30) 對數(shù)據(jù)集 ds1 中 age 屬性大于30的所有對象的 salary 字段進(jìn)行比較,取最小值

avg(取平均值)

       avg在取平均值時,如除不盡,則保留8位小數(shù),avg的語法格式如下:

       datasetName.avg(propertyName,filter)

       取平均值沒有order。

示例
說明
ds1.avg(salary) 對于數(shù)據(jù)集 ds1中的 salary 字段取平均值時,如除不盡,則保留8位小數(shù)
ds1.avg(salary, age>30) 對數(shù)據(jù)集 ds1中 age 屬性大于30的所有對象的 salary 字段取平均值時,如除不盡,則保留8位小數(shù)

取當(dāng)前單元格值

        在 UReport2 中提供了一種特殊的表達(dá)式,用來取當(dāng)前單元格值,它就是“#”,比如在給某個單元格配置鏈接時,我們可能需要將當(dāng)前單元格值作為參數(shù)傳遞給這個鏈接,那么就可以在鏈接表達(dá)式里輸入#,這就將會將當(dāng)前單元格值取出來,傳遞過去,如下圖所示:

p

       除此之外,如果在#后面加上.后接具體的屬性名,那么還可以取到與當(dāng)前單元格綁定的數(shù)據(jù)對象的具體屬性值,如:#.id,表示取與當(dāng)前單元格綁定的對象的id屬性值,當(dāng)然如果當(dāng)前單元格內(nèi)容不是一個數(shù)據(jù)集類型的,那么就會返回 null,同樣如果當(dāng)前單元格綁定的數(shù)據(jù)集屬性運行時值有多個,那么它只會取第一個對象的對應(yīng)的屬性值。



以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號