总而言之:我需要将几个表格中的数据放在一起,为了不必画一张大桌子,我简化了它们.
我需要在一个查询中这样做,我不能使用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 |
+---+-------+
Run Code Online (Sandbox Code Playgroud)
多个用户可以连接到相同的资源,用户可以访问一个或多个资源.
我希望结果接近:
user,data
+-------+-------+
| user1 | data1 |
+-------+-------+
| user1 | data2 |
+-------+-------+
| user1 | data4 |
+-------+-------+
| user2 | data2 |
+-------+-------+
Run Code Online (Sandbox Code Playgroud)
....等等
我有基本的mysql知识,但这个不在我的知识范围内.有什么方法可以加入t2吗?
我在发布这篇文章之前已经读过的帖子: 如何在join字段中使用逗号分隔列表连接两个表
如果user_resources(t1)是一个'规范化表',每个user => resource组合有一行,那么得到答案的查询就像只有joining表一样简单.
唉,denormalized将resources列作为:''资源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
Run Code Online (Sandbox Code Playgroud)
输出:
user data
---------- --------
sampleuser abcde
sampleuser azerty
sampleuser qwerty
stacky qwerty
testuser abcde
testuser azerty
Run Code Online (Sandbox Code Playgroud)
怎么样:
'技巧'是一个包含从1到某个限制的数字的表.我叫它integerseries.它可以用来转换'水平'的东西,如:';' delimited stringsinto rows.
这种方式的工作方式是,当你"加入"时integerseries,你正在做一个cross join,这就是"自然地"与"内部联接"发生的事情.
每行都integerseries使用表中不同的"序列号"进行复制,我们将其用作列表中"资源"的"索引",我们希望将其用于该表row.
这个想法是:
integerseries一个行转换成一组行提取个人"资源ID"的user.resources我们一起去.我决定使用两个函数:
给定"分隔字符串列表"和"索引"的函数将返回列表中位置的值.我称之为:VALUE_IN_SET.即,给定'A; B; C'和'索引'为2,则返回'B'.
给定"分隔字符串列表"的函数将返回列表中项目数的计数.我称之为:COUNT_IN_SET.即给定'A; B; C'将返回3
它转而认为这两个功能integerseries应该提供一般解决方案delimited items list in a column.
它有用吗?
从a创建"规范化"表的查询';' delimited string in column.它显示所有列,包括由'cross_join'(isequence.idas resources_index)生成的值:
SELECT user_resource.user,
user_resource.resources,
COUNT_IN_SET(user_resource.resources, ';') AS resources_count,
isequence.id AS resources_index,
VALUE_IN_SET(user_resource.resources, ';', isequence.id) AS resources_value
FROM
user_resource
JOIN integerseries AS isequence
ON isequence.id <= COUNT_IN_SET(user_resource.resources, ';')
ORDER BY
user_resource.user, isequence.id
Run Code Online (Sandbox Code Playgroud)
'规范化'表输出:
user resources resources_count resources_index resources_value
---------- --------- --------------- --------------- -----------------
sampleuser 1;2;3 3 1 1
sampleuser 1;2;3 3 2 2
sampleuser 1;2;3 3 3 3
stacky 2 1 1 2
testuser 1;3 2 1 1
testuser 1;3 2 2 3
Run Code Online (Sandbox Code Playgroud)
使用上面的"规范化" user_resources表,它是一个简单的连接,提供所需的输出:
所需的功能(这些是可以在任何地方使用的通用功能)
注意:这些函数的名称与mysql FIND_IN_SET函数有关.即他们在字符串列表方面做了类似的事情?
该COUNT_IN_SET函数:返回的数character delimited items列.
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 ;
Run Code Online (Sandbox Code Playgroud)
的VALUE_IN_SET功能:对待delimited list作为one based array并返回在给定的"索引"的值.
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 ;
Run Code Online (Sandbox Code Playgroud)
相关信息:
最后弄清楚如何获得SQLFiddle - 工作代码来编译函数.
有一个版本适用于SQLite数据库以及SQLite - 规范化连接字段并加入它吗?
表(带数据):
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);
Run Code Online (Sandbox Code Playgroud)
资源:
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');
Run Code Online (Sandbox Code Playgroud)
User_resource:
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');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
440 次 |
| 最近记录: |