wordpress query_posts to look at meta info - mysql

I am looking to run a query with query_posts that lets me look at meta_fields.
I have done this once before and achieved the result I wanted but now for some reason adding an extra field into the equation returns nothing.
The query below returns all attachments where the lottery_year is equal to $y, and obviously $y can be 2011 or earlier.
Now my next step I want to bring in another meta_field called photo_technique and give that one a value.
Question, how do I do that?
$querystr = "
SELECT $wpdb->posts.*
FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
WHERE ($wpdb->postmeta.meta_key = 'lottery_year' AND $wpdb->postmeta.meta_value = $y)
AND $wpdb->posts.post_type = 'attachment'
ORDER BY $wpdb->postmeta.meta_value ASC
LIMIT 100
";

If you whant to display posts that have either lottery_year = $y ( or ) photo_technique = $x, you could use :
$querystr = "
SELECT $wpdb->posts.*
FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
WHERE ($wpdb->postmeta.meta_key = 'lottery_year' AND $wpdb->postmeta.meta_value = $y) OR ($wpdb->postmeta.meta_key = 'photo_technique' AND $wpdb->postmeta.meta_value = $x)
AND $wpdb->posts.post_type = 'attachment'
ORDER BY $wpdb->postmeta.meta_value ASC
LIMIT 100
";
Edit
If you whant to display results that have both lottery_year = $y ( AND ) photo_technique = $x, you could use the following query :
$querystr = "
SELECT
$wpdb->posts.*
FROM
$wpdb->posts
INNER JOIN $wpdb->postmeta ON
$wpdb->posts.ID = $wpdb->postmeta.post_id
AND $wpdb->postmeta.meta_key IN ( 'lottery_year', 'photo_technique' )
AND $wpdb->postmeta.meta_value IN ( '$y', '$x' )
WHERE $wpdb->posts.post_type = 'attachment'
GROUP BY $wpdb->posts.ID
HAVING COUNT(1) = 2
ORDER BY $wpdb->postmeta.meta_value ASC
LIMIT 100
";
Edit
The last query ( the AND one ) will fail in some circumstances. For example you whant
lottery_year = $y AND photo_technique = $x, but it will allso return results that have the $x and $y switched like : lottery_year = $x AND photo_technique = $y, it realy depends when you can rely on it or not, like do you have a photo_technique that is called for example '2001' ( witch could pass as a lottery_year too ) . Please be carefull with it or ask this question on dba.stackexchange.com or wordpress.stackexchange.com .

Related

Combination of two SQL queries

I have two separate SQL queries that I would like to combine to a single one if possible.
Query #1 yields all entries from a table in random order
Query #2 will afterwards check whether or not the result can be used
How can I achieve this in a single step directly in SQL?
Code:
// start with a query for all of the photos, returned in random order
$query = "
SELECT DISTINCT m.mediaID
, m.description
, m.path
, m.alwayson
, m.usecollfolder
, m.mediatypeID
FROM $media_table m
WHERE m.mediatypeID = 'photos'
ORDER BY RAND();
";
$result = mysql_query($query) or die ("$text[cannotexecutequery]: $query");
while( $imgrow = mysql_fetch_assoc( $result ) ) {
// if the picture is alwayson or we are allowing living to be displayed,
// we don't need to bother
// with any further checking
if ($imgrow[alwayson] || $allow_living_db ) {
break;
// otherwise, let's check for living
} else {
// this query will return rows of personIDs on the photo that are living
$query = "
SELECT l.personID
FROM $medialinks_table l
JOIN $people_table p ON l.personID = p.personID
WHERE l.mediaID = $imgrow[mediaID]
AND p.living = 1
";
$presult = mysql_query($query) or die ("$text[cannotexecutequery]: $query");
$rows = mysql_num_rows( $presult );
mysql_free_result( $presult );
// if no rows are returned, there are no living on the photo, so let's display it
if ($rows == 0) {
break;
}
}
SELECT DISTINCT m.mediaID
, m.description
, m.path
, m.alwayson
, m.usecollfolder
, m.mediatypeID
, l.personID
FROM $media_table m
JOIN $medialinks_table l
ON l.mediaID = m.mediaID
JOIN $people_table p
ON l.personID = p.personID
WHERE m.mediatypeID = 'photos'
AND p.living = 1
ORDER
BY RAND();

limit results for wpdb query

this code displays the tags from current category only but, it gets all the tags (hundreds) so, i need to limit the number of returned results and make em random.
How to make this query get only 20 results randomly ?
/* Retrieve all tags from posts in selected categories */
$cats = array('beaches','mountains'); // Must be an array even if only one category
$cats_string = "'" . implode($cats,"','") . "'";
$sql = <<<EOSQL
SELECT DISTINCT t.*
FROM $wpdb->posts p
JOIN $wpdb->term_relationships tr ON p.ID = tr.object_id
JOIN $wpdb->term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id
AND tt.taxonomy = 'post_tag')
JOIN $wpdb->terms t ON tt.term_id = t.term_id
WHERE
p.ID IN (
SELECT p2.ID
FROM $wpdb->posts p2
JOIN $wpdb->term_relationships tr2 ON p2.ID = tr2.object_id
JOIN $wpdb->term_taxonomy tt2 ON (tr2.term_taxonomy_id = tt2.term_taxonomy_id AND tt2.taxonomy = 'category')
JOIN $wpdb->terms t2 ON (tt2.term_id = t2.term_id AND t2.name IN ($cats_string))
WHERE p2.post_type = 'post'
AND p2.post_status = 'publish'
AND p2.post_date <= NOW()
)
EOSQL;
$terms = $wpdb->get_results($sql);
// print_r($terms);
echo "<br />";
foreach ($terms as $term) {
echo "ID:$term->term_id NAME:$term->name SLUG:$term->slug<br />";
}
Thanks
You can try an ORDER BY RAND() LIMIT 20, depending on your table size this can run in decent times. See here some details on when to avoid the order by rand() logic. Like suggested, in the specified post, the other approach is to retrieve all the entries and randomly select 20 entries, in PHP rather then using mysql.

MYSQL multiply if?

I have a query that looks like this:
//execute the SQL query and return records
$result = mysql_query("SELECT SUM(ps_order_detail.product_weight) as total_provision, COUNT(ps_order_detail.id_order_detail) as antal_ordrar, ps_customer.firstname
FROM ps_order_detail
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
WHERE MONTH(ps_order_history.date_add) = MONTH(CURDATE()) AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13'
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC
");
//fetch tha data from the database
while ($row = mysql_fetch_array($result))
{
echo '<font size="3">';
echo " Namn: ".$row{'firstname'}. "";
echo " Provision: ".$row{'total_provision'}. "";
echo " Abonnemang: ".$row{'antal_ordrar'}. "";
echo '<br>';
echo '</font size>';
}
It works fine but what i wana do is if the result "antal_ordrar" is larger than say 50 i wana multiply the result "total_provision" with 1,2 (add an extra 20% to the result)
Im new on mysql and are kinda stuck. Any ideas?
SELECT SUM(ps_order_detail.product_weight) *
IF( COUNT(ps_order_detail.id_order_detail) > 50, 1.2, 1 ) AS total_provision,
COUNT(ps_order_detail.id_order_detail) AS antal_ordrar, ...
First, wrap this in a subquery:
SELECT
-- use the if statement
IF( antal_ordrar > 50, total_provision * 1.2, total_provision ),
antal_ordrar,
firstname
FROM
-- create a subquery so you can reuse the data.
( SELECT SUM(ps_order_detail.product_weight) as total_provision,
COUNT(ps_order_detail.id_order_detail) as antal_ordrar,
ps_customer.firstname as firstname
FROM ps_order_detail
-- are you sure you need this many joins?
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
-- group by normally uses the 'having' keyword.
WHERE MONTH(ps_order_history.date_add) = MONTH(CURDATE())
AND (ps_order_history.id_order_state) = '4'
OR (ps_order_history.id_order_state) = '13'
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC )
-- an alias for your subquery so you can treat it like a table.
tbl;
Just noticed this. You're using braces when you mean brackets: $row{'total_provision'} should be $row['total_provision'].
Try to add to select
if (antal_ordrar > 50, total_provision * 1.2, total_provision) as total_provision

MYSQL Limit results

I've almost done with my query, but there is still one last issue to resolve. My query looks like this:
//execute the SQL query and return records
$result = mysql_query("SELECT SUM(ps_order_detail.product_weight) * IF( COUNT(ps_order_detail.id_order_detail) > 50, 1.2, 1 )
as total_provision, COUNT(ps_order_detail.id_order_detail) as antal_ordrar, ps_customer.firstname
FROM ps_order_detail
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
WHERE MONTH(ps_order_history.date_add) = MONTH(CURDATE()) AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13'
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC
");
echo "<br>";
echo ("<img src=chart.php>");
echo "<br>";
echo ("<img src=chart_prov.php>");
//fetch tha data from the database
while ($row = mysql_fetch_array($result))
{
echo '<font size="3">';
echo " Namn: ".$row{'firstname'}. "";
echo " Provision: ".$row{'total_provision'}. "";
echo " Abonnemang: ".$row{'antal_ordrar'}. "";
echo '<br>';
echo '</font size>';
}
This part:
AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13'
causes the result to be displayed if the state of orders is either 4 or 13. The problem is that in the backend I can put it in those states many times, so if I'm not careful when updating orders, it will add the results more than one time.
Is it a way to limit that funktion to just handle latest update (have date_add in same table) or limit by 1?
Try to use
SELECT SUM(ps_order_detail.product_weight) * IF( COUNT(ps_order_detail.id_order_detail) > 50, 1.2, 1 )
as total_provision, COUNT(ps_order_detail.id_order_detail) as antal_ordrar, ps_customer.firstname
FROM ps_order_detail
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
WHERE ps_order_history.id = (select ps_order_history.id from ps_order_history where ps_orders.id_order = ps_order_history.id_order and MONTH(ps_order_history.date_add) = MONTH(CURDATE()) AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13' order by ps_order_history.date_add desc limit 1)
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC
Maybe it helps.

Can I use a variable in SQL? If not, how to avoid this?

Can I pull out data by using variable in SQL?
For example,
In controller
$frontbottom = $this->MProducts -> getFeatureProducts('Front bottom');
In model
//This does not work.
function getFeatureProducts($catname){
$data = array();
$Q = $this->db->query('SELECT P.*, C.Name AS CatName
FROM omc_products AS P
LEFT JOIN omc_categories AS C
ON C.id = P.category_id
WHERE C.Name = $catname
AND p.status = "active"
ORDER BY RAND()
');
if ($Q->num_rows() > 0){
foreach ($Q->result_array() as $row){
$data[] = $row;
}
}
$Q->free_result();
return $data;
}
This does not work. Is it because I am using variable?
The following works.
In controller
$frontbottom = $this->MProducts -> getFrontbottom();
In model
function getFrontbottom(){
$data = array();
$Q = $this->db->query('SELECT P.*, C.Name AS CatName
FROM omc_products AS P
LEFT JOIN omc_categories AS C
ON C.id = P.category_id
WHERE C.Name = "Front bottom"
AND p.status = "active"
ORDER BY RAND()
');
if ($Q->num_rows() > 0){
foreach ($Q->result_array() as $row){
$data[] = $row;
}
}
$Q->free_result();
return $data;
}
Can I use variable in SQL?
If not, what is the best way? Do I have make same SQL again and again just changing WHERE clause?
For one thing, your quotes are mixed up. If you want to include a variable in a string, you need to use double quotes rather than single quotes. Also, the quotes around "active" should be single quotes. Try this and I think it should work:
$this->db->query("SELECT P.*, C.Name AS CatName
FROM omc_products AS P
LEFT JOIN omc_categories AS C
ON C.id = P.category_id
WHERE C.Name = '$catname'
AND p.status = 'active'
ORDER BY RAND()
");
You can use variables in SQL, after all, that's just a normal string you're passing to the query function.You are using single quotes, that is why your variable does not work. All variables inside single quotes are ignored by PHP and will not be parsed. Put the query in double quotes. You should also always properly escape variables in queries to protect yourself from SQL injection attacks. Thus, this would work and be safe:
$Q = $this->db->query("SELECT P.*, C.Name AS CatName
FROM omc_products AS P
LEFT JOIN omc_categories AS C
ON C.id = P.category_id
WHERE C.Name = '".mysql_real_escape_string($catname)."',
AND p.status = 'active'
ORDER BY RAND()");
If it's still failing, try using echo mysql_error() after the query, and also echo the query to the browser so you'll see whether it's properly formatted.
Note that the database library might have it's own alternatives to mysql_real_escape_string and mysql_error, but this was just an example anyways.
you need to expand the variable before yo make the sql query.
sql_query1 = 'SELECT P.*, C.Name AS CatName
FROM omc_products AS P
LEFT JOIN omc_categories AS C
ON C.id = P.category_id
WHERE C.Name = "'
sql_query2 = '" AND p.status = "active"
ORDER BY RAND()
'
finally ,
sqlquery = sqlquery1+ $catname + sqlquery2
on your actual program don't use sqlquery1,2 etc .. this is a very cumbersome way to do this.. it is only to make it clear to understand
Try this:
//This does not work.
function getFeatureProducts($catname){
$data = array();
$Q = $this->db->query('SELECT P.*, C.Name AS CatName
FROM omc_products AS P
LEFT JOIN omc_categories AS C
ON C.id = P.category_id
WHERE C.Name = "' . $catname . '"
AND p.status = "active"
ORDER BY RAND()
');
if ($Q->num_rows() > 0){
foreach ($Q->result_array() as $row){
$data[] = $row;
}
}
$Q->free_result();
return $data;
}
The bottom line, is that you need to put the value from the variable into the SQL String. You cannot simply put the name of the variable.