Как я могу включить третий столбец в SELECT с MIN - PullRequest
0 голосов
/ 07 февраля 2019

В этом запросе я также хочу ВЫБРАТЬ третий столбец, wp_postmeta.post_id, в том же запросе.Я не могу понять, как это сделать, не добавляя его через JOIN, который включает в себя подзапрос.Есть ли более простой способ без использования подзапросов?(Готов уступить подзапросам, если решение является эффективным и не слишком ресурсоемким.)

MariaDB 10.1

create table wp_posts (
  ID integer primary key auto_increment,
  post_title varchar(30),
  post_type varchar(30)
);
create table wp_postmeta (
  ID integer primary key auto_increment,
  post_id integer,
  meta_key varchar(30) not null default '_regular_price',
  meta_value integer not null
);
insert into wp_posts (post_title, post_type) values
('Apple Pie','Product'),
('French Toast','Product'),
('Shepards Pie','Product'),
('Jam Pie','Product'),
('Jam Pie','Product'),
('Plate','Not a Product'),
('Bucket','Not a Product'),
('Chequebook','Not a Product'),
('French Toast','Product'),
('French Toast','Product'),
('Banana','Product'),
('Banana','Product'),
('Banana','Product');
insert into wp_postmeta (post_id, meta_value) values
(1,10),
(2,5),
(3,9),
(4,8),
(5,11),
(6,12),
(7,10),
(8,6),
(9,1),
(10,1),
(11,7),
(12,2),
(13,2);
SELECT wp_posts.post_title, MIN(wp_postmeta.meta_value) FROM wp_postmeta JOIN wp_posts
ON wp_postmeta.post_id = wp_posts.id 
WHERE wp_posts.post_type = 'Product' AND wp_postmeta.meta_key = '_regular_price' 
GROUP BY wp_posts.post_title
ORDER BY wp_posts.post_title
post_title   | MIN(wp_postmeta.meta_value)
:----------- | --------------------------:
Apple Pie    |                          10
Banana       |                           2
French Toast |                           1
Jam Pie      |                           8
Shepards Pie |                           9

дБ <> скрипка здесь

Редактировать: Я не был достаточно ясен и ясен в своем первоначальном вопросе - я хочу свернуть дубликат post_titles и использовать wp_postmeta.post_id, соответствующий MIN(pm.meta_value)

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Если я правильно следил за вами, ваш вопрос можно решить с помощью оконных функций :

SELECT x.post_title, x.id
FROM (
    SELECT wp_posts.post_title, wp_postmeta.id, ROW_NUMBER() OVER (PARTITION BY wp_posts.post_title ORDER BY wp_postmeta.meta_value) rn
    FROM wp_postmeta 
    INNER JOIN wp_posts ON wp_postmeta.post_id = wp_posts.id 
    WHERE wp_posts.post_type = 'Product' AND wp_postmeta.meta_key = '_regular_price'
) x WHERE x.rn = 1;

См. Эту демонстрацию DB Fiddle

Оконные функции - путь для таких случаев использования (если я правильно понял).Они обычно побеждают другие решения с точки зрения эффективности и читабельности.


Если ваша СУБД не поддерживает оконные функции, одним из решений является использование коррелированного подзапроса с условием NOT EXISTS, которое гарантирует отсутствие записи с меньшим мета-значением для данного заголовка сообщения.

SELECT p.post_title, MIN(m.id)
FROM 
    wp_postmeta m
    INNER JOIN wp_posts p 
        ON  p.id = m.post_id
        AND p.post_type = 'Product' 
WHERE 
    m.meta_key = '_regular_price'
    AND NOT EXISTS (
        SELECT 1
        FROM 
            wp_postmeta m1
            INNER JOIN wp_posts p1
                ON  p1.id = m1.post_id
                AND p1.post_type = 'Product'
        WHERE 
            m1.meta_key = '_regular_price'
            AND p1.post_title = p.post_title
            AND m1.meta_value < m.meta_value
     )
 GROUP BY p.post_title

Демонстрация DB Fiddle

Примечание: я немного очистил ваш SQL (добавил псевдоним таблицы и перенес некоторые условия в значение ONпункт соответствующего объединения).

0 голосов
/ 07 февраля 2019

Вы можете подносить с помощью CTE:

WITH T1
AS ( SELECT   post_title, MIN(id) AS ID
     FROM     wp_posts
     GROUP BY post_title )
SELECT   T1.ID, wp_posts.post_title, MIN(wp_postmeta.meta_value)
FROM     wp_postmeta
         JOIN wp_posts ON wp_postmeta.post_id = wp_posts.id
         JOIN T1 ON T1.post_title = wp_posts.post_title
WHERE    wp_posts.post_type = 'Product'
         AND wp_postmeta.meta_key = '_regular_price'
GROUP BY T1.ID,  wp_posts.post_title
ORDER BY wp_posts.post_title;

РЕДАКТИРОВАТЬ:

Ваша таблица wp_posts должна выглядеть следующим образом

Id, post_title, post_type
1, 'Apple Pie','Product'
2, 'French Toast','Product'
3, 'Shepards Pie','Product'
4, 'Jam Pie','Product'
5, 'Plate','Not a Product'
6, 'Bucket','Not a Product'
7, 'Chequebook','Not a Product'
8, 'Banana','Product'

, чем у вас в данных таблицы wp_postmetaкак это

post_id, meta_value
1,  10
2,  5
3,  9
4,  8
4,  11
5,  12 
6,  10
7,  6
2,  1
2,  1
8,  7
8,  2
8,  2

и запрос выглядит так

SELECT   wp_postmeta.post_id, wp_posts.post_title, MIN(wp_postmeta.meta_value)
FROM     wp_postmeta
         JOIN wp_posts ON wp_postmeta.post_id = wp_posts.id
WHERE    wp_posts.post_type = 'Product'
         AND wp_postmeta.meta_key = 'REG PRICE'
GROUP BY wp_postmeta.post_id,  wp_posts.post_title
ORDER BY wp_posts.post_title;
0 голосов
/ 07 февраля 2019

Разве вы не можете просто включить его в GROUP BY?

SELECT p.post_title, p.id, MIN(pm.meta_value)
FROM wp_postmeta pm JOIN
     wp_posts p
     ON pm.post_id = p.id 
WHERE p.post_type = 'Product' AND pm.meta_key = '_regular_price' 
GROUP BY p.post_title, p.id
ORDER BY p.post_title;

post_id совпадает с p.id, так что вы также можете использовать его.

РЕДАКТИРОВАТЬ:

Если заголовки можно повторить, просто используйте коррелированный подзапрос:

SELECT p.post_title, p.id, pm.meta_value
FROM wp_postmeta pm JOIN
     wp_posts p
     ON pm.post_id = p.id 
WHERE p.post_type = 'Product' AND
      pm.meta_key = '_regular_price' AND
      pm.meta_value = (SELECT MIN(pm2.meta_value)
                       FROM wp_postmeta pm2 JOIN
                            wp_posts p2
                            ON pm2.post_id = p2.id 
                       WHERE p2.post_title = p.post_title
                      )
ORDER BY p.post_title;
...