iT邦幫忙

1

mysqli 用in語法 如何bind_param

各位大大好
小弟的問題是這樣的
目的是 要記錄某日期下每個群組中的業績
每個群組底下有很多人
由於此table沒有連結群組
只有每個人的紀錄
所以只能由另外的table去拼成字串
直接上code

//先把群組中的人找出 並串成字串
$query = "select person_id from group where groupno='$_POST[group_no]'";
$result = $mysqli_oolink->query($query);
while($row = $result->fetch_array(MYSQLI_NUM)) {
    array_push($dataArray,$row[0]);
}
$person_no = implode(',',$dataArray);
//上列結果我有印出來 確定是 02032, 02033, ...  這種樣式

//主語法
$sql = "select amount from test where date = ? and person_id in (?)";
$stmt = $mysqli_oolink->prepare($sql);
$stmt->bind_param('ss', $_POST[nowdate], $person_no);
$stmt->execute();
$stmt->fetch();

為了不想傳array當參數
我覺得直接輸入一個字串進去應該會是一樣的結果
可是卻抓不出任何資料
不知道bind_param的問題 還是 in的寫法問題
請教各位大大

3
通靈亡
iT邦研究生 4 級 ‧ 2020-05-28 10:49:14
最佳解答

in 配 bind param 的寫法:

// in的資料
$person_no = implode(',',$dataArray);

// 產生bind要用到的所有?,in 跟 非 in的問號分開,所以不用+1
$bind_comma = str_repeat('?', count($dataArray));

// 產生bind用到的所有s,+1是包含前面的date
$bind_s = str_repeat('s', count($dataArray) + 1); 

// 把bind的問號放到sql語句
$sql = "select amount from test where date = ? and person_id in ($person_comma)";

// 把變數bind到所有問號上以後執行查詢
$stmt->bind_param($bind_s, $_POST[nowdate], ...$person_no);
$stmt->execute();
看更多先前的回應...收起先前的回應...
st474ddr iT邦新手 5 級 ‧ 2020-05-28 10:55:02 檢舉

先感謝大大

不過我想請問
所以這樣代表
在in語法中 一定要個別傳遞每個值
不能直接傳入一整個字串?
bind_param有字數限制嗎?
還是什麼原因

因為我這樣寫他也不會報錯或警告
只是就單純抓不出我要的資料而已

通靈亡 iT邦研究生 4 級 ‧ 2020-05-28 10:59:49 檢舉

不行直接傳字串,你的問題應該是下面這行,只有兩個s

$stmt->bind_param('ss', $_POST[nowdate], $person_no);

所以後面會被sql視為「單一個值」
變成 in ('02032, 02033')
但事實上你應該要 in ('02032', '02033')

如果你要改成上面的寫法
你直接傳字串,上面的s數量就會對不起來

st474ddr iT邦新手 5 級 ‧ 2020-05-28 11:05:29 檢舉

原來如此
感謝大大
我了解了

用sql的語法給你看

你說的一個字串,其sql碼出來會變這樣

person_id in ("1,2,3,4,5")

這位大大給你的出來的會是

person_id in ("1","2","3","4","5")

因該從這邊就能看出差異點了吧。
也能了解你的問題。

不過我其實還真的沒用過 bind_param

另外你提到了字數限制。過來人的經驗,算是有。
但並不是 bind_param 的字數限制。
而是sql語法的最大容許值。

通靈亡 iT邦研究生 4 級 ‧ 2020-05-28 12:03:06 檢舉

補充樓上大大的說明

mysql的語法最大容許值:1048576 bit (max_allowed_packet)
sql server語法的最大容許值:65,536 Byte * Network Packet Size (default packet size is 4 KB).

所以如果IN過多的資料,可以改成存暫存表+IN
或建議直接轉成JOIN的寫法,如rogeryao大大的回答。

https://stackoverflow.com/questions/1869753/maximum-size-for-a-sql-server-query-in-clause-is-there-a-better-approach

st474ddr iT邦新手 5 級 ‧ 2020-05-28 13:24:12 檢舉

感謝兩位大大的補充以及回覆~

2
rogeryao
iT邦高手 1 級 ‧ 2020-05-28 10:46:03
select amount 
from test as A
-- left join group as B on B.person_id=A.person_id
left join usergroup as B on B.person_id=A.person_id
where B.groupno='$_POST[group_no]'
........

group 是 SQL 關鍵字勿用,可改為 usergroup

st474ddr iT邦新手 5 級 ‧ 2020-05-28 10:55:41 檢舉

這我會多注意的
感謝大大提醒

2
海綿寶寶
iT邦大神 1 級 ‧ 2020-05-28 11:08:09

參考這裡的完整說明

從頭來說, 正確的 SQL 像這樣
bind_parm 只是寫法不同而已

SELECT * FROM table WHERE str IN ("A","B","C","D")

上面各位正確解答也是如此

而你的寫法
最後組出來的 SQL 會是這樣

SELECT * FROM table WHERE str IN ("A,B,C,D")

所以才會「不報錯,但也找不到你要的資料」

st474ddr iT邦新手 5 級 ‧ 2020-05-28 13:27:29 檢舉

其實我也有搜尋到很多這種說明的
由於他們傳進去的其實都是陣列
還有用call_user_func_array的
但我想拼成字串會不會就可以用一般方式傳

只是沒注意到bind_param標記資料的方式問題
經大大們提醒之後 恍然大悟 哈哈

我要發表回答

立即登入回答