I have a columns that has the time stamp when a row is created.
I need to find a way to get all the rows from the same 'day', and give each row a display number to show something like this:
+---------------------+
| order_date | // output should be:
+---------------------+
| 2016-05-11 13:01:41 | // 2016051101
| 2016-05-11 15:54:14 | // 2016051102
| 2016-05-11 17:16:18 | // 2016051103
| 2016-05-11 17:35:12 | // 2016051104
| 2016-05-11 17:55:16 | // 2016051105
| 2016-05-12 07:16:48 | // 2016051201
| 2016-05-12 09:30:57 | // 2016051202
| 2016-05-12 09:56:19 | // 2016051203
| 2016-05-13 11:27:21 | // 2016051301
| 2016-05-14 10:15:56 | // 2016051401
| 2016-05-15 11:35:07 | // 2016051501
| 2016-05-15 11:39:48 | // 2016051502
| 2016-05-15 11:40:12 | // 2016051503
+---------------------+
Can Mysql do this? or should the program, like php, handle this?
Final query I use:
SELECT t.order_date,
concat(
DATE_FORMAT(t.order_date, '%Y%m%d'),
LPAD(
(SELECT COUNT(*) FROM hz_order s WHERE s.order_date<= t.order_date AND DATE(s.order_date) = DATE(t.order_date)),
2,
0))display
FROM hz_order t
ORDER BY `display` ASC
Yes, you can do it with a correlated query, like this:
SELECT t.order_date,
concat(DATE_FORMAT(t.order_date, '%Y%m%d'),
(SELECT COUNT(*) FROM YourTable s
WHERE s.order_date<= t.order_date
AND DATE(s.order_date) = DATE(t.order_date)))
FROM YourTable t
This will generate the date as yyyymmdd+the count.
Yes, You can do this by -
SELECT CONCAT(DATE_FORMAT(date_field, '%Y%m%d'),
LPAD(COUNT(date_field), 2, '0'))
FROM table_name
GROUP BY DATE(date_field)
ORDER BY date_field DESC
DATE_FORMAT(date_field, '%Y%m%d') would format the date like yyyymmdd.
LPAD(COUNT(date_field), 2, '0') would generate a string with left padding (with 0) to 2 places with the count of that date.
Here's one way using MySQL. Other methods will be faster on larger data sets.
SELECT x.*
, CONCAT(DATE_FORMAT(x.order_date,'%Y%m%d'),LPAD(COUNT(*),2,0))oi
FROM my_table x
JOIN my_table y
ON DATE(y.order_date) = DATE(x.order_date)
AND y.order_date <= x.order_date
GROUP
BY x.order_date;
Related
I have a table that contains too many records and each bunch of records belong to someone:
---------------------
id | data | username
---------------------
1 | 10 | ali
2 | 11 | ali
3 | 12 | ali
4 | 20 | omid
5 | 21 | omid
6 | 30 | reza
now I want to create a query to result me like this:
1-10-ali
4-20-omid
6-30-reza
2-11-ali
5-21-omid
3-12-ali
Is there anyway to create a query to result me one record per each username and then one from another, and another to the end?
Unfortunately MySQL doesn't have a ranking system so you can use UDV (user defined variables) to rank your records like so.
SELECT id, `data`, name
FROM
( SELECT
id, `data`, name,
#rank := if(#name = name, #rank + 1, 1) as rank,
#name := name
FROM test
CROSS JOIN (SELECT #rank := 1, #name := '') temp
ORDER BY name, `data`
) t
ORDER BY t.rank, t.name, t.data
Sql Fiddle to play with
Output:
+---------------------+
| id | data | name |
+-----+------+--------+
| 1 | 10 | ali |
+---------------------+
| 4 | 20 | omid |
+---------------------+
| 6 | 30 | reza |
+---------------------+
| 2 | 11 | ali |
+---------------------+
| 5 | 21 | omid |
+---------------------+
| 3 | 12 | ali |
+---------------------+
The classic SQL approach is a self join and grouping that lets you determine a row's ranking position by counting the number of rows that come before it. As this is probably slower I doubt I could talk you out of the proprietary method but I mention it to give you an alternative.
select t.id, min(t.`data`), min(t.username)
from test t inner join test t2
on t2.username = t.username and t2.id <= t.id
group by t.id
order by count(*), min(t.username)
Your example would work with
SELECT id, `data`, name
FROM tbl
ORDER BY `data` % 10,
username
`data`;
If data and username do not have the desired pattern, then improve on the example.
I am comparing two datetime in the SQL statement. This is done in PHP.
$result=mysqli_query($con,"SELECT
*
FROM
join
WHERE
join_date <= '$last_join_dates'
ORDER BY
join_date DESC LIMIT 3 OFFSET 3");
$last_join_dates gets update every time, so that I use offset to keep pulling in new data. However, comparing the date is not actually working.
Inside database: structure join_date looks like 2015-10-24 13:30:22 and it is a datetime type.
$last_join_datesI use is the exact same format 2015-10-26 08:23:22.
Since that doesn't work.. I tried the following to convert them.
TRIED FORMAT() the datetime, but does not work:
$result=mysqli_query($con,"SELECT
*
FROM
join
WHERE
FORMAT(join_date, 'yyyyMMddhhmmss') <= FORMAT($last_join_dates, 'yyyyMMddhhmmss')
ORDER BY
join_date DESC LIMIT 3 OFFSET 3");
TRIED Convert() the datetime, but doesn't seem to work either:
$result=mysqli_query($con,"SELECT
*
FROM
join
WHERE
REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(19), CONVERT(DATETIME, join_date, 112), 126), '-', ''), 'T', ''), ':', '') <= REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(19), CONVERT(DATETIME, $last_join_dates, 112), 126), '-', ''), 'T', ''), ':', '')
ORDER BY
join_date DESC LIMIT 3 OFFSET 3");
I'm not sure how to debug this.. Any suggestions?
well #1, JOIN is a mysql keyword so you need to either put back-ticks around it or better yet call your table something else
#2, this wouldn't be the reason it isn't working, but you should never use string interpolation like that, it is vulnerable to sql injection. Instead use $last_join_date as a bind variable: Bind variables in a mysql_query statement
The SQL you have above is correct, as seen below:
mysql> select * from test order by the_date;
+----+---------------------+
| id | the_date |
+----+---------------------+
| 1 | 2015-01-02 11:23:21 |
| 2 | 2015-01-03 12:23:21 |
| 3 | 2015-02-03 12:25:21 |
| 4 | 2015-02-05 12:25:21 |
| 5 | 2015-02-05 15:25:21 |
| 6 | 2015-02-05 15:37:21 |
| 7 | 2015-02-05 20:37:21 |
| 8 | 2015-02-05 20:37:40 |
| 9 | 2015-03-05 20:37:40 |
| 10 | 2015-03-06 20:37:40 |
+----+---------------------+
10 rows in set (0.00 sec)
mysql> select * from test where the_date <= '2015-02-10 01:12:24' order by the_date desc limit 3, 3;
+----+---------------------+
| id | the_date |
+----+---------------------+
| 5 | 2015-02-05 15:25:21 |
| 4 | 2015-02-05 12:25:21 |
| 3 | 2015-02-03 12:25:21 |
+----+---------------------+
3 rows in set (0.00 sec)
So try naming the table something else or use backticks "`". Also try running the query from the mysql command line. Maybe the data you have isn't what you thought but the query is working fine.
Try this one:
"SELECT * FROM join WHERE join_date <= '".date("Y-m-d H:i:s", strtotime($last_join_dates))."'ORDER BY join_date DESC LIMIT 3 OFFSET 3"
It converts $last_join_dates to a timestamp using strtotime, then the date function will convert it to the proper format.
Try this:
$result=mysqli_query($con,"SELECT
*
FROM
join
WHERE
UNIX_TIMESTAMP(join_date) <= '" . strtotime($last_join_dates) . "'
ORDER BY
join_date DESC LIMIT 3 OFFSET 3");
How can I get the latest data of a specific day in MySQL?
Let's assume that I have a column of dates recorded on my database
dates | time | value
---------------------------------------------
2015-08-05 | 11:03:02 | 200
2015-08-05 | 23:04:22 | 2400
2015-08-07 | 8:00:22 | 500
2015-08-08 | 13:00:11 | 400
2015-08-08 | 13:23:11 | 200
2015-08-09 | 17:00:23 | 2200
2015-08-09 | 17:06:00 | 1290
2015-08-09 | 19:22:00 | 900
2015-08-13 | 01:01:22 | 1010
I want to get the latest data or transaction of a specific date, my desired result would be like this
dates | time | value
---------------------------------------------
2015-08-05 | 23:04:22 | 2400
2015-08-07 | 8:00:22 | 500
2015-08-08 | 13:23:11 | 200
2015-08-09 | 19:22:00 | 900
2015-08-13 | 01:01:22 | 1010
Only the latest data of a spefic or distinct date is chosen, what is the possible query with this?
You need to do this way to get that for each dates
select t1.dates,t1.time,t1.value from table as t1 inner join
(
select dates,max(time) as time from table group by dates
) as t2 on t1.dates=t2.dates and t1.time=t2.time
Use
SELECT * FROM TABLE_NAME GROUP BY dates ORDER BY time desc LIMIT 1;
Or
SELECT * FROM TABLE_NAME GROUP BY dates HAVING time <= '23:59:59' LIMIT 1;
Try this:
SELECT `dates`, MAX(`time`) AS `time`, MAX(`value`) AS `value`
FROM `tbl_name`
GROUP BY `dates`
ORDER BY `dates` ASC
Try this query:
SELECT * FROM `table` GROUP BY dates ORDER BY time DESC;
This may be a little confusing but please bear with me. Here's the thing:
I have a database that contains ~1000 records, as the following table illustrates:
+------+----------+----------+
| id | date | amount |
+------+----------+----------+
| 0001 | 14/01/15 | 100 |
+------+----------+----------+
| 0002 | 14/02/04 | 358 |
+------+----------+----------+
| 0003 | 14/05/08 | 1125 |
+------+----------+----------+
What I want to do is this:
Retrieve all the records beginning at 2014 and until yesterday:
WHERE `date` > '14-01-01' AND `date` < CURDATE()
But also get the sum of amount up to the current date, this is:
WHERE `date` < CURDATE()
I've already got this working by just selecting all the records based on the second condition, getting the sum, and then excluding those which don't match the first condition. Something like this:
SELECT `id`, `date`, `amount` FROM `table`
WHERE `date` < CURDATE()
And then:
$rows = fetchAll($PDOStatement);
foreach($rows as $row) {
$sum += $row->amount;
if (
strtotime($row->date) > strtotime('14-01-01') &&
strtotime($row->date) < strtotime(date('Y-m-d'))
) {
$valid_rows[] = $row;
}
}
unset $rows;
Is there a way to achieve this in a single query, efficiently? Would a transaction be more efficient than sorting out the records in PHP? This has to be SQL-standard compliant (I'll be doing this on MySQL and SQLite).
Update:
It doesn't matter if the result ends up being something like this:
+------+----------+----------+-----+
| id | date | amount | sum |
+------+----------+----------+-----+
| 0001 | 14/01/15 | 100 | 458 |
+------+----------+----------+-----+
| 0002 | 14/02/04 | 358 | 458 |
+------+----------+----------+-----+
| 0003 | 14/05/08 | 1125 | 458 |
+------+----------+----------+-----+
The worst case would be when the resulting set ends up being the same as the set that gives the sum (in this case appending the sum would be irrelevant and would cause an overhead), but for any other regular cases the bandwith save would be huge.
You can create a special record with your sum and add it at the end of your first query
SELECT * FROM `table` WHERE `date` > '14-01-01' AND `date` < CURDATE()
UNION
SELECT 9999, CURDATE(), SUM(`amount`) FROM `table` WHERE `date` < CURDATE()
Then you will have all your desired record and the record with id 9999 or whatever is your sum
This could be achieved by correlated subquery, something like below:
SELECT *, (SELECT SUM(amount) FROM t WHERE t.date < t1.date) AS PrevAmount
FROM t AS t1
WHERE `date` > '14-01-01' AND `date` < CURDATE()
However it is very unefficient if the number of records is large.
It's hackish, but:
> select * from foo;
+------+------+
| id | val |
+------+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
+------+------+
5 rows in set (0.02 sec)
> select * from foo
left join (
select sum(val)
from foo
where id < 3
) AS bar ON 1=1
where id < 4;
+------+------+----------+
| id | val | sum(val) |
+------+------+----------+
| 1 | 1 | 3 |
| 2 | 2 | 3 |
| 3 | 3 | 3 |
+------+------+----------+
Basically, do your summing in a joined subquery. That'll attach the sum result to every row in the outer table's results. You'll waste a bit of bandwidth sending that duplicated value out with every row, but it does get you the results in a "single" query.
EDIT:
You can get the SUM using a LEFT OUTER JOIN.
SELECT t1.`id`, t1.`date`, t2.sum_amount
FROM
`table` t1
LEFT OUTER JOIN
(
SELECT SUM(`amount`) sum_amount
FROM `table`
WHERE `date` < CURDATE()
) t2
ON 1 = 1
WHERE t1.`date` > STR_TO_DATE('01,1,2014','%d,%m,%Y') AND t1.`date` < CURDATE();
This will do what you want it to do...optimizing the subquery is the real challenge:
SELECT id,date,amount,(SELECT SUM(amount) FROM table) AS total_amount
FROM table
WHERE date BETWEEN '14-01-01' AND DATE_ADD(CURDATE(), INTERVAL -1 DAY)
how to get all the record from Mysql by supplying month in the query?
i am working in php project and i have a mysql table for posts in which all the posts are saved with their dates(not the publish date or post date but any random date).
now i am selecting the month from the front end and querying for the posts for the given month.
how to retrieve the posts that are in between that month ?
You could use MySQL's MONTH() function
SELECT * FROM tbl WHERE MONTH( date_col ) = 3
You can use MONTHName() function to check the data with the name of month you selected rom front-end.
SELECT * FROM tablename WHERE MONTHNAME(date_column) = "March"
you can fire this query
Select * from table where Date =>'$date1' and Date = '$date2'
to find data between any two dates
you can add where condition as
WHERE YEAR(col_name_of_date) = 2014 AND MONTH(Date) = 4";
or
WHERE YEAR(col_name_of_date) = YEAR(now()) AND MONTH(Date) = 4";
This will need the column col_name_of_date to be in DATE or DATETIME type.
Also you should avoid this kind of DATE() function since its a load to the mysql server.
Its better to construct the date parameter on PHP side before u pass them to query. If you
know the moth start and end and can easily construct the start and end date in Y-m-d format. For the start date d is always 01 and for the end date its the last day of the month.
Check how the query behaves using DATE() and without date
I have a table users where regdate is not indexed
explain select count(*) from users where year(regdate) = year(now()) and month(regdate) = 01 ;
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 79309 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
As u can see num of rows it may scan is the upper limit of the table.
Now lets add an index
mysql> alter table users add index `u_regdate_idx`(`regdate`) ;
Query OK, 79309 rows affected (1.44 sec)
Records: 79309 Duplicates: 0 Warnings: 0
Now run the same again
mysql> explain select count(*) from users where year(regdate) = year(now()) and month(regdate) = 01 ;
+----+-------------+-------+-------+---------------+---------------+---------+------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+-------+--------------------------+
| 1 | SIMPLE | users | index | NULL | u_regdate_idx | 4 | NULL | 79309 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------------+---------+------+-------+--------------------------+
As u can see there is no change in the performance.
Now lets change the query and see
mysql> explain select count(*) from users where regdate between '2014-01-01' AND '2014-01-31' ;
+----+-------------+-------+-------+---------------+---------------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+--------------------------+
| 1 | SIMPLE | users | range | u_regdate_idx | u_regdate_idx | 4 | NULL | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+--------------------------+
Now u can see its far better.