0

我相信所有这种性质的问题都是这样开始的…… 我有两张桌子fieldsdataFields描述(不存在的)表的列名并data包含该(不存在的)表的数据。像这样...

领域:

    +----+---------+-------------+---------------+-------+----------+
    | ID | F_ORDER | NAME        | LABEL         | VALUE | TYPE     |
    +----+---------+-------------+---------------+-------+----------+
    |  1 |       1 | IS_EMPLOYEE | Region        |       | checkbox |
    |  2 |       3 | EM_AVATAR   | Avatar        |       | avatar   |
    |  3 |       4 | EM_JOBTITLE | Job Title     |       | text     |
    |  4 |       5 | EM_COMPANY  | Company       |       | text     |
    |  5 |       6 | EM_PHONE    | Phone         |       | text     |
    |  6 |       2 | EM_ORDER    | Display Order | 5     | text     |
    +----+---------+-------------+---------------+-------+----------+

数据:

    +-----+----------+---------+--------------------------------------+
    | ID  | FIELD_ID | USER_ID | VALUE                                |
    +-----+----------+---------+--------------------------------------+
    |   5 |        1 |       1 | YES                                  |
    |   6 |        2 |       1 |                                      |
    |   7 |        3 |       1 | Owner                                |
    |   8 |        4 |       1 | Acme, Inc.                           |
    |   9 |        5 |       1 | 123-456-7987                         |
    | 150 |        5 |      31 | 123-623-5555                         |
    | 149 |        4 |      31 | Acme, Inc.                           |
    | 148 |        3 |      31 | Sales and Customer Support           |
    | 147 |        2 |      31 |                                      |
    | 146 |        1 |      31 | YES                                  |
    |  26 |        1 |       6 | NO                                   |
    |  27 |        2 |       6 | http://example.com/avi/avi.jpeg      |
    |  28 |        3 |       6 | CEO                                  |
    |  29 |        4 |       6 | Acme                                 |
    |  30 |        5 |       6 | (123) 734-5555                       |
    |  31 |        1 |       7 | NO                                   |
    |  32 |        2 |       7 | http://example.com/avi/avi.jpeg      |
    |  33 |        3 |       7 | VP, Services                         |
    |  34 |        4 |       7 | Acme                                 |
    |  35 |        5 |       7 | (913) 963-5555                       |
    |  36 |        1 |      14 | NO                                   |
    |  37 |        2 |      14 | http://example.com/avi/avi.jpeg      |
    |  38 |        3 |      14 | Senior Accountant                    |
    |  39 |        4 |      14 | Acme                                 |
    |  40 |        5 |      14 | (123) 213-5555                       |
    |  41 |        1 |      10 | NO                                   |
    |  42 |        2 |      10 | http://example.com/avi/avi.jpeg      |
    |  43 |        3 |      10 | President                            |
    |  44 |        4 |      10 | Acme                                 |
    |  45 |        5 |      10 | (123) 734-5555                       |
    |  46 |        1 |      12 | NO                                   |
    |  47 |        2 |      12 | http://example.com/avi/avi.jpeg      |
    |  48 |        3 |      12 | Services Supervisor                  |
    |  49 |        4 |      12 | Acme                                 |
    |  50 |        5 |      12 | (123) 573-5555                       |
    |  51 |        1 |      11 | NO                                   |
    |  52 |        2 |      11 | http://example.com/avi/avi.jpeg      |
    |  53 |        3 |      11 | Operations Supervisor                |
    |  54 |        4 |      11 | Acme                                 |
    |  55 |        5 |      11 | (123) 259-5555                       |
    |  56 |        1 |       8 | NO                                   |
    |  57 |        2 |       8 | http://example.com/avi/avi.jpeg      |
    |  58 |        3 |       8 | General Information                  |
    |  59 |        4 |       8 | Acme                                 |
    |  60 |        5 |       8 | (123) 213-5555                       |
    |  61 |        1 |       9 | NO                                   |
    |  62 |        2 |       9 | http://example.com/avi/avi.jpeg      |
    |  63 |        3 |       9 | VP, Sales                            |
    |  64 |        4 |       9 | Acme                                 |
    |  65 |        5 |       9 | (123) 210-5555                       |
    +-----+----------+---------+--------------------------------------+

我要查找的查询的基本用语是:我想要所有员工的所有信息 ( IS_EMPLOYEE = "YES"),并按他们的显示顺序列 ( EM_ORDER) 排序。

到目前为止,我的查询让我无处可去。我得到的结果有点像这样:

    +--------+------------+------------+-------+---------+-------+
     ID        FIELD_ID    NAME         LABEL   TYPE       VALUE
    +--------+------------+------------+-------+---------+-------+
     7         1           IS_EMPLOYEE  Region  checkbox   YES
    +--------+------------+------------+-------+---------+-------+

我需要的是这样的结果:

    +-------+------------+---------+-----------+----------+-------------+--------+
     USER_ID IS_EMPLOYEE  EM_AVATAR EM_JOBTITLE EM_COMPANY EM_PHONE      EM_ORDER   
    +-------+------------+---------+-----------+----------+-------------+--------+
     6       YES           http://  CEO         Acme       123-123-555   5 
    +-------+------------+---------+-----------+----------+-------------+--------+ 

当然,我正试图将它作为一个可用的数组($results['user_id']['jobtitle']等)返回到 PHP 中。我可以得到所有东西并使用 PHP 完成它,但我正在尝试学习 MySQL,我认为这是一种比执行几个 foreach 块更快的方法......虽然我可能是错的。

提前感谢您的帮助。

4

2 回答 2

3

您的数据表以实体-属性-值的方式组织,这不是存储关系数据的有效方式。难怪使用 SQL 将其检索到每个属性一列的常规行中会很尴尬。

要使用 SQL 执行此操作,您基本上需要执行数据透视查询。这很难编写并且执行起来非常低效。

你最好为员工获取所有数据:

SELECT e.*, f.label
FROM Data AS is_employee
JOIN Data AS e USING (user_id)
JOIN Fields AS f ON e.field_id = f.id
WHERE (is_employee.field_id, is_employee.value) = (1, 'Yes');

然后在 PHP 代码中将其重组为关联数组的集合:

while ($row = $stmt->fetch()) {
  $data[ $row['user_id'] ][ $row['label'] ] = $row['value'];
}
于 2012-11-20T20:43:06.237 回答
2

这基本上是一个PIVOT但 MySQL 没有PIVOT函数,因此您可以使用聚合函数和CASE语句来复制它。

静态版本是当您知道要转换为列的所有值时(这些是您的字段名称):

select 
  d.user_id,
  max(case when f.name = 'IS_EMPLOYEE' then d.value else null end) IS_EMPLOYEE,
  max(case when f.name = 'EM_AVATAR' then d.value else null end) EM_AVATAR,
  max(case when f.name = 'EM_JOBTITLE' then d.value else null end) EM_JOBTITLE,
  max(case when f.name = 'EM_COMPANY' then d.value else null end) EM_COMPANY,
  max(case when f.name = 'EM_PHONE' then d.value else null end) EM_PHONE,
  max(case when f.name = 'EM_ORDER' then d.value else null end) EM_ORDER
from data d
left join fields f
  on f.id = d.FIELD_ID
group by d.user_id

请参阅带有演示的 SQL Fiddle

结果:

| USER_ID | IS_EMPLOYEE |                       EM_AVATAR |                EM_JOBTITLE | EM_COMPANY |       EM_PHONE | EM_ORDER |
---------------------------------------------------------------------------------------------------------------------------------
|       1 |         YES |                          (null) |                      Owner | Acme, Inc. |   123-456-7987 |   (null) |
|       6 |          NO | http://example.com/avi/avi.jpeg |                        CEO |       Acme | (123) 734-5555 |   (null) |
|       7 |          NO | http://example.com/avi/avi.jpeg |               VP, Services |       Acme | (913) 963-5555 |   (null) |
|       8 |          NO | http://example.com/avi/avi.jpeg |        General Information |       Acme | (123) 213-5555 |   (null) |
|       9 |          NO | http://example.com/avi/avi.jpeg |                  VP, Sales |       Acme | (123) 210-5555 |   (null) |
|      10 |          NO | http://example.com/avi/avi.jpeg |                  President |       Acme | (123) 734-5555 |   (null) |
|      11 |          NO | http://example.com/avi/avi.jpeg |      Operations Supervisor |       Acme | (123) 259-5555 |   (null) |
|      12 |          NO | http://example.com/avi/avi.jpeg |        Services Supervisor |       Acme | (123) 573-5555 |   (null) |
|      14 |          NO | http://example.com/avi/avi.jpeg |          Senior Accountant |       Acme | (123) 213-5555 |   (null) |
|      31 |         YES |                          (null) | Sales and Customer Support | Acme, Inc. |   123-623-5555 |   (null) |

如果您有未知数量的值要转换为列,那么您可以使用准备好的语句来动态生成 sql。

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when f.name = ''',
      name,
      ''' then d.value end) AS ',
      name
    )
  ) INTO @sql
FROM fields;

SET @sql = CONCAT('SELECT d.user_id, ', @sql, ' 
                  from data d
                  left join fields f
                    on f.id = d.FIELD_ID
                   GROUP BY d.user_id');

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

请参阅带有演示的 SQL Fiddle

两者都会产生相同的结果。

然后,您可以添加一个WHERE子句来过滤掉任何不需要的行。

于 2012-11-20T20:46:07.653 回答