2011-09-16 238 views
1

我有以下三个SQL查询。我想将它们合并成一个是可能的,要么使用当前的方法,要么使用其他方法,如果它会更有效。结合三个SQL查询

注意:我需要知道所有三个WHERE子句的不同计数值。

查询1:

SElECT COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight; 

QUERY 2:

SElECT COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight != $maxImageHeight; 

QUERY 3:

SElECT COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId AND imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight; 

另外,我的数据库是MySQL。我听说使用!=作为“不等于”在所有情况下都不起作用,但是<>更好。在我的情况下,应该!=罚款?

+2

'!=和'<>'在MySQL中是等价的,它们之间没有区别。 – Karolis

+0

@Karolis - 谢谢! – stefmikhail

回答

6

这可能适合你。

SElECT COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId 
AND (imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight 
OR imgWidth = $maxImageWidth AND imgHeight != $maxImageHeight 
OR imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight); 

我也相信这是等同的,虽然我不确定。

SElECT COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId 
AND (imgWidth = $maxImageWidth OR imgHeight = $maxImageHeight); 

根据请求,这里是一个返回3行的单个查询。

SELECT 'ALL EQUAL' AS COL1,COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight 
UNION ALL 
SELECT 'WIDTH EQUAL' AS COL1,COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId AND imgWidth = $maxImageWidth AND imgHeight != $maxImageHeight; 
UNION ALL 
SELECT 'HEIGHT EQUAL' AS COL1,COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
) AS union_table 
WHERE primaryId = $imgId AND imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight; 
+0

感谢您的回答。好奇,这会给我提供三种不同的价值吗?我想我应该在问题中提到这一点。我需要知道所有三个WHERE子句的不同计数值。另外,我有点不确定,为什么在WHERE子句中,下面一行是'AND($ imgId AND'里面有'$ imgId')? – stefmikhail

+0

不,这只会为你提供1个值,如果你想3个不同的值,请等待一分钟,然后我为此编写一个答案。另外,正如你可能已经注意到的那样,我编辑了“$ imgid AND”部分 – Kibbee

+0

K,谢谢,对不清楚的问题感到抱歉 – stefmikhail

2

我认为需要一个CASE和GROUP BY:

SELECT CASE 
     WHEN imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight 
     THEN 0 
     WHEN imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight 
     THEN 1 
     WHEN imgWidth = $maxImageWidth AND imgHeight != $maxImageHeight 
     THEN 2 
     END AS count_type, 
     COUNT(*) AS imgCount 
    FROM (SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
     UNION ALL 
     SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
     ) AS union_table 
WHERE primaryId = $imgId 
    AND (imgWidth = $maxImageWidth OR imgHeight = $maxImageHeight) 
GROUP BY count_type; 

这至少是诱人推WHERE子句下入UNION子查询,但优化应该做的反正。通过学习EXPLAIN输出来检查它是否确实可以做到这一点。如果优化不会自动做谓语下推,你会写:

SELECT CASE 
     WHEN imgWidth = $maxImageWidth AND imgHeight = $maxImageHeight 
     THEN 0 
     WHEN imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight 
     THEN 1 
     WHEN imgWidth = $maxImageWidth AND imgHeight != $maxImageHeight 
     THEN 2 
     END AS count_type, 
     COUNT(*) AS imgCount 
    FROM (SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images 
     WHERE primaryId = $imgId -- or: imgId = $imgId 
      AND (imgWidth = $maxImageWidth OR imgHeight = $maxImageHeight) 
     UNION ALL 
     SELECT imgHeight, imgWidth, primaryId FROM secondary_images 
     WHERE primaryId = $imgId 
      AND (imgWidth = $maxImageWidth OR imgHeight = $maxImageHeight) 
     ) AS union_table 
GROUP BY count_type; 

书面这种解决方案的缺点是$maxImageWidth$maxImageHeight变量每次使用(和$imgId一次)的4倍。如果你准备的语句如图所示(在表示SQL的字符串中嵌入值),这并不算太坏。如果您使用的占位符,你需要的占位符,如果可能的命名方案(:img_ht:img_wd:img_id(或至少:1:2:3)代替?占位符),所以你只能在EXECUTE语句一次通过每个值。不过,这种能力取决于你的数据库管理系统; MySQL是许多不支持这种功能的DBMS之一。

+0

我会测试一下。只是想知道,UNION ALL会不会自动GROUP?或者我在想别的什么?我还在学习。 – stefmikhail

+0

UNION ALL与分组无关;它只是意味着所有的重复都被保留下来。要进行分组,您必须在某处执行GROUP BY。 –

+0

是的,想通了,谢谢。我收到以下回复给我:'Array ( [count_type] => 0 [imgCount] => 2 )'。我期待着三个价值观。我应该如何解读这些数据? – stefmikhail

1

你在primary_images和secondary_images表中的primaryId上有索引吗?如果是的话,那么你应该推动里面的where子句,以便可以使用索引。

SElECT COUNT(*) AS imgCount FROM (
    SELECT imgHeight, imgWidth, imgId AS primaryId FROM primary_images WHERE imgId = $imgId AND imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight 
    UNION ALL 
    SELECT imgHeight, imgWidth, primaryId FROM secondary_images WHERE primaryId = $imgId AND imgWidth != $maxImageWidth AND imgHeight = $maxImageHeight 
) AS union_table 

,否则这将是一个全表扫描找到imgId为union_table是由MySQL创建临时表中,没有任何指标。

+0

我确实在secondary_images表中有'primaryId'索引,但它在primary_images表中不存在。索引在primary_images表上的'imgId'上。这就是为什么我有'imgId AS primaryId'。这是否回答你的问题? – stefmikhail

+0

您需要按照我建议的方式重新编写查询,以便Mysql使用您在这两个表上创建的索引。 表union_table是由Mysql创建的临时表,它没有任何索引。但是,如果您将where子句应用于primary_images和secondary_images表,则Mysql可以在这些表上使用各自的索引,这是件好事! – srivani

+0

这确实是一件好事。我测试了你的建议,并收到以下数组:'Array ( [imgCount] => 0 )'。我知道有两个图像具有*两个*值,而0只有一个。我必须使用循环吗?这就是为什么我只得到一个结果? – stefmikhail