SQL Query to get most frequently visited place Laravel - mysql

I developed project at Laravel 5.2. I have database structure like this :
user_visited
id | user_id | latitude | longitude
01 | 1 | 140.5938388 | 36.3335513
02 | 1 | 140.2631739 | 36.3724621
03 | 1 | 140.0804782 | 36.083233
04 | 1 | 140.0855777 | 36.1048973
05 | 1 | 140.2215081 | 35.981243
06 | 1 | 140.577927 | 36.3114456
07 | 1 | 140.65826 | 36.6068145
08 | 1 | 140.109301 | 36.0865606
09 | 1 | 140.2055252 | 35.926693
10 | 1 | 139.7540075 | 36.1662458
11 | 1 | 140.2637594 | 36.241148
12 | 1 | 139.8043185 | 36.1115211
13 | 1 | 140.2183821 | 36.0601167
14 | 1 | 139.7540075 | 36.1662458
15 | 1 | 140.0309725 | 36.0381176
lcoations
id | Location name | Type | Address | Latitude | Longitude
31 | Murse Park | Theme Park | 552-18 | 140.6066128 | 36.3985857
32 | Dom Park | Theme Park | 552-12 | 140.6417064 | 36.5436575
33 | Football Park | Theme Park | 588-1 | 140.3690094 | 36.4195418
34 | Istanbul Park | Theme Park | 37 | 140.3330587 | 36.5449685
This is user's location history that get from mobile app that get location information every n seconds.
And from user's visited location history I want to know which place that users most frequently visited. How to do that?
The fact is, user can visit same location, but the longitude and latitude isn't perfect same.
Maybe we must set radius for 500 mill or what?
How to query that?

answering so that someone might get help.
According to Geo location, we can consider a place same if its latitude and longitude are similar at 5 to 6 precision.
Let's say if lat and long of a place are (140.5938388,36.3335513) and a user visits a place with lat and long (140.59383723,36.33355213) then by querying with precision of 5 i.e (140.59383,36.33355) we get the same block where your location exists and taking count of those places/locations will give you the frequently visited places.
Edited:
SELECT count(location_name) FROM locations
LEFT JOIN user_visited ON TRUNCATE(user_visited.latitude,5) = TRUNCATE(locations.latitude,5) AND TRUNCATE(user_visited.longitude,5) = TRUNCATE(locations.longitude,5)
WHERE user_visited.user_id = 1

Related

Conditionally move MySQL data between rows in same table

Working in Redmine, I need to copy(not move) data from certain rows to other rows based on matching project id numbers with time entries.
I have included a diagram of the table "custom_values" and my understanding of the design below(CURRENT DATA):
+----+-----------------+---------------+-----------------+-------+
| id | customized_type | customized_id | custom_field_id | value |
+----+-----------------+---------------+-----------------+-------+
| 1 | Project | 1 | 1 | 01 |
| 2 | TimeEntry | 1 | 4 | 01 |
| 3 | Project | 2 | 1 | 02 |
| 4 | TimeEntry | 2 | 4 | 02 |
| 5 | Project | 3 | 1 | 03 |
| 6 | TimeEntry | 3 | 4 | |
| 7 | Project | 4 | 1 | 04 |
| 8 | TimeEntry | 4 | 4 | |
+----+-----------------+---------------+-----------------+-------+
At the risk of oversimplifying,
"id" = The primary key for each entry in custom_values
"customized_type" = Specifies which db table the row is referring to.
"customized_id" = Specifies the primary key for the db table entry previously specified in "customized_type".
"custom_field_id" = Specifies which custom field the row is referring to. Redmine admins can arbitrarily add and remove custom fields.
"value" = The data contained within the custom field specified by
"custom_field_id"
In my situation, the values listed in "value" are representing unique customer id numbers. The customer id numbers did not always get entered with each time entry. I need to copy the customer numbers from the project rows to the matching time entry rows. Each time entry has a project_id field.
So far, here is my mangled SQL query:
SELECT
custom_field_id,
custom_values.value AS 'CUSTOMER_NUMBER',
custom_values.customized_id AS 'PROJECT_ID_NUMBER',
custom_values.customized_type,
time_entries.comments AS 'TIME_ENTRY_COMMENTS'
FROM
redmine_tweaking.custom_values
LEFT JOIN
redmine_tweaking.time_entries ON custom_values.customized_id = time_entries.project_id
WHERE
custom_values.customized_type='Project' AND custom_values.custom_field_id=1;
The query I have so far allows me to see that I have the time entries connected properly to their matching projects, but that is all I have been able to figure out. So in other words, this SQL statement does not exactly solve my problem.
Plus, even if it did work, I think the way I laid it out looks like 200 lbs of bird poop. There must be a better/more optimized way to do this.
Any help would be greatly appreciated. I am relatively new and I have been pouring hours into solving this problem.
UPDATE:
Ok, here is the time_entries table:
+----+------------+---------+----------+-------+----------+-------------+------------+-------+--------+-------+---------------------+---------------------+
| id | project_id | user_id | issue_id | hours | comments | activity_id | spent_on | tyear | tmonth | tweek | created_on | updated_on |
+----+------------+---------+----------+-------+----------+-------------+------------+-------+--------+-------+---------------------+---------------------+
| 1 | 1 | 1 | 1 | .25 | test | 9 | 2015-11-04 | 2015 | 11 | 45 | 2015-11-04 08:18:12 | 2015-11-04 10:18:12 |
| 2 | 2 | 1 | 1 | .25 | test2 | 9 | 2015-11-04 | 2015 | 11 | 45 | 2015-11-04 09:18:12 | 2015-11-04 12:18:12 |
+----+------------+---------+----------+-------+----------+-------------+------------+-------+--------+-------+---------------------+---------------------+
As opposed to the original table that I first posted, the expected output would show this:
+----+-----------------+---------------+-----------------+-------+
| id | customized_type | customized_id | custom_field_id | value |
+----+-----------------+---------------+-----------------+-------+
| 1 | Project | 1 | 1 | 01 |
| 2 | TimeEntry | 1 | 4 | 01 |
| 3 | Project | 2 | 1 | 02 |
| 4 | TimeEntry | 2 | 4 | 02 |
| 5 | Project | 3 | 1 | 03 |
| 6 | TimeEntry | 3 | 4 | 03 |
| 7 | Project | 4 | 1 | 04 |
| 8 | TimeEntry | 4 | 4 | 04 |
+----+-----------------+---------------+-----------------+-------+

Filter duplicates combining multiple columns

Example table
| name | year | latitude | longitude |
|--------------|------|----------|-----------|
| Cleveland | 1800 | 10 | 11 |
| Cleveland | 1810 | 10 | 11 |
| Medina | 1811 | 12 | 13 |
| Dayton | 1812 | 14 | 15 |
| Sandusky | 1105 | 50 | 50 |
| Mount Vernon | 1813 | 50 | 50 |
What I'm aiming to do
I want to select each unique combinations of latitude and longitude. So I want to filter out any duplicate pairs. I also need to filter out any records whose year is less than 1500.
This is the subset I'm trying to achieve:
| name | year | latitude | longitude |
|--------------|------|----------|-----------|
| Cleveland | 1800 | 10 | 11 |
| Medina | 1811 | 12 | 13 |
| Dayton | 1812 | 14 | 15 |
| Mount Vernon | 1813 | 50 | 50 |
Each records year is greater than 1500 and there aren't any duplicate lat,long pairs.
What I've tried
I've tried to find a way to use DISTINCT. Nothing I've found has worked.
I also have tried using GROUP BY:
SELECT *
FROM users
GROUP BY latitude, longitude
HAVING year > 1500;
The issue with the above query is that is eliminates both of the following records which contain the lat,long pair of 50,50:
| name | year | latitude | longitude |
|--------------|------|----------|-----------|
| Sandusky | 1105 | 50 | 50 |
| Mount Vernon | 1813 | 50 | 50 |
The group is eliminated because Sandusky's year is less than 1500. I don't want Sandusky's record, but I do want Mount Vernon.
I noticed that if if the two records where switched like so:
| name | year | latitude | longitude |
|--------------|------|----------|-----------|
| Mount Vernon | 1813 | 50 | 50 |
| Sandusky | 1105 | 50 | 50 |
...then the group's year is set as 1813 and the group is not eliminated. I thought maybe sorting by year would fix it, but it didn't:
SELECT *
FROM users
GROUP BY latitude, longitude
HAVING year > 1500
ORDER BY year DESC;
Is what I'm attempting possible?
How about this?
SELECT `id`, `name`, MAX(users.year) as `year`, latitude, longitude
FROM users
WHERE year > 1500
GROUP BY latitude, longitude;
Results in:
| 7 | Columbus | 1978 | 7 | 8
| 1 | Cleveland | 1800 | 10 | 11
| 3 | Medina | 1811 | 12 | 13
| 4 | Dayton | 1812 | 14 | 15
| 6 | Mount Vernon | 1813 | 50 | 50
The only difference is where the WHERE/HAVING is, because it is before the GROUP BY statement, it will do the filtering BEFORE the grouping happens and thus you get the desired result.
The MAX(users.year)ensure that you always get the largest year on the set. If this doesn't matter to you, you can replace SELECT `id`, `name`, MAX(users.year) as `year`, latitude, longitude with SELECT *
Maybe I didn't understand the problem, but it would be this simple:
select * from users u where u.year > 1500;
I don't know what you want to do in case there are more than one pair of the same coordinates with a year greater than 1500.
How about this unless it is a misread. I did read. It makes assumptions like you want to not eliminate a different name with same lat,long
create table users
( id int auto_increment primary key,
name varchar(50) not null,
year int not null,
latitude int not null,
longitude int not null
);
truncate table users;
insert users (name,year,latitude,longitude) values
('Cleveland',1810,10,11),
('Medina',1811,12,13),
('Dayton',1812,14,15),
('Mount Vernon',1813,50,50),
('Sandusky',1105,50,50);
SELECT distinct name,year,latitude,longitude
FROM users
where year > 1500
ORDER BY year;
+--------------+------+----------+-----------+
| name | year | latitude | longitude |
+--------------+------+----------+-----------+
| Cleveland | 1810 | 10 | 11 |
| Medina | 1811 | 12 | 13 |
| Dayton | 1812 | 14 | 15 |
| Mount Vernon | 1813 | 50 | 50 |
+--------------+------+----------+-----------+

Mysql how to find cumulative total by group

Can anyone help me to sort this out pleaase. i have a episode table and for an episode there will be following appointments . Episode table will be like
+-------------+------------+------------+------------+----------------+------+
| Episode_id | Patientid | St_date | End_date | Status | ... |
+-------------+------------+------------+------------+----------------+------+
| 61112345 | 100001 | 12-01-2010 | | Active | |
| 61112346 | xxxxxx | 20-01-2010 | 10-10-2011 | Withdrawn | |
| ......... | xxxxxxxx | 30-01-2010 | 10-05-2011 | Lost to follow | |
| ......... | xxxxxxxx | 01-02-2011 | Active | Active | |
+-------------+------------+------------+------------+----------------+------+
Status field holds the status of each episode.A episode has 6 appointments , 3 months per appointment. so totally an episode has 18 months . some patient may complete all 6 appointment , some may withdraw in the middle, or some will be lost to follow up. i need to create a dashboard .
Appointment table will have fields for
Appointment_id
PatientId
...
Stats // Completed or pending, which is used for reporting
For example if a patient complete 2 appointment and if he is marked as Withdrawn on episdode which means that he has withdrawn from 3rd visit and active for 2 visits, if we lost to follow him on 5th app, then he will be active for 4app and then he will be added to lost to follow up on 5th visit. if he completes all then he will added to active for all 6 visits. and the report should be like
Report from 01-01-2010 to 31-12-2010
+--------+--------+-------------+----------------+---------+
| | Active | Withdrawn | Lost to follow | Revised |
+------- +--------+-------------+----------------+---------+
| visit1 | 1500 | 30 | 5 | 5 |
| Visit2 | 1800 | 20 | 4 | 3 |
| Visit3 | 1900 | 45 | 3 | 2 |
| Visit4 | 1800 | 34 | 0 | 1 |
| Visit5 | 1900 | 30 | 0 | 1 |
| Visit6 | 1200 | 20 | 0 | 5 |
+--------+--------+-------------+----------------+---------+
Currently we are fetching the query and using loop only we are generating reports like this, but it is taking time to process, is there any way i can achieve using query itself.
It isn't really clear what you want to group by, but I can give you a general answer. After your where clause you can add "group by fieldname order by fieldname" where fieldname is the element you want to count or sum. You can then count(fieldname) or sum(fieldname) to either add or count.
This may be helpful: http://www.artfulsoftware.com/infotree/qrytip.php?id=105

How to Query a Table with Multiple Foreign Keys and Return Actual Values

New to MySQL, so please bear with me.
I'm working on a project that collects user's degrees. Users can save 3 degrees where the type, subject matter, and school are variable. These relations are normalized for other query uses so 5 tables are involved and are shown below (all have more columns then shown, just included the relevant info). The last one, 'user_degrees' is where the keys come together.
degrees
+----+-------------------+
| id | degree_type |
+----+-------------------+
| 01 | Bachelor's Degree |
| 02 | Master's Degree |
| 03 | Ph.D. |
| 04 | J.D. |
+----+-------------------+
acad_category
+------+-----------------------------------------+
| id | acad_cat_name |
+------+-----------------------------------------+
| 0015 | Accounting |
| 0026 | Business Law |
| 0027 | Finance |
| 0028 | Hotel & Restaurant Management |
| 0029 | Human Resources |
| 0030 | Information Systems and Technology |
+------+-----------------------------------------+
institutions
+--------+--------------------------------------------+
| id | inst_name |
+--------+--------------------------------------------+
| 000001 | A T Still University of Health Sciences |
| 000002 | Abilene Christian University |
| 000003 | Abraham Baldwin Agricultural College |
+------+----------------------------------------------+
users
+----------+----------+
| id | username |
+----------+----------+
| 00000013 | Test1 |
| 00000018 | Test2 |
| 00000023 | Test3 |
+----------+----------+
user_degrees
+---------+-----------+---------+---------+
| user_id | degree_id | acad_id | inst_id |
+---------+-----------+---------+---------+
| 18 | 1 | 4 | 1 |
| 23 | 1 | 15 | 1 |
| 23 | 2 | 15 | 1 |
| 23 | 3 | 15 | 1 |
+---------+-----------+---------+---------+
How can I query 'user_degrees' to find all degrees by user x, but return the actual values of the foreign keys? Taking user Test3 as an example, I'm looking for output like so (truncated for layout's sake):
+-------------------+-------------------+-------------------+
| degree_type | acad_cat_name | inst_name |
+-------------------+-------------------+-------------------+
| Bachelor's Degree | Accounting | A T Still Uni.. |
| Master's Degree | Accounting | A T Still Uni.. |
| Ph.D. | Accounting | A T Still Uni.. |
+-------------------+-------------------+-------------------+
I'm guessing a mix of multiple joins, temp tables and subqueries are the answer but am having trouble grasping the order of things. Any insight is much appreciated, thanks for reading.
You need to join user_degrees to degrees (and the other tables referenced by user_degrees). This is the query that will give you your example output:
SELECT
ud.user_id, d.degree_type, ac.acad_cat_name, i.inst_name
FROM
user_degrees ud
INNER JOIN degrees d ON d.id = ud.degree_id
INNER JOIN acad_category ac ON ac.id = ud.acad_id
INNER JOIN institutions i ON i.id = ud.inst_id
WHERE
ud.user_id = 18
You may also want to read this article to understand different kinds of joins: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
The only way to understand these things at your stage of learning is to actually write the queries and then modify them until you get your desired output.

Excluding rows where the max value in one column is used to check the value in another?

Sorry for the obscure title, but I'm not sure how to sum it up.
I'm working with some static train schedule data supplied to me in several tables. I'm trying to show all the trains that stop at a specific station excluding those that end at the specified station. So for example, when listing all the trains that stop at NYPenn station, I don't want those trains terminating in NYPenn station.
The relevant tables are:
trips - list all of the trips made each day. each trip has a trip_id and consists of one or more stops. it also contains a trip_headsign column that shows the final destination of the train, but as text (not ID).
+----------+------------+---------+-------------------------+--------------+----------+----------+
| route_id | service_id | trip_id | trip_headsign | direction_id | block_id | shape_id |
+----------+------------+---------+-------------------------+--------------+----------+----------+
| 1 | 1 | 1 | PRINCETON RAIL SHUTTLE | 1 | 603 | 1 |
| 1 | 2 | 2 | PRINCETON RAIL SHUTTLE | 1 | 603 | 2 |
+----------+------------+---------+-------------------------+--------------+----------+----------+
stop_times - lists every stop made by every train. all stops made on the same trip share a trip_id, so this is what i LEFT JOIN on. this table also has a column called stop_sequence, ranging from 1 to n, where n is the total number of stops for that trip. The train originates at stop_sequence=1. This value ranges from 2 to 26.
+---------+--------------+----------------+---------+---------------+-------------+---------------+---------------------+
| trip_id | arrival_time | departure_time | stop_id | stop_sequence | pickup_type | drop_off_type | shape_dist_traveled |
+---------+--------------+----------------+---------+---------------+-------------+---------------+---------------------+
| 1 | 21:15:00 | 21:15:00 | 24070 | 1 | 0 | 0 | 0 |
| 1 | 21:25:00 | 21:25:00 | 41586 | 2 | 0 | 0 | 2.5727 |
+---------+--------------+----------------+---------+---------------+-------------+---------------+---------------------+
This particular train makes only two stops. The final stop (41586) is what's listed in the headsign column (notice it doesn't match the stop_name).
+---------------+---------+---------+-------------------------+----------+----------------+
| stop_sequence | stop_id | trip_id | trip_headsign | block_id | departure_time |
+---------------+---------+---------+-------------------------+----------+----------------+
| 1 | 24070 | 1 | PRINCETON RAIL SHUTTLE | 603 | 21:15:00 |
| 2 | 41586 | 1 | PRINCETON RAIL SHUTTLE | 603 | 21:25:00 |
+---------------+---------+---------+-------------------------+----------+----------------+
+---------+----------------------------+-----------+-----------+------------+---------+
| stop_id | stop_name | stop_desc | stop_lat | stop_lon | zone_id |
+---------+----------------------------+-----------+-----------+------------+---------+
| 41586 | PRINCETON RAILROAD STATION | | 40.343398 | -74.659872 | 336 |
+---------+----------------------------+-----------+-----------+------------+---------+
So, again, what I'm looking to do is show a list of all the trains that stop at a particular station EXCEPT those that terminate at the station in question. The query I wrote to do this is (in this case, for stop_id 105 which is NY Penn station):
select stop_sequence, trips.trip_id, trip_headsign, trips.block_id, departure_time from rail_data.trips left join rail_data.stop_times on trips.trip_id = stop_times.trip_id where stop_id = '105' order by departure_time asc;
This returns results like this:
+---------------+---------+-----------------------+----------+----------------+
| stop_sequence | trip_id | trip_headsign | block_id | departure_time |
+---------------+---------+-----------------------+----------+----------------+
| 18 | 1342 | NEW YORK PENN STATION | 6600 | 05:43:00 |
| 1 | 1402 | SUMMIT | 6305 | 06:07:00 |
| 16 | 1328 | NEW YORK PENN STATION | 6604 | 06:34:00 |
| 1 | 1391 | SUMMIT | 6307 | 06:41:00 |
| 19 | 1360 | NEW YORK PENN STATION | 6908 | 06:47:00 |
+---------------+---------+-----------------------+----------+----------------+
In this case, I only want the trains headed to SUMMIT to show up. But remember I can't simply say where stop_sequence > 1 because I want to include trains that might be the second, third, etc. stop -- just not the final stop.
Thanks in advance for the help!
you can query the stop_times and check if its shape_dist_traveled==0 and take the corresponding "trip id" and then query the trips table with this id. so, you have to add a where:
where trips.trip_id in (select st.trip_id from stop_times st where st.shape_dist_traveled==0)
P.S: I assumed the shape_dist_travelled will give the distance travelled by the train