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

时间:2012-07-06 14:33:16

标签: postgresql

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

逻辑是:每个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...
)

例如:

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

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

  1. 如何创建GPA TXT字段。
  2. 如何编写case语句以根据其他字段中的值计算字段。
  3. 如果有人可以通过示例或解释将我链接到资源,我会非常感激!我正在查看文档,但没有示例,没有任何地方。

3 个答案:

答案 0 :(得分:15)

重要提示:我会根据您当前的表创建一个view并避免添加新列,因为它们会对您的架构进行非规范化。阅读更多here

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

  • 要形成GPA_TXT字段,您可以使用to_char()函数:to_char(gpa, 'FM09.0')FM将避免在结果字符串前面留出空格);
  • 对于第二个字段,我会使用GPA而不是GPA_TXT进行数字比较。您可以在the docs中的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
    

抱歉,我不知道每个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;

要在此查询之前构建视图,请先添加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');

答案 1 :(得分:3)

我建议使用“生成”列,而不是冗余地存储数据。它将占用更少的磁盘空间,这实际上可能比存储生成的值更快,并且肯定不会意外地与基础数据失去同步。假设您喜欢@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;
$$;

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

SELECT name, major, gpa, atab.adesc
  FROM atab;

这样的“生成列”可用于快速搜索的索引中,如果这就是你所追求的,可以使用类似adesc(atab).*的内容。

答案 2 :(得分:0)

这里是从包含3列的表中返回值的查询:

select *
, to_char(gpa, '09.9') as gpa_text
, name || '-' || major || '-Grade' ||
case    when gpa between 3.5 and 4.0 then 'A'
    when gpa between 2.5 and 3.4 then 'B'
    when gpa between 1.5 and 2.4 then 'C'
    when gpa between 0.5 and 1.4 then 'D'
    else 'F' end
|| '-' || ltrim(to_char(gpa, '09.9')) as newfield
from students

这是工作代码,这是Bob的新领域,“Bob-sci-GradeC-02.0”

我强烈建议您在数据库中没有文本列来保存数字值的副本。我不太清楚为什么我需要ltrim,格式化的字符串会有一个前导空白似乎很奇怪。