如何编写 mysql 查询以从一个 table 中获取记录列表,其中的列与多个其他 table 连接
How do I write a mysql query to get a list of records from one table with columns concatenated from multiple other tables
我的问题与这个类似:MySQL concatenate values from one table into a record of another
但这不一样,我想是因为我正在尝试使用来自其他几个 table 的多个串联列。
这是我的 tables:
CREATE TABLE `Albums` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userSettingsId` bigint(20) NOT NULL,
`name` varchar(100) NOT NULL,
`description` text DEFAULT NULL,
`isFavorite` tinyint(1) NOT NULL DEFAULT 0,
`isPublic` tinyint(1) NOT NULL DEFAULT 0,
`created` datetime NOT NULL DEFAULT current_timestamp(),
`lastEdited` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `Albums_UN` (`userSettingsId`,`name`),
CONSTRAINT `Albums_FK` FOREIGN KEY (`userSettingsId`) REFERENCES `UserSettings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `AlbumsImages` (
`albumsId` bigint(20) NOT NULL,
`imagesId` bigint(20) NOT NULL,
`isCoverImage` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`albumsId`,`imagesId`),
KEY `AlbumsImages_FK` (`imagesId`),
CONSTRAINT `AlbumsImages_FK` FOREIGN KEY (`imagesId`) REFERENCES `Images` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `AlbumsImages_FK_1` FOREIGN KEY (`albumsId`) REFERENCES `Albums` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `Collaborators` (
`albumsId` bigint(20) NOT NULL,
`access` enum('view','put','edit') NOT NULL DEFAULT 'view',
`email` varchar(100) NOT NULL,
PRIMARY KEY (`albumsId`,`email`),
CONSTRAINT `Collaborators_FK_1` FOREIGN KEY (`albumsId`) REFERENCES `Albums` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `Images` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`src` longtext NOT NULL,
`fileName` varchar(100) NOT NULL,
`alt` varchar(100) NOT NULL,
`userSettingsId` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Images_UN_FileName_UserSettingsId` (`fileName`,`userSettingsId`),
KEY `Images_FK` (`userSettingsId`),
CONSTRAINT `Images_FK` FOREIGN KEY (`userSettingsId`) REFERENCES `UserSettings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8 COMMENT='All images in the application';
CREATE TABLE `UserSettings` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`email` varchar(100) NOT NULL,
`firstName` varchar(100) NOT NULL,
`lastName` varchar(100) NOT NULL,
`password` text NOT NULL,
`isDarkThemeEnabled` tinyint(1) NOT NULL DEFAULT 1,
`sessionId` varchar(255) DEFAULT NULL,
`profilePicture` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UserSettings_Email_UN` (`email`),
UNIQUE KEY `UserSettings_SessionId_UN` (`sessionId`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='User Settings and Info'
注意:Collaborators
table 不使用 UserSettings.id
的外键,因为合作者不一定要有帐户。
所以,我想获取特定用户的所有相册和相关的辅助信息。像这样:
[
{
id: 1,
name: 'Album Name',
description: 'Description',
isFavorite: 0,
created: '2021-04-26 23:14:05',
lastEdited: '2021-04-27 19:12:02',
images: [
{
fileName: 'image.jpg',
alt: 'Image Title',
src: 'www.image.com/image.jpg',
isCoverImage: 0,
}, //...etc
],
collaborators: [
{
email: 'someone@example.com',
firstName: null,
lastName: null,
id: null,
access: 'put',
},
{
email: 'someoneelse@example.com',
firstName: 'someone',
lastName: 'else',
id: 14,
access: 'view',
}, //...etc
],
}, //...etc
]
这是我目前正在处理的查询。
SELECT
a.id,
a.name,
a.description,
a.isFavorite,
a.created,
a.lastEdited,
concat('[', group_concat(json_object(
'fileName', i.fileName,
'alt', i.alt,
'src', i.src,
'isCoverImage', ai.isCoverImage
)), ']') as images,
concat('[', group_concat(json_object(
'email', c.email,
'firstName', u.firstName,
'lastName', u.lastName,
'id', u.id,
'access', c.access
)), ']') as collaborators
from Albums a
left join AlbumsImages ai
on a.id=ai.albumsId
left join Images i
on i.id=ai.imagesId
left join Collaborators c
on c.albumsId = a.id
left join UserSettings u
on c.email = u.email
where a.userSettingsId=?
group by id;
Aa 并且它 确实 工作...有点。我得到了所有的相册和它们的所有信息,但是合作者的图像数量是重复的,反之亦然。作为现在的创可贴,我有一些在查询后立即运行的重复数据删除代码,但这显然是 hacky,不是我想要长期使用的东西。
有没有办法解决这个问题来做我想做的事,或者我是不是白痴,一开始就想在一个查询中获取所有这些信息?
谢谢!
所以你在 Collaborators 和 Images 之间有一个笛卡尔积。因此,两者都乘以另一个结果的数量。
您可以 运行 多个查询,然后编写应用程序代码将结果附加到更大的 JSON 文档中。
或者您可以使用相关子查询:
SELECT
a.id,
a.name,
a.description,
a.isFavorite,
a.created,
a.lastEdited,
concat('[', (
select group_concat(json_object(
'fileName', i.fileName,
'alt', i.alt,
'src', i.src,
'isCoverImage', ai.isCoverImage))
from Images i where i.id=ai.imagesId
), ']') as images,
concat('[', (
select group_concat(json_object(
'email', c.email,
'firstName', u.firstName,
'lastName', u.lastName,
'id', u.id,
'access', c.access))
from Collaborators c
left join UserSettings u
on c.email = u.email
where c.albumsId=a.id
), ']') as collaborators
from Albums a
left join AlbumsImages ai
on a.id=ai.albumsId
where a.userSettingsId=?
group by id;
(未测试)
我的问题与这个类似:MySQL concatenate values from one table into a record of another
但这不一样,我想是因为我正在尝试使用来自其他几个 table 的多个串联列。
这是我的 tables:
CREATE TABLE `Albums` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userSettingsId` bigint(20) NOT NULL,
`name` varchar(100) NOT NULL,
`description` text DEFAULT NULL,
`isFavorite` tinyint(1) NOT NULL DEFAULT 0,
`isPublic` tinyint(1) NOT NULL DEFAULT 0,
`created` datetime NOT NULL DEFAULT current_timestamp(),
`lastEdited` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `Albums_UN` (`userSettingsId`,`name`),
CONSTRAINT `Albums_FK` FOREIGN KEY (`userSettingsId`) REFERENCES `UserSettings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `AlbumsImages` (
`albumsId` bigint(20) NOT NULL,
`imagesId` bigint(20) NOT NULL,
`isCoverImage` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`albumsId`,`imagesId`),
KEY `AlbumsImages_FK` (`imagesId`),
CONSTRAINT `AlbumsImages_FK` FOREIGN KEY (`imagesId`) REFERENCES `Images` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `AlbumsImages_FK_1` FOREIGN KEY (`albumsId`) REFERENCES `Albums` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `Collaborators` (
`albumsId` bigint(20) NOT NULL,
`access` enum('view','put','edit') NOT NULL DEFAULT 'view',
`email` varchar(100) NOT NULL,
PRIMARY KEY (`albumsId`,`email`),
CONSTRAINT `Collaborators_FK_1` FOREIGN KEY (`albumsId`) REFERENCES `Albums` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `Images` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`src` longtext NOT NULL,
`fileName` varchar(100) NOT NULL,
`alt` varchar(100) NOT NULL,
`userSettingsId` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Images_UN_FileName_UserSettingsId` (`fileName`,`userSettingsId`),
KEY `Images_FK` (`userSettingsId`),
CONSTRAINT `Images_FK` FOREIGN KEY (`userSettingsId`) REFERENCES `UserSettings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8 COMMENT='All images in the application';
CREATE TABLE `UserSettings` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`email` varchar(100) NOT NULL,
`firstName` varchar(100) NOT NULL,
`lastName` varchar(100) NOT NULL,
`password` text NOT NULL,
`isDarkThemeEnabled` tinyint(1) NOT NULL DEFAULT 1,
`sessionId` varchar(255) DEFAULT NULL,
`profilePicture` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UserSettings_Email_UN` (`email`),
UNIQUE KEY `UserSettings_SessionId_UN` (`sessionId`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='User Settings and Info'
注意:Collaborators
table 不使用 UserSettings.id
的外键,因为合作者不一定要有帐户。
所以,我想获取特定用户的所有相册和相关的辅助信息。像这样:
[
{
id: 1,
name: 'Album Name',
description: 'Description',
isFavorite: 0,
created: '2021-04-26 23:14:05',
lastEdited: '2021-04-27 19:12:02',
images: [
{
fileName: 'image.jpg',
alt: 'Image Title',
src: 'www.image.com/image.jpg',
isCoverImage: 0,
}, //...etc
],
collaborators: [
{
email: 'someone@example.com',
firstName: null,
lastName: null,
id: null,
access: 'put',
},
{
email: 'someoneelse@example.com',
firstName: 'someone',
lastName: 'else',
id: 14,
access: 'view',
}, //...etc
],
}, //...etc
]
这是我目前正在处理的查询。
SELECT
a.id,
a.name,
a.description,
a.isFavorite,
a.created,
a.lastEdited,
concat('[', group_concat(json_object(
'fileName', i.fileName,
'alt', i.alt,
'src', i.src,
'isCoverImage', ai.isCoverImage
)), ']') as images,
concat('[', group_concat(json_object(
'email', c.email,
'firstName', u.firstName,
'lastName', u.lastName,
'id', u.id,
'access', c.access
)), ']') as collaborators
from Albums a
left join AlbumsImages ai
on a.id=ai.albumsId
left join Images i
on i.id=ai.imagesId
left join Collaborators c
on c.albumsId = a.id
left join UserSettings u
on c.email = u.email
where a.userSettingsId=?
group by id;
Aa 并且它 确实 工作...有点。我得到了所有的相册和它们的所有信息,但是合作者的图像数量是重复的,反之亦然。作为现在的创可贴,我有一些在查询后立即运行的重复数据删除代码,但这显然是 hacky,不是我想要长期使用的东西。
有没有办法解决这个问题来做我想做的事,或者我是不是白痴,一开始就想在一个查询中获取所有这些信息?
谢谢!
所以你在 Collaborators 和 Images 之间有一个笛卡尔积。因此,两者都乘以另一个结果的数量。
您可以 运行 多个查询,然后编写应用程序代码将结果附加到更大的 JSON 文档中。
或者您可以使用相关子查询:
SELECT
a.id,
a.name,
a.description,
a.isFavorite,
a.created,
a.lastEdited,
concat('[', (
select group_concat(json_object(
'fileName', i.fileName,
'alt', i.alt,
'src', i.src,
'isCoverImage', ai.isCoverImage))
from Images i where i.id=ai.imagesId
), ']') as images,
concat('[', (
select group_concat(json_object(
'email', c.email,
'firstName', u.firstName,
'lastName', u.lastName,
'id', u.id,
'access', c.access))
from Collaborators c
left join UserSettings u
on c.email = u.email
where c.albumsId=a.id
), ']') as collaborators
from Albums a
left join AlbumsImages ai
on a.id=ai.albumsId
where a.userSettingsId=?
group by id;
(未测试)