我目前有一个包含以下列的表:
id (INT)
parent_id (INT)
col0
col1
col2
作为示例,此表中保存了以下条目:
1 NULL abc def NULL
2 1 test NULL NULL
3 1 NULL NULL xyz
现在我想搜索所有没有任何指向它们的行B的行A(B.parent_id = A.id)。此外,行值应该是当前行中存在的行值,或者如果存在NULL,则应考虑父值的值。
为了说明我的要求,我想展示一些例子:
SEARCH(col0=test) => #2 (#1 has some children, #3.col0 = abc (inherited from #1))
SEARCH(col1=def) => #2, #3 (#1 has some children)
SEARCH(col2=xyz) => #3 (#1 has some children, #2.col2 = NULL (inherited from #1))
有谁知道如何在MySQL中实现这样的搜索?
答案 0 :(得分:2)
SELECT
# if first table has no value, use parent table
IF(t1.col0, t1.col0, t2.col0) as virtcol0,
IF(t1.col1, t1.col1, t2.col1) as virtcol1,
IF(t1.col2, t1.col2, t2.col2) as virtcol2
FROM table as t1
LEFT JOIN table as t2 ON t1.parent_id = t2.id
LEFT JOIN table as t3 ON t1.id = t3.parent_id
# t3 would be children of t1. We don't want t1 to procreate. :)
WHERE t3.id IS NULL
# Your actual search goes here:
AND virtcol0/1/2 = whatever
快?不可以。您可以使用的最佳索引是id / parent_id上的连接。
如果您有大量数据和小结果集,则可以直接在索引上查询列,然后在单独的查询中运行父项和子项的检查。这比在巨大的桌子上运行上述查询要快得多。
答案 1 :(得分:2)
最干净的解决方案可能是创建一个合并了父列和子列的视图:
CREATE VIEW foo
AS SELECT
c.id AS id,
COALESCE(c.col0, p.col0) AS col0,
COALESCE(c.col1, p.col1) AS col1,
COALESCE(c.col2, p.col2) AS col2
FROM table AS c
LEFT JOIN table AS p ON p.id = c.parent_id
WHERE NOT EXISTS
(SELECT * FROM table AS x WHERE c.id = x.parent_id)
然后,您可以针对此视图编写查询,就像它是普通表一样。
然而,正如Mantriur指出的那样, 非常有效。如果表没有经常更改,您可以使用CREATE TABLE ... SELECT
而不是CREATE VIEW
来创建包含合并数据的实际表,并在其上创建一些索引,以便可以有效地查询它。但是,这样的表不会像视图一样跟踪原始表的更改。
原则上,您可以使用触发器(或应用程序逻辑)在底层表更改时实时更新合并表,但这很容易变得复杂并容易出错。不幸的是,虽然其他一些RDBMS支持materialized views,这实际上是一种自动执行此操作的方法,但MySQL目前不支持。{/ p>
(好吧,不管怎样,不是本地的。是 Flexviews,虽然我自己没有尝试过。)