从加入中排除项目 table
Exclude items from join table
CREATE TABLE `files`
(
`file_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`filename` text COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`file_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
INSERT INTO `files` (`file_id`, `filename`)
VALUES (100, 'file_100.ext'),
(101, 'file_101.ext');
CREATE TABLE `files_tags`
(
`file_id` bigint(20) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`file_id`, `tag_id`),
CONSTRAINT `FK__files` FOREIGN KEY (`file_id`) REFERENCES `files` (`file_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
INSERT INTO `files_tags` (`file_id`, `tag_id`)
VALUES (100, 1),
(100, 2),
(100, 3),
(101, 1),
(101, 2);
SQL fiddle: http://www.sqlfiddle.com/#!9/b776ab/3
我有一个连接 table (files_tags),它列出了另一个 table(文件)的标签。我有以下查询,它适用于 select 所有标有标签 1 和 2 的文件:
SELECT f.filename
FROM files_tags ft0
INNER JOIN files f ON ft0.file_id = f.file_id
INNER JOIN files_tags ft1 ON f.file_id = ft1.file_id AND ft1.tag_id = 2
WHERE ft0.tag_id = 1;
我正在寻找 selects 文件标记为 1 和 2 但不是 3 的查询。我尝试使用此附加连接进行上述查询:
INNER JOIN files_tags ft2 ON f.file_id = ft2.file_id AND ft1.tag_id = 3
但这最终只会返回 5 行(与 files_tags table 相同),这不是我想要的。 我对此的预期输出是单行 file_101.ext
。获取标记为 1 和 2 但不是 3 的文件的正确查询是什么?
您可以使用exists/ not exists
来检查相关记录是否存在
select f.filename
from files f
where exists (
select 1
from files_tags
where tag_id = 1
and file_id = f.file_id
) and exists (
select 1
from files_tags
where tag_id = 2
and file_id = f.file_id
) and not exists (
select 1
from files_tags
where tag_id = 3
and file_id = f.file_id
)
不确定这是否足够优雅,但应该退出性能。
SELECT f.filename
FROM files_tags ft0
INNER JOIN files f ON ft0.file_id = f.file_id
INNER JOIN files_tags ft1 ON f.file_id = ft1.file_id AND ft1.tag_id = 2
LEFT JOIN files_tags ft2 on f.file_id = ft2.file_id and ft2.tag_id = 3
WHERE ft0.tag_id = 1
and ft2.file_id is null;
CREATE TABLE `files`
(
`file_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`filename` text COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`file_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
INSERT INTO `files` (`file_id`, `filename`)
VALUES (100, 'file_100.ext'),
(101, 'file_101.ext');
CREATE TABLE `files_tags`
(
`file_id` bigint(20) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`file_id`, `tag_id`),
CONSTRAINT `FK__files` FOREIGN KEY (`file_id`) REFERENCES `files` (`file_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
INSERT INTO `files_tags` (`file_id`, `tag_id`)
VALUES (100, 1),
(100, 2),
(100, 3),
(101, 1),
(101, 2);
SQL fiddle: http://www.sqlfiddle.com/#!9/b776ab/3
我有一个连接 table (files_tags),它列出了另一个 table(文件)的标签。我有以下查询,它适用于 select 所有标有标签 1 和 2 的文件:
SELECT f.filename
FROM files_tags ft0
INNER JOIN files f ON ft0.file_id = f.file_id
INNER JOIN files_tags ft1 ON f.file_id = ft1.file_id AND ft1.tag_id = 2
WHERE ft0.tag_id = 1;
我正在寻找 selects 文件标记为 1 和 2 但不是 3 的查询。我尝试使用此附加连接进行上述查询:
INNER JOIN files_tags ft2 ON f.file_id = ft2.file_id AND ft1.tag_id = 3
但这最终只会返回 5 行(与 files_tags table 相同),这不是我想要的。 我对此的预期输出是单行 file_101.ext
。获取标记为 1 和 2 但不是 3 的文件的正确查询是什么?
您可以使用exists/ not exists
来检查相关记录是否存在
select f.filename
from files f
where exists (
select 1
from files_tags
where tag_id = 1
and file_id = f.file_id
) and exists (
select 1
from files_tags
where tag_id = 2
and file_id = f.file_id
) and not exists (
select 1
from files_tags
where tag_id = 3
and file_id = f.file_id
)
不确定这是否足够优雅,但应该退出性能。
SELECT f.filename
FROM files_tags ft0
INNER JOIN files f ON ft0.file_id = f.file_id
INNER JOIN files_tags ft1 ON f.file_id = ft1.file_id AND ft1.tag_id = 2
LEFT JOIN files_tags ft2 on f.file_id = ft2.file_id and ft2.tag_id = 3
WHERE ft0.tag_id = 1
and ft2.file_id is null;