【问题标题】:PostgreSQL create a new column with values conditioned on other columnsPostgreSQL 创建一个新列,其值以其他列为条件
【发布时间】:2012-08-24 10:41:34
【问题描述】:

我使用 PostgreSQL 9.1.2,我有一个基本表,如下所示,其中条目的生存状态为布尔值 (Survival) 和天数 (Survival(Days))

我手动添加了一个名为1-yr Survival 的新列,现在我想为表中的每个条目填写此列的值,条件是该条目的SurvivalSurvival (Days) 列值。完成后,数据库表将如下所示:

Survival    Survival(Days)    1-yr Survival
----------  --------------    -------------
Dead            200                NO
Alive            -                 YES
Dead            1200               YES

输入1-yr Survival 的条件值的伪代码类似于:

ALTER TABLE mytable ADD COLUMN "1-yr Survival" text
for each row
if ("Survival" = Dead & "Survival(Days)" < 365) then Update "1-yr Survival" = NO
else Update "1-yr Survival" = YES
end 

我相信这是一个基本操作,但是我找不到执行它的 postgresql 语法。一些搜索结果返回“添加触发器”,但我不确定这是我需要的。我认为我在这里的情况要简单得多。任何帮助/建议将不胜感激。

【问题讨论】:

  • 请更准确。你的 Postgres 版本?您是在谈论一次性操作还是持续努力?性能很重要吗?有什么理由要存储冗余数据而不是使用视图?
  • @ Erwin,对不起,我现在已将版本添加到问题中。我使用 PostgreSQL 9.1.2。这是一次性的工作,我想要存储冗余数据的原因是我以 .csv 格式导出数据库以在 R 或 Matlab 中使用,并且我希望 1 年生存信息能够轻松处理并作为附加信息提供在我运行算法之前列。我不知道意见,但也会调查。
  • 我明白了。您可能会对我对COPY 的回答感兴趣。

标签: postgresql insert-update conditional-statements


【解决方案1】:

一次性操作可以通过一个普通的UPDATE来实现:

UPDATE tbl
SET    one_year_survival = (survival OR survival_days >= 365);

我建议不要在你的名字中使用驼峰式、空格和括号。虽然允许在双引号之间,但它通常会导致复杂化和混乱。考虑章节about identifiers and key words in the manual

您知道您可以使用COPY将查询结果导出为 CSV 吗?
示例:

COPY (SELECT *, (survival OR survival_days >= 365) AS one_year_survival FROM tbl)
TO '/path/to/file.csv';

您不需要以这种方式开始的冗余列。


评论的附加答案

为避免空更新:

UPDATE tbl
SET    "Dead after 1-yr" = (dead AND my_survival_col < 365)
      ,"Dead after 2-yrs" = (dead AND my_survival_col < 730)
....
WHERE  "Dead after 1-yr" IS DISTINCT FROM (dead AND my_survival_col < 365)
   OR  "Dead after 2-yrs" IS DISTINCT FROM (dead AND my_survival_col < 730)
...

就个人而言,如果我有令人信服的理由,我只会添加这些多余的列。通常我不会。如果是关于性能:你知道indexes on expressions and partial indexes吗?

【讨论】:

  • 是的,我猜 COPY 选项更有意义。非常感谢!
  • 我还有一个简短的问题。如果我在上面的场景中有一个非布尔值 X_year_Survival(与二进制 one_year_survival 相对)并且我想明确标记“1 年后死亡”、“2 年后死亡”和“3 年后死亡”怎么办?作为以 Survival_days 列为条件的列值?我们不能使用:“SET one_year_survival = (survival ORsurvival_days >= 365);”在这种情况下。基于条件显式标记的语法是什么?非常感谢。
  • @Berkan: binary != boolean。我想你问了一个新问题。您可以随时参考这个,以节省一些输入。
  • 谢谢,我想问的是我是否希望明确说明派生的 1_year_survival(列)的可能值,并且可能有两个以上的标签,而不仅仅是 TRUE/FALSE,会是什么我使用的语法?我认为我不应该为此提出新问题,因为(本页的)原始问题的定义和标题并不将 One-Year_Survival 限制为布尔列。 (但我知道您提出了一个布尔解决方案,因为它在上下文中更有意义。)
  • @Berkan:我在回答中添加了一些内容。
【解决方案2】:

老实说,我认为您最好不要将数据存储在数据库中,因为数据库可以从存储的数据中快速轻松地计算出来。一个更好的选择是模拟一个计算字段(但是下面提到的问题)。在这种情况下,您可以将 9 个空格等改为下划线,以便于维护:

CREATE FUNCTION one_yr_survival(mytable)
RETURNS BOOL
IMMUTABLE
LANGUAGE SQL AS $$
select $1.survival OR $1.survival_days >= 365;
$$;

那么你实际上可以:

SELECT *, m.one_year_survival from mytable m;

它会“正常工作”。请注意以下问题:

  • 默认列列表不会返回mytable.1_year_survival,并且
  • 您不能省略表标识符(上例中的 m),因为解析器会将其转换为 one_year_survival(m)。

但是好处是可以证明该值永远不会与其他值不同步。否则你最终会得到一堆检查约束。

您实际上可以采用这种方法。见http://ledgersmbdev.blogspot.com/2012/08/postgresql-or-modelling-part-2-intro-to.html

【讨论】:

  • 这似乎是个好主意。特别是如果此列不在一个人的源数据中(例如具有固定数据集的科学研究)。如果有人需要从源代码重新创建数据库功能,那么函数似乎是一个健康的“提醒”。此外,通过保存表空间,函数(以及逻辑)将始终保留在表空间中..
猜你喜欢
  • 2017-08-12
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-20
相关资源
最近更新 更多