有沒有更好的SQL Server 2008 R2的技術來編寫以下結合INSERT
& UPDATE
程序,允許NULL INSERT
?T-SQL開發人員插入和合並存儲過程可以修改爲NULL
我很感興趣的是看看其他開發人員如何編寫能夠處理NULL插入的程序(想象用戶想要撤消一個條目)。我很欣賞將使用MERGE
或某些事務回滾技術的更復雜和優雅的解決方案,但我確實要求您從第一原則構建您的示例,因爲這可能會導致該帖子具有更廣泛的吸引力不管什麼讀者T-SQL級別。
這個簡單化的例子的基礎是Orders
表跟蹤股票購買。該程序應只允許UPDATES
當OrderStatus
相同或增加..
OrderStatus Explanation
-------------------------
0 Creation
1 Checking
2 Placement
3 Execution
...
8 Settlement
表結構:
CREATE TABLE Orders(
OrderID INT IDENTITY,
Ticker VARCHAR(20) NOT NULL,
Size DECIMAL(31,15) NULL,
Price DECIMAL(31,15) NULL,
OrderStatus TINYINT NOT NULL)
而且,假設我們有以下數據,以便我們可以測試修改數據:
SET IDENTITY_INSERT [dbo].[Orders] ON
INSERT INTO [dbo].[Orders] ([OrderID], [Ticker], [Size], [Price], [OrderStatus])
VALUES (1, N'MSFT', CAST(1 AS Decimal(31, 15)), NULL, 0)
,(2, N'GOOG', CAST(2 AS Decimal(31, 15)), CAST(523 AS Decimal(31, 15)), 5)
,(3, N'AAPL', CAST(1 AS Decimal(31, 15)), NULL, 0)
SET IDENTITY_INSERT [dbo].[Orders] OFF
您應該具有以下數據:
OrderID Ticker Size Price OrderStatus
-----------------------------------------------
1 MSFT 1.000 NULL 0
2 GOOG 2.000 523.000 5
3 AAPL 1.000 NULL 0
現在的有趣的部分。這是我盡力設計可以處理NULL插入(即允許用戶撤消一個條目)的組合程序。請注意,我需要一個輸入參數來區分NULL的輸入值是否是有意的,並且需要將該值寫入表中,而將NULL作爲缺少的輸入參數顯示。希望這很清楚爲什麼我問這個問題,因爲我發現我的技術非常冗長。
CREATE PROCEDURE [dbo].[Upsert_Orders] @isNullInsert BIT = 0
,@OrderID INT = NULL
,@Ticker VARCHAR(20) = NULL
,@Size VARCHAR(100) = NULL
,@Price VARCHAR(100) = NULL
,@OrderStatus TINYINT = NULL
AS
BEGIN
IF (@OrderID IS NOT NULL)
-- First check if @OrderID exists
IF (
SELECT OrderID
FROM dbo.Orders
WHERE OrderID = @OrderID
) IS NULL
BEGIN
-- @OrderID does not exist therefore replace with NULL
SET @OrderID = NULL
PRINT 'spUO. Replaced OrderID ' + CAST(@OrderID AS VARCHAR) + ' input parameter with NULL.'
END
IF @OrderID IS NULL
BEGIN
-- @OrderID IS NULL so INSERT a new record
PRINT 'spUO Inserting a new record into the Orders'
INSERT INTO Orders (
-- OrderID not needed as IDENTITY new record.
Ticker
,Size
,Price
,OrderStatus
)
VALUES (
-- @OrderID not needed as IDENTITY new record
@Ticker
,@Size
,@Price
,@OrderStatus
)
END
ELSE
BEGIN
-- @OrderID IS NOT NULL therefore UPDATE the record @OrderID
PRINT 'spUO Modifying existing record with OrderID ' + CAST(@OrderID AS VARCHAR)
-- Declare CurrentVariables for @OrderID
DECLARE -- @CurrentOrderID INT not needed as @OrderID Found
@CurrentTicker VARCHAR(20)
,@CurrentSize DECIMAL(31, 15)
,@CurrentPrice DECIMAL(31, 15)
,@CurrentOrderStatus TINYINT
-- Populate Current Variables from Table Orders
SELECT -- @CurrentOrderID = OrderID not needed as @OrderID Found
@CurrentTicker = Ticker
,@CurrentSize = Size
,@CurrentPrice = Price
,@CurrentOrderStatus = OrderStatus
FROM Orders
WHERE OrderID = @OrderID
IF ISNULL(@OrderStatus, @CurrentOrderStatus) >= @CurrentOrderStatus
BEGIN
-- Update @OrderID if not moving backwards
IF @isNullInsert = 0
BEGIN
-- We are not updating the record with NULL
PRINT 'spUO NULL Parameter Input Values get replaced with the existing entries'
UPDATE Orders
SET -- OrderID = ISNULL(@OrderID, @CurrentOrderID) not needed as @OrderID Found
Ticker = ISNULL(@Ticker, @CurrentTicker)
,Size = ISNULL(@Size, @CurrentSize)
,Price = ISNULL(@Price, @CurrentPrice)
,OrderStatus = ISNULL(@OrderStatus, @CurrentOrderStatus)
WHERE OrderID = @OrderID
END
ELSE
BEGIN
-- We are potentially overwritting the record with NULL
PRINT 'spUO Old entries may be overwritten with NULL'
UPDATE Orders
SET -- OrderID = ISNULL(@OrderID, @CurrentOrderID) not needed as @OrderID Found
Ticker = @Ticker
,Size = @Size
,Price = @Price
,OrderStatus = @OrderStatus
WHERE OrderID = @OrderID
END
END
ELSE
-- User is trying to re-write hostory. Do Nothing
PRINT 'spUO You do not have permissions to roll back the OrderStatus.'
END
END
現在,我們有一個UPSERT程序,讓我來舉例說明它的用法:
步驟1:插入一個新行,顯示有意向購買一些福特的股票:
EXEC dbo.Upsert_Orders @Ticker = 'F',
@Size = 1,
@Price = 10,
@OrderStatus = 2
步驟2:讓我們看看OrderStatus
不能回捲
EXEC dbo.Upsert_Orders @OrderID = 4,
@Ticker = 'F',
@Size = 1,
@Price = 10,
@OrderStatus = 1
這產生了des紅外發光二極管輸出:
spUO Modifying existing record with OrderID 4
spUO You do not have permissions to roll back the OrderStatus.
的數據現在看起來像:
OrderID Ticker Size Price OrderStatus
-----------------------------------------------
1 MSFT 1.000 NULL 0
2 GOOG 2.000 523.000 5
3 AAPL 1.000 NULL 0
4 F 1.000 10.000 2
步驟3:最後,讓我們假設用戶想要刪除一階的股份,然後在我的程序不幸的方法需要其他默認參數將被傳遞並且需要將@isNULLInsert BIT
設置爲1。
EXEC dbo.Upsert_Orders @isNullInsert = 1,
@OrderID = 1,
@Ticker = 'MSFT',
@Size = NULL,
@Price = NULL,
@OrderStatus = 0
希望這個完整的例子示出了在添加新記錄,更新現有記錄和刪除記錄的一個字段中的概念。對這篇文章的長度抱歉,但這是我能夠製作的最簡潔的代碼!
最終數據:
OrderID Ticker Size Price OrderStatus
------------------------------------------------
1 MSFT NULL NULL 0
2 GOOG 2.000 523.000 5
3 AAPL 1.000 NULL 0
4 F 1.000 10.000 2
感謝所有,
伯蒂。
p.s.這將從Excel VBA調用。
多個用戶會一次調用嗎? – Laurence
愚蠢的問題:你爲什麼不只是刪除你想「撤消」的行?爲什麼所有這些複雜的在現有行中插入NULL值?看起來過於複雜和不必要...... –
訂單的生命週期是這樣的,訂單有很多步驟(即OrderStatus),通常跨越多天。在大公司中,許多人可以參與執行訂單以達成和解(因此鎖定可能是一個問題)。在我讀過的幾本書中,人們主張編寫存儲過程來執行INSERT和UPDATE操作。此外,財務作爲受監管的行業意味着我已經將商業/投訴邏輯編入程序(即不能改變歷史交易)。另外,當真正需要執行UPDATE時,我不喜歡過度使用DEL和INS。謝謝 – Bertie