How to structure this sql query to create the following new table? - mysql

Assume I have the following tables:
tableA
a_name | age | country
Jordan | 5 | Germany
Molly | 6 | Spain
Paris | 7 | France
tableB
b_name | age | country
Kyle | 5 | Germany
Bob | 6 | Spain
Bob | 7 | Spain
Stephen | 7 | France
Kyle | 9 | France
Mario | 2 | Mexico
I want to make it such that I can produce a tableC that contains:
id (auto increment primary key) | age | country | country_marker
1 | 5 | Germany | 1
2 | 6 | Spain | 2
3 | 7 | France | 3
4 | 7 | Spain | 2
5 | 8 | France | 3
6 | 9 | France | 3
7 | 2 | Mexico | 4
For the new table:
takes any unique "age, country" pair only and putting them into tableC with "country_marker" automatically assigning incrementing unique numbers based on distinct "country"
Note there is no countries table, as the "country" in tableC is just based on whatever countries are in tableA, and tableB and country_marker is just a system generated identifier to indicate the unique countries in the table. Output tableC "id and country marker" ordering does not matter as long as it meets the bullet above.
I have painfully tried to produce this using MySQL cursors and want to know if its possible/what is some SQL query or set of queries I could use that would make this faster than using cursors.

I'd approach this by first creating table C in something like phpmyadmin. Then I'd write a query to pull the information from tables A and B that I want to put into C. Then, within phpmyadmin, I'd export the results of the query to a .sql file on my local machine. I'd open the .sql file to make the necessary modifications to the INSERT statements so that I can import the data in the .sql file to table C.
This isn't exactly the most efficient way, but it seems like the least technical way that would definitely work.

Related

Select distinct values based column keys placed in different table

I am new to MySQL I am facing a wall. I was looking for solution but could not find anything which would match my case. I understand how joins working. My question is: Is it possible to do a SELECT based on result from different SELECT?
For clarifying I have 2 tables and 1 view:
report_type table:
id | name | view_name
-------------------------------
1 | citizens | citizens_report
report_filter table:
id | name | filter_column
-------------------------------
1 | City | city
2 | Nationality | nationality
citizens_report view:
id | city | nationality
-------------------------------
1 | Boston | American
2 | London | British
3 | London | Spanish
4 | Paris | French
5 | Paris | French
6 | Boston | German
7 | New York | American
For raportId = 1 I need to look for dynamic view based on result from: report_type table which will be citizens_report - so here is first step where I need to build query with result of it and than I need to create unions of filters based on citizens_report view.
Expected result:
filter | option
----------------------------
city | Boston
city | London
city | Paris
city | New York
nationality | French
nationality | German
nationality | American
nationality | British
nationality | Spanish
I doesn't have to be in any specific order (might be ORDER BY ASC). In any language I can create map where key is equal filter and option is added to array.
Each step I can do with separate query and in any programming language I can call for next one, but could it be done in one query?
Thanks!

MySQL query or stored procedure that calls itself recursively and returns all nodes for selected parent

id | parent_id | name
-------------------------
1 | null | World
2 | 1 | Sri Lanka
3 | 1 | America
4 | 2 | South Province
5 | 2 | Western Province
6 | 4 | Galle
7 | 6 | Wakwella
8 | 3 | New York
I need a MySQL query or stored procedure that calls itself recursively and returns all nodes,child nodes and leaf nodes for selected "id" .
As a example:
When i want to select all child of id=2
Result should be,
South Province
Western Province
Galle
Wakwella
When i want to select all child of id=3
Result should be,
New York
a similar question was answered here:
https://dba.stackexchange.com/questions/7147/find-highest-level-of-a-hierarchical-field-with-vs-without-ctes/7161#7161
You need to use stored procedures for this.

How to store multiple values in single column where use less memory?

I have a table of users where 1 column stores user's "roles".
We can assign multiple roles to particular user.
Then I want to store role IDs in the "roles" column.
But how can I store multiple values into a single column to save memory in a way that is easy to use? For example, storing using a comma-delimited field is not easy and uses memory.
Any ideas?
If a user can have multiple roles, it is probably better to have a user_role table that stores this information. It is normalised, and will be much easier to query.
A table like:
user_id | role
--------+-----------------
1 | Admin
2 | User
2 | Admin
3 | User
3 | Author
Will allow you to query for all users with a particular role, such as SELECT user_id, user.name FROM user_role JOIN user WHERE role='Admin' rather than having to use string parsing to get details out of a column.
Amongst other things this will be faster, as you can index the columns properly and will take marginally more space than any solution that puts multiple values into a single column - which is antithetical to what relational databases are designed for.
The reason this shouldn't be stored is that it is inefficient, for the reason DCoder states on the comment to this answer. To check if a user has a role, every row of the user table will need to be scanned, and then the "roles" column will have to be scanned using string matching - regardless of how this action is exposed, the RMDBS will need to perform string operations to parse the content. These are very expensive operations, and not at all good database design.
If you need to have a single column, I would strongly suggest that you no longer have a technical problem, but a people management one. Adding additional tables to an existing database that is under development, should not be difficult. If this isn't something you are authorised to do, explain to why the extra table is needed to the right person - because munging multiple values into a single column is a bad, bad idea.
You can also use bitwise logic with MySQL. role_id must be in BASE 2 (0, 1, 2, 4, 8, 16, 32...)
role_id | label
--------+-----------------
1 | Admin
2 | User
4 | Author
user_id | name | role
--------+-----------------
1 | John | 1
2 | Steve | 3
3 | Jack | 6
Bitwise logic allows you to select all user roles
SELECT * FROM users WHERE role & 1
-- returns all Admin users
SELECT * FROM users WHERE role & 5
-- returns all users who are admin or Author because 5 = 1 + 4
SELECT * FROM users WHERE role & 6
-- returns all users who are User or Author because 6 = 2 + 4
From your question what I got,
Suppose, you have to table. one is "meal" table and another one is "combo_meal" table. Now I think you want to store multiple meal_id inside one combo_meal_id without separating coma[,]. And you said that it'll make your DB to more standard.
If I not getting wrong from your question then please read carefully my suggestion bellow. It may be help you.
First think is your concept is right. Definitely it'll give you more standard DB.
For this you have to create one more table [ example table: combo_meal_relation ] for referencing those two table data. May be one visible example will clear it.
meal table
+------+--------+-----------+---------+
| id | name | serving | price |
+------+--------+-----------+---------+
| 1 | soup1 | 2 person | 12.50 |
+------+--------+-----------+---------+
| 2 | soup2 | 2 person | 15.50 |
+------+--------+-----------+---------+
| 3 | soup3 | 2 person | 23.00 |
+------+--------+-----------+---------+
| 4 | drink1 | 2 person | 4.50 |
+------+--------+-----------+---------+
| 5 | drink2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 6 | drink3 | 2 person | 5.50 |
+------+--------+-----------+---------+
| 7 | frui1 | 2 person | 3.00 |
+------+--------+-----------+---------+
| 8 | fruit2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 9 | fruit3 | 2 person | 4.50 |
+------+--------+-----------+---------+
combo_meal table
+------+--------------+-----------+
| id | combo_name | serving |
+------+--------------+-----------+
| 1 | combo1 | 2 person |
+------+--------------+-----------+
| 2 | combo2 | 2 person |
+------+--------------+-----------+
| 4 | combo3 | 2 person |
+------+--------------+-----------+
combo_meal_relation
+------+--------------+-----------+
| id | combo_meal_id| meal_id |
+------+--------------+-----------+
| 1 | 1 | 1 |
+------+--------------+-----------+
| 2 | 1 | 2 |
+------+--------------+-----------+
| 3 | 1 | 3 |
+------+--------------+-----------+
| 4 | 2 | 4 |
+------+--------------+-----------+
| 5 | 2 | 2 |
+------+--------------+-----------+
| 6 | 2 | 7 |
+------+--------------+-----------+
When you search inside table then it'll generate faster result.
search query:
SELECT m.*
FROM combo_meal cm
JOIN meal m
ON m.id = cm.meal_id
WHERE cm.combo_id = 1
Hopefully you understand :)
You could do something like this
INSERT INTO table (id, roles) VALUES ('', '2,3,4');
Then to find it use FIND_IN_SET
As you might already know, storing multiple values in a cell goes against 1NF form. If youre fine with that, using a json column type is a great way and has good methods to query properly.
SELECT * FROM table_name
WHERE JSON_CONTAINS(column_name, '"value 2"', '$')
Will return any entry with json data like
[
"value",
"value 2",
"value 3"
]
Youre using json, so remember, youre query performance will go down the drain.

MySQL query to update column in mysql based on a table?

Assume I have the following tables:
tableA
a_name | age | country
Jordan | 5 | Germany
Jordan | 6 | Spain
Molly | 6 | Spain
Paris | 7 | France
John | 7 | Saudi Arabia
John | 5 | Saudi Arabia
John | 6 | Spain
tableB
id (auto increment primary key)
| age | country | group_num (initially null)
1 | 5 | Germany |
2 | 6 | Spain |
3 | 7 | France |
4 | 7 | Spain |
5 | 8 | France |
6 | 9 | France |
7 | 2 | Mexico |
8 | 7 | Saudi Arabia |
9 | 5 | Saudi Arabia |
I want to be able to do some kind of select/update where I am able to get the following values for the "group_num" column:
tableB
id (auto increment primary key)
| age | country | group_num
1 | 5 | Germany | 1
2 | 6 | Spain | 1
3 | 7 | France | 1
4 | 7 | Spain |
5 | 7 | France | 2
6 | 9 | France |
7 | 2 | Mexico |
8 | 7 | Saudi Arabia | 1
9 | 5 | Saudi Arabia | 1
group_num is assigned based on the criteria of:
1) Places person "a_name" went.
2) Whether other people visited that same country. (regardless of age).
The reason why id's 1,2,3,8,9 all have the same groupId is because Jordan, Molly, and Paris all happen to be somehow linked because of the above two criteria. (they all went to spain) and other countries, i.e. Germany was visited by Jordan who also visited spain, so it has the same group_num. Saudi Arabia was visited by John, who also visited spain, so it has the same group_num.
is there some SQL query or queries (may or may not involve creation of other "complementary" tables to get to the desired result shown above? (i.e. it is okay if group_num should first to be filled with auto_incrementing values like the "id", then updated later if it is necessary. (it is okay to have non-null values for the other value fields currently shown as "(empty)"
Cursors/iteration is very slow... The following are the steps I would perform to fill out those values, very slow process using cursors, if I can get rid of this it would be great:
For tableA, we see that Jordan visited Germany at age 5. (Group_Num in tableB for [5,Germany] updated to 1).
Jordan visits Spain at age 6. (Group Num for [6,Spain] updated to 1 to show its the same grouping as the same guy Jordan visited Spain)
Molly visits Spain at age 6 (group_num for [6,Spain] updated to 1 since even though its a different person, the same age/country pair was hit)
Paris visited France at age 7 (group_num in tableB updated to 2 since she is a different person, visited a completely different country, regardless of age.
John visits Saudi Arabia at age 7 (group_num for [7,Saudi Arabia] in tableB updated to 3 for age+country pair)
John visits Saudi Arabia at Age 5 (group_num for [5,Saudi Arabia] in tableB updated to 3 for age+country pair since its still John)
John visits Spain at age 6 (group_num for [6,Spain] is already 1.. Jordan visited there before, there may be some grouping... so group_num for all the places John visited [6, Spain], [5, Saudi Arabia], and [7,Saudi Arabia] are all updated to 1
You will need an iterative approach which will be based on each new item added to Table1, if you execute the following statements for each such item it will be fast and efficient:
Here is SQLFiddle for state of the db just before inserting the last record in Table 1.
BTW: Your example is not entirely consistent with your description , i assume you signed France 7 as group 1 by mistake, since Paris has no relation to no one in group 1.
Notice the selects that i'm executing:
The first one searched for the group num of my previous places i have visited (this is my disjoint group , e.g. group num 3).
The second is searches if there is a disjoint group that the inserted record may be related to, by searching group num for spain and age 6.
After finding out that you have two disjoint sets that becomes joined as a result of newly inserted record , you may that UPDATE all the group num previously assigned as the second group number to the first one, in such way:
UPDATE Table2 set group_num = 1 where group_num = 3
So i have not used any cursors , but this update is per insert for Table 1.
#
Damascusi you can see if tiggers can work instead of cursors. Triggers are faster than cursors if only you could update group_num on the fly as and when the data is inserted into Table A.

SQL query to find category and sub category

I have a table which have category_id and parent_category_id. How I can get 1 category and 5 sub category by using SQL query.
Suppose table name is : Category
----------------------------------------------------------------
Category ID | Parent ID | Name
----------------------------------------------------------------
1 | NULL | Electronics
2 | 1 | Computer
3 | 1 | Calculator
4 | 1 | Mobile
5 | NULL | Four Wheeler
6 | 5 | Cars
7 | 5 | Trucks
8 | 5 | Jeep
9 | 5 | Van
Since MySQL does not support recursive queries/CTEs, you will have to emulate that (which is not, say, straightforward).
Here's an excellent tutorial on the subject:
http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
I will have the decency of not copying the code here :)
For SQL Server, you can use the WITH query to get the complete path (more here http://msdn.microsoft.com/en-us/library/ms175972.aspx).