我們現在回到函數上。記得我們用 SUM 這個指令來算出所有的 Sales (營業額)吧!如果我們的需求變成是要算出每一間店 (store_name) 的營業額 (sales),那怎么辦呢?在這個情況下,我們要做到兩件事:第一,我們對于 store_name 及 Sales 這兩個欄位都要選出。第二,我們需要確認所有的 sales 都要依照各個 store_name 來分開算。這個語法為:
SELECT "欄位1", SUM("欄位2")
FROM "表格名"
GROUP BY "欄位1"
在我們的示范上,
Store_Information 表格
store_name |
Sales |
Date |
Los Angeles |
$1500 |
Jan-05-1999 |
San Diego |
$250 |
Jan-07-1999 |
Los Angeles |
$300 |
Jan-08-1999 |
Boston |
$700 |
Jan-08-1999 |
我們就打入,
SELECT store_name, SUM(Sales)
FROM Store_Information
GROUP BY store_name
結果:
store_name |
SUM(Sales) |
Los Angeles |
$1800 |
San Diego |
$250 |
Boston |
$700 |
當我們選不只一個欄位,且其中至少一個欄位有包含函數的運用時,我們就需要用到 GROUP BY 這個指令。在這個情況下,我們需要確定我們有 GROUP BY 所有其他的欄位。換句話說,除了有包括函數的欄位外,我 們都需要將其放在 GROUP BY 的子句中。
冒泡排序:
/*
* 冒泡排序:
*/
public static void sort(int[] data) {
for (int i = 0; i < data.length; i++) {
for (int j = data.length - 1; j > i; j--) {
if (data[j] < data[j - 1]) {
int tmp = data[j];
data[j] = data[j-1];
data[j-1] = tmp;
}
}
}
}
之前我們看到的左連接 (left join),又稱內部連接 (inner join)。在這個情況下,要兩個表格內都有同樣的值,那一筆資料才會被選出。那如果我們想要列出一個表格中每一筆的資料,無論它的值在另一個表格中有沒有出現,那該怎么辦呢?在這個時候,我們就需要用到 SQL OUTER JOIN (外部連接) 的指令。
外部連接的語法是依數據庫的不同而有所不同的。舉例來說,在 Oracle 上,我們會在 WHERE 子句中要選出所有資料的那個表格之后加上一個 "(+)" 來代表說這個表格中的所有資料我們都要。
假設我們有以下的兩個表格:
Store_Information 表格
store_name |
Sales |
Date |
Los Angeles |
$1500 |
Jan-05-1999 |
San Diego |
$250 |
Jan-07-1999 |
Los Angeles |
$300 |
Jan-08-1999 |
Boston |
$700 |
Jan-08-1999 |
|
Geography 表格
region_name |
store_name |
East |
Boston |
East |
New York |
West |
Los Angeles |
West |
San Diego |
|
我們需要知道每一間店的營業額。如果我們用一個普通的連接,我們將會漏失掉 'New York'這個店,因為它并不存在于 Store_Information 這個表格。所以,在這個情況下,我們需要用外部連接來串聯這兩個表格:
SELECT A1.store_name, SUM(A2.Sales) SALES
FROM Georgraphy A1, Store_Information A2
WHERE A1.store_name = A2.store_name (+)
GROUP BY A1.store_name
我們在這里是使用了 Oracle 的外部連接語法。
如果換成了Mysql:
select a1.store_name,sum(a2.sales) from geography a1 left join store_information a2
on a1.store_name=a2.store_name group by a1.store_name;
結果:
store_name |
SALES |
Boston |
$700 |
New York |
|
Los Angeles |
$1800 |
San Diego |
$250 |
請注意: 當第二個表格沒有相對的資料時,SQL 會傳回 NULL 值。在這一個例子中, 'New York' 并不存在于 Store_Information 表格,所以它的 "SALES" 欄位是 NULL。
在之前,我對MSSQL中的內連接和外連接所得出的數據集不是很清楚。這幾天重新溫習了一下SQL的書本,現在的思路應該是很清楚了,現在把自己的理解發出來給大家溫習下。希望和我一樣對SQL的連接語句不太理解的朋友能夠有所幫助。(發這么菜的教程,各位大大們別笑話偶了,呵:D )
有兩個表A和表B。
表A結構如下:
Aid:int;標識種子,主鍵,自增ID
Aname:varchar
數據情況,即用select * from A出來的記錄情況如下圖1所示:
圖1:A表數據
表B結構如下:
Bid:int;標識種子,主鍵,自增ID
Bnameid:int
數據情況,即用select * from B出來的記錄情況如下圖2所示:
圖2:B表數據
為了把Bid和Aid加以區分,不讓大家有誤解,所以把Bid的起始種子設置為100。
有SQL基本知識的人都知道,兩個表要做連接,就必須有個連接字段,從上表中的數據可以看出,在A表中的Aid和B表中的Bnameid就是兩個連接字段。
下圖3說明了連接的所有記錄集之間的關系:
圖3:連接關系圖
現在我們對內連接和外連接一一講解。
1.內連接:利用內連接可獲取兩表的公共部分的記錄,即圖3的記錄集C
語句如下:Select * from A JOIN B ON A.Aid=B.Bnameid
運行結果如下圖4所示:
圖4:內連接數據
其實select * from A,B where A.Aid=B.Bnameid與Select * from A JOIN B ON A.Aid=B.Bnameid的運行結果是一樣的。
2.外連接:外連接分為兩種,一種是左連接(Left JOIN)和右連接(Right JOIN)
(1)左連接(Left JOIN):即圖3公共部分記錄集C+表A記錄集A1。
語句如下:select * from A Left JOIN B ON A.Aid=B.Bnameid
運行結果如下圖5所示:
圖5:左連接數據
說明:
在語句中,A在B的左邊,并且是Left Join,所以其運算方式為:A左連接B的記錄=圖3公共部分記錄集C+表A記錄集A1
在圖3中即記錄集C中的存在的Aid為:2 3 6 7 8
圖1中即表A所有記錄集A中存在的Aid為:1 2 3 4 5 6 7 8 9
表A記錄集A1中存在的Aid=(圖1中即A表中所有Aid)-(圖3中即記錄集C中存在的Aid),最終得出為:1 4 5 9
由此得出圖5中A左連接B的記錄=圖3公共部分記錄集C+表A記錄集A1,
最終得出的結果圖5中可以看出Bnameid及Bid非NULL的記錄都為圖3公共部分記錄集C中的記錄;Bnameid及Bid為NULL的Aid為1 4 5 9的四筆記錄就是表A記錄集A1中存在的Aid。
(2)右連接(Right JOIN):即圖3公共部分記錄集C+表B記錄集B1。
語句如下:select * from A Right JOIN B ON A.Aid=B.Bnameid
運行結果如下圖6所示:
圖6:右連接數據
說明:
在語句中,A在B的左邊,并且是Right Join,所以其運算方式為:A右連接B的記錄=圖3公共部分記錄集C+表B記錄集B1
在圖3中即記錄集C中的存在的Aid為:2 3 6 7 8
圖2中即表B所有記錄集B中存在的Bnameid為:2 3 6 7 8 11
表B記錄集B1中存在的Bnameid=(圖2中即B表中所有Bnameid)-(圖3中即記錄集C中存在的Aid),最終得出為:11
由此得出圖6中A右連接B的記錄=圖3公共部分記錄集C+表B記錄集B1,
最終得出的結果圖6中可以看出Aid及Aname非NULL的記錄都為圖3公共部分記錄集C中的記錄;Aid及Aname為NULL的Aid為11的記錄就是表B記錄集B1中存在的Bnameid。
總結:
通過上面的運算解說,相信很多人已經想到,上面的情況(包括圖3的關系圖)說明的都只是A在B的左邊的情況,
以下語句B在A的右邊的又會出現什么情況呢??
select * from B Left JOIN A ON A.Aid=B.Bnameid
select * from B Right JOIN A ON A.Aid=B.Bnameid
其實對圖3左右翻轉一下就可以得出以下結論:
select * from B Left JOIN A ON A.Aid=B.Bnameid和select * from A Right JOIN B ON A.Aid=B.Bnameid所得出的記錄集是一樣的
而
select * from B Right JOIN A ON A.Aid=B.Bnameid和select * from A Left JOIN B ON A.Aid=B.Bnameid所得出的記錄集也是一樣的。
import java.io.*;
public class DOMTest {
private String outFile = "c:\\people.xml";
public static void main(String args[]) {
new DOMTest();
}
public DOMTest() {
try {
javax.xml.parsers.DocumentBuilder builder =
javax.xml.parsers.DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
org.w3c.dom.Document doc = builder.newDocument();
org.w3c.dom.Element root = doc.createElement("老師");
org.w3c.dom.Element wang = doc.createElement("王");
wang.appendChild(doc.createTextNode("我是王老師"));
root.appendChild(wang);
doc.appendChild(root);
javax.xml.transform.Transformer transformer = javax.xml.transform.TransformerFactory
.newInstance().newTransformer();
transformer.setOutputProperty(
javax.xml.transform.OutputKeys.ENCODING, "gb2312");
transformer.setOutputProperty(
javax.xml.transform.OutputKeys.INDENT, "yes");
transformer.transform(new javax.xml.transform.dom.DOMSource(doc),
new
javax.xml.transform.stream.StreamResult(outFile));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
public class Aqiang {
// 靜態內部類
static class Test
{
private int i ;
public Test()
{
i = 2;
}
}
class TestB
{
private int i = 3;
}
private int j;
public static void main(String args[]) {
// 靜態內部類(Inner Class)意味著1創建一個static內部類的對象,不需要一個外部類對象
Aqiang.Test test = new Aqiang.Test();
System.out.println("test" + test.i);
// 而非靜態內部類,需要選創建一個外部類對象,然后才能創建內部內對象
Aqiang aqiang = new Aqiang();
Aqiang.TestB tb = aqiang.new TestB();
System.out.println("testb" + tb.i);
}
}
流是一個有序的字節序列,可作為一個輸入源,也可作為一個輸出的目的地。
字節流以字節為單位輸入輸出,字節流類名含有stream,字符流以字符為單位輸入輸出,字節流
類名含有reader或writer.為了通用性,java中字符是16位的unicode字符,所以8位的字節流必
須和16位的字符流進行轉換。字節流到字符流的轉換使用InputStreamReader類:
public InputStreamReader(InputStream in);
public InputStreamReader(InputStream in,String encoding);
public OuputStreamWriter(OnputStream in);
public OnputStreamWriter(OnputStream in,String encoding);
Reader和Writer類允許用戶在程序中無縫的支持國際字符集,如果要讀區的文件是別國語言,
要使用字符流。
JavaI/O字節流與字符流就是java 實現輸入/輸出 數據 字節流是一個字節一個字節的輸入/輸出 數據 (兩個字節組成一個漢字)所以在用字節流讀一串漢字時會出現亂碼問題,
同樣字符流是一個字符一個字符流(一個字符=兩個字節)的輸入/輸出 數據 用字符流讀一串漢字可以解決亂碼問題.
有以下三個對象:
US設備對象:USDevie
US設備類型對象:USDeviceModle
US設備端口對象:USDevicePort
class USDevice
{
....
// US設備類型
USDeviceModel model;
// US設備端口對象集合
Set<USDevicePort> devicePortSet = new HashSet();
}
/**
US設備類型說明每種設備都有不同的端口數目
*/
class USDeviceModel
{
....
// 設備端口數目
int deviceport;
}
class USDevicePort
{
private int deviceId;
private int devicePort;
}
1 : 1 : n
一種US設備(device)----->設備類型(model)------>不同數目的設備端口
US設備:設備類型:設備端口數目 = 1:1:n
所以,如果新增設備的時候,要根據設備類型,得到相應的設備端口數目,
然后在USDevicePort對應的數據庫表中插入記錄.
編輯設備的時候,如果編輯了US設備類型,則相應的設備端口就會改變,這種
情況除了更新USDevice對應的數據表中設備類型外,因為在USDevicePort表中
存放在以前設備類型的端口記錄,所以應該先刪除之前的端口記錄,然后再插入
現在類型所對應的端口記錄.
其實只需:
//這一步根據具體設備id,從數據庫中取出相應的設備對象
USDevice device = .....
// 得到US設備端口對象集合
Set devicePortSet = device.getDevicePortSet();
// 先清空以前所有的端口記錄
devicePortSet.clear();
// 根據編輯后類型ID,得到設備類型對象,并可以得到此種類型上的端口數目
USDeviceModel usModle = ....
// 根據上面得到的端口數據,構造"設備端口數目"對象,并把所有的設備端口對象添加到集合中
//最后更新US設備
這樣,每當編輯一個US設備的類型后,在設備端口表中,這種設備編輯之前的類型所對應的端口記錄
就會被刪除,而保持只有新的設備類型端口記錄.
注意在配置USDevice.hbm.xml文件時,要將<set name="devicePortSet " casecade="all-orphan-delete" .../>
因為它會將和USDevice沒有關聯的對象從數據中刪除,這也與程序中devicePortSet.clear()相對應.
看一看下面的很簡單的代碼,先是聲明了一個Hashtable和StringBuffer對象,然后分四次把StriingBuffer對象放入到Hashtable表中,在每次放入之前都對這個StringBuffer對象append()了一些新的字符串:
package reference;
import java.util.*;
public class HashtableAdd{
public static void main(String[] args){
Hashtable ht = new Hashtable();
StringBuffer sb = new StringBuffer();
sb.append("abc,");
ht.put("1",sb);
sb.append("def,");
ht.put("2",sb);
sb.append("mno,");
ht.put("3",sb);
sb.append("xyz.");
ht.put("4",sb);
int numObj=0;
Enumeration it = ht.elements();
while(it.hasMoreElements()){
System.out.print("get StringBufffer "+(++numObj)+" from Hashtable: ");
System.out.println(it.nextElement());
}
}
}
|
如果你認為輸出的結果是:
get StringBufffer 1 from Hashtable: abc,
get StringBufffer 2 from Hashtable: abc,def,
get StringBufffer 3 from Hashtable: abc,def,mno,
get StringBufffer 4 from Hashtable: abc,def,mno,xyz.
那么你就要回過頭再仔細看一看上一個問題了,把對象時作為入口參數傳給函數,實質上是傳遞了對象的引用,向Hashtable傳遞StringBuffer對象也是只傳遞了這個StringBuffer對象的引用!每一次向Hashtable表中put一次StringBuffer,并沒有生成新的StringBuffer對象,只是在Hashtable表中又放入了一個指向同一StringBuffer對象的引用而已。
對Hashtable表存儲的任何一個StringBuffer對象(更確切的說應該是對象的引用)的改動,實際上都是對同一個"StringBuffer"的改動。所以Hashtable并不能真正存儲能對象,而只能存儲對象的引用。也應該知道這條原則對與Hashtable相似的Vector, List, Map, Set等都是一樣的。
上面的例程的實際輸出的結果是:
/* RUN RESULT
get StringBufffer 1 from Hashtable: abc,def,mno,xyz.
get StringBufffer 2 from Hashtable: abc,def,mno,xyz.
get StringBufffer 3 from Hashtable: abc,def,mno,xyz.
get StringBufffer 4 from Hashtable: abc,def,mno,xyz.
*/
|
在做編輯功能 的時候,往往會通過一個主鍵ID得到相應的對象信息,然后顯示到編輯頁面中。如果涉及到<html:select>標簽,
表示點編輯的時候,選擇下拉框會顯示相應的選項。
JSP頁面一般這樣顯示:
<html:select property="busiSetId" style="width:120px;">
<option value="">請選擇</option>
<logic:present name="ret">
<logic:iterate id="model" name="ret">
<option value="<bean:write name="model" property="ID"/>"><bean:write name="model" property="name"/></option>
</logic:iterate>
</logic:present>
</html:select>
但這是樣子總是顯示第一條數據,解決這個問題最簡單的方法是在JSP頁面最后添加下面語句:
<script language="javascript">
document.all("busiSetId").value="<bean:write name='CustomerSetForm' property='busiSetId'/>";
</script>
因為這段代碼表示手動設置busiSetId元素,也就是<html:select>控件的值為要顯示的值,而且這個代碼是放到JSP最后面,
每次都會執行。
標簽嵌套使用注意事項:
<logic:equal value="<bean:write name='customer' property='cusId'/>" >
注意雙引號內只能使用單引號了。