I have an issue where I need to AS a column in a MySQL query and execute a BETWEEN on that column. The simplest version I can come up with that illustrates the problem is this:
SELECT ID AS post_id FROM wp_posts WHERE (post_id BETWEEN 10 AND 20)
This throws the following error:
#1054 - Unknown column 'post_id' in 'where clause'
Is there a way to make the newly created post_id column visible to the BETWEEN operator?
UPDATE:
This is my actual query. As you can see, it is slightly more complicated:
SELECT wp_postmeta.post_id,
MAX(CASE WHEN wp_postmeta.meta_key='store_lng' THEN wp_postmeta.meta_value END ) AS lng,
MAX(CASE WHEN wp_postmeta.meta_key='store_lat' THEN wp_postmeta.meta_value END ) AS lat
FROM wp_postmeta
LEFT JOIN wp_posts ON (wp_posts.ID=wp_postmeta.post_id)
WHERE
(lng BETWEEN 150.29793837662 AND 152.1161201948)
AND
(lat BETWEEN -34.775666623377 AND -32.957484805195)
AND
wp_posts.post_status='publish'
AND
wp_posts.post_type='store'
GROUP BY wp_postmeta.post_id
From the MySQL documentation:
It is not permissible to refer to a
column alias in a WHERE clause,
because the column value might not yet
be determined when the WHERE clause is
executed.
You'll either have to use ID instead of post_id in the WHERE clause or use a HAVING clause.
For example:
SELECT ID AS post_id FROM wp_posts WHERE ID BETWEEN 10 AND 20
Update: Based on your most recent update, you could use a subquery as already suggested or as I suggested earlier, you could use a HAVING clause.
For example:
SELECT wp_postmeta.post_id,
MAX(CASE WHEN wp_postmeta.meta_key = 'store_lng' THEN wp_postmeta.meta_value END) AS lng,
MAX(CASE WHEN wp_postmeta.meta_key = 'store_lat' THEN wp_postmeta.meta_value END) AS lat
FROM wp_postmeta
LEFT JOIN wp_posts
ON wp_posts.ID = wp_postmeta.post_id
WHERE wp_posts.post_status = 'publish' AND
wp_posts.post_type = 'store'
GROUP BY wp_postmeta.post_id
HAVING lng BETWEEN 150.29793837662 AND 152.1161201948 AND
lat BETWEEN -34.775666623377 AND -32.957484805195
Standard SQL disallows references to column aliases in a WHERE clause.
This restriction is imposed because when the WHERE clause is evaluated, the column value may not yet have been determined.
(http://dev.mysql.com/doc/refman/5.0/en/problems-with-alias.html)
Yes, you can!
SELECT post_id
from (select id AS post_id FROM wp_posts) x
WHERE post_id BETWEEN 10 AND 20
Edited to include changes to question. Try this (haven't run in mysql, but should be close if not correct):
SELECT *
FROM (SELECT
wp_postmeta.post_id,
MAX(CASE WHEN wp_postmeta.meta_key='store_lng' THEN wp_postmeta.meta_value END ) AS lng,
MAX(CASE WHEN wp_postmeta.meta_key='store_lat' THEN wp_postmeta.meta_value END ) AS lat
FROM wp_postmeta
GROUP BY wp_postmeta.post_id
) x
LEFT JOIN wp_posts ON wp_posts.ID = x.post_id
WHERE lng BETWEEN 150.29793837662 AND 152.1161201948
AND lat BETWEEN -34.775666623377 AND -32.957484805195
AND wp_posts.post_status='publish'
AND wp_posts.post_type='store'
Related
here is my custom sql query ;
SELECT id,
post_title,
post_content,
comment_count,
post_date,
post_status,
post_name
FROM wp_posts
WHERE post_type = 'post'
AND post_status = 'publish'
AND id NOT IN (SELECT DISTINCT post_id
FROM wp_postmeta
WHERE meta_key = 'visible_headlane'
AND meta_value = 'On')
AND id NOT IN (SELECT DISTINCT post_id
FROM wp_postmeta
WHERE meta_key = 'visible_homepage'
AND meta_value = 'On')
ORDER BY post_date DESC
LIMIT 11, 32
i can not use, LIMIT in NOT IN Query so, there is any way to use, or limit SELECT DISTINCT sql query, or any idea ?
Note : I need to optimise this query because, it takes so long , like a slow query.
Thanks.
Switch to NOT EXISTS( SELECT 1 FROM ... ) -- this variation does not need to compute the entire list of things; it only needs to check for the absence. LEFT JOIN .. ON .. IS NULL is also more efficient.
Furthermore, the standard schema for wp_postmeta is quite inefficient; see my suggestions.
Meanwhile, keep it as two tests, unlike the suggestion by 'holder'.
The EXISTS would look something like
AND NOT EXISTS ( SELECT 1 FROM wp_postmeta
WHERE post_id = wp_posts.id
AND meta_key = 'visible_headlane'
AND meta_value = 'On' )
which would make good use of the PRIMARY KEY(post_id, meta_key) that I recommend.
(Is it really 'headlane', not 'headline'?)
Maybe something like this as jarlh suggested
SELECT
ID,post_title,post_content,comment_count,post_date,post_status,post_name
FROM wp_posts t1
left join (
SELECT DISTINCT post_id from wp_postmeta
WHERE meta_key IN ('visible_headlane','visible_homepage') AND meta_value = 'On' ) t2 on t1.ID = t2.post_id
WHERE post_type = 'post'
AND post_status = 'publish'
AND t2.post_id is null
ORDER BY post_date DESC
LIMIT 11, 32
I'm starting in mysql, and I wonder how can I do to remove the result of the SELECT below, thank you all!
SELECT ID,post_name,meta_value, guid, COUNT( meta_value )
FROM wp_postmeta
INNER JOIN wp_posts
WHERE wp_postmeta.post_id = wp_posts.ID AND wp_postmeta.meta_value >100
GROUP BY meta_value
HAVING COUNT( meta_value ) >1
You can first select and create a array or you can directly put this query with delete query using IN clause.
DELETE from wp_posts
WHERE ID IN (
SELECT ID
FROM wp_posts
INNER JOIN wp_postmeta
WHERE wp_postmeta.post_id = wp_posts.ID AND wp_postmeta.meta_value >100
GROUP BY meta_value
HAVING COUNT( meta_value ) >1)
If you set foreign key with postmeta colum post_id as on delete cascade then data from this table will automatically remove.
Otherwise please consider to create unique array of post ids and postmeta ids. And use two separate delete query with IN clause.
I have created a query using a pivot table to extract some metadata (from my wordpress database) for latitude and longitude values associated with posts. I would like to only return posts that have these particular pieces of metadata, and ignore all other posts, but I am unable to filter out those posts that don't have values or these meta keys. Here is my SQL:
SELECT wp_posts.ID,
wp_posts.post_title, wp_posts.post_modified_gmt,
MAX(CASE WHEN wp_postmeta.meta_key = "_wp_geo_longitude" then wp_postmeta.meta_value ELSE NULL END) as longitude,
MAX(CASE WHEN wp_postmeta.meta_key = "_wp_geo_latitude" then wp_postmeta.meta_value ELSE NULL END) as latitude
FROM wp_posts JOIN wp_postmeta ON ( wp_postmeta.post_id = wp_posts.ID)
WHERE wp_posts.post_status = 'publish'
GROUP BY wp_posts.ID, wp_posts.post_title;
I have tried adding the following to the WHERE clause with zero effect:
WHERE longitude IS NOT NULL
WHERE wp_postmeta.meta_value IS NOT NULL
And variations of that, but all posts are still returned, regardless of null values.
Just add a having clause:
having longitude is not null and latitude is not null
This is a situation where the join method of pivoting might be more efficient:
SELECT p.ID, p.post_title, p.post_modified_gmt,
lng.meta_value as longitude, lat.meta_value as latitude
FROM wp_posts p JOIN
wp_postmeta lat
ON wp_postmeta.post_id = p.ID AND lat.meta_key = '_wp_geo_latiitude' JOIN
wp_postmeta lng
ON wp_postmeta.post_id = p.ID AND lng.meta_key = '_wp_geo_longitude'
WHERE p.post_status = 'publish';
In general, I prefer the aggregation method more than the join method because it is more flexible. However, you are only getting two fields and you want to ensure that both are there. That means that the option of using joins is quite reasonable in this case.
I have a wordpress database with a number of custom fields/metadata.
---------
wp_postmeta
---------
post_id
meta_key
meta_value
I want to find all the posts with a meta_key of 'Start Date' and a value of 'NOW()', but not the posts that have the meta_key 'Ongoing' and value of 'Yes'.
I'm a bit confused of how to join the queries:
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = 'Start Date'
AND wp_postmeta.meta_value > NOW()
with
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = 'Ongoing'
AND wp_postmeta.meta_value != 'Yes'
And potentially other queries... I think what is throwing me off is that I can't add another WHERE clause to the statement? I think I just need a prod in the right direction because I am missing some basic mysql understanding.
Thank you so much in advance!
Try this:
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
AND ((wp_postmeta.meta_key = 'Start Date'
AND wp_postmeta.meta_value > NOW()) OR (wp_postmeta.meta_key = 'Ongoing'
AND wp_postmeta.meta_value != 'Yes'))
Try to use
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = 'Start Date'
AND wp_postmeta.meta_value > NOW() and wp_posts.ID NOT IN (select post_id from wp_postmeta
where wp_postmeta.meta_key = 'Ongoing' AND wp_postmeta.meta_value = 'Yes')
I remember being there. You don't want to know the unscalable, convoluted solution I came up with.
You're just looking for a couple of paren's and an AND with a NOT.
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
-- parens make sure everything is grouped correctly and you don't have "and
-- meta_key - Ongoing and meta_value > NOW()
(wp_postmeta.meta_key = 'Start Date'
AND wp_postmeta.meta_value > NOW())
-- these conditions are all mutually exclusive, so they could never
-- simultaneously exist.
AND NOT
(wp_postmeta.meta_key = 'Ongoing'
AND wp_postmeta.meta_value != 'Yes')
IF you wanted to combine the results, you have the option of using OR. Just replace the AND NOT with an OR and see what happens.
You can also use UNION (though that is almost never done when OR is an option (I do seem to remember that there can be subtle performance differences, but worrying about that is often premature optimization)):
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
wp_postmeta.meta_key = 'Start Date'
AND wp_postmeta.meta_value > NOW()
-- Distinct vs. ALL is not really relevant here because you can't have overlap
UNION DISTINCT
SELECT * FROM wp_posts, wp_postmeta
WHERE wp_posts.ID = wp_postmeta.post_id
wp_postmeta.meta_key = 'Ongoing'
AND wp_postmeta.meta_value != 'Yes'
What i want is:
Get posts with date greater then 2010-03-02 and with the meta_value 'something' + like '2010-'
because there are other values like 239048192304 or 293811743
$query = "SELECT DISTINCT wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.ID, wp_posts.guid, wp_postmeta.post_id, wp_posts.post_title
FROM wp_postmeta
INNER JOIN wp_posts
ON wp_postmeta.post_id=wp_posts.ID
WHERE wp_postmeta.meta_value >='2010-03-02'
AND wp_postmeta.meta_value = 'something'
AND wp_postmeta.meta_value LIKE '2010-'
ORDER BY wp_postmeta.meta_value ASC
LIMIT 0,10";
can you help me out please? thank you!
Update2:
table wp_postmeta
post_id | meta_value
5 | 2010-12-30
5 | Berlin
3 | 2010-12-29
3 | Paris
2 | 2009-12-29
2 | Paris
14 | 12232456521
14 | Berlin
Output:
2010-12-30 Berlin ID 5
2010-12-29 Paris ID 3
Maybe you mean an OR instead of an AND?
...
WHERE wp_postmeta.meta_value >= '2010-03-02' OR
wp_postmeta.meta_value = 'something' OR
wp_postmeta.meta_value LIKE '2010-'
Unfortunately in the English language, AND and OR can be used interchangeably in certain cases:
"I always carry an umbrella for when it rains and snows."
"I always carry an umbrella for when it rains or snows."
The above wouldn't be equivalent for computers :)
A larger data set and sample answer would help clarify the question but here is my interpretation of what you are looking for. It's not elegant but if you've got the buffer space allocated it works.
SELECT DISTINCT wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.ID, wp_posts.guid, wp_postmeta.post_id, wp_posts.post_title
FROM wp_postmeta
INNER JOIN wp_posts
ON wp_postmeta.post_id=wp_posts.ID
WHERE wp_postmeta.post_id IN (
select post_id from wp_postmeta where str_to_date(meta_value, '%Y-%m-%d') >= 2010-03-02' and post_id in (select post_id from wp_postmeta where meta_value = 'something')
);
For getting post information and their post meta values you need the following query:
SELECT DISTINCT wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.ID,
wp_posts.guid, wp_postmeta.post_id, wp_posts.post_title
FROM wp_postmeta JOIN wp_posts
ON wp_postmeta.post_id = wp_posts.ID
WHERE wp_posts.post_date >= '2010-03-02'
AND EXISTS (SELECT 1 from wp_postmeta m1
WHERE m1.post_ised = wp_posts.ID
AND wp_postmeta.meta_value = 'something'
AND EXISTS (SELECT 1 from wp_postmeta m2
WHERE m2.post_ised = wp_posts.ID
AND wp_postmeta.meta_value LIKE '2010-%')
ORDER BY wp_postmeta.meta_value
ASC LIMIT 0, 10
Try this:
$query = "SELECT p.ID, m1.meta_value, m2.meta_value, p.post_title FROM
wp_posts p, wp_postmeta m1, wp_postmeta m2
WHERE p.post_date > '2010-03-02' AND
m1.post_id=p.ID AND m2.post_id=p.ID AND
m2.meta_value LIKE '2010-%' AND
m1.meta_value = 'something'
ORDER BY m1.meta_value, m2.meta_value
LIMIT 0,10";
No need for the distinct, since we're showing everything on one row anyway.
Those statements contradict themselves. First you are asking for it to be >= a date. So is meta_value a date? Then you say it must be equaled to 'something', so now it is a string and not a date. Finally you say have it be like 2010-, so now we are back to a string or a date, but no wild card % in the like so you are basically saying it has to be equaled to 2010- as well.
What is the value stored in meta_value?
Are you sure you do not mean to query multiple fields?
UPDATE
Based on the new information, I think this is what you want:
$query = "SELECT DISTINCT wp_postmeta.meta_key, wp_postmeta.meta_value, wp_posts.ID, wp_posts.guid, wp_postmeta.post_id, wp_posts.post_title
FROM wp_postmeta
INNER JOIN wp_posts
ON wp_postmeta.post_id=wp_posts.ID
WHERE (wp_postmeta.meta_value = 'something'
OR wp_postmeta.meta_value LIKE '2010-%')
ORDER BY wp_postmeta.meta_value ASC
LIMIT 0,10";
Hopefully that is what you were after. I removed the 2010 >= condition given that the 2010 LIKE condition will pull that same data.