iT邦幫忙

1

每一小時的訂單流水號?

// 找到現在的「時間」
$ymdh = date('Y/m/d H');

// 用現在的時間找出訂單目前是有幾筆
$findOrderSoFar = mysqli_fetch_array($pdo->query(
    "SELECT count(public_order_id) as num FROM `order_record`
    WHERE FROM_UNIXTIME(add_time, '%Y/%m/%d %H') = '{$ymdh}' "
));

// 將 $i 直接加入目前幾筆的數量
$i = $findOrderSoFar['num'];

// 如果找到零比則從一開始
$findOrderSoFar['num'] == 0 ? $i = 1 : $i = $findOrderSoFar['num'];

// 開始迴圈
while ($row = mysqli_fetch_array($sql)) {

    // 設定訂單長相
    $_SESSION['public_order_id'] = substr(date('YmdH', time()), -8).str_pad($i, 4, '0' ,STR_PAD_LEFT);
    
    // ...
    $i ++;
}

我目前作法是這樣,但是卻還是會重複流水號
就是不同使用者同時下訂時仍然會有這情形發生
我的邏輯已經死了 LOL..

補充
訂單編號格式會是:
YYMMDDHH0001

看更多先前的討論...收起先前的討論...
不明 檢舉
我記得mssql有自動流水號的功能 其它我就不知道了
不明 檢舉
我記得mssql有自動流水號的功能 其它我就不知道了
火爆浪子 iT邦研究生 1 級 ‧ 2019-01-10 23:28:25 檢舉
有我知道可以自動產生~但是我是每小時就要歸零
slime iT邦大師 1 級 ‧ 2019-01-10 23:39:55 檢舉
產生重複的號碼有什麼特徵?
slime iT邦大師 1 級 ‧ 2019-01-10 23:48:34 檢舉
個人初步建議:
1. 判斷時間的部份, 留意 php 主機與 mariadb 主機時間是否一致. (剛開始練習時通常在同一台沒問題, 之後可能跨不同主機要注意.)
2. 最好在 mariadb 有一個 table 存兩欄, 一欄是 YYYYMMDDHH , 一欄是預估的一小時內流水號如: 000001 .
3. (實作上建議, 作業的話可以放前端), 由資料庫主機的 Store Procedure 來取得 資料庫主機時間 , 如果目前的 YYYYMMDDHH 與前一步驟不同, 更新前一步驟欄位並將流水號改為 1 , 如果 YYYYMMDDHH 相同, 則第二欄流水號加一後回傳.
4. 前端呼叫該 Store Procedure 取得完整流水號.
newkevin iT邦高手 1 級 ‧ 2019-01-11 08:19:03 檢舉
抓同一台電腦的時間 ??
或不同電腦 使用者的變動 排在序號產生的前面幾碼 或後面幾碼
cs686 iT邦新手 5 級 ‧ 2019-01-11 08:38:34 檢舉
指定某一时间段生成特定号码,放到号段池,取用号段池数据生成流水号,用完重新生成
淺水員 iT邦大師 6 級 ‧ 2019-01-11 13:54:57 檢舉
問一下流程是哪一種:
(A) 使用者輸入資料之前就要給他單號,等他輸入完畢會再儲存到資料庫
(B) 使用者輸入資料時並不會給單號,等資料送出之後,再顯示單號給使用者
stevekwok iT邦新手 5 級 ‧ 2019-01-14 08:41:00 檢舉
你在那時把新流水號更新到database?
簡單的流水號用這個 uniqid();
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
6
耿直小伙
iT邦新手 1 級 ‧ 2019-01-11 09:54:29
最佳解答

產生序號的方式各位大大已經分享很多,想提供取得訂單編號之後的處理過程,當然不一定是最好的,可以參考一下。

  1. 使用迴圈產生訂單編號與執行sql insert語句
  2. 執行sql語法並取得錯誤碼
  3. 若錯誤碼等於1062代表資料重複
  4. 1062以外的錯誤碼則停止迴圈
do {
	// 取得訂單編號

	// 執行insert sql

	// 取得sql error錯誤碼
	$errorNo = getErrorNo(); // 請使用你目前程式取得錯誤碼的方式

	// 資料重複以外的錯誤則停止迴圈
	if ($errorNo > 0 && $errorNo != 1062) {
		break;
	}
} while ($errorNo == 1062); // 錯誤碼為1062則重複繼續迴圈
看更多先前的回應...收起先前的回應...
棉花 iT邦新手 4 級 ‧ 2019-01-16 14:21:11 檢舉

是說,如果資料重複的欄位是在unique key而不是primary key時,不會變成無窮迴圈嗎?

不會喔,關於訂單編號我這邊固定設為unique key而不是primary key,目前是沒發生無窮迴圈的狀況。

已經流水號設定唯一值,單號還會重複
那是重複的單號是從哪來得???

流水號只要不是透過資料庫產生就有可能會重複

4
做工仔人!
iT邦大師 1 級 ‧ 2019-01-11 09:10:06

這個問題應該不是程式邏輯旳問題.
而是"取單號"後,到資料COMMIT 到TABLE 中的時間差問題.
可以從三個方向下手:
A.單據主檔的單號位設定為"唯一值"的主INDEX.當單號重覆時,資料庫會傳回錯誤碼給前端程式.前端程式要攔截錯誤碼後, 再重新取單號.直到 INSERT 成功為止.
B.改變單號編碼還輯: 將機台編號或部門編號或員工編號...等擇一或擇二加入單號的編碼原則中.以降低重覆機率.
C.縮短"取單號"到COMMIT之間的時間差.如資料輸入時先不取單號,等除了單號外其他資料輸入完畢後,準備要INSERT進TABLE時,才取單號,取完後,立即INSERT 進TABLE .INSERT OK 後,再重新DISPLAY畫面.(將單號資料顯示在畫面上)

已經流水號設定唯一值,單號還會重複
那是重複的單號是從哪來得???

3

發現你程式幾個問題要注意。

三元判斷式不是給你這樣用的啦。而且,你根本不需要再去判斷。直接+1就好了。
三元判斷式的正規用法是

$findOrderSoFar['num'] == 0 ? $i = 1 : $i = $findOrderSoFar['num'];

改成

$i = $findOrderSoFar['num'] == 0 ? 1 : $findOrderSoFar['num'];

這才是正確的三元應用寫法。

不過在這邊,不知道你有沒有注意到。無論是0筆還是1筆。其i值都是1。這不是很奇怪嗎?

所以你的

$i = $findOrderSoFar['num'];

直接改成

$i = $findOrderSoFar['num']+1;

就可以了。那個三元判斷式就拿掉不要用它了。

再來是建議的做法。其實一般自定義的流水號,也最好不要直接取資料值數量。
可以的話,可以建一個設定檔的新表。來將值暫存在此。

2
淺水員
iT邦大師 6 級 ‧ 2019-01-11 14:46:46

我的想法是這樣

order_record

id add_time status
AUTO_INCRESMENT id 提交時間 狀態,刪除或是棄用設定為 0
  1. 使用者請求訂單時,直接 insert 到表中。(如果是填資料之前,status 可以設定為 -1 或其他數字)。
  2. 如果流程是使用者後續還要輸入資料,用 update 處理訂單。
  3. 當需要顯示單號給使用者時,抓取相同區間 add_time 的資料,然後流水號為:該筆 id - 該區間第一筆 id + 1
4
sam0407
iT邦大師 1 級 ‧ 2019-01-11 14:51:41

Oracle有一個好用的語法:
Select .... for Update
之前看前輩就用這個指令解決了樓主取號重複的問題。

搜尋select for update DB類型,應該可以解決您的問題

1
gn00044255
iT邦新手 5 級 ‧ 2019-01-11 15:35:24

1.做一個取訂單的副程式
2.在新增訂單時都去SQL取新的號碼
OrderNumber=OrderNumber_App()
3.用i+1有可能重覆

我要發表回答

立即登入回答