视图、存储过程、函数

视图、存储过程、函数

-- 创建或覆盖覆盖视图
CREATE OR REPLACE VIEW sales_by_client AS
    SELECT 
        client_id,
        name,
        SUM(invoice_total) AS total_sales
    FROM clients c
    JOIN invoices i USING(client_id)
    GROUP BY client_id, name;
    
-- 如果存在,删除视图
DROP VIEW IF EXISTS sales_by_client;

-- 创建或覆盖覆盖视图
CREATE OR REPLACE VIEW clients_balance AS
    SELECT 
        client_id,
        c.name,
        SUM(invoice_total - payment_total) AS balance
    FROM clients c
    JOIN invoices USING(client_id)
    GROUP BY client_id, c.name; -- 不要漏掉c.name虽然MySQL不会报错

注意:创建视图不能使用order by,在MySQL中不会报错,但也没有排序的效果

 -- 定义视图时不要使用ORDER BY子句,mysql不会报错但order by 不会起作用
CREATE OR REPLACE VIEW cus(customer_id, full_name) AS
    SELECT customer_id, CONCAT(first_name, ' ', last_name)
    FROM customers
    ORDER BY customer_id DESC;

更新视图

-- 准备视图
CREATE OR REPLACE VIEW invoices_with_balance AS
    SELECT 
        invoice_id, 
        number, 
        client_id, 
        invoice_total, 
        payment_total, 
        invoice_date,
        invoice_total - payment_total AS balance,  -- 余额
        due_date, 
        payment_date
    FROM invoices
    WHERE (invoice_total - payment_total) > 0;

-- 删除
DELETE FROM invoices_with_balance WHERE invoice_id = 1

-- 修改
UPDATE invoices_with_balance
SET due_date = DATE_ADD(due_date, INTERVAL 2 DAY)
WHERE invoice_id = 2

-- 增加
-- 必须满足原始表的约束才能插入,因为视图的实质是select语句
-- 如上面这个视图就无法插入数据

不可更新视图


CREATE OR REPLACE VIEW invoices_with_balance AS
    SELECT 
        invoice_id, 
        number, 
        client_id, 
        invoice_total, 
        payment_total, 
        invoice_date,
        invoice_total - payment_total AS balance,  -- 余额
        due_date, 
        payment_date
    FROM invoices
    WHERE (invoice_total - payment_total) > 0
WITH CHECK OPTION; -- 使用update语句会报错

存储过程

-- 创建存储过程
DELIMITER $$ -- 更改分隔符 ; --> $$

    CREATE PROCEDURE get_clients()  
        BEGIN
            SELECT * FROM clients; -- 存储过程内部的分割符,每一语句都要使用;分割
        END$$ -- 存储过程外面的分隔符

DELIMITER ; -- 还原分隔符

-- 执行存储过程
CALL get_clients();

-- 创建存储过程
DELIMITER $$

    CREATE PROCEDURE get_invoices_with_balance()
        BEGIN
            SELECT *
            FROM invoices_with_balance -- 存储过程中使用视图
            WHERE balance > 0;
        END$$

DELIMITER ;

-- 调用存储过程
CALL get_invoices_with_balance();

-- 如果存在,删除存储过程
DROP PROCEDURE IF EXISTS get_clients_by_state;

-- gist: 返回指定地址的顾客信息信息
DELIMITER $$

CREATE PROCEDURE get_clients_by_state
(
    state CHAR(2)  -- 参数的数据类型
)
BEGIN
    SELECT * FROM clients c
    WHERE c.state = state; -- 通过别名区分参数和列名
END$$

DELIMITER ;

-- 调用
CALL get_clients_by_state('CA') -- 必须有参数,即使为NULL


存储过程实例

USE sql_invoicing;

DROP PROCEDURE IF EXISTS get_clients_by_state;

DELIMITER $$
-- 返回指定州的客户信息
CREATE PROCEDURE get_clients_by_state(state CHAR(2))
BEGIN
    IF state IS NULL THEN 
       -- set + = 才是赋值,只有 = 是比较语句 相等于 == 
        SET state = 'CA'; -- 更改参数的值,在执行后面的SQL语句 
    END IF;
    SELECT * FROM clients c
    WHERE c.state = state;
END$$

DELIMITER ;
-- 返回指定州的客户信息,如果传入NULL,返回所有顾客信息
BEGIN
    SELECT * FROM clients c
    WHERE c.state = IFNULL(state, c.state)
END$$
CREATE PROCEDURE get_payments
(
    client_id INT,  -- 不用写成INT(4)
    payment_method_id TINYINT
)
BEGIN
    SELECT * FROM payments p
    WHERE 
        p.client_id = IFNULL(client_id, p.client_id) AND
        p.payment_method = IFNULL(payment_method_id, p.payment_method);
        -- 再次小心这种实际工作中各表相同字段名称不同的情况
END$$
-- 获取特定顾客所有未支付过的发票记录(即 payment_total = 0 的发票记录)
CREATE PROCEDURE get_unpaid_invoices_for_client(
        client_id INT
)
BEGIN
    SELECT COUNT(*), SUM(invoice_total)
    FROM invoices i
    WHERE 
        i.client_id = client_id AND
        payment_total = 0;
END

参数验证

IF payment_amount <= 0 THEN
        SIGNAL SQLSTATE '22003' 
            SET MESSAGE_TEXT = 'Invalid payment amount';  -- 相当java的throw Exception
    END IF;

输出参数,会话变量

CREATE PROCEDURE get_unpaid_invoices_for_client(
        client_id INT,
        OUT invoice_count INT,
        OUT invoice_total DECIMAL(9, 2) -- 通过out关键字指定
)
BEGIN
    SELECT COUNT(*), SUM(invoice_total)
    INTO invoice_count, invoice_total -- 使用into给out变量赋值
    FROM invoices i
    WHERE 
        i.client_id = client_id AND
        payment_total = 0;
END$$

-- 调用
set @invoice_count = 0; -- set @xx 是会话类型/用户类型的参数,存在时间是整个会话
set @invoice_total = 0;
call sql_invoicing.get_unpaid_invoices_for_client(3, @invoice_count, @invoice_total);
select @invoice_count, @invoice_total;

本地变量

CREATE PROCEDURE get_risk_factor()
BEGIN
    -- 声明本地变量
    DECLARE risk_factor DECIMAL(9, 2) DEFAULT 0;
    DECLARE invoices_total DECIMAL(9, 2);
    DECLARE invoices_count INT;

    SELECT SUM(invoice_total), COUNT(*)
    INTO invoices_total, invoices_count
    FROM invoices;

    -- 用SET语句给risk_factor计算赋值
    SET risk_factor = invoices_total / invoices_count * 5;

    -- 展示最终结果risk_factor
    SELECT risk_factor;     
END$$

函数

CREATE FUNCTION get_risk_factor_for_client
(
    client_id INT
) 
RETURNS INTEGER -- 返回值类型
-- 其他说明
-- DETERMINISTIC
READS SQL DATA
-- MODIFIES SQL DATA
BEGIN
    DECLARE risk_factor DECIMAL(9, 2) DEFAULT 0;
    DECLARE invoices_total DECIMAL(9, 2);
    DECLARE invoices_count INT;

    SELECT SUM(invoice_total), COUNT(*)
    INTO invoices_total, invoices_count
    FROM invoices i
    WHERE i.client_id = client_id;

    SET risk_factor = invoices_total / invoices_count * 5;
    RETURN IFNULL(risk_factor, 0);       
END

-- 如果存在,删除函数
DROP FUNCTION IF EXISTS get_risk_factor_for_client;

这些知识可能很少用在java开发中,因为不可移植和调试等原因

关于Oracle相关的知识可以参考这篇博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值