How can I include third column in a SELECT with MIN

拜拜、爱过 提交于 2019-12-13 04:17:33

问题


In this query, I also want to SELECT a third column, wp_postmeta.post_id, in the same query. I can't figure out how to do this without appending it via a JOIN which involves subquerying. Isn't there a simpler easier way, without the use of subqueries? (Willing to concede on subqueries if the solution is efficient and not too resource-intensive.)

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

db<>fiddle here

Edit: I wasn't clear and explicit enough in my original question - I want to collapse the duplicate post_titles and use the wp_postmeta.post_id corresponding to the MIN(pm.meta_value)


回答1:


If I followed you correctly, your question can be solved using window functions :

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;

See this DB Fiddle demo

Window functions are the way to go for such use cases (if I understood it right). They usually beat Other solutions in terms of efficiency and readability.


If your RDBMS does not support window functions, one solution is to use a correlated subquery with a NOT EXISTS condition that ensures that there is no record with a smaller meta value for the given post title.

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 demo

NB : I did a little cleaning in your SQL (added table alias and moved some condition to then ON clause of the relevant join).




回答2:


Can't you just include it in the 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;

The post_id is the same as p.id, so you might as well use that.

EDIT:

If the titles can be repeated, then simply use a correlated subquery:

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;



回答3:


You can tray with 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;

EDIT:

Your table wp_posts should look like this

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'

and than you have in wp_postmeta table data like this

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

and query look like this

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;


来源:https://stackoverflow.com/questions/54563773/how-can-i-include-third-column-in-a-select-with-min

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!