better way to handle multiple tables relationship - php

Suppose i have some tables like...
countries
id name
1 Cyprus
2 India
states
id name country_id
1 a 1
2 b 2
3 c 2
cities
id name state_id
1 x 1
2 y 2
3 z 3
4 p 2
pages
id name slug status
1 ab a-b 1
2 pq p-q 0
3 abc a-b-c 1
mode_of_training
id name
1 Virtual
2 Classroom
items
id name description
1 a something
2 b something
prices
id price currency_code
1 200 USD
2 300 AUD
3 4000 INR
offers
id name discount
1 xyz-1 20%
2 abc-2 30%
3 pqr-3 10%
Creating table structure in that way is correct?? so that i can reuse them
using there ids.
For example
items_relation_table
id country_id state_id city_id page_id item_id price_id offer_id status
1 0 0 0 1 1 1 0 1
2 0 0 0 1 1 1 1 0
3 1 0 1 2 2 1 2 1
4 1 0 1 3 3 2 1 1
Now i don't need to use field values of tables
If i want to change price. i'll change price in one place only
I'm saving number of bytes.
database table size is less
But my problem is
To fetch data i need to use Joins
Or Creating View is better idea
Or There is any Better way to create table structure

Your entity-tables look fine at the first glance. But I don't understand your relation table. Looks like you try to relate everything with everything, which in some cases probably doesn't make sense (do offers really belong to countries?) in in some cases it seems redundant: When a page is linked to (many) cities, there is no need to link it to the countries too, because the countries are determined by the cities.
You should add relation-tables only between those entities that really need to be in a direct many-to-many relation. And for each of those relations you need a separate table.
e.g. for a relation between pages and cities:
cities(id, name, state_id) <--> cities_pages(city_id, page_id) <--> pages(id, name, slug, status)
And yes, you have to join tables to fetch data. Thats one of the basic ideas behind relational databases. Don't be afraid of joins, if your tables are properly indexed thats not an expensive operation at all (assuming that performance is your concern). And of course you could add some views if that makes sense for your application, but that will include the same JOINS you would just abstract them behind CREATE VIEW statements.

Related

Auto complete search from multiple tables

Eg:
**Category Table**
Catg_id Catg_name
-------------------
1 Bike
2 Car
**Company Table**
Company_id Company_name
--------------------------
1 Bajaj
2 Honda
**Company_category table**
com_catg_id Company_id Category_id
---------------------------------------
1 1 1
2 2 1
3 2 2
** Models table**
Model_id Model_name com_catg_id
----------------------------------------
1 Pulsar 220 1
2 Unicorn 2
3 City 3
**Purchase Table***
Purchase_id Vehicle_No Rate model_id status
-------------------------------------------------------
1 KL 02 AN8306 50000 2 0
2 KL 10 AZ4764 120000 1 1
3 KL 04 AV8578 800000 3 1
These are 4 Database tables using.
I am using ajax for auto complete searching through a single field
eg: searching car, want to list all cars in purchase table of status 1
if searching bike, want to list all bike in purchase table of status 1
search using company name, want to list all vehicle from that company in purchase table of status 1
same as search using model name, vehicle no,rate want to list matched items in purchase table
Please help me and please send a mysql query for implementing this.
Check this tut
This would surely help you.
This tutorial is for single field. It isn't hard to modify the code and use for multiple fields

Display data from 3 tables

I have messed with this query for 3 days now and no matter what I cannot get the right result. I'm working on a small database for a friend of mine for his mechanic shop.
I got 3 tables car, jobs and invoices. Everything start with "cars" if you add a car you get car_id for it. Next step would be to add a job to this car. Of course job goes to jobs table and also records car_id. After the job is done you can create an invoice out of it which goes to invoices table and again records car_id.
cars jobs invoices
=======================================================
cID, make, model | jID,cID,job1 | iID,jID,cID,amount
1 audi a6 | 1 1 check | 1 1 1 99.99
2 bmw 750 | 1 2 oil | 2 2 2 56.97
3 saab 95 | 3 3 oil | 3 3 3 30.22
1 audi a6 | 4 1 oli | 4 4 1 22.33
Small draft what the tables look like. And the outcome what I'd like to get should look like this:
ID make model
--------------------------
1. audi a6
Job 1 Invoice 1
Job 4 Invoice 4
2. bmw 750
Job 2 Invoice 2
3. Saab 95
Job 3 Invoice 3
Basically when I click my client list I get a table rows with clients and underneath client I'd like to print links to jobs and invoices.
Quite long post but I hope you understand what I mean.
I've tried different JOINs, the latest that I tried was
SELECT * FROM cars
RIGHT JOIN jobs ON cars.car_id=jobs.car_id
RIGHT JOIN invoices ON cars.car_id=invoices.car_id
ORDER BY cars.car_id;
It kind a worked but it gave me separate rows for each job with same client info. May I'm printing the result wrong. I just don't know any more. Can anybody offer a solution for this? right SQL command html for printing.
Why don't you just make it in a single table with fields like this:
id car job invoices
===============+===============+==============+==============+
1 + fastCar + works + 99.99 +
+ + + +
+ + + +
With statement like this:
CREATE TABLE cars (id int(11) AUTO_INCREMENT, car text(50) default '', job text(50) default '', invoices int(5) default NULL);
Then you can get all car attributes using a query like:
SELECT job FROM cars WHERE car='fastCar';
and pass desired values with another query to a teble that contains
details for the job for example, where you can have job id as needed.

Mysql find a table in from another table record and find a specific record in this table

I'm a new in Mysql and I have a complicated problem:
I have a table with "Shops" name in this table there is a ShopID column. The records look like this:
Shop_001
Shop_002...
Every "shopID" refer to a new table with this name, for example there is a table with Shop_0001 name. In this table there is "partnumber" column which mean the parts which are available in this shop.
I send a specific part number to sql server and I want to check all shops in the "Shops" table and return a rows in the "Shop_xxxx" tables which has this specific partnumber.
Unfortunately I have no idea how do I get start on this. Can anybody help me give some instruction or anything on this?
you're looking for a many to many relationship. so you just need 3 tables
1 table is the list of shops
1 table is the list of products
and 1 table is the list of which shops have which products. like this
table1
id|shops
------
1 shop1
2 shop2
3 shop3
table2
id|products
------
1 prod1
2 prod2
3 prod3
4 prod4
5 prod5
table3
id|shop_id|prod_id
-------------------
1 2 3
2 2 1
3 2 2
4 1 3
5 1 4
6 1 5
7 3 2
So for every time a product is added to a shop, an entry is added in table3. This will allow you to query by shops or by products, and you will only ever need 3 tables.
google querying many to many relationships for how to get the list of products for shop1 or the list of shops that have product4 etc.

Ordering standings football [soccer] positions by direct matches

I have a problem trying to apply rules about direct matches in a football[soccer] app. I have read this tread and it was very heplful on creating the standing positions table by the points criteria, difference and scored goals.
But i would like to know if is possible to order the teams position by direct matches:
look this positions table:
Pos Team Pld W D L F A GD Pts
1 FC Barcelona 5 2 3 0 8 5 3 9
2 **Inter Milan** 6 2 2 2 11 10 1 8
3 *Real Madrid* 6 2 2 2 8 8 0 8
4 AC Milan 5 0 3 2 8 12 -4 3
As you may see Inter Milan and Real Madrid are tied by points, and the Inter is heading real madrid because its goal difference. The result that i want to get is this :
Pos Team Pld W D L F A GD Pts
1 FC Barcelona 5 2 3 0 8 5 3 9
2 **Real Madrid** 6 2 2 2 8 8 0 8
3 *Inter Milan* 6 2 2 2 11 10 1 8
4 AC Milan 5 0 3 2 8 12 -4 3
Notice that in this time the real madrid is in front the inter milan because it won the two direct matches between them.
i have a table for teams and other for the results.
I would like to achive this using a query in mysql if is possible. Or maybe it would be better if i do this ordering on the server side (PHP).
Thanks any help would be appreciated.
It is impossible to efficiently do what you request in a single query that would return the results you ask for and sort the ties in points with that criteria.
The reasoning is simple: lets assume that you could get a column in your query that would provide or help with the kind of sorting you want. That is to say, it would order teams that are tied in points according to which one has more victories over the others (as this is very likely to happen to more than 2 teams). To make that calculation by hand you would need a double-entry table that shows the amount of matches won between those teams as follows:
| TeamA | TeamB | TeamC
------------------------------
TeamA | 0 | XAB | XAC
TeamB | XBA | 0 | XBC
TeamC | XCA | XCB | 0
So you would just add up each column row and sorting in descending order would provide you the needed data.
The problem is that you don't know which teams are tied before you actually get the data. So creating that column for the general case would mean you need to create the whole table of every team against every team (which is no small task); and then you need to add the logic to the query to only add up the columns of a team against those that are tied with it in points... for which you need the original result set (that you should be creating with the same query anyhow).
It may be possible to get that information in a single query, but it will surely be way too heavy on the DB. You're better off adding that logic in code afterwards getting the data you know you will need (getting the amount of games won by TeamA against TeamB or TeamC is not too complicated). You would still need to be careful about how you build that query and how many you run; after all, during the first few games of a league you will have lots of teams tied up against each other so getting the data will effectively be the same as building the whole double-entry table I used as an example before for all teams against all teams.
create temporary in a stored procedure and call to procedure...
create temporary table tab1 (position int not null auto_increment ,
team_name varchar(200),
points int,
goal_pt int,
primary key(position));
insert into tab1(team_name,
points,
goal_pt)
select team_name,
points,
goal_pt
from team
order by points desc,
goal_pt desc ;

mySQL query for selecting children

I am not sure if this is possible in mySQL. Here are my tables:-
Categories table:
id
name
parent_id (which points to Categories.id)
I use the above table to map all the categories and sub-categories.
Products table:
id
name
category_id
The category_id in the Products table points to the sub-category id in which it belongs.
e.g. If I have Toys > Educational > ABC where ABC is product, Toys is Category and Educational is sub Category, then ABC will have category_id as 2.
Now the problem is that I want to use a SQL query to display all the products (in all the sub-categories and their sub-categories.. n level) for a particular category.
e.g.:
select * from categories,products where category.name = 'Toys' and ....
The above query should display the products from Educational also and all other sub categories and their subcategories.
Is this possible using a mySQL query? If not what options do I have? I would like to avoid PHP recursion.
Update: Basically I want to display the top 10 products in the main category which I will be doing by adding a hits column to products table.
What I've done in previous projects where I've needed to do the same thing, I added two new columns.
i_depth: int value of how deep the category is
nvc_breadcrumb: complete path of the category in a breadcrumb type of format
And then I added a trigger to the table that houses the category information to do the following (all three updates are in the same trigger)...
-- Reset all branches
UPDATE t_org_branches
SET nvc_breadcrumb = NULL,
i_depth = NULL
-- Update the root branches first
UPDATE t_org_branches
SET nvc_breadcrumb = '/',
i_depth = 0
WHERE guid_branch_parent_id IS NULL
-- Update the child branches on a loop
WHILE EXISTS (SELECT * FROM t_branches WHERE i_depth IS NULL)
UPDATE tobA
SET tobA.i_depth = tobB.i_depth + 1,
tobA.nvc_breadcrumb = tobB.nvc_breadcrumb + Ltrim(tobA.guid_branch_parent_id) + '/'
FROM t_org_branches AS tobA
INNER JOIN t_org_branches AS tobB ON (tobA.guid_branch_parent_id = tobB.guid_branch_id)
WHERE tobB.i_depth >= 0
AND tobB.nvc_breadcrumb IS NOT NULL
AND tobA.i_depth IS NULL
And then just do a join with your products table on the category ID and do a "LIKE '%/[CATEGORYID]/%' ". Keep in mind that this was done in MS SQL, but it should be easy enough to translate into a MySQL version.
It might just be compatible enough for a cut and paste (after table and column name change).
Expansion of explanation...
t_categories (as it stands now)...
Cat Parent CategoryName
1 NULL MyStore
2 1 Electronics
3 1 Clothing
4 1 Books
5 2 Televisions
6 2 Stereos
7 5 Plasma
8 5 LCD
t_categories (after modification)...
Cat Parent CategoryName Depth Breadcrumb
1 NULL MyStore NULL NULL
2 1 Electronics NULL NULL
3 1 Clothing NULL NULL
4 1 Books NULL NULL
5 2 Televisions NULL NULL
6 2 Stereos NULL NULL
7 5 Plasma NULL NULL
8 5 LCD NULL NULL
t_categories (after use of the script I gave)
Cat Parent CategoryName Depth Breadcrumb
1 NULL MyStore 0 /
2 1 Electronics 1 /1/
3 1 Clothing 1 /1/
4 1 Books 1 /1/
5 2 Televisions 2 /1/2/
6 2 Stereos 2 /1/2/
7 5 LCD 3 /1/2/5/
8 7 Samsung 4 /1/2/5/7/
t_products (as you have it now, no modifications)...
ID Cat Name
1 8 Samsung LNT5271F
2 7 LCD TV mount, up to 36"
3 7 LCD TV mount, up to 52"
4 5 HDMI Cable, 6ft
Join categories and products (where categories is C, products is P)
C.Cat Parent CategoryName Depth Breadcrumb ID p.Cat Name
1 NULL MyStore 0 / NULL NULL NULL
2 1 Electronics 1 /1/ NULL NULL NULL
3 1 Clothing 1 /1/ NULL NULL NULL
4 1 Books 1 /1/ NULL NULL NULL
5 2 Televisions 2 /1/2/ 4 5 HDMI Cable, 6ft
6 2 Stereos 2 /1/2/ NULL NULL NULL
7 5 LCD 3 /1/2/5/ 2 7 LCD TV mount, up to 36"
7 5 LCD 3 /1/2/5/ 3 7 LCD TV mount, up to 52"
8 7 Samsung 4 /1/2/5/7/ 1 8 Samsung LNT5271F
Now assuming that the products table was more complete so that there is stuff in each category and no NULLs, you could do a "Breadcrumb LIKE '%/5/%'" to get the last three items of the last table I provided. Notice that it includes the direct items and children of the category (like the Samsung tv). If you want ONLY the specific category items, just do a "c.cat = 5".
I think the cleanest way to achieve this would be to use the nested set model. It's a bit complicated to implement, but powerful to use. MySQL has a tutorial named Managing Hierarchical Data in MySQL. One of the big SQL gurus Joe Celko wrote about the same thing here. If you need even more information have a look at Troel's links on storing hierarchical data.
In my case I would stay away from using a RDBMS to store this kind of data and use a graph database instead, as the data in this case actually is a directed graph.
Add a column to the Categories table that will contain the complete comma-delimited tree for each group. Using your example, sub-category Educational would have this as the tree '1,2', where 1 = Toys, 2 = Educational (it includes itself). The next nested level of categories would keep adding to the tree.
To get all products in a group, you use MySQL's FIND_IN_SET function, like so
SELECT p.ID
FROM Products p INNER JOIN Categories c ON p.category_ID = c.ID
WHERE FIND_IN_SET(your_category_id, c.tree)
I wouldn't use this method for big tables, as I don't think this query can use an index.
One way is to maintain a table that contains the ancestor to descendant relationships. You can query this particular table and get the list of all dependents.
Assuming MySQL, it'll be difficult to avoid recursion in PHP.
Your question is, essentially, how to mimic Oracle's CONNECT BY PRIOR syntax in MySQL. People ask this question repeatedly but it's a feature that's never made it in to MySQL and implementing is via stored procedures probably won't work because (now) stored functions cannot be recursive.
Beware of the database kludges offered so far.
The best information so far are the three links from nawroth:
Managing Hierarchical Data in MySQL, including the Nested Set Model.
Trees in SQL - nested set model by Joel Celko
Troels' links: Relational database systems: Hierarchical data in RDBMSs
How big is the table Categories? You may need to cache this on the application level and construct the appropriate query: ... where id in (2, 3, 6, 7)
Also, it's best if you fetch categories by id which is their unique ID, indexed and fast as opposed to finding by name.
Bear with me, because I have never done something like this.
BEGIN
SET cat = "5";
SET temp = "";
WHILE STRCMP(temp, cat) != 0 DO
SET temp = cat;
SET cat = SELECT CONCAT_WS(GROUP_CONCAT(id), cat) FROM Categories GROUP BY (parent_id) HAVING FIND_IN_SET(parent_id, cat);
END LOOP;
END;
SELECT * FROM products WHERE FIND_IN_SET(category_id, cat)
I can almost guarantee the above won't work, but you can see what I'm trying to do. I got this far and I just decided to not finish the end of the query (select the top N from each category), sorry. :P

Categories