0

Ok, I'm still a beginner in sql and can not figure this one out yet. I have four tables: companies, persons, details, person_details.

companies: 
id, compname
(1, ACME), 
(2, ACME Group), ...

persons: 
id, name, lastname, company id
(1, donald, duck, 1), 
(2, lucky, luke, 1), 
(3, mickey, mouse, 2)

details: 
id, description
(1, 'weight'), 
(2, 'height'), 
(3, 'haircolor'), ...

person_details: 
id, persons id, details id, value
(1, 1, 1, 70), 
(2, 1, 3, 'red'), 
(3, 2, 1, 90), 
(4, 3, 2, 180)

As you can see, not all persons have all the details and the list of available details is variable.

Now, for a given arary of person ids and detail ids, I would like to get rows containing: company name and id, person name and last name, detail name and value for each of the details in the supplied array. Let's say persons(1,2), details(1,3) should result in:

companies.id, companies.name, name, lastname, details.description, person_details.value,...    
    1, ACME, donald, duck, 'weight', 70, 'haircolor', 'red'
    2, ACEM, lucky, luke, 'weight', 90, 'haircolor', null

Help, please...

4

1 回答 1

1

根据您的描述,您似乎想要对数据进行透视,但不幸的是 MySQL 没有透视函数,因此您需要使用带有CASE语句的聚合函数来复制它。

如果您提前知道描述值,则可以将查询硬编码为以下内容:

select c.id,
  c.compname,
  p.name,
  p.lastname,
  max(case when d.description = 'weight' then pd.value end) weight,
  max(case when d.description = 'haircolor' then pd.value end) haircolor,
  max(case when d.description = 'height' then pd.value end) height
from companies c
left join persons p
  on c.id = p.`company id`
left join person_details pd
  on p.id = pd.`persons id`
left join details d
  on pd.`details id` = d.id
-- where p.id in (1, 2)
group by c.id, c.compname, p.name, p.lastname

请参阅带有演示的 SQL Fiddle

如果您有未知数量的值,则可以使用准备好的语句来动态生成类似于以下内容的值:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(CASE WHEN d.description = ''',
      description,
      ''' then pd.value end) AS ',
      description
    )
  ) INTO @sql
FROM details;

SET @sql = CONCAT('SELECT c.id,
                      c.compname,
                      p.name,
                      p.lastname, ', @sql, ' 
                  from companies c
                  left join persons p
                    on c.id = p.`company id`
                  left join person_details pd
                    on p.id = pd.`persons id`
                  left join details d
                    on pd.`details id` = d.id
                  -- where p.id in (1, 2)
                  group by c.id, c.compname, p.name, p.lastname');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

请参阅带有演示的 SQL Fiddle

两个版本都会生成结果:

| ID |   COMPNAME |   NAME | LASTNAME | WEIGHT | HEIGHT | HAIRCOLOR |
---------------------------------------------------------------------
|  1 |       ACME | donald |     duck |     70 | (null) |       red |
|  1 |       ACME |  lucky |     luke |     90 | (null) |    (null) |
|  2 | ACME Group | mickey |    mouse | (null) |    180 |    (null) |
于 2012-12-31T14:23:34.227 回答