SQL語言由命令、子句、運(yùn)算和集合函數(shù)等構(gòu)成。在SQL中,數(shù)據(jù)定義語言DDL(用來建立及定義數(shù)據(jù)表、字段以及索引等數(shù)據(jù)庫結(jié)構(gòu))包含的命令有CREATE、DROP、ALTER;數(shù)據(jù)操縱語言DML(用來提供數(shù)據(jù)的查詢、排序以及篩選數(shù)據(jù)等功能)包含的命令有SELECT、INSERT、UPDATE、DELETE。
一、SQL語句
(1)Select 查詢語句 語法:SELECT [ALL|DISTINCT] <目標(biāo)列表達(dá)式> [AS 列名] [,<目標(biāo)列表達(dá)式> [AS 列名] ...] FROM <表名> [,<表名>…] [WHERE <條件表達(dá)式> [AND|OR <條件表達(dá)式>...] [GROUP BY 列名 [HAVING <條件表達(dá)式>]] [ORDER BY 列名 [ASC | DESC]] 解釋:[ALL|DISTINCT] ALL:全部; DISTINCT:不包括重復(fù)行 <目標(biāo)列表達(dá)式> 對字段可使用AVG、COUNT、SUM、MIN、MAX、運(yùn)算符等 <條件表達(dá)式> 查詢條件 謂詞 比較 =、>,<,>=,<=,!=,<>, 確定范圍 BETWEEN AND、NOT BETWEEN AND 確定集合 IN、NOT IN 字符匹配 LIKE(“%”匹配任何長度,“_”匹配一個字符)、NOT LIKE 空值 IS NULL、IS NOT NULL 子查詢 ANY、ALL、EXISTS 集合查詢 UNION(并)、INTERSECT(交)、MINUS(差) 多重條件 AND、OR、NOT <GROUP BY 列名> 對查詢結(jié)果分組 [HAVING <條件表達(dá)式>] 分組篩選條件 [ORDER BY 列名 [ASC | DESC]] 對查詢結(jié)果排序;ASC:升序 DESC:降序 例1: select student.sno as 學(xué)號, student.name as 姓名, course as 課程名, score as 成績 from score,student where student.sid=score.sid and score.sid=:sid 例2:select student.sno as 學(xué)號, student.name as 姓名,AVG(score) as 平均分 from score,student where student.sid=score.sid and student.class=:class and (term=5 or term=6) group by student.sno, student.name having count(*)>0 order by 平均分 DESC 例3:select * from score where sid like '9634' 例4:select * from student where class in (select class from student where name='陳小小')
(2)INSERT插入語句 語法:INSERT INTO <表名> [(<字段名1> [,<字段名2>, ...])] VALUES (<常量1> [,<常量2>, ...]) 語法:INSERT INTO <表名> [(<字段名1> [,<字段名2>, ...])] 子查詢 例子:INSERT INTO 借書表(rid,bookidx,bdate)VALUES (edit1.text,edit2.text,date) 例子:INSERT INTO score1(sno,name) SELECT sno,name FROM student WHERE class=’9634’
(3)UPDATE-SQL 語法:UPDATE 〈表名〉 SET 列名1 = 常量表達(dá)式1[,列名2 = 常量表達(dá)式2 ...] WHERE <條件表達(dá)式> [AND|OR <條件表達(dá)式>...] 例子:update score set credithour=4 where course='數(shù)據(jù)庫'
(4)DELETE-SQL 語法:DELETE FROM〈表名〉[WHERE <條件表達(dá)式> [AND|OR <條件表達(dá)式>...]] 例子:Delete from student where sid='003101'
(5)CREATE TABLE CREATE TABLE | DBF TableName1 [NAME LongTableName] [FREE] (FieldName1 FieldType [(nFieldWidth [, nPrecision])] [NULL | NOT NULL] [CHECK lExpression1 [ERROR cMessageText1]] [DEFAULT eExpression1] [PRIMARY KEY | UNIQUE] [REFERENCES TableName2 [TAG TagName1]] [NOCPTRANS] [, FieldName2 ...] [, PRIMARY KEY eExpression2 TAG TagName2 |, UNIQUE eExpression3 TAG TagName3] [, FOREIGN KEY eExpression4 TAG TagName4 [NODUP] REFERENCES TableName3 [TAG TagName5]] [, CHECK lExpression2 [ERROR cMessageText2]]) | FROM ARRAY ArrayName
(6)ALTER TABLE ALTER TABLE TableName1 ADD | ALTER [COLUMN] FieldName1 FieldType [(nFieldWidth [, nPrecision])] [NULL | NOT NULL] [CHECK lExpression1 [ERROR cMessageText1]] [DEFAULT eExpression1] [PRIMARY KEY | UNIQUE] [REFERENCES TableName2 [TAG TagName1]] [NOCPTRANS]
(7)DROP TABLE DROP TABLE [路徑名.]表名
(8)CREATE INDEX CREATE INDEX index-name ON table-name(column[,column…]) 例:CREATE INDEX uspa ON 口令表(user,password)
(9)DROP INDEX DROP INDEX table-name.index-name|PRIMARY 例:DROP INDEX 口令表.uspa
二、在程序中使用靜態(tài)SQL語句 在程序設(shè)計階段,將SQL命令文本作為TQuery組件的SQL屬性值設(shè)置。
三、在程序中使用動態(tài)SQL語句 動態(tài)SQL語句是指在SQL語句中包含有參數(shù)變量的SQL語句(如:select * from student where class=:class),在程序中可以為參數(shù)賦值。給參數(shù)賦值的方法有:
1、利用參數(shù)編輯器為參數(shù)賦值 選中TQuery組件,在對象監(jiān)視器OI中點(diǎn)取Params項,在彈出的參數(shù)編輯窗口中設(shè)置參數(shù)的值。 例:SELECT bookidx AS 書號,藏書表.bookname AS 書名, bdate AS 借書日期 FROM 借書表,藏書表 where 借書表.bookidx=藏書表.bookidx and rid=:rid
2、在程序運(yùn)行中通過程序為參數(shù)賦值 (1)根據(jù)參數(shù)在SQL語句中出現(xiàn)的順序,使用TQuery的Params屬性為參數(shù)賦值;
例:在借書表中插入一條記錄 with Query1 do begin SQL.clear; SQL.add('Insert Into 借書表(bookidx,rid,rdate)'); SQl.add('Values(:bookidx,:rid,:rdate)'); Params[0].AsString := bookidxEdit.Text; Params[1].AsString := ridEdit.Text; Params[2] .AsDate:=date; ExecSQL; End;
(2)根據(jù)SQL語句中的參數(shù)名字,調(diào)用ParamByName方法為參數(shù)賦值; ParamByName('bookidx').AsString := bookidxEdit.Text; ParamByName('rid').AsString := ridEdit.Text; ParamByName('rdate') .AsDate:=date; ExecSQL; 有:AsString 、AsSmallInt 、AsInteger 、AsWord 、AsBoolean 、AsFloat 、AsCurrency 、AsBCD 、AsDate 、AsTime 、AsDateTime轉(zhuǎn)換函數(shù)
3、使用數(shù)據(jù)源為參數(shù)賦值 把TQuery的DataSource屬性設(shè)置為另一個數(shù)據(jù)源(T DataSource名字),Delphi會把未賦值的參數(shù)與指定的數(shù)據(jù)源中的各字段相比較,并將匹配的字段的值賦給未賦值的參數(shù),可實現(xiàn)主表—明細(xì)表應(yīng)用。
四、對TQuery返回的數(shù)據(jù)集進(jìn)行修改 一般情況下,TQuery返回的數(shù)據(jù)集是只讀的,不能修改; 對不包含集操作(如:SUM、COUNT)的單表SELECT查詢,設(shè)置TQuery的RequsetLive屬性為True,則可修改TQuery返回的數(shù)據(jù)集。
var I: Integer; ListItem: string; begin for I := 0 to Query1.ParamCount - 1 do begin ListItem := ListBox1.Items[I]; case Query1.Params[I].DataType of ftString: Query1.Params[I].AsString := ListItem; ftSmallInt: Query1.Params[I].AsSmallInt := StrToIntDef(ListItem, 0); ftInteger: Query1.Params[I].AsInteger := StrToIntDef(ListItem, 0); ftWord: Query1.Params[I].AsWord := StrToIntDef(ListItem, 0); ftBoolean: begin if ListItem = 'True' then Query1.Params[I].AsBoolean := True else Query1.Params[I].AsBoolean := False; end; ftFloat: Query1.Params[I].AsFloat := StrToFloat(ListItem); ftCurrency: Query1.Params[I].AsCurrency := StrToFloat(ListItem); ftBCD: Query1.Params[I].AsBCD := StrToCurr(ListItem); ftDate: Query1.Params[I].AsDate := StrToDate(ListItem); ftTime: Query1.Params[I].AsTime := StrToTime(ListItem); ftDateTime: Query1.Params[I].AsDateTime := StrToDateTime(ListItem); end; end; end; 2003-11-25 9:59:00 2003-11-25 10:06:20 運(yùn)行期間對數(shù)據(jù)庫表的 一、數(shù)據(jù)集表的打開與關(guān)閉 打開:設(shè)置數(shù)據(jù)集組件的Active屬性為True或調(diào)用數(shù)據(jù)集組件的Open方法 關(guān)閉:設(shè)置數(shù)據(jù)集組件的Active屬性為False或調(diào)用數(shù)據(jù)集組件的Close方法
二、創(chuàng)建數(shù)據(jù)庫應(yīng)用程序 利用向?qū)?chuàng)建:使用Database菜單/Form Wizard選項; 創(chuàng)建主從表:設(shè)置從表的MasterSource、MasterField屬性; 創(chuàng)建查詢表:使用TQuery組件;
三、數(shù)據(jù)庫表記錄的定位 使用TDBNavigator組件; 調(diào)用數(shù)據(jù)集組件的First、Next、Prior、Last方法; 數(shù)據(jù)集組件的EOF屬性(或BOF屬性)用來判斷記錄指針是否指向第一條記錄(或最后一條記錄); 使用數(shù)據(jù)集的書簽BookMark(GetBookMark:獲得當(dāng)前記錄的BookMark記號;GotoBookMark:從當(dāng)前記錄直接轉(zhuǎn)到指定BookMark的那條記錄;FreeBookMark:釋放某個BookMark) 使用GotoKey、FindKey方法查找記錄進(jìn)行定位;
四、數(shù)據(jù)庫表字段對象的使用
(1)創(chuàng)建永久的字段對象 雙擊或單擊再右擊TTable(TQuery)對象打開字段編輯器,使用其彈出菜單增加字段對象、刪除字段對象、定義新的字段對象(字段編輯器的彈出菜單的New Fields選項,可創(chuàng)建計算字段);
(2)字段對象的屬性、方法、事件 字段對象名:如Table1Name、Query1Sid 屬性:Alignment(對齊方式)、Calculated(是否是從其它字段值計算得到)、DisplayLabel(顯示的標(biāo)題)、DisplayWidth(顯示的寬度)、DisplayFormat(顯示的格式)、EditMask(輸入的限制)、FieldName(字段名)、ReadOnly(是否只讀)、Visible(是否顯示) 事件:OnChange(字段值發(fā)生變化時觸發(fā))、OnGetText(當(dāng)字段對象獲得字段值時觸發(fā))、OnSetText(當(dāng)字段對象被設(shè)置字段值時觸發(fā))、OnValiData(當(dāng)修改、插入、進(jìn)行有效性檢驗時觸發(fā))
(3)字段對象的類型轉(zhuǎn)換 有:AsString 、AsSmallInt 、AsInteger 、AsWord 、AsBoolean 、AsFloat 、AsCurrency 、AsBCD 、AsDate 、AsTime 、AsDateTime轉(zhuǎn)換函數(shù) 如:Edit1.Text:=Table1Name.Value ; Table1Bdate.AsString:=DateToStr(DATE) ;
(4)對字段對象的訪問 動態(tài)字段對象的訪問:Table1.Fields[0]. DisplayLabel:= '學(xué)生編號' Table1.FieldByName('Sid'). DisplayLabel:= '學(xué)生編號' Table1.Fields[0].Assignment:=taCenter Edit1.Text:= Table1.FieldByName('Sid').AsString 永久字段對象的訪問:Query1Sid.DisplayLabel:= '學(xué)生編號' Query1Sid.DisplayWidth:= 12
五、對數(shù)據(jù)庫表數(shù)據(jù)的操作方法
(1)訪問表中某一字段的數(shù)據(jù)的方法: Table1.FieldByName('bookidx').AsString Table1.Field[0].AsInteger Table1.Fieldvalues['bookidx']
(2)數(shù)據(jù)庫表的一些屬性: 當(dāng)前記錄號:Table1.Recno 記錄總數(shù):Table1.RecordCount 得到表的字段名:Table1.GetFieldNames(ListBox1。Items)
(3)數(shù)據(jù)維護(hù)的方法: Edit方法:把數(shù)據(jù)集設(shè)置為編輯狀態(tài); Append方法:把數(shù)據(jù)集設(shè)置為插入狀態(tài)(最后); Insert方法:把數(shù)據(jù)集設(shè)置為插入狀態(tài)(當(dāng)前記錄后); Post方法:把修改的記錄寫回數(shù)據(jù)集; Cancel方法:取消當(dāng)前的操作; Delete方法:刪除表中當(dāng)前記錄; AppendRecord方法: InsertRecord方法:table1.InsertRecord(['963409', NIL, NIL,'考試']); SetRecords方法: Abort方法:取消各種方法的調(diào)用;
(4)輸入數(shù)據(jù)的合法性驗證 對數(shù)據(jù)庫表建立合法性驗證機(jī)制(如在DBD設(shè)置表的Validity Check、Table Lookup、Referential Integrity等屬性); 在字段編輯表Fields Editor(雙擊Ttable對象),選擇字段,編寫其OnValidate事件,要求非空可設(shè)置其Required屬性為True; 在程序中防止不合法輸入(如:使用TDBcombobox對象,TDBlookupcombobox對象);
六、數(shù)據(jù)檢索 (1)利用索引排序 如:TABLE1.IndexName:='uspa' 或TABLE1.IndexFieldNames:='user_id' (2)使用GotoKey方法查找數(shù)據(jù)庫中的記錄 要求查找字段建立了索引,非主索引要設(shè)置Ttable對象的IndexName屬性。 調(diào)用SetKey方法,把要查找的Ttable對象置成查找模塊; 把查找值送進(jìn)被查找的Field的查找緩沖區(qū); 調(diào)用Ttable對象的GotoKey方法,測試該方法的返回值判斷查找是否成功; (3)使用FindKey方法查找數(shù)據(jù)庫中的記錄 把查找值作為參數(shù)傳遞給FindKey函數(shù),允許有多個查找值,要求把要查找的多個字段的索引名賦給Ttable對象的IndexName屬性; (4)不精確查找 GotoNearest方法 FindNearest方法 (5)使用Locate方法查找數(shù)據(jù)庫中的記錄(不用建索引) table1.locate(‘字段名1;字段名2’,VarArroyof([‘值1’,‘值2’]),[LoCaseInsensitive,LoPartialKey]) LoCaseInsensitive:忽略大小寫;IoPartialKey:不精確查找 (6)設(shè)定查找范圍的方法 SetRangeStart、SetRangeEnd、EditRangeStart、EditRangeEnd、SetRange([Start Values],[End Value])、ApplyRange、CancelRange (7)用TQuery組件的動態(tài)SQL語句進(jìn)行查找
七、修改數(shù)據(jù)庫中的記錄 在程序中對數(shù)據(jù)庫記錄進(jìn)行操作可按下列的步驟進(jìn)行: (1)移動數(shù)據(jù)指針到要修改的記錄; (2)調(diào)用Edit方法將Ttable組件設(shè)置成編輯狀態(tài); (3)修改字段值;(Table1.Fieldvalues['字段名']:=值、Table1.Field[0].AsString:=值) (4)可用Nil對字段賦空值; (5)調(diào)用Post方法將修改后的記錄寫入數(shù)據(jù)庫;
八、插入和刪除記錄 刪除:移動指針到相應(yīng)記錄處,調(diào)用Delete方法; 插入:調(diào)用Insert、InsertRecord方法(當(dāng)前記錄處插入)或Append、InsertRecord方法(表的末尾插入); 2003-11-25 10:11:12 動態(tài)的添加PARADOX表的方法【王寒松】 下面給出的函數(shù) AddMasterPassword 完成添加PARADOX表主口令的工作 AddMasterPassword(Table1, 'MyNewPassword') procedure AddMasterPassword(Table: TTable; pswd: string); const RESTRUCTURE_TRUE = WordBool(1); var TblDesc: CRTblDesc; hDb: hDBIDb; begin {表打開?表是獨(dú)占嗎?} if (Table.Active = False) or (Table.Exclusive = False) then raise EDatabaseError.Create('數(shù)據(jù)表必須在獨(dú)占方式才可以添加口令'); {初始化表描述區(qū) } FillChar(TblDesc, SizeOf(CRTblDesc), 0); with TblDesc do begin { 把表名放到描述區(qū) } StrPCopy(szTblName, Table.TableName); { 把表類型放到描述區(qū) } StrCopy(szTblType, szPARADOX); StrPCopy(szPassword, pswd); { 設(shè)置BPROTECTED為TRUE } bProtected := RESTRUCTURE_TRUE; end; { 從當(dāng)前的HANDLE里得到DATABASE的HANDLE } Check(DbiGetObjFromObj(hDBIObj(Table.Handle), objDATABASE, hDBIObj(hDb))); { 關(guān)閉表 } Table.Close; { 添加主口令到PARADOX表里} Check(DbiDoRestructure(hDb, 1, @TblDesc, nil, nil, nil, FALSE)); {添加一個新口令到SESSION} Session.AddPassword(pswd); {重新打開表 } Table.Open; end; 添加副口令的辦法與此類似 2003-11-25 11:21:29 如何選擇一個好的數(shù)據(jù)庫【三大數(shù)據(jù)庫比較】 【開放性】
SQL Server 只能在windows 上運(yùn)行,沒有絲毫的開放性,操作系統(tǒng)的系統(tǒng)的穩(wěn)定對數(shù)據(jù)庫是十分重要的。Windows9X系列產(chǎn)品是偏重于桌面應(yīng)用,NT server只適合中小型企業(yè)。而且windows平臺的可靠性,安全性和伸縮性是非常有限的。它不象unix那樣久經(jīng)考驗,尤其是在處理大數(shù)據(jù)量的關(guān)鍵業(yè)務(wù)時.
Oracle 能在所有主流平臺上運(yùn)行(包括 windows)。完全支持所有的工業(yè)標(biāo)準(zhǔn)。采用完全開放策略??梢允箍蛻暨x擇最適合的解決方案。對開發(fā)商全力支持。
DB2 能在所有主流平臺上運(yùn)行(包括windows)。最適于海量數(shù)據(jù)。DB2在企業(yè)級的應(yīng)用最為廣泛,在全球的500家最大的企業(yè)中,幾乎85%以上用DB2數(shù)據(jù)庫服務(wù)器,而國內(nèi)到97年約占5%.
【可伸縮性,并行性】
SQL server 并行實施和共存模型并不成熟。很難處理日益增多的用戶數(shù)和數(shù)據(jù)卷。伸縮性有限。
Oracle 平行服務(wù)器通過使一組結(jié)點(diǎn)共享同一簇中的工作來擴(kuò)展windownt的能力,提供高可用性和高伸縮性的簇的解決方案。如果windowsNT不能滿足需要, 用戶可以把數(shù)據(jù)庫移到UNIX中。
DB2 DB2具有很好的并行性。DB2把數(shù)據(jù)庫管理擴(kuò)充到了并行的、多節(jié)點(diǎn)的環(huán)境.數(shù)據(jù)庫分區(qū)是數(shù)據(jù)庫的一部分,包含自己的數(shù)據(jù)、索引、配置文件、和事務(wù)日志。數(shù)據(jù)庫分區(qū)有時被稱為節(jié)點(diǎn)或數(shù)據(jù)庫節(jié)點(diǎn)
【安全性】
SQL server 沒有獲得任何安全證書。
Oracle Server 獲得最高認(rèn)證級別的ISO標(biāo)準(zhǔn)認(rèn)證。
DB2 獲得最高認(rèn)證級別的ISO標(biāo)準(zhǔn)認(rèn)證。
【性能】
SQL Server 多用戶時性能不佳
Oracle 性能最高, 保持windowsNT下的TPC-D和TPC-C的世界記錄。
DB2 適用于數(shù)據(jù)倉庫和在線事物處理,性能較高。
【客戶端支持及應(yīng)用模式】
SQL Server C/S結(jié)構(gòu),只支持windows客戶,可以用ADO,DAO,OLEDB,ODBC連接.
Oracle 多層次網(wǎng)絡(luò)計算,支持多種工業(yè)標(biāo)準(zhǔn),可以用ODBC,JDBC,OCI等網(wǎng)絡(luò)客戶連接
DB2 跨平臺,多層結(jié)構(gòu),支持ODBC,JDBC等客戶
【操作簡便】
SQL Server 操作簡單,但只有圖形界面.
Oracle 較復(fù)雜, 同時提供GUI和命令行,在windowsNT和unix下操作相同
DB2 操作簡單,同時提供GUI和命令行,在windowsNT和unix下操作相同
【使用風(fēng)險】
SQL server 完全重寫的代碼,經(jīng)歷了長期的測試,不斷延遲,許多功能需要時間來證明。并不十分兼容早期產(chǎn)品。使用需要冒一定風(fēng)險。
Oracle 長時間的開發(fā)經(jīng)驗,完全向下兼容。得到廣泛的應(yīng)用。完全沒有風(fēng)險。
DB2 在巨型企業(yè)得到廣泛的應(yīng)用,向下兼容性好。風(fēng)險小。 2003-11-25 11:25:37 SQL查詢語句使用 一、簡單查詢 簡單的Transact-SQL查詢只包括選擇列表、FROM子句和WHERE子句。它們分別說明所查詢列、查詢的表或視圖、以及搜索條件等。 例如,下面的語句查詢testtable表中姓名為“張三”的nickname字段和email字段。 SELECT nickname,email FROM testtable WHERE name='張三'
(一)選擇列表 選擇列表(select_list)指出所查詢列,它可以是一組列名列表、星號、表達(dá)式、變量(包括局部變量和全局變量)等構(gòu)成。
1、選擇所有列 例如,下面語句顯示testtable表中所有列的數(shù)據(jù): SELECT * FROM testtable 2、選擇部分列并指定它們的顯示次序 查詢結(jié)果集合中數(shù)據(jù)的排列順序與選擇列表中所指定的列名排列順序相同。 例如: SELECT nickname,email FROM testtable 3、更改列標(biāo)題 在選擇列表中,可重新指定列標(biāo)題。定義格式為: 列標(biāo)題=列名 列名 列標(biāo)題 如果指定的列標(biāo)題不是標(biāo)準(zhǔn)的標(biāo)識符格式時,應(yīng)使用引號定界符,例如,下列語句使用漢字顯示列標(biāo)題: SELECT 昵稱=nickname,電子郵件=email FROM testtable 4、刪除重復(fù)行 SELECT語句中使用ALL或DISTINCT選項來顯示表中符合條件的所有行或刪除其中重復(fù)的數(shù)據(jù)行,默認(rèn)為ALL。使用DISTINCT選項時,對于所有重復(fù)的數(shù)據(jù)行在SELECT返回的結(jié)果集合中只保留一行。 5、限制返回的行數(shù) 使用TOP n [PERCENT]選項限制返回的數(shù)據(jù)行數(shù),TOP n說明返回n行,而TOP n PERCENT時,說明n是表示一百分?jǐn)?shù),指定返回的行數(shù)等于總行數(shù)的百分之幾。 例如: SELECT TOP 2 * FROM testtable SELECT TOP 20 PERCENT * FROM testtable
(二)FROM子句 FROM子句指定SELECT語句查詢及與查詢相關(guān)的表或視圖。在FROM子句中最多可指定256個表或視圖,它們之間用逗號分隔。 在FROM子句同時指定多個表或視圖時,如果選擇列表中存在同名列,這時應(yīng)使用對象名限定這些列所屬的表或視圖。例如在usertable和citytable表中同時存在cityid列,在查詢兩個表中的cityid時應(yīng)使用下面語句格式加以限定:
SELECT username,citytable.cityid FROM usertable,citytable WHERE usertable.cityid=citytable.cityid 在FROM子句中可用以下兩種格式為表或視圖指定別名: 表名 as 別名 表名 別名
例如上面語句可用表的別名格式表示為: SELECT username,b.cityid FROM usertable a,citytable b WHERE a.cityid=b.cityid SELECT不僅能從表或視圖中檢索數(shù)據(jù),它還能夠從其它查詢語句所返回的結(jié)果集合中查詢數(shù)據(jù)。 例如: SELECT a.au_fname+a.au_lname FROM authors a,titleauthor ta (SELECT title_id,title FROM titles WHERE ytd_sales>10000 ) AS t WHERE a.au_id=ta.au_id AND ta.title_id=t.title_id 此例中,將SELECT返回的結(jié)果集合給予一別名t,然后再從中檢索數(shù)據(jù)。
(三)使用WHERE子句設(shè)置查詢條件 WHERE子句設(shè)置查詢條件,過濾掉不需要的數(shù)據(jù)行。例如下面語句查詢年齡大于20的數(shù)據(jù): SELECT * FROM usertable WHERE age>20 WHERE子句可包括各種條件運(yùn)算符: 比較運(yùn)算符(大小比較):>、>=、=、<、<=、<>、!>、!< 范圍運(yùn)算符(表達(dá)式值是否在指定的范圍):BETWEEN…AND… NOT BETWEEN…AND… 列表運(yùn)算符(判斷表達(dá)式是否為列表中的指定項):IN (項1,項2……) NOT IN (項1,項2……) 模式匹配符(判斷值是否與指定的字符通配格式相符):LIKE、NOT LIKE 空值判斷符(判斷表達(dá)式是否為空):IS NULL、NOT IS NULL 邏輯運(yùn)算符(用于多條件的邏輯連接):NOT、AND、OR 1、范圍運(yùn)算符例:age BETWEEN 10 AND 30相當(dāng)于age>=10 AND age<=30 2、列表運(yùn)算符例:country IN ('Germany','China') 3、模式匹配符例:常用于模糊查找,它判斷列值是否與指定的字符串格式相匹配??捎糜赾har、varchar、text、ntext、datetime和smalldatetime等類型查詢。 可使用以下通配字符: 百分號%:可匹配任意類型和長度的字符,如果是中文,請使用兩個百分號即%%。 下劃線_:匹配單個任意字符,它常用來限制表達(dá)式的字符長度。 方括號[]:指定一個字符、字符串或范圍,要求所匹配對象為它們中的任一個。 [^]:其取值也[] 相同,但它要求所匹配對象為指定字符以外的任一個字符。 例如: 限制以Publishing結(jié)尾,使用LIKE '%Publishing' 限制以A開頭:LIKE '[A]%' 限制以A開頭外:LIKE '[^A]%' 4、空值判斷符例WHERE age IS NULL 5、邏輯運(yùn)算符:優(yōu)先級為NOT、AND、OR
(四)查詢結(jié)果排序 使用ORDER BY子句對查詢返回的結(jié)果按一列或多列排序。ORDER BY子句的語法格式為: ORDER BY {column_name [ASC|DESC]} [,…n] 其中ASC表示升序,為默認(rèn)值,DESC為降序。ORDER BY不能按ntext、text和image數(shù)據(jù)類型進(jìn)行排序。 例如: SELECT * FROM usertable ORDER BY age desc,userid ASC 另外,可以根據(jù)表達(dá)式進(jìn)行排序。
二、聯(lián)合查詢 UNION運(yùn)算符可以將兩個或兩個以上上SELECT語句的查詢結(jié)果集合合并成一個結(jié)果集合顯示,即執(zhí)行聯(lián)合查詢。UNION的語法格式為: select_statement UNION [ALL] selectstatement [UNION [ALL] selectstatement][…n] 其中selectstatement為待聯(lián)合的SELECT查詢語句。 ALL選項表示將所有行合并到結(jié)果集合中。不指定該項時,被聯(lián)合查詢結(jié)果集合中的重復(fù)行將只保留一行。 聯(lián)合查詢時,查詢結(jié)果的列標(biāo)題為第一個查詢語句的列標(biāo)題。因此,要定義列標(biāo)題必須在第一個查詢語句中定義。要對聯(lián)合查詢結(jié)果排序時,也必須使用第一查詢語句中的列名、列標(biāo)題或者列序號。 在使用UNION 運(yùn)算符時,應(yīng)保證每個聯(lián)合查詢語句的選擇列表中有相同數(shù)量的表達(dá)式,并且每個查詢選擇表達(dá)式應(yīng)具有相同的數(shù)據(jù)類型,或是可以自動將它們轉(zhuǎn)換為相同的數(shù)據(jù)類型。在自動轉(zhuǎn)換時,對于數(shù)值類型,系統(tǒng)將低精度的數(shù)據(jù)類型轉(zhuǎn)換為高精度的數(shù)據(jù)類型。 在包括多個查詢的UNION語句中,其執(zhí)行順序是自左至右,使用括號可以改變這一執(zhí)行順序。例如: 查詢1 UNION (查詢2 UNION 查詢3)
三、連接查詢 通過連接運(yùn)算符可以實現(xiàn)多個表查詢。連接是關(guān)系數(shù)據(jù)庫模型的主要特點(diǎn),也是它區(qū)別于其它類型數(shù)據(jù)庫管理系統(tǒng)的一個標(biāo)志。 在關(guān)系數(shù)據(jù)庫管理系統(tǒng)中,表建立時各數(shù)據(jù)之間的關(guān)系不必確定,常把一個實體的所有信息存放在一個表中。當(dāng)檢索數(shù)據(jù)時,通過連接操作查詢出存放在多個表中的不同實體的信息。連接操作給用戶帶來很大的靈活性,他們可以在任何時候增加新的數(shù)據(jù)類型。為不同實體創(chuàng)建新的表,爾后通過連接進(jìn)行查詢。 連接可以在SELECT 語句的FROM子句或WHERE子句中建立,似是而非在FROM子句中指出連接時有助于將連接操作與WHERE子句中的搜索條件區(qū)分開來。所以,在Transact-SQL中推薦使用這種方法。 SQL-92標(biāo)準(zhǔn)所定義的FROM子句的連接語法格式為: FROM join_table join_type join_table [ON (join_condition)] 其中join_table指出參與連接操作的表名,連接可以對同一個表操作,也可以對多表操作,對同一個表操作的連接又稱做自連接。 join_type 指出連接類型,可分為三種:內(nèi)連接、外連接和交叉連接。內(nèi)連接(INNER JOIN)使用比較運(yùn)算符進(jìn)行表間某(些)列數(shù)據(jù)的比較操作,并列出這些表中與連接條件相匹配的數(shù)據(jù)行。根據(jù)所使用的比較方式不同,內(nèi)連接又分為等值連接、自然連接和不等連接三種。 外連接分為左外連接(LEFT OUTER JOIN或LEFT JOIN)、右外連接(RIGHT OUTER JOIN或RIGHT JOIN)和全外連接(FULL OUTER JOIN或FULL JOIN)三種。與內(nèi)連接不同的是,外連接不只列出與連接條件相匹配的行,而是列出左表(左外連接時)、右表(右外連接時)或兩個表(全外連接時)中所有符合搜索條件的數(shù)據(jù)行。 交叉連接(CROSS JOIN)沒有WHERE 子句,它返回連接表中所有數(shù)據(jù)行的笛卡爾積,其結(jié)果集合中的數(shù)據(jù)行數(shù)等于第一個表中符合查詢條件的數(shù)據(jù)行數(shù)乘以第二個表中符合查詢條件的數(shù)據(jù)行數(shù)。 連接操作中的ON (join_condition) 子句指出連接條件,它由被連接表中的列和比較運(yùn)算符、邏輯運(yùn)算符等構(gòu)成。 無論哪種連接都不能對text、ntext和image數(shù)據(jù)類型列進(jìn)行直接連接,但可以對這三種列進(jìn)行間接連接。例如: SELECT p1.pub_id,p2.pub_id,p1.pr_info FROM pub_info AS p1 INNER JOIN pub_info AS p2 ON DATALENGTH(p1.pr_info)=DATALENGTH(p2.pr_info) (一)內(nèi)連接 內(nèi)連接查詢操作列出與連接條件匹配的數(shù)據(jù)行,它使用比較運(yùn)算符比較被連接列的列值。內(nèi)連接分三種: 1、等值連接:在連接條件中使用等于號(=)運(yùn)算符比較被連接列的列值,其查詢結(jié)果中列出被連接表中的所有列,包括其中的重復(fù)列。 2、不等連接: 在連接條件使用除等于運(yùn)算符以外的其它比較運(yùn)算符比較被連接的列的列值。這些運(yùn)算符包括>、>=、<=、<、!>、!<和<>。 3、自然連接:在連接條件中使用等于(=)運(yùn)算符比較被連接列的列值,但它使用選擇列表指出查詢結(jié)果集合中所包括的列,并刪除連接表中的重復(fù)列。 例,下面使用等值連接列出authors和publishers表中位于同一城市的作者和出版社: SELECT * FROM authors AS a INNER JOIN publishers AS p ON a.city=p.city 又如使用自然連接,在選擇列表中刪除authors 和publishers 表中重復(fù)列(city和state): SELECT a.*,p.pub_id,p.pub_name,p.country FROM authors AS a INNER JOIN publishers AS p ON a.city=p.city (二)外連接 內(nèi)連接時,返回查詢結(jié)果集合中的僅是符合查詢條件( WHERE 搜索條件或 HAVING 條件)和連接條件的行。而采用外連接時,它返回到查詢結(jié)果集合中的不僅包含符合連接條件的行,而且還包括左表(左外連接時)、右表(右外連接時)或兩個邊接表(全外連接)中的所有數(shù)據(jù)行。 如下面使用左外連接將論壇內(nèi)容和作者信息連接起來: SELECT a.*,b.* FROM luntan LEFT JOIN usertable as b ON a.username=b.username 下面使用全外連接將city表中的所有作者以及user表中的所有作者,以及他們所在的城市: SELECT a.*,b.* FROM city as a FULL OUTER JOIN user as b ON a.username=b.username (三)交叉連接 交叉連接不帶WHERE 子句,它返回被連接的兩個表所有數(shù)據(jù)行的笛卡爾積,返回到結(jié)果集合中的數(shù)據(jù)行數(shù)等于第一個表中符合查詢條件的數(shù)據(jù)行數(shù)乘以第二個表中符合查詢條件的數(shù)據(jù)行數(shù)。 例,titles表中有6類圖書,而publishers表中有8家出版社,則下列交叉連接檢索到的記錄數(shù)將等于6*8=48行。 SELECT type,pub_name FROM titles CROSS JOIN publishers ORDER BY type 2003-11-25 11:31:30 SQL Server中Image Data Type的使用技巧 【國商網(wǎng)絡(luò)有限公司 蔣心武】 MS SQL Server 是微軟公司推出的大型數(shù)據(jù)庫軟件,在NT平臺上擁有近一半的數(shù)據(jù)庫市場,特別是在SQL Server 7.0推出后,其發(fā)展勢頭更加迅猛。SQL Server中Image數(shù)據(jù)類型是用來存儲圖形的。在此我談?wù)勗鯓釉觥h、改此類型數(shù)據(jù)及在主頁中讀出此類型數(shù)據(jù)。
一、在表中添加圖形 Image 數(shù)據(jù)類型不同于其它數(shù)據(jù)類型,不能用Insert 、Update的標(biāo)準(zhǔn)SQL語法進(jìn)行圖形的添加和修改。需用到SQL Server中的TEXTPTR 、WRITETEXT、UPDATETEXT等函數(shù)進(jìn)行圖形的添加和修改。
首先假設(shè)在庫Im_Test中建立一張表Im_Info,此表中有兩個字段,分別為Pr_Id (INT),Pr_Info (IMAGE),用來存儲圖形編號及圖形信息。其語法如下:
CREATE TEALE Im_Info ( Pr_Id INT NULL , Pr_Info IMAGE NULL )
第一步往表中插入一條記錄,并初始化PR_INFO字段。其語法如下:
INSERT INTO Im_Info VALUES (1 ,0xFFFFFFFF)
第二步往表中寫入圖形信息。其語法如下:
DECLARE @@ptrval varbinary(16) SELECT @@ptrval = TEXTPTR(Pr_Info) FROM Im_Info WHERE Pr_Id = 1 WRITETEXT Im_Text.Im_Info @@ptrval 0x624fd543fd…..
其中0x624fd543fd….. 為圖形的十六進(jìn)制數(shù)據(jù),可以通過C 、Java等工具獲得。注意在寫入圖形信息前必須先將此數(shù)據(jù)庫的 'select into/bulkcopy' 屬性設(shè)置為 True ,其語法如下:
sp_dboption Im_Test , 'select into/bulkcopy' ,True
若想修改圖形數(shù)據(jù)可用UPDATETEXT函數(shù)修改,其語法如下:
DECLARE @@ptrval varbinary(16) SELECT @@ptrval = TEXTPTR(Pr_Info) FROM Im_Info WHERE Pr_Id = 1 UPDATETEXT Im_Text.Im_Info @@ptrval 0xaa31bcfe543fd…..
二、在主頁中顯示圖形
第一步建立數(shù)據(jù)源 若想將加入的圖形顯示在主頁中,必須先建立數(shù)據(jù)源,打開Windows 中的控制面板。通過ODBC 應(yīng)用程序,建立數(shù)據(jù)源(取名Im_Test)連接到Im_Test數(shù)據(jù)庫
第二步編寫程序 < % @ LANGUAGE = VBScript % > < % Option Explicit % > < % Dim oConn Dim oRs Dim Pic Dim PicSize
Response.Buffer = TRUE Response.ContentType = "image/gif"
Set oConn = Server.CreateObject ("ADODB.Connection") oConn.Open "Im_Test",”sa”,”” Set oRs = oConn.Execute("SELECT Pr_Info FROM Im_Info WHERE Pr_Id=1”)
PicSize = oRs("Pr_Info").ActualSize Pic = oRs("Pr_Info ").GetChunk(PicSize) Response.BinaryWrite Pic Response.End % >
此程序中先定義四個變量。然后設(shè)置屬性 Response.Buffer=TRU和Response.ContentType = "image/gif" ,再連接數(shù)據(jù)庫取出圖形,在加以顯示。 2003-11-25 11:41:44 深入SQL編程【關(guān)于存儲過程和索引】 這里所指的SQL編程并不是那些在象ASP,PHP腳本語言里用的某個SQL語句,如果你是個程序員并在做DB C/S開發(fā),我想你會很清楚的知道SQL編程是很復(fù)雜的,先拋開嵌入語句,動態(tài)執(zhí)行,高級函數(shù),表達(dá)試等這些不談單就解決性能問題就很頭疼,下面就性能問題給出一些解決放案.(以下程序均在NT+SP6 SQL SERVER 7下調(diào)試通過)
一,存儲過程 我的一個朋友用VC/SQL SERVER做C/S項目開發(fā),再開發(fā)過程中他的程序雖順利執(zhí)行,但遇到了由于需要大批量插入數(shù)據(jù)而引出的性能問題。他找到了我,雖然我沒有用過VC但很明顯在他程序中看出是在前臺用循環(huán)操作象后臺插入數(shù)據(jù)。這種方法再處理大批量數(shù)時無疑是不可取的,因編譯器并不會處理SQL語句而是通過ODBC傳輸?shù)胶笈_,再在后臺解釋執(zhí)行。 由此可見經(jīng)過以上幾步性能問題以大打折扣,后我將他的程序段改為后臺SQL編程,用存儲過程實現(xiàn)。然后在前臺用VC調(diào)用,這樣一來問題以得到完美的解決。改后程序如下:(遇到此類問題的朋友可參考解決)
CREATE PROC usp_insert_temp @iCount VARCHAR(10), @Text VARCHAR(50), @price VARCHAR(15)
AS
DECLARE @iIndex INT DECLARE @pMoney FLOAT
SET @iIndex=CONVERT(INT,@iCount) SET @pMoney=CONVERT(FLOAT,@price)
BEGIN TRAN SELECT rygl_id,title,price INTO rygl_temp FROM rqk WHERE EXISTS (SELECT rygl_id FROM rygl WHERE rqk.rygl_id=rygl.rygl_id AND qty<30) ORDER BY title_id
IF @@ERROR<>0 ROLLBACK TRAN ELSE COMMIT TRAN
WHILE @iIndex>0 BEGIN BEGIN TRAN SET @pMoney=@pMoney+1.1111 INSERT INTO rygl_temp(rygl_id,title,price) VALUES(@iIndex,@Text,CONVERT(SMALLMONEY,@pMoney))
IF @@ERROR<>0 OR @@ROWCOUNT=0 ROLLBACK TRAN ELSE COMMIT TRAN SET @iIndex=@iIndex-1 END
二,索引測試,比較 合理的索引建立,運(yùn)用可很大幅度提高程序性能,以下是在工作當(dāng)中得出的經(jīng)驗,與大家共享。
1,ORDER BY和GROPU BY 如果用戶經(jīng)常選擇數(shù)據(jù)和使用ORDER BY和GROUP BY短語,任何一種索引都有助于SELECT的性能提高。如果用戶選擇的是顧客并按其姓名分類,兩種索引都能快速檢索數(shù)據(jù)。但下面的一些因素會使用戶選擇使用某一種索引。
2,返回范圍內(nèi)的數(shù)據(jù) 列如,如果擁護(hù)希望返回在SMITH和TALBERT之間的所有顧客姓名,或者返回在日期“11/1/98”和“11/30/98”之間的訂貨量,并且用戶經(jīng)常做這類事情,那么最好在該范圍所在的指定列使用聚類索引。因聚類索引已包含了經(jīng)過分類排序的數(shù)據(jù),這對于在指定范圍內(nèi)檢索數(shù)據(jù)更為有效。聚類索引只需找到要檢索的所有數(shù)據(jù)中的開頭和結(jié)尾數(shù)據(jù)即可;而不象非聚類索,必須在數(shù)據(jù)層專查找來字葉層的每一個數(shù)據(jù)項。
3,列中有一個或極少的不同值 在用戶表中的某些列中喊有極少不同值,列如狀態(tài)列中只包含INACVTIVE,ACVIVE或者TERMINATED。在這種情況下,在該列上使用任何類型索引都是不明智的,原因很簡單:如果用戶表包含了1500行大概有三分之一的行即500行在狀態(tài)列中含有ACTIVE。掃描整個表,如果不是更高效,至少也是同先在索引頁面中查找每個數(shù)據(jù)項而后尋找到包含ACTIVE狀態(tài)的行所在的數(shù) 據(jù)頁面也相同的效率。下面這個列子創(chuàng)建了一個表,它在有很很多重復(fù)值的列上進(jìn)行索引,而該列具有很少的不同值。運(yùn)行該腳本可能要花幾分鐘。
*/
DROP TABLE IndexTestTable CREATE TABLE IndexTestTable ( Tid INT IDENTITY(1,1) NOT NULL, Status CHAR(10) NULL )
GO
SET IDENTITY_INSERT IndexTestTable ON DECLARE @intCount INT
BEGIN TRAN SET @intCount=1 WHILE @intCount<=1500 BEGIN INSERT IndexTestTable(Tid,Status) VALUES(@intCount,'Active') SET @intCount=@intCount+3 END
SET @intCount=2 WHILE @intCount<=1500 BEGIN INSERT IndexTestTable(Tid,Status) VALUES(@intCount,'inactive') SET @intCount=@intCount+3 END
SET @intCount=3 WHILE @intCount<=1500 BEGIN INSERT IndexTestTable(Tid,Status) VALUES(@intCount,'Terminated') SET @intCount=@intCount+3 END COMMIT TRAN
SET IDENTITY_INSERT IndexTestTable OFF GO
DUMP TRANSACTION pubs WITH NO_LOG GO
CREATE INDEX inTableUniquesStatus ON IndexTestTable(Status) GO
--不用索引查詢 SELECT * FROM IndexTestTable WITH(index(0)) WHERE Status='inactive'
--用索引查詢 SELECT * FROM IndexTestTable WITH(index(inTableUniquesStatus)) WHERE Status='inactive'
/*
選中SHOW STATS I/O查看運(yùn)行結(jié)果會另人吃驚。第一個SELECT語句引起全表掃描幾乎不需要內(nèi)存操作(因為只是進(jìn)行插入,所有所有數(shù)據(jù)都在內(nèi)存中,并不需要進(jìn)行磁盤或物理讀操作)。第二個SELECT語句則需要執(zhí)行500個讀操作,這就證實了我們所說的在這種情況下,使用任何類型索引都是不明智的。
4, 以上舉列說明了在何種情況下不應(yīng)使用索引,現(xiàn)在咱們再反過來看看當(dāng)索引列中 不同數(shù)目值增加時即有較少不同值時會怎樣?見如下代碼
*/
DROP TABLE IndexTestTable GO
CREATE TABLE IndexTestTable ( Tid INT IDENTITY(1,1) NOT NULL, Status CHAR(10) NULL, Co3 CHAR(20) NOT NULL, Co4 CHAR(50) NOT NULL ) GO
DECLARE @intNum INT SET @intNum=0
BEGIN TRAN WHILE @intNum<=1300 BEGIN INSERT indexTestTable VALUES(CHAR(@intNum %26 +65),'test3','test4') SET @intNum=@intNum+1 END COMMIT TRAN GO
--不用索引查詢 SELECT * FROM IndexTestTable WHIT(INDEX(0)) WHERE Status='B'
--創(chuàng)建聚集索引 CREATE CLUSTERED INDEX icIndexTestTable ON IndexTestTable(Status) GO
--使用索引查詢 SELECT * FROM IndexTestTable WITH(INDEX(icIndexTestTable)) WHERE Status='B'
/*
5, 用戶很明顯地能看出,隨著表中行的數(shù)目和列中不同值的增長。使用索引可以較大幅度提高效率,由此又引出另一個問題,在何種情況下用何種索引更有效?上面列子已經(jīng)介紹了聚類索引,大家都能看出在對于有較少不同植時使用聚類索引是有很大幫助的,但當(dāng)不同值的數(shù)木增加并達(dá)到表中行的樹木時則應(yīng)該選非聚類索引。此時使用非聚類索在讀操作上和聚類似索引并無 二異,但在對表進(jìn)行寫操作上的性能卻提高不少,如果用戶經(jīng)常從表中的一個或少是數(shù)幾個字段中檢索數(shù)據(jù),當(dāng)非聚集索引包含要檢索的所有字段時就會減少所需的讀操作,如果不是那么正如上面第二條所說使用非聚集索引通常是鐘很差的選擇,下面這個列子說明了在何時應(yīng)該使用聚集索引
*/
DROP TABLE IndexTestTable GO
CREATE TABLE IndexTestTable ( Tid INT IDENTITY(1,1)NOT NULL, Status CHAR(20) NOT NULL ) GO
DECLARE @intCount INT SET @intCount=0
BEGIN TRAN WHILE @intCount<=500 BEGIN INSERT INTO IndexTestTable(Status) VALUES('test'+CONVERT(CHAR(6),@intCount)) SET @intCount=@intCount+1 END COMMIT TRAN GO
--創(chuàng)建聚集索引 CREATE CLUSTERED INDEX icIndexTestTable ON IndexTestTable(Tid) GO
--創(chuàng)建非聚集索引 CREATE INDEX inIndexTestTable ON IndexTestTable(Tid) GO
--使用非聚集索引查詢 SELECT Tid FROM IndexTestTable WITH(INDEX(inIndexTestTable)) WHERE Tid BETWEEN 100 AND 500
--使用聚集索引查詢 SELECT Tid FROM IndexTestTable WITH(INDEX(icIndexTestTable)) WHERE Tid BETWEEN 100 AND 500
/*
集索引包含絕大多數(shù)的檢索數(shù)據(jù),則只需要讀取很少的數(shù)據(jù)頁這種情況下非聚集索引要比聚集索引好,如果表的數(shù)據(jù)行很龐大效果會更加明顯。
6, 要說明的是,索引雖有助于提高性能但不是索引越多越好,恰好相反過多的索引會導(dǎo)致系統(tǒng)低效。用戶在表中每加進(jìn)一個索引,維護(hù)索引集合就要做相應(yīng)的更新工作。 2003-11-25 11:49:45 SQL Server日期計算 通常,你需要獲得當(dāng)前日期和計算一些其他的日期,例如,你的程序可能需要判斷一個月的第一天或者最后一天。你們大部分人大概都知道怎樣把日期進(jìn)行分割(年、月、日等),然后僅僅用分割出來的年、月、日等放在幾個函數(shù)中計算出自己所需要的日期!在這篇文章里,我將告訴你如何使用DATEADD和DATEDIFF函數(shù)來計算出在你的程序中可能你要用到的一些不同日期。 在使用本文中的例子之前,你必須注意以下的問題。大部分可能不是所有例子在不同的機(jī)器上執(zhí)行的結(jié)果可能不一樣,這完全由哪一天是一個星期的第一天這個設(shè)置決定。第一天(DATEFIRST)設(shè)定決定了你的系統(tǒng)使用哪一天作為一周的第一天。所有以下的例子都是以星期天作為一周的第一天來建立,也就是第一天設(shè)置為7。假如你的第一天設(shè)置不一樣,你可能需要調(diào)整這些例子,使它和不同的第一天設(shè)置相符合。你可以通過@@DATEFIRST函數(shù)來檢查第一天設(shè)置。
為了理解這些例子,我們先復(fù)習(xí)一下DATEDIFF和DATEADD函數(shù)。DATEDIFF函數(shù)計算兩個日期之間的小時、天、周、月、年等時間間隔總數(shù)。DATEADD函數(shù)計算一個日期通過給時間間隔加減來獲得一個新的日期。要了解更多的DATEDIFF和DATEADD函數(shù)以及時間間隔可以閱讀微軟聯(lián)機(jī)幫助。
使用DATEDIFF和DATEADD函數(shù)來計算日期,和本來從當(dāng)前日期轉(zhuǎn)換到你需要的日期的考慮方法有點(diǎn)不同。你必須從時間間隔這個方面來考慮。比如,從當(dāng)前日期到你要得到的日期之間有多少時間間隔,或者,從今天到某一天(比如1900-1-1)之間有多少時間間隔,等等。理解怎樣著眼于時間間隔有助于你輕松的理解我的不同的日期計算例子。
【一個月的第一天】 第一個例子,我將告訴你如何從當(dāng)前日期去這個月的最后一天。請注意:這個例子以及這篇文章中的其他例子都將只使用DATEDIFF和DATEADD函數(shù)來計算我們想要的日期。每一個例子都將通過計算但前的時間間隔,然后進(jìn)行加減來得到想要計算的日期。
這是計算一個月第一天的SQL 腳本: SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)
我們把這個語句分開來看看它是如何工作的。最核心的函數(shù)是getdate(),大部分人都知道這個是返回當(dāng)前的日期和時間的函數(shù)。下一個執(zhí)行的函數(shù)DATEDIFF(mm,0,getdate())是計算當(dāng)前日期和“1900-01-01 00:00:00.000”這個日期之間的月數(shù)。記?。簳r期和時間變量和毫秒一樣是從“1900-01-01 00:00:00.000”開始計算的。這就是為什么你可以在DATEDIFF函數(shù)中指定第一個時間表達(dá)式為“0”。下一個函數(shù)是DATEADD,增加當(dāng)前日期到“1900-01-01”的月數(shù)。通過增加預(yù)定義的日期“1900-01-01”和當(dāng)前日期的月數(shù),我們可以獲得這個月的第一天。另外,計算出來的日期的時間部分將會是“00:00:00.000”。
這個計算的技巧是先計算當(dāng)前日期到“1900-01-01”的時間間隔數(shù),然后把它加到“1900-01-01”上來獲得特殊的日期,這個技巧可以用來計算很多不同的日期。下一個例子也是用這個技巧從當(dāng)前日期來產(chǎn)生不同的日期。
【本周的星期一】 這里我是用周(wk)的時間間隔來計算哪一天是本周的星期一。 SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)
【一年的第一天】 現(xiàn)在用年(yy)的時間間隔來顯示這一年的第一天。 SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)
【季度的第一天】 假如你要計算這個季度的第一天,這個例子告訴你該如何做。 SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)
【當(dāng)天的半夜】 曾經(jīng)需要通過getdate()函數(shù)為了返回時間值截掉時間部分,就會考慮到當(dāng)前日期是不是在半夜。假如這樣,這個例子使用DATEDIFF和DATEADD函數(shù)來獲得半夜的時間點(diǎn)。 SELECT DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)
【深入DATEDIFF和DATEADD函數(shù)計算】 你可以明白,通過使用簡單的DATEDIFF和DATEADD函數(shù)計算,你可以發(fā)現(xiàn)很多不同的可能有意義的日期。
目前為止的所有例子只是僅僅計算當(dāng)前的時間和“1900-01-01”之間的時間間隔數(shù)量,然后把它加到“1900-01-01”的時間間隔上來計算出日期。假定你修改時間間隔的數(shù)量,或者使用不同的時間間隔來調(diào)用DATEADD函數(shù),或者減去時間間隔而不是增加,那么通過這些小的調(diào)整你可以發(fā)現(xiàn)和多不同的日期。
這里有四個例子使用另外一個DATEADD函數(shù)來計算最后一天來分別替換DATEADD函數(shù)前后兩個時間間隔。
【上個月的最后一天】 這是一個計算上個月最后一天的例子。它通過從一個月的最后一天這個例子上減去3毫秒來獲得。有一點(diǎn)要記住,在Sql Server中時間是精確到3毫秒。這就是為什么我需要減去3毫秒來獲得我要的日期和時間。 SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))
計算出來的日期的時間部分包含了一個Sql Server可以記錄的一天的最后時刻(“23:59:59:997”)的時間。
【去年的最后一天】 連接上面的例子,為了要得到去年的最后一天,你需要在今年的第一天上減去3毫秒。 SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
【本月的最后一天】 現(xiàn)在,為了獲得本月的最后一天,我需要稍微修改一下獲得上個月的最后一天的語句。修改需要給用DATEDIFF比較當(dāng)前日期和“1900-01-01”返回的時間間隔上加1。通過加1個月,我計算出下個月的第一天,然后減去3毫秒,這樣就計算出了這個月的最后一天。這是計算本月最后一天的SQL腳本。 SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))
【本年的最后一天】 你現(xiàn)在應(yīng)該掌握這個的做法,這是計算本年最后一天腳本 SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))。
【本月的第一個星期一】 好了,現(xiàn)在是最后一個例子。這里我要計算這個月的第一個星期一。這是計算的腳本。 select DATEADD(wk, DATEDIFF(wk,0,dateadd(dd,6-datepart(day,getdate()),getdate())), 0) 在這個例子里,我使用了“本周的星期一”的腳本,并作了一點(diǎn)點(diǎn)修改。修改的部分是把原來腳本中“getdate()”部分替換成計算本月的第6天,在計算中用本月的第6天來替換當(dāng)前日期使得計算可以獲得這個月的第一個星期一。
【總結(jié)】 我希望這些例子可以在你用DATEADD和DATEDIFF函數(shù)計算日期時給你一點(diǎn)啟發(fā)。通過使用這個計算日期的時間間隔的數(shù)學(xué)方法,我發(fā)現(xiàn)為了顯示兩個日期之間間隔的有用歷法是有價值的。注意,這只是計算出這些日期的一種方法。要牢記,還有很多方法可以得到相同的計算結(jié)果。假如你有其他的方法,那很不錯,要是你沒有,我希望這些例子可以給你一些啟發(fā),當(dāng)你要用DATEADD和DATEDIFF函數(shù)計算你程序可能要用到的日期時。 2003-11-25 12:11:33 在數(shù)據(jù)庫管理系統(tǒng)中,查詢是一項必不可少的功能。查詢功能是直接體現(xiàn)系統(tǒng)功能的一項重要指標(biāo)。查詢的方式主要有以下幾種:1固定字段的單一查詢;2可選擇字段的單一查詢;3限制若干個字段的多重查詢;4可任意選擇字段的多重查詢。前兩種也稱為單條件查詢,后兩種稱為多重(或多條件)查詢。在實際中,系統(tǒng)(實為程序員)提供給用戶的查詢方式以單條件查詢?yōu)槎啵词固峁┝硕鄺l件方式,通常也只有兩或三個條件,因為編寫多重查詢是一項非常棘手且繁瑣的事情。僅為此,程序員吃盡了苦頭。實際上,利用表格Grid功能,就能輕松地實現(xiàn)多重查詢。本人以Delphi為例,介紹具體的實現(xiàn)方法,但這種思想,也同樣適合于其它的編程語言(如Visual Foxpro)。
另外,為使程序方便“移植”, 本人把各功能模塊化,使其更具有通用性。
程序主要按如下三個功能來實現(xiàn): ①設(shè)置DBGrid ②生成查詢條件(語句) ③執(zhí)行查詢
具體步驟如下: ⑴新建一工程文件,取名為PDBGrid.dpr; ⑵給單元文件取名為UDBGrid.pas,在其相應(yīng)的表單(取名為frmDBGrid)中添加如下控件并編寫相應(yīng)的代碼:
控件名稱 主要屬性及值 備注 Table1 DataBaseName(MyAlias) TableName (MyTable1.db) Active (false) 查詢對象:數(shù)據(jù)集 MyTable1.db為任意的表 DataSource1 DataSet(Table1)
DBGrid1 DataSource(DataSource1)
顯示數(shù)據(jù)源 Table2 DataBaseName(MyAlias) TableName (CxComm.db) Active (false)
記錄查詢條件的數(shù)據(jù)集 (CxComm.db結(jié)構(gòu)下述) DataSource2 DataSet(Table2)
DBGrid2 DataSource(DataSource2)
提供查詢處理 Query1 DataBaseName(MyAlias) Active (false)
保存和執(zhí)行SQL語句的數(shù)據(jù)集 DataSource3 DataSet (Query 1)
DGrid3 DataSource (DataSource3)
顯示查詢結(jié)果 Memo1 Lines(<動態(tài)賦值>)
顯示及修改SQL語句 Button1 Caption(設(shè)置DBGrid)
Click事件下述 Button2 Caption(生成查詢)
Click事件下述 Button3 Caption(執(zhí)行查詢)
Click事件下述
其中 Table2(記錄查詢條件的數(shù)據(jù)集)對應(yīng)的表CxComm.db的結(jié)構(gòu)定義如下:
字段名 項目 關(guān)系 實例 邏輯 類型 A(字符型) A(字符型) A(字符型) A(字符型) 大小 14 5 10 6
表單的FormActivate事件代碼如下: procedure TfrmDBGrid.FormActivate(Sender: TObject); begin if Table2.Active then Table2.Close; Table2.EmptyTable; //清空條件 Table1.Open; Table2.Open; end;
Button1(設(shè)置DBGrid)的Click事件代碼如下: procedure TfrmDBGrid.Button1Click(Sender: TObject); begin MySetDBGrid(Table1,DBGrid2); // MySetDBGrid為自定義過程 //以Table1為數(shù)據(jù)源,DBGrid2為記錄篩選(查詢)條件的表格 end;
Button2(生成查詢)的Click事件代碼如下: procedure TfrmDBGrid.Button2Click(Sender: TObject); begin if MyCreate_SQL(Table1,Table2,Query1) //MyCreate_SQL為自定義函數(shù) //由指定數(shù)據(jù)來源表來生成SQL,存入Query1 then begin Memo1.Lines.Clear; Memo1.Lines:=(Query1.SQL); Memo1.Modified:=false; end end;
Button3(執(zhí)行查詢)的Click事件代碼如下: procedure TfrmDBGrid.Button3Click(Sender: TObject); begin with Query1,SQL do begin Close; if Memo1.Modified //用戶可修改SQL語句 then SQL:=Memo1.Lines; try ExecSQL; Open; except //捕捉錯誤并處理 begin MessageBeep(0); Application.MessageBox('錯誤的SQL語句!','確認(rèn)',MB_OK+MB_ICONSTOP); Close; end; end //try end; end; //執(zhí)行SQL
自定義過程MySetDBGrid (設(shè)置DBGrid)的代碼如下: procedure TfrmDBGrid.MySetDBGrid(sTable:TTable;tjDBGrid:TDBGrid); //參數(shù)說明:sTable為數(shù)據(jù)(包括字段,記錄)來源表 // tjDBGrid為記錄篩選(查詢)條件的表格 var i:byte; begin //設(shè)置查詢項目 if not sTable.Active then sTable.Open; tjDBGrid.Columns[0].PickList.Clear; for i:=0 to sTable.FieldCount-1 do //記錄數(shù)(即字段數(shù)) begin tjDBGrid.Columns[0].PickList.Add(sTable.Fields[i].FieldName); end; //for //設(shè)置關(guān)系(=,<>,>,>=,<,<=) 及邏輯(AND,OR) tjDBGrid.Columns[1].PickList.Text:='='+#13+'<>'+#13+'>'+#13+'>='+#13+'<'+#13+'<='; tjDBGrid.Columns[3].PickList.Text:='AND'+#13+'OR'; end;//設(shè)置DBGrid
自定義函數(shù)MyCreate_SQL (生成查詢)的代碼如下: function TfrmDBGrid.MyCreate_SQL(sTable,tjTable:TTable;tjQuery:TQuery):boolean; //參數(shù)說明:sTable為數(shù)據(jù)(包括字段,記錄)來源表 // tjTable為記錄篩選(查詢)條件的表 // tjQuery記錄SQL語句 var i:byte; lsDate:TDate; //檢測日期格式用 sLj,sFilter,sFieldName:string; //分別表示:邏輯關(guān)系,篩選條件,字段名 begin Result:=true; //生成"篩選條件"語句 with tjQuery,SQL do begin Close; Clear; DatabaseName:=sTable.DatabaseName; //設(shè)置Query1的別名 Add('Select * from '''+sTable.TableName+''''); end; with tjTable do //查詢(篩選)條件表 begin if not Active then Open; if IsEmpty then begin Application.MessageBox('未選擇篩選條件!','確定',MB_OK+MB_ICONEXCLAMATION); Exit; end; tjQuery.SQL.Add(' Where ');//含有篩選條件 sFilter:=''; //臨時記錄篩選條件 First; for i:=0 to RecordCount-1 do begin sLj:=Fields[3].AsString; //邏輯關(guān)系A(chǔ)ND,OR //(字段名0>1實際值2) sFilter:=sFilter+'('; sFilter:=sFilter+Fields[0].AsString+Fields[1].AsString; sFieldName:=Fields[0].AsString; //取第1列的字段名 case Table1.FieldByName(sFieldName).DataType of ftString: begin //字符型處理 sFilter:=sFilter+''''+Fields[2].AsString+'''' //第2列為關(guān)系 end; ftFloat, //浮點(diǎn)型處理 ftAutoInc, //自增型 ftSmallInt, //短整型 ftInteger, //整型 ftCurrency: begin //貨幣型 sFilter:=sFilter+Fields[2].AsString; end; ftDate: begin //日期型處理 try lsDate:=StrToDate(Fields[2].AsString); sFilter:=sFilter+''''+FormatDateTime('mm/dd/yyyy',StrToDate(Fields[2].AsString))+''''; except Application.MessageBox('錯誤的日期格式!','確認(rèn)',MB_OK+MB_ICONSTOP); Result:=false; //返回錯誤標(biāo)志 break; end;//try 日期格式判斷 end; //此處可增加對其它類型數(shù)據(jù)的處理 end;//case sFilter:=sFilter+')'; if sLj<>'' then begin if RecNo<>RecordCount //且"非最后行"的記錄 then sFilter:=sFilter+Fields[3].AsString; //And|Or; end else break; Next end; end; //not IsEmpty(篩選)非空 tjQuery.SQL.Add(sFilter); //保存查詢條件 end; //處理篩選條件
另外,需要進(jìn)行如下說明: ... Type ... procedure MySetDBGrid(sTable:TTable;tjDBGrid:TDBGrid); function MyCreate_SQL(sTable,tjTable:TTable;tjQuery:TQuery):boolean; private { Private declarations } ...
值得說明的是,⑴為從一定程序上簡化程序,邏輯關(guān)系只提供了AND和OR兩種,但為允許用戶修改SQL語句,如:在多條件之間增加括號來改變運(yùn)算順序等,使得查詢功能更加強(qiáng)大,因此增加了Memo控件;⑵在實際系統(tǒng)中,為方便用戶的操作,可增加幾個Button(按鈕),功能分別是對Table2的“增加”、“刪除”,這樣用戶界面會更友好些。 利用這種方法來設(shè)置查詢,條件個數(shù)是無限制的,且在屏幕上不會占據(jù)太大的空間,程序員實現(xiàn)起來要簡單得多了。
軟件環(huán)境:中文Win98/中文Delphi5.0。 2003-11-25 12:39:56 有關(guān)重復(fù)記錄的刪除 有兩個意義上的重復(fù)記錄,一是完全重復(fù)的記錄,也即所有字段均重復(fù)的記錄,二是部分關(guān)鍵字段重復(fù)的記錄,比如Name字段重復(fù),而其他字段不一定重復(fù)或都重復(fù)可以忽略。
1、對于第一種重復(fù),比較容易解決,使用 select distinct * from tableName 就可以得到無重復(fù)記錄的結(jié)果集。 如果該表需要刪除重復(fù)的記錄(重復(fù)記錄保留1條),可以按以下方法刪除 select distinct * into #Tmp from tableName drop table tableName select * into tableName from #Tmp drop table #Tmp 發(fā)生這種重復(fù)的原因是表設(shè)計不周產(chǎn)生的,增加唯一索引列即可解決。
2、這類重復(fù)問題通常要求保留重復(fù)記錄中的第一條記錄,操作方法如下假設(shè)有重復(fù)的字段為Name,Address,要求得到這兩個字段唯一的結(jié)果集 select identity(int,1,1) as autoID, * into #Tmp from tableName select min(autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID select * from #Tmp where autoID in(select autoID from #tmp2) 最后一個select即得到了Name,Address不重復(fù)的結(jié)果集(但多了一個autoID字段,實際寫時可以寫在select子句中省去此列) 2003-11-25 13:15:26 SQL SERVER 2000 數(shù)據(jù)庫備份與恢復(fù)單元 unit BackRestoreSQLDB; {描述:SQL SERVER 2000 數(shù)據(jù)庫備份與恢復(fù)單元 ,本單元函數(shù)在SQL SERVER 2000 +Delphi7.0編譯通過 時間:2003.09.15 作者:chenshaizi } interface
uses adodb, db; function repl_substr(sub_old, sub_new, s: string): string; //把sub_old換成sub_new,后面有用。 function BackupSQLDataBase(connstr_sql, DatabaseName, Backup_FileName: string): Boolean; //數(shù)據(jù)庫備份函數(shù) //SQL數(shù)據(jù)數(shù)據(jù)庫備份,connstr_sql是ADO控件的connectionstring,DatabaseName是數(shù)據(jù)庫名稱, //Backup_FileName要備份到的目 標(biāo)文件 function RestoreSQLDataBase(connstr_sql, DatabaseName, Restore_FileName: string): Boolean; //數(shù)據(jù)庫恢復(fù)函數(shù) //Restore_FileName以前備份的數(shù)據(jù)庫文件, implementation
function repl_substr(sub_old, sub_new, s: string): string; var i: integer; begin repeat i := pos(sub_old, s); if i > 0 then begin delete(s, i, Length(sub_old)); insert(sub_new, s, i); end; until i < 1; Result := s; end;
function BackupSQLDataBase(connstr_sql, DatabaseName, Backup_FileName: string): Boolean; var //備份SQL數(shù)據(jù)庫SQL數(shù)據(jù)數(shù)據(jù)庫備份,connstr_sql是ADO控件的connectionstring,DatabaseName是數(shù)據(jù)庫名稱, //Backup_FileName要備份到的目標(biāo)文件 aADOQuery: TADOQuery; begin try aADOQuery := TADOQuery.Create(nil); aADOQuery.Close; aADOQuery.ConnectionString := connstr_sql; aADOQuery.SQL.Clear; aADOQuery.SQL.Add('backup database ' + DatabaseName + ' to disk = ' + '''' + Backup_FileName + ''' with format'); try aADOQuery.ExecSQL; Result := true; except Result := false; exit; end; finally aADOQuery.Free; end; end;
function RestoreSQLDataBase(connstr_sql, DatabaseName, Restore_FileName: string): Boolean; var //數(shù)據(jù)庫恢復(fù)函數(shù),estore_FileName以前備份的數(shù)據(jù)庫文件 aADOQuery: TADOQuery; begin try aADOQuery := TADOQuery.Create(nil); aADOQuery.Close; //恢復(fù)數(shù)據(jù)庫不能打開數(shù)據(jù)庫,要打開系統(tǒng)數(shù)據(jù)庫master,把連接字符串如adoconnetion的connectionstring中的數(shù)據(jù)庫名稱換成"master"數(shù)據(jù)庫 aADOQuery.ConnectionString := repl_substr(DatabaseName, 'master', connstr_sql); aADOQuery.SQL.Clear; aADOQuery.SQL.Add('RESTORE DATABASE ' + DatabaseName + ' from disk = ' + '''' + Restore_FileName + ''''); try aADOQuery.ExecSQL; Result := true; except Result := false; exit; end; finally aADOQuery.Free; end; end; end. 2003-11-25 13:17:15 不用控件,通過ADO對象連接sqlserver數(shù)據(jù)庫 關(guān)鍵詞:ADO連接sqlserver數(shù)據(jù)庫 uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,comobj, Db, ADODB;
//要伸明comobj 下面為連接代碼:
var adoc,ador:variant; begin adoc:=createoleobject('adodb.connection'); adoc.open('Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=customer;Data Source=BERN'); ador:=createoleobject('adodb.recordset'); ador.activeconnection:=adoc; ador.CursorType:=ctDynamic; ador.open('select * from t_customer',adoc); end; 2003-11-25 13:28:58 存取JPEG文件到SQLSERVER數(shù)據(jù)庫【王大川(WDCZZH)】 【關(guān)鍵詞】:JPEG圖片圖像數(shù)據(jù)庫 最近在CSDN上看到兩篇關(guān)于《DELPHI中存取JPEG文件到SQLSERVER》中的文章之后,覺得其中講述的方法雖然有可取之處,但頗費(fèi)時,我這里有更簡單的操作方法,而且安全可靠,不敢一人獨(dú)享,愿發(fā)布出來與大家共享。在Delphi7.0+Win2000+SqlServer 2000中測試通過,運(yùn)行良好,現(xiàn)將思路、源碼公開如下:
【解決思路】: 1、 關(guān)鍵在于將打開的JPEG文件動態(tài)轉(zhuǎn)換為Tbitmap對象并顯示在Timage對象中; 2、 將顯示的圖片提交到數(shù)據(jù)庫中。
本例中在SQLSERVER2000中建立了一個試?yán)恚篹xam(xm char(10),photo image); 程序源代碼:
unit SavePic;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtDlgs, ExtCtrls, DBCtrls, Grids, DBGrids, DB, ADODB, Buttons, StdCtrls,Jpeg;
type TForm1 = class(TForm) SpeedButton1: TSpeedButton; ADOConnection1: TADOConnection; Table1: TADOTable; DataSource1: TDataSource; DBGrid1: TDBGrid; DBImage1: TDBImage; Image1: TImage; SpeedButton2: TSpeedButton; OpenPictureDialog1: TOpenPictureDialog; Label1: TLabel; Label2: TLabel; Edit1: TEdit; SpeedButton3: TSpeedButton; procedure SpeedButton2Click(Sender: TObject); procedure SpeedButton1Click(Sender: TObject); procedure SpeedButton3Click(Sender: TObject); private { Private declarations } public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.SpeedButton2Click(Sender: TObject); var bmp1:TBitmap; jpg1:TJpegImage; begin OpenPictureDialog1.DefaultExt:=GraphicExtension(TJpegimage); if OpenPictureDialog1.Execute then begin bmp1:=TBitmap.Create; jpg1:=TJpegImage.Create; try jpg1.LoadFromFile(OpenPictureDialog1.FileName); bmp1.Assign(jpg1); Image1.Picture.Bitmap.Assign(bmp1); finally jpg1.Free; bmp1.Free; end; end; end;
procedure TForm1.SpeedButton1Click(Sender: TObject); begin table1.Open; table1.insert; table1.fieldbyname('xm').asstring:=Edit1.Text; table1.FieldByName('photo').Assign(Image1.Picture); table1.post; table1.Refresh; end;
end.
以上就是將JPEG存取到SQLSERVER中的操作方法,本文在此僅是拋磚引玉,希望各位朋友舉一反三想出更多、更好、更實用的應(yīng)用技術(shù)。 另外原來那兩篇《DELPHI中存取JPEG文件到SQLSERVER》暫時沒有找到。。。 2003-11-25 16:41:42 多個 Edit 的 SQL 查詢 問:關(guān)于判斷的問題:假如在form1里有Edit1、Edit2和Edit3,如果是查詢,有7種情況: (1)、當(dāng)Edit1不為空,而其它兩個為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field1=:field1'); Parambyname('field1').AsString:=Edit1.text; Open; end; (2)、當(dāng)Edit2不為空,而其它兩個為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field2=:field2'); Parambyname('field2').AsString:=Edit2.text; Open; end; (3)、當(dāng)Edit3不為空,而其它兩個為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field3=:field3'); Parambyname('field3').AsString:=Edit3.text; Open; end; (4)、當(dāng)Edit1和Edit2不為空,Edit3為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field1=:field1 and field2=:field2'); Parambyname('field1').AsString:=Edit1.text; Parambyname('field2').AsString:=Edit2.text; Open; end; (5)、當(dāng)Edit1和Edit3不為空,Edit2為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field1=:field1 and field3=:field3'); Parambyname('field1').AsString:=Edit1.text; Parambyname('field3').AsString:=Edit2.text; Open; end; (6)、當(dāng)Edit2和Edit3不為空,Edit1為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field2=:field2 and field3=:field3'); Parambyname('field2').AsString:=Edit1.text; Parambyname('field3').AsString:=Edit2.text; Open; end; (7)、當(dāng)Edit1、Edit2和Edit3都不為空: with query1 do begin close; sql.clear; sql.add('select * from fstao where field1=:field1 and field2=:field2 and field3=:field3'); Parambyname('field2').AsString:=Edit1.text; Parambyname('field3').AsString:=Edit2.text; Parambyname('field1').AsString:=Edit2.text; Open; end; 編程的時候,那么就逐個逐個判斷,有3個Edit就有7種情況,那么4個、5個Edit時,那么分別有14種和25種情況,那就很麻煩,如果是逐個判斷的話那么就得寫一兩萬行代碼,而且很煩。我想請教有沒有更好的方法,比如自由判斷。數(shù)據(jù)庫為Oracle8。 【答1】:你可以這樣做: query1.sql.add (' select * from table1 where '); if edit1.text<>'' then begin query1.sql.add ('field1:field1'); Parambyname('field1').AsString:=Edit1.text; end; ....... if edit9.text<>'' then begin query1.sql.add ('field9:field9'); Parambyname('field9').AsString:=Edit9.text; end; ..............
【答2】:我是這么干的: var SQLCondition:string; FirstConjunction:string; begin FirstConjunction := 'WHERE '; if Edit1.Text <> '' then begin SQLCondition := FirstConjunction + '(FieldName1="'+Edit1.Text + '")'; FirstConjunction := 'AND '; end; if Edit2.Text <> '' then begin SQLCondition := FirstConjunction + '(FieldName2="'+Edit2.Text + '")'; FirstConjunction := 'AND '; end;
.......
if Editn.Text <> '' then begin SQLCondition := FirstConjunction + '(FieldNamen="'+Editn.Text + '")'; FirstConjunction := 'AND '; end; sql.clear; sql.Add('SELECT * FROM DATABASE'); sql.Add(SQLCondition); open;
【答3】:用不著這么麻煩吧... 我是這么干的: begin sql.clear; sql.Add('SELECT * FROM DATABASE'); if Edit1.Text <> '' then sql.Add('(FieldName1="'+Edit1.Text + '") and '; if Edit2.Text <> '' then sql.Add('(FieldName2="'+Edit2.Text + '") and ';
.......
if Edit9.Text <> '' then sql.Add('(FieldName9="'+Edit9.Text + '") and '; if Pos(sql.Lines[1],'and')>0 then Delete(sql.Lines[1],Length(sql.Lines[1]-4),3); open; end; 2003-11-25 16:51:16 從 Foxpro 到 SQL Server 的數(shù)據(jù)轉(zhuǎn)移方法 在計算機(jī)應(yīng)用系統(tǒng)的軟件升級改造過程中,我們經(jīng)常遇到這樣一個問題:老系統(tǒng)的數(shù)據(jù)庫平臺與新系統(tǒng)不同。例如,老系統(tǒng)的數(shù)據(jù)庫平臺是 Foxpro, 而新系統(tǒng)的平臺是 SQL Server。 而且,我們需要把舊的數(shù)據(jù)庫應(yīng)用系統(tǒng)中的一些數(shù)據(jù)轉(zhuǎn)移到新系統(tǒng)來。但是因為新老系統(tǒng)在定義數(shù)據(jù)類型、數(shù)據(jù)格式等方面的差異,就很難用人工錄入的方法來實現(xiàn)。因此,需要有一個能實現(xiàn)這種功能的程序。
本文利用 Borland Delphi 實現(xiàn)了這個轉(zhuǎn)移過程。
基本思想是:在一個 Form 中,分別用兩個 TDatabase 控件連接新老數(shù)據(jù)庫。并采用TTable、TDbGrid 作為數(shù)據(jù)轉(zhuǎn)移的中心,根據(jù) DbGrid 中的數(shù)據(jù)生成標(biāo)準(zhǔn)的 SQL 插入語句。這樣,就實現(xiàn)了從一個數(shù)據(jù)庫系統(tǒng)到另一個數(shù)據(jù)庫系統(tǒng)的數(shù)據(jù)轉(zhuǎn)移。在這里,采用 TTable、TDbGrid 作為數(shù)據(jù)轉(zhuǎn)移的中心是一個技巧,因為:TTable 的 Fields 屬性能指示出某字段的字段名稱、數(shù)據(jù)類型等,這為數(shù)據(jù)轉(zhuǎn)移過程中的 Insert 語句的生成及數(shù)據(jù)類型轉(zhuǎn)換提供了依。
下面的例子展示了從 Foxpro 到 SQL Server 的數(shù)據(jù)轉(zhuǎn)移方法。至于其他系統(tǒng)間的數(shù)據(jù)轉(zhuǎn)移,只要根據(jù)目標(biāo)系統(tǒng)的數(shù)據(jù)定義要求,修改相應(yīng)的 Insert 語句。
---- 程 序 代 碼 如 下:
unit ConvertDBF;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, DBTables, Db, Grids, DBGrids;
type TfrmConvertDB = class(TForm) btnOK: TButton; Label1: TLabel; db1: TDatabase; {用于連接老數(shù)據(jù)庫系統(tǒng)} db2: TDatabase; {用于連接新數(shù)據(jù)庫系統(tǒng)} dbg: TDBGrid; tblSource: TTable; {dbg的Datasource} qryInsert: TQuery; {用于存放生成的SQL Insert語句} srcSource: TDataSource; tblDest: TTable; {DBGrid1的Datasource} DBGrid1: TDBGrid; srcDest: TDataSource; edFromtbl: TEdit; Label2: TLabel; Label3: TLabel; edToTbl: TEdit; procedure btnOKClick(Sender: TObject); private { Private declarations } public { Public declarations } end;
var frmConvertDB: TfrmConvertDB;
implementation
{$R *.DFM}
procedure TfrmConvertDB.btnOKClick (Sender: TObject); var iField :integer; begin if ((edTotbl.text<>'') and (edFromtbl.text<>''))then begin tblSource.TableName:=edFromtbl.text; {指定TableName} tblDest.TableName:=edTotbl.text; with tblSource do begin Open; {打開老系統(tǒng)的表} while EOF=FALSE do begin {逐條記錄處理} qryInsert.SQL.Clear; qryInsert.sql.Add('Insert into '+edTotbl.text + '('); for iField:=0 to dbg.FieldCount-1 do begin qryInsert.sql.add(dbg.Fields[iField].DisplayLabel); if iField<>dbg.FieldCount-1 then qryInsert.sql.add(','); end; qryInsert.sql.add(') values('); for iField:=0 to dbg.FieldCount-1 do begin {進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換} if dbg.fields[iField].DataType=ftInteger then qryInsert.sql.add(inttostr(dbg.fields[iField].asInteger)); if dbg.fields[iField].DataType=ftFloat then qryInsert.sql.add(floattostr(dbg.fields[iField].asFloat)); if dbg.fields[iField].DataType=ftDate then qryInsert.sql.add(''''+datetostr(dbg.fields[iField].asDateTime)+''''); if dbg.fields[iField].DataType=ftString then begin if dbg.fields[iField].asString<>'' then qryInsert.sql.add(''''+dbg.fields[iField].asString+'''') else qryInsert.sql.add('NULL'); end; if iField<>dbg.FieldCount-1 then qryInsert.sql.add(','); end; qryInsert.sql.add(')'); qryInsert.ExecSQL; {把數(shù)據(jù)插入到新系統(tǒng)的表中} next; end; end; tblDest.Close; tblDest.Open;; ShowMessage(' 轉(zhuǎn)換完畢! '); end else ShowMessage ('請輸入要插入數(shù)據(jù)的表的名稱 '); end;
end. 2003-11-25 17:01:50 Delphi數(shù)據(jù)集過濾技巧 當(dāng)我們在操作數(shù)據(jù)集時,往往需要對數(shù)據(jù)進(jìn)行篩選。例如:一個名為Customer的數(shù)據(jù)表,它具有 CustNo、CustName、Country、Address、Phone、State、TaxRate 等字段,如果只想查看國別為China或顧客號大于1000的顧客記錄,就需要對數(shù)據(jù)集進(jìn)行過濾。經(jīng)總結(jié),有下面這些過濾方法:
一、利用Ttable和Tquery的Filter屬性 1.在設(shè)計時設(shè)置Filter屬性 例如,設(shè)置Filter為:Country=′China′ 然后改變Filtered屬性為True(注意,F(xiàn)iltered為True時過濾才有效)。則只能看到對應(yīng)的 Country字段內(nèi)容為‘China’的記錄。 設(shè)置Filter時可以使用的操作符有:<、>、<=、>=、=、<>、AND、OR、NOT。 例如,設(shè)置Filter為:CustNo>=1000 and CustNo<=5000,則只能看到顧客號在1000與5000之間的顧客記錄。 2.在程序運(yùn)行期間進(jìn)行動態(tài)過濾 要在程序運(yùn)行時改變Filter屬性,這包括兩種情況: (1)操作符右邊為常量,例如: Table1Filter:=′State′+′=′+′′′HI′′′; 注意:字符串常量必須用三對單引號括起來。 (2)操作符右邊不為常量,可能是通過一個變量指定的值,或由一輸入框給出的值。這時需要用到Format函數(shù)。其代碼形式為: Table1Filter:=Format(′State′+′=′+′′′%S′′′,[StateValue]); 其中StateValue為已經(jīng)賦值的一個字符串變量,也可以為其他形式,例如:Edit1Text。
二、用ApplyRange篩選數(shù)據(jù)集的記錄 執(zhí)行下面這段代碼,將只能看到顧客號在1000至5000之間的顧客記錄。組成該例程的幾個過 程為:ApplyRange,SetRangeStart,SetRangeEnd。 Table1SetRangeStart; Table1[′CustNo′]:=1000; Table1SetRangeEnd; Table1[′CustNo′]:=5000; Table1ApplyRange; 注意:該過程只適用于索引的字段。如果想基于非索引字段篩選,則不妨使用一點(diǎn)小花招: 建立假索引。實現(xiàn)的方法為: Table1IndexFieldNames:=字段名; Delphi還提供了簡單的調(diào)用SetRangeStart、SetRangeEnd和ApplyRange的方法,例如:Table1SetRange([Edit1Text],[Edit2Text]);
三、用OnFilterRecord事件篩選 OnFilterRecord事件允許按非鍵控字段建立篩選程序,例如: procedure TForm1Table1FilterRecord(DataSet:TDataSet;var Accept:Boolean); begin Accept:=DataSet[′State′]=′CA′; end;
四、用Tquery控件的SQL語句 1.SQL語句中不包含變量和參數(shù) Select*from Customer Where CustNo>=1000 and CustNo<=5000 2.SQL語句中包含參數(shù) Select*from Customer Where CustNo>=:CustNo 在運(yùn)行期間給參數(shù)CustNo賦值。 3.SQL語句中包含變量 這時向Tquery控件添加SQL語句的代碼應(yīng)當(dāng)這樣寫: Query1Close; Query1SQLClear; Query1SQLAdd(Format(′Select*from Customer′+′′+′ where State=′+′′′%S′′′,[StateValue])); Query1O(jiān)pen; 在上面的四種方法中,第四種功能最強(qiáng)大,使用最靈活。 2003-11-25 17:06:12 建立臨時表 數(shù)據(jù)輸入是開發(fā)數(shù)據(jù)庫程序的必然環(huán)節(jié)。在Client/Server結(jié)構(gòu)中,客戶端可能要輸入一批數(shù)據(jù)后,再向服務(wù)器的后臺數(shù)據(jù)庫提交,這就需要在本地(客戶端)建立臨時數(shù)據(jù)表來存儲用戶輸入的數(shù)據(jù),待提交后,清除本地表數(shù)據(jù)。這種方法的好處是:提高輸入效率,減小網(wǎng)絡(luò)負(fù)擔(dān)。 由于用戶一次輸入的數(shù)據(jù)量一般情況下較小(不會超過幾百條記錄),所以臨時表可以建立 在內(nèi)存中,這樣處理速度較快。
方法1:使用查詢控件(TQuery) 第1步:在窗體上放上查詢控件(TQuery),設(shè)置好所連接的數(shù)據(jù)表。 第2步:使TQuery. CachedUpdates=True; TQuery. RequestLive=True 第3步:在原有的SQL語句后加入一條Where子語句,要求加入這條Where子語句后SQL查詢結(jié)果為空。 例如:
SELECT Biolife.″Species No″, Category, Common_Name, Biolife.″Species Name″, Biolife.″Length (cm)″, Length_In, Notes, Graphic FROM ″biolife.db″ Biolife where Biolife.Category=′A′ and Biolife.Category=′B′
這樣臨時表就建立完成了。
方法2:使用代碼創(chuàng)建臨時表 代碼如下:
function CreateTableInMemory(const AFieldDefs:TFieldDefs): TDataSet; var TempTable:TClientDataSet; begin TempTable:=nil; Result:=nil; if AFieldDefs<>nil then begin try TempTable:=TClientDataSet.Create(Application); TempTable.FieldDefs.Assign(AFieldDefs); TempTable.CreateDataSet; Result:=(TempTable as TDataSet); Except if TempTable<>nil then TempTable.Free; Result:=nil; raise; end end end;
在程序中按如下方法使用:
procedure TForm1.Button1Click(Sender: TObject); var ADataSet:TDataSet; begin ADataSet:=TDataSet.Create(Self); with ADataSet.FieldDefs do begin Add(′Name′,ftString,30,False); Add(′Value′,ftInteger,0,False); end; with DataSource1 do begin DataSet:=CreateTableInMemory(ADataSet.FieldDefs); DataSet.Open; end; ADataSet.Free; end;
臨時表創(chuàng)建完成。
方法1使用簡單,但由于利用查詢控件,清空數(shù)據(jù)時需要查詢服務(wù)器后臺數(shù)據(jù)庫,所以速度稍慢,而且不適用于臨時表中各個字段由數(shù)個數(shù)據(jù)表的字段拼湊而成的情況。方法2適用范圍廣、速度快,但需要編寫代碼。(代碼中TFieldDefs的使用方法十分簡單,見Delphi的聯(lián)機(jī)幫助)。 2003-11-25 17:08:31 Delphi中多庫關(guān)聯(lián)查詢 在我們對數(shù)據(jù)庫進(jìn)行操作時,經(jīng)常用到TTable控件,但TTable只能同時對一個數(shù)據(jù)表進(jìn)行操 作,而TQuery控件不僅具有TTable的多數(shù)功能,而且同時可對多個數(shù)據(jù)表進(jìn)行操作。不僅如此, TQuery控件還有更強(qiáng)大的數(shù)據(jù)庫查詢功能,可以同時對多個不同結(jié)構(gòu)的數(shù)據(jù)庫進(jìn)行關(guān)聯(lián)查詢,被 查詢的數(shù)據(jù)庫可以是ODBC支持的任何一種類型,當(dāng)然計算機(jī)中必須先安裝ODBC和BDC(Delphi的數(shù) 據(jù)庫引擎),現(xiàn)舉例說明。
一、連接Paradox和dBASE進(jìn)行異庫查詢 例如:Master.db和Customer.dbf分別為Paradox和dBASE的數(shù)據(jù)庫,它們有一個公共字段 CustNo。這時可輸入如下代碼: Query1.Close; Query1.DataBaseName:=′′; Query1.SQL.Clear; Query1.SQL.Add(′Select * from ″Master.db″ A,″Customer.dbf ″ B Where A.CustNo=B.CustNo′);{在同一行內(nèi)輸入} Query1.Open; 注意:進(jìn)行多庫聯(lián)查時,TQuery控件的DataBaseName屬性必須先置空,單引號內(nèi)不包含任何 字符;A和B分別是Master.db和Customer.dbf的別名(引用別名可減少代碼長度)。
二、MS Access的多表聯(lián)查 Access數(shù)據(jù)庫屬于多表集合數(shù)據(jù)庫(一個數(shù)據(jù)庫中包含多個數(shù)據(jù)表),所以,對兩個Access數(shù) 據(jù)庫進(jìn)行查詢的方法就與上述有所不同。例如:我們有RSDA.mdb和ZFGjj.mdb兩個數(shù)據(jù)庫,RSDA中包含人事檔案、在職職工目錄和離職職工目錄等數(shù)據(jù)表,ZFGjj通過公共字段“用戶號”與RSDA相連。如果我們從ZFGjj中提取一個用戶號,需要從RSDA中得到擁有此用戶號的職工姓名,這時就必須用到TQuery的多表查詢。 第一步 在ODBC中增加兩個數(shù)據(jù)源“ZFGjj”和“RSDA”。 第二步 在BDE數(shù)據(jù)庫引擎中添加兩個數(shù)據(jù)庫列名“ZFGjj”和“RSDA”。 第三步 在表單中增加兩個DataBase控件“DataBase1”和“DataBase2”,在AliasName屬性 中分別選擇“ZFGjj”和“RSDA”,DataBaseName屬性中分別鍵入“ZFGjj”和“RSDA”,最后將 KeepConnection和Connected屬性都設(shè)為“True”。
現(xiàn)在可以輸入相應(yīng)的代碼了: Begin For I:=1 To 10 Do Begin Query1.Close; Query1.DataBaseName:=′′; Query1.Sq1.Clear; Query1.Sq1.Add(′Select A.七月,B.個人賬號,B.用戶號,C.姓名From“:ZFGjj:個人匯激部門表”A,“:ZFGjj:住房公積金明細(xì)表”B,“:RSDA:在職職工目錄”C Where(A.用戶號=B.封存=:ib)′);{在同一行輸入} Query1.Prepare; Query1.Params[0].DataType.=ftInteger; Query1.Params[1].DataType.=ftBoolean; Query1.Params[0].Asinteger:=ia[I]; Query1.Params[1].Asboolean:=ib; Query1.Open; End; End;
代碼中SQL語句必須在一行內(nèi)輸入,不能分行。SQL語句中使用了動態(tài)參數(shù)“ia”和“ib”, Delphi會自動按參數(shù)出現(xiàn)的順序?qū)⑺鼈兲砑釉赒uery1的Params屬性中并分配索引號分別為0和1, 參數(shù)“ia”和“ib”應(yīng)在程序開始時聲明其類型并賦值。 |