「最佳實踐」之一是通過存儲過程訪問數據。我明白爲什麼這種情況很好。 我的動機是拆分數據庫和應用程序邏輯(如果存儲過程的行爲相同,可以更改表),爲SQL注入防禦(用戶不能執行「select * from some_tables」,它們只能調用存儲過程),和安全性(在存儲過程中可以是任何安全的「任何東西」,該用戶不能選擇/插入/更新/刪除數據,這不適用於他們)。使用存儲過程訪問數據
我不知道如何使用動態過濾器訪問數據。
我使用的是MSSQL 2005
如果我有表:
CREATE TABLE tblProduct (
ProductID uniqueidentifier -- PK
, IDProductType uniqueidentifier -- FK to another table
, ProductName nvarchar(255) -- name of product
, ProductCode nvarchar(50) -- code of product for quick search
, Weight decimal(18,4)
, Volume decimal(18,4)
)
那麼我應該創建4個存儲過程(創建/讀取/更新/刪除)。
「創建」的存儲過程很容易。
CREATE PROC Insert_Product (@ProductID uniqueidentifier, @IDProductType uniqueidentifier, ... etc ...) AS BEGIN
INSERT INTO tblProduct (ProductID, IDProductType, ... etc ..) VALUES (@ProductID, @IDProductType, ... etc ...)
END
「刪除」的存儲過程也很容易。
爲「更新」的存儲過程是爲「刪除」類似,但我不知道這是正確的方式,如何做到這一點。我認爲更新所有列是不高效的。
CREATE PROC Update_Product(@ProductID uniqueidentifier, @Original_ProductID uniqueidentifier, @IDProductType uniqueidentifier, @Original_IDProductType uniqueidentifier, ... etc ...) AS BEGIN
UPDATE tblProduct SET ProductID = @ProductID, IDProductType = @IDProductType, ... etc ...
WHERE ProductID = @Original_ProductID AND IDProductType = @Original_IDProductType AND ... etc ...
END
而最後一個「讀取」的存儲過程對我來說是個小小的祕密。如何爲複雜條件傳遞過濾器值?我有幾個建議:
使用XML參數傳遞WHERE條件:
CREATE PROC Read_Product (@WhereCondition XML) AS BEGIN
DECLARE @SELECT nvarchar(4000)
SET @SELECT = 'SELECT ProductID, IDProductType, ProductName, ProductCode, Weight, Volume FROM tblProduct'
DECLARE @WHERE nvarchar(4000)
SET @WHERE = dbo.CreateSqlWherecondition(@WhereCondition) --dbo.CreateSqlWherecondition is some function which returns text with WHERE condition from passed XML
DECLARE @LEN_SELECT int
SET @LEN_SELECT = LEN(@SELECT)
DECLARE @LEN_WHERE int
SET @LEN_WHERE = LEN(@WHERE)
DECLARE @LEN_TOTAL int
SET @LEN_TOTAL = @LEN_SELECT + @LEN_WHERE
IF @LEN_TOTAL > 4000 BEGIN
-- RAISE SOME CONCRETE ERROR, BECAUSE DYNAMIC SQL ACCEPTS MAX 4000 chars
END
DECLARE @SQL nvarchar(4000)
SET @SQL = @SELECT + @WHERE
EXEC sp_execsql @SQL
END
但是,我覺得「4000」字符一個查詢的限制是醜陋的。
下一個建議是對每列使用過濾器表。將過濾器的值到過濾表,然後調用存儲過程的過濾器ID:
CREATE TABLE tblFilter (
PKID uniqueidentifier -- PK
, IDFilter uniqueidentifier -- identification of filter
, FilterType tinyint -- 0 = ignore, 1 = equals, 2 = not equals, 3 = greater than, etc ...
, BitValue bit , TinyIntValue tinyint , SmallIntValue smallint, IntValue int
, BigIntValue bigint, DecimalValue decimal(19,4), NVarCharValue nvarchar(4000)
, GuidValue uniqueidentifier, etc ...)
CREATE TABLE Read_Product (@Filter_ProductID uniqueidentifier, @Filter_IDProductType uniqueidentifier, @Filter_ProductName uniqueidentifier, ... etc ...) AS BEGIN
SELECT ProductID, IDProductType, ProductName, ProductCode, Weight, Volume
FROM tblProduct
WHERE (@Filter_ProductID IS NULL
OR ((ProductID IN (SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_ProductID AND FilterType = 1) AND NOT (ProductID IN (SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_ProductID AND FilterType = 2))
AND (@Filter_IDProductType IS NULL
OR ((IDProductType IN (SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_IDProductType AND FilterType = 1) AND NOT (IDProductType IN (SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_IDProductType AND FilterType = 2))
AND (@Filter_ProductName IS NULL OR (... etc ...))
END
但這個建議被littlebit複雜,我想。
有沒有一些「最佳做法」來做這種類型的存儲過程?
我應該使用視圖還是函數? 我認爲這些功能更加靈活。是爲什麼不使用函數而不是視圖或者不重要? – TcKs 2008-10-29 15:43:11
通常DBMS優化器會比函數更好地理解視圖。 – 2008-10-29 15:45:50
然後,它可能不會 - 在一個大型的生產數據庫中,當我們將一些較大的複雜查詢從視圖切換到函數時,我們的性能得到了顯着改善...... – 2008-10-29 16:11:41