Oracle PL/SQL 入门

正则表达式

字符类别

类别 描述
\d 任意数字(等同于[0-9])
\D 任意非数字字符(等同于[^0-9])
\w 任意字母或数字(等同于[a-zA-Z0-9])
\W 任意非字母或数字字符(等同于[^a-zA-Z0-9])
\s 任意空白字符
\S 任意非空白字符

重复元字符

元字符 描述
* 0个或多个匹配
+ 1个或多个匹配(等价于{1,})
? 0个或1个匹配(等价于{0,1})
{n} 具体的匹配次数
{n,} 不少于指定的匹配次数
{n,m} 匹配的范围

锚元字符

描述
^ 文本的开头
$ 文本的末尾

^有两种用法:在字符集内(使用[和]定义),使用它来对字符集取反;否则,将把它用于指示字符串的开头。

/* SELECT prod_name, vend_id
FROM products; */

SELECT DISTINCT vend_id -- DISTINCT 关键字用法
FROM products;

SELECT prod_id, prod_price, prod_name
FROM products
ORDER BY prod_price DESC;

SELECT prod_name, prod_price
FROM products
WHERE prod_price BETWEEN 5 AND 10
ORDER BY prod_name;

SELECT prod_name, prod_price
FROM products
WHERE vend_id = 1002 OR vend_id = 1003
ORDER BY prod_name;

SELECT prod_name, prod_price
FROM products
-- WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10
WHERE vend_id IN (1002,1003) AND prod_price >= 10 -- 可以使用IN
ORDER BY prod_name;

SELECT prod_id, prod_name
FROM products
WHERE prod_name LIKE '_ ton anvil%';

SELECT prod_name
FROM products
WHERE REGEXP_LIKE (prod_name, '.000') -- 正则函数
ORDER BY prod_name;

SELECT prod_name
FROM products
WHERE REGEXP_LIKE(prod_name, '1000|2000|3000')
ORDER BY prod_name;

SELECT prod_name
FROM products
WHERE REGEXP_LIKE(prod_name,'[1-5] ton')
ORDER BY prod_name;

SELECT vend_name
FROM vendors
WHERE REGEXP_LIKE(vend_name, '\.'); -- 用转义符"\"搜索"."

SELECT prod_name
FROM products
-- WHERE REGEXP_LIKE(prod_name, '\(\d sticks?\)')
WHERE REGEXP_LIKE(prod_name, '\d{4}')
ORDER BY prod_name;

常用文本操作函数

函数 描述
Length() 返回字符串的长度
Lower() 把字符串转换成小写形式
LPad() 在字符串左边填充空格
LTrim() 从字符串左边修剪掉空白
RPad() 在字符串右边填充空格
RTrim() 从字符串右边修剪掉空白
Soundex() 返回字符串的SOUNDEX值
SubString() 返回字符串内的字符
Upper() 把字符串转换成大写形式

常用的日期和时间操作函数

函数 描述
Add_Month() 给日期添加月份(也可以减去月份)
Extract() 从日期和时间中减去年、月、日、时、分或秒
Last_Day() 返回月份的最后一天
Months_Between() 返回两个月份之间的月数
Next_Day() 返回指定日期后面的那一天
Sysdate() 返回当前日期和时间
To_Date() 把字符串转换成日期

常用的数值操作函数

函数 描述
Abs() 返回数字的绝对值
Cos() 返回指定角度的三角余弦值
Exp() 返回指定数字的指数值
Mod() 返回除法运算的余数
Sin() 返回指定角度的三角正弦值
Sqrt() 返回指定数字的平方根
Tan() 返回指定角度的三角正切值

SQL聚合函数

函数 描述
AVG() 返回列的平均值
COUNT() 返回列中的行数
MAX() 返回列的最大值
MIN() 返回列的最小值
SUM() 返回列的值汇总
  • 可以使用COUNT()的两种方式是:

    • 使用COUNT(*)统计表中的行数,无论列包含的是数值还是NULL值;
    • 使用COUNT(column)统计在特定列中具有值(忽略NULL值)的行数。
  • GROUP BY子句必须出现在WHERE子句的后面和ORDER BY子句的前面。

  • HAVING与WHERE的区别:
    WHERE过滤发生在数据分组之前,而HAVING过滤则发生在数据分组之后。这是一个重要的区别,被WHERE子句删除的行不会包括在分组中。这可能会改变计算值,基于HAVING子句中使用的那些值,它反过来又可能影响哪些分组将会被过滤。

ORDER BY与GROUP BY的比较

ORDER BY GROUP BY
对生成的输出进行排序 对行进行分组,不过输出可能没有采用分组顺序
可能使用任意列(甚至包括没有选择的列) 只可能使用所选的列或表达式列,并且一定会使用所有选择的列表达式
从来都不是必需的 如果结合使用列(或表达式)与聚合函数,则是必需的

SELECT子句和它们的顺序

子句 描述 是否必需
SELECT 要返回的列或表达式
FROM 要从中检索数据的表 是(Oracle)
WHERE 行级过滤
GROUP BY 分组规范 仅当按分组计算聚合值时是必需的
HAVING 分组级过滤
ORDER BY 输出的排列顺序

查询示例

SELECT RTRIM(vend_name) || ',(' || RTRIM(vend_country) || ')'
AS vend_title
FROM vendors
ORDER BY vend_name;

SELECT prod_id, quantity, item_price,
       quantity * item_price AS expanded_price
FROM orderitems
WHERE order_num = 20005;

SELECT cust_id, order_num
FROM orders
WHERE order_date = TO_DATE('2015-02-01', 'yyyy-mm-dd');
SELECT cust_id, order_num
FROM orders
WHERE order_date>= TO_DATE('2015-02-01', 'yyyy-mm-dd')
   AND order_date< TO_DATE('2015-02-02', 'yyyy-mm-dd');
   
SELECT cust_id, order_num
FROM orders
-- 检索order_date在2015年和2月的所有行
WHERE Extract(Year FROM order_date) = 2015
   AND Extract(Month FROM order_date) = 2;
   
SELECT AVG(prod_price) AS avg_price
FROM products
WHERE vend_id = 1003;

SELECT COUNT(*) AS num_cust
FROM customers;

SELECT COUNT(cust_email) AS num_cust
FROM customers;

SELECT SUM(quantity) AS items_ordered
FROM orderitems
WHERE order_num = 20005;

SELECT SUM(item_price*quantity) AS total_price
FROM orderitems
WHERE order_num = 20005;

SELECT COUNT(*) AS num_items,
       MIN(prod_price) AS price_min,
       MAX(prod_price) AS price_max,
       AVG(prod_price) AS price_avg
FROM products;

SELECT vend_id, COUNT(*) AS num_prods 
FROM products
GROUP BY vend_id; -- GROUP BY 聚合分组

SELECT cust_id, COUNT(*) AS orders
FROM orders
GROUP BY cust_id
HAVING COUNT(*) >= 2; -- HAVING用于过滤分组 等同于过滤行的 WHERE

/* 列出具有2件或更多产品并且价格在10以上(含10)的所有供应商 */
SELECT vend_id, COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10
GROUP BY vend_id
HAVING COUNT(*) >= 2;

/* 检索总价在50以上(含50)的所有订单的订单号和订单总价,并按订单总价对输出进行排序 */
SELECT order_num, SUM(quantity * item_price) AS order_total
FROM orderitems
GROUP BY order_num
HAVING SUM(quantity * item_price) >= 50
ORDER BY order_total;

/* 子查询:查询订购商品TNT2的所有顾客的信息,下面有连接表方法查询 */
SELECT cust_name, cust_contact
FROM customers
WHERE cust_id IN (SELECT cust_id
                  FROM orders
                  WHERE order_num IN (SELECT order_num
                                      FROM orderitems
                                      WHERE prod_id = 'TNT2'));

SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
       FROM orders
       WHERE orders.cust_id = customers.cust_id) AS orders -- orders为计算字段
FROM customers
ORDER BY cust_name;

/* 表的连接,必须使用完全限定的列名(用点号把表和列分隔开) */
SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;
-- 等同于下面的内连接,WHERE更简化,INNER更清晰
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;

-- 显示了订单号20005中的商品
SELECT prod_name, vend_name, prod_price, quantity
FROM orderitems, products, vendors
WHERE products.vend_id = vendors.vend_id
   AND orderitems.prod_id = products.prod_id
   AND order_num = 20005;

/* 使用连接表:查询订购商品TNT2的所有顾客的信息,上面有子查询方法 */
-- WHERE连接表
SELECT cust_name, cust_contact
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
   AND orderitems.order_num = orders.order_num
   AND prod_id = 'TNT2';
-- FROM子句,INNER JOIN ON实现
SELECT cust_name, cust_contact
FROM customers
INNER JOIN orders ON customers.cust_id = orders.cust_id
INNER JOIN orderitems ON orderitems.order_num = orders.order_num
WHERE prod_id = 'TNT2';

表别名和列别名

列别名使用 AS:

SELECT RTrim(vend_name) || ', (' || RTrim(vend_country) || ')'
  AS vend_title
FROM vendors
ORDER BY vend_name;

表别名如下:

SELECT cust_name, cust_contact
FROM customers c, orders o, orderitems oi
WHERE c.cust_id = o.cust_id
  AND oi.order_num = o.order_num
  AND prod_id = 'TNT2';

注意:只在查询执行期间使用表别名。与列别名不同,表别名永远不会返回给客户。

/* 查询商品ID为DTNTR的商品的同一个供应商制造的所有产品 */
-- 子查询方法
SELECT prod_id, prod_name 
FROM products
WHERE vend_id = (SELECT vend_id
                 FROM products
                 WHERE prod_id = 'DTNTR')
ORDER BY prod_id;
/* 自连接 */
-- 连接表 WHERE
SELECT p1.prod_id, p1.prod_name
FROM products p1, products p2
WHERE p1.vend_id = p2.vend_id
    AND p2.prod_id = 'DTNTR'
ORDER BY prod_id;
-- 连接表 INNER JOIN ON
SELECT p1.prod_id, p1.prod_name
FROM products p1
INNER JOIN products p2 ON p1.vend_id = p2.vend_id
WHERE p2.prod_id = 'DTNTR'
ORDER BY prod_id;

/* 自然连接 */
SELECT c.*, o.order_num, o.order_date,   -- c.*为customers表中所有列
            oi.prod_id, oi.quantity, OI.item_price
FROM customers c, orders o, orderitems oi
WHERE c.cust_id = o.cust_id
   AND oi.order_num = o.order_num
   AND prod_id = 'FB';
   
SELECT c.*, o.order_num, o.order_date,
            oi.prod_id, oi.quantity, OI.item_price
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id
INNER JOIN orderitems oi ON oi.order_num = o.order_num
WHERE prod_id = 'FB';   

/* 外连接:检索所有顾客及其订单 */
SELECT c.cust_id, o.order_num
FROM customers c
INNER JOIN orders o ON c.cust_id = o.cust_id;
-- 检索所有顾客的列表,包括那些没有下订单的顾客
SELECT customers.cust_id, orders.order_num
FROM customers
LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id;

与将两个表中的行相关联的内连接不同,外连接还包括没有相关行的行。
当使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字指定要包括所有行的表(RIGHT用于OUTER JOIN右边的表,LEFT则用于左边的表)。前面的示例在FROM子句中使用LEFT OUTER JOIN从左边的表(customers表)中选择所有的行。要从右边的表中选择所有的行,可以使用RIGHT OUTER JOIN

外连接类型:
有两种基本的外连接形式:左外连接和右外连接,它们之间的唯一区别是相关联的表的顺序。换句话说,可以把左外连接转变成右外连接,只需在FROM或WHERE子句中颠倒表的顺序即可。因此,可以互换地使用两类外连接,而要使用哪种外连接则取决于方便性。

/* 检查所有顾客的列表以及每位顾客下的订单数量 */
-- 内连接
SELECT customers.cust_name,
       COUNT(orders.order_num) AS num_ord
FROM customers
INNER JOIN orders ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_name;
-- 外连接
SELECT customers.cust_name,
       COUNT(orders.order_num) AS num_ord
FROM customers
LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_name;

/* 组合查询 UNION */
/* 价格在5以下的所有产品,包括由供应商1001和1002制造的所有产品,不管价格 */
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN (1001,1002)
ORDER BY vend_id, prod_price;

SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
  OR vend_id IN (1001,1002);

使用UNION ALL,Oracle将不会消除重复的行。

INSERT 插入的用法

/* INSERT语句用法示例 */
-- 下面是依赖列顺序的,强烈不推荐
INSERT INTO Customers
VALUES(10006,
       'Pep E. LaPew',
       '100 Main Street',
       'Los Angeles',
       'CA',
       '90046',
       'USA',
       NULL,
       NULL);
-- 推荐写法
INSERT INTO customers(cust_id,
                      cust_name,
                      cust_address,
                      cust_city,
                      cust_state,
                      cust_zip,
                      cust_country)
VALUES(10006,
       'Pep E. LaPew',
       '100 Main Street',
       'Los Angeles',
       'CA',
       '90046',
       'USA');
       
       
-- 使用INSERT SELECT把custnew中的所有数据导入到customers中       
INSERT INTO custnew(cust_id,
                    cust_contact,
                    cust_email,
                    cust_name,
                    cust_address,
                    cust_city,
                    cust_state,
                    cust_zip,
                    cust_country)
SELECT cust_id,
       cust_contact,
       cust_email,
       cust_name,
       cust_address,
       cust_city,
       cust_state,
       cust_zip,
       cust_country
FROM custnew;

UPDATE更新数据

-- 更新顾客10005的电子邮件
UPDATE customers
SET cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;

-- 更新多列数据
UPDATE customers
SET cust_name = 'The Fudds',
    cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;

-- 更新为空值(删除列)
UPDATE customers
SET cust_email = NULL
WHERE cust_id = 10005;

UPDATE语句需要结束于一个WHERE子句,它告诉Oracle要更新哪一行,否则更新所有行。

DELETE删除数据的使用

-- 从customers表中删除单独一行
DELETE FROM customers
WHERE cust_id = 10006;

DELETE不接受列名或者通配符,它将删除整行,而不是删除列。要删除特定的列,可以使用UPDATE语句。
永远不要执行不带有WHERE子句的UPDATE或DELETE,除非确实打算更新和删除每一行。

创建表

---------------------------------------------
-- Create customers table
---------------------------------------------
CREATE TABLE customers
(
  cust_id   int      NOT NULL ,
  cust_name char(50) NOT NULL ,
  cust_address char(50)  NULL ,
  cust_city    char(50)  NULL ,
  cust_state   char(5)   NULL ,
  cust_zip     char(10)  NULL ,
  cust_country char(50)  NULL ,
  cust_contact char(50)  NULL ,
  cust_email   char(255) NULL
);


---------------------------------------------
-- Create orderitems table
---------------------------------------------
CREATE TABLE orderitems
(
  order_num  int          NOT NULL ,
  order_item int          NOT NULL ,
  prod_id    char(10)     NOT NULL ,
  quantity   int          DEFAULT 1 NOT NULL , -- 设置默认值
  item_price decimal(8,2) NOT NULL
);

ALTER TABLE更新表定义

-- 向表中添加一列
ALTER TABLE vendors
ADD vend_phone CHAR(20);

-- 删除添加列
ALTER TABLE vendors
DROP COLUMN vend_phone;

-- 定义主键
----------------------
-- Define primary keys
----------------------
ALTER TABLE customers ADD CONSTRAINT pk_customers
                      PRIMARY KEY (cust_id);
ALTER TABLE orderitems ADD CONSTRAINT pk_orderitems
                       PRIMARY KEY (order_num, order_item);
ALTER TABLE orders ADD CONSTRAINT pk_orders
                   PRIMARY KEY (order_num);
ALTER TABLE products ADD CONSTRAINT pk_products
                     PRIMARY KEY (prod_id);
ALTER TABLE vendors ADD CONSTRAINT pk_vendors
                    PRIMARY KEY (vend_id);
ALTER TABLE productnotes ADD CONSTRAINT pk_productnotes
                         PRIMARY KEY (note_id);      
                         
-- 定义外键
---------------------------------------------
-- Define foreign keys
---------------------------------------------
ALTER TABLE orderitems
      ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num)
      REFERENCES orders (order_num);
ALTER TABLE orderitems
      ADD CONSTRAINT fk_orderitems_products
      FOREIGN KEY (prod_id) REFERENCES products (prod_id);
ALTER TABLE orders
      ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id)
      REFERENCES customers (cust_id);
ALTER TABLE products
      ADD CONSTRAINT fk_products_vendors
      FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);
ALTER TABLE productnotes
      ADD CONSTRAINT fk_productnotes_products
      FOREIGN KEY (prod_id) REFERENCES products (prod_id);
      

删除表

-- 永久删除整个表customers2
DROP TABLE customers2; 

重命名表

ALTER TABLE customers2 RENAME TO customers;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 关系型数据库和SQL SQL语言的三个部分DML:Data Manipulation Language,数据操纵语...
    Awey阅读 1,937评论 0 13
  • SQL与MySQL简介 数据库基础 从SQL的角度来看,数据库就是一个以某种有组织的方式存储的数据集合。我们可以采...
    heming阅读 3,060评论 1 8
  • 1. SQL 简介 SQL 的目标 理想情况下,数据库语言应允许用户: 建立数据库和关系结构 完成基本数据管理任务...
    板蓝根plank阅读 2,330评论 0 11
  • 前言 读《sql必知必会 第四版》随手做的笔记,写的比较乱,可读性并不好,读的是中文版,翻译过来的感觉有点怪怪的。...
    _老徐_阅读 620评论 0 0
  • 一直想更新下绍兴游记,网上的信息几乎全都不准确,各家有各家的说法,更多的应该还是网络推广带来的营销弊端,坑苦的是我...
    温暖dream阅读 301评论 2 3