N.B。我用SQLAlchemy和Python标记了该标签,因为问题的全部重点是开发一个查询以转换为SQLAlchemy。我发布的答案很清楚。它也适用于MySQL。
我有三个相互联系的表格,用来描述一本书。 (在下表说明中,我消除了手头问题的多余行。)
[mysql]
host = localhost
port = 3306
charset = utf8mb4
dbname = myDatabase
username = myUsername
password = myPassword
options[20] = false ;PDO::ATTR_EMULATE_PREPARES
options[1000] = true ;PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
options[3] = 2 ;PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
options[19] = 2 ;PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
MariaDB [icc]> describe edition;
+-----------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
+-----------+------------+------+-----+---------+----------------+
7 rows in set (0.001 sec)
MariaDB [icc]> describe line;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| edition_id | int(11) | YES | MUL | NULL | |
| line | varchar(200) | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.001 sec)
MariaDB [icc]> describe line_attribute;
+------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+-------+
| line_id | int(11) | NO | PRI | NULL | |
| num | int(11) | YES | | NULL | |
| precedence | int(11) | YES | MUL | NULL | |
| primary | tinyint(1) | NO | MUL | NULL | |
+------------+------------+------+-----+---------+-------+
5 rows in set (0.001 sec)
是给定标题的层次结构级别。因此,如果“战争与和平”的“书籍”>“章节”,则所有行都具有与其所在的书籍相对应的属性(例如,书籍1具有line_attribute.precedence
和precedence=1
)以及“章节”的属性它们所在的位置(例如,第2章包含num=1
和precedence=2
)。这使我可以翻译书籍的层次结构,包括卷,书籍,零件,章节,章节,甚至是行为和场景。主列是一个布尔值,因此每一行都有 one 属性是主属性。如果是书籍标题,则为num=2
属性;如果是书籍标题,则为Book
属性。如果它是文本中的规则行,则它是Chapter
属性,并且优先级为0,因为它不是层次结构的一部分。
我需要能够查询具有特定line
且也具有两个line_attributes交集的所有行。
(这将使我能够从特定版本中获得《战争与和平》第二卷第一章的所有内容。)
我可以获取所有带有Book 1的行
edition_id
我可以得到所有包含第2章的行:
SELECT
line.*
FROM
line
INNER JOIN
line_attribute
ON
line_attribute.line_id=line.id
WHERE
line.edition_id=2 AND line_attribute.precedence=1 AND line_attribute.num=1;
除了第二个查询,返回《战争与和平》中每本书的第二章。
如何通过这两个查询来公正第一本书第二章的内容?
答案 0 :(得分:0)
注释中来自Raymond Nijland
的警告:
供以后的读者注意。.因为这个问题被标记为MySQL .. MySQL不支持INTERSECT关键字.. MariaDB确实是MySQL源代码的分支,但支持MySQL不支持的其他功能。在MySQL中,您可以simulate INTERSECT关键字加上INNER JOIN或IN()
尝试在SO上写一个问题可以帮助我弄清思路,并最终在必须提出问题之前解决问题。上面的查询比我最初的查询要清晰得多,而且这个问题本身也有很多答案,但是我从来没有找到一个关于intersect实用程序的明确答案,所以无论如何我都会发布这个答案。
解决方案是 INTERSECT
运算符。
解决方案就是这两个查询的交集:
SELECT
line.*
FROM
line
INNER JOIN
line_attribute
ON
line_attribute.line_id=line.id
WHERE
line.edition_id=2 AND line_attribute.precedence=1 AND line_attribute.num=1
INTERSECT /* it is literally this simple */
SELECT
line.*
FROM
line
INNER JOIN
line_attribute
ON
line_attribute.line_id=line.id
WHERE
line.edition_id=2 AND line_attribute.precedence=2 AND line_attribute.num=2;
这也意味着我可以通过简单地添加一个附加约束(line_attribute.primary=1
)来获取特定书籍的所有书籍和章节标题。
此解决方案似乎广泛适用于我。例如,假设您在StackOverflow克隆中有被标记的问题,则可以将问题与两个标签相交(例如,同时具有SQLAlchemy
和Python
标签的所有帖子)。我肯定会在这种查询中使用这种方法。
我在MySQL中对此进行了编码,因为它可以帮助我直接获取查询以将其转换为SQLAlchemy。
SQLAlchemy查询非常简单:
[nav] In [10]: q1 = Line.query.join(LineAttribute).filter(LineAttribute.precedence==1, LineAttribute.num==1)
[ins] In [11]: q2 = Line.query.join(LineAttribute).filter(LineAttribute.precedence==2, LineAttribute.num==1)
[ins] In [12]: q1.intersect(q2).all()
希望这个问题中的数据库结构可以帮助某人。解决自己的问题后,我不想删除该问题。