MYSQL Select group by order by - mysql

i have this table:
messages
/*Table structure for table `messages` */
CREATE TABLE `messages` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`fromperson` varchar(255) NOT NULL,
`sent` datetime(6) NOT NULL,
`msgread` int(2) DEFAULT 0,
`content` text DEFAULT NULL,
`toperson` varchar(255) NOT NULL,
`route` int(2) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=75508 DEFAULT CHARSET=utf8mb4;
/*Data for the table `messages` */
insert into `messages`(`id`,`fromperson`,`sent`,`msgread`,`content`,`toperson`,`route`) values
(75477,'jaritje','2020-07-31 11:47:59.000000',1,'helemaal niks :)','anaisje',0),
(75478,'jaritje','2020-07-31 11:48:25.000000',1,'wdj','anaisje',1),
(75479,'jaritje','2020-05-25 12:57:27.000000',1,'cv','anaisje',0),
(75501,'jaritje','2020-05-25 13:38:31.000000',1,'gmj*','anaisje',1),
(75502,'jaritje','2020-05-25 13:38:48.000000',1,'gm','anaisje',1),
(75503,'jaritje','2020-05-26 16:53:27.000000',1,'hgh','anaisje',0),
(75504,'jaritje','2020-05-26 17:05:27.000000',1,'hey\r\n','anaisje',1),
(75505,'jaritje','2020-05-26 18:14:03.000000',1,'hallo','anaisje',0),
(75507,'jaritje','2020-07-22 12:57:27.000000',1,'TEST ','saartje',1);
Now i want to select every most recent message with every person.
So the most recent message with "anaisje" and with "saartje".
So i want the rows with id 75478 and 75507.
I read on the internet that
SELECT * FROM (SELECT * FROM messages ORDER BY sent DESC) AS person WHERE fromperson = ?
should work, but it doesn't for me...
Anyone can help me with this?
Thanks in advance,
Jari

To get the most recent row of data by sender and receiver, you can use a self join as follows:
select *
from messages msg
where sent = (select max(sent)
from messages msg_
where msg_.fromperson = msg.fromperson
and msg_.toperson = msg.toperson)
See how it works in this Fiddle

Related

Mysql Multiple statements different conditions

I have a mysql table:
CREATE TABLE `templates_assignments` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` int(11) NOT NULL DEFAULT '2'
`assignment_id` int(11) NOT NULL DEFAULT '1',
`template_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `template_id` (`template_id`),
) ENGINE=InnoDB AUTO_INCREMENT=122 DEFAULT CHARSET=latin1;
/*Data for the table `templates_assignments` */
insert into `templates_assignments`
(`id`,`type`,`assignment_id`,`template_id`)
values
(15,1,1,1),
(16,1,1,2),
(19,1,1,6),
(54,2,30,6),
(55,1,5,11),
(56,1,5,15),
(57,1,5,22);
I want to select the template that qualifies for both conditions:
type=2 AND assignment_id=30
type=1 AND assignment_id=1
the only template_id that should come back is 6, but i keep getting all or none.
My query condition was something like:
WHERE
(
(templatesAssignments.type=2 AND templatesAssignments.assignment_id=30) AND (templatesAssignments.type=1 AND templatesAssignments.assignment_id=1)
)
But no luck...what am i missing?
SELECT ta1.template_id
FROM templatesAssignments ta1
INNER JOIN templatesAssignments ta2 ON ta1.template_id = ta2.template_id
WHERE (ta1.type=1 AND ta1.assignment_id=1)
AND (ta2.type=2 AND ta2.assignment_id=30)
select template_id
from templatesAssignments
group by template_id
having sum(type=2 AND assignment_id=30) > 0
and sum(type=1 AND assignment_id=1) > 0

JOIN LEFT with multiple conditions

I'm having following tables structure
CREATE TABLE IF NOT EXISTS `review_author` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`email` varchar(255) NOT NULL,
`client_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_37D99F0819EB6921` (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2110 ;
AND
CREATE TABLE IF NOT EXISTS `brokers_comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hb_broker_id` int(11) NOT NULL,
`client_id` int(11) DEFAULT NULL,
`user_name` varchar(100) NOT NULL,
`user_email` varchar(100) NOT NULL,
`state` int(11) NOT NULL DEFAULT '0',
`text` varchar(3000) NOT NULL,
PRIMARY KEY (`id`),
KEY `IDX_5365DFFB9FE55EF7` (`hb_broker_id`),
KEY `IDX_5365DFFB19EB6921` (`client_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1583 ;
Before extracting value i did following query:
INSERT INTO review_author (
name,
email,
client_id
)
SELECT
brokers_comments.user_name,
brokers_comments.user_email,
brokers_comments.client_id
FROM brokers_comments
LEFT JOIN review_author
ON brokers_comments.user_name=review_author.name AND
brokers_comments.user_email=review_author.email AND
brokers_comments.client_id=review_author.client_id
WHERE review_author.id IS NULL
Not in review_author should be all author from table brokers_comments and now i'm trying to get authors id using following query:
SELECT
review_author.id
FROM brokers_comments
LEFT JOIN review_author
ON brokers_comments.user_name=review_author.name AND
brokers_comments.user_email=review_author.email AND
brokers_comments.client_id=review_author.client_id
WHERE review_author.id IS NOT NULL
but i'm getting about 110 results from total 1531 records from table brokers_comments.
UPDATE
I couldn't manage to insert data in http://sqlfiddle.com/ so following link are dump for two tables review_author and brokers_comments.
Again my issue is to transfer distinct columns(user_name, user_email, client_id) from table brokers_comments to table review_author and then select review_author.id based on relation name/email/client_id from both tables.
http://wrttn.in/7ca325
http://wrttn.in/3a7885
Insert new author was wrong and made duplication. Below is new correct form.
INSERT INTO review_author (
name,
email,
client_id
)
SELECT user_name, user_email, client_id
FROM brokers_comments AS broker
WHERE NOT EXISTS
(
SELECT 1
FROM review_author AS author
WHERE author.email = broker.user_email
)
GROUP BY broker.user_email
P.S. I somebody will make a working online mysql database please put in comments so i could put it there.
Resolved
Only now i realised that user_email must be unique. Based on this i made following select statement:
SELECT
author.id
FROM brokers_comments AS broker
LEFT JOIN review_author AS author
ON broker.user_email = author.email
It seems you use excess fields in JOIN clause since client_id is a key, you need to join tables only on this field. Possible cause of that you getting not same number of records is different name/email for same client_id in those two tables. So, your two queries should be like this:
INSERT INTO review_author (
name,
email,
client_id
)
SELECT
brokers_comments.user_name,
brokers_comments.user_email,
brokers_comments.client_id
FROM brokers_comments
LEFT JOIN review_author
ON brokers_comments.client_id=review_author.client_id
WHERE review_author.id IS NULL
and
SELECT
review_author.id
FROM brokers_comments
LEFT JOIN review_author
ON brokers_comments.client_id=review_author.client_id
WHERE review_author.id IS NOT NULL

How to INNER JOIN around a loop of tables

I have four tables as follows:
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
CREATE TABLE IF NOT EXISTS `categories_friends` (
`category_id` int(10) unsigned NOT NULL,
`friend_id` int(10) unsigned NOT NULL,
UNIQUE KEY `category_id` (`friend_id`,`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `friends` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`friend_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`,`friend_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
CREATE TABLE IF NOT EXISTS `ratings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`title` varchar(255) NOT NULL,
`description` text NOT NULL,
`rating` tinyint(2) unsigned NOT NULL,
`public` tinyint(1) NOT NULL DEFAULT '0',
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
I am trying to perform the following query on those tables:
SELECT *
FROM `favred`.`ratings` AS `Rating`
INNER JOIN `favred`.`friends` AS `JFriend`
ON (`JFriend`.`friend_id` = `Rating`.`user_id`)
INNER JOIN `favred`.`categories_friends` AS `JCategoriesFriend`
ON (`JCategoriesFriend`.`category_id` = `Rating`.`category_id`
AND `JCategoriesFriend`.`friend_id` = `JFriend`.`id`)
INNER JOIN `favred`.`categories` AS `JCategory`
ON (`JCategory`.`id` = `Rating`.`category_id`
AND `JCategory`.`id` = `JCategoriesFriend`.`category_id`)
WHERE `JFriend`.`user_id` = 1
AND `Rating`.`user_id` <> 1
AND `JCategory`.`id` IN (4, 14)
GROUP BY `Rating`.`id`
The query above is not working, as it returns no results (although there is data in the tables that should return), what I'm trying to do is to find all the Ratings that were not authored by me (ID:1), but were authored by my Friends, but only if I've selected to view a specific Category for that Friend, with the resulting set being filtered by a given set of specific Categories.
The INNER JOINs loop around through Rating --> Friend --> CategoriesFreind --> Category --> back to Rating.
If I remove the additional portion of the INNER JOIN's ON clauses as follows:
SELECT *
FROM `favred`.`ratings` AS `Rating`
INNER JOIN `favred`.`friends` AS `JFriend`
ON (`JFriend`.`friend_id` = `Rating`.`user_id`)
INNER JOIN `favred`.`categories_friends` AS `JCategoriesFriend`
ON (`JCategoriesFriend`.`friend_id` = `JFriend`.`id`)
INNER JOIN `favred`.`categories` AS `JCategory`
ON (`JCategory`.`id` = `JCategoriesFriend`.`category_id`)
WHERE `JFriend`.`user_id` = 1
AND `Rating`.`user_id` <> 1
AND `JCategory`.`id` IN (4, 14)
GROUP BY `Rating`.`id`
then the query will return results, but because the INNER JOIN joining the CategoriesFriend to the Rating is not being filtered by the 'JCategory'.'id' IN (4, 14) clause, it returns all Ratings by that friend instead of filtered as it should be.
Any suggestions on how to modify my query to get it to pull the filtered results?
And I'm using CakePHP, so a query that would fit into it's unique query format would be preferred although not required.
first ,why are you use the JFriend.id, does it mean something,or is it as the same as user_id?
try this one,the same logic but it's from top to bottom ,I feel:
SELECT * FROM categories as JCategory
INNER JOIN categories_friends as JCategoriesFriend ON JCategoriesFriend.category_id = JCategory.id
INNER JOIN friends AS JFriend ON JFriend.friend_id = JCategoriesFriend.friend_id
INNER JOIN ratings AS Rating ON Rating.user_id = JFriend.friend_id
WHERE JCategory.id IN (4,14) AND JFriend.user_id = 1 AND Rating.user_id <> 1 GROUP BY Rating.id
I got one result from all the data that I made for the testing.
if it does not work also,try make some correct data,maybe the data is not right...
the testing data below:
categories: id | name (14| 141414)
categories_friends: category_id| friend_id (14| 2)
friends: id | user_id | friend_id (4| 1| 2)
ratings: id | user_id | category_id | title (2| 2| 14 | 'haha')
So I wondered if the INNER JOINs were being a little too limiting and specific in their ON clauses. So I thought that maybe a LEFT JOIN would work better...
SELECT *
FROM `favred`.`ratings` AS `Rating`
INNER JOIN `favred`.`friends` AS `JFriend`
ON (`JFriend`.`friend_id` = `Rating`.`user_id`)
LEFT JOIN `favred`.`categories_friends` AS `JCategoriesFriend`
ON (`JCategoriesFriend`.`friend_id` = `JFriend`.`id`
AND `JCategoriesFriend`.`category_id` = `Rating`.`category_id`)
WHERE `JFriend`.`user_id` = 1
AND `JRatingsUser`.`id` IS NULL
AND `Rating`.`user_id` <> 1
GROUP BY `Rating`.`id`
That query worked for me.
I did away with linking to the categories table directly, and linked indirectly through the categories_friends table which sped up the query a little bit, and everything is working great.

group conversation by users mysql select for messages

Table:
CREATE TABLE `messages` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`from_user_id` int(11) unsigned NOT NULL,
`to_user_id` int(11) unsigned NOT NULL,
`seen` tinyint(1) NOT NULL DEFAULT '0',
`sent` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`message` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `messages` (`id`, `from_user_id`, `to_user_id`, `seen`, `sent`, `message`)
VALUES
(1,2,1,0,'2013-11-06 11:05:42','Hello!'),
(2,1,2,0,'2013-11-06 11:05:52','Hello you too!'),
(3,3,1,0,'2013-11-06 11:06:08','Whats up?'),
(4,1,3,0,'2013-11-06 11:06:27','Not much');
I would put this in sqlfiddle but it is down for me, I cannot access it last 32 hours.
I've searched SO and found several related topics, but with different grouping requirements so I could not apply them to my project.
For the query, I know current user id and target user id, and based on this I want query to return all conversation of these two users ordered by date.
I was thinking something like:
SELECT message FROM messages WHERE from_user_id = 1 OR to_user_id = 1 [but where do I limit this query to target user 3?]
In other words I want to select:
(3,3,1,0,'2013-11-06 11:06:08','Whats up?')
(4,1,3,0,'2013-11-06 11:06:27','Not much')
For user 1, conversation with user 3. All of it.
SELECT message FROM messages
WHERE 1 in (from_user_id,to_user_id) and 3 in (from_user_id,to_user_id)

mySql subtract row of different table

I want to subtract between two rows of different table:
I have created a view called leave_taken and table called leave_balance.
I want this result from both table:
leave_taken.COUNT(*) - leave_balance.balance
and group by leave_type_id_leave_type
Code of both table
-----------------View Leave_Taken-----------
CREATE ALGORITHM = UNDEFINED DEFINER=`1`#`localhost` SQL SECURITY DEFINER
VIEW `leave_taken`
AS
select
`leave`.`staff_leave_application_staff_id_staff` AS `staff_leave_application_staff_id_staff`,
`leave`.`leave_type_id_leave_type` AS `leave_type_id_leave_type`,
count(0) AS `COUNT(*)`
from
(
`leave`
join `staff` on((`staff`.`id_staff` = `leave`.`staff_leave_application_staff_id_staff`))
)
where (`leave`.`active` = 1)
group by `leave`.`leave_type_id_leave_type`;
----------------Table leave_balance----------
CREATE TABLE IF NOT EXISTS `leave_balance` (
`id_leave_balance` int(11) NOT NULL AUTO_INCREMENT,
`staff_id_staff` int(11) NOT NULL,
`leave_type_id_leave_type` int(11) NOT NULL,
`balance` int(3) NOT NULL,
`date_added` date NOT NULL,
PRIMARY KEY (`id_leave_balance`),
UNIQUE KEY `id_leave_balance_UNIQUE` (`id_leave_balance`),
KEY `fk_leave_balance_staff1` (`staff_id_staff`),
KEY `fk_leave_balance_leave_type1` (`leave_type_id_leave_type`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
------- Table leave ----------
CREATE TABLE IF NOT EXISTS `leave` (
`id_leave` int(11) NOT NULL AUTO_INCREMENT,
`staff_leave_application_id_staff_leave_application` int(11) NOT NULL,
`staff_leave_application_staff_id_staff` int(11) NOT NULL,
`leave_type_id_leave_type` int(11) NOT NULL,
`date` date NOT NULL,
`active` int(11) NOT NULL DEFAULT '1',
`date_updated` date NOT NULL,
PRIMARY KEY (`id_leave`,`staff_leave_application_id_staff_leave_application`,`staff_leave_application_staff_id_staff`),
KEY `fk_table1_leave_type1` (`leave_type_id_leave_type`),
KEY `fk_table1_staff_leave_application1` (`staff_leave_application_id_staff_leave_application`,`staff_leave_application_staff_id_staff`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=32 ;
Well, I still don't think you've provided enough information. It would be very helpful to have some sample data and your expected output (in tabular format). That said, I may have something you can start working with. This query finds all staff members, calculates their current leave (grouped by type), and determines the difference between that and their balance by leave type. Take a look at it, and more importantly (perhaps) the sqlfiddle here that I used which has the sample data in it (very important to determining if this is the correct path for your data).
SELECT
staff.id_staff,
staff.name,
COUNT(`leave`.id_leave) AS leave_count,
leave_balance.balance,
(COUNT(`leave`.id_leave) - leave_balance.balance) AS leave_difference,
`leave`.leave_type_id_leave_type AS leave_type
FROM
staff
JOIN `leave` ON staff.id_staff = `leave`.staff_leave_application_staff_id_staff
JOIN leave_balance ON
(
staff.id_staff = leave_balance.staff_id_staff
AND `leave`.leave_type_id_leave_type = leave_balance.leave_type_id_leave_type
)
WHERE
`leave`.active = 1
GROUP BY
staff.id_staff, leave_type;
Good luck!