【问题标题】:MySQL query to expand a bitfield into individual named columns?MySQL查询将位域扩展为单独的命名列?
【发布时间】:2017-07-06 06:41:49
【问题描述】:

我有以下问题 我有两个表,第一个表包含一个类似 01001101110 的字符串,每个数字代表表二中提到的技能。

所以第一个数字显示一个零,表示此人不具备 id 1 的技能。第二个数字显示此人确实具有 id 2 的技能

表 1:

|-----------|-----------------------------|
|  name  |             skillset            |
|-----------|-----------------------------|
|   John  | 01001101110             |
|-----------|-----------------------------|

表 2:

|-----------|-----------------------------|
|    id       |              skill              |
|-----------|-----------------------------|
|       1    | polite                         |
|-----------|-----------------------------|
|      2     | easy going                 |
|-----------|-----------------------------|

现在我需要创建带有结果的 i 查询

|-----------|-------------------|------------------|
|  name  |      polite        |   easy going  |
|-----------|-------------------|------------------|
|  John   |          0            |            1        |
|-----------|-------------------|------------------|

【问题讨论】:

  • 你到底为什么要设计这样的桌子?规范化您的数据并对其进行查询变得微不足道。
  • 我以前没有为公司工作的脚本编写者做过,我们现在必须忍受它。但我知道重新设计是一种选择,但不是我现在正在寻找的。
  • 技能列表长 158 项,正在与两个表进行匹配。像这样看待它的想法非常巧妙,但也许不是解决它的最佳方法。前编码员的所有学分
  • 你可以用substring得到一个字符串的字符。将行放入列中称为枢轴,例如here。如果你现在在想:“天哪,我必须写 158 个案例陈述吗?”。不,你不必那样做。您甚至不必加入您的第二张桌子。您只需要编写 158 个子字符串语句,因为该表设计对于进行数据透视来说还算不错。别的不多,但至少做一个支点。 (因为它基本上已经是一个支点)。
  • 我改写了你的问题的标题。 Stack Overflow 更喜欢标题描述或总结问题,而不是仅描述您的“Noob using MySQL”。 :-)

标签: mysql pivot-table dynamic-sql bit-fields


【解决方案1】:

我见过很多这样的故事,“一位前程序员实现了这个,现在我们被它困住了。”我想只有一个单独的程序员,他从一家公司搬到另一家公司,以最聪明和最难维护的方式实现事情,然后迅速转移到他的下一个受害公司。

我还觉得讽刺的是,有人会在 varchar 中实现一个位域,因为他们最终使用一个完整字节(8 位)来存储每个 1 或 0。:facepalm:

无论如何,要解决您的任务,您必须使用动态 SQL 查询。

事实上,any 数据透视表查询需要动态 SQL,因为在您检查列出您的技能的表之前,您不知道列数,但是您无法运行查询首先知道列数。因此,您至少需要运行两个查询。

这是测试数据:

create table table1 (name varchar(20), skillset varchar(200));

insert into table1 values ('John', '01001101110110');

create table table2 (id int, skill varchar(20));

insert into table2 values
    (1, 'polite'),
    (2, 'easy going'),
    (3, 'trustworthy'),
    (4, 'loyal'),
    (5, 'helpful'),
    (6, 'friendly'),
    (7, 'courteous'),
    (8, 'kind'),
    (9, 'obedient'),
    (10, 'cheerful'),
    (11, 'thrifty'),
    (12, 'brave'),
    (13, 'clean'),
    (14, 'reverent');

Now 是一个聪明的查询,它通过在选择列表中为技能表中的每个条目附加一个字段来生成动态查询的 SQL。关键是MySQL的GROUP_CONCAT()函数。

select concat(
    'select name,',
    group_concat(concat(' mid(skillset,',id,',1) as `',skill,'`')),
    ' from table1;') as _sql
from table2;

上述查询的输出如下:

select name, 
 mid(skillset,1,1) as `polite`, 
 mid(skillset,2,1) as `easy going`, 
 mid(skillset,3,1) as `trustworthy`, 
 mid(skillset,4,1) as `loyal`, 
 mid(skillset,5,1) as `helpful`, 
 mid(skillset,6,1) as `friendly`, 
 mid(skillset,7,1) as `courteous`, 
 mid(skillset,8,1) as `kind`, 
 mid(skillset,9,1) as `obedient`, 
 mid(skillset,10,1) as `cheerful`, 
 mid(skillset,11,1) as `thrifty`, 
 mid(skillset,12,1) as `brave`, 
 mid(skillset,13,1) as `clean`, 
 mid(skillset,14,1) as `reverent` 
from table1;

我确保使用反引号分隔列别名,以防其中一个技能名称包含特殊字符或空格或与 SQL 保留字冲突。

然后这可以作为第二个查询运行,其结果如下:

+------+--------+------------+-------------+-------+---------+----------+-----------+------+----------+----------+---------+-------+-------+----------+
| name | polite | easy going | trustworthy | loyal | helpful | friendly | courteous | kind | obedient | cheerful | thrifty | brave | clean | reverent |
+------+--------+------------+-------------+-------+---------+----------+-----------+------+----------+----------+---------+-------+-------+----------+
| John | 0      | 1          | 0           | 0     | 1       | 1        | 0         | 1    | 1        | 1        | 0       | 1     | 1     | 0        |
+------+--------+------------+-------------+-------+---------+----------+-----------+------+----------+----------+---------+-------+-------+----------+

【讨论】:

    【解决方案2】:

    使其成为SET 数据类型;这为您提供了两全其美的优势 - 以位为单位存储多达 64 个预定义选项的任意组合,并以字符串形式读取/写入。

    简单的SELECT skillset FROM tbl WHERE name = 'John' 会作为字符串返回

    "easy going,helpful,friendly,kind"  (etc)
    

    Reference

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-28
      • 2017-09-19
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 2012-09-13
      • 2016-01-12
      • 2018-09-01
      相关资源
      最近更新 更多