Trouble understanding an SQL query for a many-to-many table - sql

I have a many-to-many table which manages stock between stores and products
I'm trying to create a simple query to show all the rows in store_stock but in a more user friendly way by showing the product name and store name.
I've tried a few variations of this but I just keep getting errors
SELECT product.product_name, store.store_name, store_stock.quantity
FROM store_stock
INNER JOIN product ON store_stock.product_id = product.product.id
INNER JOIN store ON store_stock.store_id = store.store_id
When I do it via phpMyAdmin query tab it runs this: (However I had to change it from LEFT JOINs to INNER JOINs)
SELECT `product`.`name` AS `product_name`, `store`.`name` AS `store_name`, `store_stock`.`quantity`
FROM `product`
INNER JOIN `store_stock` ON `store_stock`.`product_id` = `product`.`product_id`
INNER JOIN `store` ON `store_stock`.`store_id` = `store`.`store_id`
ORDER BY `product`.`name` ASC, `store`.`name` ASC
This works, but what I don't understand is why it runs 'FROM product', instead of 'FROM store_stock' table

Related

Inner Join and Left Join on 5 tables in Access using SQL

I am attempting to access data from the following tables:
OrgPlanYear
ProjOrgPlnYrJunction
DC
DCMaxEEContribLevel
DCNonDiscretionaryContribLevel
Basically, I need to inner join OrgPlanYear + DC and ProjOrgPlnYrJunction then I need to Left Join the remaining tables (tables 4 and 5) due to the fact the tables 1-3 have all the rows I need and only some have data in tables 4-5. I need several variables from each table. I also need the WHERE function to be across all fields (meaning I want all this data for a select group where projectID=919).
Please help!
I have tried many things with errors including attempting to use the Design Query side (i.e. JOIN function issues, badly formatted FROM function, etc.)! Here is an example of one excluding all variables I need:
SELECT
ProjOrgPlnYrJunction.fkeyProjectID, OrgPlanYear.OrgName, DC.PlanCode, DCNonDiscretionaryContribLevel.Age,DCNonDiscretionaryContribLevel.Service
FROM
(((OrgPlanYear INNER JOIN DC ON OrgPlanYear.OrgPlanYearID = DC.fkeyOrgPlanYearID) INNER JOIN ProjOrgPlnYrJunction ON OrgPlanYear.OrgPlanYearID = ProjOrgPlnYrJunction.fkeyOrgPlanYearID)
LEFT JOIN
(SELECT DCNonDiscretionaryContribLevel.Age AS Age, DCNonDiscretionaryContribLevel.Service AS Service FROM DCNonDiscretionaryContribLevel WHERE ProjOrgPlnYrJunction.fkeyProjectID)=919)
LEFT JOIN (
SELECT DCMaxEEContribLevel.EEContribRoth FROM EEContribRoth WHERE ProjOrgPlnYrJunction.fkeyProjectID)=919)
ORDER BY OrgPlanYear.OrgName;
Main issues with your query:
Missing ON clauses for each LEFT JOIN.
Referencing other table columns in SELECT and WHERE of a different subquery (e.g., FROM DCNonDiscretionaryContribLevel WHERE ProjOrgPlnYrJunction.fkeyProjectID).
Unmatched parentheses around subqueries and joins per Access SQL requirements.
See below adjusted SQL that now uses short table aliases. Be sure to adjust SELECT and ON clauses with appropriate columns.
SELECT p.fkeyProjectID, o.OrgName, DC.PlanCode, dcn.Age, dcn.Service, e.EEContribRoth
FROM (((OrgPlanYear o
INNER JOIN DC
ON o.OrgPlanYearID = DC.fkeyOrgPlanYearID)
INNER JOIN ProjOrgPlnYrJunction p
ON o.OrgPlanYearID = p.fkeyOrgPlanYearID)
LEFT JOIN
(SELECT Age AS Age, Service AS Service
FROM DCNonDiscretionaryContribLevel
WHERE fkeyProjectID = 919) AS dcn
ON dcn.fkeyProjectID = p.fkeyOrgPlanYearID)
LEFT JOIN
(SELECT EEContribRoth
FROM EEContribRoth
WHERE fkeyProjectID = 919) AS e
ON e.fkeyProjectID = p.fkeyProjectID
ORDER BY o.OrgName;

Group and Ordering in SQL

I need to make a query in SQL that can display the top selling book. for this I need to do a inner join and I get a problem after I did the inner join. Here is my code:
CREATE VIEW mostpopularbookssold AS
SELECT Count(orders.book_id) AS numberofbookssold ,
Top(1) books.[Name]
FROM orders
INNER JOIN books
ON books.id=orders.book_id
GROUP BY books.[Name]
select *
FROM mostpopularbookssold
The TOP(1) should be placed at the start of your query, after SELECT. Furthermore you have to make an ordering by the books sold:
CREATE VIEW MostPopularBooksSold
AS
SELECT TOP(1)
COUNT(Orders.Book_ID) AS NumberOfBooksSold
, Books.[Name]
FROM [the database name].[schema name].[Orders] AS Orders
INNER JOIN [the database name].[schema name].[Books] AS Books
ON Books.ID = Orders.Book_ID
GROUP BY Books.[Name]
ORDER BY COUNT(Orders.Book_ID) DESC
You should replace the database name with the name of the database, in which you have created the corresponding tables and you have replace the schema name with the schema name, under which you have created the corresponding tables (usually this is the dbo, if you haven't stated explicitly a schema name).

SQL select for many to many relationship using binding table

I am struggling with writing a select for diagram on the picture.
What I want to do is write a select, which will show me details of a car repair. As you can see in table Repairs there are only 2 attributes but I am not sure if it's necessary to add more, especialy those from employees_list and parts_list, since I want to show repair data for every vehicle by it's plate_number. By repair data I mean repair id, vehicle plate_number, all employees working on the repair and all parts used on the repair. If my diagram is wrong, please help me fix it and I have no idea how to write select for this because of the many to many relation and the use of binding tables.
This is not so hard as it may seem.
First, obviously, we have to select cars:
select vehicles.* from vehicles
then, let's join repairs:
select
vehicles.*
from vehicles
inner join repairs on vehicles.id = repairs.vehicle.id
We don't need data from repairs in resule set, so we just join it but not mention in 'select' part.
Then we have to join parts needed for repair, and info about parts itself:
select
vehicles.*
from vehicles
inner join repairs on vehicles.id = repairs.vehicle.id
inner join parts_list on parts_list.repair_id = repairs.id
inner join parts on parts_list.part_id = parts.id
For that query we get amout of rows equivalent of amount of parts needed for repair. But it would be more easy to handle such data in code if we aggregate all of them into json column. So in result set we willsee something like:
vehicle_id, vehicle_part, parts_needed_as_json
Lets aggregate this:
select
vehicles.*, json_agg(parts.*) as parts_needed
from vehicles
inner join repairs on vehicles.id = repairs.vehicle_id
inner join parts_list on parts_list.repair_id = repairs.id
inner join parts on parts_list.part_id = parts.id
group by vehicles.id, repairs.id
Now you can add same logic for employees:
select
vehicles.*,
json_agg(parts.*) as parts_needed,
json_agg(employes.*) as employees_needed
from vehicles
inner join repairs on vehicles.id = repairs.vehicle.id
inner join parts_list on parts_list.repair_id = repairs.id
inner join parts on parts_list.part_id = parts.id
inner join employees_list on employes_list.repair_id = repairs.id
inner join employees on employees_list.employee_id = employees.id
group by vehicles.id, repairs.id
BTW, I suggest you to rename your tables to lowercase and singulars.
Like: 'repair', 'employee' and 'vehicle';
Also, name your binding tables like: 'repair_part' and 'repair_employee'.
Some people even suggest to arrange related tables in that names by alphabet, like: 'employee_repair' and 'part_repair', but I think it's not required;
Maybe this is a question of taste but in most cases this leads to more readable queries.
I.e, the query above will looks like:
select
vehicle.*,
json_agg(part.*) as parts_needed,
json_agg(employee.*) as employees_needed
from vehicle
inner join repair on vehicle.id = repair.vehicle_id
inner join parts_repair on parts_repair.repair_id = repair.id
inner join part on parts_repair.part_id = part.id
inner join employees_repair on employees_repair.repair_id = repair.id
inner join employee on employees_repair.employee_id = employee.id
group by vehicle.id, repair.id
Note how elegant 'on' conditions looks now: parts_repair.part_id = part.id, parts_repair.part_id = part.id
Sorry for bad english

Help with SQL INNER JOIN statement

I have 2 tables , one showing me customer addresses and one other table showing all the order data. i would like to query the two tables using a JOIN so that i can get a result set shwoing me all the email addresses for customers that have not ordered in the last year.
so far i have this , but my inner join is not working, if you may help:
SELECT SHH.CUST_NO,ADR.EMAIL
FROM SALES_HISTORY_HEADER SHH,ADDRESS ADR
INNER JOIN ADR ON
SHH.CUST_NO = ADR.CUST_NO
GROUP BY SHH.CUST_NO
HAVING Max(SHH.INVOICE_DATE) < '20100728'
You were mixing join styles. If you're going to use explicit joins (and you should) then you specify the second table on the JOIN rather than listing all the tables in the FROM clause.
SELECT SHH.CUST_NO,ADR.EMAIL
FROM SALES_HISTORY_HEADER SHH
INNER JOIN ADDRESS ADR
ON SHH.CUST_NO = ADR.CUST_NO
GROUP BY SHH.CUST_NO, ADR.EMAIL
HAVING Max(SHH.INVOICE_DATE) < '20100728'

Join query from table with multiple foreign keys to same table primary key

I have a workorder system using SQL Express 2008. I have a table called Workorders that has several personnel that are linked to it via UserID. In the Workorder table I have TechID for the Technician, CustomerID for the Customer, QAID for quality assurance. These are linked back to the User Table via UserID (User Table PK). I want to join the tables to return Technician Name, Customer Name, and QA Name from the User Table and other job information information from the Workorder Table. I have no idea how to construct the join.
What about something a bit like this :
select tech.name as tech_name,
customer.name as customer_name,
qa.name as qa_name
from Workorders
inner join User as tech on tech.userId = Workorders.techId
inner join User as customer on customer.useId = Workorders.CustomerId
inner join User as qa on qa.useId = Workorders.QAID
(Might need some tunning, but the idea should be here)
ie, you are :
starting with a workorder
inner join on its tech guy (a User),
and then inner joinning on its customer (another user)
and so on
And this allows you to get each name, using the right alias in the select clause.
Note that I used aliases in the select clause too -- that might be usefull to have "worker_name" and "tech_name", instead of just two columns names "name" -- especially if you are calling this query from some other programming language.
Note : if one of those userId field can be NULL, you might want to use a left join, instead of an inner join.
select tus.Name as 'TechnicianName',
cus.Name as 'CustomerName',
qus.Name as 'QaName',
wod.*
from WorkOrders wod
left outer join
Users tus on tus.UserId = wod.TechId
left outer join
Users cus on cus.UserId = wod.CustomerId
left outer join
Users qus on qus.UserId = wod.QaId