Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我可以用纯mysql解决这个问题吗?(在列中以';';分隔的值连接)_Mysql_Join - Fatal编程技术网

我可以用纯mysql解决这个问题吗?(在列中以';';分隔的值连接)

我可以用纯mysql解决这个问题吗?(在列中以';';分隔的值连接),mysql,join,Mysql,Join,长话短说:我有几个表中的数据需要收集在一起,为了不必绘制一个巨大的表,我简化了它们 我需要在一个查询中这样做,我不能使用PHP或任何其他语言来处理结果。(如果我能简单地解决这个问题,我会使用PHP) 如果我有一个连接t1行和t2行的链接表,这就不会是一个问题,但不幸的是,我没有也不能引入一个链接表 User table: (alias t1) user(varchar 150),resources(varchar 250) +-------+-------+ | user1 | 1;2;4 |

长话短说:我有几个表中的数据需要收集在一起,为了不必绘制一个巨大的表,我简化了它们

我需要在一个查询中这样做,我不能使用PHP或任何其他语言来处理结果。(如果我能简单地解决这个问题,我会使用PHP)

如果我有一个连接t1行和t2行的链接表,这就不会是一个问题,但不幸的是,我没有也不能引入一个链接表

User table: (alias t1)
user(varchar 150),resources(varchar 250)
+-------+-------+
| user1 | 1;2;4 |
+-------+-------+
| user2 | 2     |
+-------+-------+
| user3 | 3;4   |
+-------+-------+

Resources table: (alias t2)
id(int 11 AI), data(text)
+---+-------+
| 1 | data1 |
+---+-------+
| 2 | data2 |
+---+-------+
| 3 | data3 |
+---+-------+
| 4 | data4 |
+---+-------+
| 5 | data5 |
+---+-------+
多个用户可以连接到同一资源,并且用户可以访问一个或多个资源

我希望结果接近:

user,data
+-------+-------+
| user1 | data1 |
+-------+-------+
| user1 | data2 |
+-------+-------+
| user1 | data4 |
+-------+-------+
| user2 | data2 |
+-------+-------+
……等等

我有基本的mysql知识,但这个超出了我的知识范围。我有办法加入t2吗

我在写这篇文章之前读过的帖子:


如果
用户资源(t1)是一个“规范化表”,每个
用户=>资源组合有一行,那么获取答案的查询将非常简单,只需将
表连接在一起即可

唉,它是
非规范化的
,方法是将
资源
列作为一个“资源id列表”,用“;”分隔性格

如果我们能够将“resources”列转换成行,那么随着表连接变得简单,许多困难就消失了

用于生成所需输出的查询:

SELECT user_resource.user, 
       resource.data

FROM user_resource 
     JOIN integerseries AS isequence 
       ON isequence.id <= COUNT_IN_SET(user_resource.resources, ';') /* normalize */

     JOIN resource 
       ON resource.id = VALUE_IN_SET(user_resource.resources, ';', isequence.id)      
ORDER BY
       user_resource.user,  resource.data
如何:

“诀窍”是有一个包含从1到某个极限的数字的表。我称之为
integerseries
。它可以用来转换“水平”事物,例如:
“;”分隔字符串

其工作方式是,当您使用
整数系列
进行“连接”时,您正在进行
交叉连接
,这是使用“内部连接”时“自然”发生的情况

integerseries
表中,每一行都使用不同的“序列号”进行复制,我们将其用作列表中要用于该
行的“资源”的“索引”

其想法是:

  • 计算列表中的项目数
  • 根据项目在列表中的位置提取每个项目
  • 使用
    integerseries
    将一行转换为一组行,从
    user
    resources
    提取单个“资源id”
我决定使用两个函数:

  • 给定“分隔字符串列表”和“索引”的函数将返回列表中位置处的值。我称之为:
    集合中的值。i、 e.给予“A”;BC'和'index'为2,然后返回'B'

  • 给定“分隔字符串列表”的函数将返回列表中项目数的计数。我称之为:
    COUNT\u IN\u SET
    。i、 e.给予“A”;BC'将返回3

结果是,这两个函数和
integerseries
应该为列中的
分隔项列表提供一个通用解决方案

它有用吗

创建“规范化”表的查询;'列中的分隔字符串
。它显示所有列,包括由于“交叉联接”而生成的值(
isequence.id
as
resources\u index
):

使用上述“规范化的”
user\u resources
表,它是一个简单的连接,可以提供所需的输出:

所需的功能(这些是可以在任何地方使用的通用功能)

注意:这些函数的名称与mysql相关。i、 e.他们在字符串列表方面做了类似的事情

COUNT\u IN_SET
函数:返回列中
字符分隔项的计数

DELIMITER $$

DROP FUNCTION IF EXISTS `COUNT_IN_SET`$$

CREATE FUNCTION `COUNT_IN_SET`(haystack VARCHAR(1024), 
                               delim CHAR(1)
                               ) RETURNS INTEGER
BEGIN
      RETURN CHAR_LENGTH(haystack) - CHAR_LENGTH( REPLACE(haystack, delim, '')) + 1;
END$$

DELIMITER ;
集合中的
函数:将
分隔列表
视为一个
基于一的数组
,并返回给定“索引”处的值

DELIMITER $$

DROP FUNCTION IF EXISTS `VALUE_IN_SET`$$

CREATE FUNCTION `VALUE_IN_SET`(haystack VARCHAR(1024), 
                               delim CHAR(1), 
                               which INTEGER
                               ) RETURNS VARCHAR(255) CHARSET utf8 COLLATE utf8_unicode_ci
BEGIN
      RETURN  SUBSTRING_INDEX(SUBSTRING_INDEX(haystack, delim, which),
                     delim,
                     -1);
END$$

DELIMITER ;
相关信息:

user        data    
----------  --------
sampleuser  abcde   
sampleuser  azerty  
sampleuser  qwerty  
stacky      qwerty  
testuser    abcde   
testuser    azerty  
  • 最终解决了如何编译函数

  • 有一个版本也适用于
    SQLite
    数据库

表(含数据):

资源:

CREATE TABLE `resource` (
  `id` int(11) NOT NULL,
  `data` varchar(250) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `resource` */

insert  into `resource`(`id`,`data`) values (1,'abcde');
insert  into `resource`(`id`,`data`) values (2,'qwerty');
insert  into `resource`(`id`,`data`) values (3,'azerty');
用户资源:

CREATE TABLE `user_resource` (
  `user` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `resources` varchar(250) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`user`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `user_resource` */

insert  into `user_resource`(`user`,`resources`) values ('sampleuser','1;2;3');
insert  into `user_resource`(`user`,`resources`) values ('stacky','3');
insert  into `user_resource`(`user`,`resources`) values ('testuser','1;3');

如果更换
使用
您可以使用FIND_IN_SET函数来连接您的表:

选择u.user,r.data
来自用户u
加入资源库
在查找集合中的时(r.id,replace(u.resources,“;”,“,”))
美国用户订购,r.id
结果:

|用户|数据|
|-------|-------|
|用户1 |数据1|
|用户1 |数据2|
|用户1 |数据4|
|用户2 |数据2|
|用户3 |数据3|
|用户3 |数据4|

如果您可以使用子查询将
用户表(t1)
转换为“适当的表”,那么您能在一个查询中解决它吗?如果是这样,问题就变成了转换
user1 | 1;2.4
进入“行”。这在标准SQL中是可能的。是的,如果你用一个连续的“整数”表连接它。我调用“integerseries”。当我测试它时,我会把它放在一个视图中。我还没有试过,但它应该可以工作。如果你用测试数据设置一个。我想快速开始测试查询,而不是设置表和测试数据。我在@RyanVincent做了一件类似的事情,今天晚些时候当我有一台可用的pc时,我会做一件类似的事情,当时我发布了这篇文章,sqlfiddle是遥不可及的:(@RyanVincent整理并添加了一个工作项。我已经使用函数重新做了这个,它更整洁了。很快将发布更新。感谢您在这里为帮助我付出的巨大努力:)视图解决方案足以让我立即完成工作,但我真的很期待你的其他解决方案,也用于学习目的。如果你将此作为单独的答案发布,我可以投票。
CREATE TABLE `integerseries` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `integerseries` */

insert  into `integerseries`(`id`) values (1);
insert  into `integerseries`(`id`) values (2);
insert  into `integerseries`(`id`) values (3);
insert  into `integerseries`(`id`) values (4);
insert  into `integerseries`(`id`) values (5);
insert  into `integerseries`(`id`) values (6);
insert  into `integerseries`(`id`) values (7);
insert  into `integerseries`(`id`) values (8);
insert  into `integerseries`(`id`) values (9);
insert  into `integerseries`(`id`) values (10);
CREATE TABLE `resource` (
  `id` int(11) NOT NULL,
  `data` varchar(250) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `resource` */

insert  into `resource`(`id`,`data`) values (1,'abcde');
insert  into `resource`(`id`,`data`) values (2,'qwerty');
insert  into `resource`(`id`,`data`) values (3,'azerty');
CREATE TABLE `user_resource` (
  `user` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `resources` varchar(250) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`user`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `user_resource` */

insert  into `user_resource`(`user`,`resources`) values ('sampleuser','1;2;3');
insert  into `user_resource`(`user`,`resources`) values ('stacky','3');
insert  into `user_resource`(`user`,`resources`) values ('testuser','1;3');