我們都知道,在紫金橋軟件中可以通過腳本或報表來訪問關系庫系統(tǒng)。我們通常的訪問方式大概如下(以報表訪問關系庫為例):
- 建立報表關系數(shù)據(jù)源點,配置關系數(shù)據(jù)源點連接的數(shù)據(jù)庫用戶名和密碼等屬性。
- 繪制報表,在報表的關系數(shù)據(jù)庫連接中指明第一步建立的報表關系數(shù)據(jù)源點。
- 在報表上寫對關系庫操作的命令,比如SELECT命令。
- 在報表中對關系庫返回的結果進行處理,最簡單的是報表自動顯示結果。
這里第3步的SELECT命令中可以訪問SQL中的表或視圖。另外也可以使用存儲過程,比如:
#R.SqlExeCmdNoRet("EXEC DOTRANCDATA");
這里的EXEC DOTRANCDATA表示執(zhí)行DOTRANCDATA這個存儲過程。
下面我們通過一個簡單的例子來說明一下存儲過程的用法。
比如我們需要做一個產(chǎn)品出入庫的項目,產(chǎn)品在某一個地方通過驅(qū)動或條碼設備自動進行入庫操作,當數(shù)據(jù)進入關系庫之后,可以通過關系庫的各種統(tǒng)計分析查詢功能來對產(chǎn)品進行統(tǒng)計和檢索,由于需要在多個地方進行檢索,所以SQL數(shù)據(jù)庫放在遠端網(wǎng)絡的一個服務器上。
但是這里存在這么一個問題,由于網(wǎng)絡有可能會偶爾出現(xiàn)故障,雖然在故障情況下暫時不能查詢是可以理解的,但是我們不能允許在網(wǎng)絡出現(xiàn)故障的情況下,產(chǎn)品不能入庫。
這種問題可以這么解決,在本地關系庫中建立一個緩沖表,數(shù)據(jù)先插入本地的緩沖表中,然后通過存儲過程,把本地的緩沖表中的數(shù)據(jù)移動到遠端的產(chǎn)品庫中。在本地的任何檢索和查詢都是針對的遠端的產(chǎn)品庫來進行。這樣當網(wǎng)絡中斷的時候,數(shù)據(jù)就可以先緩沖到本地,此時產(chǎn)品的入庫工作仍然可以順利的進行,只不過本地的數(shù)據(jù)無法自動的移動到遠端,此時在遠端的數(shù)據(jù)庫中是無法檢索到這些入庫的產(chǎn)品的。當網(wǎng)絡恢復之后,由存儲過程自動的把數(shù)據(jù)移動到遠端數(shù)據(jù)庫中,此時在遠端數(shù)據(jù)庫中就可以檢索到這些產(chǎn)品了。
下面我們舉一個簡單的例子,為了簡化說明我們的兩個表都在本地數(shù)據(jù)庫中,首先數(shù)據(jù)插入其中的一個表中,然后在使用存儲過程移動到另外一個表。對于跨數(shù)據(jù)庫的表,處理方式一樣,只需要稍微做些調(diào)整就行了。
首先我們在SQL中建立兩個表,名為“測試數(shù)據(jù)源”和“測試目標”,如下圖所示:

在測試數(shù)據(jù)源和測試目標中建立結構相同的兩個數(shù)據(jù)表,如下圖所示:

這里是一個簡單的人員入庫表,表明為User,有三個字段,第一個是自動增長的ID,第二個是人名,第三個年齡。
我們在紫金橋中創(chuàng)建一個關系數(shù)據(jù)源點,讓該點連接“測試數(shù)據(jù)源”數(shù)據(jù)庫,如下圖所示:

在紫金橋中創(chuàng)建一個窗口,并且創(chuàng)建一個報表,給報表關聯(lián)剛剛建立的報表關系數(shù)據(jù)源點。
在報表上允許用戶輸入姓名和年齡,如下圖所示:

給姓名和年齡的輸入位置設置相應的輸入方式,給提交按鈕關聯(lián)如下的腳本:
SqlExeCmdNoRet("INSERT INTO [User](Name, [Year]) VALUES ('"+Txt(1,1)+"', "+Txt(2,1)+")");
即可把人員姓名和年齡插入數(shù)據(jù)庫中。
下面我們通過存儲過程來把數(shù)據(jù)從“測試數(shù)據(jù)源”庫移動到“測試目標”庫中。
在“測試數(shù)據(jù)源”庫中創(chuàng)建一個存儲過程,如下圖所示:

點擊確定即可創(chuàng)建存儲過程。
打開SQL查詢分析器,選中相應的存儲過程,右鍵菜單選擇編輯功能,如下圖所示:

在此處輸入如下的代碼:
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS OFF
GO
ALTERPROCEDURE MoveDataAS
DECLARE @strVARCHAR(1000)
DECLARE @SqlstrVARCHAR(1000)
SET @str = ''
SELECT @str=@str+','+syscolumns.[name] FROM syscolumns WHERE syscolumns.id=object_id('User') and syscolumns.[name]<>'ID'
SET @str = stuff(@str,1,1,'')
SET @str = 'INSERT INTO 測試目標.dbo.[User](' + @str + ') SELECT ' + @str + ' FROM 測試數(shù)據(jù)源.dbo.[User]'
DECLARE Ptr CURSOR
FOR
SELECT ID FROM 測試數(shù)據(jù)源.dbo.[User]
OPEN Ptr
DECLARE @ID INT
FETCH NEXT FROM Ptr INTO @ID
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
SET @Sqlstr = @str + ' WHERE ID=' + CONVERT(varchar, @ID)
EXEC(@Sqlstr)
DELETE FROM 測試數(shù)據(jù)源.dbo.[User] WHERE ID = @ID
END
FETCH NEXT FROM Ptr INTO @ID
END
CLOSE Ptr
DEALLOCATE Ptr
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
其中前面和后面5行代碼,是固定的,功能主要是更改存儲過程的內(nèi)容。
中間的內(nèi)容是移動數(shù)據(jù),這里我們不能簡單的這樣寫:
INSERT INTO 測試目標.dbo.[User] SELECT * FROM 測試數(shù)據(jù)源.dbo.[User]
因為,兩個表中都有自動增長的字段ID,如果復制所有的內(nèi)容,也會導致復制ID字段的內(nèi)容,而這會打亂系統(tǒng)自動增長的規(guī)律,可能會導致執(zhí)行失敗。
DECLARE @strVARCHAR(1000)
DECLARE @SqlstrVARCHAR(1000)
SET @str = ''
SELECT @str=@str+','+syscolumns.[name] FROM syscolumns WHERE syscolumns.id=object_id('User') and syscolumns.[name]<>'ID'
SET @str = stuff(@str,1,1,'')
這一段代碼,查詢User表中的所有名稱不為ID的字段的名稱,并用逗號分隔。
SET @str = stuff(@str,1,1,'')
這一句代碼的功能是去除開始的逗號。
SET @str = 'INSERT INTO 測試目標.dbo.[User](' + @str + ') SELECT ' + @str + ' FROM 測試數(shù)據(jù)源.dbo.[User]'
這一句代碼生成復制數(shù)據(jù)的命令。
DECLARE Ptr CURSOR
FOR
SELECT ID FROM 測試數(shù)據(jù)源.dbo.[User]
OPEN Ptr
DECLARE @ID INT
FETCH NEXT FROM Ptr INTO @ID
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
SET @Sqlstr = @str + ' WHERE ID=' + CONVERT(varchar, @ID)
EXEC(@Sqlstr)
DELETE FROM 測試數(shù)據(jù)源.dbo.[User] WHERE ID = @ID
END
FETCH NEXT FROM Ptr INTO @ID
END
CLOSE Ptr
DEALLOCATE Ptr
這一段代碼,使用了多個游標,逐行的復制數(shù)據(jù)和刪除數(shù)據(jù),以實現(xiàn)移動數(shù)據(jù)的目的。
這里之所以采取一行一行的移動數(shù)據(jù),主要是為了防止,在移動數(shù)據(jù)的過程中,又有了新的人員入庫,插入了新的記錄。一行一行的移動可以使得復制數(shù)據(jù)和刪除數(shù)據(jù)可以一一對應。
最后可以把此存儲過程放到作業(yè)中,使得它可以被周期運行,就可以實現(xiàn)自動的數(shù)據(jù)移動了。
|