I have the joy of recreating the phone, by building a customized messaging system in PHP that uses an API to send and receive messages.
I'm trying to emulate the functionality found in Facebook messaging on their desktop site.
[Col 1] [Col 2]
A list of the Conversation View.
latest messages
received in order
of Newest to oldest
I am having issues with the Query for the first column.
I currently have a table in MySQL with the following structure:
CREATE TABLE IF NOT EXISTS `History` (
`ID` int(10) NOT NULL AUTO_INCREMENT COMMENT 'MessageID',
`Sender` varchar(10) NOT NULL,
`Recipient` varchar(10) NOT NULL,
`ExtReference` int(20) DEFAULT NULL,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`Status` varchar(100) NOT NULL,
`userid` int(3) NOT NULL,
`Message` longtext NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=609 ;
With a sample Date set like:
INSERT INTO `History` (`ID`, `Sender`, `Recipient`, `ExtReference`, `Date`, `Status`, `userid`, `Message`) VALUES
(1, '0412345678', '0468888888', 33845909, '2013-03-17 04:17:34', '1', 11, 'Just testing....'),
(2, '0412345678', '0400222333', 33845910, '2013-03-17 04:17:35', '1', 11, 'Amazing'),
(3, '0412345678', '0411111111', 33847419, '2013-03-17 04:46:04', '1', 8, 'Nothing here to see'),
(4, '0412345678', '0400222333', 33850155, '2013-03-17 06:31:57', '1', 12, 'Hello there Mr IT Guru :-)'),
(5, '0400222333', '0412345678', 33850179, '2013-03-17 06:33:21', '1', 12, '[Write message here]'),
(6, '0412345678', '0411111111', 33955423, '2013-03-23 01:26:22', '1', 8, 'Hello Charles'),
(7, '0412345678', '0411111111', 33959071, '2013-03-23 03:08:26', '1', 13, 'Sample Message'),
(8, '0400222333', '0412345678', 33964111, '2013-03-23 05:27:51', '1', 13, 'How do I use this system?'),
(9, '0400222333', '0412345678', 34107503, '2013-03-30 03:13:38', '1', 12, 'Is this thing on?'),
(10, '0412345678', '0401411210', 34230869, '2013-03-05 00:18:09', '1', 16, 'Hello')
(In this example my number is: 0412345678).
SQL Fiddle here: http://sqlfiddle.com/#!2/29197/1/0
I have worked out how to get a list of all the unique numbers used across both the Sender and Recipient columns:
SELECT DISTINCT `Sender` AS phoneID FROM `History`
UNION
SELECT DISTINCT `Recipient` AS phoneID FROM `History`
But I can't work how to attach the latest Date and message to this data.
If I focus on either just messages sent to me or sent by me I can get somewhere with these two:
SELECT `ID`, `Sender`, `Recipient`, MAX(`Date`), `Message` FROM History
GROUP BY Sender
ORDER BY `History`.`Date` DESC
or
SELECT `ID`, `Sender`, `Recipient`, MAX(`Date`), `Message`, `Status` FROM History
GROUP BY Recipient
ORDER BY `History`.`Date` DESC
Any thoughts?
I can recreate the History table layout if needed.
I'll also need to try and join the phone number with a persons name in a Contacts table later on down the track.
Thanks
Charlie
Possibly not the best way but you could combine the two queries you have. Something like:
SELECT `ID`, `Sender`, `Recipient`,`Date`,`Message`,`Status` FROM
(
SELECT `ID`, `Sender`, `Recipient`, `Date`, `Message`,`Status` FROM History
WHERE Sender = "0412345678"
GROUP BY Sender
UNION
SELECT `ID`, `Sender`, `Recipient`, MAX(`Date`), `Message`, `Status` FROM History
WHERE Recipient = "0412345678"
GROUP BY Recipient
) res
GROUP BY res.ID
ORDER BY res.Date DESC
Note that this is for a specific number. You could remove the WHERE clauses if this wasn't needed.
Related
This question already has answers here:
Get the latest date from grouped MySQL data
(7 answers)
Closed 1 year ago.
I'm creating a school project where I need to monitor the member's availability based on their loan transactions.
Now the issue here is when a member already makes tons of transactions, my existing query displays all of the transactions which I only wanted the present status based on their latest date requested of a transaction.
I will provide a screenshot of the issue for more visualization.
This is my query as of now:
$query = $this->db->query("
SELECT * FROM `tbl_members`
LEFT JOIN tbl_loanrequests
on tbl_members.member_id = tbl_loanrequests.member_id
");
And here's the useful information:
CREATE TABLE `tbl_members` (
`member_id` int(11) NOT NULL,
`firstname` varchar(250) NOT NULL,
`lastname` varchar(250) NOT NULL,
`middlename` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `tbl_members` (`member_id`, `firstname`, `lastname`, `middlename`) VALUES
(1, 'Maribeth', 'Cunha', ''),
(2, 'Thelma ', 'Rush ', ''),
(3, 'Latoria ', 'Shinn', ''),
(4, 'Quinton ', 'Everman', ''),
(5, 'Robert', 'Evermen', '');
CREATE TABLE `tbl_loanrequests` (
`loanreq_id` int(11) NOT NULL,
`member_id` int(11) NOT NULL,
`loanreq_status` varchar(50) NOT NULL,
`date_requested` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `tbl_loanrequests` (`loanreq_id`, `member_id`, `loanreq_status`, `date_requested`) VALUES
(2, 1, 'Paid', '2021-05-06'),
(3, 2, 'For Release', '2021-05-06'),
(4, 3, 'Pending', '2021-05-06'),
(5, 5, 'Ongoing', '2021-05-06'),
(6, 1, 'Cancelled', '2021-05-07');
http://sqlfiddle.com/#!9/7647a4/1
This is the preview where member_id #1 supposed to be displaying only one status which is the Cancelled since it got the latest date_requested. On the left side, it displays Clear though but that's a way for me to monitor if a member is able to file a loan.
I considered that your loanreq_id is incremented and thus that the highest for each member always contain the highest loanreq date for that member. If not I can adapt
The trick is to determine the highest loanreq_id for each member using a MAX...GROUP BY:
SELECT member_id, MAX(loanreq_id) AS last_loanreq_id
FROM tbl_loanrequests
GROUP BY member_id
You should then join the result of this query to only keep the latest loanreq of each member. Your query becomes :
SELECT m.*, l.*
FROM `tbl_members` m
LEFT JOIN
(
SELECT member_id, MAX(loanreq_id) AS last_loanreq_id
FROM tbl_loanrequests
GROUP BY member_id
) lm ON lm.member_id = m.member_id
LEFT JOIN tbl_loanrequests l on l.loanreq_id = lm.last_loanreq_id
I have two query to get count and sum of rate for unique ip's.
Query one groups by date and query two groups by country
This is the table
DROP TABLE IF EXISTS `stats`;
CREATE TABLE IF NOT EXISTS `stats` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int(5) UNSIGNED NOT NULL,
`country` int(3) UNSIGNED NOT NULL,
`user_ip` int(50) UNSIGNED NOT NULL,
`timestamp` int(10) UNSIGNED NOT NULL,
`rate` int(7) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `stats`
--
INSERT INTO `stats` (`id`, `user_id`, `country`, `user_ip`, `timestamp`, `rate`) VALUES
(1, 1, 1, 1111111111, 1489999983, 15000),
(2, 1, 2, 1111111112, 1489999984, 10000),
(3, 1, 1, 1111111111, 1489999985, 10000),
(4, 1, 1, 1111111111, 1490086333, 10000),
(5, 1, 2, 1111111111, 1490086334, 10000),
(6, 1, 1, 1111111121, 1490086335, 10000);
These are the queries I am using to get data
To get sum of rates based on date I use following query
SELECT COUNT(`user_ip`) AS `count`, SUM(`rate`) AS `rate`, `timestamp`
FROM (
SELECT DISTINCT `user_ip`, `rate`, `timestamp`
FROM `stats`.`stats`
WHERE `user_id`=? `timestamp`>=? AND `timestamp`<=?
GROUP BY DATE(FROM_UNIXTIME(`timestamp`)),`user_ip`
) c
GROUP BY DATE(FROM_UNIXTIME(`timestamp`))
Result
date count rate
20-03-2017 2 25000
21-03-2017 2 20000
To get sum of rates based on country I use following query
SELECT COUNT(`user_ip`) AS `count`, SUM(`rate`) AS `rate`, `timestamp`, `country`
FROM (
SELECT DISTINCT `user_ip`, `rate`, `timestamp`, `country`
FROM `stats`.`stats`
WHERE `user_id`=? `timestamp`>=? AND `timestamp`<=?
GROUP BY DATE(FROM_UNIXTIME(`timestamp`)),`user_ip`
) c
GROUP BY `country`
Result
country count rate
1 3 35000
2 1 10000
Since these two query are nearly same and fetches same rows from table is it possible to get both result from single query instead of two query.
Also please suggest if it can be be done in PHP effectively than MYSQL.
Thanks
Try this in php
$country="";
$groupByCondition="DATE(FROM_UNIXTIME(`timestamp`))";
if(/*BasedOnCountry*/){
$country=", `country`";
$groupByCondition = "`country`";
}
$query= "SELECT COUNT(`user_ip`) AS `count`, SUM(`rate`) AS `rate`, `timestamp`"+ $country +"
FROM (
SELECT DISTINCT `user_ip`, `rate`, `timestamp`"+ $country +"
FROM `stats`.`stats`
WHERE `user_id`=? `timestamp`>=? AND `timestamp`<=?
GROUP BY DATE(FROM_UNIXTIME(`timestamp`)),`user_ip`
) c
GROUP BY "+ $groupByCondition ;
//execute the query and get the results
I need to get unique counts along with country counts and sum rate for every user
I have come up with this basic design for database where uid is user id
DROP TABLE IF EXISTS `stats`;
CREATE TABLE IF NOT EXISTS `stats` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`uid` int(5) UNSIGNED NOT NULL,
`country` int(3) UNSIGNED NOT NULL,
`ip` int(10) UNSIGNED NOT NULL,
`date` int(10) UNSIGNED NOT NULL,
`timestamp` int(10) UNSIGNED NOT NULL,
`rate` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `stats`
(`id`, `uid`, `country`, `ip`, `date`, `timestamp`, `rate`) VALUES
(1, 1, 10, 1111111111, 2222222222, 3333333333, 100),
(2, 1, 10, 1111111112, 2222222222, 3333333333, 100),
(3, 2, 10, 1111111111, 2222222222, 3333333333, 100),
(4, 1, 10, 1111111114, 2222222223, 3333333333, 100),
(5, 1, 11, 1111111112, 2222222223, 3333333333, 100),
(6, 1, 10, 1111111111, 2222222223, 3333333333, 100);
And this is the query I am using to fetch daily counts
$query="
SELECT `uid`,
COUNT(DISTINCT `ip`)AS `count`,
`country`,
SUM(`rate`) AS `sum`,
`date`
FROM `stats`
GROUP BY `uid`, `date`
";
$result=mysqli_query($connection, $query) or trigger_error(mysqli_error($connection), E_USER_ERROR);
while($row = mysqli_fetch_assoc($result)){
echo 'userid:'.$row['uid'].' count:'.$row['count'].' country:'.$row['country'].' sum:'.$row['sum'].' date:'.$row['date'].'<br>';
};
I am getting this result
userid:1 count:2 country:10 sum:200 date:2222222222
userid:1 count:3 country:10 sum:300 date:2222222223
userid:2 count:1 country:10 sum:100 date:2222222222
Expected result
userid:1 count:2 country:10=>2 sum:200 date:2222222222
userid:1 count:3 country:10=>2, 11=>1 sum:300 date:2222222223
userid:2 count:1 country:10=>1 sum:100 date:2222222222
I guess I need something like SELECT DISTINCT country FROM stats to get country counts in main query.
Please see and suggest any possible way to do this.
Thanks
You can use subquery to achieve this:
SELECT
t.uid,
SUM(t.count) AS count,
GROUP_CONCAT(CONCAT(t.country, ' => ', t.views) SEPARATOR ', ') AS country,
SUM(t.sum) as sum,
t.date
FROM (
SELECT
s.uid,
COUNT(DISTINCT s.ip) AS count,
s.country,
COUNT(s.country) as views,
SUM(s.rate)AS sum,
s.date
FROM stats s
GROUP BY uid, date, country
) AS t
GROUP BY
t.uid,
t.date
Also available at sqlfiddle.
SUM needs a column and you gave string 'rate' in it, remove the ' from rate column name try this,
SELECT
COUNT(DISTINCT `ip`)AS `count`,
`country`,
SUM(rate) AS `sum`
FROM `stats`
GROUP BY `uid`, `date`
You will have to add country into the GROUP condition too:
SELECT
COUNT(DISTINCT `ip`) AS `count`,
`country`,
COUNT(`country`) as `countryViewsByUser`, -- added
SUM(`rate`)AS `sum`
FROM
`stats`
GROUP BY
`uid`,
`date`,
`country` -- added
You will just need to add country to your group by clause like below
$query="
SELECT
COUNT(DISTINCT `ip`)AS `count`,
`country`,
COUNT(DISTINCT `country`) AS country_count,
SUM(`rate`) AS `sum`
FROM `stats`
GROUP BY `country`, `uid`, `date`
";
And please you need to move away from mysqli_* functions, and take a look at PDO instead
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`names` varchar(30) NOT NULL,
`matricno` varchar(30) NOT NULL,
`class` varchar(30) NOT NULL,
`scores` varchar(30) NOT NULL,
`subject` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
$con = mysqli_connect("localhost", "root", "1024", "sch_one");
if (!$con) {
echo "Failed to connect to Database". mysqli_error();
}
INSERT INTO `users` (`id`, `names`, `matricno`, `class`, `scores`) VALUES
(1, 'Henry Okon Etim', '15/HCSS/001', 'A', 800),
(2, 'Henry Okon Etim', '15/HCSS/002', 'A', 804),
(3, 'Etim Okon Etim', '15/HCSS/003', 'A', 820),
(4, 'Lavalish Okon Etim', '15/HCSS/004', 'A', 730),
(5, 'Pherema Okon Etim', '15/HCSS/005', 'A', 920),
(6, 'Leman Okon Etim', '15/HCSS/006', 'A', 803),
(7, 'Lema3 Okon Etim', '15/HCSS/007', 'A', 500);
I am on a project that gives students positions based on their final scores.
My problem is how to output positions according to the scores in a as 1st, 2nd, 3rd, 4th, 5th and so on.
Please explanations and codes are welcome. Thanks!
Please try the following code:
SELECT * FROM users ORDER BY scores DESC;
From what I'm understanding you want to pimary keys(1/2/3..) to reflect their position?
That's not what the id's are for, if you want to order them you can just add an order by in your get query.
$result = $mysqli->query("SELECT * FROM users ORDER BY scores desc");
If you really want an index/counter in your select, you could always take a look at ranking in mysql, end result would be something like this:
SET #rank=0;
SELECT #rank:=#rank+1 AS rank, users.* FROM users ORDER BY scores DESC;
I have a table:
CREATE TABLE IF NOT EXISTS `ccu_log` (
`id` int(15) NOT NULL AUTO_INCREMENT,
`ccu` int(10) DEFAULT NULL,
`time` time DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5626 ;
--
-- Dumping data for table `ccu_log`
--
INSERT INTO `ccu_log` (`id`, `ccu`, `time`, `date`) VALUES
(1, 0, '22:27:30', '2015-01-08'),
(2, 0, '22:29:01', '2015-01-08'),
(3, 0, '22:30:31', '2015-01-08'),
(4, 0, '22:32:01', '2015-01-08'),
(5, 3, '22:33:31', '2015-01-08'),
(6, 0, '22:35:01', '2015-01-08'),
(7, 4, '22:36:31', '2015-01-08'),
(8, 8, '22:38:01', '2015-01-09'),
(9, 5, '22:39:31', '2015-01-09'),
(10, 1, '22:41:01', '2015-01-09');
When I want select data with mysql query:
SELECT *
FROM `ccu_log`
WHERE UNIX_TIMESTAMP("date") = UNIX_TIMESTAMP('09-01-2015')
It show all rows from my table. If i user query:
SELECT * FROM `ccu_log` where UNIX_TIMESTAMP(date) = UNIX_TIMESTAMP('09-01-2015')
It doesn't return the expected results.
Any suggestions?
When the field is already of type date, you don't even need to convert to a timestamp for comparison. Just do
SELECT * FROM `ccu_log` WHERE `date`='2015-01-09'
Please try like this,
SELECT * FROM `ccu_log` where DATE_FORMAT(date,"%d-%m-%Y") = '09-01-2015';