❶ 在寫sql語句的時候最常犯的錯誤有哪些
.......................
1、多寫空格,『,』等特殊符號
2、因個人思路問題造成的語法錯誤或者因使用不同的庫,因各庫間有差異導致的語法錯誤
3、欄位名,表名寫錯
暫時也就想這些,,,這個出錯的可能很多,開始養成良好的習慣就好,,,
❷ SQL資料庫問題
1. 查看資料庫的版本
select @@version
2.查看資料庫所在機器操作系統參數
exec master..xp_msver
3. 查看資料庫啟動的參數
sp_configure
4.查看資料庫啟動時間
select convert(varchar(30),login_time,120) from master..sysprocesses where spid=1
查看資料庫伺服器名和實例名
print ''Server Name...............: '' + convert(varchar(30),@@SERVERNAME)
print ''Instance..................: '' + convert(varchar(30),@@SERVICENAME)
5. 查看所有資料庫名稱及大小
sp_helpdb
重命名資料庫用的SQL
sp_renamedb ''old_dbname'', ''new_dbname''
❸ sql安裝時會經常碰到哪些問題
問題1:如果安裝文件或安裝目錄有中文名稱,就會提示幫助文件安裝錯信息
問題2:如果之前有程序需要重啟而沒有重啟,會提示有程序掛起,需要重啟,重啟完才能安裝的情況,不過一般重啟完還是不能安裝,需要直接刪除注冊表中的值,網上搜索"SQL 掛起",就有詳細說明和解決方法
問題3:安裝的時候如果你不是域用戶,就不要在安裝過程中選域用戶(安裝程序默認是域用戶)
問題4:記得打sp4補丁,否則會出現程序莫名的連不上資料庫的情況,微軟的補丁執行的時候好像安裝了,實質他只是一個壓縮問題,會解壓到c盤的sql2ksp4的文件夾中,需要進去再執行setup.bat才是真正執行補丁程序
問題5:如果你的電腦中已安裝其他版本的SQL,安裝2000的時候不能用默認的實例名,需要新增一個實例名,否則2000會和其他版本沖突
問題6:不同版本的SQL對操作系統有要求的,例如企業版不能安裝在xp下
問題7:網上一些SQL的安裝程序是經過破解序列號的,所以會被某些殺毒軟體誤報,並清除了破解程序,導致SQL的安裝程序運行了,但一直沒有反應
問題8:一時間想不到了,你出現安裝不到的時候再問吧
❹ SQL的問題
說明:復製表(只復制結構,源表名:a 新表名:b)
SQL: select * into b from a where 1<>1
說明:拷貝表(拷貝數據,源表名:a 目標表名:b)
SQL: insert into b(a, b, c) select d,e,f from b;
說明:顯示文章、提交人和最後回復時間
SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
說明:外連接查詢(表名1:a 表名2:b)
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
說明:日程安排提前五分鍾提醒
SQL: select * from 日程安排 where datediff('minute',f開始時間,getdate())>5
說明:兩張關聯表,刪除主表中已經在副表中沒有的信息
SQL:
delete from info where not exists ( select * from infobz where info.infid=infobz.infid )
說明:--
SQL:
SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE
FROM TABLE1,
(SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE
FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND
FROM TABLE2
WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X,
(SELECT NUM, UPD_DATE, STOCK_ONHAND
FROM TABLE2
WHERE TO_CHAR(UPD_DATE,'YYYY/MM') =
TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, 'YYYY/MM') ¦¦ '/01','YYYY/MM/DD') - 1, 'YYYY/MM') ) Y,
WHERE X.NUM = Y.NUM (+)
AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <> X.STOCK_ONHAND ) B
WHERE A.NUM = B.NUM
說明:--
SQL:
select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and 系名稱='"&strdepartmentname&"' and 專業名稱='"&strprofessionname&"' order by 性別,生源地,高考總成績
說明:
從資料庫中去一年的各單位電話費統計(電話費定額賀電化肥清單兩個表來源)
SQL:
SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') AS telyear,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '01', a.factration)) AS JAN,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV,
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC
FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration
FROM TELFEESTAND a, TELFEE b
WHERE a.tel = b.telfax) a
GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy')
說明:四表聯查問題:
SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
說明:得到表中最小的未使用的ID號
SQL:
SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID
FROM Handle
WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a)
掌握SQL四條最基本的數據操作語句:Insert,Select,Update和Delete。
練掌握SQL是資料庫用戶的寶貴財 富。在本文中,我們將引導你掌握四條最基本的數據操作語句—SQL的核心功能—來依次介紹比較操作符、選擇斷言以及三值邏輯。當你完成這些學習後,顯然你已經開始算是精通SQL了。
在我們開始之前,先使用CREATE TABLE語句來創建一個表(如圖1所示)。DDL語句對資料庫對象如表、列和視進行定義。它們並不對表中的行進行處理,這是因為DDL語句並不處理資料庫中實際的數據。這些工作由另一類SQL語句—數據操作語言(DML)語句進行處理。
SQL中有四種基本的DML操作:INSERT,SELECT,UPDATE和DELETE。由於這是大多數SQL用戶經常用到的,我們有必要在此對它們進行一一說明。在圖1中我們給出了一個名為EMPLOYEES的表。其中的每一行對應一個特定的雇員記錄。請熟悉這張表,我們在後面的例子中將要用到它。
INSERT語句
用戶可以用INSERT語句將一行記錄插入到指定的一個表中。例如,要將雇員John Smith的記錄插入到本例的表中,可以使用如下語句:
INSERT INTO EMPLOYEES VALUES
('Smith','John','1980-06-10',
'Los Angles',16,45000);
通過這樣的INSERT語句,系統將試著將這些值填入到相應的列中。這些列按照我們創建表時定義的順序排列。在本例中,第一個值「Smith」將填到第一個列LAST_NAME中;第二個值「John」將填到第二列FIRST_NAME中……以此類推。
我們說過系統會「試著」將值填入,除了執行規則之外它還要進行類型檢查。如果類型不符(如將一個字元串填入到類型為數字的列中),系統將拒絕這一次操作並返回一個錯誤信息。
如果SQL拒絕了你所填入的一列值,語句中其他各列的值也不會填入。這是因為SQL提供對事務的支持。一次事務將資料庫從一種一致性轉移到另一種一致性。如果事務的某一部分失敗,則整個事務都會失敗,系統將會被恢復(或稱之為回退)到此事務之前的狀態。
回到原來的INSERT的例子,請注意所有的整形十進制數都不需要用單引號引起來,而字元串和日期類型的值都要用單引號來區別。為了增加可讀性而在數字間插入逗號將會引起錯誤。記住,在SQL中逗號是元素的分隔符。
同樣要注意輸入文字值時要使用單引號。雙引號用來封裝限界標識符。
對於日期類型,我們必須使用SQL標准日期格式(yyyy-mm-dd),但是在系統中可以進行定義,以接受其他的格式。當然,2000年臨近,請你最好還是使用四位來表示年份。
既然你已經理解了INSERT語句是怎樣工作的了,讓我們轉到EMPLOYEES表中的其他部分:
INSERT INTO EMPLOYEES VALUES
('Bunyan','Paul','1970-07-04',
'Boston',12,70000);
INSERT INTO EMPLOYEES VALUES
('John','Adams','1992-01-21',
'Boston',20,100000);
INSERT INTO EMPLOYEES VALUES
('Smith','Pocahontas','1976-04-06',
'Los Angles',12,100000);
INSERT INTO EMPLOYEES VALUES
('Smith','Bessie','1940-05-02',
'Boston',5,200000);
INSERT INTO EMPLOYEES VALUES
('Jones','Davy','1970-10-10',
'Boston',8,45000);
INSERT INTO EMPLOYEES VALUES
('Jones','Indiana','1992-02-01',
'Chicago',NULL,NULL);
在最後一項中,我們不知道Jones先生的工薪級別和年薪,所以我們輸入NULL(不要引號)。NULL是SQL中的一種特殊情況,我們以後將進行詳細的討論。現在我們只需認為NULL表示一種未知的值。
有時,像我們剛才所討論的情況,我們可能希望對某一些而不是全部的列進行賦值。除了對要省略的列輸入NULL外,還可以採用另外一種INSERT語句,如下:
INSERT INTO EMPLOYEES(
FIRST_NAME, LAST_NAME,
HIRE_DATE, BRANCH_OFFICE)
VALUE(
'Indiana','Jones',
'1992-02-01','Indianapolis');
這樣,我們先在表名之後列出一系列列名。未列出的列中將自動填入預設值,如果沒有設置預設值則填入NULL。請注意我們改變了列的順序,而值的順序要對應新的列的順序。如果該語句中省略了FIRST_NAME和LAST_NAME項(這兩項規定不能為空),SQL操作將失敗。
讓我們來看一看上述INSERT語句的語法圖:
INSERT INTO table
[(column { ,column})]
VALUES
(columnvalue [{,columnvalue}]);
和前一篇文章中一樣,我們用方括弧來表示可選項,大括弧表示可以重復任意次數的項(不能在實際的SQL語句中使用這些特殊字元)。VALUE子句和可選的列名列表中必須使用圓括弧。
SELECT語句
SELECT語句可以從一個或多個表中選取特定的行和列。因為查詢和檢索數據是資料庫管理中最重要的功能,所以SELECT語句在SQL中是工作量最大的部分。實際上,僅僅是訪問資料庫來分析數據並生成報表的人可以對其他SQL語句一竅不通。
SELECT語句的結果通常是生成另外一個表。在執行過程中系統根據用戶的標准從資料庫中選出匹配的行和列,並將結果放到臨時的表中。在直接SQL(direct SQL)中,它將結果顯示在終端的顯示屏上,或者將結果送到列印機或文件中。也可以結合其他SQL語句來將結果放到一個已知名稱的表中。
SELECT語句功能強大。雖然表面上看來它只用來完成本文第一部分中提到的關系代數運算「選擇」(或稱「限制」),但實際上它也可以完成其他兩種關系運算—「投影」和「連接」,SELECT語句還可以完成聚合計算並對數據進行排序。
SELECT語句最簡單的語法如下:
SELECT columns FROM tables;
當我們以這種形式執行一條SELECT語句時,系統返回由所選擇的列以及用戶選擇的表中所有指定的行組成的一個結果表。這就是實現關系投影運算的一個形式。
讓我們看一下使用圖1中EMPLOYEES表的一些例子(這個表是我們以後所有SELECT語句實例都要使用的。而我們在圖2和圖3中給出了查詢的實際結果。我們將在其他的例子中使用這些結果)。
假設你想查看雇員工作部門的列表。那下面就是你所需要編寫的SQL查詢:
SELECT BRANCH_OFFICE FROM EMPLOYEES;
以上SELECT語句的執行將產生如圖2中表2所示的結果。
由於我們在SELECT語句中只指定了一個列,所以我們的結果表中也只有一個列。注意結果表中具有重復的行,這是因為有多個雇員在同一部門工作(記住SQL從所選的所有行中將值返回)。要消除結果中的重復行,只要在SELECT語句中加上DISTINCT子句:
SELECT DISTINCT BRANCH_OFFICE
FROM EMPLOYEES;
這次查詢的結果如表3所示。
現在已經消除了重復的行,但結果並不是按照順序排列的。如果你希望以字母表順序將結果列出又該怎麼做呢?只要使用ORDER BY子句就可以按照升序或降序來排列結果:
SELECT DISTINCT BRANCH_OFFICE
FROM EMPLOYEES
ORDER BY BRANCH_OFFICE ASC;
這一查詢的結果如表4所示。請注意在ORDER BY之後是如何放置列名BRANCH _OFFICE的,這就是我們想要對其進行排序的列。為什麼即使是結果表中只有一個列時我們也必須指出列名呢?這是因為我們還能夠按照表中其他列進行排序,即使它們並不顯示出來。列名BRANCH_ OFFICE之後的關鍵字ASC表示按照升序排列。如果你希望以降序排列,那麼可以用關鍵字DESC。
同樣我們應該指出ORDER BY子句只將臨時表中的結果進行排序;並不影響原來的表。
假設我們希望得到按部門排序並從工資最高的雇員到工資最低的雇員排列的列表。除了工資括弧中的內容,我們還希望看到按照聘用時間從最近聘用的雇員開始列出的列表。以下是你將要用到的語句:
SELECT BRANCH_OFFICE,FIRST_NAME,
LAST_NAME,SALARY,HIRE_DATE
FROM EMPLOYEES
ORDER BY SALARY DESC,
HIRE_DATE DESC;
這里我們進行了多列的選擇和排序。排序的優先順序由語句中的列名順序所決定。SQL將先對列出的第一個列進行排序。如果在第一個列中出現了重復的行時,這些行將被按照第二列進行排序,如果在第二列中又出現了重復的行時,這些行又將被按照第三列進行排序……如此類推。這次查詢的結果如表5所示。
將一個很長的表中的所有列名寫出來是一件相當麻煩的事,所以SQL允許在選擇表中所有的列時使用*號:
SELECT * FROM EMPLOYEES;
這次查詢返回整個EMPLOYEES表,如表1所示。
下面我們對開始時給出的SELECT語句的語法進行一下更新(豎直線表示一個可選項,允許在其中選擇一項。):
SELECT [DISTINCT]
(column [{, columns}])| *
FROM table [ {, table}]
[ORDER BY column [ASC] | DESC
[ {, column [ASC] | DESC }]];
定義選擇標准
在我們目前所介紹的SELECT語句中,我們對結果表中的列作出了選擇但返回的是表中所有的行。讓我們看一下如何對SELECT語句進行限制使得它只返回希望得到的行:
SELECT columns FROM tables [WHERE predicates];
WHERE子句對條件進行了設置,只有滿足條件的行才被包括到結果表中。這些條件由斷言(predicate)進行指定(斷言指出了關於某件事情的一種可能的事實)。如果該斷言對於某個給定的行成立,該行將被包括到結果表中,否則該行被忽略。在SQL語句中斷言通常通過比較來表示。例如,假如你需要查詢所有姓為Jones的職員,則可以使用以下SELECT語句:
SELECT * FROM EMPLOYEES
WHERE LAST_NAME = 'Jones';
LAST_NAME = 'Jones'部分就是斷言。在執行該語句時,SQL將每一行的LAST_NAME列與「Jones」進行比較。如果某一職員的姓為「Jones」,即斷言成立,該職員的信息將被包括到結果表中(見表6)。
使用最多的六種比較
我們上例中的斷言包括一種基於「等值」的比較(LAST_NAME = 'Jones'),但是SQL斷言還可以包含其他幾種類型的比較。其中最常用的為:
等於 =
不等於 <>
小於 <
大於 >
小於或等於 <=
大於或等於 >=
下面給出了不是基於等值比較的一個例子:
SELECT * FROM EMPLOYEES
WHERE SALARY > 50000;
這一查詢將返回年薪高於$50,000.00的職員(參見表7)。
邏輯連接符
有時我們需要定義一條不止一種斷言的SELECT語句。舉例來說,如果你僅僅想查看Davy Jones的信息的話,表6中的結果將是不正確的。為了進一步定義一個WHERE子句,用戶可以使用邏輯連接符AND,OR和NOT。為了只得到職員Davy Jones的記錄,用戶可以輸入如下語句:
SELECT * FROM EMPLOYEES
WHERE LAST_NAME = 'Jones' AND FIRST_NAME = 'Davy';
在本例中,我們通過邏輯連接符AND將兩個斷言連接起來。只有兩個斷言都滿足時整個表達式才會滿足。如果用戶需要定義一個SELECT語句來使得當其中任何一項成立就滿足條件時,可以使用OR連接符:
SELECT * FROM EMPLOYEES
WHERE LAST_NAME = 'Jones' OR LAST_NAME = 'Smith';
有時定義一個斷言的最好方法是通過相反的描述來說明。如果你想要查看除了Boston辦事處的職員以外的其他所有職員的信息時,你可以進行如下的查詢:
SELECT * FROM EMPLOYEES
WHERE NOT(BRANCH_OFFICE = 'Boston');
關鍵字NOT後面跟著用圓括弧括起來的比較表達式。其結果是對結果取否定。如果某一職員所在部門的辦事處在Boston,括弧內的表達式返回true,但是NOT操作符將該值取反,所以該行將不被選中。
斷言可以與其他的斷言嵌套使用。為了保證它們以正確的順序進行求值,可以用括弧將它們括起來:
SELECT * FROM EMPLOYEES
WHERE (LAST_NAME = 'Jones'
AND FIRST_NAME = 'Indiana')
OR (LAST_NAME = 'Smith'
AND FIRST_NAME = 'Bessie');
SQL沿用數學上標準的表達式求值的約定—圓括弧內的表達式將最先進行求值,其他表達式將從左到右進行求值。
以上對邏輯連接符進行了說明,在對下面的內容進行說明之前,我們再一次對SELECT語句的語法進行更新:
SELECT [DISTINCT]
(column [{, column } ] )| *
FROM table [ { , table} ]
[ORDER BY column [ASC] | [DESC
[{ , column [ASC] | [DESC } ] ]
WHERE predicate [ { logical-connector predicate } ];
NULL和三值邏輯
在SQL中NULL是一個復雜的話題,關於NULL的詳細描述更適合於在SQL的高級教程而不是現在的入門教程中進行介紹。但由於NULL需要進行特殊處理,並且你也很可能會遇到它,所以我們還是簡略地進行一下說明。
首先,在斷言中進行NULL判斷時需要特殊的語法。例如,如果用戶需要顯示所有年薪未知的職員的全部信息,用戶可以使用如下SELECT語句:
SELECT * FROM EMPLOYEES
WHERE SALARY IS NULL;
相反,如果用戶需要所有已知年薪數據的職員的信息,你可以使用以下語句:
SELECT * FROM EMPLOYEES
WHERE SALARY IS NOT NULL;
請注意我們在列名之後使用了關鍵字IS NULL或IS NOT NULL,而不是標準的比較形式:COLUMN = NULL、COLUMN <> NULL或是邏輯操作符NOT(NULL)。
這種形式相當簡單。但當你不明確地測試NULL(而它們確實存在)時,事情會變得很混亂。
例如,回過頭來看我們圖1中的EM-PLOYEES表,可以看到Indiana Jones的工薪等級或年薪值都是未知的。這兩個列都包含NULL。可以想像運行如下的查詢:
SELECT * FROM EMPLOYEES
WHERE GRADE <= SALARY;
此時,Indiana Jones應該出現在結果表中。因為NULL都是相等的,所以可以想像它們是能夠通過GRADE小於等於SALARY的檢查的。這其實是一個毫無疑義的查詢,但是並沒有關系。SQL允許進行這樣的比較,只要兩個列都是數字類型的。然而,Indiana Jones並沒有出現在查詢的結果中,為什麼?
正如我們早先提到過的,NULL表示未知的值(而不是象某些人所想像的那樣表示一個為NULL的值)。對於SQL來說意味著這個值是未知的,而只要這個值為未知,就不能將其與其他值比較(即使其他值也是NULL)。所以SQL允許除了在true 和false之外還有第三種類型的真值,稱之為「非確定」(unknown)值。
如果比較的兩邊都是NULL,整個斷言就被認為是非確定的。將一個非確定斷言取反或使用AND或OR與其他斷言進行合並之後,其結果仍是非確定的。由於結果表中只包括斷言值為「真」的行,所以NULL不可能滿足該檢查。從而需要使用特殊的操作符IS NULL和IS NOT NULL。
UPDATE語句
UPDATE語句允許用戶在已知的表中對現有的行進行修改。
例如,我們剛剛發現Indiana Jones的等級為16,工資為$40,000.00,我們可以通過下面的SQL語句對資料庫進行更新(並清除那些煩人的NULL)。
UPDATE EMPLOYEES
SET GRADE = 16, SALARY = 40000
WHERE FIRST_NAME = 'Indiana'
AND LAST_NAME = 'Jones';
上面的例子說明了一個單行更新,但是UPDATE語句可以對多行進行操作。滿足WHERE條件的所有行都將被更新。如果,你想讓Boston辦事處中的所有職員搬到New York,你可以使用如下語句:
UPDATE EMPLOYEES
SET BRANCH_OFFICE = 'New York'
WHERE BRANCH_OFFICE = 'Boston';
如果忽略WHERE子句,表中所有行中的部門值都將被更新為'New York'。
UPDATE語句的語法流圖如下面所示:
UPDATE table
SET column = value [{, column = value}]
[ WHERE predicate [ { logical-connector predicate}]];
DELETE語句
DELETE語句用來刪除已知表中的行。如同UPDATE語句中一樣,所有滿足WHERE子句中條件的行都將被刪除。由於SQL中沒有UNDO語句或是「你確認刪除嗎?」之類的警告,在執行這條語句時千萬要小心。如果決定取消Los Angeles辦事處並解僱辦事處的所有職員,這一卑鄙的工作可以由以下這條語句來實現:
DELETE FROM EMPLOYEES
WHERE BRANCH_OFFICE = 'Los Angeles';
如同UPDATE語句中一樣,省略WHERE子句將使得操作施加到表中所有的行。
DELETE語句的語法流圖如下面所示:
DELETE FROM table
[WHERE predicate [ { logical-connector predicate} ] ];
現在我們完成了數據操作語言(DML)的主要語句的介紹。我們並沒有對SQL能完成的所有功能進行說明。SQL還提供了許多的功能,如求平均值、求和以及其他對表中數據的計算,此外SQL還能完成從多個表中進行查詢(多表查詢,或稱之為連接)的工作。這種語言還允許你使用GRANT和REVOKE命令控制使用者的數據訪問許可權。
Visual C++中實現對圖像數據的讀取顯示
2003-12-9加入 來自yesky 作者劉 濤 4條評論 點擊3030次
在利用VC進行資料庫編程時,經常需要處理資料庫中的圖像數據,將該圖像從資料庫中讀取出來並顯示,圖像數據與文本欄位不同,它是作為OLE欄位在資料庫中存儲,通過數據集對象的成員變數自動交換得到的圖像數據,得到的數據並不能直接顯示,如何處理圖像數據,一直是資料庫編程中的一個難點,目前關於VC進行資料庫編程的資料不少,但很少涉及圖像數據的操作,筆者針對一現狀,結合自己開發的一個項目,解決了如何顯示資料庫中的圖像這一問題,本文以操作ACESS資料庫為例子,講解一下自己的實現思路,希望對愛好VC編程的朋友們有所幫助,以起到拋磚引玉的作用。
為了簡化問題,該資料庫的表中只有一個名為Images的OLE欄位,我使用DAO連接操作資料庫,讀取的圖像數據顯示在一個對話框上,至於使用ODBC、DAO還是ADO,這要根據具體情況而定,但無論使用哪一種,對圖像的顯示來說,實現的過程是大同小異的。由於篇幅有限,文章中對如何實現資料庫的連接不再作具體的說明,有興趣的讀者朋友可以參考VC資料庫編程的資料。實現過程中,首先定義一個CDaoRecordset的子類 CimageData如下:
class CimageData : public CDaoRecordset
{
public:
CimageData (CDaoDatabase* pDatabase = NULL);
DECLARE_DYNAMIC(CimageData)
file://{{AFX_FIELD(CimageData, CDaoRecordset)
CByteArray m_Images;//聲明位元組數組用來存放圖像數據
file://}}AFX_FIELD
// Overrides
// ClassWizard generated virtual function overrides
file://{{AFX_VIRTUAL(CimageData)
public:
virtual CString GetDefaultDBName();
virtual CString GetDefaultSQL();
virtual void DoFieldExchange(CDaoFieldExchange* pFX);
file://}}AFX_VIRTUAL
該類的實現為:
CimageData:: CimageData (CDaoDatabase* pdb)
: CDaoRecordset(pdb)
{
file://{{AFX_FIELD_INIT(CimageData)
m_nFields = 1;//資料庫的表中僅有一個欄位
file://}}AFX_FIELD_INIT
m_nDefaultType = dbOpenDynaset;//以動態集方式打開資料庫
}
CString CimageData::GetDefaultDBName()
{
return _T("E:\\IMAGES.mdb");//默認的ACESS資料庫在E盤,名為IMAGES
}
CString CimageData::GetDefaultSQL()
{
return _T("[Table]");//默認打開資料庫中名為"Table"的表
}
void CimageData::DoFieldExchange(CDaoFieldExchange* pFX)
{
file://{{AFX_FIELD_MAP(CimageData)
pFX->SetFieldType(CDaoFieldExchange::outputColumn);
DFX_Binary(pFX, _T("[Images]"), m_Images);//以二進制方式在Images欄位和m_Images變數間交換數據
file://}}AFX_FIELD_MAP
}
有了該類,就可以定義相應的對象來與資料庫中的圖像欄位交換數據,下面定義的函數GetImageData()說明了如何根據讀取的OLE欄位數據生成待顯示的圖像,需要注意的是該函數中使用的CBitmap類的變數Bitmap是預定義的一個全局變數:
BOOL CImageDlg:: GetImageData(CByteArray & DBArray)
{
CByteArray Array;
Array.Copy( DBArray);
int HeaderLen = 78 + sizeof(BITMAPFILEHEADER); file://確定圖像頭信息的起始位置
Array.RemoveAt( 0, HeaderLen ); // 移動到圖像頭信息的起始位置
BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)Array.GetData() ;
BITMAPINFO &bmInfo = *(LPBITMAPINFO)Array.GetData() ;
file://得到圖像數據的頭信息
int nColors=bmiHeader.biClrUsed ? bmiHeader.biClrUsed : 1 << bmiHeader.biBitCount;
file://確定圖像的顏色數
LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits=(LPVOID)((LPDWORD)(bmInfo.bmiColors+bmInfo.bmiHeader.biClrUsed)+
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
file://得到圖像各個像素的具體數據
CClientDC dc(NULL);
HBITMAP hBmp = CreateDIBitmap( dc.m_hDC,
&bmiHeader,
CBM_INIT,
❺ SQL Server中常見的問題與解決方法
關於事務日誌
在使用sql server時,經常會出現系統提示事務日誌
已滿的錯誤信息(錯誤1105),以使的應用系統的資料庫
無法打開,影響到系統的正常運行。通常有三種方法可以
解決這一問題:
●擴展資料庫空間
可以通過擴展資料庫大小來增大事務日誌的空間。先
利用alter database增大資料庫空間,再通過sp—logdev
ice系統存儲過程把事務日誌轉移到事務日誌資料庫設備
上去,具體語法如下:
語法:
·alter database database—name on database—d
evice』增大資料庫空間
·sp—logdevice dbname,database_device』轉移
事務日誌
例:alterdatabasemydbonmydb—log—dev=8
sp—logdevicemydbmydb—log—dev
如果資料庫對資料庫設備變得過大(通常在決定數據
庫大小時,先指定一個保守的值,如果以後需要增大空間
,用alter database增加其大小),需先擴展資料庫設備
,再增大事務日誌的空間,具體語法如下:
語法:
·disk resize name=logical—device_name,size=
final—size』擴展資料庫設備
·alter database database—name on database—d
evice』增大資料庫空間
·sp_logdevicedbname,database_device』轉移事
務日誌
例:disk resize name=mydb on mydb—log—dev=8
alter database mydb on mydb—log—dev=8
sp—logdevice mydb mydb—log—dev
(以上工作也可以通過對microsoft sql enterprise
manger提供的gui界面直接操作來完成。)
●定期執行mp database語句來完成截短
事務日誌。其語法為:
語法:
·mp database dbname to mp_device
例:mp databas emydb to mymp—dev(通過將
資料庫mydb備份到備份設備mymp—dev上完成截短事務日
志。)
●trunc.logonchkpt.選項來完成截短事
務日誌
預設時,在新建的資料庫上,trunc.logonchkpt.
選項設置成off(預設值),事務日誌永遠不作備份,事務
日誌不停地增長,可能會耗盡資料庫的存儲空間,將trun
c.logonchkpt.選項設置成on,每次checkpoint進程發
生時(通常每分鍾一次)都截短事務日誌(刪除已提交的
事務),使得事務日誌不會不停地增長以耗盡資料庫的存
儲空間。
配置選項和值
在使用sql server時,同樣會經常出現系統提示user
connections(用戶連接)已達到配置數,系統無法正常
運行的問題。sql server用戶連接最大值是32767,而缺
省時的一般配置數為15個。如果使用中的用戶連接已達到
配置數,而又來了一個用戶連接請求,sqlserver將回送一
個錯誤消息。這時可以通過修改sql server的配置選項中
的user connections項的最大值來解決這一問題。配置選
項的顯示和管理可通過sp—configure系統過程來完成,
但不能使用sp—configure來設定一個比當前配置選項最大
值還大的配置選項。
語法:sp—configure〔『config—name』〔,confi
g—value〕〕
其中config—name為配置選項的項名,config—valu
e為設置值。
例:sp—configure『user_connections』,30
同時用戶可以使用sp—configure來顯示配置選項,
通過重新設置一些配置選項,調節性能和優化存儲分配。
(註:修改sql server的配置選項,必須以系統管理員身
份登錄。)?
❻ sql常見問題
begin
select getdate()
select year(getdate())
select day(getdate())
end
go
year,day 要參數的
❼ 關於SQL的問題
不同的操作系統SQL2000的安裝有一定的前提,安裝它是須要一些軟體的支持,有的就是系統的補丁,下面說說安裝他的一些軟體須求:
SQL Server 2000的軟體要求
1. SQL Server 2000的某些功能要求必須在Windows 2000 Server(任何版本)下才可以使用。
2. 另外,在Microsoft Windows NT Server 4.0上,必須安裝Service Pack 5(SP5)或更高版本,這是SQL Server 2000所有版本的最低要求。
3. SQL Server 2000中文版不支持英文版的Windows NT 4.0企業版。
4. 如果在不帶網卡的Windows 98計算機上安裝SQL Server 2000個人版,需要Windows 98第二版。
SQL Server 2000的網路要求
1. 操作系統必須安裝Microsoft Internet Explorer 5.0以上瀏覽器。
2. 安裝 SQL Server 2000 之前,必須在操作系統級啟用 TCP/IP。
如果以上要求你達到了,還是不行,請看下文,或許能對你起著一定的啟發。
先把SQL Server卸載,再把安裝時產生的「Microsoft SQL Server」文件夾刪掉,在運行注冊表,把HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server,和HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server全部刪掉,(注意要把Microsoft SQL Server文件夾整個刪掉),然後重起。 再裝就應該沒有問題了!
Windows 2000 裝不上 SQL Server 2000 問題很常見。常見為:
(1)配置伺服器時中斷
(2)注冊ActiveX 時中斷
(3)顯示到100%的時候中斷
當然重新安裝 Windows 2000 完全可以安裝 SQL Server 2000。為了安全起見,你先要:
1. 先備份您的注冊表
2. 備份您的數據[進不了SQL Server 2000,可以備份 Program Files\Microsoft SQL Server\MSSQL\Data 文件夾的文件
您必須知道:Windows 2000 Server 可以安裝SQL Server 2000的任何版本,Windows 2000 Professional 僅可以安裝SQL Server 2000的個人版。
有兩種辦法:
1. 先卸載您的SQL Server 2000,必要的時候刪除Program Files\Microsoft SQL Server 文件夾
2. 放入 SQL Server 2000 光碟
3. 在"開始"--"運行"鍵入 "F:\x86\setup.exe k=dbg" (F是光碟) (此命令的意思單步運行安裝 SQL Server 2000)
4. 98%安裝不成功,沒有任何的提示。可能是:
(1)配置伺服器時中斷
(2)注冊 ActiveX 時中斷
(3)顯示到100%的時候中斷
這樣一來,您只能使用下面的辦法了!否則,您只有FORMAT了!
1. 打開注冊表 在"開始"--"運行"鍵入 "regedit"
2. 按下列順序點擊打開 + HKEY_LOCAL_MACHINE + SOFTWART + Microsoft + Windows + CurrentVersion + Setup + ExceptionComponents
3. 將 ExceptionComponents 下面的文件夾全部刪除! 如 {60BFF50D-FB2C-4498-A577-C9548C390BB9} {60BFF50D-FB2C-4498-A577-C9548C390BB9} {60BFF50D-FB2C-4498-A577-C9548C390BB9} {60BFF50D-FB2C-4498-A577-C9548C390BB9} .......
4. 重新啟動
5. 重新安裝 SQL Server 2000
注冊表中查找並刪除所有的MS SQL Server選項;刪除SQL安裝生成的目錄;將SQL安裝文件復制到硬碟上,以保證所有的安裝文件都能被正常讀取(排除安裝文件的問題) ,然後重新啟動操作系統,再重新安裝。如果問題依舊,試試先修復操作系統。命令提示符下執行:sfc /scannow, 然後按上面的方法重新安裝一次。 如果還不行,放入win2000安裝光碟,安裝操作系統,安裝的時候選擇修復。完成後,再按第一樓的方法重試安裝。 如果還是不行,重新安裝操作系統。如果還是不行,檢查硬體,特別檢查磁碟分區有沒有壞區。另外一個很另類的問題是,有個網友安裝了N次不成功,換個電源就行了。
如果每次都是安裝到MDAC失敗,那你就嘗試先安裝MDAC(Microsoft Data Access Components)。
❽ 常用SQL語句問題
--1
select課號,課程名,學分+1as修正學分from課程
--2
selectdistinct學分from課程
--3
selectmax(b.成績)as成績from學生a,選課bwherea.學號=b.學號anda.所在系='計算機系'
--4
select學號,姓名from學生where學號in(selecta.學號from選課a,課程bwherea.課號=b.課號andb.課程名='操作系統')
--5
deletefrom學生where學號=95001
--6
select學分,count(*)as課程數from課程
❾ SQL中的問題
1. 檢查約束
檢查約束是最常見的約束類型。它允許你聲明在某個欄位里的數值必須使一個布爾表達式為真。比如,要強制一個正數的產品價格,你可以用:
CREATE TABLE procts ( proct_no integer, name text, price numeric CHECK (price > 0) );
如你所見,約束定義在數據類型之後,就好像預設值定義一樣。預設值和約束可以按任意順序排列。一個檢查約束由一個關鍵字 CHECK 後面跟一個放在圓括弧里的表達式組成。檢查約束表達式應該包含受約束的欄位,否則這個約束就沒什麼意義了。
你還可以給這個約束取一個獨立的名字。這樣就可以令錯誤信息更清晰,並且在你需要修改它的時候引用這個名字。語法是:
CREATE TABLE procts ( proct_no integer, name text, price numeric CONSTRAINT positive_price CHECK (price > 0) );
因此,要聲明一個命名約束,使用關鍵字 CONSTRAINT 後面跟一個標識符(作為名字),然後再跟約束定義。如果你不用這個方法聲明約束,那麼系統會自動為你選擇一個名字。
一個檢查約束也可以引用多個欄位。假設你存儲一個正常價格和一個折扣價,並且你想保證折扣價比正常價低。
CREATE TABLE procts ( proct_no integer, name text, price numeric CHECK (price > 0), discounted_price numeric CHECK (discounted_price > 0), CHECK (price > discounted_price) );
頭兩個約束看上去很面熟。第三個使用了一個新的語法。它沒有附著在某個欄位上,而是在逗號分隔的欄位列表中以一個獨立行的形式出現。欄位定義和約束定義可以按照任意順序列出。
我們稱頭兩個約束是"欄位約束",而第三個約束是"表約束"(和欄位定義分開寫)。欄位約束也可以寫成表約束,而反過來很可能不行,因為系統假設欄位約束只引用它所從屬的欄位。PostgreSQL 並不強制這條規則,但是如果你希望自己的表定義可以和其它資料庫系統兼容,那麼你最好還是遵循這條規則。上面的例子也可以這么寫:
CREATE TABLE procts ( proct_no integer, name text, price numeric, CHECK (price > 0), discounted_price numeric, CHECK (discounted_price > 0), CHECK (price > discounted_price) ); 或者是
CREATE TABLE procts ( proct_no integer, name text, price numeric CHECK (price > 0), discounted_price numeric, CHECK (discounted_price > 0 AND price > discounted_price) );
這只是風格的不同。
和欄位約束一樣,我們也可以給表約束賦予名稱,方法也相同:
CREATE TABLE procts ( proct_no integer, name text, price numeric, CHECK (price > 0), discounted_price numeric, CHECK (discounted_price > 0), CONSTRAINT valid_discount CHECK (price > discounted_price) );
我們還要注意的是,當約束表達式計算結果為 NULL 的時候,檢查約束會被認為是滿足條件的。因為大多數表達式在含有 NULL 操作數的時候結果都是 NULL ,所以這些約束不能阻止欄位值為 NULL 。要確保一個欄位值不為 NULL ,可以使用下一節介紹的非空約束。
2. 非空約束
非空約束只是簡單地聲明一個欄位必須不能是 NULL 。下面是一個例子:
CREATE TABLE procts ( proct_no integer NOT NULL, name text NOT NULL, price numeric );
一個非空約束總是寫成一個欄位約束。非空約束在功能上等效於創建一個檢查約束 CHECK (column_name IS NOT NULL) ,但在 PostgreSQL 里,創建一個明確的非空約束效率更高。缺點是你不能給它一個明確的名字。
當然,一個欄位可以有多個約束。只要一個接著一個寫就可以了:
CREATE TABLE procts ( proct_no integer NOT NULL, name text NOT NULL, price numeric NOT NULL CHECK (price > 0) );
它們的順序無所謂。順序並不影響約束檢查的順序。
NOT NULL 約束有個相反的約束:NULL 約束。它並不意味著該欄位必須是空,因為這樣的欄位也沒用。它只是定義了該欄位可以為空的這個預設行為。在 SQL 標准里沒有定義 NULL 約束,因此不應該在可移植的應用中使用它。在 PostgreSQL 裡面增加這個約束只是為了和其它資料庫系統兼容。不過,有些用戶喜歡它,因為這個約束可以讓他們很容易在腳本文件里切換約束。比如,你可以從下面這樣開始
CREATE TABLE procts ( proct_no integer NULL, name text NULL, price numeric NULL );
然後在需要的時候插入 NOT 關鍵字。
【提示】在大多數資料庫設計里,主要的欄位都應該標記為非空。
3. 唯一約束
唯一約束保證在一個欄位或者一組欄位里的數據與表中其它行的數據相比是唯一的。它的語法是:
CREATE TABLE procts ( proct_no integer UNIQUE, name text, price numeric );
上面是寫成欄位約束,下面這個則寫成表約束:
CREATE TABLE procts ( proct_no integer, name text, price numeric, UNIQUE (proct_no) );
如果一個唯一約束引用一組欄位,那麼這些欄位用逗號分隔列出:
CREATE TABLE example ( a integer, b integer, c integer, UNIQUE (a, c) );
這樣就聲明了特定欄位值的組合在整個表范圍內是唯一的。但是這些欄位中的某個單獨值可以不必是(並且通常也確實不是)唯一的。
你也可以給唯一約束賦予一個自己定義的名字,方法與前面相同:
CREATE TABLE procts ( proct_no integer CONSTRAINT must_be_different UNIQUE, name text, price numeric );
通常,如果包含在唯一約束中的那幾個欄位在表中有多個相同的行,就違反了唯一約束。但是在這種比較中,NULL 被認為是不相等的。這就意味著,在多欄位唯一約束的情況下,如果在至少一個欄位上出現 NULL ,那麼我們還是可以存儲同樣的這種數據行。這種行為遵循 SQL 標准,但是我們聽說其它 SQL 資料庫可能不遵循這個標准。因此如果你要開發可移植的程序,那麼最好仔細些。
4. 主鍵
從技術上講,主鍵約束只是唯一約束和非空約束的組合。所以,下面兩個表定義是等價的:
CREATE TABLE procts ( proct_no integer UNIQUE NOT NULL, name text, price numeric ); CREATE TABLE procts ( proct_no integer PRIMARY KEY, name text, price numeric );
主鍵也可以約束多於一個欄位;其語法類似於唯一約束:
CREATE TABLE example ( a integer, b integer, c integer, PRIMARY KEY (a, c) );
主鍵表示一個或多個欄位的組合可以用於唯一標識表中的數據行。這是定義一個主鍵的直接結果。請注意:一個唯一約束實際上並不能提供一個唯一標識,因為它不排除 NULL 。這個功能對文檔目的和客戶應用都很有用。比如,一個可以修改行數值的 GUI 應用可能需要知道一個表的主鍵才能唯一地標識每一行。
一個表最多可以有一個主鍵(但是它可以有多個唯一和非空約束)。關系型資料庫理論告訴我們,每個表都必須有一個主鍵。PostgreSQL 並不強制這個規則,但我們最好還是遵循它。
5. 外鍵
外鍵約束聲明一個欄位(或者一組欄位)的數值必須匹配另外一個表中出現的數值。我們把這個行為稱為兩個相關表之間的參照完整性。
假設你有個產品表,我們可能使用了好幾次:
CREATE TABLE procts ( proct_no integer PRIMARY KEY, name text, price numeric );
假設你有一個存儲這些產品的訂單的表。我們想保證訂單表只包含實際存在的產品。因此我們在訂單表中定義一個外鍵約束引用產品表:
CREATE TABLE orders ( order_id integer PRIMARY KEY, proct_no integer REFERENCES procts (proct_no), quantity integer );
現在,我們不能創建任何其 proct_no 沒有在產品表中出現的訂單。
在這種情況下我們把訂單表叫做引用表,而產品表叫做被引用表。同樣,也有引用欄位和被引用欄位。
你也可以把上面的命令簡寫成
CREATE TABLE orders ( order_id integer PRIMARY KEY, proct_no integer REFERENCES procts, quantity integer );
因為如果缺少欄位列表的話,就會引用被引用表的主鍵。
一個外鍵也可以約束和引用一組欄位。同樣,也需要寫成表約束的形式。下面是一個捏造出來的語法例子:
CREATE TABLE t1 ( a integer PRIMARY KEY, b integer, c integer, FOREIGN KEY (b, c) REFERENCES other_table (c1, c2) );
當然,被約束的欄位數目和類型需要和被引用欄位數目和類型一致。
和平常一樣,你也可以給外鍵約束賦予自定義的名字。
一個表可以包含多於一個外鍵約束。這個特性用於實現表之間的多對多關系。比如你有關於產品和訂單的表,但現在你想允許一個訂單可以包含多種產品(上面那個結構是不允許這么做的),你可以使用這樣的結構:
CREATE TABLE procts ( proct_no integer PRIMARY KEY, name text, price numeric ); CREATE TABLE orders ( order_id integer PRIMARY KEY, shipping_address text, ... ); CREATE TABLE order_items ( proct_no integer REFERENCES procts, order_id integer REFERENCES orders, quantity integer, PRIMARY KEY (proct_no, order_id) );
注意最後的表的主鍵和外鍵是重疊的。
我們知道外鍵不允許創建和任何產品都無關的訂單。但是如果一個訂單創建之後其引用的產品被刪除了怎麼辦?SQL 也允許你處理這個問題。簡單說,我們有幾種選擇:
不允許刪除一個被引用的產品
同時也刪除訂單
其它的?
為了說明這個問題,我們對上面的多對多關系制定下面的策略:如果有人想刪除一種仍然被某個訂單引用的產品(通過 order_items),那麼就不允許這么做。如果有人刪除了一個訂單,那麼訂單項也被刪除。
CREATE TABLE procts ( proct_no integer PRIMARY KEY, name text, price numeric ); CREATE TABLE orders ( order_id integer PRIMARY KEY, shipping_address text, ... ); CREATE TABLE order_items ( proct_no integer REFERENCES procts ON DELETE RESTRICT, order_id integer REFERENCES orders ON DELETE CASCADE, quantity integer, PRIMARY KEY (proct_no, order_id) );
限制和級聯刪除是兩種最常見的選項。RESTRICT 禁止刪除被引用的行。NO ACTION 的意思是如果在檢查約束的時候還存在任何引用行,則拋出錯誤;如果你不聲明任何東西,那麼它就是預設的行為。這兩個選擇的實際區別是:NO ACTION 允許約束檢查推遲到事務的晚些時候,而 RESTRICT 不行。CASCADE 聲明在刪除一個被引用的行的時候,所有引用它的行也會被自動刪除掉。在外鍵欄位上的動作還有兩個選項:SET NULL 和 SET DEFAULT ,它們導致在被引用行刪除的時候,將引用它們的欄位分別設置為 NULL 和預設值。請注意這些選項並不能讓你逃脫被觀察和約束的境地。比如,如果一個動作聲明 SET DEFAULT ,但是預設值並不能滿足外鍵,那麼該動作就會失敗。
與 ON DELETE 類似的還有 ON UPDATE 選項,它是在被引用欄位修改(更新)的時候調用的,可用的動作是一樣的。
有關更新和刪除數據的更多信息可以在章6里找到。
最後,我們應該說明的是,一個外鍵必須要麼引用一個主鍵,要麼引用一個唯一約束。如果外鍵引用了一個唯一約束,那麼在如何匹配 NULL 這個問題上還有一些其它的可能性。這些東西都在 CREATE TABLE 中解釋。
❿ sql運行問題
sql運行問題?
資料庫運行過程中常見的故障有3類:事物故障、系統故障、介質故障。
恢復策略:
1、事物故障:
發生事務故障時,被迫中斷的事務可能已對資料庫進行丁修改,為了消除該事務對資料庫的影響,要利用日誌文件中所記載的信息,強行回滾該事務,將資料庫恢復到修改前的初始狀態。
為此,要檢查日誌文件中由這些事務所引起的發生變化的記錄,取消這些沒有完成的事務所做的一切改變,這類恢復操作稱為事務撤銷。
2、系統故障:
系統故障的恢復要完成兩方面的工作,既要撤銷所有末完成的事務,還要重做所有已提交的事務,這樣才能將資料庫真正恢復到一致的狀態。
3、介質故障:
介質故障比事務故障和系統故障發生的可能性要小,但這是最嚴重的一種故障,破壞性很大,磁碟上的物理數據和日誌文件可能被破壞,這需要裝入發生介質故障前最新的後備資料庫副本,然後利用日誌文件重做該副本後所運行的所有事務。
「數據故障恢復」和「完整性約束」、「並發控制」一樣,都是資料庫數據保護機制中的一種完整性控制。所有的系統都免不了會發生故障,有可能是硬體失靈,有可能是軟體系統崩潰,也有可能是其他外界的原因,比如斷電等等。
資料庫運行的突然中斷會使資料庫處在一個錯誤的狀態,而且故障排除後沒有辦法讓系統精確地從斷點繼續執行下去。這就要求DBMS要有一套故障後的數據恢復機構,保證資料庫能夠回復到一致的、正確地狀態去。