【问题标题】:Selecting certain columns from a table with dates as columns从以日期为列的表中选择某些列
【发布时间】:2020-05-09 13:58:41
【问题描述】:

我有一个表,其中列名类似于年份 "2020-05","2020-06", "2020-07" 等,以及许多年作为列。我只需要从该表中选择当前月份、下个月和第三个月的列。(DB : PostgreSQL Version 11)

但由于列名是“TEXT”,格式为 YYYY-MM,我如何才能从该表中仅选择当前月份和未来 2 个月而不对列名进行硬编码。

下面是表结构,名称:static_data

必需的选择语句是这样的,该表包含上面屏幕截图中的 14 个月数据,例如 DATES 作为列。从这里我想要当前月份和接下来的 2 个月列以及它们的数据,如下所示。

从静态中选择“2020-05”、“2020-06”、“2020-07” -- 选择当前月份和接下来的 2 个月 所需输出:

【问题讨论】:

  • 您应该真正规范您的数据库设计并将每个日期存储在单独的行中。您当前的结构使简单的任务变得非常复杂。
  • 表定义和样本数据最好显示为formatted text。请参阅here,了解有关如何创建漂亮表格的一些提示。
  • 这些列的内容到底是什么?你不也想看看吗?
  • @a_horse_with_no_name 有一些文本值,基本上是各种格式的数字,如 1000 美元等。在这些列中。是的,我也需要查看数据。我就是这样寻找。

标签: postgresql


【解决方案1】:

几乎不可能将当前月份的实际值作为列名,但您可以执行以下操作:

select d.item_sku,
       d.status,
       to_jsonb(d) ->> to_char(current_date, 'yyyy-mm') as current_month,
       to_jsonb(d) ->> to_char(current_date + interval '1 month', 'yyyy-mm') as "month + 1",
       to_jsonb(d) ->> to_char(current_date + interval '2 month', 'yyyy-mm') as "month + 2"
from bad_design d
;

【讨论】:

  • 非常感谢,尽管它是一个不必要的复杂的,但 baove 工作正常,非常感谢!!我会重新设计的。
  • @Linu:由于您的数据模型损坏,这是“不必要的复杂”
【解决方案2】:

从技术上讲,您可以使用信息架构来实现这一点。但是,就像GMB 说的那样,请重新设计您的架构,首先不要这样处理这个问题。

特殊架构information_schema 包含有关您的数据库的元数据。其中包括有关现有columns 的详细信息。换句话说,您可以查询它并将它们的名称转换为日期,以便将它们与您需要的进行比较。
这里有一些提示。

查询现有列名。

SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'your_schema'
  AND table_name   = 'your_table'

比较两个日期。

SELECT now() + INTERVAL '3 months' < now() AS compare;
 compare                                                       
---------
 f
(1 row)

您自己已经非常接近转换了。

玩得开心并重新设计您的架构!

【讨论】:

  • 我也需要数据,比如“SELECT Curent_month,Next_month,third_month FROM static_data”
【解决方案3】:

免责声明:这不能回答您的问题 - 但评论太长了。

您需要修复此表的设计。不应将日期存储在列中,而应将每个日期放在单独的行中。

您当前的设计有很多缺点:

  • 非常简单的查询非常复杂:过滤日期、聚合...所有这些操作都需要动态 SQL,这增加了很多复杂性

  • 添加或删除新日期需要修改表格结构

  • 对于并非所有列都已填满的行会浪费存储空间

考虑一下这个简单的设计,一张表存储每个item_sku的主数据,还有一张子表

create table myskus (
    item_sku int primary key,
    name text,
    cat_level_3_name text
);

create table myvalues (
    item_sku int references myskus(item_sku),
    date_sku date,
    value_sku text,
    primary key (item_sku, date_sku)
);

现在你原来的问题很容易解决:

select v.*, s.name, s.cat_level_3_name
from myskus s
inner join myvalues v on v.item_sku = s.item_sku
where 
    v.date_sku >= date_trunc('month', now()) 
    and v.date_sku < date_trunc('month', now()) + interval '3 month'

【讨论】:

  • 完全理解你的意思!但是表中只有 16 个月的数据,而且这个表是用来更新谷歌表的,所以这就是为什么想出这个设计。但我一定会改变你提到的结构。
猜你喜欢
  • 1970-01-01
  • 2019-04-18
  • 2020-03-27
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多