根据其他表中的条件列表选择串联列

问题描述 投票:0回答:1

我有一张桌子1

线 a b c d e f g h
1 18 2 2 22 0 2 1 2
2 20 2 2 2 0 0 0 2
3 10 2 2 222 0 2 1 2
4 12 2 2 3 0 0 0 0
5 15 2 2 3 0 0 0 0

还有一张桌子2

 线 标准
1  a,b
2  b、c、f、h
3  a、b、e、g、h
4  c,e

我正在使用此代码来查看/选择连接/连接列的独特结果,例如来自

concat(c,',',d)
concat(b,',',d,',',g)
table1
等,并且工作正常:

SELECT DISTINCT(CONCAT(c,',',d)) 
FROM table1

但是,我不想像

concat(c,',',d)
那样手动编写,而是想参考
table2.criteria
来从
table1
获取要连接/连接的列引用,以便我可以根据每个连接条件看到整个唯一结果

尝试过这个,但出现错误:

SELECT DISTINCT(SELECT criteria FROM table2) 
FROM table1

错误:用作表达式的子查询返回不止一行
SQL状态:21000

预期的独特结果是这样的;

| criteria     | result     |
| ------------ | ---------- |
| a,b          | 15,2       |
| a,b          | 10,2       |
| a,b          | 20,2       |
| a,b          | 12,2       |
| a,b          | 18,2       |
| b,c,f,h      | 2,2,2,2    |
| b,c,f,h      | 2,2,0,2    |
| b,c,f,h      | 2,2,0,0    |
| a,b,e,g,h    | 20,2,0,0,2 |
| a,b,e,g,h    | 12,2,0,0,0 |
| a,b,e,g,h    | 15,2,0,0,0 |
| a,b,e,g,h    | 10,2,0,1,2 |
| a,b,e,g,h    | 18,2,0,1,2 |
| c,e          | 2,0        |
sql postgresql select concatenation dynamic-sql
1个回答
1
投票

SQL 不允许参数化标识符。有多种方法可以解决此限制。

问题不清楚,但根据评论,您希望为

table1
中的每一行连接给定的模式。

1.动态 SQL

创建一个辅助函数(一次!),动态连接和执行语句。
基础知识:

CREATE OR REPLACE FUNCTION f_concat_cols(_cols text)
  RETURNS TABLE (result text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE format(
     $q$SELECT concat_ws(',', %s) FROM table1 ORDER BY line$q$, _cols);
END
$func$;

这是一个集合返回函数(又名“表函数”),对于每个给定模式,为

table1
中的每一行返回一个结果行。

警告:将用户输入转换为这样的代码是SQL注入的绝佳机会。您必须确保

table1.criteria
只能保存有效的字符串!

要获取完整的结果矩阵(表 2 中每行都有不同的结果),查询现在很简单:

SELECT DISTINCT line AS t2_line, criteria, t1.*
FROM   table2, f_concat_cols(criteria) t1
ORDER  BY t2_line;

2.转换为 JSON 的解决方法

SELECT DISTINCT t2.line AS t2_line, t2.criteria, c.*
FROM   table2 t2
CROSS  JOIN (SELECT line, to_json(t) AS js FROM table1 t) t1
CROSS  JOIN LATERAL (
   SELECT string_agg(t1.js->>sub, ',') AS result
   FROM   string_to_table(t2.criteria, ',') sub
   ) c
ORDER  BY t2_line;

将行从

t1
转换为JSON记录后,我们可以直接访问键(从列名转换)。
我使用
string_to_table()
(Postgres 14+) 取消模式的嵌套,访问每个单个键,并将结果聚合到
LATERAL
子查询中。参见:

您可以将逻辑封装在1.中的函数中,但在本例中这是可选的。

3.转换为 Postgres 数组的解决方法

SELECT DISTINCT t2.line AS t2_line, t2.criteria, c.*
FROM   table2 t2
CROSS  JOIN (SELECT line, ARRAY [a,b,c,d,e,f,g,h] AS arr FROM table1 t) t1
CROSS  JOIN LATERAL (
   SELECT string_agg(t1.arr[idx::int]::text, ',') AS result
   FROM   string_to_table(translate(t2.criteria, 'abcdefgh', '12345678'), ',') idx
   ) c
ORDER  BY t2_line;

与 JSON 的“技巧”类似,我们可以通过将列转换为普通的 Postgres 数组来避免动态 SQL。然后将列名称投影到整数数组索引。我使用

translate()
来表示简单的情况,但这仅适用于单个字母!使用
replace()
regexp_replace()
或其他一些方法来获得更长的名称。
剩下的就和上面一样了

小提琴 - 显示全部。

© www.soinside.com 2019 - 2024. All rights reserved.