楼主: oraclelang

MySQL中文參考手冊

[复制链接]
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
171#
 楼主| 发表于 2006-4-29 13:10 | 只看该作者
冊最新的TODO表版本。見F 我們想要在未來加入到MySQL的事情列表(TODO)。

5.4.1 子選擇
在MySQL中下列語句還不能工作:

SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
SELECT * FROM table1 WHERE id NOT IN (SELECT id FROM table2);

然而,在很多情況下,你可以重寫查詢,而不用子選擇:

SELECT table1.* FROM table1,table2 WHERE table1.id=table2.id;
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id where table2.id IS NULL

對于更複雜的子查詢,通常你可以創建臨時的表保存子查詢。然而在一些情況下,這種選擇將行不通。最經常遇到的情形是DELETE語句,對于它標准SQL不支持聯結(join)(除了在子選擇)。對于這種情況,有2個可用選擇,直到子選擇被MySQL支持。

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
172#
 楼主| 发表于 2006-4-29 13:10 | 只看该作者
第一個選擇是使用一種過程化的程序語言(例如Perl或PHP)來提交一個SELECT查詢獲得要被刪除記錄主鍵,並然後使用這些值構造DELETE語句(DELETE FROM ... WHERE ... IN (key1, key2, ...))。

第二個選擇是使用交互式SQL自動構造一套DELETE語句,使用MySQL擴展CONCAT()(代替標准||操作符)。例如:

SELECT CONCAT('DELETE FROM tab1 WHERE pkid = ', tab1.pkid, ';')
  FROM tab1, tab2
WHERE tab1.col1 = tab2.col2;

你可以把這個查詢放在一個腳本文件並且從它重定向輸入到mysql命令行解釋器,將其輸出作為管道返回給解釋器的第2個實例:

prompt> mysql --skip-column-names mydb < myscript.sql | mysql mydb

MySQL僅支持INSERT ... SELECT ...和REPLACE ... SELECT ...,獨立的子選擇將可能在3.24.0得到,然而,在其他環境下,你現在可以使用函數IN()。

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
173#
 楼主| 发表于 2006-4-29 13:10 | 只看该作者
5.4.2 SELECT INTO TABLE
MySQL還不支持Oracle SQL的擴展:SELECT ... INTO TABLE ....,相反MySQL支持ANSI SQL句法INSERT INTO ... SELECT ...,基本上他們是一樣的。

另外,你可使用SELECT INTO OUTFILE...或CREATE TABLE ... SELECT解決你的問題。

5.4.3 事務處理
不支持事務處理。MySQL將在短時間內支持原子(atomic)操作,它象沒有回卷的事務。用原子操作,你能執行一組INSERT/SELECT/whatever 命令並且保証沒有其他線程介入。在本文中,你通常不會需要回卷。目前,你可通過使用LOCK TABLES和UNLOCK TABLES命令阻止其他線程的幹擾。見7.24 LOCK TABLES/UNLOCK TABLES句法。

5.4.4 存儲過程和觸發器
一個存儲過程是能在服務器中編譯並存儲的一套SQL命令。一旦這樣做了,顧客不需要一直重新發出全部查詢,而可以參考存儲過程。因為查詢僅需一次詞法分析並且較少的信息需要在服務器和客戶之間傳送,因此這提供了更好的性能。你與可以通過擁有在服務器中的函數庫提升概念上的層次。

一個觸發器是當一個特別的事件發生時,被調用的一個存儲過程。例如,你可以安裝一個存儲過程,它在每次從一個交易表刪除一條記錄時觸發,並且當它所有交易被刪除時,自動地從一個客戶表中刪除相應的客戶。

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
174#
 楼主| 发表于 2006-4-29 13:10 | 只看该作者
5.4.5 外鍵
注意,在SQL中外鍵不用于聯結表,而主要用于檢查參考完整性(RI)。如果你想要得到用一個SELECT語句從多個表得到結果, 你通過聯結表做!

SELECT * from table1,table2 where table1.id = table2.id;

見7.13 JOIN句法。見8.3.5 使用外鍵。

在MySQL里存在FOREIGN KEY句法僅僅為了與其他SQL供應商的CREATE TABLE命令相兼容;它不做任何事情。沒有ON DELETE ...的FOREIGN KEY句法主要用于文檔目的。一些ODBC應用程序可以使用它自動生成WHERE子句,但是這通常很容易的覆蓋。 FOREIGN KEY有時用作一個約束檢查,但是如果行以正確的順序被插入表,該檢查實際上是不必要的。MySQL僅僅支持這些子句(不考慮是否他們工作!),因為一些應用程序要求他們存在。

在MySQL中,你可以解決ON DELETE ...沒被實現的問題,,在你從一個用外鍵的表刪除記錄時,通過為一個應用程序增加適當的DELETE語句即可。實際上,這很快(在一些情況下更快)並且比使用外鍵更比便于移植。

在不久的將來我們將擴充FOREIGN KEY實現,以便至少信息將在表說明文件中保存並且可以由mysqldump和ODBC檢索。

5.4.5.1 不使用外鍵的理由

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
175#
 楼主| 发表于 2006-4-29 13:11 | 只看该作者
有很多與FOREIGN KEY有關的問題我們不知道從哪兒開始:

外鍵使生活更複雜,因為外鍵的定義必須存儲在一個數據庫中並且實現他們將破壞使用能被移動、拷貝和刪除文件的全部“好方法”。
速度影響對INSERT和UPDATE語句是可怕的,並且在這種情況下幾乎所有的FOREIGN KEY檢查都是無用的,因為不管怎樣你通常以正確的順序在正確的表中插入記錄。
當更新一張表時,也有在許多表上保存鎖的需求,因為副作用可以串聯通過全部數據庫。首先從一張表中刪除記錄並且隨後從其他表中刪除他們,這更快。
你再也不可以通過做一個全面的表刪除並隨後恢複所有的記錄的方法來恢複一張表(從新來源或從一個備份)。
如果你有外鍵,你不能傾倒和恢複表,除非你以一個非常特定的做這些。
很容易做一個“允許的”的循環定義使得不可能用一個單個create語句重建每一個表,就算定義可行又可用。
FOREIGN KEY唯一好的方面是它給ODBC和一些其他客戶程序檢查一張表如何被連接的能力,並且使用它們顯示出連接圖表並幫助構造應用。

MySQL不久將存儲FOREIGN KEY定義以便一個客戶能詢問並收到原來的連接如何進行的一個答案。當前的“.frm 文件格式沒有它應有的地位。

5.4.6 視圖

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
176#
 楼主| 发表于 2006-4-29 13:11 | 只看该作者
MySQL不支持視圖,但是它在TODO上。

5.4.7 '--'作為一個注釋的開始
有些其他SQL數據庫使用'--'開始注釋。MySQL有“#”作為開始數注釋的字符,即使mysql命令行工具刪除以'--'開始的所有行。你也可以在MySQL中使用C注釋風格/* this is a comment */。見7.29 注釋句法。

MySQL3.23.3和以上版本支持'--'注釋風格,只要注釋跟在一個空格之後。這是因為這種退化的注釋風格已經引起用像下列代碼那樣的自動生成的SQL查詢的許多問題,這里我們自動地為!payment!插入支付值:

UPDATE tbl_name SET credit=credit-!payment!
你想出當payment的值是負的時將發生什麼嗎?

因為1--1在SQL中是合法的,我們認為'--'開始注釋是可怕的。

然而在MySQL 3.23中,你可使用:1-- This is a comment

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
177#
 楼主| 发表于 2006-4-29 13:11 | 只看该作者
如果你正在咝幸粋

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
178#
 楼主| 发表于 2006-4-29 13:12 | 只看该作者
MySQL不支持COMMIT-ROLLBACK。問題是有效地處理COMMIT-ROLLBACK將需要完全不同于MySQL今天使用的表布局。MySQL也將需要額外的線程在表上做自動清除工作,而且磁盤用量將更高。這將使MySQL比現今慢上大約2-4倍。MySQL比幾乎所有其他SQL數據庫都快(一般至少快2-3倍)。原因之一就是缺少COMMIT-ROLLBACK。

目前,我們是更多地實現SQL服務器語言(象存儲過程),有了它,你將確實很少需要COMMIT-ROLLBACK,這也將得到更好的性能。

通常需要事務的循環可以借助LOCK TABLES進行編碼,並且當你能即時地更新記錄時,你不需要光標(cursor)。

我們在TODO上有事務和光標,然而並非相當優先。如果我們實現這些,將作為CREATE TABLE的選項,那意味著COMMIT-ROLLBACK將僅工作在那些表上,以便速度損失僅僅強加在那些表上。

我們在TcX有一個更大的需求,一個比100%通用數據庫的真正快速的數據庫。無論何時我們發現一個方法來實現這些特征而沒有任何速度損失,我們將可能做它。暫時,有許多更重要的事情要做。檢查TODO,看我們此時如何將事情優先排列。(有的較高級別支持的客戶可以改變它,因此事情是可以重新優先化的。)

當前的問題實際上是ROLLBACK,沒有ROLLBACK,你能用LOCK TABLES做任何COMMIT動作。為了支持ROLLBACK,MySQL將必須被改變以存儲所有的舊記錄,如果發出ROLLBACK,它們被更新的並且將任何東西恢複到起點。對于簡單的情形,這不是難做的 (當前isamlog可以用于此目的),但是為ALTER/DROP/CREATE TABLE實現ROLLBACK將是更困難的。

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
179#
 楼主| 发表于 2006-4-29 13:12 | 只看该作者
避免使用ROLLBACK,你可以使用下列策略:

使用LOCK TABLES ...鎖住所有你想要存取的數據庫表。
測試條件。
如果一切無誤,更新。
使用UNLOCK TABLES釋放你的鎖。
這通常比使用可能帶ROLLBACK的交易是一個更快的方法,盡管不總是這樣。這個解決方案不能處理的唯一狀況是當某人在更新當中殺死線程時。在這種情況下,所有的鎖將被釋放,但是一些更改不能被執行。

你也可使函數以單個操作更新記錄。你能通過使用下列技術得到一個很有效率的應用程序:

相對他們的當前的值修改字段
僅僅更新那些實際上更改的字段
例如,當我們正在更新一些客戶信息時,我們僅僅更新那些改變了的客戶數據並只測試沒有任何數據的改變,或數據取決于改變的數據,與原來的行相比變化了。對于改變了的數據的測試用WHERE子句在UPDATE語句中完成。如果記錄沒被更新,我們給客戶一條消息:“你改變了的一些數據已被其他用戶改變了”,然後我們在一個窗口中顯示新行對照舊行,因此用戶能決定他該使用哪個版本的客戶記錄。

這給了我們類似于“列鎖定”的東西,但是實際上甚至更好,因為我們僅僅更新某些列,使用相對于他們的當前值的值。這意味著典型的UPDATE語句看上去象這些一樣東西:

使用道具 举报

回复
论坛徽章:
4
每日论坛发贴之星
日期:2005-04-26 01:01:12会员2006贡献徽章
日期:2006-04-17 13:46:34ITPUB元老
日期:2008-01-09 22:26:12
180#
 楼主| 发表于 2006-4-29 13:12 | 只看该作者
UPDATE tablename SET pay_back=pay_back+'relative change';

UPDATE customer
  SET
    customer_date='current_date',
    address='new address',
    phone='new phone',
    money_he_owes_us=money_he_owes_us+'new_money'
  WHERE
    customer_id=id AND address='old address' AND phone='old phone';

正如你能看到的,這是很有效的並且就算其他客戶已經改變了pay_back或money_he_owes_us列的也能工作。

在許多情況下,為管理一些表格的唯一標識符目的,用戶已經想要ROLLBACK或LOCK TABLES。這可用一個AUTO_INCREMENT列和一個SQL函數LAST_INSERT_ID()或C API函數mysql_insert_id()更高效地處理。見20.4.29 mysql_insert_id()。

在TcX,我們從來沒有任何對行級鎖定的需求,因為我們總是能通過編碼解決它。一些情況下需要確實行鎖定,但是他們是很少見的。如果你想要行級鎖定,你可以在表中使用標志列並且這樣做:

UPDATE tbl_name SET row_flag=1 WHERE id=ID;

如果行被找到發現並且row_flag在原來的行已經不是1,對受影響的行數MySQL返回1。

你可以想到它,因為MySQL把上面的查詢變為:

UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表