從文件導(dǎo)入:
load data infile 'e:\custom.txt' replace into table custom;
load data infile 'e:\custom.txt' replace into table custom fields terminated by ',' optionally enclosed by '"';
從庫中其他表導(dǎo)入:
insert into tablename1 select * from tablename2;
///////////// 導(dǎo)入導(dǎo)出給定列 ///////////
load data infile 'e:\custom.txt' replace into table custom fields terminated by ',' optionally enclosed by
'"'(customid,name,sex);
select customid,name,sex from custom into outfile 'e:\acustom.txt' fields terminated by ',' optionally enclosed
by '"';
////////////////////////
MYSQL的主鍵是放主存的,第一次的時(shí)候執(zhí)行max獲取最大編號,如果插入的時(shí)候沒有就自增,如果插入的時(shí)候指定了主鍵,則判
斷是否大于max,是則設(shè)置主鍵為max,并插入記錄,否則替換或出錯(cuò);如果自增主鍵為null,則仍是自增;
所以導(dǎo)入的時(shí)候,自增主鍵也可以直接導(dǎo)入;
如果導(dǎo)入的時(shí)候出現(xiàn):truncated字樣,則是SQL_MODE問題,修改sql_mode就可以了;
show variables like '%sql_mode%';
set sql_mode='no_auto_create_user,no_engine_substitution';
如出現(xiàn)錯(cuò)誤:ERROR 1262 (01000): Row 6737 was truncated; it contained more data than there were input columns.
如:文件中出現(xiàn),,空字符,正常情況下會(huì)出錯(cuò),需要修改sql_mode后才能導(dǎo)入(會(huì)有正常警告);
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
import com.sunyard.lmas.Base;
public abstract class ExpreCountAmt extends Base {
private ArrayList<String> middle = new ArrayList<String>();// 存儲(chǔ)中序表達(dá)式
private ArrayList<String> right = new ArrayList<String>();// 存儲(chǔ)右序表達(dá)式
protected String getExpression(){
return middle.toString();
}
protected String getRight(){
return right.toString();
}
/**
* 獲取中序表達(dá)式
*/
private void setMiddle(String expression)throws Exception{
middle.clear();
right.clear();
expression = expression==null ? "" : expression.trim();
if(expression.length()>0&&Calculate.isOperator(expression.substring(0,1))){
middle.add("0");
}
StringTokenizer st = new StringTokenizer(expression, "+-*/()%", true);
while (st.hasMoreElements()) {
String item = st.nextToken();
if(Calculate.isOperator(item))
// if(item.endsWith("+")||item.endsWith("-")||item.endsWith("*")||item.endsWith("/")||item.endsWith("(")||item.endsWith(")")||item.endsWith("%"))
middle.add(item);
else
middle.add(getAmt(item).toString());
}
}
/**
* 將中序表達(dá)式轉(zhuǎn)換為右序表達(dá)式
*/
private void toRight() {
if(middle.size()<=0)
return;
Stacks aStack = new Stacks();
String operator;
int position = 0;
while (true) {
if (Calculate.isOperator((String) middle.get(position))) {
if (aStack.top == -1
|| ((String) middle.get(position)).equals("(")) {
aStack.push(middle.get(position));
} else {
if (((String) middle.get(position)).equals(")")) {
if (!((String) aStack.top()).equals("(")) {
operator = (String) aStack.pop();
right.add(operator);
}
} else {
if (Calculate.priority((String) middle
.get(position)) <= Calculate
.priority((String) aStack.top())
&& aStack.top != -1) {
operator = (String) aStack.pop();
if (!operator.equals("("))
right.add(operator);
}
aStack.push(middle.get(position));
}
}
} else
right.add(middle.get(position));
position++;
if (position >= middle.size())
break;
}
while (aStack.top != -1) {
operator = (String) aStack.pop();
right.add(operator);
}
}
/**
* 獲取結(jié)果
* @return
*/
private double getResult(){
if(right.size()==0)
return 0.0;
String result;
Stacks aStack = new Stacks();
String op1, op2, is = null;
Iterator<String> it = right.iterator();
while (it.hasNext()) {
is = (String) it.next();
if (Calculate.isOperator(is)) {
op1 = (String) aStack.pop();
op2 = (String) aStack.pop();
aStack.push(Calculate.twoResult(is, op1, op2));
} else
aStack.push(is);
}
result = (String) aStack.pop();
return Double.parseDouble(result);
}
public final double getCountAmt(String expression)throws Exception{
setMiddle(expression);
toRight();
return getResult();
}
public abstract Double getAmt(String subjectno)throws Exception;
}
應(yīng)用報(bào)文摘要方法,得到單向的加密字符串
//MD5是16位,SHA是20位(這是兩種報(bào)文摘要的算法)
//MessageDigest md= MessageDigest.getInstance("MD5");
MessageDigest messageDigest=MessageDigest.getInstance("SHA-1");
messageDigest.update(originalPwd.getBytes());
//String digestedPwdString = new String(messageDigest.digest());
String digestedPwdString = new String(Base64.encode(messageDigest.digest()));
System.out.println("pwd:" + digestedPwdString);
這樣,就得到密碼的報(bào)文摘要,把此摘要保存到數(shù)據(jù)庫,
以后用戶登陸時(shí),用相同的算法算出摘要,和數(shù)據(jù)庫中的比較,如果一致,則密碼正確。
注意:
byte[] digest = messageDigest.digest();
得到的是個(gè)二進(jìn)制byte數(shù)組,有可能某些byte是不可打印的字符。
所以用Base64.encode把它轉(zhuǎn)化成可打印字符。
也可以把digest的每個(gè)byte轉(zhuǎn)化成hex(16進(jìn)制)保存。
MessageDigest messageDigest=MessageDigest.getInstance("SHA-1");
messageDigest.update(originalPwd.getBytes());
byte[] bin = messageDigest.digest();
再調(diào)用下面的方法生產(chǎn)hex(16進(jìn)制)保存。
二行制轉(zhuǎn)hex字符串的方法如下:
private static String byte2hex(byte[] b){
String hs="";
String stmp="";
for (int n=0; n<b.length; n++){
stmp=(java.lang.Integer.toHexString(b[n] & 0xFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
}
return hs;
}
或者:
private static String byto2hex2(byte[] bin){
StringBuffer buf = new StringBuffer();
for (int i = 0; i < bin.length; ++i) {
int x = bin[i] & 0xFF, h = x >>> 4, l = x & 0x0F;
buf.append((char) (h + ((h < 10) ? '0' : 'a' - 10)));
buf.append((char) (l + ((l < 10) ? '0' : 'a' - 10)));
}
return buf.toString();
}
或者:
干脆直接用下面的方法生成,用到第三方包:
public static String encryptPwd(String pwd, String algorithm){
//String a = org.apache.catalina.realm.RealmBase.Digest(pwd,"SHA-1");
return org.apache.catalina.realm.RealmBase.Digest(pwd, algorithm);
}
CREATE TRIGGER trigger_name
ON { table | view
}
[ WITH ENCRYPTION ]
{
{
{
FOR | AFTER | INSTEAD OF
} { [ INSERT ] [ , ] [ UPDATE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS
[ { IF UPDATE ( column )
[ { AND | OR } UPDATE ( column ) ]
[ ...n ]
| IF ( COLUMNS_UPDATED ( )
{ bitwise_operator
} updated_bitmask )
{ comparison_operator
} column_bitmask [ ...n ]
} ]
sql_statement [ ...n ]
}
}
trigger_name
是觸發(fā)器的名稱。觸發(fā)器名稱必須符合標(biāo)識符規(guī)則,并且在數(shù)據(jù)庫中必須唯一。可以選擇是否指定觸發(fā)器所有者名稱。
Table | view
是在其上執(zhí)行觸發(fā)器的表或視圖,有時(shí)稱為觸發(fā)器表或觸發(fā)器視圖。可以選擇是否指定表或視圖的所有者名稱。
WITH ENCRYPTION
加密 syscomments 表中包含 CREATE TRIGGER 語句文本的條目。使用 WITH ENCRYPTION 可防止將觸發(fā)器作為 SQL Server 復(fù)制的一部分發(fā)布。
AFTER
指定觸發(fā)器只有在觸發(fā) SQL 語句中指定的所有操作都已成功執(zhí)行后才激發(fā)。所有的引用級聯(lián)操作和約束檢查也必須成功完成后,才能執(zhí)行此觸發(fā)器。
如果僅指定 FOR 關(guān)鍵字,則 AFTER 是默認(rèn)設(shè)置。
不能在視圖上定義 AFTER 觸發(fā)器。
INSTEAD OF
指定執(zhí)行觸發(fā)器而不是執(zhí)行觸發(fā) SQL 語句,從而替代觸發(fā)語句的操作。
在表或視圖上,每個(gè) INSERT、UPDATE 或 DELETE 語句最多可以定義一個(gè) INSTEAD OF 觸發(fā)器。然而,可以在每個(gè)具有 INSTEAD OF 觸發(fā)器的視圖上定義視圖。
INSTEAD OF 觸發(fā)器不能在 WITH CHECK OPTION 的可更新視圖上定義。如果向指定了 WITH CHECK OPTION 選項(xiàng)的可更新視圖添加 INSTEAD OF 觸發(fā)器,SQL Server 將產(chǎn)生一個(gè)錯(cuò)誤。用戶必須用 ALTER VIEW 刪除該選項(xiàng)后才能定義 INSTEAD OF 觸發(fā)器。
{ [DELETE] [,] [INSERT] [,] [UPDATE] }
是指定在表或視圖上執(zhí)行哪些數(shù)據(jù)修改語句時(shí)將激活觸發(fā)器的關(guān)鍵字。必須至少指定一個(gè)選項(xiàng)。在觸發(fā)器定義中允許使用以任意順序組合的這些關(guān)鍵字。如果指定的選項(xiàng)多于一個(gè),需用逗號分隔這些選項(xiàng)。
對于 INSTEAD OF 觸發(fā)器,不允許在具有 ON DELETE 級聯(lián)操作引用關(guān)系的表上使用 DELETE 選項(xiàng)。同樣,也不允許在具有 ON UPDATE 級聯(lián)操作引用關(guān)系的表上使用 UPDATE 選項(xiàng)。
WITH APPEND
指定應(yīng)該添加現(xiàn)有類型的其它觸發(fā)器。只有當(dāng)兼容級別是 65 或更低時(shí),才需要使用該可選子句。如果兼容級別是 70 或更高,則不必使用 WITH APPEND 子句添加現(xiàn)有類型的其它觸發(fā)器(這是兼容級別設(shè)置為 70 或更高的 CREATE TRIGGER 的默認(rèn)行為)。有關(guān)更多信息,請參見 sp_dbcmptlevel。
WITH APPEND 不能與 INSTEAD OF 觸發(fā)器一起使用,或者,如果顯式聲明 AFTER 觸發(fā)器,也不能使用該子句。只有當(dāng)出于向后兼容而指定 FOR 時(shí)(沒有 INSTEAD OF 或 AFTER),才能使用 WITH APPEND。以后的版本將不支持 WITH APPEND 和 FOR(將被解釋為 AFTER)。
NOT FOR REPLICATION
表示當(dāng)復(fù)制進(jìn)程更改觸發(fā)器所涉及的表時(shí),不應(yīng)執(zhí)行該觸發(fā)器。
AS
是觸發(fā)器要執(zhí)行的操作。
sql_statement
是觸發(fā)器的條件和操作。觸發(fā)器條件指定其它準(zhǔn)則,以確定 DELETE、INSERT 或 UPDATE 語句是否導(dǎo)致執(zhí)行觸發(fā)器操作。
當(dāng)嘗試 DELETE、INSERT 或 UPDATE 操作時(shí),Transact-SQL語句中指定的觸發(fā)器操作將生效。
觸發(fā)器可以包含任意數(shù)量和種類的 Transact-SQL 語句。觸發(fā)器旨在根據(jù)數(shù)據(jù)修改語句檢查或更改數(shù)據(jù);它不應(yīng)將數(shù)據(jù)返回給用戶。觸發(fā)器中的 Transact-SQL 語句常常包含控制流語言。CREATE TRIGGER 語句中使用幾個(gè)特殊的表:
SELECT *
FROM deleted
當(dāng)兼容級別是 80 或更高時(shí),SQL Server 允許在表或視圖上通過 INSTEAD OF 觸發(fā)器更新 text、ntext 或 image 列。
n
是表示觸發(fā)器中可以包含多條 Transact-SQL 語句的占位符。對于 IF UPDATE (column) 語句,可以通過重復(fù) UPDATE (column) 子句包含多列。
IF UPDATE (column)
測試在指定的列上進(jìn)行的 INSERT 或 UPDATE 操作,不能用于 DELETE 操作。可以指定多列。因?yàn)樵?ON 子句中指定了表名,所以在 IF UPDATE 子句中的列名前不要包含表名。若要測試在多個(gè)列上進(jìn)行的 INSERT 或 UPDATE 操作,請?jiān)诘谝粋€(gè)操作后指定單獨(dú)的 UPDATE(column) 子句。在 INSERT 操作中 IF UPDATE 將返回 TRUE 值,因?yàn)檫@些列插入了顯式值或隱性 (NULL) 值。
說明 IF UPDATE (column) 子句的功能等同于 IF、IF...ELSE 或 WHILE 語句,并且可以使用 BEGIN...END 語句塊。有關(guān)更多信息,請參見控制流語言。
可以在觸發(fā)器主體中的任意位置使用 UPDATE (column)。
column
是要測試 INSERT 或 UPDATE 操作的列名。該列可以是 SQL Server 支持的任何數(shù)據(jù)類型。但是,計(jì)算列不能用于該環(huán)境中。有關(guān)更多信息,請參見數(shù)據(jù)類型。
IF (COLUMNS_UPDATED())
測試是否插入或更新了提及的列,僅用于 INSERT 或 UPDATE 觸發(fā)器中。COLUMNS_UPDATED 返回 varbinary 位模式,表示插入或更新了表中的哪些列。
COLUMNS_UPDATED 函數(shù)以從左到右的順序返回位,最左邊的為最不重要的位。最左邊的位表示表中的第一列;向右的下一位表示第二列,依此類推。如果在表上創(chuàng)建的觸發(fā)器包含 8 列以上,則 COLUMNS_UPDATED 返回多個(gè)字節(jié),最左邊的為最不重要的字節(jié)。在 INSERT 操作中 COLUMNS_UPDATED 將對所有列返回 TRUE 值,因?yàn)檫@些列插入了顯式值或隱性 (NULL) 值。
可以在觸發(fā)器主體中的任意位置使用 COLUMNS_UPDATED。
bitwise_operator
是用于比較運(yùn)算的位運(yùn)算符。
updated_bitmask
是整型位掩碼,表示實(shí)際更新或插入的列。例如,表 t1 包含列 C1、C2、C3、C4 和 C5。假定表 t1 上有 UPDATE 觸發(fā)器,若要檢查列 C2、C3 和 C4 是否都有更新,指定值 14;若要檢查是否只有列 C2 有更新,指定值 2。
comparison_operator
是比較運(yùn)算符。使用等號 (=) 檢查 updated_bitmask 中指定的所有列是否都實(shí)際進(jìn)行了更新。使用大于號 (>) 檢查 updated_bitmask 中指定的任一列或某些列是否已更新。
column_bitmask
是要檢查的列的整型位掩碼,用來檢查是否已更新或插入了這些列。
觸發(fā)器常常用于強(qiáng)制業(yè)務(wù)規(guī)則和數(shù)據(jù)完整性。SQL Server 通過表創(chuàng)建語句(ALTER TABLE 和 CREATE TABLE)提供聲明引用完整性 (DRI);但是 DRI 不提供數(shù)據(jù)庫間的引用完整性。若要強(qiáng)制引用完整性(有關(guān)表的主鍵和外鍵之間關(guān)系的規(guī)則),請使用主鍵和外鍵約束(ALTER TABLE 和 CREATE TABLE 的 PRIMARY KEY 和 FOREIGN KEY 關(guān)鍵字)。如果觸發(fā)器表存在約束,則在 INSTEAD OF 觸發(fā)器執(zhí)行之后和 AFTER 觸發(fā)器執(zhí)行之前檢查這些約束。如果違反了約束,則回滾 INSTEAD OF 觸發(fā)器操作且不執(zhí)行(激發(fā))AFTER 觸發(fā)器。
可用 sp_settriggerorder 指定表上第一個(gè)和最后一個(gè)執(zhí)行的 AFTER 觸發(fā)器。在表上只能為每個(gè) INSERT、UPDATE 和 DELETE 操作指定一個(gè)第一個(gè)執(zhí)行和一個(gè)最后一個(gè)執(zhí)行的 AFTER 觸發(fā)器。如果同一表上還有其它 AFTER 觸發(fā)器,則這些觸發(fā)器將以隨機(jī)順序執(zhí)行。
如果 ALTER TRIGGER 語句更改了第一個(gè)或最后一個(gè)觸發(fā)器,則將除去已修改觸發(fā)器上設(shè)置的第一個(gè)或最后一個(gè)特性,而且必須用 sp_settriggerorder 重置排序值。
只有當(dāng)觸發(fā) SQL 語句(包括所有與更新或刪除的對象關(guān)聯(lián)的引用級聯(lián)操作和約束檢查)成功執(zhí)行后,AFTER 觸發(fā)器才會(huì)執(zhí)行。AFTER 觸發(fā)器檢查觸發(fā)語句的運(yùn)行效果,以及所有由觸發(fā)語句引起的 UPDATE 和 DELETE 引用級聯(lián)操作的效果。
CREATE TRIGGER 必須是批處理中的第一條語句,并且只能應(yīng)用到一個(gè)表中。
觸發(fā)器只能在當(dāng)前的數(shù)據(jù)庫中創(chuàng)建,不過觸發(fā)器可以引用當(dāng)前數(shù)據(jù)庫的外部對象。
如果指定觸發(fā)器所有者名稱以限定觸發(fā)器,請以相同的方式限定表名。
在同一條 CREATE TRIGGER 語句中,可以為多種用戶操作(如 INSERT 和 UPDATE)定義相同的觸發(fā)器操作。
如果一個(gè)表的外鍵在 DELETE/UPDATE 操作上定義了級聯(lián),則不能在該表上定義 INSTEAD OF DELETE/UPDATE 觸發(fā)器。
在觸發(fā)器內(nèi)可以指定任意的 SET 語句。所選擇的 SET 選項(xiàng)在觸發(fā)器執(zhí)行期間有效,并在觸發(fā)器執(zhí)行完后恢復(fù)到以前的設(shè)置。
與使用存儲(chǔ)過程一樣,當(dāng)觸發(fā)器激發(fā)時(shí),將向調(diào)用應(yīng)用程序返回結(jié)果。若要避免由于觸發(fā)器激發(fā)而向應(yīng)用程序返回結(jié)果,請不要包含返回結(jié)果的 SELECT 語句,也不要包含在觸發(fā)器中進(jìn)行變量賦值的語句。包含向用戶返回結(jié)果的 SELECT 語句或進(jìn)行變量賦值的語句的觸發(fā)器需要特殊處理;這些返回的結(jié)果必須寫入允許修改觸發(fā)器表的每個(gè)應(yīng)用程序中。如果必須在觸發(fā)器中進(jìn)行變量賦值,則應(yīng)該在觸發(fā)器的開頭使用 SET NOCOUNT 語句以避免返回任何結(jié)果集。
DELETE 觸發(fā)器不能捕獲 TRUNCATE TABLE 語句。盡管 TRUNCATE TABLE 語句實(shí)際上是沒有 WHERE 子句的 DELETE(它刪除所有行),但它是無日志記錄的,因而不能執(zhí)行觸發(fā)器。因?yàn)?TRUNCATE TABLE 語句的權(quán)限默認(rèn)授予表所有者且不可轉(zhuǎn)讓,所以只有表所有者才需要考慮無意中用 TRUNCATE TABLE 語句規(guī)避 DELETE 觸發(fā)器的問題。
無論有日志記錄還是無日志記錄,WRITETEXT 語句都不激活觸發(fā)器。
觸發(fā)器中不允許以下 Transact-SQL 語句:
ALTER DATABASE | CREATE DATABASE | DISK INIT |
DISK RESIZE | DROP DATABASE | LOAD DATABASE |
LOAD LOG | RECONFIGURE | RESTORE DATABASE |
RESTORE LOG |
說明 由于 SQL Server 不支持系統(tǒng)表中的用戶定義觸發(fā)器,因此建議不要在系統(tǒng)表中創(chuàng)建用戶定義觸發(fā)器。
SQL Server 允許為每個(gè)數(shù)據(jù)修改事件(DELETE、INSERT 或 UPDATE)創(chuàng)建多個(gè)觸發(fā)器。例如,如果對已有 UPDATE 觸發(fā)器的表執(zhí)行 CREATE TRIGGER FOR UPDATE,則將創(chuàng)建另一個(gè)更新觸發(fā)器。在早期版本中,在每個(gè)表上,每個(gè)數(shù)據(jù)修改事件(INSERT、UPDATE 或 DELETE)只允許有一個(gè)觸發(fā)器。
說明 如果觸發(fā)器名稱不同,則 CREATE TRIGGER(兼容級別為 70)的默認(rèn)行為是在現(xiàn)有的觸發(fā)器中添加其它觸發(fā)器。如果觸發(fā)器名稱相同,則 SQL Server 返回一條錯(cuò)誤信息。但是,如果兼容級別等于或小于 65,則使用 CREATE TRIGGER 語句創(chuàng)建的新觸發(fā)器將替換同一類型的任何現(xiàn)有觸發(fā)器,即使觸發(fā)器名稱不同。有關(guān)更多信息,請參見 sp_dbcmptlevel。
當(dāng)在 sp_dboption 中啟用 recursive triggers 設(shè)置時(shí),SQL Server 還允許觸發(fā)器的遞歸調(diào)用。
遞歸觸發(fā)器允許發(fā)生兩種類型的遞歸:
使用間接遞歸時(shí),應(yīng)用程序更新表 T1,從而激發(fā)觸發(fā)器 TR1,該觸發(fā)器更新表 T2。在這種情況下,觸發(fā)器 T2 將激發(fā)并更新 T1。
使用直接遞歸時(shí),應(yīng)用程序更新表 T1,從而激發(fā)觸發(fā)器 TR1,該觸發(fā)器更新表 T1。由于表 T1 被更新,觸發(fā)器 TR1 再次激發(fā),依此類推。
下例既使用了間接觸發(fā)器遞歸,又使用了直接觸發(fā)器遞歸。假定在表 T1 中定義了兩個(gè)更新觸發(fā)器 TR1 和 TR2。觸發(fā)器 TR1 遞歸地更新表 T1。UPDATE 語句使 TR1 和 TR2 各執(zhí)行一次。而 TR1 的執(zhí)行將觸發(fā) TR1(遞歸)和 TR2 的執(zhí)行。給定觸發(fā)器的 inserted 和 deleted 表只包含與喚醒調(diào)用觸發(fā)器的 UPDATE 語句相對應(yīng)的行。
說明 只有啟用 sp_dboption 的 recursive triggers 設(shè)置,才會(huì)發(fā)生上述行為。對于為給定事件定義的多個(gè)觸發(fā)器,并沒有確定的執(zhí)行順序。每個(gè)觸發(fā)器都應(yīng)是自包含的。
禁用 recursive triggers 設(shè)置只能禁止直接遞歸。若要也禁用間接遞歸,請使用 sp_configure 將 nested triggers 服務(wù)器選項(xiàng)設(shè)置為 0。
如果任一觸發(fā)器執(zhí)行了 ROLLBACK TRANSACTION 語句,則無論嵌套級是多少,都不會(huì)進(jìn)一步執(zhí)行其它觸發(fā)器。
觸發(fā)器最多可以嵌套 32 層。如果一個(gè)觸發(fā)器更改了包含另一個(gè)觸發(fā)器的表,則第二個(gè)觸發(fā)器將激活,然后該觸發(fā)器可以再調(diào)用第三個(gè)觸發(fā)器,依此類推。如果鏈中任意一個(gè)觸發(fā)器引發(fā)了無限循環(huán),則會(huì)超出嵌套級限制,從而導(dǎo)致取消觸發(fā)器。若要禁用嵌套觸發(fā)器,請用 sp_configure 將 nested triggers 選項(xiàng)設(shè)置為 0(關(guān)閉)。默認(rèn)配置允許嵌套觸發(fā)器。如果嵌套觸發(fā)器是關(guān)閉的,則也將禁用遞歸觸發(fā)器,與 sp_dboption 的 recursive triggers 設(shè)置無關(guān)。
SQL Server 允許 Transact-SQL 存儲(chǔ)過程、觸發(fā)器和批處理引用編譯時(shí)不存在的表。這種能力稱為延遲名稱解析。但是,如果 Transact-SQL 存儲(chǔ)過程、觸發(fā)器或批處理引用在存儲(chǔ)過程或觸發(fā)器中定義的表,則只有當(dāng)兼容級別設(shè)置(通過執(zhí)行 sp_dbcmptlevel 設(shè)置)等于 65 時(shí),才會(huì)在創(chuàng)建時(shí)發(fā)出警告。如果使用批處理,則在編譯時(shí)發(fā)出警告。如果引用的表不存在,將在運(yùn)行時(shí)返回錯(cuò)誤信息。有關(guān)更多信息,請參見延遲名稱解析和編譯。
CREATE TRIGGER 權(quán)限默認(rèn)授予定義觸發(fā)器的表所有者、sysadmin 固定服務(wù)器角色成員以及 db_owner 和 db_ddladmin 固定數(shù)據(jù)庫角色成員,并且不可轉(zhuǎn)讓。
若要檢索表或視圖中的數(shù)據(jù),用戶必須在表或視圖中擁有 SELECT 語句權(quán)限。若要更新表或視圖的內(nèi)容,用戶必須在表或視圖中擁有 INSERT、DELETE 和 UPDATE 語句權(quán)限。
如果視圖中存在 INSTEAD OF 觸發(fā)器,用戶必須在該視圖中有 INSERT、DELETE 和 UPDATE 特權(quán),以對該視圖發(fā)出 INSERT、DELETE 和 UPDATE 語句,而不管實(shí)際上是否在視圖上執(zhí)行了這樣的操作。
當(dāng)有人試圖在 titles 表中添加或更改數(shù)據(jù)時(shí),下例將向客戶端顯示一條消息。
說明 消息 50009 是 sysmessages 中的用戶定義消息。有關(guān)創(chuàng)建用戶定義消息的更多信息,請參見 sp_addmessage。
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'reminder' AND type = 'TR')
DROP TRIGGER reminder
GO
CREATE TRIGGER reminder
ON titles
FOR INSERT, UPDATE
AS RAISERROR (50009, 16, 10)
GO
當(dāng) titles 表更改時(shí),下例將電子郵件發(fā)送給指定的人員 (MaryM)。
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'reminder' AND type = 'TR')
DROP TRIGGER reminder
GO
CREATE TRIGGER reminder
ON titles
FOR INSERT, UPDATE, DELETE
AS
EXEC master..xp_sendmail 'MaryM',
'Don''t forget to print a report for the distributors.'
GO
由于 CHECK 約束只能引用定義了列級或表級約束的列,表間的任何約束(在下例中是指業(yè)務(wù)規(guī)則)都必須定義為觸發(fā)器。
下例創(chuàng)建一個(gè)觸發(fā)器,當(dāng)插入或更新雇員工作級別 (job_lvls) 時(shí),該觸發(fā)器檢查指定雇員的工作級別(由此決定薪水)是否處于為該工作定義的范圍內(nèi)。若要獲得適當(dāng)?shù)姆秶仨氁?jobs 表。
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'employee_insupd' AND type = 'TR')
DROP TRIGGER employee_insupd
GO
CREATE TRIGGER employee_insupd
ON employee
FOR INSERT, UPDATE
AS
/* Get the range of level for this job type from the jobs table. */
DECLARE @min_lvl tinyint,
@max_lvl tinyint,
@emp_lvl tinyint,
@job_id smallint
SELECT @min_lvl = min_lvl,
@max_lvl = max_lvl,
@emp_lvl = i.job_lvl,
@job_id = i.job_id
FROM employee e INNER JOIN inserted i ON e.emp_id = i.emp_id
JOIN jobs j ON j.job_id = i.job_id
IF (@job_id = 1) and (@emp_lvl 10)
BEGIN
RAISERROR ('Job id 1 expects the default level of 10.', 16, 1)
ROLLBACK TRANSACTION
END
ELSE
IF NOT (@emp_lvl BETWEEN @min_lvl AND @max_lvl)
BEGIN
RAISERROR ('The level for job_id:%d should be between %d and %d.',
16, 1, @job_id, @min_lvl, @max_lvl)
ROLLBACK TRANSACTION
END
下例創(chuàng)建兩個(gè)觸發(fā)器以說明延遲名稱解析。
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'trig1' AND type = 'TR')
DROP TRIGGER trig1
GO
-- Creating a trigger on a nonexistent table.
CREATE TRIGGER trig1
on authors
FOR INSERT, UPDATE, DELETE
AS
SELECT a.au_lname, a.au_fname, x.info
FROM authors a INNER JOIN does_not_exist x
ON a.au_id = x.au_id
GO
-- Here is the statement to actually see the text of the trigger.
SELECT o.id, c.text
FROM sysobjects o INNER JOIN syscomments c
ON o.id = c.id
WHERE o.type = 'TR' and o.name = 'trig1'
-- Creating a trigger on an existing table, but with a nonexistent
-- column.
USE pubs
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'trig2' AND type = 'TR')
DROP TRIGGER trig2
GO
CREATE TRIGGER trig2
ON authors
FOR INSERT, UPDATE
AS
DECLARE @fax varchar(12)
SELECT @fax = phone
FROM authors
GO
-- Here is the statement to actually see the text of the trigger.
SELECT o.id, c.text
FROM sysobjects o INNER JOIN syscomments c
ON o.id = c.id
WHERE o.type = 'TR' and o.name = 'trig2'
下例創(chuàng)建兩個(gè)表:一個(gè) employeeData 表和一個(gè) auditEmployeeData 表。人力資源部的成員可以修改 employeeData 表,該表包含敏感的雇員薪水信息。如果更改了雇員的社會(huì)保險(xiǎn)號碼 (SSN)、年薪或銀行帳戶,則生成審核記錄并插入到 auditEmployeeData 審核表。
通過使用 COLUMNS_UPDATED() 功能,可以快速測試對這些包含敏感雇員信息的列所做的更改。只有在試圖檢測對表中的前 8 列所做的更改時(shí),COLUMNS_UPDATED() 才起作用。
USE pubs IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'employeeData') DROP TABLE employeeData IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'auditEmployeeData') DROP TABLE auditEmployeeData GO CREATE TABLE employeeData ( emp_id int NOT NULL, emp_bankAccountNumber char (10) NOT NULL, emp_salary int NOT NULL, emp_SSN char (11) NOT NULL, emp_lname nchar (32) NOT NULL, emp_fname nchar (32) NOT NULL, emp_manager int NOT NULL ) GO CREATE TABLE auditEmployeeData ( audit_log_id uniqueidentifier DEFAULT NEWID(), audit_log_type char (3) NOT NULL, audit_emp_id int NOT NULL, audit_emp_bankAccountNumber char (10) NULL, audit_emp_salary int NULL, audit_emp_SSN char (11) NULL, audit_user sysname DEFAULT SUSER_SNAME(), audit_changed datetime DEFAULT GETDATE() ) GO CREATE TRIGGER updEmployeeData ON employeeData FOR update AS /*Check whether columns 2, 3 or 4 has been updated. If any or all of columns 2, 3 or 4 have been changed, create an audit record. The bitmask is: power(2,(2-1))+power(2,(3-1))+power(2,(4-1)) = 14. To check if all columns 2, 3, and 4 are updated, use = 14 in place of >0 (below).*/ IF (COLUMNS_UPDATED() & 14) > 0 /*Use IF (COLUMNS_UPDATED() & 14) = 14 to see if all of columns 2, 3, and 4 are updated.*/ BEGIN -- Audit OLD record. INSERT INTO auditEmployeeData (audit_log_type, audit_emp_id, audit_emp_bankAccountNumber, audit_emp_salary, audit_emp_SSN) SELECT 'OLD', del.emp_id, del.emp_bankAccountNumber, del.emp_salary, del.emp_SSN FROM deleted del -- Audit NEW record. INSERT INTO auditEmployeeData (audit_log_type, audit_emp_id, audit_emp_bankAccountNumber, audit_emp_salary, audit_emp_SSN) SELECT 'NEW', ins.emp_id, ins.emp_bankAccountNumber, ins.emp_salary, ins.emp_SSN FROM inserted ins END GO /*Inserting a new employee does not cause the UPDATE trigger to fire.*/ INSERT INTO employeeData VALUES ( 101, 'USA-987-01', 23000, 'R-M53550M', N'Mendel', N'Roland', 32) GO /*Updating the employee record for employee number 101 to change the salary to 51000 causes the UPDATE trigger to fire and an audit trail to be produced.*/ UPDATE employeeData SET emp_salary = 51000 WHERE emp_id = 101 GO SELECT * FROM auditEmployeeData GO /*Updating the employee record for employee number 101 to change both the bank account number and social security number (SSN) causes the UPDATE trigger to fire and an audit trail to be produced.*/ UPDATE employeeData SET emp_bankAccountNumber = '133146A0', emp_SSN = 'R-M53550M'
WHERE emp_id = 101
GO
SELECT * FROM auditEmployeeData
GO
如果必須測試影響到表中前 8 列以外的列的更新時(shí),必須使用 UBSTRING 函數(shù)測試由 COLUMNS_UPDATED 返回的適當(dāng)?shù)奈弧O吕郎y試影響 Northwind.dbo.Customers 表中的第 3、第 5 或第 9 列的更新。
USE Northwind
DROP TRIGGER tr1
GO
CREATE TRIGGER tr1 ON Customers
FOR UPDATE AS
IF ( (SUBSTRING(COLUMNS_UPDATED(),1,1)=power(2,(3-1))
+ power(2,(5-1)))
AND (SUBSTRING(COLUMNS_UPDATED(),2,1)=power(2,(1-1)))
)
PRINT 'Columns 3, 5 and 9 updated'
GO
UPDATE Customers
SET ContactName=ContactName,
Address=Address,
Country=Country
GO
一.寫入BLOB
1.先在blob中插入empty_blob()
2.獲得對剛剛插入記錄的引用
BLOB blob = (BLOB) rs.getBlob("你的blob字段名稱");
3.寫入
OutputStream out = blob.getBinaryOutputStream();
out.write(ENCYPWD);//注意這里
二.讀出BLOB
1.blob = rs.getBlob("你的blob字段名稱");
2.
InputStream is = blob.getBinaryStream();
int length = (int) blob.length();
byte[] buffer = new byte[length];
is.read(buffer);
is.close();
3.你有了is就隨便處理了
比如說輸出到一個(gè)文件
FileOutputStream fo = new FileOutputStream(filename);//數(shù)據(jù)到的文件名
fo.write(buffer);
fo.close();
首先在本機(jī)啟動(dòng)一個(gè)ftp服務(wù),ftp的用戶:"IUSR_ZJH" 密碼:"123";隨后在ftp主目錄下建一個(gè)名為upftp的子目錄;下面有4個(gè)文件就可啟動(dòng)這個(gè)例題了。
文件1:MainCtrl.java(servlet文件)內(nèi)容如下:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.FileInputStream;
import java.io.IOException;
import sun.net.TelnetOutputStream;
import sun.net.ftp.FtpClient;
public class MainCtrl extends HttpServlet {
private FtpClient ftpClient;
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html; charset=UTF-8");
try {
//連接ftp服務(wù)器
connectServer("127.0.0.1", "IUSR_ZJH", "123", "upftp");
//上傳文件;并返回上傳文件的信息
req.setAttribute("inf", upload(req.getParameter("file_name")));
} catch (Exception e) {
System.out.println(e.toString());
req.setAttribute("inf", e.toString());
req.getRequestDispatcher("view_inf.jsp").forward(req, resp);
return;
} finally {
if (ftpClient != null) {
ftpClient.closeServer();
}
}
req.getRequestDispatcher("view_inf.jsp").forward(req, resp);
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
//連接ftp服務(wù)器
private void connectServer(String server, String user, String password,
String path) throws IOException {
// server:FTP服務(wù)器的IP地址;user:登錄FTP服務(wù)器的用戶名
// password:登錄FTP服務(wù)器的用戶名的口令;path:FTP服務(wù)器上的路徑
ftpClient = new FtpClient();
ftpClient.openServer(server);
ftpClient.login(user, password);
//path是ftp服務(wù)下主目錄的子目錄
if (path.length() != 0)
ftpClient.cd(path);
//用2進(jìn)制上傳
ftpClient.binary();
}
//上傳文件;并返回上傳文件的信息
private String upload(String filename) throws Exception {
TelnetOutputStream os = null;
FileInputStream is = null;
try {
//"upftpfile"用ftp上傳后的新文件名
os = ftpClient.put("upftpfile");
java.io.File file_in = new java.io.File(filename);
if (file_in.length()==0) {
return "上傳文件為空!";
}
is = new FileInputStream(file_in);
byte[] bytes = new byte[1024];
int c;
while ((c = is.read(bytes)) != -1) {
os.write(bytes, 0, c);
}
} finally {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
}
return "上傳文件成功!";
}
}
文件2:upftp.htm(前臺操作頁面)內(nèi)容如下:
文件3:view_inf.jsp(信息提示頁面)和upftp.htm一樣放在context的根目錄下,
內(nèi)容如下:
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
th
{
background-color: #4455aa;
color: white;
font-size: 14px;
font-weight:bold;
}
td.TableBody1
{
background-color: #FFFFF0;
color: white;
font-size: 14px;
font-weight:bold;
font-color: red;
}
.tableBorder1
{
width:97%;
border: 1px;
background-color: #6595D6;
}
</style>
</head>
<body>
<%String inf = (String) request.getAttribute("inf");
if (inf == null) {
inf = request.getParameter("inf");
}%>
<table class="tableborder1" style="width: 75%;" align="center"
cellpadding="3" cellspacing="1">
<tbody>
<tr align="center">
<th colspan="2" height="25" width="100%">信 息 提 示:</th>
</tr>
<tr align="center">
<td class="tablebody1" colspan="2" width="100%" height="200"><%=inf%></td>
</tr>
<tr align="center">
<td><input name="back" value="返 回" onclick="history.back();"
type="button" /></td>
</tr>
</tbody>
</table>
</body></html>
文件4:web.xml(j2ee的備置文件)放在WEB-INF目錄下,
內(nèi)容如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<!--Servlet name-->
<servlet>
<servlet-name>MainCtrl</servlet-name>
<servlet-class>MainCtrl</servlet-class>
</servlet>
<!--Servlet mapping-->
<servlet-mapping>
<servlet-name>MainCtrl</servlet-name>
<url-pattern>/MainCtrl</url-pattern>
</servlet-mapping>
</web-app>