PostgreSQL中如何将数值与CSV格式的列值进行比较?
问题描述
我有一张名为device_info的表,数据示例如下:
| device_ip | cpu | memory |
|---|---|---|
| 100.33.1.0 | 10.0 | 29.33 |
| 110.35.58.2 | 3.0, 2.0 | 20.47 |
| 220.17.58.3 | 4.0, 3.0 | 23.17 |
| 30.13.18.8 | -1 | 26.47 |
| 70.65.18.10 | -1 | 20.47 |
| 10.25.98.11 | 5.0, 7.0 | 19.88 |
| 12.15.38.10 | 7.0 | 22.45 |
我需要筛选出cpu列中存在大于3的值的行。由于cpu列以CSV格式存储,我尝试用PostgreSQL的string_to_array函数转换,但执行以下查询后没有得到预期结果:
select device_ip, cpu, memory from device_info where 3 > any(string_to_array(cpu, ',')::float[]);
预期输出:
| device_ip | cpu | memory |
|---|---|---|
| 100.33.1.0 | 10.0 | 29.33 |
| 220.17.58.3 | 4.0, 3.0 | 23.17 |
| 10.25.98.11 | 5.0, 7.0 | 19.88 |
| 12.15.38.10 | 7.0 | 22.45 |
请问我哪里出错了?
问题分析与解决
你的查询存在两个问题:
- 逻辑判断写反:
3 > any(...)的含义是“3大于数组中任意一个元素”,但你需要的是“数组中存在任意一个元素大于3”,正确的条件应为any(string_to_array(cpu, ',')::float[]) > 3。 - 未处理CSV中的空格:部分
cpu值的逗号后带有空格(比如3.0, 2.0),直接用string_to_array(cpu, ',')分割会得到带空格的元素,无法正常转为float类型。
以下是两种正确的查询方式:
方式一:正则分割+正确判断逻辑
用regexp_split_to_array按“逗号+任意空格”的规则分割,确保元素无空格干扰,再判断数组中是否有元素大于3:
select device_ip, cpu, memory from device_info where any(regexp_split_to_array(cpu, '\s*,\s*')::float[]) > 3;
方式二:展开数组后筛选
将数组展开为单行记录,再筛选出存在大于3值的原表行(用distinct去重):
select distinct d.device_ip, d.cpu, d.memory from device_info d cross join unnest(regexp_split_to_array(d.cpu, '\s*,\s*')) as cpu_val where cpu_val::float > 3;
两种方式都能得到你想要的预期结果。
内容的提问来源于stack exchange,提问作者Souvik Ray
相关产品推荐
相关产品推荐

