I have a sample data
product (ID, name)
1 | 'iPhone'
2 | 'iPad'
3 | 'iWatch'
product_meta (ID, product_id, meta_key, meta_value)
1 1 image iPhone.png
2 2 view 123
And using query:
SELECT p.*, m.*
FROM product AS p
LEFT JOIN product_meta AS m ON m.product_id = p.ID
WHERE p.ID = 1
GROUP BY p.ID
How to get all value to result is
product(ID, name, image, view) => 1 | iPhone | iPhone.png | 123
Assuming your sample data is incorrect and you're trying to PIVOT your results, you can use MAX with CASE for this:
select p.id,
p.name,
max(case when pm.meta_key = 'image' then pm.meta_value end) image,
max(case when pm.meta_key = 'view' then pm.meta_value end) view
from product AS p
left join product_meta AS pm ON pm.product_id = p.ID
where p.ID = 1
group by p.ID
you can do like select table1.column1, table2.column2 from .......... rest of query.
Based on the same assumption as sgeddes:
SELECT p.id, p.name, mimage.meta_value, mview.meta_value
FROM product AS p
LEFT JOIN product_meta AS mimage
ON mimage.product_id = p.id AND mimage.meta_key = 'image'
LEFT JOIN product_meta AS mview
ON mview.product_id = p.id AND mview.meta_key = 'view'
WHERE p.id = 1
Related
I've two tables, for example:
post:
id | author | content | date
1 | Lucas | Hello! | 2016
2 | Igor | Hi! | 2016
comment:
id | post_id | content | date
1 | 2 | hehehe | 2016
2 | 1 | hahaha | 2016
3 | 2 | huhuhu | 2016
And I to do a SELECT that return all posts and a COUNT of rows of all comments with post.id = comment.id.
So, I tried:
SELECT p.id, p.author, p.content, p.date, COUNT(*) AS numComments FROM post p LEFT JOIN comment ON p.id = post_id WHERE p.author = '$author' GROUP BY p.id DESC LIMIT 12
And I got do it. But, even when no exists comments with p.id = post_id he returns 1.
So, I tried:
SELECT p.id, p.author, p.content, p.date, CASE WHEN COUNT(*) < 1 THEN '0' ELSE COUNT(*) END AS numComments FROM post p LEFT JOIN comment ON p.id = post_id WHERE p.author = '$author' GROUP BY p.id DESC LIMIT 12
But the result is the same. How to do this?
As outer joins return a row even if there's no matching data you need to count a column from the inner table, usually it's the column used in join:
SELECT p.id, p.author, p.content, p.date, COUNT(post_id) AS numComments
FROM post p LEFT JOIN comment ON p.id = post_id
WHERE p.author = '$author'
GROUP BY p.id -- seems to be mysql, otherwise you need to add more columns to the list
If you don't want to show rows with a zero count simply switch to an
INNER JOIN.
you can get count by this way, also last is order by not group by:
SELECT p.id, p.author, p.content, p.date,
(select COUNT(*) from comment where p.id = comment.post_id) AS numComments FROM post p
WHERE p.author = '$author'
ORDER BY p.id DESC LIMIT 12
Mysql Detail:
Table A (name: post): id
Table B (name: post_has_relate) : post_id, object_id
Could I get the post in table A with same object_id that post_id is const? I try to write with a sub-query. Could I can write it with a join?
SELECT
p.sumary AS sumary,
p.source_link AS source_link,
p.source_name AS source_name,
p.created AS created,
p.id AS id,
p.slug AS slug
FROM
post_has_relate AS pr
LEFT JOIN post as p ON p.id = pr.post_id
WHERE
pr.object_id IN (
SELECT
post_has_relate.object_id AS object_id
FROM
post_has_relate
WHERE
post_has_relate.post_id = 1052
)
AND pr.post_id != 1052
AND p. STATUS = 1
GROUP BY
p.id
ORDER BY
p.created DESC
LIMIT 5 OFFSET 0
I think you could achieve the same result with a join:
SELECT
p.sumary AS sumary,
p.source_link AS source_link,
p.source_name AS source_name,
p.created AS created,
p.id AS id,
p.slug AS slug
FROM
post_has_relate AS pr
LEFT JOIN post as p ON p.id = pr.post_id
JOIN post_has_relate AS pr2
ON pr2.object_id=pr.object_id AND pr2.post_id=1052
WHERE
pr.post_id != 1052
AND p.STATUS = 1
GROUP BY
p.id
ORDER BY
p.created DESC
LIMIT 5 OFFSET 0
MySQL is driving me nuts. I've been requested for a csv file of Wordpress data. The posts have a bunch of meta entries and for the most part, I have things coming out ok. But I'm trying to connect user id's in the Other Authors to their display names (See below). The difficulty I'm having is trying to output each display name in that column.
Tracking Number | Post Title | Post Date | Primary Author | Other Authors
1153 | Title of Post | 2013/03/06 | Tom Smith | 213, 100, 600
And here's my query:
SELECT results.ID as ID, results.post_title as post_title, results.post_date
as post_date, results.post_content as post_content, u.display_name as
primary_author, results.other_authors as other_authors
FROM (SELECT m.meta_value as ID,p.post_title as post_title, p.post_date as
post_date,p.post_content as post_content,m2.meta_value as primary_author,
m3.meta_value as other_authors
FROM wp_posts p
INNER JOIN wp_postmeta m ON (p.ID = m.post_id)
INNER JOIN wp_postmeta m2 ON (p.ID = m2.post_id)
INNER JOIN wp_postmeta m3 ON (p.ID = m3.post_id)
WHERE p.post_type='post' AND p.post_status NOT IN ('trash') AND
(m.meta_key='idea_tracking_num' AND m.meta_value != '')
AND m2.meta_key='primary_author' AND m3.meta_key='other_authors'
ORDER BY p.post_date
DESC) as results
INNER JOIN wp_users u on (u.ID = results.primary_author)
INNER JOIN wp_users u2 on (u2.ID = results.other_authors)
I've also tried this, but it just outputs the first one:
SELECT results.ID as ID, results.post_title as post_title, results.post_date
as post_date, results.post_content as post_content, u.display_name as
primary_author, u2.display_name as other_authors
FROM (SELECT m.meta_value as ID,p.post_title as post_title, p.post_date as
post_date,p.post_content as post_content,m2.meta_value as primary_author,
m3.meta_value as other_authors
FROM wp_posts p
INNER JOIN wp_postmeta m ON (p.ID = m.post_id)
INNER JOIN wp_postmeta m2 ON (p.ID = m2.post_id)
INNER JOIN wp_postmeta m3 ON (p.ID = m3.post_id)
WHERE p.post_type='post' AND p.post_status NOT IN ('trash') AND
(m.meta_key='idea_tracking_num' AND m.meta_value != '')
AND m2.meta_key='primary_author' AND m3.meta_key='other_authors'
ORDER BY p.post_date
DESC) as results
INNER JOIN wp_users u on (u.ID = results.primary_author)
INNER JOIN wp_users u2 on (u2.ID = results.other_authors)
WordPress's wp_postmeta table has all the additional fields for a post but they are in rows so it's easy to add more.
However, now I want to query for all the fields of all the posts lets say, I obviously want those fields in a column and not a row.
This is my query that I am running
SELECT p.post_title,
m.meta_value,
m.meta_key
FROM wp_posts p
JOIN wp_postmeta m
ON p.id = m.post_id
WHERE p.id = 72697;
This will give me all the meta_values and their respective meta keys as columns. But I need the meta keys values as columns and meta values as rows
For example a meta_key could be additional_description and it's value could be What's up
So I need something like this
SELECT p.post_title, additional_description
FROM wp_posts p
JOIN wp_postmeta m
ON p.id = m.post_id
WHERE p.id = 72697;
I need it as a column. I also need all of the posts and not a specific one, but whenever I remove the where it just doesn't query (I have lots of posts, that could be an issue).
Here is some sample data and how I want the results to show up
wp_postmeta table
meta_key post_id meta_key meta_value
1 5 total_related 5
2 5 updated 0
3 5 cricket 1
4 8 total_related 8
5 8 updated 1
6 8 cricket 0
wp_post table
id post_title other things I dont care about
5 This is awesome
8 This is more awesome
wp_post id is related to post_id on wp_postmeta table
Result wanted
post_title total_related updated cricket
This is awesome 5 0 1
This is more awesome 8 1 0
What about something like this?
SELECT p.post_title, m1.meta_value as 'total_related', m2.meta_value as 'updated', m3.meta_value as 'cricket'
FROM wp_posts p
LEFT JOIN wp_postmeta m1
ON p.id = m1.post_id AND m1.meta_key = 'total_related'
LEFT JOIN wp_postmeta m2
ON p.id = m2.post_id AND m2.meta_key = 'updated'
LEFT JOIN wp_postmeta m3
ON p.id = m3.post_id AND m3.meta_key = 'cricket'
And since you aren't looking for a specific post you should be able to do this.
If you want to query specific post_types you can try something like this
SELECT p.post_title, m1.meta_value as 'total_related', m2.meta_value as 'updated', m3.meta_value as 'cricket'
FROM wp_posts p
LEFT JOIN wp_postmeta m1
ON p.id = m1.post_id AND m1.meta_key = 'total_related'
LEFT JOIN wp_postmeta m2
ON p.id = m2.post_id AND m2.meta_key = 'updated'
LEFT JOIN wp_postmeta m3
ON p.id = m3.post_id AND m3.meta_key = 'cricket'
WHERE p.post_type = 'my_custom_post_type';
Try that:
select post_title ,
MAX(CASE WHEN `meta_key`='total_related' THEN meta_value END)as 'total_related',
MAX(CASE WHEN `meta_key` = 'updated' THEN meta_value END) as 'updated' ,
MAX(CASE WHEN `meta_key` = 'cricket' THEN meta_value END) as 'cricket'
FROM wp_posts p
JOIN wp_postmeta m ON p.id = m.post_id
GROUP BY p.id
There are several approaches.
Here's an example of one way to get the specified result, using correlated subqueries in the SELECT list:
SELECT p.post_title
, ( SELECT m1.meta_value
FROM wp_post_metadata m1
WHERE m1.meta_key = 'total_related'
AND m1.post_id = p.id
ORDER BY m1.meta_key LIMIT 1
) AS `total_related`
, ( SELECT m2.meta_value
FROM wp_post_metadata m2
WHERE m2.meta_key = 'updated'
AND m2.post_id = p.id
ORDER BY m2.meta_key LIMIT 1
) AS `updated`
, ( SELECT m3.meta_value
FROM wp_post_metadata m3
WHERE m3.meta_key = 'cricket'
AND m3.post_id = p.id
ORDER BY m3.meta_key LIMIT 1
) AS `cricket`
FROM wp_posts p
WHERE p.id IN (5,8)
There are several other approaches, each with its own advantages and drawbacks.
There's a somewhat related question I referenced in a comment on the question. That question illustrates several approaches, but omits a correlated subquery approach.)
Here's how I did this dynamically - this procedure builds a SQL statement for every postmeta key for a given post type and then runs the "pivot" query for you:
This isn't the fastest query, and we use it only for migration and deep dives into data, but it does the job.
Note that this temporarily resets the max length of the concat function so you can build a large SQL statement:
CREATE PROCEDURE `wp_posts_pivot`(IN post_type_filter varchar(50))
BEGIN
/* allow longer concat */
declare max_len_original INT default 0;
set max_len_original = ##group_concat_max_len;
set ##group_concat_max_len=100000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(pm.meta_key = ''',
meta_key,
''', pm.meta_value, NULL)) AS `',
meta_key,
'`'))
INTO #sql FROM
wp_posts p
INNER JOIN
wp_postmeta AS pm ON p.id = pm.post_id
WHERE
p.post_type = post_type_filter;
SET #sql = CONCAT('SELECT p.id
, p.post_title
, ', #sql, '
FROM wp_posts p
LEFT JOIN wp_postmeta AS pm
ON p.id = pm.post_id
where p.post_type=\'',post_type_filter,'\'
GROUP BY p.id, p.post_title');
/* reset the default concat */
set ##group_concat_max_len= max_len_original;
/*
select #sql;
*/
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
You can then call this with a simple call such as this one, which will select a single row for each 'page' post type along with all meta values:
call wp_posts_pivot('page');
I have a sample data:
users(id, name)
1 | peter
...
usermeta(user_id, meta_key, meta_value)
1 | level | 10
1 | display | pc
...
points(user_id, type, point)
1 | like | 5
2 | comment| 10
...
And mysql:
SELECT u.*,
(case when m.meta_key = 'level' then m.meta_value end) level ,
p.points AS point
FROM users u
LEFT JOIN points p ON p.user_id = u.id
LEFT JOIN usermeta AS m ON m.user_id = u.id
Result level = NULL, how to fix it?
id | name | level | point
1 | peter| NULL | 5
1 | peter| 10 | 10
Put m.meta_key = 'level' as the join condition.
SELECT u.*,
m.meta_value AS level ,
p.points AS point
FROM users u
LEFT JOIN points p ON p.uid = u.id
LEFT JOIN usermeta AS m ON m.user_id = u.id AND m.meta_key = 'level'
Have you tried providing an ELSE clause to your CASE? And according to your tables p.uid doesn't exist, it should be p.user_id, right?
Also, you should use INNER JOIN in this case as you want to retrieve only those cases in which the id field in the users table matches the ones in points and usermeta respectively. This should work properly:
SELECT
u.*,
CASE WHEN m.meta_key = 'level' THEN m.meta_value ELSE NULL END AS level,
p.points AS point
FROM users u
INNER JOIN points p ON p.user_id = u.id
INNER JOIN usermeta m ON m.user_id = u.id