EdgeDBSet
是整個EdgeDB的核心,今天我們特別做個整理,加強一下大家對它的認識。
union幫助大家找出兩個EdgeDBSet
的所有元素。例如:
select {1, 2, 3, 3} union {3, 3, 4, 5};
{1, 2, 3, 3, 3, 3, 4, 5}
except幫助大家找出在第一個EdgeDBSet
卻不在第二個EdgeDBSet
的元素。例如:
select {1, 2, 3, 3} except {3, 3, 4, 5};
{1, 2}
intersect幫助大家找出在第一個EdgeDBSet
也在第二個EdgeDBSet
的元素。例如:
select {1, 2, 3, 3} intersect {3, 3, 4, 5};
{3, 3}
distinct幫大家找出EdgeDBSet
中所有獨特的元素,也就是說該EdgeDBSet
中不會有相同的元素,就像是Python中的set
一樣。
select distinct {1, 2, 3, 3};
{1, 2, 3}
??
operator??可以幫助我們選擇第一個出現的非空EdgeDBSet
。例如:
select <int64>{} ?? {1};
{1}
由於空EdgeDBSet
也是需要型別的,所以上面的空EdgeDBSet
需要加上<int64>
。由於??
左邊是一個空EdgeDBSet
,所以??
會返回{1}
。
假設??
兩個都為空EdgeDBSet
,則會返回後面那個。例如:
with a:= (select <int64>{} ?? <float64>{})
select a is float64;
{true}
或許您會覺得int64
與float64
不是同一型別,為什麼可以比較呢?這是因為EdgeDB為了方便使用者,會對整數及浮點數做自動的型別轉換(預設的整數型態為int64
,而預設的浮點數型態為float64
)。例如:
select {1} + {2.3};
{3.3}
這樣的轉換不只出現在整數與浮點數間,整數與整數間或是浮點數與浮點數間也會進行。例如:
with a:= (select <int16>{1} + <int32>{2})
select a is int32;
{true}
或是:
with a:= (select <float32>{1.1} + {1.1})
select a is float64;
{true}
exists可以幫助我們判斷所傳入的是否為空EdgeDBSet
。例如:
select exists({1});
{true}
當想在兩個EdgeDBSet
中進行選擇時,exists
與??
的功能類似。例如:
with a:= <int64>{},
b:= {1}
select a if exists(a) else b;
也可以寫為:
with a:= <int64>{},
b:= {1}
select a ?? b;
兩者的結果都是b
:
{1}
EdgeDBSet
可以進行多種運算。例如:
+
operatorselect {5} + {2};
{7}
-
operatorselect {5} - {2};
{3}
*
operatorselect {5} * {2};
{10}
/
operatorselect {5} / {2};
{2.5}
//
operatorselect {5} // {2};
{2}
%
operatorselect {5} % {2};
{1}
EdgeDBSet
的各種運算看起來相當直觀,有時候會讓人忘了它的運算其實是element-wise
。例如:
select {1, 2} + {3, 4};
{4, 5, 5, 6}
element-wise
的意思是EdgeDBSet
內的每個元素都會各別參與一次計算。所以上面的{4, 5, 5, 6}
分別是1+3
、1+4
、2+3
及2+4
的結果。
++
operator當EdgeDBSet
內元素為str
,而需要與其它內部元素也是str
的EdgeDBSet
連接時,需要使用++
。例如:
select {"a", "b"} ++ {"c", "d"};
{'ac', 'ad', 'bc', 'bd'}
如果寫成:
select {"a", "b"} + {"c", "d"};
會報錯:
error: InvalidTypeError: operator '+' cannot be applied to operands of type 'std::str' and 'std::str'
EdgeDBSet
當EdgeDBSet
的計算中遇到空EdgeDBSet
時,會立刻返回該種型別的空EdgeDBSet
。例如:
select <int64>{} + {1, 2};
{}
或是:
select <str>{} ++ {"a", "b"};
{}
我們可以透過introspect及typeof來觀察返回的空EdgeDBSet
:
with a:=(select <int64>{} + {1, 2})
select (introspect typeof a) {*};
{
schema::ScalarType {
final: false,
is_final: false,
abstract: false,
is_abstract: false,
id: 00000000-0000-0000-0000-000000000105,
name: 'std::int64',
internal: false,
builtin: true,
computed_fields: [],
expr: {},
from_alias: false,
is_from_alias: false,
inherited_fields: [],
default: {},
enum_values: {},
arg_values: {},
},
}
可以看出其name property
顯示其為std::int64
。
考慮schema如下:
abstract type Portfolio {
multi stocks: Stock
}
type ValueInvesting extending Portfolio;
type TechnicalAnalysis extending Portfolio;
type Stock {
required name: str {
constraint min_len_value(4);
constraint max_len_value(5);
}
required eps: float64
}
我們這裡模擬一個股市的投資情境:
Portfolio abstract type
為一投資組合,內部含有多個Stock object
,供ValueInvesting object
及TechnicalAnalysis object
來extending
。ValueInvesting object
代表價值投資學派選股法。TechnicalAnalysis object
代表技術分析學派選股法Stock object
含有一個name property
及一個eps property
,用以記錄股票名字及比益比。接著執行下列query,insert
五個Stock object
、一個ValueInvesting object
及一個TechnicalAnalysis object
:
with stocks:= {
(name:="好棒棒實業", eps:= 5),
(name:="井噴金控", eps:= 12),
(name:="歐印集團", eps:= 15),
(name:="雜空企業", eps:= 18),
(name:="多娃廚房", eps:= 40),
}
for stock in stocks
union (
insert Stock {
name:= stock.name,
eps:= stock.eps
}
);
insert ValueInvesting {
stocks:= (
select Stock
filter .name in {"好棒棒實業", "井噴金控", "歐印集團", "雜空企業"}
)
};
insert TechnicalAnalysis {
stocks:= (
select Stock
filter .name in {"井噴金控", "歐印集團", "雜空企業", "多娃廚房"}
)
};
我們可以透過下面query,列出兩個學派共同選中的股票:
select ValueInvesting.stocks intersect TechnicalAnalysis.stocks {**};
{
default::Stock {id: d5718b48-549a-11ef-82dd-dbb5b0359637},
default::Stock {id: d5718b98-549a-11ef-82dd-13f3b149f61d},
default::Stock {id: d5718bca-549a-11ef-82dd-a39cbfb647d8},
}
雖然我們加上了{**}
,但卻沒有顯示出Stock
的shape
,不方便觀察。這是因為set operation
在做運算之後(例如這邊的intersect
),shape
不會保存。
我們需要使用with
來幫忙改寫query如下:
with common_stocks:= (ValueInvesting.stocks intersect TechnicalAnalysis.stocks)
select common_stocks {name, eps};
{
default::Stock {name: '雜空企業', eps: 18},
default::Stock {name: '歐印集團', eps: 15},
default::Stock {name: '井噴金控', eps: 12},
}
這麼一來,我們就可以觀察出有三檔股票,是兩個學派都擁有的標的。