connecting tables through split fields - mysql

I have two tables;
- The Items table - that has basic information about products: name, the basic price of the product, and if the product has any attributes - they will be specified there in the following format: attribute's option ID - attribute's value ID. (an example of an option would be a colour or size, an example of value would be red).
For example:
items table
id | name |attributes |price
1 | a |13-49 | 5.00
2 | b |5-101,13-77| 5.00
3 | c | | 5.00
4 | b |5-102,13-70| 5.00
The second table has every option and value assigned to products (id_option and id_value - meaning the same as in the previous table) as well as information if the attribute value changes the basic price of the product (change) and what the change should be (value).
items_attributes
id |id_item|id_option|id_value |change | value
1 | 1 | 13 | 49 | 1 |10.00
2 | 2 | 5 | 101 | 1 | 5.50
3 | 2 | 13 | 77 | 1 | 0.50
4 | 4 | 5 | 102 | 0 | 0
5 | 4 | 13 | 70 | 1 | 1.00
I want to get a table witch is the same as the first, but with the price calculated according to changes noted in items_attributes table.
id | name |attributes | price
1 | a |13-49 | 15.00
2 | b |5-101,13-77| 11.00
3 | c | | 5.00
4 | b |5-102,13-70| 6.00
How do I split the attributes from the items table and use it to join the two tables?

You can do this with a join using find_in_set():
select i.id, i.name, i.attributes,
i.price + coalesce(sum(ia.value)) as price
from items i left join
items_attributes ia
on find_in_set(concat(ia.id_option, '-', ia.id_attribute), i.attributes) > 0
group by i.id;
Unfortunately, you cannot improve performance of this query using indexes. For better performance, you need a better data structure.

Related

MySql Join two tables with multiple columns

I have two tables
tblcities:
id | name
----------------
1 | Bahawalpur
2 | Multan
3 | Karachi
4 | Lahore
tblflights:
id | from_city_id | to_city_id
-------------------------------
1 | 1 | 2
2 | 3 | 4
3 | 2 | 1
I want to join tables so it shows the city name for both columns i.e: from_city_id & to_city_id
what i tried:
SELECT *
FROM tblflights
JOIN tblcities
ON tblflights.from_city_id = tblcities.id
result:
id | from_city_id | to_city_id | name
--------------------------------------------
1 | 1 | 2 | Bahawalpur
2 | 3 | 4 | Karachi
3 | 2 | 1 | Multan
but i want name of both cities (from_city_id & to_city_id)
i tried my best but could not found any solution.
i am using CodeIgniter
Try something like this.
SELECT tf.id, tc1.name from_city_name, tc2.name to_city_name
FROM tblflights tf
JOIN tblcities tc1
ON tf.from_city_id = tc1.id
JOIN tblcities tc2
ON tf.from_city_id = tc2.id;
You may need to remove duplicates depending on your table contents.

How to calculate student rank in access

I want to calculate student rank based on their obtmarks as per below tables. Suppose any student scored highest marks in their class but he/she fail in any one subjects then they shouldn't consider for rank.
1. Table name is "resultdata"
Total marks of full marks is(1000)
pass marks is 33
ID | subject ID | subject | fullmarks | obtmarks |passmarks
1 | 1 | HINDI | 100 | 80 | 33
2 | 2 | ENGLISH | 100 | 90 | 33
3 | 3 | MATHEMATICS | 100 | 76 | 33
4 | 4 | SOCIAL SCIENCE| 100 | 69 | 33
like that others subjects also.
2. Table name is "result"
ID|result | student |student|mother |father |class|term/ |rollno|section|
|date | ID |name |name |name | |semester | | |
1 |11.09.2019| 1 |Jasmine|Eliana |Ritesh | 8 |1st Term | 10 | A |
2 |11.09.2019| 2 |Kiyas |Fanny |Rajnish| 10 |1st Term | 1 | B |
3 |11.09.2019| 3 |Ena |Rashmi |Prakash| 9 |1st Term | 12 | C |
4 |11.09.2019| 4 |Sunaina|Ankita |Chander| 7 |1st Term | 15 | A |
5 |11.09.2019| 5 |Ankit |Sujata |Roy | 8 |1st Term | 11 | B |
6 |11.09.2019| 6 |Krishna|Bala |Gopal | 8 |1st Term | 5 | C |
7 |11.09.2019| 7 |Ranga |Hima |Hitesh | 9 |1st Term | 7 | A |
8 |11.09.2019| 8 |Suraj |Priya |Hemal | 7 |1st Term | 10 | B |
9 |11.09.2019| 9 |Saurabh|Archana|Suyog | 10 |1st Term | 9 | B |
3. Table name is "subjects"
ID | subject | fullmarks | passmarks
1 | HINDI | 100 | 33
2 | ENGLISH | 100 | 33
3 | MATHEMATICS | 100 | 33
4 | SOCIAL SCIENCE | 100 | 33
5 | Computer | 50 | 20
like that others subjects also.
ID of subjects table and subjectID of resultdata table has relationship.
How to resolve this issue using a formula or vba code?
Condition1: Calculate every student rank on basis of their total obtained marks. But any student has failed in any subjects they will not consider for TOP 10 rank.
Condition 2: Calculate every student rank on basis of their total obtained marks.
I tried this formula in query but it does not work:
Rank: DCount("*","resultdata","[fullmarks]>" & [obtmarks])+1
If you don't want to include students with any failing grade then do a preliminary query to eliminate them. Then use that query to rank the remaining students. Consider:
Query1: Passing
SELECT resultdata.StudentID, Sum(resultdata.obtmarks) AS SumOfobtmarks
FROM resultdata
GROUP BY resultdata.StudentID
HAVING resultdata.StudentID Not In (SELECT resultdata.StudentID
FROM resultdata
WHERE resultdata.obtmarks<[passmarks]);
Query2:
SELECT Passing.SumOfobtmarks, Passing.StudentID,
(SELECT Count(*) FROM Passing AS T1 WHERE T1.SumOfobtmarks > Passing.SumOfobtmarks)+1 AS Rank
FROM Passing
ORDER BY Passing.SumOfobtmarks DESC;
However, if multiple students have same score, results will likely not be satisfactory. This is a common topic with many examples. For one review http://allenbrowne.com/ranking.html. Best solution might be one involving a 'temp' table as explained in Allen's article. Or try Lebans Serialize function, link is in Allen's article. Another excellent tutorial demonstrating these techniques http://www.mendipdatasystems.co.uk/rank-order-queries/4594424063.

MySQL - join multiple mapped tables and count records with different mapping conditions

It's the 3rd day I'm trying to write a MySQL query. Did lots of search, but it still doesn't work as expected. I'll try to simplify tables as much as possible
System has tkr_restaurants table:
restaurant_id | restaurant_name
1 | AA
2 | BB
3 | CC
Each restaurant has a division assigned (tkr_divisions table):
division_id | restaurant_id | division_name
1 | 1 | AA-1
2 | 1 | AA-2
3 | 2 | BB-1
Then there are meals in tkr_meals_to_restaurants_divisions table, where each meal can be assigned (mapped) to whole restaurant(s) and/or specific division(s). If meal is mapped to restaurant, all restaurant's divisions should see it. If meal is mapped to division(s), only specific division(s) should see it.
meal_id | mapped_restaurant_id | mapped_division_id
1 | 1 | NULL
2 | NULL | 1
3 | NULL | 2
I need to display a list of restaurants and number of meals mapped to it depending on user permissions.
Example 1: if user has permissions to access whole restaurant_id 1 and restaurant_3 (and no specific divisions), then list should be:
AA | 3
CC | 0
(because user can access meals mapped to restaurant 1 + all its division, and restaurant 3 + all its divisions (even if restaurant 3 has no divisions/meals mapped))
Example 2: if user has permissions to access only division_id 1, then list should be:
AA | 1
(because user can only access meals mapped to division 1).
The closest query I could get is:
Example 1:
SELECT *,
(SELECT COUNT(DISTINCT meal_id)
FROM
tkr_meals_to_restaurants_divisions
WHERE
tkr_meals_to_restaurants_divisions.mapped_restaurant_id=tkr_restaurants.restaurant_id
OR tkr_meals_to_restaurants_divisions.mapped_division_id=tkr_divisions.division_id)AS total_meals
FROM
tkr_restaurants
LEFT JOIN
tkr_divisions
ON tkr_restaurants.restaurant_id=tkr_divisions.restaurant_id
WHERE
tkr_restaurants.restaurant_id IN (1, 3)
OR tkr_restaurants.restaurant_id IN (
SELECT restaurant_id
FROM tkr_divisions
WHERE division_id IN (NULL)
)
GROUP BY
tkr_restaurants.restaurant_id
ORDER BY
tkr_restaurants.restaurant_name
However, result was:
AA | 2
CC | 0
I believe I'm greatly over-complicating this query, but all the simpler queries I wrote produced even more inaccurate results.
What about this query:
SELECT
FROM tkr_restaurants AS a
JOIN tkr_divisions AS b
ON a.restaurant_id = b.restaurant_id
LEFT OUTER JOIN tkr_meals_to_restaurants_divisions AS c
ON (c.mapped_restaurant_id = a.restaurant_id OR c.mapped_division_id = b.division_id)
As a Base four your further work. It combine all information into one table. If you add e.g. this:
WHERE a.restaurant_id IN (1, 3)
the result will be
| restaurant_id | restaurant_name | division_id | restaurant_id | division_name | meal_id | mapped_restaurant_id | mapped_division_id |
|---------------|-----------------|-------------|---------------|---------------|---------|----------------------|--------------------|
| 1 | AA | 1 | 1 | AA-1 | 1 | 1 | (null) |
| 1 | AA | 2 | 1 | AA-2 | 1 | 1 | (null) |
| 1 | AA | 1 | 1 | AA-1 | 2 | (null) | 1 |
| 1 | AA | 2 | 1 | AA-2 | 3 | (null) | 2 |
just count the distinct meal ids with COUNT(DISTINCT c.meal_id) and take the restaurant name to get AA: 3 for your example 2
I used a sqlfiddle: http://sqlfiddle.com/#!9/fa2b78/18/0
[EDIT]
Change JOIN tkr_divisions AS b to LEFT OUTER JOIN tkr_divisions AS b
Change SELECT * to SELECT a.restaurant_name, COUNT(DISTINCT c.meal_id)
Add a GROUP BY a.restaurant_name at the end.
Update the SQL Fiddle (new link)

MySQL Advanced Ranks Query

I have a table that looks like this:
map uid time name
'first' 1 5.0 'Jon'
'first' 3 4.9 'Robin'
'second' 1 2.0 'Jon'
'first' 2 5.3 'Max'
'second' 3 2.1 'Robin'
I am currently selecting the values using this:
SELECT records.* FROM `records` WHERE `uid` = '3' ORDER BY `records`.`time` ASC
Now obviously, I have multiple uids for different maps. How would I find the rank of every user out of total ranks? I know I can find total ranks of the map by using COUNT(DISTINCT map). However, I am having issues selecting a specific user and their rank in the map. Any help would be appreciated!
EDIT:
Desired output when selecting uid 3 is as follows:
map uid time name position totalposition (totalposition would be COUNT(DISTINCT map))
'first' 3 4.9 'Robin' 2 3
'second' 3 2.1 'Robin' 2 2
Use the following query : -
mysql> set #pos = 0; select records.*, #pos:=#pos+1 as position from records order by time desc;
Output :
+--------+------+------+-------+--------------+
| map | uid | time | name | position |
+--------+------+------+-------+--------------+
| first | 2 | 5.30 | Max | 1 |
| first | 1 | 5.00 | jon | 2 |
| first | 3 | 4.90 | Robin | 3 |
| second | 3 | 2.10 | Robin | 4 |
| second | 1 | 2.00 | Jon | 5 |
+--------+------+------+-------+--------------+
And now, to recieve position of a particular :
mysql> set #pos = 0; select * from (select records.*, #pos:=#pos+1 as position
mysql> from records order by time desc) as t where uid = 3;
Output :
+--------+------+------+-------+----------+
| map | uid | time | name | position |
+--------+------+------+-------+----------+
| first | 3 | 4.90 | Robin | 3 |
| second | 3 | 2.10 | Robin | 4 |
+--------+------+------+-------+----------+

How to display the string values of a table refering to Two foreign ID keys on the main table

So I have this database
TABLE: rates
ID | FID | TID | RATE
---------------------------
1 | 1 | 2 | 0.3
2 | 1 | 3 | 1.2
3 | 1 | 4 | 4.5
4 | 2 | 1 | 1.3
5 | 2 | 3 | 3.3
6 | 2 | 4 | 4.4
TABLE: currencies
ID | Name | Symbol
---------------------
1 | Euro | E
2 | Pound | P
3 | Dollar | $
4 | CAD | C
So what I tried so far was
SELECT rates.*,
currencies.name,
currencies.symbol FROM RATES
JOIN CURRENCIES ON
(rates.fid = currencies.id)
Which worked but only for 1 column. I could not find a way to add more. Also I want to give a custom output name for each currency. So the final output should be:
ID | FromCurrency (FID) | ToCurrency (TID) | Rate
You need to do multiple joins, and as you are using the same table for both joins, give them an alias.
Something like this:
SELECT rates.ID,
a.name AS 'FromCurrency (FID)',
a.symbol AS 'FID Symbol',
b.name AS 'ToCurrency (TID)',
b.symbol AS 'TID Symbol',
rates.rate
FROM RATES
JOIN CURRENCIES AS a ON
(rates.fid = a.id)
JOIN CURRENCIES AS b ON
(rates.tid = b.id)
Here is a working example