Say I have the following table:
CREATE TABLE `table` (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
userid INT UNSIGNED NOT NULL,
reference INT,
`datetime` DATETIME
) Engine=InnoDB;
I want to select from the table, group by the reference and order by DATE, but also order by the latest reference entry?
For example:
reference: 79
datetime: 2011-12-31 00:32:30
reference: 77
datetime: 2011-12-31 00:40:30
reference: 77
datetime: 2011-12-31 00:43:30
reference: 77
datetime: 2011-12-31 00:45:30
reference: 78
datetime: 2011-12-31 00:47:30
They should show in this order: 78, 77 (the 00:45 one), 79
I currently have this as my query:
SELECT *
FROM `table`
WHERE `userid` = '" . mysql_real_escape_string($id) . "'
GROUP BY `reference`
ORDER BY `datetime` DESC
How can I get this query to work? So when a reference which already exists gets another entry, it jumps to the top of the list?
Thank you
Try
SELECT id, userid, reference, MAX(datetime) AS datetime
FROM `table` WHERE `userid` = ID
GROUP BY `reference`
ORDER BY `datetime` DESC
you need to specify all the columns near Group By clause.
SELECT id, userid, reference, MAX(datetime) AS datetime
FROM `table` WHERE `userid` = ID
GROUP BY `id`, `userid`, `reference`
ORDER BY `datetime` DESC
Related
first of all this is my first time posting a question here. If my question is already asked and answered, please provide me with the links to that question because even i don't know how to properly ask this.
so i have a table with records like this.
ID ITEM_ID DATE OUT IN
1 1002 2019-01-20 1 NULL
2 1002 2019-01-22 NULL 2
3 1004 2019-01-23 4 NULL
4 1007 2019-01-23 4 NULL
5 1002 2019-01-24 1 NULL
6 1004 2019-01-26 NULL 13
7 1003 2019-02-03 NULL 35
how can i select it to look it like this in mysql?
ITEM_ID DATE_OUT OUT DATE_IN IN
1002 2019-01-24 1 2019-01-22 2
1003 - - 2019-02-03 35
1004 2019-01-23 4 2019-01-26 13
1007 2019-01-23 4 - -
what i'm trying to do is more like concate from multiple row of same ITEM ID into 1 latest date of IN and latest date of OUT in 1 row
edit : i've add more data set for more clarification of what i'm trying to achieve.
thank you very much to anyone that have been helping me.
SELECT
a.item_id,
b.date AS date_out,
b.out,
a.date AS date_in,
a.in
FROM (SELECT item_id, date, in FROM your_table WHERE in IS NOT NULL) a
INNER JOIN (SELECT item_id, date, out FROM your_table WHERE out IS NOT NULL) b
ON b.item_id= a.item_id
Yoy can try with a left Join
SELECT a.id,a.item_id,b.date as date_out,`b.out` as 'out',a.date_in as date_in,`a.in` as 'in'
from table1 a left join table1 b
on item_id=item_id and `a.in` is not null and `b.out` is not null
If the table is called dta, then this would be:
SELECT dta_out.ID,dta_in.ITEM_ID,dta_out.`DATE` DATE_OUT, dta_out.`OUT`, dta_in.`DATE` DATE_IN, dta_in.`IN` FROM dta dta_in
INNER JOIN dta dta_out
ON dta_in.ITEM_ID=dta_out.ITEM_ID
WHERE NOT dta_in.`IN` IS NULL AND NOT dta_out.`OUT` IS NULL
I used the following table create:
CREATE TABLE `dta` (
`ID` int(11) DEFAULT NULL,
`ITEM_ID` int(11) DEFAULT NULL,
`DATE` date DEFAULT NULL,
`OUT` int(11) DEFAULT NULL,
`IN` int(11) DEFAULT NULL
)
first of all you have your table created wrong, make it like this
CREATE TABLE `your_database_name`.`new_table_name` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`item_id` INT(10) NULL,
`date_in` DATETIME NULL,
`date_out` DATETIME NULL,
`out` INT(10) NULL,
`in` INT(10) NULL,
PRIMARY KEY (`id`));
you should store the dates separately so you can select them more easy, and the query to show what you want is:
SELECT id, item_id, date_out, out, date_in, in from new_table_name;
To select the date you want from your table is going like this:
SELECT ID, ITEM_ID, (SELECT DATE FROM table_name WHERE OUT IS NOT NULL) AS
DATE_OUT, OUT, (SELECT DATE FROM table_name WHERE IN IS NOT NULL) AS DATE_IN, IN
from table_name
this select above is on your specific table with your specific 2 rows, please create the table as i posted at the begining of answer, that will make your life easier(i gave you the select aswell)
You can use this query to fetch the desired result:
SELECT DISTINCT
item_id,
(SELECT max(`date`) FROM items WHERE `out` = 1 AND item_id = 1002) DATE_OUT,
MAX(`OUT`) `OUT`,
(SELECT max(`date`) FROM items WHERE `IN` = 2 AND item_id = 1002) DATE_IN,
MAX(`IN`) `IN`
FROM items
Here is the SQL fiddle
SQL Query
i have made a table for an audit trail.
CREATE TABLE IF NOT EXISTS `audit_trail_timer` (
`_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`remaining_duration` varchar(50) NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`_id`)
)
now i wanted to select a row where the timestamp is the most recent one.
$query = select * from audit_trail_timer where user_id='$id' and timestamp='';
SELECT top 1 * FROM audit_trail_timer WHERE user_id='$id'
ORDER BY TIMESTAMP DESC;
try this
SELECT * FROM audit_trail_timer WHERE user_id='$id'
ORDER BY TIMESTAMP DESC LIMIT 1
try this,
SELECT * FROM audit_trail_timer WHERE user_id='$id'
ORDER BY TIMESTAMP DESC LIMIT 1
Use
SELECT *
FROM audit_trail_timer
WHERE user_id = '$id'
ORDER BY `timestamp` DESC
LIMIT 1
timestamp is reserved keyword
I have a following db table review_vote
review_id | user_id | status | date_added
2 3 good 20130116135259
3 3 normal 20130116145259
4 2 normal 20130116155259
5 2 good 20130116165259
6 2 good 20130116175259
7 1 great 20130116185259
8 3 good 20130117135259
9 3 normal 20130117145259
currently I can get the highest vote by using the following query:
SELECT review_id FROM review_vote GROUP BY review_id HAVING COUNT(*) =
(
SELECT MAX(x.counts) FROM
(
SELECT review_id, COUNT(*) counts FROM review_vote GROUP BY review_id
)x
)
order by date_added desc
but if i need to get highest vote perday how can i modified the code above? Which means if today were 2013-01-16 I need to get highest vote for yesterday 2013-01-15
my attempt to use date_added = CURDATE() is failed.
SQLFIDDLE: http://sqlfiddle.com/#!2/9a2b5/6
Update query:
CREATE TABLE IF NOT EXISTS `review_vote` (
`review_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`status` varchar(100) NOT NULL,
`date_added` varchar(100) NOT NULL,
KEY `review_id` (`review_id`,`user_id`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `review_vote` (`review_id`, `user_id`, `status`, `date_added`) VALUES
(223, 2, 'lame', '20130116195259');
INSERT INTO `review_vote` (`review_id`, `user_id`, `status`, `date_added`) VALUES(222, 2, 'lame', '20130115195259');
Just add this in your where condition:
DATE_FORMAT(date_added, '%Y-%m-%d') = CURDATE()
Updating as per your error
SELECT review_id FROM review_vote AS RV WHERE DATE_FORMAT(RV.date_added, '%Y-%m-%d') = CURDATE()
GROUP BY review_id HAVING COUNT() =
(
SELECT MAX(x.counts) FROM
(
SELECT review_id, COUNT() counts FROM review_vote GROUP BY review_id
)x
)
Please have a look at demo :demo
SELECT review_id
FROM review_vote
WHERE date_added LIKE '20130115%'
GROUP BY review_id
ORDER BY COUNT(*) DESC
LIMIT 1
But really you ought to consider changing your date_added column to an appropriate temporal type, like DATETIME or TIMESTAMP.
Add the following to your WHERE clause:
`date_added` BETWEEN
DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 DAY), '%Y%m%d')
AND DATE_FORMAT(CURDATE(), '%Y%m%d')
Make sure you have an index on date_added!
Documentation for the date functions is all here: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
Life would be easier for you if your date_added column was a native date type.
I use Yii framework to develop a website, I want to know how to get the last 5 images orderd by create_time but not within the same album by using Yii active record and by plain SQL.
here's my albums table:
CREATE TABLE IF NOT EXISTS `tbl_album` (
`album_id` int(11) NOT NULL AUTO_INCREMENT,
`album_name` varchar(45) DEFAULT NULL,
`album_folder_name` int(11) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`create_user_id` int(11) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`update_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`album_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=55 ;
and here's my images table:
CREATE TABLE IF NOT EXISTS `tbl_image` (
`image_id` int(11) NOT NULL AUTO_INCREMENT,
`image_name` varchar(100) DEFAULT NULL,
`image_description` varchar(100) DEFAULT NULL,
`image_album_id` int(11) NOT NULL,
`create_time` datetime DEFAULT NULL,
`create_user_id` int(11) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`update_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`image_id`),
KEY `fk_image_album` (`image_album_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
please note that I use "create_time" for sorting images.
Again, I need a query to get the last 5 images orderd by create_time but not within the same album by Yii active record and plain SQL.
for example the last 7 images are:
a.jpg in the album 7
b.jpg in the album 5
c.jpg in the album 7
d.jpg in the album 6
e.jpg in the album 3
f.jpg in the album 4
g.jpg in the album 2
h.jpg in the album 1
I need the query result to be like the following:
a.jpg in album 7
b.jpg in album 5
d.jpg in album 6
e.jpg in album 3
f.jpg in album 4
not like the following:
a.jpg in album 7
b.jpg in album 5
c.jpg in album 7
d.jpg in album 6
e.jpg in album 3
Thanks in advance.
Try this:
SELECT
a.album_name,
i1.image_name
FROM tbl_album a
INNER JOIN tbl_image i1 ON i1.image_album_id = a.album_id
INNER JOIN
(
SELECT image_album_id, MIN(image_id) image_id
FROM tbl_image
GROUP BY image_album_id
) i2 ON i2.image_album_id = i1.image_album_id
AND i1.image_id = i2.image_id
ORDER BY a.album_name DESC
LIMIT 5;
The JOIN with:
SELECT image_album_id, MIN(image_id) image_id
FROM tbl_image
GROUP BY image_album_id
will insure that for each album, the first image will be returned. Therefore you will got only one image for each album, then LIMIT 5 will limit the result set to be only 5 albums.
SQL Fiddle Demo
Note that: The ORDER BY clause will determine which five albums will be returned by the LIMIT 5 clause. So don't expect that the albums are returned in the way they are stored as the expected result in your question, because records in the table has no specific order. They are stored as a set, and you have to specify an ORDER BY clause in your query to get them in a specific order.
Update: IF you are looking for the last created image for each album, use the MAX(creaet_time) instead like so:
SELECT
a.album_name,
i1.image_name,
date_format(i1.create_time, '%Y-%m-%d') create_time
FROM tbl_album a
INNER JOIN tbl_image i1 ON i1.image_album_id = a.album_id
INNER JOIN
(
SELECT image_album_id, MAX(create_time) LatestCreateTime
FROM tbl_image
GROUP BY image_album_id
) i2 ON i2.image_album_id = i1.image_album_id
AND i1.create_time = i2.LatestCreateTime
ORDER BY i1.create_time DESC
LIMIT 5;
Updated SQL Fiddle Demo
Update 2: For the duplicate values, use the DISTINCT keyword, or you can use the MAX(image_id) instead, since the image_id is autoincremental, like so:
SELECT
a.album_name,
i1.image_name,
date_format(i1.create_time, '%Y-%m-%d') create_time
FROM tbl_album a
INNER JOIN tbl_image i1 ON i1.image_album_id = a.album_id
INNER JOIN
(
SELECT image_album_id, MAX(image_id) LatestId
FROM tbl_image
GROUP BY image_album_id
) i2 ON i2.image_album_id = i1.image_album_id
AND i1.image_id = i2.LatestId
ORDER BY i1.create_time DESC
LIMIT 5;
Updated SQL Fiddle Demo
I find another solution to my question!
SELECT *
FROM tbl_image
WHERE image_id IN (SELECT MAX(image_id)
FROM tbl_image
GROUP BY image_album_id)
ORDER BY create_time DESC
LIMIT 5;
It gives me the same result, Without use inner join which reduce performance,
What your opinion about this solution?
SQL Fiddle
Try this and let me know what it returns,
select m.image_name,a.album_name
from tbl_album a inner join
tbl_image m on a.album_id=m.image_id
group by m.image_name,a.album_name
order by 2 LIMIT 5
I have a seemingly simple task but I cannot seem to find an elegant solution using 1 query...
Problem:
I have a table of recorded 'clicks' on 'posts', where each post is part of a 'category'.
I want to find the 16 highest clicked posts in the last 30 days -- but I want to avoid duplicate categories.
It seems very simple actually, but I seem to be stuck.
I know how to get the most clicked in last 30, but I can't figure out how to avoid duplicate cats.
SELECT cat_id,
post_id,
COUNT(post_id) AS click_counter
FROM cs_coupon_clicks
WHERE time_of_click > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY post_id
ORDER BY click_counter DESC
I tried to get creative/hacky with it... it's close but not correct:
SELECT cat_id,
Max(sort) AS sortid
FROM (SELECT cat_id,
post_id,
COUNT(post_id) AS click_counter,
CONCAT(COUNT(post_id), '-', post_id) AS sort
FROM cs_coupon_clicks
WHERE time_of_click > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY cat_id, post_id) t1
GROUP BY cat_id
ORDER BY cat_id ASC
Any help would be greatly appreciated as I am not really a MySQL expert. I may end up just doing some PHP logic in the end, but I am very curious as to the correct way to approach a problem like this.
Thanks guys.
EDIT (structure):
CREATE TABLE `cs_coupon_clicks` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`src` varchar(255) NOT NULL DEFAULT '',
`cat_id` int(20) NOT NULL,
`post_id` int(20) NOT NULL,
`tag_id` int(20) NOT NULL,
`user_id` int(20) DEFAULT NULL,
`ip_address` char(30) DEFAULT NULL,
`referer` varchar(255) NOT NULL,
`browser` varchar(10) DEFAULT NULL,
`server_var` text NOT NULL,
`time_of_click` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `cat_id` (`cat_id`),
KEY `post_id` (`post_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
TEMP WORKING SOLUTION (HACKY):
SELECT
cat_id,
MAX(sort) AS sortid
FROM (
SELECT
cat_id,
post_id,
COUNT(post_id) AS click_counter,
RIGHT(Concat('00000000', COUNT(post_id), '-', post_id), 16) AS SORT
FROM cs_coupon_clicks
WHERE time_of_click > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY cat_id, post_id
) AS t1
GROUP BY cat_id
ORDER BY sortid DESC
There is no easy single query solution to this problem, it's a group-wise maximum kind of problem based on a temporary table (the one with counts) that would require self-joins.
Assuming your database grows big enough (otherwise just go for your php logic) I would go for a statistics table, holding info about categories, posts and click counts:
CREATE TABLE `click_cnts` (
`cat_id` int(20) NOT NULL,
`post_id` int(20) NOT NULL,
`clicks` int(20) NOT NULL,
PRIMARY KEY (`cat_id`,`post_id`),
KEY `cat_id` (`cat_id`,`clicks`)
)
and fill it using the same query as the first one in the question:
INSERT INTO click_cnts(cat_id, post_id, clicks)
SELECT cat_id, post_id, COUNT(post_id) AS click_counter
FROM cs_coupon_clicks
WHERE time_of_click > NOW() - INTERVAL 30 DAY
GROUP BY cat_id,post_id
You could update this table using triggers or running update query periodically (do users really need info up to the very last second? probably not...) and save a lot of processing as finding most clicks for each category on indexed table requires a lot less time using a classic group-wise max approach:
SELECT cg.cat_id, cu.post_id, cg.most_clicks
FROM
( SELECT cat_id, max(clicks) as most_clicks FROM click_cnts
GROUP BY cat_id ) cg
JOIN click_cnts cu
ON cg.cat_id = cu.cat_id
AND cu.post_id = ( SELECT cc.post_id FROM click_cnts cc
WHERE cc.cat_id = cg.cat_id
AND cc.clicks = cg.most_clicks
LIMIT 1 )
ORDER BY cg.most_clicks DESC
LIMIT 16
Shot in the dark here. Did you try Select DISTINCT cat_id