How to update data using two tables - mysql

I have two tables gains and final_gains.
I'm wondering how I could calculate the sum of two columns and insert it into a different table...I need to be using a WHERE clause which would be inside runescape_name inside the gains table.
Like so
hitpoints_end_exp - hitpoints_starting_exp,
magic_end_exp - magic_starting_exp,
range_end_exp - range_starting_exp
And insert the result into final_gains.hp_gained, final_gains.magic_gains and final_gains.range_gained
Here are my two tables
gains
+------------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+-------------+------+-----+---------+-------+
| runescape_name | varchar(12) | NO | PRI | NULL | |
| hitpoints_starting_exp | int(50) | NO | | NULL | |
| magic_starting_exp | int(50) | NO | | NULL | |
| range_starting_exp | int(50) | NO | | NULL | |
| hitpoints_end_exp | int(50) | NO | | NULL | |
| magic_end_exp | int(50) | NO | | NULL | |
| range_end_exp | int(50) | NO | | NULL | |
+------------------------+-------------+------+-----+---------+-------+
final_gains
+----------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+-------+
| runescape_name | varchar(12) | NO | PRI | NULL | |
| hp_gained | int(50) | NO | | NULL | |
| magic_gained | int(50) | NO | | NULL | |
| range_gained | int(50) | NO | | NULL | |
+----------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
Sorry If I'm unclear, trying to explain the best as I can, I hope I'm clear enough

Use an INSERT, SELECT like this:
INSERT INTO final_gains (runescape_name, hp_gained, magic_gains, range_gained)
SELECT runescape_name,
hitpoints_end_exp - hitpoints_starting_exp,
magic_end_exp - magic_starting_exp,
range_end_exp - range_starting_exp
FROM gains;
In order to avoid duplicate keys:
INSERT INTO final_gains (runescape_name, hp_gained, magic_gains, range_gained)
SELECT runescape_name,
hitpoints_end_exp - hitpoints_starting_exp,
magic_end_exp - magic_starting_exp,
range_end_exp - range_starting_exp
FROM gains
ON DUPLICATE KEY
UPDATE hp_gained = hitpoints_end_exp - hitpoints_starting_exp,
magic_gains = magic_end_exp - magic_starting_exp,
range_gained = range_end_exp - range_starting_exp;
This is untested code, but should be close.
Note: I removed the first suggestion as it s not applicable to these table definitions. runescape_name is primary key in table final_gains so it has to be inserted/assigned as well.

Related

How do I set Maximum Value of a Column in MYSQL?

I have Table called WORKERS, and the Table consists of totalNumberOfWorkers, i want to set the maximum value of the worker to be 30 and it shouldn't exceed over 30, it should be in the range of 0 to 30.
I have tried this, but it doesn't work and shows an error, my code isn't right.
ALTER TABLE WORKERS
CONSTRAINT WORKERS_CHECK CHECK (totalNumberOfWorkers => 0 AND totalNumberOfWorkers <31);
Here is the Table Called WORKERS
+------------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+-------------+------+-----+---------+-------+
| WorkerID | int(6) | NO | PRI | NULL | |
| dateOfWork | date | NO | | NULL | |
| timeOfWork | time | NO | | NULL | |
| descOfWorker | varchar(50) | NO | | NULL | |
| totalNumberOfWorkers | int(2) | NO | | NULL | |
+------------------------+-------------+------+-----+---------+-------+
Found a solution
ALTER TABLE WORKERS
ADD CONSTRAINT TOTALNUMBER_CHECK1 CHECK(totalNumberOfWorkers BETWEEN 1 AND 30);

Having more than one value inserted into the same column

I have a webapp that I'm building. This webapp will take as input some products (cars, motos, boats, houses, etc...) and each product will have one or more photos associated with it. The id of each of photo is generated by the uniqid() function of php.
My problem is:I can't seem to fit more than two id_photos into the same column
+-----------+------------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------------------------------+------+-----+---------+----------------+
| carid | int(11) | NO | MUL | NULL | auto_increment |
| brand | enum('Alfa Romeo','Aston Martin','Audi') | NO | | NULL | |
| color | varchar(20) | NO | | NULL | |
| type | enum('gasoline','diesel','eletric') | YES | | NULL | |
| price | mediumint(8) unsigned | YES | | NULL | |
| mileage | mediumint(8) unsigned | YES | | NULL | |
| model | text | YES | | NULL | |
| year | year(4) | YES | | NULL | |
| id_photos | varchar(30) | YES | | NULL | |
+-----------+------------------------------------------+------+-----+---------+----------------+
What I would like to happen is something like this: INSERT INTO cars(id_photos) values ('id_1st_photo', 'id_2nd_photo')
Ending up having something like this:
| 60 | Audi | Yellow | diesel | 252352 | 1234112 | R8 | 1990 | id_1st_photo id_2nd_photo |
Eventually I would have to grab those photos from the folders they are in which is something like this: /var/www/website/$login/photos/id_of_photo with the query select id_photos from cars where carid=$id.
You may found some data types that is not proprelly good for the data that the server will receive but I'm one week into mysql and I'll worry about data types later on.
First of all I don't know if that is possible, if it's not how can I design something to work like that?
I have found this question that is quite the same of mine but I can't seem to implement something like this: add multiple values in one column
You can insert the concatenated values into a field. But it is not a good practice. You can create another table with foreign key having the id of the parent table.
You can easily adapt the approach in the linked question and even remove one table needed:
You first table stays almost the same, but has the id_photos column removed:
+-----------+------------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------------------------------+------+-----+---------+----------------+
| carid | int(11) | NO | MUL | NULL | auto_increment |
| brand | enum('Alfa Romeo','Aston Martin','Audi') | NO | | NULL | |
| color | varchar(20) | NO | | NULL | |
| type | enum('gasoline','diesel','eletric') | YES | | NULL | |
| price | mediumint(8) unsigned | YES | | NULL | |
| mileage | mediumint(8) unsigned | YES | | NULL | |
| model | text | YES | | NULL | |
| year | year(4) | YES | | NULL | |
+-----------+------------------------------------------+------+-----+---------+----------------+
Then you'll add a second table to store the links to the photo ids:
+-----------+------------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------------------------------+------+-----+---------+----------------+
| carid | int(11) | NO | MUL | NULL | |
| id_photos | varchar(30) | NO | | NULL | |
+-----------+------------------------------------------+------+-----+---------+----------------+
Both tables are linked by the field carid (You should even make carid in the second table a foreign key pointing to the one in the first table).
Each id_photos then results in a new row in the second table.
To query the data you probably need a JOIN between both tables and maybe a GROUP BY to reduce the result to one row per carid again, but this depends on the other usecases.
You can insert the string formatted woth multiple photo name
INSERT INTO cars(id_photos) values ('id_1st_photo, id_2nd_photo')
In this way you don'have a well normalized database structure so you have problem when retrive the singole foto name ..
i suggest you of normalize the id_photo column in a separata table with reference to the master table and in this way store each single photo in one row

Improve query performance in MySQL

I am posting this thread in order to have some advices regarding the performance of my SQL query.
I have actually 2 tables, one which called HGVS_SNP with about 44657169 rows and another on run table which has an average of 2000 rows.
When I try to update field Comment of my run table it takes lot's of time to perform the query. I was wondering if there is any method to increase my SQL query.
Structure of HGVS_SNP Table:
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| snp_id | int(11) | YES | MUL | NULL | |
| hgvs_name | text | YES | | NULL | |
| source | varchar(8) | NO | | NULL | |
| upd_time | varchar(32) | NO | | NULL | |
+-----------+-------------+------+-----+---------+-------+
My run table has the following structure:
+----------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| ID | varchar(7) | YES | | NULL | |
| Reference | varchar(7) | YES | MUL | NULL | |
| HGVSvar2 | varchar(120) | YES | MUL | NULL | |
| Comment | varchar(120) | YES | | NULL | |
| Compute | varchar(20) | YES | | NULL | |
+----------------------+--------------+------+-----+---------+-------+
Here's my query:
UPDATE run
INNER JOIN SNP_HGVS
ON run.HGVSvar2=SNP_HGVS.hgvs_name
SET run.Comment=concat('rs',SNP_HGVS.snp_id) WHERE run.Compute not like 'tron'
I`m guessing since you JOIN a text column with a VARCHAR(120) column that you don`t really need a text column. Make it a VARCHAR so you can index it
ALTER TABLE `HGVS_SNP` modify hgvs_name VARCHAR(120);
ALTER TABLE `HGVS_SNP` ADD KEY idx_hgvs_name (hgvs_name);
This will take a while on large tables
Now your JOIN should be much faster,also add an index on compute column
ALTER TABLE `run` ADD KEY idx_compute (compute);
And the LIKE is unnecessary,change it to
WHERE run.Compute != 'tron'

Mysql paginate more than one table

I'm working on an ECommerce website, in which there are 2 database tables in MySQL, one is products and the other one is taxonomies, products and taxonomies are many to many relationship, and taxonomies have a tree structure, meaning there's a parent_id field in taxonomies table to identify the parent id of a taxonomy.
When user selects one taxonomy, I want to get all the products that belong to this taxonomy and all its offspring taxonomies, I did this by first finding out all the offspring taxonomies of the selected taxonomy, then get paginated products result from there, but in my site there are in total 5000 taxonomies, and my solution makes the site slow like a dog...... Any advice on how I could achieve this for the sake of performance?
products table:
+-------------------+----------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+----------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| code | bigint(20) | NO | UNI | NULL | |
| SKU | varchar(255) | NO | | NULL | |
| name | varchar(100) | NO | | NULL | |
| description | varchar(2000) | NO | | NULL | |
| short_description | varchar(200) | NO | | NULL | |
| price | decimal(8,2) | NO | | 0.00 | |
| discounted_price | decimal(8,2) | NO | | 0.00 | |
| stock | smallint(5) unsigned | NO | | 0 | |
| sales | smallint(5) unsigned | NO | | 0 | |
| num_reviews | smallint(6) | NO | | 0 | |
| weight | decimal(5,2) | NO | | 0.00 | |
| overall_rating | decimal(3,2) | NO | | 5.00 | |
| activity_id | int(10) unsigned | YES | MUL | NULL | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------------+----------------------+------+-----+---------------------+----------------+
taxonomies table:
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(100) | YES | UNI | NULL | |
| parent_id | int(10) unsigned | YES | MUL | NULL | |
| num_products | smallint(6) | NO | | 0 | |
+--------------+------------------+------+-----+---------+----------------+
product_taxonomy table:
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| product_id | int(10) unsigned | NO | MUL | NULL | |
| taxonomy_id | int(10) unsigned | NO | MUL | NULL | |
+-------------+------------------+------+-----+---------+----------------+
In case depth of single level one can use the following query
SELECT * FROM `product_taxonomy`
INNER JOIN (SELECT * FROM `taxonomies` WHERE `id` = 100 OR `parent_id` = 100) `taxonomies`
ON `product_taxonomy`.`taxonomy_id` = `taxonomies`.`id`
LEFT JOIN `products` ON `product_taxonomy`.`product_id` = `products`.`id`
You can add limit, offset to the above query for pagination.
100 in the above query represents the taxonomy id requested by the user.
Apart from this I would suggest :-
1) id in your product table to renamed if possible to product_id as referenced in your product_taxonomy and I presume in other tables, similarly taxonomy_id.
This way when you join query column name would be the same.
2) I hope product_taxonomy.product_id, product_taxonomy.taxonomy_id are indexed for faster querying.
Update:
What you had mentioned in the comment below is a hierarchical data problem and not what relational database ideally intended for.
Solution 1
IF you know for sure that you will have only 4 levels / generation then you can do 4 join queries.
I can elaborate on this if you need to.
Solution 2
If you are not too deep or committed to the architecture of this project I would recommend restructuring it such a way, where recursion is taken care of by the server side scripting. i.e You change your CMS/taxonomy management in such a way that whenever you add/remove/modify taxonomy the script will update a table called taxonomy_childs with all possible offspring for a given category so that you have a flat data at your disposal when you need it.
Personally I would prefer this. I always like my database to match my business logic requirement.
I can elaborate on this if you need to.
Solution 3
As mentioned earlier hierarchical data is not a strong point of a relational database. Having said that you can implement something called as Nested Set Model.
Please read more at http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
You would need to add 3 columns to your taxonomy table :- level_depth, lft, rht.
Please let me know which solution would you want me to elaborate.

Change data type from varchar to enum

I have a table for which I've recently changed the type of several columns from varchar to enum (see below). My app queries against this table on both of these columns and, once the type change was made, I have seen serious performance degradation for this query (I've included the query below as well as the explain plan results). I've so far been unable to find a culprit here and was hoping someone had run into this problem and could advise.
desc order_transmission_history;
+--------------------------+--------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+--------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| transmission_id | varchar(255) | YES | | NULL | |
| transmitter_type | varchar(10) | YES | MUL | NULL | |
| initial_attempt_date | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| most_recent_attempt_date | timestamp | NO | | 0000-00-00 00:00:00 | |
| most_recent_status | varchar(16) | YES | | NULL | |
+--------------------------+--------------+------+-----+---------------------+----------------+
the index is: KEY transmission_history_transmitter_status_date (transmitter_type,most_recent_status,initial_attempt_date)
explain SELECT * FROM order_transmission_history where transmitter_type = 'FAX_1' AND transmission_id = '' AND (most_recent_status is null or (most_recent_status not in ('SENT', 'ERROR')));
+----+-------------+----------------------+-------+-------------------------------------------------------------------------------------------+----------------------------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+-------------------------------------------------------------------------------------------+----------------------------------------------+---------+------+------+-------------+
| 1 | SIMPLE | transmission_history | range | transmission_history_transmitter_status_date | transmission_history_transmitter_status_date | 32 | NULL | 350 | Using where |
+----+-------------+----------------------+-------+-------------------------------------------------------------------------------------------+----------------------------------------------+---------+------+------+-------------+
Now, with the changed data types:
+--------------------------------------+----------------------------------------------------------------------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------------------+----------------------------------------------------------------------------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| transmission_id | varchar(255) | YES | | NULL | |
| initial_attempt_date | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| most_recent_attempt_date | timestamp | YES | | NULL | |
| transmitter_type | enum('FAX_1','FAX_2','FAX_3','EMAIL') | YES | MUL | NULL | |
| most_recent_status | enum('NONE','PENDING','TRANSIENT_ERROR','ERROR','SENDING','SENT','SYSTEM_ERROR') | YES | | NULL | |
+--------------------------------------+----------------------------------------------------------------------------------+------+-----+-------------------+----------------+
explain SELECT * FROM order_transmission_history where transmitter_type = 'FAX_1' AND transmission_id = '' AND (most_recent_status is null or (most_recent_status not in ('SENT', 'ERROR')));
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
| 1 | SIMPLE | order_transmission_history | ref | transmission_history_transmitter_status_date | transmission_history_transmitter_status_date | 2 | const | 394992 | Using where |
+----+-------------+----------------------------+------+----------------------------------------------+----------------------------------------------+---------+-------+--------+-------------+
Since you using in your select
most_recent_status is null OR (most_recent_status not in ('SENT', 'ERROR'))
planner will not use your key. Becuase there are no way use key with such where clause.
So only thing it can use is
transmitter_type = 'FAX_1' AND transmission_id = ''
but in your case planner think you have alot of lines with those values in index, so no advantage use index.
You can force use of index, but not think it will help. Probably you need think about way of rewrite your query to be more specific(for example add "order by most_recent_attempt_date limit 10" and create key with most_recent_attempt_date first)
Also you can got more perfomance if not use null value in most_recent_status(put 'undefined' in enum) and use query which use status value instead of query which user sets ( in/not in).
It has been my experience that MySQL does not like to use an index when you have a where not in or <> on an enum field. Try flipping your query to check for explicit values instead.
SELECT * FROM order_transmission_history
where transmitter_type = 'FAX_1'
AND transmission_id = ''
AND (most_recent_status is null or
(most_recent_status in
('NONE','PENDING','TRANSIENT_ERROR','SENDING','SYSTEM_ERROR')));