Adding (results of a query) to an existing table - mysql

So i have the following problem. I have 2 tables (Users: 100 rows and geo-zipcodes: 450k rows) and I want to update my users table to display the lon and lat if the zipcode is filled in. When it's not filled in i want the lon/lat to display NULL. How do I achieve this?
I do this in MySQL using the standard provided MySQL workbench.
+CURRENT SITUATION----+------+
| id | zipcode | lon | lat |
+----+---------+------+------+
| 88 | 3531EK | NULL | NULL |
| 89 | 5691JN | NULL | NULL |
| 90 | 5701NR | NULL | NULL |
| 91 | 3531EK | NULL | NULL |
| 92 | 5691JN | NULL | NULL |
| 93 | NULL | NULL | NULL |
| 94 | NULL | NULL | NULL |
| 95 | NULL | NULL | NULL |
| 96 | NULL | NULL | NULL |
| 97 | NULL | NULL | NULL |
+----+---------+------+------+
+FUTURE SITUATION------------------+-----------------+
| id | zipcode | lat | lon |
+-----+---------+------------------+-----------------+
| 583 | NULL | NULL | NULL |
| 632 | NULL | NULL | NULL |
| 797 | 4194WD | 51.8724978062918 | 5.2758839816285 |
| 812 | 9723ZT | 53.2067353295688 | 6.5886266741127 |
| 782 | 5617BD | 51.4471593854488 | 5.4566869544855 |
| 799 | NULL | NULL | NULL |
| 800 | 5623ET | 51.4618395108795 | 5.4733910341403 |
| 179 | 5709BN | 51.4752182995384 | 5.7022349534995 |
| 112 | 5701CN | 51.4759330063412 | 5.6780783810570 |
| 90 | 5701NR | 51.4775509176254 | 5.6576320175919 |
+-----+---------+------------------+-----------------+

In MySQL, you can do this with a join:
update users u join
zipcodes z
on u.zipcode = z.zipcode
set u.lat = z.lat, u.lon = z.lon;
However, I don't see why this is necessary. Why not just look up the coordinates using the zip code table when you need it? There might be good reasons -- for instance, you might have other sources of coordinates. But if the zip code is the only source, then there is no need to store the same information in two places.

Related

fill at once data null on table sql

I have table transaksi:
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(150) | YES | | NULL | |
| price | int(11) | YES | | NULL | |
| type | int(11) | YES | | NULL | |
+-------------+--------------+------+-----+---------+-------+
and have data (I fill in the data with insert into transaksi (name,price,type) select name,price,type from store)
+-----------+--------------------------+---------+-------+
| id | name | price | Type |
+-----------+--------------------------+---------+-------+
| NULL | Pants | 79 | 9 |
| NULL | Cup | 38 | 7 |
| NULL | Shoes | 21 | 1 |
| NULL | Hat | 11 | 5 |
| NULL | Pulpen | 39 | 2 |
+___________|__________________________|_________|_______|
How to fill "NULL" data at once in ID ?

Combine data from three unrelated tables

I need to use a data visualization tool that can only query a single source for a given chart. I have three tables with the data I need to visualize. So, I need to combine them into a single view or output table. Here are the table schemas:
MySQL [bdCaloriesNeeded]> desc activity;
+---------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+----------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | text | YES | | NULL | |
| Gender | text | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| length | text | YES | | NULL | |
| weight | int(11) | YES | | NULL | |
| exercise | int(11) | YES | | NULL | |
| food_consumed | int(11) | YES | | NULL | |
| date | datetime | YES | | NULL | |
+---------------+----------+------+-----+---------+-------+
MySQL [bdCaloriesNeeded]> desc exercise;
+---------------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------+------+-----+---------+-------+
| Gender | text | YES | | NULL | |
| Min_Age | int(11) | YES | | NULL | |
| Max_Age | int(11) | YES | | NULL | |
| min_exercise_hours | int(11) | YES | | NULL | |
| med_exercise_hours | int(11) | YES | | NULL | |
| high_exercise_hours | int(11) | YES | | NULL | |
+---------------------+---------+------+-----+---------+-------+
MySQL [bdCaloriesNeeded]> desc food;
+---------------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------+------+-----+---------+-------+
| size | text | YES | | NULL | |
| min_pounds | int(11) | YES | | NULL | |
| max_pounds | int(11) | YES | | NULL | |
| min_food_oz_per_day | int(11) | YES | | NULL | |
| max_food_oz_per_day | int(11) | YES | | NULL | |
+---------------------+---------+------+-----+---------+-------+
Here's the actual source data in the above tables:
MySQL [bdCaloriesNeeded]> select * from activity;
+------+----------+--------+------+--------+--------+----------+---------------+---------------------+
| id | name | Gender | age | length | weight | exercise | food_consumed | date |
+------+----------+--------+------+--------+--------+----------+---------------+---------------------+
| 14 | spot | M | 2 | 2'7" | 13 | 5 | 13 | 2017-10-08 00:00:00 |
| 67 | princess | F | 6 | 3'3" | 75 | 3 | 15 | 2017-09-05 00:00:00 |
+------+----------+--------+------+--------+--------+----------+---------------+---------------------+
MySQL [bdCaloriesNeeded]> select * from exercise
+--------+---------+---------+--------------------+--------------------+---------------------+
| Gender | Min_Age | Max_Age | min_exercise_hours | med_exercise_hours | high_exercise_hours |
+--------+---------+---------+--------------------+--------------------+---------------------+
| M | 1 | 2 | 1 | 4 | 6 |
| M | 3 | 7 | 1 | 3 | 4 |
| M | 8 | 15 | 1 | 2 | 2 |
| F | 1 | 2 | 1 | 4 | 6 |
| F | 3 | 7 | 1 | 3 | 5 |
| F | 8 | 15 | 1 | 2 | 2 |
+--------+---------+---------+--------------------+--------------------+---------------------+
MySQL [bdCaloriesNeeded]> select * from food;
+--------+------------+------------+---------------------+---------------------+
| size | min_pounds | max_pounds | min_food_oz_per_day | max_food_oz_per_day |
+--------+------------+------------+---------------------+---------------------+
| small | 1 | 10 | 12 | 18 |
| medium | 11 | 30 | 15 | 30 |
| large | 31 | 100 | 25 | 50 |
+--------+------------+------------+---------------------+---------------------+
Here's the SQL I'm executing:
SELECT activity.id, activity.name, activity.Gender, activity.age, activity.weight, activity.exercise, activity.date, exercise.min_exercise_hours, exercise.high_exercise_hours, food.size, food.min_food_oz_per_day, food.max_food_oz_per_day
from activity, exercise, food
where (
activity.exercise between exercise.min_exercise_hours and exercise.high_exercise_hours
)
and
(
activity.weight between food.min_pounds and food.max_pounds
)
and
(
activity.Gender = exercise.Gender
)
Here's the undesired result I'm getting:
+------+----------+--------+------+--------+----------+---------------------+--------------------+---------------------+--------+---------------------+---------------------+
| id | name | Gender | age | weight | exercise | date | min_exercise_hours | high_exercise_hours | size | min_food_oz_per_day | max_food_oz_per_day |
+------+----------+--------+------+--------+----------+---------------------+--------------------+---------------------+--------+---------------------+---------------------+
| 14 | spot | M | 2 | 13 | 5 | 2017-10-08 00:00:00 | 1 | 6 | medium | 15 | 30 |
| 67 | princess | F | 6 | 75 | 3 | 2017-09-05 00:00:00 | 1 | 6 | large | 25 | 50 |
| 67 | princess | F | 6 | 75 | 3 | 2017-09-05 00:00:00 | 1 | 5 | large | 25 | 50 |
+------+----------+--------+------+--------+----------+---------------------+--------------------+---------------------+--------+---------------------+---------------------+
I'm getting two rows for Princess. I need one row for each dog. The desired result should use Princess's's weight to look up the correct range of food per day, and use her gender and age to look up the correct range of exercise.
I've been banging on this for hours, can't see what doing wrong here.
So interestingly your question says that the tables are Unrelated but they are actually related and this is the whole point of a relational database, to join data based on those relationships.
The issue is that your exercise table is only being joined on exercise hours using the between so princess matches rows 4 and 5 in the exercise table. (the first where clause matches rows 1 and 2 also but the later where clause limits the Gender)
It looks to me like you should also limit the match on the exercise table to age as well as exercise and gender
so add
and (activity.age between exercise.min_age and exercise.max_age)
Also personally i like to use JOIN clauses rather than WHERE - it keeps all the stuff together.
SELECT activity.id,
activity.name,
activity.Gender,
activity.age,
activity.weight,
activity.exercise,
activity.date,
exercise.min_exercise_hours,
exercise.high_exercise_hours,
food.size,
food.min_food_oz_per_day,
food.max_food_oz_per_day
FROM activity
JOIN exercise
ON activity.exercise BETWEEN exercise.min_exercise_hours AND exercise.high_exercise_hours
AND activity.Gender = exercise.Gender
AND activity.age BETWEEN exercise.min_age AND exercise.max_age
JOIN food
ON activity.weight BETWEEN food.min_pounds AND food.max_pounds
Since you are looking for things that may be OUTSIDE of the ranges suggested you may want to consider LEFT JOIN on the exercise and food tables, so that the dogs on the activity table that fall outside of any range will still show up (with NULL values for the missing data for the other table.)
just change the join lines to LEFT JOIN like so:
LEFT JOIN exercise
LEFT JOIN food
See also: What is the difference between "INNER JOIN" and "OUTER JOIN"?

Update a date column with the result of the next closest date column

I have a MySQL table that looks like this:
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| person_id | int(11) | NO | MUL | NULL | |
| location_id | int(11) | NO | MUL | NULL | |
| date_signed | date | NO | | NULL | |
| date_ended | date | YES | | NULL | |
+-------------+---------+------+-----+---------+-------+
Where all of the records are like this:
+-----------+-------------+-------------+------------+
| person_id | location_id | date_signed | date_ended |
+-----------+-------------+-------------+------------+
| 1 | 49 | 2007-09-29 | NULL |
| 1 | 41 | 2010-10-09 | NULL |
| 2 | 45 | 2007-09-29 | NULL |
| 2 | 58 | 2007-12-16 | NULL |
| 3 | 49 | 2007-09-29 | NULL |
| 4 | 45 | 2007-09-29 | NULL |
| 4 | 35 | 2013-10-04 | NULL |
| 5 | 45 | 2007-09-29 | NULL |
| 5 | 37 | 2009-01-09 | NULL |
| 5 | 32 | 2009-10-08 | NULL |
+-----------+-------------+-------------+------------+
I'm trying to update each person's date_ended to be one day less than the date_signed in the next chronological row for that person:
+-----------+-------------+-------------+------------+
| person_id | location_id | date_signed | date_ended |
+-----------+-------------+-------------+------------+
| 1 | 49 | 2007-09-29 | 2010-10-08 |
| 1 | 41 | 2010-10-09 | NULL |
| 2 | 45 | 2007-09-29 | 2007-12-15 |
| 2 | 58 | 2007-12-16 | NULL |
.
.
.
But I can't figure out how to select the next chronological record. I tried a few suggestions from similar questions:
UPDATE a column based on the value of another column in the same table
Mysql - update table column from another column based on order
ROW_NUMBER() in MySQL
But I couldn't get them to work. Is there a way to do this in MySQL?
SQL Fiddle: http://sqlfiddle.com/#!9/8b5219/1

Needed aid with complicated MySQL query - very narrow scope

Here are my TABLES described and their contents:
users:
+-----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| public_key_path | varchar(100) | NO | | NULL | |
| email | varchar(50) | NO | | NULL | |
| pbox | varchar(50) | YES | UNI | NULL | |
+-----------------+--------------+------+-----+---------+----------------+
contents:
+----+-------------------+----------------------+--------+
| id | public_key_path | email | pbox |
+----+-------------------+----------------------+--------+
| 33 | /path/to/pubkey1/ | FirstUser#email.com | Pbox01 |
| 34 | /path/to/pubkey2/ | SecondUser#email.com | Pbox02 |
| 35 | /path/to/pubkey3/ | ThirdUser#email.com | Pbox03 |
+----+-------------------+----------------------+--------+
files:
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| file_path | varchar(100) | NO | UNI | NULL | |
| owner_id | int(11) | NO | MUL | NULL | |
+-----------+--------------+------+-----+---------+----------------+
contents:
+-----+-----------------+----------+
| id | file_path | owner_id |
+-----+-----------------+----------+
| 104 | /path/to/file1/ | 33 |
| 105 | /path/to/file2/ | 34 |
| 106 | /path/to/file3/ | 35 |
| 107 | /path/to/file4/ | 33 |
| 108 | /path/to/file5/ | 33 |
| 109 | /path/to/file6/ | 34 |
+-----+-----------------+----------+
encrypted_symmetric_keys:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| key_path | varchar(100) | YES | UNI | NULL | |
| file_id | int(11) | NO | MUL | NULL | |
| user_id | int(11) | NO | MUL | NULL | |
+----------+--------------+------+-----+---------+----------------+
contents:
+-----+---------------------+---------+---------+
| id | key_path | file_id | user_id |
+-----+---------------------+---------+---------+
| 106 | /path/to/key1forU1/ | 104 | 33 |
| 107 | /path/to/key2forU2/ | 105 | 34 |
| 108 | /path/to/key3forU3/ | 106 | 35 |
| 109 | /path/to/key4forU1/ | 107 | 33 |
| 110 | /path/to/key5forU1/ | 108 | 33 |
| 111 | /path/to/key6forU2/ | 109 | 34 |
| 112 | /path/to/key3forU1/ | 106 | 33 |
| 113 | /path/to/key2forU1/ | 105 | 33 |
| 114 | /path/to/key6forU1/ | 109 | 33 |
+-----+---------------------+---------+---------+
This is a newbie database for a server that stores filepaths that are encrypted with encrypted symmetric keys(ESKs).
If there is key_path /path/to/key1forU1/ that means that the key is stored for file1 for user1.
I need a query that, when given file_path (ex. "/path/to/file1/") lists all users that have access to this file.
Let me know if you need any more information, I'll provide it immediately.
I know that this is a very localized question, but I've been thinking for more than an hour about that now and I'm having horrible problems with wrapping my head around it.
Thank you very much in advance.
EDIT:
My final set of data I need is, when given
'/path/to/file1/'
would return
FirstUser#email.com
But when given for example
/path/to/file2/'
would return
FirstUser#email.com
SecondUser#email.com
because
I think this is what you are looking for
as this will give you all email that are using file_path = '/path/to/file6/' except the owner's email
SELECT su.email
FROM encrypted_symmetric_keys AS c
INNER JOIN users AS su ON su.id = c.user_id
INNER JOIN files AS f ON f.id = c.file_id AND f.owner_id <> c.user_id
WHERE f.file_path = '/path/to/file6/'

How to get rid of null values in pivoted table?

I am trying to pivot a table in MySQL so that I can turn row values into column headers for an easier-to-read table in a report. Here is a sample of what comes out so far (data has been obfuscated a bit but the concept is still the same):
+------------+------+------+---------+
| Date | RS1 | RS2 | RS3 |
+------------+------+------+---------+
| 2007-02-26 | 12 | NULL | NULL |
| 2007-04-12 | 8 | NULL | NULL |
| 2007-07-31 | 9 | NULL | NULL |
| 2008-02-07 | 12 | NULL | NULL |
| 2008-11-06 | 20 | NULL | NULL |
| 2010-03-04 | 8 | NULL | NULL |
| 2010-12-16 | 7 | NULL | NULL |
| 2011-01-24 | 20 | NULL | NULL |
| 2011-03-22 | 7 | NULL | NULL |
| 2012-11-12 | 19 | NULL | NULL |
| 2007-02-26 | NULL | 18 | NULL |
| 2007-04-12 | NULL | 2 | NULL |
| 2007-07-31 | NULL | 4 | NULL |
| 2008-02-07 | NULL | 10 | NULL |
| 2008-11-06 | NULL | 8 | NULL |
| 2010-03-04 | NULL | 6 | NULL |
| 2010-12-16 | NULL | 6 | NULL |
| 2011-01-24 | NULL | 5 | NULL |
| 2011-03-22 | NULL | 11 | NULL |
| 2012-11-12 | NULL | 13 | NULL |
| 2007-02-26 | NULL | NULL | 15 |
| 2007-04-12 | NULL | NULL | 6 |
| 2007-07-31 | NULL | NULL | 5 |
| 2008-02-07 | NULL | NULL | 8 |
| 2008-11-06 | NULL | NULL | 11 |
| 2010-03-04 | NULL | NULL | 1 |
| 2010-12-16 | NULL | NULL | 19 |
| 2011-01-24 | NULL | NULL | 14 |
| 2011-03-22 | NULL | NULL | 15 |
| 2012-11-12 | NULL | NULL | 10 |
+------------+------+------+---------+
30 rows in set (0.00 sec)
The only thing left to do is to get rid of the NULL values so that all the columns are aligned with each other for each date. In other words, delete the last 20 rows from column 1, the first 10 and last 10 from column 2, and the first 20 from column 3, so that all the columns and their values are aligned.
Is there an easy way to do this in MySQL?
Try this:
SELECT Date,
MAX(RS1),
MAX(RS2),
MAX(RS3)
FROM Table1
GROUP BY Date
SQLFiddle demo
You can create a new table and INSERT again the data while grouping by date:
INSERT INTO mynewtable (date,RS1,RS2,RS3)
SELECT Date,MAX(RS1),MAX(RS2),MAX(RS3)
FROM myoldtable GROUP BY Date