multiple tables in my sqli - php

first i want to sorry for my bad english :D
second , i have a project in my college in sql and php that the doctor asked me to make 4 tables ( clients , payment , project , flats )
clients table have a relation with payment table and project table with a foreign key , and project table have a relation with flats table
i can make an insert statment to show all information on clients,payment and project tables
( SELECT clients.name, payment.first_cash, project_type.type_of_flat
FROM clients
INNER JOIN payment ON clients.client_id = payment.client_id
INNER JOIN project_type ON clients.client_id = project_type.client_id
LIMIT 0 , 30 )
now i want to show information in flat table also ,,
project table has a relation with flats table
project table is the parent and flats table is the child
thanks in advance and sorry again for my bad english :D
__
why the row repeated now ?
enter image description here

You need to add another JOIN with flats table.
SELECT clients.name, payment.first_cash, project_type.type_of_flat
FROM clients
INNER JOIN payment ON clients.client_id = payment.client_id
INNER JOIN project_type ON clients.client_id = project_type.client_id
INNER JOIN flats ON flats.project_id = project_type.project_id
LIMIT 0 , 30
In JOINS, you join two tables with an id field.
First table has actual data and the id field generally is its Primary Key.
Second table has reference with first table's id field which is Foreign Key.

Related

Joining Tables with id VS saving the text

I have two table one is accounts table and account group table. currently I am using the auto increment id as foreign key in the accounts table but my question is I have multiple tables where it will join with accounts table and I need to retrieve account group name in a view where there is 20 union all queries which it join to the accounts table.
SELECT acc.name,accgrp.groupName,bill.supplier,bill.amount
FROM bills bill
INNER JOIN accounts acc ON acc.accId=bills.accId
INNER JOIN accountGroup accgrp ON accgrp.groupId=acc.groupId
UNION ALL
.....
What is the correct way to save the data in accounts table saving id is the best approach or saving the group name is best approach. If i used id as foreign key and join in 20 union all is it make my query slower? or saving group name in my accounts table and retrieve it without join make my query faster?

How to show one row if it has more rows in inner join and left join query?

I have more than one shop in ps_shop table and its some of shop have in ps_storeinfo table but those shop of ps_shop table are not in ps_storeinfo table that are needed to insert into ps_storeinfo with user id and shop name. Here shopname of ps_shop table = storename in ps_storeinfo table. Here I have written sql query for this and I am getting all data but problem is more than one user is coming by my SQL if it have more than one user. I need one user for one shop.
In ps_ employee_shop table user is assigned for shop base on shop id. And In ps_ employee table is for user. This is for prestashop 1.6.
My SQL is given below :
$table_prefix = _DB_PREFIX_;
'SELECT ps.*, pe.email, pe.firstname, pe.lastname, pes.id_employee,psi.storename
FROM '.$table_prefix.'shop ps
LEFT JOIN '.$table_prefix.'storeinfo psi ON ps.name = psi.storename
INNER JOIN '.$table_prefix.'employee_shop pes ON ps.id_shop = pes.id_shop
INNER JOIN '.$table_prefix.'employee pe ON pes.id_employee = pe.id_employee where ps.id_shop <>1 and pe.id_employee <>1
GROUP BY pes.id_employee
';
Output image is:
Well, if more than one entity exists in the table on the right side of the JOIN with the matching ON key any relational DB engine will return one row for each matching entity on the right side, duplicating the left side of the JOIN clause.
In the scenario described you need to decide which user you want to return. The first one sorted alphabetically? The one created most recently?
Based on the answer you will need to use a JOIN with a correlated subquery. Here's an example for getting the employee with the highest value of id_employee:
SELECT
ps.*, pe.email, pe.firstname, pe.lastname, pes.id_employee,psi.storename
FROM
'.$table_prefix.'shop ps
LEFT JOIN '.$table_prefix.'storeinfo psi ON ps.name = psi.storename
INNER JOIN (
SELECT
pe.email, pe.firstname, pe.lastname, pes.id_employee
FROM
'.$table_prefix.'employee pe
'.$table_prefix.'employee_shop pes ON pes.id_employee = pe.id_employee
WHERE
pe.id_employee <> 1
AND ps.id_shop = pes.id_shop
ORDER BY
pe.id_employee DESC
LIMIT 1
)
WHERE
ps.id_shop <>1
As you can see what this is really doing is limiting the resulting list of employees to just one record to avoid duplication. In this case the list is ordered by id_employee, but the correct ordering depends on the business logic that needs to be implemented.

Two tables - how to formulate the join

One question:
I have two tables:
Table station has the columns stationid and fullname.
Table route has the columns routeid, fromstationid, tostationid.
Table station has the full names of all stations saved. Each station has its unique ID (stationid is primary key).
Table Route has all route information. Each route has its unique ID (routeid is the primary key) and the starting station (fromstationid) and the terminal station (tostationid).
Now there is foreign key relationship between fromstationid, tostationid from the table route with stationid from the table station.
Now I want my website to spell out the following information:
Column 1: Route ID
Column 2: Full name of the starting station
Column 3: Full name of the terminal station
I have formulated two SQL queries.
SELECT route.routeid, route.fromstationid, station.fullname
FROM route INNER JOIN
station
ON route.fromstationid=station.stationid;
SELECT route.routeid, route.tostationid, station.fullname
FROM route INNER JOIN
station
ON route.totationid=station.stationid
Is there any to get this done with just one SQL query (ideally on a SQL database)?
Have I missed an important relational database concept?
Yes, you just need to join to station twice:
SELECT r.routeid, sfrom.fullname as fromstationname, sto.fullname as tostationname
FROM route r INNER JOIN
station sfrom
ON r.fromstationid = sfrom.stationid INNER JOIN
station sto
ON r.totationid = sto.stationid
You're very close. You just need to add the second join into the query, like so:
SELECT r.routeid, r.fromstationid, s1.fullname as start_station, r.tostationid, s2.fullname as end_station
FROM route r
LEFT JOIN station s1 ON r.fromstationid = s1.stationid
LEFT JOIN station s2 ON r.tostationid = s2.stationid

data show from 4 table mysql

How to show the common data from all table on base of vendorID where vendorID is unique key in my vendor table. and i use this as an foriegn key for all other(cost table, hour table,employee table, temporary table and ) table.
This is my Cost table struructre
This is my Hour table structure
This is my Temporarytable structure
This is my Employee table
This is my Final table vendor there are vendorID is unique Key
And i have use the following query but it is showing the different data.
SELECT * FROM cw_employee_csv as emp
inner join cw_cost_hour as cost on cost.vendorid=emp.vendorid
inner join cw_temp_employee as temp on cost.vendorid=temp.vendorid
inner join cw_hour_company as hour on temp.vendorid=hour.vendorid
inner join cw_vendor as vendor on temp.vendorid=vendor.vendorid
where vendor.companyid=1 ORDER BY hour.timeFrom ASC
If I understand, try this:
In your query in the field list explicit fields you want to show, for example:
SELECT
emp.assignmentid, cost.bill_type
FROM
cw_employee_csv AS emp
INNER JOIN
cw_cost_hour AS cost ON cost.vendorid = emp.vendorid
INNER JOIN
cw_temp_employee AS temp ON cost.vendorid = temp.vendorid
INNER JOIN
cw_hour_company AS hour ON temp.vendorid = hour.vendorid
INNER JOIN
cw_vendor AS vendor ON temp.vendorid = vendor.vendorid
WHERE
vendor.companyid = 1
ORDER BY
hour.timeFrom ASC
If the cardinality of tables is different and you want to show only one row per vendor, you must write a main query with cw_vendor and use some subquery to retrieve additional information by other table. Obviously, about parent table of your vendor table you can use INNER JOIN information without use subqueries.
EDIT AFTER COMMENT:
You start by this query (after chat discussion):
I extract an aggregate by company (I suppose to summarize your cost by vendor, if you want to apply another formula, it's the same algorithm)
select
sum(t.vendor_cost), t.companyid
from
(select
vendor.companyid as companyid, vendor.id as vendorid,
(select SUM(c.cost)
from cw_cost_hoyr c
where c.vendorid = vendor.id) as vendor_cost
from
cw_vendor vendor) as t
group by
t.companyid
Now we add other information but I must understand what do you want exactly with their relations

MySQL: Understanding mapping tables

When building a category navigation system for a business directory with a many to many relationship, I understand that it is good practise to create a mapping table.
Category Table ( CategoryId, CategoryName )
Business Table ( BusinessId, BusinessName )
Category Mapping Table ( BusinessId, CategoryId )
When I join the Category table and Business table to create the mapping table would this then give me a table which contains every possible business and category relationship?
I have 800 categories and 1000 business listings. Would that then give me a table containing 800,000 possible relationships. If so how would I focus on only the relationships that exist? Would I have to go through all listings (800,000) marking them as true or false?
I have been getting really confused about this so any help would be much appreciated.
When using many-to-many relationships, the only realistic way to handle this is with a mapping table.
Lets say we have a school with teachers and students, a student can have multiple teachers and visa versa.
So we make 3 tables
student
id unsigned integer auto_increment primary key
name varchar
teacher
id unsigned integer auto_increment primary key
name varchar
link_st
student_id integer not null
teacher_id integer not null
primary key (student_id, teacher_id)
The student table will have 1000 records
The teacher table will have 20 records
The link_st table will have as many records as there are links (NOT 20x1000, but only for the actual links).
Selection
You select e.g. students per teacher using:
SELECT s.name, t.name
FROM student
INNER JOIN link_st l ON (l.student_id = s.id) <--- first link student to the link-table
INNER JOIN teacher t ON (l.teacher_id = t.id) <--- then link teacher to the link table.
ORDER BY t.id, s.id
Normally you should always use an inner join here.
Making a link
When you assign a teacher to a student (or visa versa, that's the same).
You only need to do:
INSERT INTO link_st (student_id, teacher_id)
SELECT s.id, t.id
FROM student s
INNER JOIN teacher t ON (t.name = 'Jones')
WHERE s.name = 'kiddo'
This is a bit of a misuse of an inner join, but it works as long as the names are unique.
If you know the id's, you can just insert those directly of course.
If the names are not unique this will be a fail and should not be used.
How to avoid duplicate links
It's very important to avoid duplicate links, all sorts of bad things will happen if you have those.
If you want to prevent inserting duplicate links to your link table, you can declare a unique index on the link (recommended)
ALTER TABLE link_st
ADD UNIQUE INDEX s_t (student_id, teacher_id);
Or you can do the check in the insert statement (not really recommended, but it works).
INSERT INTO link_st (student_id, teacher_id)
SELECT s.id, t.id
FROM student s
INNER JOIN teacher t ON (t.id = 548)
LEFT JOIN link_st l ON (l.student_id = s.id AND l.teacher_id = t.id)
WHERE (s.id = 785) AND (l.id IS NULL)
This will only select 548, 785 if that data is not already in the link_st table, and will return nothing if that data is in link_st already. So it will refuse to insert duplicate values.
If you have a table schools, it depends if a student can be enrolled in multiple schools (unlikely, but lets assume) and teachers can be enrolled in multiple schools. Very possible.
table school
id unsigned integer auto_increment primary key
name varchar
table school_members
id id unsigned integer auto_increment primary key
school_id integer not null
member_id integer not null
is_student boolean not null
You can list all students in a school like so:
SELECT s.name
FROM school i
INNER JOIN school_members m ON (i.id = m.school_id)
INNER JOIN student s ON (s.id = m.member_id AND m.is_student = true)
When I join the Category table and
Business table to create the mapping
table would this then give me a table
which contains every possible business
and category relationship?
Yes.
Would I have to go through all listings (800,000) marking them as true or false?
No, you need to use the ON-clause to set join-conditions.
SELECT <columns> FROM categories as c
INNER JOIN mapping AS m
ON m.CategoryId = c.CategoryId
INNER JOIN businesses as b
ON m.BusinessId = b.BusinessId
You should use mapping tables when you are trying to model a many-to-many or one-to-many relationship.
For example, in an address book application, a particular contact could belong to zero, one or many categories. If you set your business logic that a contact can only belong to one category, you would define your contact like:
Contact
--------------
contactid (PK)
name
categoryid (FK)
Category
--------------
categoryid (PK)
categoryname
But if you wanted to allow a contact to have more than one email address, use a mapping table:
Contact
--------------
contactid (PK)
name
Category
--------------
categoryid (PK)
categoryname
Contact_Category
--------------
contactid (FK)
categoryid (FK)
Then you can use SQL to retrieve a list of categories that a contact is assigned to:
select a.categoryname from Category a, Contact b, Contact_Category c where a.categoryid=c.categoryid and b.contactid=c.contactid and b.contactid=12345;
select a.categoryname
from Category a
inner join Contact_Category c on a.categoryid=c.categoryid
inner join Contact b on b.contactid=c.contactid
where b.contactid=12345;
you only put the real relationships in the mapping table. so on average fi a business is in 2 categories, then in your example, there would only be 2000 records in the mapping table, not 800,000
"When I join the Category table and Business table to create the mapping table" you don't join those two tables to create the mapping table. You create an actual physical table.

Categories