2010-02-21 29 views
1

下面是一个MySQL查询我运行:保持SQL干

-- get the sid of every supplier who does not supply both a red and green part 
SELECT Suppliers.sid, Parts.color 
FROM Suppliers 
JOIN Catalog ON Catalog.sid = Suppliers.sid 
JOIN Parts ON Parts.pid = Catalog.pid 
WHERE Suppliers.sid NOT IN (
    SELECT Suppliers.sid 
    FROM Suppliers 
    JOIN Catalog ON Catalog.sid = Suppliers.sid 
    JOIN Parts ON Parts.pid = Catalog.pid 
    WHERE Parts.color IN ('red', 'green') 
    GROUP BY Suppliers.sid 
    HAVING COUNT(DISTINCT Parts.color) = 2 
) 
ORDER BY Suppliers.sid DESC; 

正如你所看到的,这是重复两次:

FROM Suppliers 
JOIN Catalog ON Catalog.sid = Suppliers.sid 
JOIN Parts ON Parts.pid = Catalog.pid 

我能做些什么,只申报这个曾经,并参考两次?或者,这是否表明我的整个查询存在缺陷?

当我用这三条相同的线运行15个不同的查询时,问题会加剧。

回答

5

如果您打算在整个系统中继续使用表格关系,那么您想查看的内容称为view

+1

的视图解决了重复SQL的问题,如上所述由scwagner。它还为物理表存储和数据的逻辑外观提供了一种有用的抽象级别。 – 2010-02-21 04:14:54

+0

但是要小心,如果你使用太多的视图,视图可能会咬你,尤其是当视图返回的列多于你在特定情况下需要的列或者正在进行大量不必要的连接时。如果你是在直接表演中,你只需要干掉 – CResults 2010-02-21 14:10:05

0

更ANSI解决方案,我认为在MySQL将工作:

SELECT X.sid, X.color 
    FROM (SELECT Catalog.sid, parts.color, 
       count(distinct parts.color) as distinct_color_count 
      from Catalog 
       inner jOIN Parts 
        ON Parts.pid = Catalog.pid 
     where parts.color in ("red", "green") 
     group by catalog.sid, parts.color) 
     ) x 
where x.distinct_color_count = 2 
order by x.sid desc 

你不拉东西出来,但供应商的SID,而且必须在目录存在的,所以使用Catalog.sid代替。

嵌套select语句,以便获取distinct_color_count,以便您可以在以下步骤中进行筛选。如果你尝试这样做:

SELECT Catalog.sid, parts.color, 
     count(distinct parts.color) 
    from Catalog 
     inner join Parts 
      ON Parts.pid = Catalog.pid 
where parts.color in ("red", "green") 
having count(distinct parts.color) = 2 
group by catalog.sid, parts.color 
order by catalog.sid ; 

它不会工作,因为每行只有一个不同的颜色。

0

可以干起来最常用的查询(尤其是常见的连接)与这样一个观点:

CREATE OR REPLACE ALGORITHM=MERGE VIEW Suppliers_Catalog_Parts 
AS 
select * 
FROM Suppliers 
JOIN Catalog ON Catalog.sid = Suppliers.sid 
JOIN Parts ON Parts.pid = Catalog.pid; 

您可能希望*变成特定列,以避免ID名称冲突。

有几个问题需要注意。

首先,对于没有where子句的视图总是将算法指定为MERGE,以便视图存储为查询,然后在运行时与SQL合并;否则它可以被评估为一个临时表(这对于像这样的通用视图可能是灾难性的)。

其次,有些查询不能创建为VIEW - 特别是如果from子句包含子查询。这也有一些解决方法。

如果你想了解更多,我写了关于如何编写SQL干此系列: http://blog.gruffdavies.com/2014/08/23/how-to-write-dry-sql-in-mysql-part-1-views/

HTH

响螺