MySQL Query – is there a better way? - php

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

Related

How to implode these conditions to achieve this query structure?

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;

Wanted to find the number of present days using php?

Hi to all the people here in stackoverflow, I would just like to ask for a little help from you guys. I'm stuck on what I'm doing I wanted to count the number of days present in my query but I don't know how. Could anyone help me on this? An form of help would be much appreciated.
Here is my codes with comments:
//Used for getting the values
$mfrom = $this->input->get('mfroma'); //From: Month
$yfrom = $this->input->get('yfroma'); //From: Year
$yto = $this->input->get('ytoa'); //To : Year
$n_of_months = $this->input->get('n_of_monthsa'); // Month or year Range
$cmonth = $mfrom; //From: Month
$cyear = $yfrom; //From: Year
$clastyear = $yto; //To: Year
$sSQLSelect = "";
$sSQLSelect1 = "";
for($i=0;$i<=$n_of_months;$i++)
{
$curdate = $cmonth." ".$cyear;
$sSQLSelect = $sSQLSelect."SUM(IF(DATE_FORMAT(date_d, '%c %Y') = '$curdate' ,
IF(DP.hrsdiff <= 4, 0.5, 1), 0)) AS 'month$cmonth$cyear', ";
$sSQLSelect1 = $sSQLSelect1."month$cmonth$cyear + ";
if($cmonth+1 > 12) {
$cyear++;
$cmonth = 1;
} else
$cmonth++;
}
date_default_timezone_set('Asia/Manila');
$current_date = date('Y-m',time());
$d = array();
$i = 0;
$sSQL = "SELECT TS.id AS TSid, employeeid, `date` AS date_d, TS.TI1 AS TI1, TS.TO1 AS TO1,
CONCAT(E.lastName,', ',E.firstName,' ',E.middleInitial,'.') AS 'fullname',
(TIME_TO_SEC(CAST(TS.`TI1` AS time))/3600) AS 'timeinint',
(TIME_TO_SEC(CAST(TS.`TO1` AS time))/3600) AS 'timeoutint',
E.startDate, C.companyName, B.branchName,
R.mon, R.tue, R.wed, R.thu, R.fri, R.sat, R.sun
FROM timeschedule AS TS
LEFT JOIN employee AS E ON TS.employeeid = E.id
LEFT JOIN company AS C ON E.companyid = C.id
LEFT JOIN branch AS B ON E.branchid = B.id
LEFT JOIN restday AS R ON R.id = E.restDayid
WHERE TS.`show` = '1' $namecondition $companynamecondition $branchnamecondition
GROUP BY employeeid
ORDER BY fullname ASC";
$result = $this->db->query($sSQL);
$data = array();
foreach($result->result() as $row)
{
$rowemployeedetails = $row;
$fullname = $row->fullname;
$startdate = $row->startDate;
$st_month = (int)(date("m",strtotime($startdate)));
$st_day = (int)(date("d",strtotime($startdate)));
$st_year = (int)(date("Y",strtotime($startdate)));
$data['data'][$i][] = array($row->fullname);
$data['data'][$i][] = array($row->companyName);
$data['data'][$i][] = array($row->branchName);
// #$cmonth = start_month
// #$cyear = start_year
// #number months in between
$cmonth = $mfrom;
$cyear = $yfrom;
for($j=0; $j<= $n_of_months ;$j++){
if((date('Y-m', strtotime($startdate)) <= date('Y-m', strtotime($cyear.'-'.$cmonth)))&&($current_date >= date('Y-m', strtotime($cyear.'-'.$cmonth))))
{
$d[$j] = ((date('Y-m', strtotime($cyear.'-'.$cmonth)) == date('Y-m',time()))?date('d', time()):cal_days_in_month(CAL_GREGORIAN, $cmonth, $cyear));
}
else
{
$d[$j]=0;
}
if($cmonth === 12){
$cyear++;
$cmonth = 1;
}
else{
$cmonth++;
}
}
// #Result: d[] = number of days in month
// #$cyear = start year filter
// #$clastyear = last year filter
// #$cmonth = start_month
$cyear = $yfrom;
$clastyear = $yto;
}
$result->free_result();
return json_encode($data);
}
If you have two dates and want to know the amount of days from one to the other, a simple solution would be to use DateTime::diff like so:
<?php
$from = new DateTime('2014-03-28');
$to = new DateTime('2014-03-30');
$interval = $from->diff($to);
echo $interval->format('%R%a'); // +2

How can I write this multiple-count loop as a single query?

I'm really stumped here, I've tried using:
sum(case when date_format(from_unixtime(l.date_updated), '%Y-%m-%d') = date_format(now(), '%Y-%m-%d') then 1 else 0 end) AS day0_leads,
in my query, and it did not work as intended, so I ended up using this:
<?php
$total_days = '14';
for ($i = $total_days - 1; $i >= 0; $i--)
{
$day = strtotime('-'.$i.' days');
$day_string = date('n/j', $day);
$leads = mysql_result(mysql_query("select count(*) from `leads` where date_format(from_unixtime(`date_updated`), '%m-%d-%Y') = date_format(from_unixtime($day), '%m-%d-%Y')"), 0);
$assigns = mysql_result(mysql_query("select count(*) from `assigns` where date_format(from_unixtime(`date_assigned`), '%m-%d-%Y') = date_format(from_unixtime($day), '%m-%d-%Y') and `id_dealer` not in (1,2,3)"), 0);
echo "['$day_string', $leads, $assigns]";
if ($i > 0)
echo ',';
}
?>
It is making the page load slow, obviously due to unnecessary queries. What is the proper way of writing this as a single query and outputting the results? Like I said, I've tried a sum with a then else, and it did not product the correct numbers.
Any help would greatly be appreciated.
Heres my solution:
$total_days = '14';
// get leads count array
$sql = mysql_query("select count(*) as `count`, `date_updated`
from `leads`
where date_format(from_unixtime(`date_updated`), '%Y-%m-%d') >= date_format(now() - interval $total_days day, '%Y-%m-%d')
group by date(from_unixtime(`date_updated`));") or die(mysql_error());
$leads_count = array();
while ($row = mysql_fetch_assoc($sql))
$leads_count[date('n/j', $row['date_updated'])] = $row['count'];
// get assigns count array
$sql = mysql_query("select count(*) as `count`, `date_assigned`
from `assigns`
where date_format(from_unixtime(`date_assigned`), '%Y-%m-%d') >= date_format(now() - interval $total_days day, '%Y-%m-%d') and `id_dealer` not in (1,2,3,4)
group by date(from_unixtime(`date_assigned`));") or die(mysql_error());
$assigns_count = array();
while ($row = mysql_fetch_assoc($sql))
$assigns_count[date('n/j', $row['date_assigned'])] = $row['count'];
for ($i = $total_days - 1; $i >= 0; $i--)
{
$day = strtotime('-'.$i.' days');
$day_string = date('n/j', $day);
$leads = ((empty($leads_count[$day_string])) ? '0' : $leads_count[$day_string]);
$assigns = ((empty($assigns_count[$day_string])) ? '0' : $assigns_count[$day_string]);
echo "['$day_string', $leads, $assigns]";
if ($i > 0)
echo ',';
}

Query through database and pullout user by user id

I have table of cities, birthday, and users.
Now, what I am trying to do is to query through database and filter range of ages and city of living (out of a list of cities in the selected region - that is why I am checking if count($city[]))>=1), and finely pull out the name of the user based on uid / entety_id.
First I am checking if the user match the range of age, and then if he lives in one of the cities from the selected list.
If no city was selected, I want to filter only the range of ages.
I don't know what is the problem but as far as I notice,
there is this loop, that I have notice that does not execute at all:
for ($d = 1; $d < (count($the_resaults_array)); $d++)
this is the code:
function toodate_query_db($loest_age, $highest_age, $city){
$sql_user_name = '';
if((count($city[0]))>=1){
for ($i = 0; $i < count($city); $i++) {
$city_item_for_check = $city[$i];
$sql = "SELECT field_data_field_birth_date.entity_id
FROM field_data_field_birth_date, field_data_field_city
WHERE(
(field_birth_date_value >= DATE_ADD(NOW(), INTERVAL -{$highest_age} YEAR))
AND
(field_birth_date_value <= DATE_ADD(NOW(), INTERVAL -{$loest_age} YEAR))
AND
(field_city_tid = {$city_item_for_check})
AND
(field_data_field_birth_date.entity_id = field_data_field_city.entity_id))";
if(db_query($sql)->fetchColumn()){
$the_resaults_array[$i] = db_query($sql)->fetchAll();
}
}
for ($d = 1; $d < (count($the_resaults_array)); $d++) {
$user_id = $the_resaults_array[$d];
$sql_user_name .= '<p><strong>'.
db_query("SELECT name FROM {users} WHERE uid = {$user_id}")->fetchColumn()
.'</p></strong>';
}
} else{
$sql = "SELECT field_data_field_birth_date.entity_id
FROM field_data_field_birth_date
WHERE
field_birth_date_value >= DATE_ADD(NOW(), INTERVAL -{$highest_age} YEAR)
AND field_birth_date_value <= DATE_ADD(NOW(), INTERVAL -{$loest_age} YEAR)";
foreach (db_query($sql) as $result) {
$entity_id = $result->entity_id;
$sql_user_id = db_query("SELECT uid FROM {profile} WHERE pid = {$entity_id}")->fetchColumn();
$sql_user_name .= '<p><strong>'.
db_query("SELECT name FROM {users} WHERE uid = {$sql_user_id}")->fetchColumn()
.'</p></strong>';
}}
return $sql_user_name;
}

Pagination. Select from x number of tables

i'm trying to make my second website using php and i'm stuck at some typical problem (i believe),
but very hard for me.
I'm making a page that show list of items depends on GET.
#1 if only "type" sended - show all items with x type.
#2 if only "tag" sended - show all items with x tag.
#3 if "type" and "tag" sended at the same time - show all items with x type and x tag.
problem #1 i solved this way
// items per page
$per_page = 5;
// 1) if isset type
if ( (isset($_GET['type'])) && (!isset($_GET['tag'])) ){
$type_id = get_safe_var($_GET['type']);
$con = mysql_connect(DB_HOST,DB_LOGIN,DB_PASSWORD) or die(mysql_error());
if ($con) {
mysql_select_db(DB_NAME) or die(mysql_error());
$sql = mysql_query("SELECT `item_type`, `item_type_name` FROM `item_types` WHERE `type_id` = '$type_id'");
$row = mysql_fetch_assoc($sql);
$type = $row['item_type'];
$type_name = $row['item_type_name'];
if ($type != ''){
$pages_query = mysql_query("SELECT COUNT(`id`) FROM `".$type."` WHERE `insearch` = '1'");
$number_of_pages = ceil( mysql_result($pages_query, 0) / $per_page );
$current_page = ( (isset($_GET['page'])) && ((int)$_GET['page'] > 0) ) ? (int)$_GET['page'] : 1;
$start = ($current_page - 1) * $per_page;
echo "<h1>$type_name</h1>";
$sql = mysql_query("SELECT `id`, `name`, `img` FROM `".$type."` WHERE `insearch` = '1' ORDER BY `id` DESC LIMIT $start, $per_page");
// echo items
while ($row = mysql_fetch_assoc($sql)){
$id = $row['id'];
$name = $row['name'];
$img = $row['img'];
echo "
<div id='items_cell'>
<img alt='$name' src='$img' width='145' height='200' /><br />
<a href='open_item.php?type=$type_id&id=$id'>$name</a><br />
<em>$type_name</em>
</div>";
}
}
mysql_close($con);
} else {echo 'sql connection error';}
}
pagination
// echo pagination
// 1) if isset type
if ( (isset($_GET['type'])) && (!isset($_GET['tag'])) ){
if ( (isset($number_of_pages)) && ($number_of_pages >= 1) && ($current_page <= $number_of_pages) ){
for ($i = 1; $i <= $number_of_pages; $i++){
if ($i == $current_page){
echo "<li><a href='?type=$type_id&page=$i' class='sel'>$i</a></li>";
} else {
echo "<li><a href='?type=$type_id&page=$i'>$i</a></li>";
}
}
}
}
I'm stuck at problem #2.
I got tag ID. Need to show all items with that tag.
I don't understand how to make a SELECT from x-number of tables with a working paginatin.
database structure -
Any help is welcome!
P.S. Maybe i need to change db structure to make SELECT easier?
You should definitely work on your table design. Having dynamic table names is a big NO-NO as you won't ever be able to do any useful joins. Just create one big tag-table and add a column type like you did in your table item_types.
To solve problems #1-#3 just build the WHERE-part of your query dynamically:
// empty selection
$where = array();
if (!empty($_GET["type"])
$where[] = "`item_type` = '".mysql_real_escape_string($_GET["type"])."'";
if (!empty($_GET["tag"])
$where[] = "`tag` = '".mysql_real_escape_string($_GET["tag"])."'";
$query = "SELECT ... FROM `item`"
// Join type-table
. " JOIN `item_types` ON `item`.`id` = `item_types`.`item_id`"
// Join all of this item's tags
. " JOIN `item_tags` ON `item`.`id` = `item_tags`.`item_id`"
// Filter tags by item_type
. " AND `item_types`.`item_type` = `item_tags`.`item_type`"
;
if (count($where) > 0)
$query .= "WHERE ".implode(" AND ", $where);

Categories