【发布时间】:2021-04-30 18:03:26
【问题描述】:
这个表是一个大杂乱查询的(假例子)结果。
=> WITH data(run, host, status, field_ip, control_ip, field_data, control_data) AS (
VALUES (1, 1, 'no_control', '10.0.0.1', NULL, 'foo', NULL),
(1, 2, 'good', '10.0.0.1', '10.0.0.1', 'bar', 'bar'),
(1, 3, 'problem_1', '10.0.0.1', NULL, 'bar', NULL),
(1, 3, 'problem_2', '10.0.0.2', NULL, 'baz', NULL),
(1, 3, NULL, NULL, '192.168.1.1', NULL, 'wallace'))
SELECT * FROM data;
run | host | status | field_ip | control_ip | field_data | control_data
-----+------+------------+----------+-------------+------------+--------------
1 | 1 | no_control | 10.0.0.1 | | foo |
1 | 2 | good | 10.0.0.1 | 10.0.0.1 | bar | bar
1 | 3 | problem_1 | 10.0.0.1 | | bar |
1 | 3 | problem_2 | 10.0.0.2 | | baz |
1 | 3 | | | 192.168.1.1 | | wallace
我想根据以下规则将“control_ip”和“control_data”字段从它们不为 NULL 的行合并到它们为 NULL 的行中:考虑具有相同“运行”和“主机”的每组行' 值独立。在每个这样的组内:
- 所有字段都为 NOT NULL 的每一行都将被原样输出并从组中删除。 (例如,第 (1,2) 行将保持原样输出。它是其组中的唯一行,因此该组现在已完成。)
- 对于“field_ip”和“field_data”字段不为空但“control_ip”和“control_data”字段为空的每一行,在组中找到相反的另一行,并复制其“control_ip” ' 和 'control_data' 字段到第一行。然后输出修改后的行并将其从组中删除。
- 如果不存在“相反为真的另一行”,则原样输出第一行(例如,要原样输出第 (1,1) 行)。
- 如果有多个“另一行相反的情况”,则任意选择一个,并在复制其值后将其丢弃。 (样本数据集中没有这样的例子。)
- 如果只有一个“另一行相反的情况”,请不要在复制其值后丢弃它。 (例如,行 (1,3,NULL,NULL,'192.168.1.1',NULL,'wallace') 应该将其 control_ip/control_Data 值复制到 both (1,3,problem_1 ,10.0.0.1) 和 (1,3,problem_2,10.0.0.2) 行。)
- 重复第 2 步,直到组中不再有“field_ip”和“field_data”字段不为空的行。
- 丢弃组中所有剩余的行(它们都将具有 NULL field_ip 和 field_data)。
上述样本数据的期望输出是:
run | host | status | field_ip | control_ip | field_data | control_data
-----+------+------------+----------+-------------+------------+--------------
1 | 1 | no_control | 10.0.0.1 | | foo |
1 | 2 | good | 10.0.0.1 | 10.0.0.1 | bar | bar
1 | 3 | problem_1 | 10.0.0.1 | 192.168.1.1 | bar | wallace
1 | 3 | problem_2 | 10.0.0.2 | 192.168.1.1 | baz | wallace
这是与How to concatenate text from multiple rows into a single text string in SQL server? 类似的问题,但该答案对我不起作用,因为GROUP BY run, host plus 聚合只能为每组发出一行,而在某些情况下我需要为每组发出多行。我尝试了一些涉及GROUP BY run, host, field_ip 的事情,但是第三 (1,3) 行被视为自己的组,这不好。另外,我使用的是 PostgreSQL (12),而不是 SQL Server,并且 AIUI PIVOT 是一个 sql-server-ism。
注意:大杂乱查询的最后一步,生成显示的表,是运行、主机和 field_ip = control_ip 上的 FULL JOIN 的结果。如果从前体开始到 FULL JOIN 更容易完成我的要求,请告诉我。
你有什么建议?
【问题讨论】:
-
哪些规则让您知道想要丢弃第三 (1,3) 行而不是应用“垂直合并”来填充它的
NULL值?同样,对于您正在填写NULL值的行,您能否保证永远只有 一个NOT NULL价值选择?最后,您是否只需要为control_列执行此操作? -
@MatBailie 我已经为我想要的问题添加了更明确的规则。
-
我已经更新了我的答案,并将示例数据扩大了一行以展示一些行为。顺便问一下,你想要一份工作吗?我可以问,因为这条评论是短暂的。
标签: sql postgresql