PHP SQL join table rows as keys [closed] - php

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I was wondering if someone could help me. I have the following two tables:
---Posts----
id | title | content |
544 | Alan | Blah
---Postmeta----
metaid | post_id | meta_key | meta_value
1 | 544 | age | 45
2 | 544 | email | test#hotmail.co.uk
I want to join the two tables by post_id and then display the meta_keys. Something like this
SELECT posts.post_id,
postmeta.age,
postmeta.email,
FROM
posts
JOIN posts
ON posts.post_id = postmeta.post_id
Any help would be much appreciated. Cheers

You need to PIVOT the rows inside the table postmeta into columns, using CASE with MAX as an aggregate function to eliminate NULLs like so:
SELECT p.id, pm.age, pm.email
FROM posts p
JOIN
(
SELECT
post_id,
MAX(CASE WHEN meta_key = 'age' THEN meta_value END) AS age,
MAX(CASE WHEN meta_key = 'email' THEN meta_value END) AS email
FROM postsmeta
GROUP BY post_id
) pm ON p.id = pm.post_id
Here is a Demo in sql fiddle
Note that: You are currently storing all values for age and email in one column of the same data type that would be varchar for example then you have to cast the age values to INT in the query in order to get it like INT if you want to perform some calculations later on, and I left this part for you.

SELECT
posts.id,
postmeta.key,
postmeta.meta_value
FROM
posts
JOIN
postmeta ON posts.id = postmeta.post_id
WHERE
postmeta.key IN ('age', 'email')

it should be like this
SELECT posts.post_id,
postmeta.age,
postmeta.email,
FROM
posts
JOIN postsmeta
ON posts.post_id = postmeta.post_id

SELECT posts.id,
postmeta.age,
postmeta.email,
m.meta_key,
m.meta_value
FROM
posts p
JOIN Postmeta m
ON p.id = m.post_id

Instead of saving meta_key in a new row, try to make your table structure like this
metaid | post_id | age | email
1 | 544 | 45 | test1#hotmail.co.uk
2 | 545 | 51 | test2#hotmail.co.uk
3 | 546 | 20 | test3#hotmail.co.uk
4 | 547 | 26 | test4#hotmail.co.uk
you can add more fields to table structure.
and after that you can make a simple join query, that will save your time and resources to execute the query.
like this
SELECT posts.post_id, postmeta.age, postmeta.email FROM posts JOIN postmeta ON posts.post_id = postmeta.post_id;

Joining twice to the postmeta table:
SELECT p.id,
pm1.meta_value AS age,
pm2.meta_value AS email
FROM
posts AS p
LEFT JOIN
postmeta AS pm1
ON pm1.post_id = p.id
AND pm1.meta_key = 'age'
LEFT JOIN
postmeta AS pm2
ON pm2.post_id = p.id
AND pm2.meta_key = 'email' ;

Related

MySQL joining tables and returning the latest row from the second table when the comparison is made between identical values

I have table 1: users
id | name |
1 | john |
2 | garry|
3 | sam |
And table two called posts:
id | user_id | title | posted
1 | 1 | Something | 1551128761
2 | 1 | Else | 1551128761
3 | 3 | Some Title | 1551122745
4 | 2 | Demo Title | 1551129777
5 | 3 | Something | 1551126793
user_id in the second table is the id of the user in the first table
I need to get the latest post out of the table and i'm doing that currently by using this query:
SELECT u.id, u.name, p.title
FROM users AS u
LEFT JOIN posts AS p
ON p.user_id= u.id
WHERE p.posted = ( SELECT MAX(posted) FROM posts WHERE user_id = u.id )
ORDER BY u.id
LIMIT 15
But the problem with this query is that if the timestamp is the same for the same user (in this example for user with user_id 1 the timestamp is the same) i'm getting both of those rows instead of just the latest one(the latest one has the highest id)
Try this MySQL query:
SELECT u.id,
u.name,
p.title
FROM users AS u
JOIN posts AS p
ON p.id = (SELECT pi.id
FROM posts AS pi
WHERE pi.user_id = u.id
ORDER BY pi.id DESC
LIMIT 1);
Tested and works fine. Here is a demo: DBFiddle
To speed up select query, consider adding indexes
ALTER TABLE posts ADD INDEX(user_id);
ALTER TABLE posts ADD INDEX(posted);
One option using id column from posts table as following. This is assuming id is going to be different for each post record is posts table. Demo here
SELECT u.id, u.name, p.title,p.posted
FROM users AS u
LEFT JOIN posts AS p
ON p.user_id= u.id
WHERE (p.posted,p.id) = ( SELECT MAX(posted),MAX(id) FROM posts WHERE user_id = u.id )
ORDER BY u.id
How about restructuring the query slightly?
SELECT posts.title, users.id, users.name
FROM posts, users
WHERE posts.user_id = users.id
ORDER BY posts.posted DESC, posts.id DESC
LIMIT 1
Essentially selecting from posts, ordering by the posted timestamp and secondly the id of the post in descending order in case timestamp is the same.

mysql muliple joins from same colums with different keys

I need some help making the second join with the tables below. I got some help from here previously where it was suggested I need to add a second JOIN, however, this is where I'm stuck and need some assistance.
wp-posts
-----------------
id | Post_Title |
-----------------
01 | Event 1 |
-----------------
02 | Event 2 |
-----------------
wp-postmeta
-------------------------------------------------------
meta_id | post_id | meta_key | meta_value |
-----------------------------------------------------
456 | 01 | _EventStartDate | 01/01/2017 |
-------------------------------------------------- ---
789 | 01 | _EventEndDate | 05/02/2017 |
-----------------------------------------------------
The end result I'm after is something like;
Title - starts on <_EventStartDate > and ends on <_EventEndDate>
and im using the following to get the data:
$result = $wpdb->get_results ( "
SELECT $wpdb->posts.ID, $wpdb->posts.post_content, $wpdb->postmeta.meta_id,
$wpdb->postmeta.post_id, $wpdb->postmeta.meta_key, $wpdb->postmeta.meta_value, $wpdb->posts.post_title
FROM $wpdb->posts INNER JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id
WHERE $wpdb->postmeta.meta_key = '_EventStartDate'
ORDER BY $wpdb->postmeta.meta_value " );
Now I've been told that the WHERE will just return a single row and that I need to make the second JOIN using $wpdb->postmeta.meta_key = '_EventStartDate' but after hours of trying to implement this I'm unable to get and data back at all.
If someone could help solve this it would be immensely helpful as I have a few more queries I would like to write and I'm guessing I will need to use the same principal with them too.
Thanks for reading!!
You can do it with a single inner join, grouping by the post ID and then splitting start date and end date:
select
wpposts.post_content,
substring_index(GROUP_CONCAT(meta_value order by str_to_date(meta_value,'%d/%m/%Y')), ',', 1) as start_date ,
substring_index(GROUP_CONCAT(meta_value order by str_to_date(meta_value,'%d/%m/%Y')), ',', -1) as end_date
from wpposts inner join wppostmeta
on wpposts.id = wppostmeta.post_id
where wppostmeta.meta_key='_EventStartDate' or wppostmeta.meta_key='_EventEndDate'
group by wppostmeta.post_id
You can get the start_date and end_date in one row using group by like this:
select
t1.*,
max(case when meta_key = '_EventStartDate' then meta_value end) start_date,
max(case when meta_key = '_EventEndDate' then meta_value end) end_date
from wp_posts t1
inner join wp_postmeta t2
on t1.id = t2.post_id
group by t1.post_id;
if ONLY_FULL_GROUP_BY is enabled, change the group by clause to:
group by t1.post_id, t1.Post_title;
Assuming there is only one _EventStartDate and one _EventEndDate per post in wp-postmeta, a simplified query would be:
SELECT p.post_title, pm1.meta_value AS start_date, pm2.meta_value AS end_date
FROM wp-posts p
INNER JOIN wp-postmeta pm1
ON p.post_id = pm1.post_id
AND pm1.meta_ekey = '_EventStartDate'
INNER JOIN wp-postmeta pm2
ON p.post_id = pm2.post_id
AND pm2.meta_ekey = '_EventEndDate'

COUNT number of rows on table with LEFT JOIN returns 1 when not exists

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

How to order by COUNT with SUM and MINUS of multi tables

I'm trying to show post by order them with sum of comment and like.
There are three table using in this query post,comment and like
for table like it has column type that keep value like or unlike.
SQL
SELECT (SELECT COUNT(id) AS count_comment
FROM comment WHERE comment.post_id = post.post_id),
(SELECT COUNT(id) AS count_like
FROM like WHERE like.post_id = post.post_id AND like.type = 'like'),
(SELECT COUNT(id) AS count_unlike
FROM like WHERE like.post_id = post.post_id AND like.type = 'unlike'),
post.* FROM post
ORDER BY (count_comment + count_like - count_unlike) DESC;
So, this is an example when it shows on the page
post_id | comment | like | unlike | (comment+like-unlike)
4 | 5 | 3 | 1 | 7
1 | 2 | 3 | 0 | 5
2 | 1 | 1 | 4 | -2
... | ... | ... | ... | ...
My problem is my SQL is very slow, please suggest another way if it can. I've tried to use JOIN but i can't figured out how its SQL should be, please help thanks.
Using a derived table for each of the counts, the query below counts comments, likes, unlikes for each post and then joins the counts to the post table by post_id.
SELECT
p.post_id,
COALESCE(c.comment_count,0) comment_count,
COALESCE(l.like_count,0) like_count,
COALESCE(ul.unlike_count,0) unlike_count,
(COALESCE(c.comment_count,0)
+ COALESCE(l.like_count,0)
- COALESCE(ul.unlike_count,0)) total
FROM post p
LEFT JOIN (
SELECT c.post_id,
COUNT(*) comment_count
FROM comment c
GROUP BY c.post_id
) c ON c.post_id = p.post_id
LEFT JOIN (
SELECT l.post_id,
COUNT(*) like_count
FROM like l
WHERE l.type = 'like'
GROUP BY l.post_id
) l ON l.post_id = p.post_id
LEFT JOIN (
SELECT ul.post_id,
COUNT(*) unlike_count
FROM like ul
WHERE ul.type = 'unlike'
GROUP BY ul.post_id
) ul ON ul.post_id = p.post_id
ORDER BY total DESC

Get data from 3 tables for toxi tagging system [duplicate]

This question already has answers here:
SQL Queries to join three tables
(4 answers)
Closed 8 years ago.
Here i have 3 tables with the following structure.
Post:
post_id | Post_name
---------+----------
1 | Test Post
2 | India
Tag:
tag_id | tag_name
---------+------------
1 | java
2 | php
Tag_map:
tag_map contain only foreign key from post and tag tables.
post_id | tag_id
-----------+------------
1 | 1
1 | 2
2 | 1
2 | 2
I want to get the data from the particular post_id which is given by the user.
Can any one help me for this??? I"m a very beginer to php..
Thanks in advance.
You need to JOIN the data something as below and this will return data in multiple rows when the post has multiple tags in the tag_map
select
p.post_id ,
p.Post_name,
t.tag_name
from tag_map tm
join Post p on p.post_id = tm.post_id
join Tag t on t.tag_id = tm.tag_id
where p.post_id = 'some id';
For getting data in a single row per each post and all the tags as comma separation you will need to use group_concat() as
select
p.post_id ,
p.Post_name,
group_concat(t.tag_name) as tag_name
from tag_map tm
join Post p on p.post_id = tm.post_id
join Tag t on t.tag_id = tm.tag_id
where p.post_id = 'some id'
group by p.post_id
;

Categories