【问题标题】:Dynamic column names in view (Postgres)视图中的动态列名 (Postgres)
【发布时间】:2012-02-27 15:05:43
【问题描述】:

我目前正在编写一个 SQL 视图,它应该提供特定月份的填充字段的计数。

这就是我希望构建视图的方式:

Country   | (Current Month - 12) Eg Feb 2011 | (Current Month - 11) | (Current Month - 10)
----------|----------------------------------|----------------------|---------------------
UK        | 10                               | 11                   | 23

月份下的数字应该是特定国家/地区所有填充字段的计数。该字段名为 eldate,是格式为 10-12-2011 的日期(转换为字符)。我希望计数只计算与月份匹配的日期。

因此,“当前月份 - 12”列应仅包含当前 12 个月之前的月份内的日期计数。例如,当前月份 - 英国的 12 应该包括在 2011 年 2 月之间的日期计数。

我希望列标题实际反映它所查看的月份:

Country | Feb 2011 | March 2011 | April 2011
--------|----------|------------|------------
UK      | 4        | 12         | 0

比如:

SELECT c.country_name,
        (SELECT COUNT("C1".eldate) FROM "C1" WHERE "C1".eldate LIKE %NOW()-12 Months% AS NOW() - 12 Months
        (SELECT COUNT("C1".eldate) FROM "C1" WHERE "C1".eldate LIKE %NOW()-11 Months% AS NOW() - 11 Months
FROM country AS c
INNER JOIN "site" AS s using (country_id)
INNER JOIN "subject_C1" AS "C1" ON "s"."site_id" = "C1"."site_id"

显然这不起作用,只是为了让您了解我的意思。

有什么想法吗?

感谢您的帮助,如有更多疑问请咨询。

【问题讨论】:

  • 我不知道您是否可以使用视图来实现这一点,但您可以使用函数。注意在 PostgreSQL 中你可以调用这样的函数:SELECT * FROM funName()
  • 是的,我认为这可能是这样,但是,我是一个新手,不知道如何构建一个函数来做到这一点

标签: sql postgresql relational-database


【解决方案1】:

我的第一个想法是制作这张桌子:

+---------+-------+--------+
| Country | Month | Amount |
+---------+-------+--------+
| UK      | Jan   | 4      |
+---------+-------+--------+
| UK      | Feb   | 12     |
+---------+-------+--------+

等等。并转动它。所以你会从(例如)开始:

SELECT 
  c.country, 
  EXTRACT(MONTH FROM s.eldate) AS month, 
  COUNT(*) AS amount
FROM country AS c
JOIN site AS s ON s.country_id = c.id
WHERE 
  s.eldate > NOW() - INTERVAL '1 year'
GROUP BY c.country, EXTRACT(MONTH FROM s.eldate);

然后您可以将其插入 one the crosstab functions from the tablefunc module 以实现枢轴,执行以下操作:

SELECT * 
FROM crosstab('<query from above goes here>') 
  AS ct(country varchar, january integer, february integer, ... december integer);

【讨论】:

  • 我不确定我理解你的意思,但感谢您的帮助
  • @AydinHassan 怎么了?
【解决方案2】:

您可以截断日期以进行比较:

WHERE date_trunc('month', eldate) = date_trunc('month', now()) - interval '12 months'

更新

您的查询的这种替换:

(SELECT COUNT("C1".eldate) FROM "C1" WHERE date_trunc('month', "C1".eldate) =
    date_trunc('month', now()) - interval '12 months') AS TWELVE_MONTHS_AGO

但这将涉及每个月对表的扫描,因此您可以进行单次扫描,并按照以下方式进行更多操作:

SELECT SUM( CASE WHEN date_trunc('month', "C1".eldate) =  date_trunc('month', now()) - interval '12 months' THEN 1 ELSE 0 END ) AS TWELVE_MONTHS_AGO
      ,SUM( CASE WHEN date_trunc('month', "C1".eldate) =  date_trunc('month', now()) - interval '11 months' THEN 1 ELSE 0 END ) AS ELEVEN_MONTHS_AGO
...

或与其他人显示的月份表进行联接。

更新2

关于修复从一月到十二月的列的评论,我在想这样的事情:过滤过去几年的记录,然后在适当的月份求和。可能是这样的:

SELECT SUM( CASE WHEN EXTRACT(MONTH FROM "C1".eldate) = 1 THEN 1 ELSE 0 END ) AS JAN
      ,SUM( CASE WHEN EXTRACT(MONTH FROM "C1".eldate) = 2 THEN 1 ELSE 0 END ) AS FEB
      ...

  WHERE date_trunc('month', "C1".eldate) <  date_trunc('month', now())
    AND date_trunc('month', "C1".eldate) >= date_trunc('month', now()) - interval '12 months'

【讨论】:

  • 您能进一步解释一下吗?
  • 好的,谢谢,但是没有办法真正动态命名列吗?
  • @AydinHassan 我不知道。在这种情况下,我倾向于修复列(JAN - DEC),然后做一些涉及 now() - jan、now() - feb 等的数学运算,而不是硬编码的 -12、-11、.. . 需要对年份边界进行一些处理,但这可能是一些最小/最大的东西。
猜你喜欢
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2018-07-08
  • 2013-09-04
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多