從存儲過程到通用 SQL:進銷存系統的數據操作優化
在進銷存系統的開發與維護中,數據庫查詢語句的編寫方式對系統的性能、兼容性和可維護性有著深遠影響。本文將圍繞給定的三段 SQL 代碼展開,深入探討將存儲過程轉換為通用 SQL 在進銷存場景下的諸多好處,同時對字段進行中文轉換以滿足發表和隱私需求。
原始存儲過程剖析
原始的 SQL 存儲過程代碼如下:
sql
$sql = "exec sp_executesql N'SELECT 庫存ID, 庫存編碼, RTRIM(庫存名稱) AS 庫存名稱, -- 去除中文字段尾部空格RTRIM(庫存類別) AS 庫存類別,RTRIM(庫存款式) AS 庫存款式,RTRIM(庫存規格) AS 庫存規格,ISNULL(門店成本, 庫存成本) AS 庫存成本, 期初數量, 增加數量, 減少數量, (期初數量 + 增加數量 - 減少數量) AS 總數量 FROM (SELECT 庫存主表.庫存ID AS 庫存ID, 庫存主表.庫存編碼 AS 庫存編碼, 庫存主表.庫存名稱 AS 庫存名稱, 庫存主表.庫存類別 AS 庫存類別, 庫存主表.庫存款式 AS 庫存款式, 庫存主表.庫存規格 AS 庫存規格, 庫存主表.庫存成本 AS 庫存成本, (SELECT 庫存成本 FROM 庫存門店成本 WHERE 庫存門店成本.庫存ID = 庫存主表.庫存ID AND 庫存門店成本.分店 = @倉庫) AS 門店成本, SUM(CASE WHEN (庫存憑證.出入庫 = 1 OR 庫存憑證.出入庫 = -1) AND 庫存憑證.生效日期 < @開始日期 THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 ELSE 0 END) AS 期初數量, SUM(CASE WHEN 庫存憑證.出入庫 = 1 AND 庫存憑證.生效日期 >= @開始日期 AND 庫存憑證.生效日期 <= @結束日期 THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 ELSE 0 END) AS 增加數量, SUM(CASE WHEN 庫存憑證.出入庫 = -1 AND 庫存憑證.生效日期 >= @開始日期 AND 庫存憑證.生效日期 <= @結束日期 THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 * -1 ELSE 0 END) AS 減少數量 FROM 庫存憑證, 庫存憑證明細, 庫存主表 WHERE 庫存憑證.憑證ID = 庫存憑證明細.主表ID AND 庫存憑證明細.庫存ID = 庫存主表.庫存ID AND 庫存憑證.狀態 = @狀態 AND 庫存憑證.倉庫 LIKE @倉庫 GROUP BY 庫存主表.庫存ID, 庫存主表.庫存編碼, 庫存主表.庫存名稱, 庫存主表.庫存類別, 庫存主表.庫存款式, 庫存主表.庫存規格, 庫存主表.庫存成本) AS 庫存數據 ORDER BY 庫存編碼',N'@狀態 int, @開始日期 datetime, @結束日期 datetime, @倉庫 nvarchar(4)',@狀態 =?, @開始日期 =?, @結束日期 =?, @倉庫 =? ";
此存儲過程通過?sp_executesql
?執行動態 SQL,用于從進銷存相關的多張表(庫存主表、庫存門店成本表、庫存憑證表、庫存憑證明細表)中獲取特定時間段和倉庫的庫存數據,包括庫存 ID、編碼、名稱、類別、款式、規格、成本以及不同時間段的數量變化情況。通過參數化查詢,使得該存儲過程在不同條件下具有一定的靈活性。
轉換為通用 SQL 的過程及優勢
- 消除特定數據庫依賴,提升兼容性:許多數據庫系統雖然支持存儲過程,但語法和特性存在差異。將存儲過程轉換為通用 SQL,可以避免依賴特定數據庫的存儲過程執行機制,如?
sp_executesql
?是 SQL Server 特定的語法。轉換后的通用 SQL 可以在更多類型的數據庫系統中運行,無需針對不同數據庫進行語法調整,大大提高了系統的兼容性和可移植性。
sql
// 構建帶參數的SQL語句
$sql = " SELECT 庫存ID, 庫存編碼, RTRIM(庫存名稱) AS 庫存名稱,RTRIM(庫存類別) AS 庫存類別,RTRIM(庫存款式) AS 庫存款式,RTRIM(庫存規格) AS 庫存規格,ISNULL(門店成本, 庫存成本) AS 庫存成本, 期初數量, 增加數量, 減少數量, (期初數量 + 增加數量 - 減少數量) AS 總數量 FROM (SELECT 庫存主表.庫存ID AS 庫存ID, 庫存主表.庫存編碼 AS 庫存編碼, 庫存主表.庫存名稱 AS 庫存名稱, 庫存主表.庫存類別 AS 庫存類別, 庫存主表.庫存款式 AS 庫存款式, 庫存主表.庫存規格 AS 庫存規格, 庫存主表.庫存成本 AS 庫存成本, (SELECT 庫存成本 FROM 庫存門店成本 WHERE 庫存門店成本.庫存ID = 庫存主表.庫存ID AND 庫存門店成本.分店 = @倉庫) AS 門店成本, SUM(CASE WHEN (庫存憑證.出入庫 = 1 OR 庫存憑證.出入庫 = -1) AND 庫存憑證.生效日期 < @開始日期 THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 ELSE 0 END) AS 期初數量, SUM(CASE WHEN 庫存憑證.出入庫 = 1 AND 庫存憑證.生效日期 >= @開始日期 AND 庫存憑證.生效日期 <= @結束日期 THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 ELSE 0 END) AS 增加數量, SUM(CASE WHEN 庫存憑證.出入庫 = -1 AND 庫存憑證.生效日期 >= @開始日期 AND 庫存憑證.生效日期 <= @結束日期 THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 * -1 ELSE 0 END) AS 減少數量 FROM 庫存憑證, 庫存憑證明細, 庫存主表 WHERE 庫存憑證.憑證ID = 庫存憑證明細.主表ID AND 庫存憑證明細.庫存ID = 庫存主表.庫存ID AND 庫存憑證.狀態 = @狀態 AND 庫存憑證.倉庫 LIKE @倉庫 " . // 添加商品ID篩選條件(如果提供了商品ID)(!empty($商品ID)? " AND 庫存主表.庫存ID = @商品ID " : "") . "GROUP BY 庫存主表.庫存ID, 庫存主表.庫存編碼, 庫存主表.庫存名稱, 庫存主表.庫存類別, 庫存主表.庫存款式, 庫存主表.庫存規格, 庫存主表.庫存成本) AS 庫存數據 ORDER BY 庫存編碼',N'@狀態 int, @開始日期 datetime, @結束日期 datetime, @倉庫 nvarchar(4)" . (!empty($商品ID)? ", @商品ID int" : "") . "',@狀態 = " . $狀態 . ", @開始日期 = '" . $開始日期 . "', @結束日期 = '" . $結束日期 . "', @倉庫 = N'" . $分店 . "'" . // 商品ID參數(如果提供)(!empty($商品ID)? ", @商品ID = " . $商品ID : "");
- 簡化維護難度,提高代碼可讀性:通用 SQL 以更直觀的方式展示數據查詢邏輯,對于不熟悉存儲過程復雜語法和結構的開發人員來說,更容易理解和維護。在上述轉換后的代碼中,SQL 語句的結構和邏輯一目了然,直接從多張表中獲取數據并進行計算和篩選,開發人員可以快速定位和修改相關邏輯,減少維護成本。
- 便于代碼審查和優化:通用 SQL 便于進行代碼審查,因為其語法和結構相對統一。審查人員可以更清晰地分析查詢性能,發現潛在的問題,如是否存在冗余連接、不合理的條件判斷等。通過優化通用 SQL,可以提高查詢效率,進而提升整個進銷存系統的性能。
sql
// 基礎查詢SQL
$sql = "SELECT 庫存ID, 庫存編碼, RTRIM(庫存名稱) AS 庫存名稱,RTRIM(庫存類別) AS 庫存類別,RTRIM(庫存款式) AS 庫存款式,RTRIM(庫存規格) AS 庫存規格,ISNULL(門店成本, 庫存成本) AS 庫存成本, 期初數量, 增加數量, 減少數量, (期初數量 + 增加數量 - 減少數量) AS 總數量 FROM (SELECT 庫存主表.庫存ID AS 庫存ID, 庫存主表.庫存編碼 AS 庫存編碼, 庫存主表.庫存名稱 AS 庫存名稱, 庫存主表.庫存類別 AS 庫存類別, 庫存主表.庫存款式 AS 庫存款式, 庫存主表.庫存規格 AS 庫存規格, 庫存主表.庫存成本 AS 庫存成本, (SELECT 庫存成本 FROM 庫存門店成本 WHERE 庫存門店成本.庫存ID = 庫存主表.庫存ID AND 庫存門店成本.分店 = '" . $分店 . "') AS 門店成本, SUM(CASE WHEN (庫存憑證.出入庫 = 1 OR 庫存憑證.出入庫 = -1) AND 庫存憑證.生效日期 < '" . $開始日期 . "' THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 ELSE 0 END) AS 期初數量, SUM(CASE WHEN 庫存憑證.出入庫 = 1 AND 庫存憑證.生效日期 >= '" . $開始日期 . "' AND 庫存憑證.生效日期 <= '" . $結束日期 . "' THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 ELSE 0 END) AS 增加數量, SUM(CASE WHEN 庫存憑證.出入庫 = -1 AND 庫存憑證.生效日期 >= '" . $開始日期 . "' AND 庫存憑證.生效日期 <= '" . $結束日期 . "' THEN 庫存憑證明細.數量 * 庫存憑證.增減標識 * -1 ELSE 0 END) AS 減少數量 FROM 庫存憑證, 庫存憑證明細, 庫存主表 WHERE 庫存憑證.憑證ID = 庫存憑證明細.主表ID AND 庫存憑證明細.庫存ID = 庫存主表.庫存ID AND 庫存憑證.狀態 = " . $狀態 . " AND 庫存憑證.倉庫 LIKE '" . $分店 . "' ";// 添加商品ID篩選條件(如果提供了商品ID)
if (!empty($商品ID)) {$sql .= " AND 庫存主表.庫存ID = '" .$商品ID . "' ";
}// 完成SQL語句
$sql .= " GROUP BY 庫存主表.庫存ID, 庫存主表.庫存編碼, 庫存主表.庫存名稱, 庫存主表.庫存類別, 庫存主表.庫存款式, 庫存主表.庫存規格, 庫存主表.庫存成本) AS 庫存數據 ORDER BY 庫存編碼";
結論
在進銷存系統中,將存儲過程轉換為通用 SQL 具有顯著的好處,不僅可以提升系統的兼容性,降低數據庫遷移成本,還能簡化代碼維護難度,提高查詢性能。開發人員在實際項目中應根據具體需求和場景,權衡存儲過程和通用 SQL 的使用,以實現更高效、穩定的進銷存系統。
阿雪技術觀
在科技發展浪潮中,我們不妨積極投身技術共享。不滿足于做受益者,更要主動擔當貢獻者。無論是分享代碼、撰寫技術博客,還是參與開源項目維護改進,每一個微小舉動都可能蘊含推動技術進步的巨大能量。東方仙盟是匯聚力量的天地,我們攜手在此探索硅基生命,為科技進步添磚加瓦。
Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets, hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology.