PostgreSQL 循环
- 前言
- 笔记
- WHILE 循环
- 基本结构
- 简单示例
- 详细示例
- 创建示例函数
- 解释
- 调用示例函数
- 预期输出
- FOR 循环
- Numeric FOR Loop
- 基本结构
- 简单示例
- 详细示例
- 创建示例函数
- 解释
- 调用示例函数
- 预期输出
- Reverse Numeric FOR Loop
- 基本格式
- 简单示例
- 详细说明
- 创建函数
- 解释
- 调用函数
- 预期输出
- FOREACH Loop
- 基本结构
- 简单示例
- 详细示例
- 创建示例函数
- 调用示例函数
- 预期输出
- Loop 循环
- 基本结构
- 退出 `LOOP` 循环
- 简单示例
- 详细示例
- 创建函数
- 解释
- 调用函数
- 预期输出
- 扩展
- EXIT 和 CONTINUE 控制
- 使用 EXIT
- 使用 CONTINUE
前言
在PostgreSQL中,可以通过以下几种方法进行循环:
WHILE循环
:使用WHILE条件循环语句,当满足条件时执行循环体内的代码,直到条件不再满足时跳出循环。
WHILE condition LOOP
-- 循环体内的代码
END LOOP;
FOR循环
:使用FOR循环语句,可以遍历一个集合或者执行一定次数的循环。
FOR i IN 1..10 LOOP
-- 循环体内的代码
END LOOP;
LOOP循环
:使用简单的LOOP语句创建一个无限循环,在循环体内部可以通过条件语句和BREAK语句来控制循环的终止条件。
LOOP-- 循环体内的代码IF condition THENEXIT;END IF;
END LOOP;
笔记
WHILE 循环
基本结构
在PL/pgSQL中,WHILE
循环的基本结构如下:
DECLAREcounter INT := 0;
BEGINWHILE counter < 10 LOOP-- 执行一些操作counter := counter + 1;END LOOP;
END;
简单示例
WHILE
循环在执行循环体之前先检查条件,如果条件为真,则执行循环体。
DO $$
DECLAREcounter INT := 0;
BEGINWHILE counter < 10 LOOPRAISE 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 $$
DECLAREresult 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) LOOPword := word_array[i];-- 如果结果字符串不为空,则添加空格IF result <> '' THENresult := 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 $$
DECLAREi INT;
BEGINFOR i IN 1..10 LOOPRAISE NOTICE 'Value: %', i;END LOOP;
END $$;
在上面的示例中,i
是循环计数器,它的初始值是 1,结束值是 10。在每次循环中,i
的值从 1 递增到 10,并且在每次迭代中打印出当前的值。
在或者,
DO $$
BEGINFOR counter IN 0..9 LOOPRAISE NOTICE 'Counter: %', counter;END LOOP;
END $$;
详细示例
假设我们要实现一个函数,该函数接受一个整数N,并返回从1到N的所有数值的平方。我们可以使用FOR
循环来实现这个功能。
创建示例函数
CREATE OR REPLACE FUNCTION generate_squares(N INT)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLAREresult TEXT := ''; -- 用于存储结果字符串i INT; -- 循环计数器
BEGIN-- 使用 FOR 循环遍历从 1 到 N 的数值FOR i IN 1..N LOOP-- 将当前数值的平方添加到结果字符串IF result <> '' THENresult := 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 $$
DECLAREi INT;
BEGINFOR i IN REVERSE 10..1 LOOPRAISE NOTICE 'Value: %', i;END LOOP;
END $$;
在上面的示例中,i
是循环计数器,它的结束值是 10,起始值是 1。在每次循环中,i
的值从 10 递减到 1,并且在每次迭代中打印出当前的值。
在或者,
DO $$
BEGINFOR counter IN REVERSE 9..0 LOOPRAISE NOTICE 'Counter: %', counter;END LOOP;
END $$;
详细说明
假设你需要编写一个函数,该函数接受一个整数 N 作为输入,然后从 N 开始递减,直到 1,并计算每个数的阶乘。
创建函数
CREATE OR REPLACE FUNCTION calculate_factorial(N INT)
RETURNS BIGINT
LANGUAGE plpgsql
AS $$
DECLAREresult BIGINT := 1; -- 用于存储最终结果i INT; -- 循环计数器
BEGINFOR i IN REVERSE N..1 LOOPresult := 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 $$
DECLAREarr INT[] := ARRAY[1, 2, 3, 4, 5];elem INT;
BEGINFOREACH elem IN ARRAY arr LOOPRAISE NOTICE 'Element: %', elem;END LOOP;
END $$;
在上面的示例中,elem
是循环变量,它依次取数组 arr
中的每个元素。在每次迭代中,elem
的值将是数组中的当前元素,并且在每次迭代中打印出当前元素的值。
在或者,
DO $$
DECLAREarr INT[] := ARRAY[1, 2, 3, 4, 5];elem INT;
BEGINFOREACH elem IN ARRAY arr LOOPRAISE NOTICE 'Element: %', elem;END LOOP;
END $$;
详细示例
假设我们要实现一个函数,该函数接受一个整数数组,并返回数组中每个元素的平方。我们可以使用FOREACH
循环来实现这个功能。
创建示例函数
CREATE OR REPLACE FUNCTION square_elements(input_array INT[])
RETURNS INT[]
LANGUAGE plpgsql
AS $$
DECLAREresult_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 THENEXIT; -- 退出循环END IF;
END LOOP;
在上面的示例中,如果 some_condition
条件满足,则会执行 EXIT
语句,从而终止循环。
简单示例
以下是一个简单的示例,演示如何使用 LOOP
循环输出 1 到 5 的所有整数:
DO $$
DECLAREi INT := 1;
BEGINLOOPEXIT 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 $$
DECLAREcurrent_value INT := start_value;
BEGINLOOPEXIT 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 $$
BEGINFOR counter IN 0..9 LOOPRAISE NOTICE 'Counter: %', counter;IF counter = 5 THENEXIT; -- 退出循环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 $$
BEGINFOR counter IN 0..9 LOOPIF counter = 5 THENCONTINUE; -- 跳过本次循环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=#