SQL: Trying to select two meta_values in one query - mysql

SELECT meta_value
FROM wp_postmeta
WHERE meta_key = "bid_resource_lat"
AND meta_key = "bid_resource_lng"
I'm trying to select two rows within one query, as you can see above ... and I can't wrap my head around why this isn't working...
And how would I make sure that the two results are grouped together within a row?

You need "OR" as the logic is the wrong way round from as you're imagining it.
SELECT meta_value FROM wp_postmetaWHERE meta_key = "bid_resource_lat" OR meta_key = "bid_resource_lng"
Explanation:
You want to get a row if the key is either the first OR if it's the second. This returns up to two rows. The way you wrote it then both conditions needed to be matched.
"I want a car that is italian OR expensive" - You can get a Ferrari, a Mercedes and a Fiat
"I want a car that is italian AND expensive" - You can get a Ferrari

You want to use an OR condition, not an AND condition:
SELECT meta_value
FROM wp_postmeta
WHERE meta_key = "bid_resource_lat"
OR meta_key = "bid_resource_lng"
Your query could not return any rows, because you're asking for records where the meta_key column is equal to both "bid_resource_lng" and "bid_resource_lng", which can obviously never happen since one row will only have one value in the meta_key column.

meta_key = "bid_resource_lat" AND meta_key = "bid_resource_lng"
Above will never be TRUE. Use OR instead
meta_key cannot be bid_resource_lat and bid_resource_lng at the same time.

Related

Wordpress SQL data query layout

I am using SQL Executioner in Wordpress Admin and trying to get a list of data from a table (wp_postmeta) using the following:
SELECT post_id, meta_value from wp_postmeta
WHERE meta_key = "_wprm_reservation_name"
UNION
(SELECT post_id, meta_value from wp_postmeta
WHERE meta_key = "_wprm_reservation_phone_number");
This returns the information that I require but the layout is wrong. I am getting two columns: one with the post_id number and meta_value (persons name) listed then after all those I am getting the post_id number repeated and the telephone number.
Ideally I am trying to get the phone number to be placed next to the persons name. The post_id is the key as the number is used for both the name and phone number.
I have tried number variations trying to understand the UNION statement but cannot get this to work. Can anyone advise please where I am going wrong here?
Union working like this, see the documentation. What you need is a subquery, or a join. This is with subquery:
SELECT wppm.post_id, wppm.meta_value,
(SELECT wppmphone.meta_value FROM wp_postmeta wppmphone
WHERE wppmphone.meta_key = "_wprm_reservation_phone_number"
AND wppmphone.post_id = wppm.post_id) AS phoneNum
FROM wp_postmeta wppm WHERE meta_key = "_wprm_reservation_name";
This is one query, I just separated the subquery by new lines to be readable. This is not tested, but it should like something like this.
Note, I am using aliases for the table names.

Change meta_value relating to specific meta_key

I have a wordpress directory theme in which a bunch of listings are about to expire. The were all created on different days. I want to batch update the whole database so that all my listings are reset for another year as of today.
They related to the table wp_postmeta and the meta_key is "alive_days" and I need to update the pertaining meta_value.
If anyone can suggest an SQL query to fix this, I will be saved a from pulling out my hair.
Thanks in advance.
LLG
See http://snag.gy/KfJfB.jpg for screengrab of the database.
Based on your response to my question, this should do the trick (take a backup of your database first, just in case):
update wp_postmeta
set meta_value = '365' -- I assume you meant that, not 356
where meta_key = 'alive_days'
The existing blanks will be updated, but since they relate to posts that no longer exist, that shouldn't matter. If you don't want to update them, you could add an extra condition (I assume they contain the empty string, not null, but the ifnull should handle that):
update wp_postmeta
set meta_value = '365'
where meta_key = 'alive_days'
and ifnull(meta_value, '') != ''

mysql combined query, ids from comma separated list

I am not that familiar with mysql, so do not exactly not how sample the query correctly. I am working with wordpress and to illustrate what I would like to select please see the image below:
I have the ID of one special post. I would like to get all other Posts that are connected to it in the following way:
In the posts_meta table can exist entries, whose post_id matches the given ID. One of these entries meta_key is of a certain value and the meta_value of that very entry is a comma separated list of post_id's. I would like to Select * for each of Posts whose ID is in that comma separated list
I started with the following:
SELECT *
FROM prefix_posts AS a
JOIN prefix_postmeta AS b ON ( a.ID = b.post_id )
WHERE … //??
but I have no idea how to finish the query. How can I select the ids, to select posts in turn? I found SO answers dealing with FIND_IN_SET, but I do not want to test if a given ID is in the set, I the more need something like »STR_SPLIT« in a subquery.
I would like to Select * for each of Posts whose ID is in that comma separated list
Why not using FIND_IN_SET method ?, it can help you for your problem
This query return all posts whose have id in meta_value field from meta row having your "special post id" as post_id.
SELECT * FROM Post a, meta b
WHERE FIND_IN_SET(a.id, b.linked)>0 AND b.post_id= $id_post;
Tried on SQLFiddle, it seems to work.
Add a GROUP BY clause if you want avoid duplicates.

How make this eav query to make horizontal result

The case:
tables:
product:
product_id|name |
------------------------
1 |iphone 4 |
2 |gallaxy 2 |
3 |blackbery 6 |
product_attribute:
id|product_id|attribute_id
--------------------------------------------------
1 |1 |2
2 |1 |6
. . .
attribute:
------------------------------
attribute_id|name |value|
1 |width |300
2 |width |320
3 |width |310
4 |height|390
5 |height|370
6 |height|380
should get result:
product_id|height|width
1 |380 |320
......................
Edit:
height and width attributes its only part of product attributes - product need to have dynamic ability to be added by the user in backend as it done in magento, because that i choose eav db design.
Please write queries if it possible in case we dont know which names product have.
Thanks
There are several ways to implement this. Something like this should work joining back on the table multiple times for each attribute value:
SELECT p.product_id,
a.value height,
a2.value width
FROM Product p
JOIN Product_Attribute pa ON p.product_id = pa.product_id
JOIN Attribute a ON pa.attribute_id = a.attribute_id AND a.name = 'height'
JOIN Product_Attribute pa2 ON p.product_id = pa2.product_id
JOIN Attribute a2 ON pa2.attribute_id = a2.attribute_id AND a2.name = 'width'
And here is the Fiddle.
Here is an alternative approach using MAX and GROUP BY that I personally prefer:
SELECT p.product_id,
MAX(Case WHEN a.name = 'height' THEN a.value END) height,
MAX(Case WHEN a.name = 'width' THEN a.value END) width
FROM Product p
JOIN Product_Attribute pa ON p.product_id = pa.product_id
JOIN Attribute a ON pa.attribute_id = a.attribute_id
GROUP BY p.product_id
Good luck.
One approach is to use correlated subqueries in the SELECT list, although this can be less than optimum for performance on large sets. For retrieving just a few rows rows from the product table, it won't be bad. (You'll definitely want appropriate indexes.)
SELECT p.product_id
, ( SELECT a1.value
FROM attribute a1
JOIN product_attribute q1
ON q1.attribute_id = a1.attribute_id
WHERE q1.product_id = p.product_id
AND a1.attribute_name = 'height'
ORDER BY a1.id
LIMIT 0,1
) AS height_1
, ( SELECT a2.value
FROM attribute a2
JOIN product_attribute q2
ON q2.attribute_id = a2.attribute_id
WHERE q2.product_id = p.product_id
AND a2.attribute_name = 'width'
ORDER BY a2.id
LIMIT 0,1
) AS width_1
FROM product p
WHERE p.product_id = 1
This query will return the row from product, along with the values of the attributes, if they exist. If the attribute values are not found, the query will return a NULL in place of the attribute value. (This differs from the behavior of a query that uses INNER JOIN in place of correlated subquery... where a "missing" row from the attribute or product_attribute table would filter out the row from product being returned.)
The purpose of the LIMIT clauses is to guarantee that the subqueries will return not return more than one row. (If a subquery in the SELECT list were return more than one row, MySQL would return an error.) The purpose of the ORDER BY is to make the query deterministic, again, in the event there is more than one row that satisfies the subquery. (Absent the ORDER BY clause, when there is more than one row, MySQL is free to arbitrarily return whichever row it chooses to.)
For "multi-valued" attributes, the same approach works. We just add more subqueries, but specify LIMIT 1,1 to return the second attribute value, LIMIT 2,1 to return the third value, etc.
(Oh, the joy of an EAV model implemented in a relational database.)
Followup:
Q: "... more general case as it happen in eav db that we dont know before which attributes names we have."
A: The relational model is based on the principle that a tuple contains a specified number of columns, of a specified type.
What you are (apparently) trying to do is return a variable number of columns when you run a query. A SELECT statement includes a specific list of expressions to be returned; this cannot vary and the datatypes of the values returned by each expression does not vary from row to row.
The query above returns one instance of a "height" attribute value, and one instance of a "width" attribute value, for each product.
For a more "more general case", we would really expect that each attribute value would be returned on its own separate row.
The more general query, if you don't know "ahead of time" what attributes are associated with a product would be:
SELECT p.product_id
, a.attribute_id
, a.name AS attribute_name
, a.value AS attribute_value
FROM product p
LEFT
JOIN product_attribute q
ON q.product_id = p.product_id
LEFT
JOIN attribute a
ON a.attribute_id = q.attribute_id
WHERE p.product_id = 1
ORDER
BY p.product_id
, a.name
, a.attribute_id
That will return a resultset which can easily be processed:
product_id attribute_id attribute_name attribute_value
---------- ------------ -------------- ---------------
1 6 height 380
1 2 width 320
Q: "looks like should be done in 2 stages: 1. get all attributes names for product 2.then your code with server side code of attributes names in for loop"
A: No, it looks like a single query will return all the attribute name and value pairs for a product. Each attribute name/value will be on a separate row.
There's no need to use a "for loop" to generate additional queries against the database. Yes, it's possible to do that, but totally unnecessary.
If you have some bizarre requirement to compose another query to run against the database to return the resultset in the format you specified, whatever processing you would do to process the resultset from the "more general case" statement, it would probably be more efficient to just process the resultset, without running any more queries against the database.
If you need to return a resultset that looks like this:
product_id height width
---------- ------ -----
1 380 320
(as bizarre a requirement as that is, to compose another query) it's entirely possible to use that resultset from the "more general query" to generate a query that looks like this:
SELECT 1 AS product_id, '380' AS height, '320' AS width
Though such an exercise is rather pointless, given that you aren't returning any new information you didn't return previously, and now you have another resultset that you need to process, which just seems to me to be a boatload of unnecessary overhead.
Let me first say this is a really poor design. Under your current approach, you will need to run multiple subqueries or joins with table aliases to achieve the result you want.
SELECT
product_id,
(
SELECT product_attribute.value
FROM product_attribute, attribute
WHERE product_attribute.product_id=product.product_id
AND product_attribute.attribute_id=attribute.attribute_id
AND product_attribute.name = 'width'
) AS 'width',
(
SELECT product_attribute.value
FROM product_attribute, attribute
WHERE product_attribute.product_id=product.product_id
AND product_attribute.attribute_id=attribute.attribute_id
AND product_attribute.name = 'height'
) AS 'height'
FROM
product
ORDER BY
...
Let me suggest:
attribute
attribute_sid (eg, string id)
product
product_id
name
...
product_attribute
product_id (foreign key to product table)
attribute_sid (foreign key to attribute table)
value
This way, you have a definitive list of attributes, and a single attribute value per product.
SELECT attribute_sid, value FROM product_attribute WHERE product_id = 1
... will retrieve all the attributes and values, which can conveniently be placed in a dict, array, or map.

Mysql Query - Joins causing confusion for me in this query

I have a query that returns results related to items that match a specific category...
There are 3 mysql tables that results to this, items, categories and item_categories.
These i assume are self explanatory, but the latter, is a linking table that links any specific item to any specific category, using a match of id's.
The items table contains one row, with an id value of 1.
The categories table is filled with 15 rows, with id values of 1-15.
the item_categories table contains one row, the item_id value is 1 and the category_id value is 5.
This is the mysql query in its php form:
$catResultQuery = "
SELECT i.id, name, price
FROM items i
INNER JOIN item_categories
ON i.id = item_id
INNER JOIN categories c
ON category_id = c.id
WHERE MATCH (c.id)
AGAINST ('{$_SESSION['input']}' IN BOOLEAN MODE)
ORDER BY name
";
The session variable has a value of 5, but for some reason, this query displays a 0 result set.
Even when i run the query in php myadmin, it returns 0 rows.
And i am confused, because in my head, the logic behind all of this seems fairly simple, but for some reason i get 0? Does anyone have any idea where i have gone wrong with this?
Any advice and input would be greatly appreciated, thank you!!
Ok, I see now that you're building the SQL dynamically. If that's the case, then this should work:
SELECT i.id, name, price
FROM items i
INNER JOIN item_categories
ON i.id = item_id
INNER JOIN categories c
ON category_id = c.id
WHERE c.id
IN ('{$_SESSION['input']}')
ORDER BY name
Just make sure '{$_SESSION['input']}' is comma delimited and be aware that this carries the risk of SQL injection because you're constructing the SQL on the fly.