前言
在PostgreSQL中,可以通过以下几种方法进行循环:
WHILE循环
:使用WHILE条件循环语句,当满足条件时执行循环体内的代码,直到条件不再满足时跳出循环。
WHILE condition LOOP
-- 循环体内的代码
END LOOP;
FOR循环
:使用FOR循环语句,可以遍历一个集合或者执行一定次数的循环。
FOR i IN 1..10 LOOP
-- 循环体内的代码
END LOOP;
LOOP循环
:使用简单的LOOP语句创建一个无限循环,在循环体内部可以通过条件语句和BREAK语句来控制循环的终止条件。
LOOP
-- 循环体内的代码
IF condition THEN
EXIT;
END IF;
END LOOP;
笔记
WHILE 循环
基本结构
在PL/pgSQL中,WHILE
循环的基本结构如下:
DECLARE
counter INT := 0;
BEGIN
WHILE counter < 10 LOOP
-- 执行一些操作
counter := counter + 1;
END LOOP;
END;
简单示例
WHILE
循环在执行循环体之前先检查条件,如果条件为真,则执行循环体。
DO $$
DECLARE
counter INT := 0;
BEGIN
WHILE counter < 10 LOOP
RAISE NOTICE 'Counter: %', counter;
counter := counter + 1;
END LOOP;
END $$;
详细示例
假设我们要实现一个函数,该函数接受一个字符串,并在每个单词前添加一个编号。我们可以使用WHILE
循环来遍历字符串中的每个单词,并为每个单词添加编号。
创建示例函数
CREATE OR REPLACE FUNCTION add_number_to_words(input_str TEXT)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
result TEXT := ''; -- 用于存储结果字符串
word TEXT; -- 用于存储当前处理的单词
counter INT := 1; -- 用于编号
word_array TEXT[]; -- 用于存储拆分的单词数组
i INT := 1; -- 循环计数器
BEGIN
-- 使用正则表达式将输入字符串拆分为单词数组
word_array := regexp_split_to_array(input_str, '\s+');
-- 获取单词数组的长度
WHILE i <= array_length(word_array, 1) LOOP
word := word_array[i];
-- 如果结果字符串不为空,则添加空格
IF result <> '' THEN
result := result || ' ';
END IF;
-- 将编号和单词添加到结果字符串中
result := result || counter || '. ' || word;
-- 增加编号和循环计数器
counter := counter + 1;
i := i + 1;
END LOOP;
RETURN result;
END;
$$;
解释
- 变量声明:
result
:用于存储最终结果字符串。word
:用于存储当前处理的单词。counter
:用于为每个单词添加编号。word_array
:用于存储输入字符串拆分后的单词数组。i
:循环计数器,用于遍历单词数组。
- 字符串拆分:
regexp_split_to_array(input_str, '\s+')
:使用正则表达式将输入字符串按空格拆分成单词数组。
**WHILE**
** 循环**:
WHILE i <= array_length(word_array, 1) LOOP
:循环遍历单词数组。- 在循环体内,首先将当前单词存储到
word
变量中。 - 如果
result
字符串不为空,则在result
字符串后添加一个空格。 - 将编号和当前单词添加到
result
字符串中。 - 增加编号
counter
和循环计数器i
。
- 返回结果:
- 循环结束后,返回结果字符串
result
。
调用示例函数
SELECT add_number_to_words('Hello world this is a test');
预期输出
1. Hello 2. world 3. this 4. is 5. a 6. test
在这个例子中,WHILE
循环用于遍历输入字符串拆分后的单词数组,并为每个单词添加一个编号。
FOR 循环
在PL/pgSQL中,FOR
循环有几种形式:
- Numeric FOR Loop:用于遍历一系列数值。
- Reverse Numeric FOR Loop:用于反向遍历一系列数值。
- FOREACH Loop:用于遍历数组或集合类型。
Numeric FOR Loop
用于执行一系列数值的循环。
基本结构
Numeric FOR Loop 在 PL/pgSQL 中的基本结构如下所示:
FOR 变量名 IN 开始值..结束值 LOOP
-- 循环体
END LOOP;
在这个结构中:
变量名
:循环计数器的名称,用于迭代循环。开始值
:循环计数器的起始值。结束值
:循环计数器的结束值。- 循环体:在 LOOP 和 END LOOP 之间的部分,包含需要重复执行的代码块。
在循环的每次迭代中,变量名
将从 开始值
递增(或递减)到 结束值
,并在每次迭代中执行循环体中的代码。
简单示例
例如,以下是一个简单的示例,演示如何使用 Numeric FOR Loop 打印出 1 到 10 之间的所有整数:
DO $$
DECLARE
i INT;
BEGIN
FOR i IN 1..10 LOOP
RAISE NOTICE 'Value: %', i;
END LOOP;
END $$;
在上面的示例中,i
是循环计数器,它的初始值是 1,结束值是 10。在每次循环中,i
的值从 1 递增到 10,并且在每次迭代中打印出当前的值。
在或者,
DO $$
BEGIN
FOR counter IN 0..9 LOOP
RAISE NOTICE 'Counter: %', counter;
END LOOP;
END $$;
详细示例
假设我们要实现一个函数,该函数接受一个整数N,并返回从1到N的所有数值的平方。我们可以使用FOR
循环来实现这个功能。
创建示例函数
CREATE OR REPLACE FUNCTION generate_squares(N INT)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
result TEXT := ''; -- 用于存储结果字符串
i INT; -- 循环计数器
BEGIN
-- 使用 FOR 循环遍历从 1 到 N 的数值
FOR i IN 1..N LOOP
-- 将当前数值的平方添加到结果字符串
IF result <> '' THEN
result := result || ', ';
END IF;
result := result || i || '^2=' || (i * i);
END LOOP;
RETURN result;
END;
$$;
解释
- 变量声明:
result
:用于存储最终结果字符串。i
:循环计数器,用于遍历从1到N的数值。
**FOR**
** 循环**:
FOR i IN 1..N LOOP
:循环遍历从1到N的数值。- 在循环体内,首先检查
result
字符串是否为空,如果不为空,则在result
字符串后添加一个逗号和空格。 - 将当前数值的平方(格式为
i^2=x
)添加到result
字符串中。
- 返回结果:
- 循环结束后,返回结果字符串
result
。
调用示例函数
SELECT generate_squares(5);
预期输出
1^2=1, 2^2=4, 3^2=9, 4^2=16, 5^2=25
在这个例子中,
FOR
循环用于遍历从1到N的数值,并生成这些数值的平方。
Reverse Numeric FOR Loop
用于执行一系列数值的反向循环。
基本格式
FOR 变量名 IN REVERSE 结束值..开始值 LOOP
-- 循环体
END LOOP;
在这个结构中:
变量名
:循环计数器的名称,用于迭代循环。结束值
:循环计数器的结束值。开始值
:循环计数器的起始值。- 循环体:在
LOOP
和END LOOP
之间的部分,包含需要重复执行的代码块。
在 Reverse Numeric FOR Loop 中,循环计数器的值从 结束值
开始递减,直到达到 开始值
。
简单示例
例如,以下是一个简单的示例,演示如何使用 Reverse Numeric FOR Loop 打印出 10 到 1 之间的所有整数:
DO $$
DECLARE
i INT;
BEGIN
FOR i IN REVERSE 10..1 LOOP
RAISE NOTICE 'Value: %', i;
END LOOP;
END $$;
在上面的示例中,i
是循环计数器,它的结束值是 10,起始值是 1。在每次循环中,i
的值从 10 递减到 1,并且在每次迭代中打印出当前的值。
在或者,
DO $$
BEGIN
FOR counter IN REVERSE 9..0 LOOP
RAISE NOTICE 'Counter: %', counter;
END LOOP;
END $$;
详细说明
假设你需要编写一个函数,该函数接受一个整数 N 作为输入,然后从 N 开始递减,直到 1,并计算每个数的阶乘。
创建函数
CREATE OR REPLACE FUNCTION calculate_factorial(N INT)
RETURNS BIGINT
LANGUAGE plpgsql
AS $$
DECLARE
result BIGINT := 1; -- 用于存储最终结果
i INT; -- 循环计数器
BEGIN
FOR i IN REVERSE N..1 LOOP
result := result * i;
END LOOP;
RETURN result;
END;
$$;
解释
在上面的示例中,我们创建了一个名为 calculate_factorial
的函数,它接受一个整数 N 作为输入,并返回 N 的阶乘。函数内部使用 Reverse Numeric FOR Loop 来递减地遍历从 N 到 1 的整数,并计算它们的乘积。在每次迭代中,循环计数器 i 的值递减,直到达到 1。
这个函数的执行过程如下:
- 当 N = 5 时,循环将从 5 开始递减到 1,计算 5 _ 4 _ 3 _ 2 _ 1 的乘积,即 120。
Reverse Numeric FOR Loop 是在这个示例中实现递减序列的理想选择,它提供了一种简洁而清晰的方式来处理从大到小的循环迭代。
调用函数
SELECT calculate_factorial(5);
预期输出
120
FOREACH Loop
用于遍历数组或其他集合类型。
基本结构
FOREACH
Loop 在 PL/pgSQL 中的基本结构如下所示:
FOREACH 循环变量 IN ARRAY 数组变量 LOOP
-- 循环体
END LOOP;
在这个结构中:
循环变量
:用于迭代循环的临时变量,它将依次取数组中的每个元素。数组变量
:要迭代的数组。- 循环体:在
LOOP
和END LOOP
之间的部分,包含需要重复执行的代码块。
在每次迭代中,循环变量
将依次取数组中的每个元素,并执行循环体中的代码。
简单示例
例如,以下是一个简单的示例,演示如何使用 FOREACH
Loop 遍历一个整数数组并打印出每个元素的值:
DO $$
DECLARE
arr INT[] := ARRAY[1, 2, 3, 4, 5];
elem INT;
BEGIN
FOREACH elem IN ARRAY arr LOOP
RAISE NOTICE 'Element: %', elem;
END LOOP;
END $$;
在上面的示例中,elem
是循环变量,它依次取数组 arr
中的每个元素。在每次迭代中,elem
的值将是数组中的当前元素,并且在每次迭代中打印出当前元素的值。
在或者,
DO $$
DECLARE
arr INT[] := ARRAY[1, 2, 3, 4, 5];
elem INT;
BEGIN
FOREACH elem IN ARRAY arr LOOP
RAISE NOTICE 'Element: %', elem;
END LOOP;
END $$;
详细示例
假设我们要实现一个函数,该函数接受一个整数数组,并返回数组中每个元素的平方。我们可以使用FOREACH
循环来实现这个功能。
创建示例函数
CREATE OR REPLACE FUNCTION square_elements(input_array INT[])
RETURNS INT[]
LANGUAGE plpgsql
AS $$
DECLARE
result_array INT[] := '{}'; -- 用于存储结果数组
elem INT; -- 用于存储当前处理的数组元素
BEGIN
-- 使用 FOREACH 循环遍历数组中的每个元素
FOREACH elem IN ARRAY input_array LOOP
-- 将当前元素的平方添加到结果数组
result_array := array_append(result_array, elem * elem);
END LOOP;
RETURN result_array;
END;
$$;
调用示例函数
SELECT square_elements(ARRAY[1, 2, 3, 4, 5]);
预期输出
{1, 4, 9, 16, 25}
在这个例子中,
FOREACH
循环用于遍历输入数组,并生成每个元素的平方。
Loop 循环
在 PL/pgSQL 中,LOOP
循环是一种无限循环结构,它不会像 FOR
或 WHILE
循环那样有明确的退出条件。
基本结构
基本的 LOOP
循环结构如下所示:
LOOP
-- 循环体
END LOOP;
在这个结构中:
LOOP
:表示进入循环的开始标记。- 循环体:在
LOOP
和END LOOP
之间的部分,包含需要重复执行的代码块。 END LOOP
:表示循环的结束标记。
LOOP
循环将一直执行循环体中的代码,直到遇到 EXIT
语句才会终止循环。
退出 LOOP
循环
要从 LOOP
循环中退出,可以使用 EXIT
语句。例如:
LOOP
-- 循环体
IF some_condition THEN
EXIT; -- 退出循环
END IF;
END LOOP;
在上面的示例中,如果 some_condition
条件满足,则会执行 EXIT
语句,从而终止循环。
简单示例
以下是一个简单的示例,演示如何使用 LOOP
循环输出 1 到 5 的所有整数:
DO $$
DECLARE
i INT := 1;
BEGIN
LOOP
EXIT WHEN i > 5; -- 当 i 大于 5 时退出循环
RAISE NOTICE 'Value: %', i;
i := i + 1;
END LOOP;
END $$;
在上面的示例中,LOOP
循环将一直执行,直到 i
的值大于 5,然后通过 EXIT
语句退出循环。在每次循环中,会打印出当前 i
的值。
详细示例
假设我们要实现一个简单的倒计时器,从某个初始值开始,每秒递减并打印出当前值,直到计时器归零。
创建函数
CREATE OR REPLACE FUNCTION countdown_timer(start_value INT)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
current_value INT := start_value;
BEGIN
LOOP
EXIT WHEN current_value <= 0; -- 当当前值小于等于 0 时退出循环
RAISE NOTICE 'Countdown: %', current_value;
PERFORM pg_sleep(1); -- 暂停 1 秒
current_value := current_value - 1; -- 递减当前值
END LOOP;
END;
$$;
解释
在上面的示例中,我们创建了一个名为 countdown_timer
的函数,它接受一个整数 start_value
作为输入,并使用 LOOP
循环实现了倒计时器的逻辑。函数内部的循环将一直执行,直到 current_value
小于等于 0 时才退出循环。在每次循环中,会打印出当前的倒计时值,并通过 pg_sleep(1)
函数暂停 1 秒,然后将 current_value
递减 1。
调用函数
SELECT countdown_timer(10);
预期输出
Countdown: 10
Countdown: 9
Countdown: 8
Countdown: 7
Countdown: 6
Countdown: 5
Countdown: 4
Countdown: 3
Countdown: 2
Countdown: 1
这个示例展示了如何使用 LOOP
循环创建一个简单的倒计时器。LOOP
循环提供了一种简单而灵活的方式来实现这样的循环逻辑,而不需要明确的退出条件,只需在需要时使用 EXIT
语句即可退出循环。
扩展
EXIT 和 CONTINUE 控制
你可以使用EXIT
从循环中提前退出,使用CONTINUE
跳过本次循环并继续下一次循环。
使用 EXIT
DO $$
BEGIN
FOR counter IN 0..9 LOOP
RAISE NOTICE 'Counter: %', counter;
IF counter = 5 THEN
EXIT; -- 退出循环
END IF;
END LOOP;
END $$;
-- 输出结果:
NOTICE: Counter: 0
NOTICE: Counter: 1
NOTICE: Counter: 2
NOTICE: Counter: 3
NOTICE: Counter: 4
NOTICE: Counter: 5
DO
postgres=#
使用 CONTINUE
DO $$
BEGIN
FOR counter IN 0..9 LOOP
IF counter = 5 THEN
CONTINUE; -- 跳过本次循环
END IF;
RAISE NOTICE 'Counter: %', counter;
END LOOP;
END $$;
-- 输出结果:
NOTICE: Counter: 0
NOTICE: Counter: 1
NOTICE: Counter: 2
NOTICE: Counter: 3
NOTICE: Counter: 4
NOTICE: Counter: 6
NOTICE: Counter: 7
NOTICE: Counter: 8
NOTICE: Counter: 9
DO
postgres=#