SQL Query between three tables, get data only from one table - sql

I have these 3 tables:
product table
id
siteId
optionsSet table
id
productId
...
option table
id
optionsSetId
code
...
Question:
How can I make a SQL query to select all from option table by knowing these two: option.code and product.siteId ?
I know how to do a query with JOIN on two tables, but I am struggling with joining these three tables.

Something like
SELECT
*
FROM
option
WHERE
code = #code
AND optionsSetId IN
(SELECT
os.id
FROM
optionsSet os
JOIN product p ON os.productId = p.Id
WHERE
p.siteId = #siteId)
where #code is your code parameter and #siteId is your siteid parameter
to use inner joins you would have to join all 3 tables together and that would like
SELECT
DISTINCT o.*
FROM
option o
JOIN optionsSet os ON o.optionsSetId = os.Id
JOIN product p ON os.productId = p.Id
WHERE
o.code = #code
AND p.siteId = #site
if you notice that requires a DISTINCT to only get the data from option. It may be simpler and easier to understand but not very efficient.
another option that someone will probably say is way more awesome is using EXISTS
SELECT
o.*
FROM
OPTION o
WHERE
o.code = #code
AND EXISTS(
SELECT
1
FROM
optionsSet os
JOIN product p ON os.productId = p.Id
WHERE
o.optionSetId = os.Id
AND p.siteId = #siteId
)
I used EXISTS exclusively for a few years and the started working on databases with tables that had +100million records and IN was faster than EXISTS in some cases and identical in the others. Plus IN is less code.

SELECT * FROM option
LEFT JOIN product
ON option.code = product.siteId (+)
--(+) is a left outter join. This should include all of the values in option.code and all of the values in product that have the same siteId as values in option.
I'm unsure on how you want OptionSet to relate to the other 2 databases though?
if you want to include the third tables result you can just add another join on that table for the condition you want.

Related

How to build a complex sql query?

Database design here
I want to get records from the product_spec_data table that are associated with products whose category_id is 5.
Please help me make a query to the database...
All of the relationship are clearly laid out, a simple join across tables would works.
SELECT psd.*
FROM product_spec_data psd
INNER JOIN product_spec_values psv ON psd.id = psv.product_spec_data_id
INNER JOIN products prod ON psv.product_id = prod.id
INNER JOIN categories cat ON prod.category_id = cat.id
-- with category id = 5
WHERE cat.id = 5;
I am not sure what do you mean by complex query. I guess your question is not complete. I think the query for your question (if it is T-SQL) will be as follows
select d.*
from product_spec_data d
left outer join product_spec_values v on d.id=v.product_spec_data_id
left outer join products p on v.product_id=p.id
where p.category_id=5
(I think in MySQL also above syntax will remain same, you may remove [outer] clause in MySQL)

How to put conditions on left joins

I have two tables, CustomerCost and Products that look like the following:
I am joining the two tables using the following SQL query:
SELECT custCost.ProductId,
custCost.CustomerCost
FROM CUSTOMERCOST Cost
LEFT JOIN PRODUCTS prod ON Cost.productId =prod.productId
WHERE prod.productId=4
AND (Cost.Customer_Id =2717
OR Cost.Customer_Id IS NULL)
The result of the join is:
joins result
What i want to do is when I pass customerId 2717 it should return only specific customer cost i.e. 258.93, and when customerId does not match then only it should take cost as 312.50
What am I doing wrong here?
You can get your expected output as follows:
SELECT Cost.ProductId,
Cost.CustomerCost
FROM CUSTOMERCOST Cost
INNER JOIN PRODUCTS prod ON Cost.productId = prod.productId
WHERE prod.productId=4
AND Cost.Customer_Id = 2717
However, if you want to allow customer ID to be passed as NULL, you will have to change the last line to AND Cost.Customer_Id IS NULL. To do so dynamically, you'll need to use variables and generate the query based on the input.
The problem in the original query that you have posted is that you have used an alias called custCost which is not present in the query.
EDIT: Actually, you don't even need a join. The CUSTOMERCOST table seems to have both Customer and Product IDs.
You can simply:
SELECT
Cost.ProductId, Cost.CustomerCost
FROM
CUSTOMERCOST Cost
WHERE
Cost.Customer_Id = 2717
AND Cost.productId = 4
You seem to want:
SELECT c.*
FROM CUSTOMERCOST c
WHERE c.productId = 4 AND c.Customer_Id = 2717
UNION ALL
SELECT c.*
FROM CUSTOMERCOST c
WHERE c.productId = 4 AND c.Customer_Id IS NULL AND
NOT EXISTS (SELECT 1 FROM CUSTOMERCOST c2 WHERE c2.productId = 4 AND c2.Customer_Id = 2717);
That is, take the matching cost, if it exists for the customer. Otherwise, take the default cost.
SELECT custCost.ProductId,
custCost.CustomerCost
FROM CUSTOMERCOST Cost
LEFT JOIN PRODUCTS prod
ON Cost.productId =prod.productId
AND (Cost.Customer_Id =2717 OR Cost.Customer_Id IS NULL)
WHERE prod.productId=4
WHERE applies to the joined row. ON controls the join condition.
Outer joins are why FROM and ON were added to SQL-92. The old SQL-89
syntax had no support for them, and different vendors added different,
incompatible syntax to support them.

Inner join SQL 2 tables

I need help making a inner join.
I have to tables, one named Cycletype and the other Cykler.
Cycletype has a column named Type. In this column I have named the different type of cycles.
On my other table Cykler I have some columns with data about the cycles and a fk_cycletype_Id column so that they can link to eachother.
My problem is that I dont know how to write the code in my CS file.
This is what I have written so far(not working):
SELECT * FROM Cykler
INNER JOIN Cycletype
ON Cykler.fk_cycletype_Id = id
WHERE id = #id
I havent much experience with inner joins so I am completely lost and I am in big need of help.
On my frontend page I have 6 different pictures with the different types of cycles so that when I click on mountainbikes, for example, it should show all mountainbikes from Cykler. But i need help if anyone can, please?
http://imgur.com/RnL93cY
picture description of the tables
It's hard to tell without seeing the rest of your columns names...
But...is it possible that your "id" column exists in both tables... thus naming the table fixes the issue...
SELECT * FROM Cykler
INNER JOIN Cycletype ON Cykler.fk_cycletype_Id = Cycletype.id
WHERE Cycletype.id = #id
Based on your question and comments, your query should be :
SELECT * FROM Cykler
INNER JOIN Cycletype
ON Cykler.fk_cycletype_Id = Cycletype.Cycletype_Id
WHERE Cycletype_Id = #id
select *
from Cykler c
inner join CycleType ct on ct.ID = c.fk_cycletype_Id
where c.ID = #ID
You could then access the Type's by selecting ct.Type, or whatever the name of the Type field is in CycleTypes.
EDIT -- after seeing your second picture
This should work:
select ct.Type
from Cykler c
inner join Cycletype ct on ct.Cycletype_Id = c.fk_cycletype_Id
where c.ID = #ID
I put ct.Type in the select, but of course you could select whatever you need.

Query with columns from 4 tables in SQL

Can anyone who knows SQL, specifically the flavor used in Microsoft Access 2013, tell me what I'm doing wrong here?
SELECT custid, custname, ordno, itemno, itemname
FROM cust
INNER JOIN order
ON cust.custid = order.custid
INNER JOIN orderitems
ON order.ordno = orderitems.ordno
INNER JOIN inv
ON orderitems.itemno = inv.itemno;
I've already read other, similar questions, and tried the methods they used in their solutions, but I'm getting a "Syntax error in FROM clause.", almost no matter what I try.
* * *
SOLUTION: Thanks for the replies! In addition to adding square brackets around "order" and using TableName.ColumnName syntax in SELECT, I had to use parentheses for my multiple INNER JOINs. Here is the fixed code:
SELECT cust.custid, cust.custname, [order].ordno, orderitems.itemno, inv.itemname
FROM ((cust
INNER JOIN [order]
ON cust.custid = [order].custid)
INNER JOIN orderitems
ON [order].ordno = orderitems.ordno)
INNER JOIN inv
ON orderitems.itemno = inv.itemno;
SELECT cust.custid --<-- Use two part name here
,cust.custname
,[order].ordno
,orderitems.itemno --<-- Only guessing here use the correct table name
,inv.itemname --<-- Only guessing here use the correct table name
FROM cust
INNER JOIN [order]
ON cust.custid = [order].custid --<-- used square brackets [] around ORDER as it is
INNER JOIN orderitems -- a key word.
ON [order].ordno = orderitems.ordno
INNER JOIN inv
ON orderitems.itemno = inv.itemno;
In your Select Statament you need to use Two Part name i.e TableName.ColumnName since these column can exist in more than one Tables in your FROM clause you need to tell sql server that columns in your select coming from which table in your from clause.

Query on Many to Many tables with multiple OR/AND

I have a basic many-to-many table that is:
tbFilter
filterId | filterName
tbProduct
productId | productName
tbProductFilter
filterId | productId
So, I have many products with many filters (colors, sizes, etc). Now, I need to create a procedure to finde products with some filter combination, like:
All products that is(blue OR green) and (large OR xlarge) and (forMen)
The only way that I found to create this query is with multiple joins of same table, each join for a "group" filter or with multiples subqueries, each one for a group. The biggest problem is that the many-to-many table have more them 100k records, so this approaches give a poor performance.
How is the best way to do this query? I'm using sql 2012.
Thanks
This is how I get working now:
select [produtos].* FROM [dbo].[tbProdutos] AS [produtos] JOIN [dbo].tbJuncaoProdutoCategoria] AS [juncaoProdutoCategoria] ON [produtos].[produtoId] = juncaoProdutoCategoria].[produtoId] JOIN [dbo].[tbJuncaoProdutoCategoria] AS juncaoProdutoCategoria2] ON [produtos].[produtoId] = [juncaoProdutoCategoria2].[produtoId] JOIN [dbo].[tbProdutoCategoria] AS [produtoCategoria] ON [produtoCategoria].[categoriaId] = [juncaoProdutoCategoria].[categoriaId] where [juncaoProdutoCategoria].categoriaId = 1 AND ([juncaoProdutoCategoria2].categoriaId = 300 OR [juncaoProdutoCategoria2].categoriaId = 301)
Put the filters into a table (or a table-valued parameter), join that to the ProductFilter table, group by product, and count the unique filters that get joined.
This method can handle an arbitrary number of filters and perform fuzzy matching, i.e. "show me the products that match three of these four filters"
DECLARE #filterCount int = 3
DECLARE #filterSet TABLE ( filterNum int, filterName varchar(max) )
INSERT #filterSet VALUES
(1,'blue'),(1,'green'),
(2,'large'),(2,'xlarge'),
(3,'forMen')
SELECT pf.ProductId
FROM tbProductFilter pf
INNER JOIN tbFilter f ON f.filterId = pf.filterId
INNER JOIN #filterSet s ON s.filterName = f.filterName
GROUP BY pf.productId
HAVING COUNT(DISTINCT s.filterNum) = #filterCount
First of all, you most certainly want to check your indexing - you'll want indexes on all foreign key fields, as well as on the fitlerName.
Assuming your indexing is in good shape, here's one way you might do this:
SELECT p.* -- preferably just select the fields you need here...
FROM products p
WHERE p.productId IN (
SELECT pf.product_id
FROM tbProductFilter pf
WHERE EXISTS (SELECT 1 FROM tbFilter f
WHERE pf.filterId = f.filterId AND f.filterName IN ('blue', 'green'))
AND EXISTS (SELECT 1 FROM tbFilter f
WHERE pf.filterId = f.filterId AND f.filterName IN ('large', 'xlarge'))
AND EXISTS (SELECT 1 FROM tbFilter f
WHERE pf.filterId = f.filterId AND f.filterName = 'forMen')
)