關係運算子
在所有運算子中,關係運算子是最複雜的運算子,這就是我們將它們留到最後的原因。
關係運算子也稱為比較運算子,它們用於比較事物。
比較結果是布林值 false 或 true。
有趣的是,如果你在 VFP 幫助中檢查它,你只能看到一個簡短的列表操作和更多的行,就好像它是關於那些運算子的。
嗯,複雜性來自這樣一個事實:它們可以在任何型別上執行,無論是數字,日期,日期時間,邏輯還是字串,甚至是物件。此外,行為可能看起來很尷尬,除非你知道結果會產生什麼影響,否則你得不到你的期望。
讓我們從關係運算子列表開始:
操作者 | 描述 | MOST 基本樣本 |
---|---|---|
> | 比…更棒 | ?1> 2 && .F。 |
< | 少於 | ?1 <2 && .T。 |
> = | 大於或等於 | ?1> = 2 &&。F。 |
<= | 小於或等於 | ?1 <= 2 && .T。 |
= | 等於 | ?1 = 1 && .T。 |
== | 完全等於(對字串有意義) | ? ‘1’=‘1’&& .T。 |
!=,#,<> | 不等於(所有 3 個運算子的行為方式相同,選擇你最喜歡的) | ?1 != 1 && .F。 |
儘管可以將這些用於所有資料型別,但運算元之間應該存在型別相容性。例如,如果你嘗試將 Date 與 Integer 進行比較,則會出現錯誤。
可以比較日期和日期時間,儘管它們是不同的型別,VFP 會隱式為你進行轉換。
? Date() > DateTime() && .F.
? Date() <= DateTime() && .T.
? Date() < DateTime() && .T. if it is not midnight
當運算元是數字時,所有這些操作符都很簡單直接,它們就像在數學表示式中那樣工作。
有了邏輯運算元,F。被認為小於 .T。
物件我們比較的是物件在記憶體中的引用。因此,最常用的比較是確定兩個物件變數是否指向同一個物件。即:
local o1, o2
o1 = createobject('Label')
o2 = createobject('Label')
? m.o1 = m.o2 && is o1 and o2 the same object?
? m.o1 > m.o2 && this would work too but likely you would never use
* remember we are comparing their references in memory
*
* They are different objects, but do they have any difference in their properties?
? CompObj(m.o1, m.o2) && .T. They are identical properties wise
字元資料型別的比較,即字串的比較是 VFP 中最令人困惑的。它不像其他語言和/或資料庫那樣工作,並且對 VFP 是獨一無二的(也可能是其他一些 xBase 語言)。
許多年前,我甚至看到社群中一些非常先進的成員,他們還不知道這些運算子如何在 VFP 中運作。因此,可以理解的是,輕微的細微差別可能會讓新手容易混淆。
比較基本上是關於相等與否。如果它們不相等,那麼我們可能會考慮運算子>,<,> =,<=,對嗎?對於字串,當兩個字串被認為相等時,它會令人困惑。
重要提示: VFP 字串區分大小寫。 ‘A’和’a’是兩個不同的字串。對於許多資料庫而言,情況並非如此,其中預設情況下使用不區分大小寫的排序規則。例如,在使用不區分大小寫(CI)排序規則建立的表上的 postgreSQL 或 MS SQL Server 中:
select * from myTable where Country = 'TURKEY'
select * from myTable where Country = 'Turkey'
會產生相同的結果。在 VFP 中雖然只能獲得套管匹配的那些。然而,VFP 具有一些整理支援並且使得不區分大小寫的比較。 (不要相信,見下文)
-
如果兩個字串不相等,那麼這麼好,**只要你沒有更改任何預設值,**那麼它們將根據它們的 ASCII 值進行比較。
? 'Basoz' < 'Cetin' && is true. ? 'basoz' < 'Cetin' && is false. ? 'Cetin' < 'David' && is true. ? 'Çetin' < 'David' && is false.
整理的預設值是機器,這就是你得到的。當你將排序規則更改為其他內容時,你將根據該排序規則的排序順序進行比較。對於預設計算機以外的排序規則設定,你還意味著比較不區分大小寫(不要相信這是相同的):
set collate to 'GENERAL'
? 'Basoz' < 'Cetin'
? 'basoz' < 'Cetin'
? 'Cetin' < 'David'
? 'Çetin' < 'David'
現在所有這些表示式都是正確的。
個人建議:VFP 中的排序規則從來都不夠可靠。我建議你不要使用排序規則並堅持使用預設的’MACHINE’。如果你要使用排序規則,那麼請記住,當你遇到關於字元資料的非常意外的事情時,請先檢查它。我已經看到並證明它在許多情況下都失敗了,但後來我在 VFP9 版本之前停止嘗試使用它,它現在可能是一致的,我真的不知道。
考慮到我們用字串覆蓋不等式情況,棘手的是同等情況。在 VFP 中基本上有兩個設定影響比較:
- SET EXACT(預設為 OFF 並影響常規比較 - 除了 SQL 之外)
- SET ANSI(預設為 OFF 並僅在 SQL 中進行效果比較 .SET EXACT 對 SQL 查詢中的比較沒有影響。
使用 SET EXACT OFF,讀取比較為右邊的字串是否為左邊的字串?它們與正確的字串長度進行比較。
? "Bobby" = "B" && Bobby starts with B, so TRUE
? "Bobby" = "Bob" && Bobby starts with Bob, so TRUE
? "Bobby" = "Bob " && Bobby starts with Bob but there is a trailing space there, FALSE
? "Bobby" = "bob" && would be true with collation set to GENERAL
注意,通過常規比較,
Bobby
=B
為 TRUE,但B
=Bobby
為 FALSE。換句話說,運算元的位置很重要。
使用 SET EXACT ON 時,字串必須完全匹配,但忽略它們的尾隨空格(我們忽略了 set collate,這也會使用大小寫不敏感):
? "BOBBY" = "BOB" && FALSE
? "BOBBY" = "BOBBY" && TRUE
? "BOBBY" = "BOBBY " && TRUE
? "BOBBY " = "BOBBY" && TRUE
現在,使用 SQL 命令 SET EXACT 沒有任何效果,它的行為就像 SET EXACT OFF 一樣。
Select * from Customers where Country = 'U'
從美國,英國選擇以’U’開頭的任何國家的客戶。
但是,在 SQL 中,根據定義,更改運算元的順序應該會產生相同的結果。從而:
Select * from Customers where 'U' = Country
也會以相同的方式工作(請注意與非 SQL 命令的區別)。
當你想暗示完全匹配時,一個選項是開啟 ANSI:
SET ANSI ON
Select * from Customers where Country = 'USA'
返回來自美國的所有客戶。請注意,將忽略國家/地區欄位 OR 中右側表示式的尾隨空格。無論你有多少落後都沒關係。你可以像進行比較一樣進行比較:RTRIM(Country)
= RTRIM(‘USA’)。
儘管在 VFP 中的操作符中未提及,但 SQL 運算子是 LIKE。當你使用 LIKE 時,無論 SET ANSI 設定如何,你都會獲得完全匹配的比較(使用 LIKE 強制和隱式 ANSI ON 情況 - 畢竟它是 ANSI 運算子)。但是,請注意行為略有不同。除非帶有預告片的總大小等於或小於欄位大小,否則它不會忽略尾隨空格。例如,如果 Country 欄位是
C(10)
,則 Country =‘USA’或 Country =‘USA__‘將起作用,但 Country =‘USA___________‘將失敗( 下劃線表示一個空格,最後一個表示多於 7 個尾隨空格)。
最後我們是最後一個運算子,==。這意味著完全相同,並使用字串。一個優點是,使用==你總是意味著你想要完全匹配,無論 SET EXACT 或 SET ANSI 設定如何。但是請注意,當它是 SQL 命令或非 SQL 常規命令時,它的行為是不同的。
使用 SQL:
Select * from Customers where Country == 'USA'
無論 ANSI 和 EXACT 設定如何,我們都希望所有來自美國的客戶。任何一側的尾隨空格都會被忽略。
使用非 SQL:
? m.lcString1 == m.lcString2
只有在它們的套管和長度完全相同時才會成立 (尾隨空格不會被忽略)。它不受 SET ANSI,EXACT 或 COLLATE 設定的影響。