【问题标题】:How do I convert a many-to-many relationship from 2-column table?如何从 2 列表转换多对多关系?
【发布时间】:2012-03-09 20:59:59
【问题描述】:

假设我有一个存储两个列表之间关系的数据库表(下面的一些示例代码)(在我的例子中是需求和测试用例),并且我想创建一个表,其中的行显示测试用例,列显示需求,指示器显示存在关系。

一些限制

  • 我没有更改数据库结构的奢侈,因为它属于开源测试用例管理系统 (TestLink)。
  • 可以为此编写一些代码,但我希望可以在 MySQL 中完成。
  • 啊,是的,它使用 MySQL,所以它必须在那个环境中工作。
  • 此功能曾经存在,但已被取消,因为通常情况下,当有数以万计的测试用例和需求时,这种类型的工作会使数据库陷入困境。

    创建表pivot ( req_id int(11), testcase_id int(11) ) ;

    /*表pivot的数据*/

    插入pivot(req_id,testcase_id) 值 (1,1);

    插入pivot(req_id,testcase_id) 值 (2,2);

    插入pivot(req_id,testcase_id) 值 (3,3);

    插入pivot(req_id,testcase_id) 值 (4,1);

    插入pivot(req_id,testcase_id) 值 (5,2);

    插入pivot(req_id,testcase_id) 值 (6,3);

    插入pivot(req_id,testcase_id) 值 (2,1);

    插入pivot(req_id,testcase_id) 值 (3,2);

我想从查询中得到一个看起来像这样的表:

   1    2    3    4    5    6
1  x    x         x
2       x    x         x
3            x              x

注意:行是testcase_ids,列是'req_ids'

任何人都知道如何仅使用 SQL 来获得此信息?

【问题讨论】:

  • 您正在尝试生成关系模型的报告,这不是您应该在 SQL 中执行的操作。 SQL 是用于可靠存储和返回结构化数据的引擎,而不是用于格式化数据的引擎。报告工具甚至电子表格都可以轻松地为您转换这些数据。
  • 如果您有一组已知的 testcase_id,那么您可以编写一系列乏味的左连接来获得结果。如果您不知道,那么您可以生成一系列左连接作为动态查询,然后将它们放在前面提到的繁琐查询中。无论哪种方式,这都很乏味和不愉快。
  • 测试用例会随着时间的推移而增长(需求列表也会增长),因此实现这一目标的通用方式将是首选方式。
  • 感谢大家的参与:)

标签: mysql sql many-to-many pivot-table


【解决方案1】:

下面的效率要高得多:

为test_cases创建一张表,比如

create table testCases(
id int(11) auto_increment,
testcase varchar(200),
primary key(id))

一张需求表

requirements(
id int(11) auto_increment,
requirements varchar(200),
primary key(id))

然后在第三个表中映射关系

 create table matchRequirementsToTests(
 requirements varchar(200),
 testcase varchar(200),
primary key(requirements, testcase),
foreign key (requirements) references Requirements(id),
foreign key(test case) references Test_cases(id))

【讨论】:

  • 对不起,这个数据库不是我要更改的,而是要查询的。
  • 我明白了。不幸的是,您尝试做的事情并不适合 mysql。从mysql得到结果集后,你应该在控制层--php、java等做
  • 你好。这是您创建三个表(作为多对多关系)的方式,但是您如何使用它们来执行查询(并让 SQL 遵循关系)?谢谢
【解决方案2】:
select testcase_id, 
  if(sum(req_id = 1), 'X', '') as '1', 
  if(sum(req_id = 2), 'X', '') as '2', 
  if(sum(req_id = 3), 'X', '') as '3', 
  if(sum(req_id = 4), 'X', '') as '4', 
  if(sum(req_id = 5), 'X', '') as '5', 
  if(sum(req_id = 6), 'X', '') as '6'
from pivot
group by testcase_id;

它很丑,但它有效:

+-------------+---+---+---+---+---+---+
| testcase_id | 1 | 2 | 3 | 4 | 5 | 6 |
+-------------+---+---+---+---+---+---+
|           1 | X | X |   | X |   |   | 
|           2 |   | X | X |   | X |   | 
|           3 |   |   | X |   |   | X | 
+-------------+---+---+---+---+---+---+
3 rows in set (0.00 sec)

【讨论】:

  • 所以每次添加需求都需要修改脚本吗?有没有办法概括这一点?
  • 我不知道有什么方法可以在结果集中动态生成列。如果是我的应用程序,我会编写一个程序来生成 sql,然后在数据库上运行 sql;不要试图让 sql 做动态部分。您有更多工具可以用其他过程语言编写高效的 sql - 您可以自动分析架构、决定需要哪些列、生成特定的 sql、运行它并获得所需的输出。
【解决方案3】:

我现在有一个我想要完成的名字。这是一个“动态交叉表”。这是我如何得到解决方案的。感谢http://rpbouman.blogspot.com/2005/10/creating-crosstabs-in-mysql.html 提供的明确指示。

第 1-20 行 - 设置用于测试的表格。

第 22-29 行 - 一个“静态”交叉表查询,假设我知道我有多少需求。 感谢 D Mac 提供的解决方案:)

第 30-44 行 - 动态生成上述静态查询的查询。

第 45-72 行 - 这就是我遇到问题的地方。目的是创建一个返回动态查询结果的存储过程。 MySQL 说存在语法问题,但我不知道如何解决它。有什么想法吗?

drop table if exists pivot;

create table `pivot` ( 
`req_id` int(11), 
`testcase_id` int(11) 
); 

/*Data for the table `pivot` */ 

insert into `pivot`(`req_id`,`testcase_id`) values (1,4); 
insert into `pivot`(`req_id`,`testcase_id`) values (2,4); 
insert into `pivot`(`req_id`,`testcase_id`) values (3,4); 
insert into `pivot`(`req_id`,`testcase_id`) values (4,7); 
insert into `pivot`(`req_id`,`testcase_id`) values (1,7); 
insert into `pivot`(`req_id`,`testcase_id`) values (2,12); 
insert into `pivot`(`req_id`,`testcase_id`) values (3,12); 
insert into `pivot`(`req_id`,`testcase_id`) values (4,4); 

select * from pivot;

select testcase_id
,        if(sum(req_id = 1), 1, 0)
,        if(sum(req_id = 2), 1, 0)
,        if(sum(req_id = 3), 1, 0)
,        if(sum(req_id = 4), 1, 0)
from pivot
group by testcase_id;

select concat(
      'select testcase_id','\n'
      , group_concat(
         concat(
                ',        if(sum(req_id = ',p2.req_id,'), 1, 0)','\n'
          )
          order by p2.req_id
          separator ''
        )
      , 'from pivot','\n'
      , 'group by testcase_id;','\n'
      ) statement
from pivot p2
order by p2.req_id;

CREATE PROCEDURE p_coverage()
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
begin
    select concat(
                  'select testcase_id','\n'
                  , group_concat(
                     concat(
                            ',        if(sum(req_id = ',p2.req_id,'), 1, 0)','\n'
                      )
                      order by p2.req_id
                      separator ''
                    )
                  , 'from pivot','\n'
                  , 'group by testcase_id;','\n'
                  ) statement
    into @coverage_query
    from pivot p2
    order by p2.req_id;

    prepare coverage from @coverage_query;

    execute coverage;

    deallocate prepare coverage;
end;

select * from pivot;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 2019-08-22
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    相关资源
    最近更新 更多