# 如何使用procedures.sql?
我稍微修改了search.sql的運作方式,也加了新的功能。以下會說明它的功能和使用方式
## search.sql的內容
* **開頭的註釋**
輸入參數的範例
* **兩個mysql的procedure(`main`,`cat_city_locations`)**
這個檔案的主要功能。執行`main`之後,會依據輸入參數產生`@query`並將`@query`視為mysql的query輸入執行。`cat_city_locations`只特別用於處理地點搜尋。
## 如何使用
1. `source search.sql`
執行search.sql,定義要用到的兩個procedure。
procedure在定義之後應該不會不見,除非它被手動刪除掉,所以基本上可以跳過這步。
2. `set` 要用到的參數
```mysql
set @inputStartDate = "2019-03-20";
#mysql的 DATE格式("YYYY-MM-DD")
set @inputEndDate = "2020-12-31";
#同上
set @inputCityID = "0,4";
#逗點(',')區隔的整數
set @inputCategoryID = "4,5,6";
#同上
set @inputIsFree = "Y"
#'Y'或'N'
```
沒有要用某個參數時,要把它設成`NULL`。這些參數會保留到使用者登出(執行`exit`)。所以要在每次執行前**把沒用到的參數主動設成NULL**
3. 執行main
```mysql
call main();
```
## 目前的功能
1. 搜尋**特定時間**內有多少展演中的文藝表演
2. 以**特定位置**為搜尋目標,找出該地點於某段時間內有哪些文藝表演
3. 根據使用者喜愛的**活動類別**,推薦即將開展或展演中的表演
4. 有些活動是**免費**的,能分辨出來並展示給使用者
## cat_city_locations
### code
```mysql
create procedure cat_city_locations()
begin
declare i int default 1;
declare cnt int default 0;
declare v_location_name text;
declare location_cur cursor for
select location_name
from locations
where city_id = @curr_cityid
;
open location_cur;
select count(UID) into cnt from locations where city_id = @curr_cityid;
while i<cnt do
set @query = concat(@query, " or ");
fetch location_cur into v_location_name;
set @query = concat(@query,
" instr(showInfo.location, \"",
v_location_name,
"\" collate utf8mb4_unicode_ci)");
set i=i+1;
end while;
close location_cur;
# in main():
# ...
if not isnull(@inputCityID) then
select length(@inputCityID)-length(replace(@inputCityID,',',''))+1 into cnt;
set @query = concat(@query, " and ( false ");
while i <= cnt do
select cast(
substring_index(
substring_index(@inputCityID,',',i)
,',',-1)
as unsigned)
into @curr_cityid;
call cat_city_locations();
set i=i+1;
end while;
set @query = concat(@query, ")");
end if;
#...
end //
```
### 說明
#### main
```mysql
select length(@inputCityID)-length(replace(@inputCityID,',',''))+1 into cnt;
```
找出`@inputCityID`裡有多少個輸入(`@inputCityID`的長度-`@inputCityID`去掉逗號之後的長度)
```mysql
set @query = concat(@query, " and ( false ");
```
`@inputCityID`條件的開頭,要和其他條件做and
```mysql
# in while
select
cast(
substring_index(
substring_index(@inputCityID,',',i)
,',',-1)
as unsigned)
into @curr_cityid;
call cat_city_locations();
```
一一把@inputCityID裡的值選出來,並輸入到 `cat_city_locations()`裡
```mysql
# after while
set @query = concat(@query, ")");
```
`@inputCityID`條件的結尾,把開頭的and的括弧關起來
#### cat_city_location
```mysql
declare location_cur cursor for
select location_name
from locations
where city_id = @curr_cityid
;
open location_cur;
```
宣告並開啟一個能夠查locations裡city_id符合`@curr_cityid`的項目並把值一一`fetch`出來的`cursor`
```mysql
# in while:
set @query = concat(@query, " or ");
fetch location_cur into v_location_name;
```
在條件後面接上 or,然後`fetch`下一個`location_name`到`v_location_name`裡
```mysql
# in while:
set @query = concat(@query,
" instr(showInfo.location, \"",
v_location_name,
"\" collate utf8mb4_unicode_ci)");
```
在條件後面接上`v_location_name`對應的條件
##### 產出的條件
```mysql
instr(showInfo.location,"*v_location_name的值*" collate utf8mb4_unicode_ci)
```
`instr()`: 找`showInfo.location`裡有沒有包含`v_location_name`
`collate utf8mb4_unicode_ci`: 轉換`v_location_name`的編碼方式
## 舉例
設定:
```mysql
set @inputStartDate = "2019-03-20";
set @inputEndDate = "2020-12-31";
set @inputCityID = "0,3";#台北、新竹
set @inputCategoryID = "4,5,6";
set @inputIsFree = "Y";
call main();
select @query;
```
output:
```mysql
# 固定的開頭
select *
from artshow, showInfo
where artshow.UID = showInfo.artshowUID
# 如果 @inputStartDate 是NULL,就沒有這個條件
and showInfo.time >= @inputStartDate
# 如果 @inputEndDate 是NULL,就沒有這個條件
and showInfo.time <= @inputEndDate
# 把locations裡的台北和新竹的地名加入條件
and ( false
or instr(showInfo.location, "台北市" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "臺北市" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "仁愛路四段" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "國立歷史博物館" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "忠孝西路一段" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "新生南路" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "杭州南路" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "研究院路" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "新竹市" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "新竹縣" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "北區集賢街" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "文興路" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "竹北市" collate utf8mb4_unicode_ci)
)
# 把 @inputCategoryID 裡的數字加入category的條件
and ( false
or artshow.category = 4
or artshow.category = 5
or artshow.category = 6
)
# 如果 @inputIsFree 是NULL,就沒有這個條件
and showInfo.onsales = @inputIsFree collate utf8mb4_unicode_ci
```
設定:
```mysql
set @inputStartDate = NULL;
set @inputEndDate = "2020-12-31";
set @inputCityID = "0";#台北
set @inputCategoryID = NULL;
set @inputIsFree = "Y";
call main();
select @query;
```
output:
```mysql
# 固定的開頭
select *
from artshow, showInfo
where artshow.UID = showInfo.artshowUID
# @inputStartDate 是NULL,跳過這個條件
# 如果 @inputEndDate 是NULL,就沒有這個條件
and showInfo.time <= @inputEndDate
# 把locations裡的台北的地名加入條件
and ( false
or instr(showInfo.location, "台北市" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "臺北市" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "仁愛路四段" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "國立歷史博物館" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "忠孝西路一段" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "新生南路" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "杭州南路" collate utf8mb4_unicode_ci)
or instr(showInfo.location, "研究院路" collate utf8mb4_unicode_ci)
)
# 跳過category的條件
# 如果 @inputIsFree 是NULL,就沒有這個條件
and showInfo.onsales = @inputIsFree collate utf8mb4_unicode_ci
```