Объединить три SQL-запроса - PullRequest
1 голос
/ 17 сентября 2011

У меня есть три следующих запроса 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;

ЗАПРОС 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;

ЗАПРОС 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.Я слышал, что использование != для «не равно» работает не во всех случаях, но что <> лучше.В моем случае != должно быть в порядке?

Ответы [ 3 ]

6 голосов
/ 17 сентября 2011

Это может работать для вас.

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;
2 голосов
/ 17 сентября 2011

Я считаю, что нужны 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 используются 4 раза каждая (и$imgId один раз).Если вы готовите оператор, как показано (встраивая значения в строку, представляющую SQL), это не так уж плохо.Если вы используете заполнители, вам нужна схема именования для заполнителей, если это возможно (:img_ht, :img_wd, :img_id (или, по крайней мере, :1, :2, :3) вместо ? заполнители), поэтому вы можете передавать каждое значение только один раз в инструкции EXECUTE.Эта возможность зависит от вашей СУБД;MySQL является одной из ряда СУБД, которые не поддерживают эту возможность.

1 голос
/ 17 сентября 2011

Есть ли у вас индексы primaryId в ваших таблицах primary_images и second_images?Если да, то вы должны вставить предложение 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 и не имеющей индексов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...