MySql - Pivot Table - mysql

I'm trying to pull some data out of the wp_postmeta table which is basically a series of key/value pairs tied to a numeric post_id. As such, when I try to extract various values for a post, this is what I get:
This is the current query I'm using to get that output:
select post_id,meta_key,meta_value from wp_postmeta
where meta_key in ('_sku','_length','_width','_height')
and post_id in (
select post_id from wp_postmeta
where meta_value in ('28-005080','28-005287')
)
order by post_id DESC
What I'm trying to do is format the information like this:
I've tried to look at the MySql pivot table examples, but I'm not sure if they quite fit this specific scenario. Frankly, I don't know where to start with accomplishing this task.

You can use conditional aggregation:
select post_id,
max(case when meta_key = '_sku' then meta_value end) as sku,
max(case when meta_key = '_length' then meta_value end) as length,
max(case when meta_key = '_width' then meta_value end) as width,
max(case when meta_key = '_height' then meta_value end) as height
from wp_postmeta
where
meta_key in ('_sku','_length','_width','_height')
and post_id in (select post_id from wp_postmeta where meta_value in ('28-005080','28-005287'))
group by post_id
order by post_id desc
Actually, we might be able to replace the subquery in the where clause with a having clause:
select post_id,
max(case when meta_key = '_sku' then meta_value end) as sku,
max(case when meta_key = '_length' then meta_value end) as length,
max(case when meta_key = '_width' then meta_value end) as width,
max(case when meta_key = '_height' then meta_value end) as height
from wp_postmeta
group by post_id
having max(meta_value in ('28-005080','28-005287')) = 1
order by post_id desc

Related

MYSQL select column value when two rows have same condition

I need get value if two rows have same value. I need get post_id one field 145 in output.
Should i use JOIN or not? Or maybe some simpler/faster way to do this?
But this is not correct one...But i need someting like this, when barcode and _sku values are SAME.
SELECT post_id
FROM wp_postmeta
WHERE meta_key = 'barcode' = '_sku' AND meta_value = '123';
Getting error and checking just barcode field...
Warning: #1292 Truncated incorrect DECIMAL value: '_sku'
Since MySQL 8.0 you can use INTERSECT:
SELECT post_id
FROM wp_postmeta
WHERE meta_key = 'barcode' AND meta_value = '123'
INTERSECT
SELECT post_id
FROM wp_postmeta
WHERE meta_key = '_sku' AND meta_value = '123';
https://sqlize.online/sql/mysql80/d0a7123a10d11065d9f0609044c70d35/
Another way is use GROUP BY and HAVING:
SELECT post_id
FROM wp_postmeta
WHERE meta_key IN ('barcode', '_sku') AND meta_value = '123'
GROUP BY post_id
HAVING COUNT(DISTINCT meta_key) = 2;
https://sqlize.online/sql/mysql80/594f4b262c55c10d4958f3bc54c7353b/
SELECT post_id
FROM wp_postmeta
WHERE
meta_key IN ('barcode')
AND meta_value = '123'
AND EXISTS (SELECT post_id FROM wp_postmeta pm WHERE meta_key IN ('_sku')
AND meta_value = '123' AND pm.post_id = wp_postmeta.post_id)
;

MySql query not returning correct data

I have a Wordpress MySQL database that I need to create a custom query for using SQL. I am trying to return the current event (post) where the "date_start" value is less than the current day and the "date_end" value is greater than or equal to the current day. I know that there is a data record that should be returned butnothing is being returned when I try to do a search on both "date_start" and "date_end"
This is my old SQL statement:
select ID, post_name, meta_id, meta_key, meta_value from wp_posts inner join wp_postmeta on wp_posts.ID = wp_postmeta.post_id and ((meta_key='date_end' and meta_value >= CURDATE() + interval 1 day) and (meta_key='date_start' and meta_value < CURDATE())) where post_type='programs' order by meta_value
The new SQL statement:
SELECT
ID,
post_name,
(SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_start') AS 'date_start',
(SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_end') AS 'date_end'
FROM wp_posts
WHERE
post_type = 'programs'
AND ((CURDATE() >= (SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_start'))
AND (CURDATE() <= (SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_end')))
ORDER BY `wp_posts`.`ID` ASC
And the date that is being returned is:
ID post_name date_start date_end
1221 culture-analytics 20160307 20160610
2446 culture-analytics-tutorials 20160308 20160311
I have also tried where the date_start and date_end portion of the inner join was in the WHERE clause.
IMPORTANT: wp_postmeta is a Many To 1 schema, whereas 'date_start' and 'date_end' are separate records but both point to the same PostID
What seems to be the problem.
You have two conflicting constraints on meta_key. Your query expects meta_key to equal both "date_start" and "date_end" at the same time.
Maybe try something like this:
SELECT
ID,
post_name,
meta_id,
(SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_start') AS 'date_start',
(SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_end') AS 'date_end'
FROM wp_posts
WHERE
post_type = 'programs'
AND (SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_start') < CURDATE()
AND (SELECT meta_value FROM wp_postmeta WHERE wp_postmeta.post_id = ID AND meta_key = 'date_end') >= (CURDATE() + INTERVAL 1 DAY)
ORDER BY 4
I don't have access to a Wordpress database so I haven't run it but it might work...
#obe caught the core problem with your original query in his answer; but I would solve it with an additional join rather than four subqueries:
SELECT ID, post_name, meta_id
, beginMeta.meta_key As beginKey, endMeta.meta_key AS endKey
, beginMeta.meta_value AS beginDate
, endMeta.meta_value AS endDate
FROM wp_posts
INNER JOIN wp_postmeta AS endMeta
ON wp_posts.ID = endMeta.post_id
AND endMeta.meta_key='date_end'
AND endMeta.meta_value >= CURDATE() + interval 1 day
INNER JOIN wp_postmeta AS beginMeta
ON wp_posts.ID = beginMeta .post_id
AND beginMeta.meta_key='date_start'
AND beginMeta.meta_value < CURDATE()
WHERE post_type='programs'
ORDER BY beginDate, endDate
;
Edit: This assumes (post_id, meta_key) combinations are unique in wp_postmeta.

SQL PIVOT after an INNER JOIN

I'm trying to create and event page from the data in my wordpress database.
The data are saved in 2 tables ($wp_posts and $wp_postmeta). After the INNER JOIN i need to PIVOT the table $wp_postmeta but after multiple tries i cannot figure out how to do it.
My Query is :
SELECT
PO.ID,
PO.post_title,
PO.post_content,
PM.post_id,
PM.meta_key,
PM.meta_value
FROM $wp_posts PO
INNER JOIN $wp_postmeta PM ON PO.ID = PM.post_id
I need to have the "meta_key" from the table $wp_postmeta to become column names then to be able to select meta_values
Thank you for your help with my query.
MySQL doesn't have the ability to run a pivot.. but you can fake a pivot.
NOTE:
you need to know the number of rows you want to pivot.
QUERY:
SELECT
MAX(CASE meta_key WHEN '_EventOrganizerID' THEN meta_value END )AS _EventOrganizerID,
MAX(CASE meta_key WHEN '_EventURL' THEN meta_value END )AS _EventURL,
MAX(CASE meta_key WHEN '_EventCost' THEN meta_value END )AS _EventCost,
MAX(CASE meta_key WHEN '_EventCurrencyPosition' THEN meta_value END )AS _EventCurrencyPosition,
MAX(CASE meta_key WHEN '_EventCurrencySymbol' THEN meta_value END)AS _EventCurrencySymbol,
MAX(CASE meta_key WHEN '_EventVenueID' THEN meta_value END )AS _EventVenueID,
MAX(CASE meta_key WHEN '_EventDuration' THEN meta_value END )AS _EventDuration,
MAX(CASE meta_key WHEN '_EventEndDate' THEN meta_value END )AS _EventEndDate,
MAX(CASE meta_key WHEN '_EventStartDate' THEN meta_value END )AS _EventStartDate,
MAX(CASE meta_key WHEN '_EventAllDay' THEN meta_value END )AS _EventAllDay
FROM
( SELECT
PO.ID,
PO.post_title,
PO.post_content,
PM.post_id,
PM.meta_key,
PM.meta_value
FROM $wp_posts PO
INNER JOIN $wp_postmeta PM ON PO.ID = PM.post_id
) t
GROUP BY post_id
ANOTHER NOTE:
if you want to select the meta_values from this query.. as it not just pivot the result but actually select specific stuff you can select from this query like I did to pivot it.

Wordpress - fetch data from multiple tables

I have these two different tables (wp_usermeta & my cutom table-sia_licence):
wp_usermeta table:-
sia_licence table(custom):-
and I want final data table to be like this:-
We tried using
$data = $wpdb->get_results("SELECT * FROM wp_usermeta, sia_licence WHERE wp_usermeta.user_id = sia_user_id
AND wp_usermeta.meta_key = 'first_name'
AND wp_usermeta.meta_key = 'last_name'
AND wp_usermeta.meta_key = 'phone_number'
AND wp_usermeta.meta_key = 'email'
AND wp_usermeta.meta_key = 'address'");
but getting blank array..
You need to perform conditional aggregation on wp_usermeta in order to pivot all attributes (first name, last name, ...) per user_id and then JOIN with sia_licence to produce desired output
SELECT q.user_id, q.first_name, q.last_name, q.email, q.phone_number, q.address,
l.select_licence, l.visa_expiry, l.licence_number, l.sia_licence, l.driving_licence
FROM
(
SELECT user_id,
MAX(CASE WHEN meta_key = 'first_name' THEN meta_value END) first_name,
MAX(CASE WHEN meta_key = 'last_name' THEN meta_value END) last_name,
MAX(CASE WHEN meta_key = 'phone_number' THEN meta_value END) phone_number,
MAX(CASE WHEN meta_key = 'email' THEN meta_value END) email,
MAX(CASE WHEN meta_key = 'address' THEN meta_value END) address
FROM wp_usermeta m
WHERE EXISTS
(
SELECT *
FROM sia_licence
WHERE sia_user_id = m.user_id
)
GROUP BY user_id
) q JOIN sia_licence l
ON q.user_id = l.sia_user_id
or join first and then aggregate
SELECT q.user_id,
MAX(CASE WHEN meta_key = 'first_name' THEN meta_value END) first_name,
MAX(CASE WHEN meta_key = 'last_name' THEN meta_value END) last_name,
MAX(CASE WHEN meta_key = 'phone_number' THEN meta_value END) phone_number,
MAX(CASE WHEN meta_key = 'email' THEN meta_value END) email,
MAX(CASE WHEN meta_key = 'address' THEN meta_value END) address,
MAX(select_licence) select_licence,
MAX(visa_expiry) visa_expiry,
MAX(licence_number) licence_number,
MAX(sia_licence) sia_licence,
MAX(driving_licence) driving_licence
FROM wp_usermeta q JOIN sia_licence l
ON q.user_id = l.sia_user_id
GROUP BY q.user_id
try this:
SELECT * FROM wp_usermeta wu
INNER JOIN sia_licence sl ON wu.user_id = sl.sia_user_id
WHERE <you can specify your filter here>;
Does sla_user_id reference user_id?
if so you want to use a JOIN like this...
SELECT um.*,sl.select_licence,sl.visa_expiry,sl.licence_number,sl.sia_licence,sl.driving_licence FROM `wp_usermeta`um JOIN `sia_licence`sl ON um.`user_id`=sl.`sia_user_id`;
You can also add a where clause like this
SELECT um.*,sl.select_licence,sl.visa_expiry,sl.licence_number,sl.sia_licence,sl.driving_licence FROM `wp_usermeta`um JOIN `sia_licence`sl ON um.`user_id`=sl.`sia_user_id` WHERE um.`user_id`=101;
if neeeded. IN the above example it would just return user ID = 101.
You can also just use SELECT *, in this case, but generally it's a bad idea because if there are any ambigious columns (columns with the same names) between the two tables it'll give you an error, but in your case it looks like you should be fine with:
SELECT * FROM `wp_usermeta`um JOIN `sia_licence`sl ON um.`user_id`=sl.`sia_user_id`;

MySQL query with multiple where clauses

I have a table wp_postmeta with columns called meta_key and meta_value. I have 5 records in meta_key (location,area,price,bedrooms,bathrooms)
For example, I want to find a hotel in Texas with 2 bathrooms:
select post_id from wp_postmeta where meta_key = 'location' and meta_value = 'texas' and where meta_key = 'bathrooms' and meta_value= '2';
I know the above SQL command is not valid. Can anyone please help me to achieve the above result?
You can try mysql subquery:
select post_id
from wp_postmeta
where meta_key = 'location' and meta_value = 'texas'
and post_id IN (select post_id
from wp_postmeta
where meta_key = 'bathrooms' and meta_value= '2')