Below is my working query that gets into action after a form submit. My query works only if all textboxes are filled, so currently everything is required.
WORKING QUERY
SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count(*) AS total
FROM behaviour,
audience,
new_table
WHERE ( $url )
AND behaviour.timestamp >= Date_sub(Curdate(), INTERVAL $last_visit day) AND behaviour.timestamp < Date_add(Curdate(), INTERVAL 1 day)
AND behaviour.hash = audience.hash
AND behaviour.hash = new_table.hash
AND audience.country = '$from_country'
GROUP BY behaviour.hash
HAVING Count(*) >= $more_than
AND timespent >= $time_spent
AND new_table.percentile_rank >= $lead_scoring
What I want to achieve is not to require the user to fill all the textboxes in order to submit, but only those he prefers. So I built the following, but it has some errors.
My problem is that my query has a having clause so not every condition is connected with AND as I have for now (look below my code). So, the first of the $more_than or $time_spent or $lead_scoring textboxes that submitted, it must have HAVING instead of AND.
How to edit my code in order to achieve this "special conditions" ?
MY CODE
$url= 'url="'.implode('" OR url="', $vals).'"';
$conditions = array();
if (!empty($last_visit)) $conditions[] = "behaviour.TIMESTAMP >= DATE_SUB( CURDATE( ) , INTERVAL '".$last_visit."' DAY) AND behaviour.TIMESTAMP < DATE_ADD( CURDATE( ) , INTERVAL 1 DAY ) ";
if (!empty($from_country)) $conditions[] = "audience.country = '".$from_country."'";
if (!empty($more_than)) $conditions[] = "COUNT( * ) >= '".$more_than."'";
if (!empty($time_spent)) $conditions[] = "timeSpent >= '".$time_spent."'";
if (!empty($lead_scoring)) $conditions[] = "new_table.percentile_rank >= '".$lead_scoring."'";
$conditionString = implode(' AND ', $conditions);
$sql = "SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count( * ) AS total
FROM behaviour,
audience,
new_table
WHERE ($url) AND ".$conditionString;
CURRENT OUTPUT
In the example below, all textboxes except more_than have been filled. The thing is that instead AND timespent >= '20' should be HAVING timespent >= '20'
SELECT behaviour.hash,
SUM(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count(*) AS total
FROM behaviour,
audience,
new_table
WHERE ( url = "/10369" )
AND behaviour.timestamp >= Date_sub(Curdate(), interval '3' day)
AND behaviour.timestamp < Date_add(Curdate(), interval 1 day)
[missing] AND behaviour.hash = audience.hash
[missing] AND behaviour.hash = new_table.hash
AND audience.country = 'it'
[missing] GROUP BY behaviour.hash
[wrong] AND timespent >= '20' ////// it should be HAVING /////
AND new_table.percentile_rank >= '30'
First, you must ensure SQL injection is not possible. To do that, lets use PDO.
Next, to solve your actual problem, you simple need to create two lists with conditions. One with the conditions you want to have in the WHERE part of the query, and one with the conditions that need to go in the HAVING part of the query.
$pdo = new PDO(/* See http://php.net/manual/en/pdo.construct.php */);
$whereConditions = [];
$havingConditions = [];
$parameters = [];
if (!empty($last_visit)) {
$whereConditions[] = "behaviour.TIMESTAMP >= DATE_SUB( CURDATE( ) , INTERVAL :last_visit DAY) AND behaviour.TIMESTAMP < DATE_ADD( CURDATE( ) , INTERVAL 1 DAY ) ";
$parameters['last_visit'] = $last_visit;
}
if (!empty($from_country)) {
$whereConditions[] = "audience.country = :from_country";
$parameters['from_country'] = $from_country;
}
if (!empty($more_than)) {
$havingConditions[] = "COUNT( * ) >= :more_than";
$parameters['more_than'] = $more_than;
}
if (!empty($time_spent)) {
$havingConditions[] = "timeSpent >= :time_spent";
$parameters['time_spent'] = $time_spent;
}
if (!empty($lead_scoring)) {
$havingConditions[] = "new_table.percentile_rank >= :lead_scoring";
$parameters['lead_scoring'] = $lead_scoring;
}
if (count($vals)) {
$escapedUrlList = implode(', ', array_map(function ($url) use ($pdo) {
return $pdo->quote($url);
}, $vals));
$whereConditions[] = "url IN($escapedUrlList)";
}
$whereClause = count($whereConditions) ? ' AND ' . implode(' AND ', $whereConditions) : '';
$havingClause = count($havingConditions) ? ' HAVING ' . implode(' AND ', $havingConditions) : '';
$statement = $pdo->prepare("
SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count(*) AS total
FROM behaviour,
audience,
new_table
WHERE behaviour.hash = audience.hash
AND behaviour.hash = new_table.hash
{$whereClause}
GROUP BY behaviour.hash
{$havingClause}
");
$result = $statement->execute($parameters);
Here's a bit "tricky" approach (looks clean though) that is using prepared statements. I've added some general purpose "features" in case of future changes.
Read the comments with explanations (will be more convenient this way I think):
//assume established PDO connection - example:
try {
$pdo = new PDO("mysql:dbname={$database_name};host=localhost", $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
//static: conditional strings without parameters check (no keys required)
//conditional: assoc - keys should match both query placeholders and variable names
$static_where = [];
$optional_where = [
'last_visit' => 'behaviour.TIMESTAMP >= DATE_SUB(CURDATE(), INTERVAL :last_visit DAY) AND behaviour.TIMESTAMP < DATE_ADD(CURDATE(), INTERVAL 1 DAY)',
'from_country' => 'audience.country = :from_country'
];
$static_having = [];
$optional_having = [
'more_than' => 'COUNT(*) >= :more_than',
'time_spent' => 'timeSpent >= :time_spent',
'lead_scoring' => 'new_table.percentile_rank >= :lead_scoring'
];
//params: query parameters array - assigned manually + resolved from optional variables
$params = [];
//resolve condition from $urls array
if (count($urls) == 1) {
$static_where[] = 'url = :url';
$params['url'] = reset($urls);
} else if (!empty($urls)) {
foreach ($urls as $idx => $url) {
$params['url' . $idx] = $url;
}
$static_where[] = 'url IN(:' . implode(', :', array_keys($params)) . ')';
}
//filtering existing params used in query
//empty() is not a good idea for general purpose though,
//because some valid values might be recognised as empty (int 0, string '0')
$params += array_filter(
compact(array_keys($optional_where), array_keys($optional_having)),
function ($value) { return !empty($value); }
);
//concatenating conditional strings
//with corresponding params that weren't filtered out
//or these without params (static)
$where_clause = implode(' AND ', $static_where + array_intersect_key($optional_where, $params));
$having_clause = implode(' AND ', $static_having + array_intersect_key($optional_having, $params));
//don't need clauses without conditions - same as if (!empty($where)) {...}
empty($where_clause) or $where_clause = 'WHERE ' . $where_clause;
empty($having_clause) or $having_clause = 'HAVING ' . $having_clause;
$sql = "SELECT
behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count( * ) AS total
FROM behaviour,
INNER JOIN audience ON behaviour.hash = audience.hash,
INNER JOIN new_table ON behaviour.hash = new_table.hash
{$where_clause}
GROUP BY behaviour.hash
{$having_clause}";
//PDO part
$query = $pdo->prepare($sql);
$result = $query->execute($params);
//...
Here is a less complicated way using string concatenation instead of implode. The "trick" is to start the conditions with 1=1. So every following condition can begin with AND.
$andWhere = '';
$andHaving = '';
$params = [];
if (!empty($last_visit)) {
$andWhere .= " AND behaviour.TIMESTAMP >= CURDATE() - INTERVAL :last_visit DAY AND behaviour.TIMESTAMP < CURDATE() + INTERVAL 1 DAY";
$params['last_visit'] = $last_visit;
}
if (!empty($from_country)) {
$andWhere .= " AND audience.country = :from_country";
$params['from_country'] = $from_country;
}
if (!empty($more_than)) {
$andHaving .= " AND COUNT( * ) >= :more_than";
$params['more_than'] = $more_than;
}
if (!empty($time_spent)) {
$andHaving .= " AND timeSpent >= :time_spent";
$params['time_spent'] = $time_spent;
}
if (!empty($lead_scoring)) {
$andHaving .= " AND new_table.percentile_rank >= :lead_scoring";
$params['lead_scoring'] = $lead_scoring;
}
$urlPlaceholders = [];
foreach ($vals as $key => $val) {
$urlPlaceholders[] = ":url_$key";
$params["url_$key"] = $val;
}
if (count($vals) > 0) {
$inUrl = implode(',', $urlPlaceholders);
$andWhere .= " AND url IN ($inUrl)";
}
$sql = "
SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count(*) AS total
FROM behaviour
JOIN audience ON behaviour.hash = audience.hash
JOIN new_table ON behaviour.hash = new_table.hash
WHERE 1=1 {$andWhere}
GROUP BY behaviour.hash
HAVING 1=1 {$andHaving}
";
#var_export($sql);
#var_export($params);
$sth = $dbh->prepare($sql);
$sth->execute($params);
$data = $sth->fetchAll(PDO::FETCH_ASSOC);
#var_export($data);
Having sample data like
$last_visit = '';
$from_country = 'UK';
$more_than = '5';
$time_spent = '3';
$lead_scoring = '';
$vals = ['u1', 'u2'];
You would get the following query:
SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count(*) AS total
FROM behaviour
JOIN audience ON behaviour.hash = audience.hash
JOIN new_table ON behaviour.hash = new_table.hash
WHERE 1=1 AND audience.country = :from_country AND url IN (:url_0,:url_1)
GROUP BY behaviour.hash
HAVING 1=1 AND COUNT(*) >= :more_than AND timeSpent >= :time_spent
with these bindings:
array (
'from_country' => 'UK',
'more_than' => '5',
'time_spent' => '3',
'url_0' => 'u1',
'url_1' => 'u2',
)
Demo on rextester.com
If having is the only problem why not splitting it into different block like this:
$conditions = array();
if (!empty($last_visit)) $conditions[] = "behaviour.TIMESTAMP >= DATE_SUB( CURDATE( ) , INTERVAL '".$last_visit."' DAY) AND behaviour.TIMESTAMP < DATE_ADD( CURDATE( ) , INTERVAL 1 DAY ) ";
if (!empty($from_country)) $conditions[] = "audience.country = '".$from_country."'";
$conditionString = implode(' AND ', $conditions);
$conditions_having = array();
if (!empty($more_than)) $conditions_having[] = "COUNT( * ) >= '".$more_than."'";
if (!empty($time_spent)) $conditions_having[] = "timeSpent >= '".$time_spent."'";
if (!empty($lead_scoring)) $conditions_having[] = "new_table.percentile_rank >= '".$lead_scoring."'";
$conditionString .= " GROUP BY behaviour.hash"
if(count($conditions_having))
$conditionString .= " HAVING ".implode(' AND ', $conditions_having);
$sql = "SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count( * ) AS total
FROM behaviour,
audience,
new_table
WHERE ($url) AND ".$conditionString;
You can change only your implode function to this code
$conditionString = implode(' ', array_map(function($item) {
if ((strpos($item, 'timeSpent') !== false))
return 'HAVING '.$item;
return 'AND '.$item;
}, $conditions));
Be aware that your code is vulnerable.
for more information see this: SQL Injection In CAPEC
$url= 'url="'.implode('" OR url="', $vals).'"';
$conditions = array();
$havings = array();
if (!empty($last_visit)) $conditions[] = "behaviour.TIMESTAMP >= DATE_SUB( CURDATE( ) , INTERVAL '".$last_visit."' DAY) AND behaviour.TIMESTAMP < DATE_ADD( CURDATE( ) , INTERVAL 1 DAY ) ";
if (!empty($from_country)) $conditions[] = "audience.country = '".$from_country."'";
if (!empty($more_than)) $havings[] = "COUNT( * ) >= '".$more_than."'";
if (!empty($time_spent)) $havings[] = "timeSpent >= '".$time_spent."'";
if (!empty($lead_scoring)) $havings[] = "new_table.percentile_rank >= '".$lead_scoring."'";
$conditionString = implode(' AND ', $conditions);
$havingString = '';
if(count($havings)>0) {
$havingString = ' having '.implode(', ', $havings);
}
$sql = "SELECT behaviour.hash,
Sum(behaviour.timespent) AS timeSpent,
new_table.percentile_rank,
Count( * ) AS total
FROM behaviour,
audience,
new_table
WHERE ($url) AND ".$conditionString.$havingString;
I have the following PHP script. How do I get the correct results. Each query should only return a number. I need to get rank in this case. I was also wondering how to combine those two queries into one statement.
function getRankings($country, $deviceid)
{
$queryWorld = "SELECT 1 + (SELECT count( * ) FROM ScoreTable a WHERE a.score > b.score ) AS rank FROM
ScoreTable b WHERE DeviceID='$deviceid' ORDER BY rank LIMIT 1";
$queryCountry = "SELECT 1 + (SELECT count( * ) FROM ScoreTable a WHERE a.score > b.score AND Country='$country') AS rank FROM ScoreTable b WHERE DeviceID='$deviceid' ORDER BY rank LIMIT 1";
$resultWorld = mysql_query($queryWorld) or die(mysql_error());
$rowWorld = mysql_fetch_row($resultWorld);
$resultCountry = mysql_query($queryCountry) or die(mysql_error());
$rowCountry = mysql_fetch_row($resultCountry);
$arr = array();
$arr[] = array("WorldRanking" => $rowWorld[0], "CountryRanking" => $rowCountry[0]);
echo json_encode($arr);
}
If I type the queries individually into MYSQl I get the correct answers. But the echo produces
[{"WorldRanking":null,"CountryRanking":null}]
It should be something like
[{"WorldRanking":"4","CountryRanking":"1"}]
I think I need to get the value of rank but I do not know how.
try your code like this, but I don't know this code correct or not:
function getRankings($country, $deviceid)
{
$queryWorld = "SELECT 1 + (SELECT count( * ) FROM ScoreTable a WHERE a.score > b.score ) AS rank FROM
ScoreTable b WHERE DeviceID='$deviceid' ORDER BY rank LIMIT 1";
$queryCountry = "SELECT 1 + (SELECT count( * ) FROM ScoreTable a WHERE a.score > b.score AND Country='$country') AS rank FROM ScoreTable b WHERE DeviceID='$deviceid' ORDER BY rank LIMIT 1";
$resultWorld = mysql_query($queryWorld) or die(mysql_error());
while ($rowWorld = mysql_fetch_row($resultWorld)){
$value1 = $rowWorld['filedname1'];
}
$resultCountry = mysql_query($queryCountry) or die(mysql_error());
while($rowCountry = mysql_fetch_row($resultCountry)){
$value2 = $rowWorld['filedname2'];
}
$arr[] = array("WorldRanking" => $value1, "CountryRanking" => $value2);
print_r($arr);
}
<?php
function getRankings($country, $deviceid)
{
$queryWorld = "SELECT 1 + (SELECT count( * ) FROM ScoreTable a WHERE a.score > b.score ) AS rank FROM
ScoreTable b WHERE DeviceID=$deviceid ORDER BY rank LIMIT 1";
$queryCountry = "SELECT 1 + (SELECT count( * ) FROM ScoreTable a WHERE a.score > b.score AND Country='$country') AS rank FROM ScoreTable b WHERE DeviceID=$deviceid ORDER BY rank LIMIT 1";
$resultWorld = mysql_query($queryWorld) or die(mysql_error());
$no_of_results_in_resultWorld = mysql_num_rows($resultWorld);
if($no_of_results_in_resultWorld > 0){
$rowWorld = mysql_fetch_row($resultWorld);
}
$resultCountry = mysql_query($queryCountry) or die(mysql_error());
$no_of_results_in_resultCountry = mysql_num_rows($resultCountry);
if($no_of_results_in_resultCountry > 0){
$rowCountry = mysql_fetch_row($resultCountry);
}
$arr = array();
$arr[] = array("WorldRanking" => $rowWorld[0], "CountryRanking" => $rowCountry[0]);
echo json_encode($arr);
}
check whether it is returning results or not.
I have a problem to get total rows counting with condition. This is my code
$pagesize = 10;
$recordstart = (int)$_GET['recordstart'];
$recordstart = (isset($_GET['recordstart'])) ? $recordstart : 0;
$town = $_GET['label_town'];
$sub = ucfirst($_GET['label_sub']);
Here is my selecting condition. I also use this condition to count totalrows
if (isset($_GET['label_town']) === true && isset($_GET['label_sub']) === true) {
$where = "WHERE p.label_town = '$town' AND p.label_sub = '$sub' AND `visible` = 1";
} else if (isset($_GET['label_town']) === true && isset($_GET['label_sub']) === false) {
$where = "WHERE p.label_town = '$town' AND `visible` = 1";
} else {
$where = "WHERE `visible` = 1";
}
// Selecting data
$all_page_index = mysql_query("SELECT p.page_id, p.timestamp, p.label_town, p.label_sub, p.ime_nekretnine, p.mjesto, p.cijena_noc, p.krevet_apart, p.broj_apart, p.min_nocenja, p.description, p.visits, i.image_id, i.page_id, i.ext
FROM data_page AS p
LEFT JOIN (
SELECT MAX( image_id ) AS max, page_id
FROM images
GROUP BY page_id
) AS n ON p.page_id = n.page_id
LEFT JOIN images AS i ON i.image_id = n.max
$where
ORDER BY p.page_id DESC
LIMIT $recordstart, $pagesize");
// Counting rows with conditions
function totalrows() {
return mysql_result(mysql_query("SELECT COUNT(p.page_id) FROM data_page AS p $where"), 0);
}
Selecting and displaying data works fine but problem is with SELECT COUNT. Always count totalrows no mater what condition is. Where I making wrong?
Thanks!
Your COUNT is within function definition, where $where isn't defined. You need to pass it as a parameter or move query outside the function.
On my blog I am have a function that counts how many blog posts have been made month by month and these can be displayed in a sub menu.
It is looped by year, and then another nested loop by month. Each time it runs this query to count how many articles were posted in each month.
This is the query:
Select * from DM_blog blog where blog.id IN
( SELECT entry_id FROM DM_tags_target tagstarget WHERE tagstarget.parent_id IN
( SELECT id FROM DM_tags tags WHERE tags.tag = '".$data['page']['id']."' AND tags.type = 'blog_target' )) AND blog.publish < '".date("Y-m-d H:i:s")."' and blog.status = '0' and YEAR(blog.publish) = '".$year."' and MONTH(blog.publish) = '".$month."'"
Is there a better way to do this? Can I do all of the months at once instead of having to do 12 queries a year? The full code is here:
$this->benchmark->mark('blog_submenu_start');
$dates = $this->blog_model->menu_dates($data);
if($dates['years']){
$i = 0;
foreach($dates['years'] as $year){
if($data['segments']['modal'] == $year['YEAR(blog.publish)']){
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['class'] = 'selected';
$selected = true;
}else if(date("Y") == $year['YEAR(blog.publish)'] && $selected == false){
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['class'] = 'selected';
$selected = true;
}
// find the start month
if($dates['first_entry'][0]['YEAR(blog.publish)'] == $year['YEAR(blog.publish)']){
if($dates['first_entry'][0]['MONTH(blog.publish)'] < 2){
$limit_s['start'] = '1';
$limit_s['end'] = 13;
}else{
$limit_s['start'] = $dates['first_entry'][0]['MONTH(blog.publish)'];
$limit_s['end'] = 12;
}
}else{
$limit_s['start'] = 1;
$limit_s['end'] = 13;
}
// run through the months
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_start');
for($x=$limit_s['start'];$x<=$limit_s['end'];$x++){
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_start');
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_mysql_start');
$count = $this->blog_model->month_count($year['YEAR(blog.publish)'],$x,$data);
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_mysql_end');
if($last == false){
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_selected_start');
if($data['segments']['modal'] == $year['YEAR(blog.publish)'] and $data['segments']['para_one'] == $x){
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['months'][$x]['class'] = 'selected';
}
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_selected_end');
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_assign_start');
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['months'][$x]['month'] = $x;
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['months'][$x]['display_full'] = date('F',strtotime($year['YEAR(blog.publish)'].'-'.$x.'-01'));
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['months'][$x]['display_short'] = date('M',strtotime($year['YEAR(blog.publish)'].'-'.$x.'-01'));
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['months'][$x]['count'] = $count;
$data['date_submenu']['year'][$year['YEAR(blog.publish)']]['months'][$x]['sef'] = $year['YEAR(blog.publish)'].'/'.$x.'/';
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_assign_end');
if(date("Y") == $year['YEAR(blog.publish)'] and date("m") == $x || date("n") == $x){
$last = true;
} // end date
$i++;
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_'.$x.'_end');
} // end last false
} // end for
$this->benchmark->mark('blog_submenu_dates_'.$year['YEAR(blog.publish)'].'_end');
}
}
$this->benchmark->mark('blog_submenu_end');
$this->blog_model->month_count - this function is as follows:
function month_count($year,$month,$data=false){
$query = $this->db->query("Select * from DM_blog blog where blog.id IN
( SELECT entry_id FROM DM_tags_target tagstarget WHERE tagstarget.parent_id IN
( SELECT id FROM DM_tags tags WHERE tags.tag = '".$data['page']['id']."' AND tags.type = 'blog_target' )) AND blog.publish < '".date("Y-m-d H:i:s")."' and blog.status = '0' and YEAR(blog.publish) = '".$year."' and MONTH(blog.publish) = '".$month."'");
return $query->num_rows();
}
You can add group by clause to group the results by year and month.
Select * from DM_blog blog where blog.id IN
( SELECT entry_id FROM DM_tags_target tagstarget WHERE tagstarget.parent_id IN
( SELECT id FROM DM_tags tags WHERE tags.tag = '".$data['page']['id']."' AND tags.type = 'blog_target' )) AND blog.publish < '".date("Y-m-d H:i:s")."' and blog.status = '0' GROUP BY YEAR(blog.publish), MONTH(blog.publish)
You could use a GROUP BY expression:
SELECT id, YEAR(blog.publish), MONTH(blog.publish)
FROM DM_blog blog
WHERE blog.id IN
( SELECT entry_id
FROM DM_tags_target tagstarget
WHERE tagstarget.parent_id IN
( SELECT id
FROM DM_tags tags
WHERE tags.tag = '".$data['page']['id']."'
AND tags.type = 'blog_target'
)
)
AND blog.publish < '".date("Y-m-d H:i:s")."'
AND blog.status = '0'
GROUP BY YEAR(blog.publish), MONTH(blog.publish)
It will give you the results grouped by year and month
i have a function where i get the ratings of the selected user by id,
it gets the ratings from one type of things, the ratings of a diff type of things and then does a+b
i know it's not very optimized but i'm focus on making all work...
this i do it like this
function votos_usuario($id){
$previa = "SELECT id FROM preguntas WHERE id_usuario = '$id'";
$r_previo = mysql_query($previa);
$ids_p = '0, ';
while($items_previos = mysql_fetch_array($r_previo)){
$ids_p .= $items_previos['id'].", ";
//echo "ids pregunta usuario: ".$items_previos['id']."<br>";
}
$ids = substr($ids_p,0,-2);
//echo $ids;
$consulta = "SELECT valor FROM votos_pregunta WHERE id_pregunta IN ( $ids )";
//echo $consulta;
$resultado = mysql_query($consulta);
$votos_preguntas = 0;
while($voto = mysql_fetch_array($resultado)){
$votos_preguntas = $votos_preguntas + $voto['valor'];
}
//$votos_preguntas= 0;
//$votos_preguntas = mysql_query("SELECT SUM(valor) FROM votos_pregunta WHERE id_pregunta IN (SELECT id FROM preguntas WHERE id_usuario = '$id')");
$previa_r = "SELECT id FROM recetas WHERE id_usuario = '$id'";
$r_previo_r = mysql_query($previa_r);
$ids_r = '0, ';
while($items_previos_r = mysql_fetch_array($r_previo_r)){
$ids_r .= $items_previos_r['id'].", ";
//echo "ids pregunta usuario: ".$items_previos['id']."<br>";
}
$ids = substr($ids_r,0,-2);
$consulta_b = "SELECT valor FROM votos_receta WHERE id_receta IN ( $ids )";
//echo $consulta;
$resultado_b = mysql_query($consulta_b);
$votos_recetas = 0;
while($voto_r = mysql_fetch_array($resultado_b)){
$votos_recetas = $votos_recetas + $voto_r['valor'];
}
$total = $votos_preguntas + $votos_recetas;
return $total;
}
Now the Question,
how can i do it to get all users ordered by rating desc ???? i just can't see it :S
SELECT uid, SUM(Votes)
FROM (
SELECT p.id_usuario uid, SUM(vp.valor) votes
FROM preguntas p JOIN votos_pregunta vp ON p.id = vp.id_pregunta
GROUP BY p.id_usuario
UNION ALL
SELECT r.id_usuario uid, SUM(vr.valor) votes
FROM recetas r JOIN votos_receta vr ON r.id = vr.id_receta
GROUP BY r.id_usuario
) rs
GROUP BY uid
ORDER BY SUM(Votes) DESC
instead of your php loop and all the sub queries, you can use this single query to get what you want:
SELECT (
SELECT SUM(vp.valor)
FROM preguntas p JOIN votos_pregunta vp ON p.id = vp.id_pregunta
WHERE p.id_usuario = '$id')
+ (
SELECT SUM(vr.valor)
FROM recetas r JOIN votos_receta vr ON r.id = vr.id_receta
WHERE r.id_usuario = '$id'
)
Also, when you're only using the associative keys in the result array, using mysql_fetch_assoc() is much, much faster than mysql_fetch_array().
Same applies to using mysql_fetch_row() instead when you're just using the numerical keys.