如何使用保存在表中的水平数据作为postgres中的列

Posted

技术标签:

【中文标题】如何使用保存在表中的水平数据作为postgres中的列【英文标题】:How to use Horizontal data saved in a table as Columns in postgres 【发布时间】:2020-04-10 14:59:22 【问题描述】:

我有一张这样的桌子:

虚拟现实桌

ID  Key         Value   Date
123 First_Name  Vlad    01-01-2011
234 First_Name  Jim     07-01-2011
456 First_Name  Olimpia 10-02-2012
123 Last_Name   Kofman  12-02-2014
234 Last_Name   Cramer  14-02-2014
456 Last_Name   Dukakis 04-03-2015
123 Dept    IT          08-03-2016
234 Dept    Marketing
456 Dept    Accounting
123 Sex M
234 Sex M
456 Sex F

现在,我想编写一个查询来获取 First_Name ='Vlad' AND Last_Name='Cramer' 的值。 另一个场景是我想获取日期 '01-01-2011' 到 '14-02-2016' 之间的所有记录。

我写的查询是:

SELECT VR.key,
      Min(( CASE
              WHEN ( VR.key = 'FIRST_NAME' ) THEN
             VR.value
              ELSE 'n/a'
            END )) AS first_name,
      Min(( CASE
              When ( VR.key = 'LAST_NAME' ) THEN
              VR.value
              ELSE 'n/a'
            END )) AS last_name
FROM   VR
WHERE   ( ( VR.first_name = 'Vlad' )
          AND ( VR.last_name = 'Cramer' ) )
GROUP  BY VR.key
ORDER  BY VR.first_name,
VR.last_name

我得到的例外是 Amazon](500310) 无效操作:列 VR.first_name 不存在;

任何人都可以帮助我了解我应该如何达到预期的结果。

【问题讨论】:

请仅标记您正在使用的一个数据库(您同时拥有mysqlpostgres,它们是两个不同的数据库)。从错误消息来看,您实际上正在运行 amazon-redshift - 该数据库有一个特定的标签。 编辑了标签 喜欢编写 SQL 来处理 EAV 模型中的数据……“期望的结果”究竟是什么样的?我们期望返回什么?这些属性行是否完全由id 列链接...我们是否应该将其视为像(123,'Vlad','Kofman','M','IT',...)(234,'Jim','Cramer','M','Marketing',...)(456,'Olympia','Dukakis','F','Accounting',...) 这样的元组(行)并编写一个返回的查询什么?鉴于损坏的 sql 作为规范,我们只是在猜测...... @spencer7593 为了您的理解,我修改了我的问题,实际上我需要获取日期范围 '01-01-2011' 到 '14-02-2016' 之间的所有记录,它没有什么可做的使用 first_name 和 last_name。你能帮我查询一下吗? 目前还不清楚“获取所有记录”是什么样的。该问题没有给出要返回的结果集是什么样子的示例。如果我们想获取两个日期之间的所有记录,那么我们可以这样做 SELECT t* FROM VR t WHERE t.Date >= '2011-01-01' AND t.Date < '2016-02-15' ,但我怀疑(考虑到问题中的 SQL)这并不是我们真正想要的结果集。 【参考方案1】:

您的表没有名为 first_namelast_name 的列 - 这些是 key 列中的值。

我认为您实际上是在寻找条件聚合:

select id
from vr
where key in ('First_Name', 'Last_Name')
group by id
having 
    max(case when key = 'First_Name' and value = 'Vlad' then 1 end) = 1
    and max(case when key = 'Last_Name' and value = 'Cramer' then 1 end) = 1

这会给您ids,他们的名字等于 Vlad,姓氏等于 Cramer。

【讨论】:

你也可以看看这个***.com/questions/61158654/…【参考方案2】:

您应该从您的 VR 表构建一个常规表,并以此为起点进行查询或从该内部 SELECT 构建一个视图

SELECT 
    *
FROM
    (SELECT 
        VR.id,
            MAX(IF(VR.key = 'First_Name', VR.Value, NULL)) 'First_Name',
            MAX(IF(VR.key = 'Last_Name', VR.Value, NULL)) 'Last_Name',
            MAX(IF(VR.key = 'Dept', VR.Value, NULL)) 'Dept',
            MAX(IF(VR.key = 'Sex M', 'male', IF(VR.key = 'Sex F', 'female', NULL))) 'Gender'
    FROM
        VR
    GROUP BY VR.id) comp
WHERE
    First_Name = 'Vlad'
        AND Last_Name = 'Kofman';
编号 |名字 |姓氏 |部门 |性别 --: | :--------- | :-------- | :--- | :----- 123 |弗拉德 |科夫曼 |资讯科技 |男性

db小提琴here

【讨论】:

以上是关于如何使用保存在表中的水平数据作为postgres中的列的主要内容,如果未能解决你的问题,请参考以下文章

在 Postgres 中自我加入

如何使用 PL/SQL 中的过程在表中插入多个值?

如何有效地将树状数据结构插入 postgres

如何在表中插入变量(@id)作为 SQL 服务器查询中的自动增量?

SQLSERVER如何在数据库里根据某个字段,查出该表名字

MSSQL之三 在表中操纵数据