MySQL Group By get title column with smallest date value - mysql

I have a query like:
SELECT *
FROM table
GROUP BY sid
ORDER BY datestart desc
LIMIT 10
which returns the last 10 sid groups.
For each of these groups, I need the title column of the row with the lowest datestart value
I tried using
SELECT *, min(datestart)
but that didn't return the row with the smallest datestart value, just the lowest datestart. I need the title from the lowest datestart.
(Relevant) Table Structure:
CREATE TABLE `table` (
`title` varchar(1000) NOT NULL,
`datestart` timestamp NOT NULL default CURRENT_TIMESTAMP,
`sid` bigint(12) unsigned NOT NULL,
KEY `datestart` (`datestart`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Any ideas?

Updated answer
select t1.* from `table` as t1
inner join (
select sid,min(datestart) as elder
from `table`
group by sid
order by elder desc limit 10) as t2
on t1.sid = t2.sid and t1.datestart = t2.elder
Use a composite index on (sid,datestart)

Try this query. You will get expected results. If it don't work change Table_2.datestart > Table_1.datestart by Table_2.datestart < Table_1.datestart
SELECT title, datestart
FROM `table` AS Table_1
LEFT JOIN `table` AS Table_2 ON (Table_2.sid = Table_1.sid AND Table_2.datestart > Table_1.datestart)
Table_2.sid IS NULL;
Edited query
SELECT Table_1.title, Table_1.datestart
FROM `table` AS Table_1
LEFT JOIN `table` AS Table_2 ON (Table_2.sid = Table_1.sid AND Table_2.datestart > Table_1.datestart)
Table_2.sid IS NULL;

Related

how to implement two aggregate functions on the same column mysql

SELECT max(sum(`orderquantity`)), `medicinename`
FROM `orerdetails`
WHERE `OID`=
(
SELECT `OrderID`
FROM `order`
where `VID` = 5 AND `OrerResponse` = 1
)
GROUP BY `medicinename`
i want to get the max of the result(sum of the order quantity) but it gives error any soultion to solve this
You don't need Max() here. Instead sort your recordset by that Sum('orderquantity') descending, and take the first record returned:
SELECT sum(`orderquantity`) as sumoforderqty, `medicinename`
FROM `orerdetails`
WHERE `OID`=
(
SELECT `OrderID`
FROM `order`
where `VID` = 5 AND `OrerResponse` = 1
)
GROUP BY `medicinename`
ORDER BY sumoforderqty DESC
LIMIT 1

Delete child records if the count exceeds 10

I have a parent-child relation for the following tables:
CREATE TABLE `pages` (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NULL,
PRIMARY KEY ( id )
)
CREATE TABLE `pageObjects` (
id INT NOT NULL AUTO_INCREMENT,
object TEXT NULL,
lastChanged TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL,
fkPageId int NOT NULL,
PRIMARY KEY ( id )
)
The pages have a one:many relation with pageObjects.
Whenever the pageObjects records connected to a single page exceed 10, all records that are edited furthest in the past and exceeding the 10 must be deleted.
I wanted to do this in a single query, but I can't seem to figure this out...
This is how far I've gotten:
DELETE
FROM pageObjects
WHERE id NOT IN (
SELECT po.id, po.fkPageId FROM (
SELECT objects.fkPageId FROM (
SELECT COUNT(*) as count, fkPageId
FROM pageObjects
GROUP BY fkPageId
) objects
WHERE count > 10
) AS page
JOIN pageObjects po
ON page.fkPageId = po.fkPageId
AND po.lastChanged < (
SELECT MIN(lastChanged )
FROM pageObjects
WHERE fkPageId = po.fkPageId
GROUP BY fkPageId
ORDER BY lastChanged DESC
LIMIT 10
)
)
Sadly, the LIMIT bit in the bottom sub-query is not working the way I want to, because the MIN() function should be applied AFTER the LIMIT is applied.
So I tried that:
DELETE
FROM pageObjects
WHERE id NOT IN (
SELECT po.id, po.fkPageId FROM (
SELECT objects.fkPageId FROM (
SELECT COUNT(*) as count, fkPageId
FROM pageObjects
GROUP BY fkPageId
) objects
WHERE count > 10
) AS page
JOIN pageObjects po
ON page.fkPageId = po.fkPageId
AND po.lastChanged < (
SELECT MIN(lastChanged)
FROM (
SELECT lastChanged
FROM pageObjects
WHERE fkPageId = po.fkPageId
GROUP BY fkPageId
ORDER BY lastChanged DESC
LIMIT 10
)
)
)
But this is not possible, because the po.fkPageId is not available in the sub-query of the sub-query.
Is there any way to do this like this?
You can do this quite simply by counting the number of later entries for each id:
DELETE FROM pageObjects
WHERE id IN (
SELECT id FROM pageObjects po
WHERE (
SELECT count(id)
FROM pageObjects po2
WHERE po2.fkPageId = po.fkPageId
AND po2.lastChanged > po.lastChanged
) > 10
)
Check out what the select returns here:
http://www.sqlfiddle.com/#!9/f5218f/1/0

Load top 5 records per date

I have a table, in which there are date wise quiz score of different users. I want to load top 5 scorers for every date.
Table sample create statement:
CREATE TABLE `subscriber_score` (
`msisdn` varchar(25) COLLATE utf8_unicode_ci NOT NULL,
`date` date NOT NULL,
`score` int(11) NOT NULL DEFAULT '0',
`total_questions_sent` int(11) NOT NULL DEFAULT '0',
`total_correct_answers` int(11) NOT NULL DEFAULT '0',
`total_wrong_answers` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`msisdn`,`date`),
KEY `fk_subscriber_score_subscriber1` (`msisdn`),
CONSTRAINT `fk_subscriber_score_subscriber1` FOREIGN KEY (`msisdn`) REFERENCES `subscriber` (`msisdn`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query which I have tried:
SELECT subscriber.msisdn AS msisdn,subscriber.name AS name,subscriber.gender AS gender,tmp2.score AS score,tmp2.date AS winning_date
FROM subscriber,
(SELECT msisdn,tmp.date,tmp.score
FROM subscriber_score,
(SELECT date,MAX(score) AS score
FROM subscriber_score
WHERE date > '2014-10-10' AND date < '2014-11-10' GROUP BY date)
tmp
WHERE subscriber_score.date=tmp.date AND subscriber_score.score=tmp.score)
tmp2
WHERE subscriber.msisdn=tmp2.msisdn ORDER BY winning_date
Actual output: Only one top scorer for every date is shown.
Wanted Output Top 5(or say 10) records for every date are required.
I think you can do this using variables to assign each row a row number, then filter the top 5 for each date.
SELECT s.name AS name,
s.gender AS gender,
s.msisdn,
ss.date,
ss.score
FROM ( SELECT ss.msisdn,
ss.score,
#r:= CASE WHEN ss.Date = #d THEN #r + 1 ELSE 1 END AS RowNum,
#d:= ss.date AS winning_date
FROM subscriber_score AS ss
CROSS JOIN (SELECT #d:= '', #r:= 0) AS v
WHERE ss.date > '2014-10-10'
AND ss.date < '2014-11-10'
ORDER BY ss.Date, ss.Score DESC
) AS ss
INNER JOIN Subscriber AS s
ON s.msisdn = ss.msisdn
WHERE ss.RowNum <= 5;
Example on SQL Fiddle
refer this query its not complete but hope it helps
SELECT SCORE
FROM table
WHERE date='somedate'
ORDER BY SCORE DESC LIMIT 5
select bc.msisdn msisdn,bc.name name,bc.gender gender,ab.score score,ab.date winning_date
(
select msisdn,date,score,
dense_rank() over (partition by date order by score desc) rnk
from subscriber_score
) ab,subscriber bc
where bc.msisdn=ab.msisdn and ab.rnk<=5
order by winning_date ;
This is how you can get solution of your problem in oracle sql.
try below
SELECT subscriber.msisdn AS msisdn,subscriber.name AS name,subscriber.gender AS gender,tmp2.score AS score,tmp2.date AS winning_date
FROM subscriber inner join
(select msisdn,date, score, ROW_NUMBER() OVER(PARTITION BY date ORDER BY score DESC) AS Row
FROM subscriber_score
WHERE date > '2014-10-10' AND date < '2014-11-10' GROUP BY date)
tmp
on subscriber.msisdn=tmp.msisdn and tmp.row<=5

MySQL multiple COUNTs

I have a table like this:
Fiddle: http://sqlfiddle.com/#!2/44d9e/14
CREATE TABLE IF NOT EXISTS `mytable` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(20) NOT NULL,
`money_earned` int(20) NOT NULL,
PRIMARY KEY (`id`)
) ;
INSERT INTO mytable (user_id,money_earned) VALUES ("111","10");
INSERT INTO mytable (user_id,money_earned) VALUES ("111","6");
INSERT INTO mytable (user_id,money_earned) VALUES ("111","40");
INSERT INTO mytable (user_id,money_earned) VALUES ("222","45");
INSERT INTO mytable (user_id,money_earned) VALUES ("222","1");
INSERT INTO mytable (user_id,money_earned) VALUES ("333","5");
INSERT INTO mytable (user_id,money_earned) VALUES ("333","19");
I need to know table has how many rows, how many different users, and how many times each user has earned.
I need this result:
TOTAL_ROWS: 7
TOTAL_INDIVIDUAL_USERS: 3
USER_ID USER_TIMES
111 3
222 2
333 2
Is your problem that you want the total as well? If so, then you can get this using rollup:
SELECT coalesce(cast(user_id as char(20)), 'TOTAL USER_TIMES'),
COUNT(*) as times
FROM mytable
GROUP BY user_id with rollup;
You can get the user counts in a separate column with this trick:
SELECT coalesce(cast(user_id as char(20)), 'TOTAL USER_TIMES'),
COUNT(*) as times, count(distinct user_id) as UserCount
FROM mytable
GROUP BY user_id with rollup;
You realize that a SQL query just returns a table of values. You are asking for very specific formatting, which is typically done better at the application level. That said, you can get close to what you want with something like this:
select user, times
from ((SELECT 3 as ord, cast(user_id as char(20)) as user, COUNT(*) as times
FROM mytable
GROUP BY user_id
)
union all
(select 1, 'Total User Count', count(*)
from mytable
)
union all
(select 2, 'Total Users', count(distinct user_id)
from mytable
)
) t
order by ord;
I think this could be a typo anyway your are trying to sum your COUNT() times, simply replace with money_earned
SELECT user_id,
COUNT(*) AS 'times',
SUM(money_earned) AS 'sum_money'
FROM mytable GROUP BY user_id;
SQL Fiddle

need select from two fields, unique in first based on highest of second

I have a table with three fields, an ID, a Date(string), and an INT. like this.
+---------------------------
+BH|2012-09-01|56789
+BH|2011-09-01|56765
+BH|2010-08-01|67866
+CH|2012-09-01|58789
+CH|2011-09-01|56795
+CH|2010-08-01|67866
+DH|2012-09-01|52789
+DH|2011-09-01|56665
+DH|2010-08-01|67866
I need to essentially for each ID, i need to return only the row with the highest Date string. From this example, my results would need to be.
+---------------------------
+BH|2012-09-01|56789
+CH|2012-09-01|58789
+DH|2012-09-01|52789
SELECT t.id, t.date_column, t.int_column
FROM YourTable t
INNER JOIN (SELECT id, MAX(date_column) AS MaxDate
FROM YourTable
GROUP BY id) q
ON t.id = q.id
AND t.date_column = q.MaxDate
SELECT id, date, int
FROM ( SELECT id, date, int
FROM table_name
ORDER BY date DESC) AS h
GROUP BY id
Replace table_name and columns to the right ones.
Assuming the following structure:
CREATE TABLE `stackoverflow`.`table_10357817` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Date` datetime NOT NULL,
`Number` int(11) NOT NULL,
`Code` char(2) NOT NULL,
PRIMARY KEY (`Id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1
The following query will wield the expected results:
SELECT Code, Date, Number
FROM table_10357817
GROUP BY Code
HAVING Date = MAX(Date)
The GROUP BY forces a single result per Code (you called it id) and the HAVING clauses returns only the data where it matches the max date per code/id.
Update
Used the following data script:
INSERT INTO table_10357817
(Code, Date, Number)
VALUES
('BH', '2012-09-01', 56789),
('BH', '2011-09-01', 56765),
('BH', '2010-08-01', 67866),
('CH', '2012-09-01', 58789),
('CH', '2011-09-01', 56795),
('CH', '2010-08-01', 67866),
('DH', '2012-09-01', 52789),
('DH', '2011-09-01', 56665),
('DH', '2010-08-01', 67866)