将数据库列转换为行和求和

时间:2015-03-24 04:11:24

标签: sql postgresql

我正在构建一个系统,我必须使用数据库数据找到计算机系统的总价。第一个屏幕截图是系统表的构建。

系统表 enter image description here

零件表

enter image description here

不同的种类有:主板,外壳,内存,CPU,图形。 我需要的是将列转换成行的一些方法,从而总结每个系统的价格。

以下是表格和内容。

CREATE TABLE Component ( 
        nome VARCHAR(30), 
        kind VARCHAR(10), /*cpu, ram, mainboard, cases*/
        price INT,
        PRIMARY KEY(nome)
    );

CREATE TABLE Computer_system ( 
        nome VARCHAR(30),
        ram VARCHAR(20),
        cpu VARCHAR(20),
        mainboard VARCHAR(20),
        cases VARCHAR(20),
        gfx VARCHAR(20),
        PRIMARY KEY(nome)
    );


INSERT INTO Computer_system VALUES('SERVER1','D31','XEON1','LGA2011_D3_E_OGFX','CASE_A',null); 
INSERT INTO Computer_system VALUES('SERVER2','D43','XEON3','LGA2011_D4_E_OGFX','CASE_A',null);
INSERT INTO Computer_system VALUES('CONSUMER1','D43','I71','LGA1150_D4_ATX_OGFX','CASE_B',null); 
INSERT INTO Computer_system VALUES('GAMING1', 'D51', 'FX','AM3+_D5_ATX','BLACK_PEARL', 'NVIDIA_TITAN_BLACK_X');
INSERT INTO Computer_system VALUES('BUDGETO', 'D31', 'XEON1','LGA2011_D3_ATX','CASE_B', null);

4 个答案:

答案 0 :(得分:1)

在Postgres using UNNEST( ARRAY( ...) )

中有一个关于unpivot的巧妙技巧

这有效地(在表的一次通过中)将表computer_system的多列展开成多行(在这种情况下)3列:“nome”,“colkind”和“colnome”。不透明数据的一个例子:

|      nome |   colkind |              colnome |
|-----------|-----------|----------------------|
|   BUDGETO |       ram |                  D31 |
|   BUDGETO |       gfx |               (null) |
|   BUDGETO |     cases |               CASE_B |
|   BUDGETO | mainboard |       LGA2011_D3_ATX |
|   BUDGETO |       cpu |                XEON1 |

一旦该数据以该格式提供,就可以很容易地加入到Components表中,如下所示:

SELECT
      *
FROM (
      /* this "unpivots" the source data */
      SELECT
           nome
         , unnest(array[ram, cpu, mainboard,cases,gfx]) AS colnome
         , unnest(array['ram', 'cpu', 'mainboard','cases','gfx']) AS colkind
      FROM Computer_system
      ) unpiv
INNER JOIN Components c ON unpiv.colnome = c.nome AND unpiv.colkind = c.kind
;

从这里可以很容易地得出这个结果:

|      nome | sum_price |
|-----------|-----------|
|   BUDGETO |       291 |
|   GAMING1 |       515 |
| CONSUMER1 |       292 |
|   SERVER1 |       285 |
|   SERVER2 |       289 |

使用:

SELECT
      unpiv.nome, sum(c.price) sum_price
FROM (
      /* this "unpivots" the source data */
      SELECT
           nome
         , unnest(array[ram, cpu, mainboard,cases,gfx]) AS colnome
         , unnest(array['ram', 'cpu', 'mainboard','cases','gfx']) AS colkind
      FROM Computer_system
      ) unpiv
INNER JOIN Components c ON unpiv.colnome = c.nome AND unpiv.colkind = c.kind
GROUP BY
      unpiv.nome
;

查看此SQLfiddle演示&请注意执行计划

QUERY PLAN
HashAggregate (cost=487.00..488.00 rows=100 width=82)
-> Hash Join (cost=23.50..486.50 rows=100 width=82)
Hash Cond: ((((unnest(ARRAY[computer_system.ram, computer_system.cpu, computer_system.mainboard, computer_system.cases, computer_system.gfx])))::text = (c.nome)::text) AND ((unnest('{ram,cpu,mainboard,cases,gfx}'::text[])) = (c.kind)::text))
-> Seq Scan on computer_system (cost=0.00..112.00 rows=20000 width=368)
-> Hash (cost=15.40..15.40 rows=540 width=120)
-> Seq Scan on components c (cost=0.00..15.40 rows=540 width=120)

答案 1 :(得分:0)

我认为你需要将你的表设计分解为3个表,有Component,Computer_System和Computer_component。以下是字段列表: Computer_System - > computer_id和名字 组件 - > nome_component,种类,价格 Computer_Component - > computer_id,nome_component。使用该表,您可以通过将计算机组件连接到计算机组件上来计算每个computer_id的总价格b on a.computer_id = b.Computer id JOIN组件c ON b.nome_component = c.nome_component

答案 2 :(得分:0)

您只需将Computer_system表加入Component for each kind,就像下面的查询一样,您就可以做到这一点:

select c.nome as name,
  (coalesce(ram.price,0)
   +coalesce(cpu.price,0)
   +coalesce(+mainboard.price,0)
   +coalesce(cases.price,0)
   +coalesce(gfx.price,0)) as price
from Computer_system c
left join Components ram on c.ram=ram.nome
left join Components cpu on c.cpu=cpu.nome
left join Components mainboard on c.mainboard=mainboard.nome
left join Components cases on c.cases=cases.nome
left join Components gfx on c.gfx=gfx.nome

SQLFIDDLE DEMO

答案 3 :(得分:0)

这很棘手,因为您的表格结构不适合此类查询。此外,如果您希望构建中有多个gfx,则它不灵活。

以下是我建议的答案:

select sum(price)
from components
where nome in (
  select ram from computer_system where nome = 'GAMING1'
  UNION ALL 
  select cpu from computer_system where nome = 'GAMING1'
  UNION ALL 
  select mainboard from computer_system where nome = 'GAMING1'
  UNION ALL 
  select cases from computer_system where nome = 'GAMING1'
  UNION ALL 
  select gfx from computer_system where nome = 'GAMING1'
  )
;

这是一个工作小提琴:http://sqlfiddle.com/#!15/228d7/8

如果我重组了表格,我会在这个小提琴中做出类似的事情:http://sqlfiddle.com/#!15/f4ed06/1parts_list表:

CREATE TABLE parts_list (
  system_nome VARCHAR(30),
  component_kind VARCHAR(10),
  component_nome VARCHAR(30),
  PRIMARY KEY (system_nome, component_kind, component_nome)
  );

,您对GAMING1系统成本的查询变得更加简单:

select sum(price)
from components as c 
inner join parts_list as PL ON c.kind = pl.component_kind and c.nome = pl.component_nome
where pl.system_nome = 'GAMING1'
;