I have a field in a table named startdate and what I would like to do is run as little queries as possible to obtain a list that would display as the following:
2012
January
March
October
2011
September
November
The only dates that I want to show per year are the dates where there is a record for.
Any help or pointers appreciated.
Thanks
This query can be used to find all distinct Year/Month combinations in a table for a given date (here start date).
SELECT YEAR(startdate) AS DYear, MONTH(startdate) AS DMonth
FROM tablename
GROUP BY YEAR(startdate), MONTH(startdate)
After you have your results back in whatever way you choose to get them you can do something like this:
$year = 0;
while ($row) { //loop through your rows here using while or foreach
if($year != $row['DYear']){
echo '<h1>'.$row['DYear'].'</h1>';
$year = $row['DYear'];
}
echo '<ul>';
echo '<li>'.$row['DMonth'].'</li>';
echo '</ul>';
}
select distinct column1, column2, column3... from table where columnx <> "" order by year, month
Using PDO, you could do something like:
$dbh = new PDO("mysql:dbname=$dbname", $username, $password);
$qry = $dbh->query('
SELECT DISTINCT
YEAR(startdate) AS year,
MONTHNAME(startdate) AS month
FROM
my_table
ORDER BY
startdate
');
if ($qry) {
$row = $qry->fetch();
while ($row) {
$current_year = $row['year'];
echo '<h1>',htmlentities($current_year),'</h1><ul>';
do {
echo '<li>',htmlentities($row['month']),'</li>';
} while ($row = $qry->fetch() and $row['year'] == $current_year);
echo '</ul>';
}
}
SELECT DISTINCT YEAR(startdate), MONTHNAME(startdate)
FROM mytable
ORDER BY YEAR(startdate) desc, MONTH(startdate) asc;
should do the trick, however the output will be:
2012 January
2012 March
2012 October
2011 September
2011 November
you can use the code given by eggyal to convert this into a format that you are looking for. Note that you will need to order on MONTH and not MONTHNAME (unless you want alphabetical order)
As other posts have given your answer, I am going to provide information on why these answers work.
In an SQL select statement you can provide keywords. Specifically for MySQL you can provide ALL, DISTINCT, DISTINCTROW(and others unrelated to distinct rows).
The latter two options are actually the same option and yield the same results. The default select statement with no keyword uses ALL which returns all results. By passing in DISTINCT you eliminate any duplicate entries.
A duplicate entry is an entry where all the fields are the same, However, it should be noted that if you have an auto-incrementing primary key each row is distinct from the last as the pk is different. In order to select a distinct value with this kind of setup, you would need to specify a separate column name that is truly distinct.
For more reading on MySQL SELECT statements refer to the users guide's select section.
Hopefully I didn't provide information you have already gathered from the provided answers, but I have always found understanding "why" and "how" often allow me to understand when a particular solution will work, as well as when it won't work.
Related
I'm fetching data with PDO from a table containing 2 fields : comment and date.
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
extract($row);
echo $comment;
echo $date;
}
Which displays a list of all comments.
Now I'm trying to group these comments by month, the main goal is to create some filter menu with a GET value so that only the current month comments are displayed :
<ul>
<li>October 2014</li>
<li>November 2014</li>
<li>December 2014</li>
</ul>
I think I should be fine with the LIKE operator for displaying the results, but what about the menu links generation ?
Main issue : $date is in d/m/Y format, so I have to process before using it :
$created = $date;
$month = $created->format('mY');
Also I can't really know in advance which months are going to be registered in the table, so it have to be "dynamic".
So how do I get a list of every month appearing in the table ? Without redundancy of course. Like
1014
1114
1214
even if there is numerous comments created on October for instance.
You can use MySQL's STR_TO_DATE and DATE_FORMAT functions to return the date in the format you need. For example:
SELECT `comment`, DATE_FORMAT(STR_TO_DATE(`date`, "%d/%m/%Y"), "%m%y") as `date2` FROM `data`
If you need to query all the unique month/year combinations, use DISTINCT:
SELECT DISTINCT DATE_FORMAT(STR_TO_DATE(`date`, "%d/%m/%Y"), "%m%y") as `date2` FROM `data`
Here's a SQL fiddle showing the distinct select.
I have a database of customers and would like to run a query to display how many customers have an active account on a month by month basis.
I already have the following to count how many customers have an expiry date for each month, but can anybody suggest a way to then count those with an expirydate >= now for each month?
<?php
$query = "select count(cid) as num_rows from customers WHERE expirydate LIKE '%-12-%'";
$result = mysql_query($query);
$row = mysql_fetch_object( $result );
$total = $row->num_rows;
echo "December: " .$total;
?>
Simple
mysql_query( "select count(cid) as num_rows from customers WHERE expirydate >= curdate()" );
Try to avoid mysql_* functions due to they are depricated.Instead use mysqli_* functions or PDO statements
The following will tell you have many customers have an expirydate per month for records on or after today.
SELECT
MONTH(expirydate) month, COUNT(cid) as count
FROM
customers
WHERE
DATE(expirydate) >= CURDATE()
GROUP BY MONTH(expirydate)
Do note though that as this groups only by month, records spanning multiple years may be misleading (3 July 2013 and 7 Jul 2014 would both count as July, for example).
You should look into the date and time functions and group by/aggregate functions for more information.
This query show you how much customers has expirydate after now. Correct your date format in STR_TO_DATE function for your case. MySQL STR_TO_DATE
SELECT COUNT(*) as `num_rows`, MONTH(STR_TO_DATE(`expirydate`,'%Y-%m-%d')) as `month`
FROM `customers`
WHERE STR_TO_DATE(`expirydate`,'%Y-%m-%d') > NOW()
GROUP BY `month`
Also try to use timestamp field type in your tables instead of varchar or etc.
I have an sql query that I use to display the news section of my website.
I would really love for the dates to be presented as "2nd January, 2012" however as I am selecting all fields from 5 tables I don't know where to put my formatting requirements (I am not selecting individual fields).
My query is below:
$query_newsheadlines = "
SELECT *
FROM
NewsArticles,
NewsArticleCategories,
NewsArticlePhotos,
NewsCategories,
NewsPhotos
WHERE
NewsArticles.id = NewsArticleCategories.newsArticleID
AND NewsArticles.id = NewsArticlePhotos.newsArticleID
AND NewsArticlePhotos.newsPhotoID = NewsPhotos.id
AND NewsArticleCategories.newsCategoryID = NewsCategories.id
AND NewsCategories.SectionID = 201
ORDER BY NewsArticles.publishDate DESC";
Any ideas would be appreciated :)
update the column my date is located in is NewsArticles.publishDate
you need to specify what column do you want to be formatted (just don't be lazy on specifying the column). Use DATE_FORMAT
SELECT DATE_FORMAT(CURDATE(),'%D %M, %Y')
SQLFiddle Demo
Other Source(s)
DATE_FORMAT()
Okay guys, this probably has an easy answer but has been stumping me for a few hours now.
I am using PHP/HTML to generate a table from a MySQL Table. In the MySQL table (TimeRecords) I have a StartTime and EndTime column. In my SELECT statement I am subtracting the EndTime from the StartTime and aliasing that as TotalHours. Here is my query thus far:
$query = "SELECT *,((EndTime - StartTime)/3600) AS TotalPeriodHours
FROM TimeRecords
WHERE Date
BETWEEN '{$CurrentYear}-{$CurrentMonth}-1'
AND '{$CurrentYear}-{$CurrentMonth}-31'
ORDER BY Date
";
I then loop that through an HTML table. So far so good. What I would like to do is to add up all of the TotalHours and put that into a separate DIV. Any ideas on 1) how to write the select statement and 2) where to call that code from the PHP/HTML?
Thanks in advance!
Try this
$query= "
SELECT ((EndTime - StartTime)/3600) AS Hours, otherFields, ...
FROM TimeRecords
WHERE
Date BETWEEN '{$CurrentYear} - {$CurrentMonth} - 1'
AND '{$CurrentYear}-{$CurrentMonth} - 31' ";
$records =mysql_query($query);
$sum= 0;
while($row=mysql_fetch_array($records))
{
echo"$row['otherFields']";
echo"$row['Hours']";
$sum+=$row['Hours'];
}
echo" Total Hours : $sum ";
Just use a single query with a Sum(). You could also manually calculate it if you're already displaying all rows. (If paginating or using LIMIT, you'll need a separate query like below.)
$query = "
SELECT Sum(((EndTime - StartTime)/3600)) AS SumTotalPeriodHours
FROM TimeRecords
WHERE
Date BETWEEN '{$CurrentYear} - {$CurrentMonth} - 1'
AND '{$CurrentYear}-{$CurrentMonth} - 31'
";
You can do this in the same query if you have a unique id using GROUP BY WITH ROLLUP
$query = "
SELECT unique_id,SUM((EndTime - StartTime)/3600) AS TotalPeriodHours
FROM TimeRecords
WHERE Date BETWEEN '{$CurrentYear}-{$CurrentMonth}-1'
AND '{$CurrentYear}-{$CurrentMonth}-31'
GROUP BY unique_id WITH ROLLUP
ORDER BY Date
";
In this instance the last result from your query with contain NULL and the overall total. If you don't have a unique ID you will need to do it in PHP as per Naveen's answer.
A few comments on your code:
Using SELECT * is not considered good practice. SELECT the columns you need.
Not all months have a day 31 so this may produce unexpected results. If you're using PHP5.3+, you can use
$date = new DateTime();
$endDate = $date->format( 'Y-m-t' );
The "t" flag here gets the last day of that month. See PHP docs for more on DateTime.
I have a mysql database of entries with dates. So what I want is to show all the dates in my database and then under each date, I want to show all the entries in the database entered on the specefic date. I am thinking of two loops but I don't know how to write the condition to display all the dates in my database before I loop out the entries under that date.
Edit: i used NOW() to store the date. Using the loop by longneck, how can ignore the time when checking if date is sameas previous? Should I explode? What's the best way?
you should use one query, sort it by date, and detect the change in the date as a signal to display the next date:
<?php
$sql = 'select start_date, name from events order by start_date';
$res = mysql_query($sql) or die(mysql_error());
$prev_date = null;
while ($row = mysql_fetch_assoc($res)) {
if ($row['start_date'] != $prev_date) {
echo "<h1>{$row['start_date']}</h1>"\n;
$prev_date = $row['start_Date'];
}
echo "<p>{$row['name']}</p>";
}
?>
I'm assuming that you want a list of the dates so that you can then do separate queries for each date's entries. Usually you would use a query like:
SELECT DISTINCT date_field FROM table_name ORDER BY date_field DESC
(this will do it newest-first, remove DESC to make it oldest-first)
Now, you probably don't want to do it this way, because it will require a lot of queries (one for each day's entries). It is more efficient to just order the entries by the date, and then use logic in your php to print out the headers. So you would use code like:
$result = $db->query("SELECT * FROM table_name ORDER BY date_field DESC");
$current_date = "";
while ($row = $result->fetch_array()) {
if ($current_date != $row["date_field"]) {
echo "<h3>{$row['date_field']}</h3>";
$current_date = $row["date_field"];
}
// Print your entry from $row here.
}
you would probably want to get that in your SQL statement: (assuming it is datetime type)
SELECT * FROM table
WHERE date BETWEEN '2009-9-8 00:00:00' AND '2008-9-8
23:59:59'
Then just do your normal loop through your results
Also have a look at the GROUP BY clause of the SELECT statement.