如何根据其他列的值和选择在postgres中创建列?

use*_*044 12 postgresql

我想在我的表中创建一个新字段(或两个),这是其他字段的串联,这似乎相对简单.但是我用什么case语法或if/when语法来帮助创建以下字段(GPA_TXT,和newfield)?

逻辑是:每个GPA应该是#.#,每个新字段应该是:

name & "-" & GPA_TXT & (
    case where GPA_TXT > 3.3
        set newfield = newfield & 'GradeA',
    case where GPA_TXT >2.7 and GPA_TXT < 3.3
        set newfield = newfield & "GradeB",
    etc...
)
Run Code Online (Sandbox Code Playgroud)

例如:

name         major     GPA(num) GPA_TXT   [newfield]
Bob          sci       2        02.0      Bob-sci-GradeC-02.0
Jane         chem      3.1      03.1      Jane-chem-GradeB-03.1
Charlie      phys      3.7      03.7      Charlie-phys-GradeA-03.7
Garfield     food      0        00.0      Garfield-food-GradeF-00.0
Run Code Online (Sandbox Code Playgroud)

所以我想我在这里有两个问题:

  1. 如何创建GPA TXT字段.
  2. 如何根据其他字段中的值编写case语句来计算字段.

如果有人可以通过示例或解释将我链接到资源,我会非常感激!我正在查看文档,但没有示例,没有任何地方.

vye*_*rov 15

重要说明:我将根据您当前的表创建一个视图,并避免添加新列,因为它们会对您的模式进行非规范化.在这里阅读更多.

此外,我将使用小写名称为所有标识符,以避免qouting.

  • 形成GPA_TXT字段可以使用to_char()功能:to_char(gpa, 'FM09.0')(在FM所得到的字符串前面将避免空间);
  • 对于第二个字段,我会使用GPA而不是GPA_TXT数字比较.您可以CASE文档中查看有关构造的更多信息,但该块可能是以下块:

    CASE WHEN gpa >= 3.3 THEN 'A'
         WHEN gpa > 2.7 AND gpa < 3.3 THEN 'B'
         WHEN gpa > 0 THEN 'C'
         ELSE 'F' END
    
    Run Code Online (Sandbox Code Playgroud)

对不起,我不知道每个GPA如何分配成绩,请相应调整.

结果查询可能是(也在SQL Fiddle上):

SELECT name,major,gpa,
       to_char(gpa, 'FM09.0') AS gpa_txt,
       name||'-'||major||'-Grade'||
  CASE WHEN gpa >= 3.3 THEN 'A'
       WHEN gpa > 2.7 AND gpa < 3.3 THEN 'B'
       WHEN gpa > 0 THEN 'C'
       ELSE 'F' END || '-' || to_char(gpa, 'FM09.0') AS adesc
  FROM atab;
Run Code Online (Sandbox Code Playgroud)

CREATE VIEW aview AS在此查询之前构建一个视图.


编辑

如果您仍然要添加列,以下应该可以做到:

ALTER TABLE atab ADD gpa_txt text, ADD adesc text;
UPDATE atab SET
    gpa_txt = to_char(gpa, 'FM09.0'),
    adesc = name||'-'||major||'-Grade'||
      CASE WHEN gpa >= 3.3 THEN 'A'
           WHEN gpa > 2.7 AND gpa < 3.3 THEN 'B'
           WHEN gpa > 0 THEN 'C'
           ELSE 'F' END || '-' || to_char(gpa, 'FM09.0');
Run Code Online (Sandbox Code Playgroud)


kgr*_*ttn 5

我建议使用“生成”列,而不是冗余存储数据。它将占用更少的磁盘空间,这实际上可能比存储生成的值更快,并且肯定不太容易意外地与基础数据不同步。假设您喜欢@vyegorov提供的格式,您可以创建一个这样的函数,使用表的记录类型(与表名称匹配)作为输入:

CREATE FUNCTION adesc(rec atab)
  RETURNS text
  IMMUTABLE
  LANGUAGE SQL
AS $$
SELECT to_char($1.gpa, 'FM09.0') AS gpa_txt,
       $1.name||'-'||$1.major||'-Grade'||
  CASE WHEN $1.gpa >= 3.3 THEN 'A'
       WHEN $1.gpa > 2.7 AND $1.gpa < 3.3 THEN 'B'
       WHEN $1.gpa > 0 THEN 'C'
       ELSE 'F' END || '-' || to_char($1.gpa, 'FM09.0') AS adesc;
$$;
Run Code Online (Sandbox Code Playgroud)

您需要使用关系限定符(表名或别名)来引用它。当通过查找实际列无法解析此类引用时,PostgreSQL 将查找将表的记录类型作为其唯一参数的函数。所以你可以做这样的事情:

SELECT name, major, gpa, atab.adesc
  FROM atab;
Run Code Online (Sandbox Code Playgroud)

这样的“生成列”可以在索引中用于快速搜索,如果这就是您所追求的,例如adesc(atab).*.