假设我有两个单独的表供我查询。这两个表都与第三个表有关系。如何使用单个非UNION查询查询这两个表?
这是一个理论上的例子。我有一个用户表。该用户可以同时拥有CD和书籍。我希望通过匹配字符串的单个查询找到所有用户的书籍和CD(在此示例中为“awesome”)。
基于UNION的查询可能如下所示:
SELECT "book" AS model, name, ranking
FROM book
WHERE name LIKE 'Awesome%'
UNION
SELECT "cd" AS model, name, ranking
FROM cd
WHERE name LIKE 'Awesome%'
ORDER BY ranking DESC
如何在没有UNION的情况下执行这样的查询?如果我从用户到书籍和CD进行简单的左连接,我们最终得到的结果总数等于匹配书籍的匹配数量。是否有GROUP BY或其他一些编写查询的方法来修复此问题?
(编辑:我想避免使用Union方法的原因是因为这实际上是一个DQL查询而且Doctrine不支持UNION。如果没有UNION没有办法做到这一点,我将使用本机SQL路由。此外,真实查询包含一堆额外的列,在上面的示例中,这些列不能很好地相互映射。)
答案 0 :(得分:5)
想想你如何在OO应用程序中对此进行建模。您将为书籍和CD创建一个超类,然后您的用户将拥有一组Collectibles
。该集合中的任何给定对象都是书籍或CD(或其他类型的收藏品),但它只有这些子类型中的一种。
您可以通过创建与超类型相对应的表来执行与SQL类似的操作:
CREATE TABLE Collectibles (
collectible_id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES Users(user_id)
);
然后每个子类型都包含一个引用它以使其可收集:
CREATE TABLE Books (
book_id BIGINT UNSIGNED PRIMARY KEY
book_name VARCHAR(100) NOT NULL,
FOREIGN KEY (book_id) REFERENCES Collectibles(collectible_id)
);
CREATE TABLE CDs (
cd_id BIGINT UNSIGNED PRIMARY KEY
cd_name VARCHAR(100) NOT NULL,
FOREIGN KEY (cd_id) REFERENCES Collectibles(collectible_id)
);
现在您可以进行查询,并确保您不会获得笛卡尔积:
SELECT u.*, COALESCE(b.book_name, d.cd_name) AS media_name
FROM Users u
JOIN Collectibles c ON (u.user_id = c.user_id)
LEFT OUTER JOIN Books b ON (b.book_id = c.collectible_id)
LEFT OUTER JOIN CDs d ON (d.cd_id = c.collectible_id);
答案 1 :(得分:3)
如果你试图避免联合,一种方法是创建视图。
编辑:要create view你有两个选择
如果您的查询仅用于选择记录,则
应该没有问题CREATE VIEW media AS
SELECT "book" AS model, name, ranking
FROM book
WHERE name LIKE 'Awesome%'
UNION
SELECT "cd" AS model, name, ranking
FROM cd
WHERE name LIKE 'Awesome%'
ORDER BY ranking DESC
如果您需要可以更新的视图,那么如果您重构,它可能会飞:
EDIT2:我忘了评论UNION ALL必须超过UNION,除非你希望MySQL每次运行视图/查询时都开始在磁盘上构建索引(感谢HLGEM)。
答案 2 :(得分:0)
除非有令人信服的理由不使用UNION,否则只需使用UNION。
答案 3 :(得分:0)
也许你可以试试这样的东西......这个例子假设第三个表叫做User:
$q = Doctrine_Query::create()
->select('c.cd, b.book')
->from('User u')
->LeftJoin('Cd c ON u.user_id = c.user_id AND c.name LIKE ?, 'Awesome%')
->LeftJoin('Book b ON u.user_id = b.user_id AND b.name LIKE ?, 'Awesome%');
$result = $q->execute();