如何在PostgreSQL的SELECT语句中使用行值作为列?

时间:2018-04-22 04:15:57

标签: sql postgresql postgresql-9.2

我的PostgreSQL 9.2.8数据库中有这三个表的表结构:

enter image description here

我正在尝试弄清楚如何选择orders行,并在SAME行添加order_pointspoints中的一些列。

您可以将points表视为一个人可以购买的所有商品的列表,abbrev在内部知道该商品的成本amount

order_points表是购买的每件商品,因此points.id == order_points.points_idamount类似于说他们购买了5个糖果棒。它通过order_points.order_id == orders.id

链接到订单

当我选择订单时,我希望每个abbrev都有一个列,以及amount表中的order_points

所以如果points有这个:

 id | name      | abbrev | amount
 --------------------------------
  1 | Snickers  | sn     | 1.34
  2 | Milky Way | mw     | 1.73
  3 | Coffee    | cf     | 10.12

order_points有这个:

 id | order_id | points_id | amount
 ----------------------------------
  1 |        1 |         1 |     10
  2 |        1 |         3 |      1

然后,当我得到我的行时,我想要订单中的所有列,再加上三列。我不想列出上面订单中显示的每一个列,但基本上假设我只想要其中的4个,加上所有points这些东西我最终将其作为一行输出:

 id | created    | due        | name  | sn | mw | cf
 ------------------------------------------------
  1 | 2018-04-21 | 2018-05-01 | Fooey | 10 |  0 |  1

我不知道如何从表查找中动态添加名称(abbrev)的列。

2 个答案:

答案 0 :(得分:4)

正如Adam Silenko所说,你不能在运行时添加一列。您可以做的最好的事情是使用2个查询。一个函数将创建一个包含所需列的临时表,另一个函数用于查询表并获取结果。这解释为here

将创建临时表的函数:

CREATE OR REPLACE FUNCTION get_order(orderId BIGINT)
  RETURNS VOID AS
  $$
  DECLARE column_names varchar[];
  DECLARE column_values float[];
  DECLARE final_select TEXT := 'SELECT id, name points_columns FROM orders where id=' || orderId;
  DECLARE create_table_statement TEXT := 'CREATE TEMP TABLE temp_result_table ON COMMIT DROP AS select_statement';
  DECLARE columns_values_concatenated TEXT := '';
  BEGIN
    SELECT array_agg(abbrev),  array_agg(CASE WHEN amount IS NULL THEN 0 ELSE amount END)
    into column_names, column_values FROM
     (SELECT abbrev, order_points.amount as amount FROM points LEFT JOIN order_points ON points.id = order_points.points_id and order_id = orderId
     ORDER BY points.id) points_amount;

     FOR i IN 1 .. array_upper(column_names, 1)
       LOOP
       columns_values_concatenated := columns_values_concatenated || ', ' || column_values[i] || ' as ' || column_names[i];
     end loop;
    final_select := replace(final_select, 'points_columns',columns_values_concatenated);
    create_table_statement:= replace(create_table_statement, 'select_statement', final_select);
    EXECUTE create_table_statement;
end;

$$ LANGUAGE Plpgsql;

我们使用2个数组column_namescolumn_values来存储名称(" sn"," mw"," cf)和值分别为所选订单的名称。

我们使用这两个数组来生成select语句(在当前代码中,我只从orders表中获取id和name,但您可以轻松地更改它)。我们将select语句存储到final_select变量中。最后,我们将生成的select语句添加到create_table_statement,然后创建并填充临时表。

现在,正如上面的链接所解释的那样,因为我们需要2个查询来访问数据,所以我们必须在单个事务中执行两个查询(为了避免名称冲突,如果我们多次调用该函数)

BEGIN;
SELECT * FROM get_order(1);
SELECT * FROM temp_result_table;
COMMIT; --The temporary table will be dropped on commit

答案 1 :(得分:2)

您无法动态添加名称未知的列。必须知道查询中的列名称。但是您可以使用一个查询的输出以编程方式定义输出查询中的字段名称。