【问题标题】:Select items if they or their children match a tag如果项目或其子项与标签匹配,则选择项目
【发布时间】:2021-01-29 18:02:16
【问题描述】:

我正在尝试选择已创建列表项的用户列表。

可以有父列表项和列表项的子项。

只应显示与某个标签匹配的结果,或者如果他们的孩子与该标签匹配。

我做了一个简化的可重现示例,由于only_full_group_by,不得不稍微更改查询。

这是我目前的查询,试图显示与 ID 为 3 (tag-c) 的标签匹配的结果。

此查询无法显示匹配项的所有标签及其已发布的子项。我也摆弄了这么多,以至于 ATM 将子项目显示为结果,这是错误的。

CREATE TABLE IF NOT EXISTS `listings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `branchid` int(11) NOT NULL,
  `title` text NOT NULL,
  `published` tinyint(1) NOT NULL DEFAULT '0',
  `uid` int(11) NOT NULL,
  `vid` int(11) NOT NULL,  
  PRIMARY KEY (`id`)
);

INSERT IGNORE INTO `listings` VALUES 
(1, 0, 'Listing',1,1,1),
(2, 0, 'Listing',1,1,1),
(3, 0, 'Listing',1,2,2),
(4, 2, 'Listing B - Child',1,1,1),
(5, 2, 'Listing B - Child',1,1,1),
(6, 3, 'Listing C - Child',1,2,2),
(9, 3, 'Listing C - Child',0,2,2),
(7, 0, 'Listing',1,3,3),
(8, 7, 'Listing D - Child',1,3,3);


CREATE TABLE IF NOT EXISTS `listing_map` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `listing_id` int(11) NOT NULL,
  `tagid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT IGNORE INTO `listing_map` VALUES 
(600,1,1),
(610,1,2),
(632,2,1),
(650,2,3),
(652,2,4),
(653,3,6),
(654,3,2),
(655,5,1),
(605,5,6),
(590,5,4),
(638,6,2),
(601,6,3),
(611,8,5),
(612,9,1);

CREATE TABLE IF NOT EXISTS `listing_tags` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
   `title` text NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT IGNORE INTO `listing_tags` VALUES 
(1, 'tag-a'),
(2, 'tag-b'),
(3, 'tag-c'),
(4, 'tag-d'),
(5, 'tag-e'),
(6, 'tag-f');

CREATE TABLE IF NOT EXISTS `vendors` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
   `uid` int(11) NOT NULL,
   `title` text NOT NULL,
   `default` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
);

INSERT IGNORE INTO `vendors` VALUES 
(1, 1, 'vendor A', 1),
(2, 2, 'vendor B', 0),
(3, 3, 'vendor C', 1),
(4, 4, 'vendor D', 1);

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` text NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT IGNORE INTO `users` VALUES 
(1, 'user A'),
(2, 'user B'),
(3, 'user C'),
(4, 'user D');

https://www.db-fiddle.com/f/pMJvDPNqVRhcEhD4U4r3f7/19

如果 branchid 等于 0,则它是父项。如果 branchid 是数字,则它是 branchid 父项的子项。

有几个重要的条件:

  1. 一次只搜索一个标签。所以不需要匹配多个标签(虽然会很好)。
  2. 结果应该只显示父项,即使它们不匹配任何标签,但它们的子项匹配。
  3. 结果应显示父项及其子项(如果存在)包含的所有标签。我一直在尝试通过 GROUP_CONCAT。
  4. 应考虑父母和孩子的已发布状态
  5. 一个用户分配给一个供应商
  6. 未分配列表的供应商应获得包含其用户标题而不是供应商标题的默认结果。
  7. 如果搜索标签,默认供应商将不再获得结果。因此,如果没有搜索任何内容,“vendor B”就会得到结果。

只是一个解释:

Listing A
- user 1, vendor 1
- no childs 
- tags: tag-a, tag-b

Listing B
- user 1, vendor 2
- two childs 
- tags: tag-a, tag-c, tag-d, tag-f

Listing C
- user 2, vendor 2
- one child
- tags: tag-f, tag-b, tag-c

Listing D
- user 3, vendor 3
- one child
- tags: tag-e

显示匹配 tag-f 的项目:

Listing B (tags: tag-a, tag-c, tag-d, tag-f)
Listing C (tag-f, tag-b, tag-c)

显示匹配标签-e的项目:

Listing D (tag-e)

显示所有项目:

Listing A (tag-a, tag-b)
Listing B (tags: tag-a, tag-c, tag-d, tag-f)
Listing C (tag-f, tag-b, tag-c)
Listing D (tag-e)
Vendor D  (no tags, default entry)

谢谢

【问题讨论】:

  • 通过 db-fiddle 添加了可重现的示例
  • 将某些东西称为 tagid(无下划线)和其他的东西 Listing_id(下划线)只是有点令人生气。

标签: mysql mariadb


【解决方案1】:

回顾一下,这是一个返回所有孤儿及其相关标签的查询(假设层次结构只有一层深)...

请注意,我用 NULL 而不是 '0' 表示孤儿,因为这是我更习惯的做法,但如果您愿意,可以将其改回 0。

SELECT DISTINCT parent.id
              , parent.title listing
              , parent.uid
              , parent.vid
              , t.title tag
           FROM listings parent 
           LEFT
           JOIN listings child 
             ON child.branchid = parent.id
            AND child.published = 1
           JOIN listing_map lt
             ON lt.listing_id IN(parent.id,child.id)
           JOIN listing_tags t
             ON t.id = lt.tagid
          WHERE parent.branchid IS NULL
          ORDER 
             BY parent.id
              , tag;
+----+-----------+-----+-----+-------+
| id | listing   | uid | vid | tag   |
+----+-----------+-----+-----+-------+
|  1 | Listing A |   1 |   1 | tag-a |
|  1 | Listing A |   1 |   1 | tag-b |
|  2 | Listing B |   1 |   1 | tag-a |
|  2 | Listing B |   1 |   1 | tag-c |
|  2 | Listing B |   1 |   1 | tag-d |
|  2 | Listing B |   1 |   1 | tag-f |
|  3 | Listing C |   2 |   2 | tag-b |
|  3 | Listing C |   2 |   2 | tag-c |
|  3 | Listing C |   2 |   2 | tag-f |
|  7 | Listing D |   3 |   3 | tag-e |
+----+-----------+-----+-----+-------+

【讨论】:

  • 仅当将表单 NULL 更改为 0 时,使用此查询无法获得任何结果。用户和供应商表也不包括在内。标签应在结果中连接(如问题中的描述),因此仅输出一个供应商行。
  • 标签不应串联。这是一个显示问题,最好在应用程序代码中解决。还有迈克,也许需要一点时间。
  • 这就是问题所在。我需要将它们连接起来。
  • 老实说,我认为您现在有足够的信息来完成这项任务;我将在我的编辑中再添加一个提示...
  • 好吧,老实说,我自己的查询已经更进一步了。如果没有连接和解决 GROUP BY 周围的麻烦,这将无济于事。
猜你喜欢
  • 2011-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多