SQL Server multiple table JOIN - sql

I have 3 tables
Table 1 [StockItem] contains information about an item, I need only the Id from this table
Table 2 [Categories] contains the categories and subcategories with their names and URL slug
Table 3 [ItemCategories] contains the categories for each item and has only two columns, CategoryId and StockItemId
I have this query which now returns the category id and combined slug as category/subcategory...
WITH categoryPath(Id, Slug)
AS
(
SELECT
Id, Slug
FROM
Categories
WHERE
ParentCategoryId IS NULL
UNION ALL
SELECT
Categories.Id
,CAST(categoryPath.Slug + '/' + categories.Slug AS NVARCHAR(150))
FROM
Categories
JOIN
categoryPath ON Categories.ParentCategoryId = categoryPath.Id
)
SELECT *
FROM ItemCategories
JOIN categoryPath ON ItemCategories.StockId = categoryPath.Id
WHERE ItemCategories.StockId = 5
The result of this query looks like this:
What I want is to add to the result the Category Name from the [Categories] table which have the column [CategoryName], but I don't know how to add another JOIN to this already complex query.

If the column is indeed in that table, then you can use this SELECT in the CTE.
You don't need another join, you just need the name column to be part of the categoryPath CTE.
SELECT Id,
,Slug
,CategoryName
FROM Categories
WHERE ParentCategoryId IS NULL
UNION ALL
SELECT Categories.Id
,CAST(categoryPath.Slug + '/' + categories.Slug AS NVARCHAR(150))
,CategoryName
FROM Categories
Don't forget to update the CTE definition with:
WITH categoryPath(Id,Slug,CategoryName)

Related

SQL join based on select as column name

So in one table I can use a replace and charindex to extract a specific ID that relates to a PK in another table, I want to then join the data from the other table based on the trimmed value, how can I do this?
select top 100 *, Replace(Left(LogValue,Charindex(';', LogValue) - 1) ,'RtaId=', '') as TaskID, PrmRoutingTask.*
from SytLog
inner join PrmRoutingTask on RtaId = TaskID
where LogTableName like '%Routing%' and LogValue like '%RtaAniId=397%'
order by 5 desc;
The problem I get is that the temp column name I create (TaskID) is not working in the inner join where in fact the results of TaskID have the reference to the RtaId in the RoutingTask table.
Assuming LogValue belongs to the first table you can use the column named TaskID if you produce a subquery as a table expression of the main query.
For example you can produce the column in the table expression a by doing:
select top 100
a.*,
PrmRoutingTask.*
from (
select *,
Replace(Left(LogValue,Charindex(';', LogValue) - 1) ,'RtaId=', '') as TaskID
from SytLog
) a
inner join PrmRoutingTask on PrmRoutingTask.RtaId = a.TaskID
where LogTableName like '%Routing%'
and LogValue like '%RtaAniId=397%'
order by 5 desc

SQL Server: Query for products with matching tags

I have been pondering over this for the past few hours but I cannot find a solution.
I have a products in a table, tags in another table and a product/tag link table.
Now I want to retrieve all products which have the same tags as a certain product.
Here are the tables (simplified):
PRODUCT:
id varchar(36) (primary key)
Name varchar(50)
TAG:
id varchar(36) (primary key)
Name varchar(50)
PRODUCTTAG:
id varchar(36) (primary key)
ProductID varchar(36)
TagID varchar(36)
I find quite a few answers here on Stackoverflow talking about returning full and partial matches. However I am looking for a query which only gives full matches.
Example:
Product A has tags 1, 2, 3
Product B has tags 1, 2
Product C has tags 1, 2, 3
Product D has tags 1, 2, 3, 4
If I query for product A, only product C should be found - as it is the only one having exactly the same tags.
Is this even possible?
Yes, yes, try this way:
with aa as (
select count(*) count
from [PRODUCTTAG]
where ProductID = '19A947C0-6A0F-4A6F-9675-48FBE30A877D'
), bb as
(
select ProductID, count(*) count
from [PRODUCTTAG]
group by ProductID
)
select distinct b.ProductID
from [dbo].[PRODUCTTAG] a join
[dbo].[PRODUCTTAG] b on a.TagID = b.TagID cross join
aa join
bb on aa.count = bb.count and b.ProductID = bb.ProductID
where a.ProductID = '19A947C0-6A0F-4A6F-9675-48FBE30A877D'
declare #PRODUCTTAG table(id int identity(1,1),ProductID int,TagID int)
insert into #PRODUCTTAG VALUES
(1,1),(1,2),(1,3)
,(2,1),(2,2)
,(3,1),(3,2),(3,3)
,(4,1),(4,2),(4,3),(4,4)
;With CTE as
(
select ProductID,count(*)smallCount
FROM #PRODUCTTAG
group by ProductID
)
,CTE1 as
(
select smallCount, count(smallCount)BigCount
from cte
group by smallCount
)
,CTE2 as
(
select * from cTE c
where exists(
select smallCount from cte1 c1
where BigCount>1 and c1.smallCount=c.smallCount
)
)
select * from cte2
--depending upon the output expected join this with #PRODUCTTAG,#Product,#Tag
--like this
--select * from #PRODUCTTAG PT
--where exists(
--select * from cte2 c2 where pt.productid=c2.productid
--)
Or Tell what is final output look like ?
This is a case where I find it simpler to combine all the tags into a single string and compare the strings. But, that is painful in SQL Server until 2016.
So, there is a set based solution:
with pt as (
select pt.*, count(*) over (partition by productid) as cnt
from producttag pt
)
select pt.productid
from pt join
pt pt2
on pt.cnt = pt2.cnt and
pt.productid <> pt2.productid and
pt.tagid = pt2.tagid
where pt2.productid = #x
group by pt.productid, pt.cnt
having count(*) = pt.cnt;
This matches every product to your given product based on the tags. The having clause then ensures that the number of matching tags is the same for the two products. Because the join only considers matching tags, all the tags are the same.

How to get all child of a given id in SQL Server query

I have two tables in SQL Server database:
category(
itemid,
parentid
)
ArticleAssignedCategories(
categid,
artid
)
categid is a foreign key of itemid
I want to get count of artids and child of that for given itemid (child means categories with parentid of given itemid.)
For example; If given itemid = 1 and in table category have (3,1),(4,1)(5,3)
All of 3, 4, 5 are child of 1
Can anyone help me to write a good query?
Recursive queries can be done using CTE
with CTE(itemid, parentid)
as (
-- start with some category
select itemid, parentid
from category where itemid = <some_itemid>
union all
-- recursively add children
select c.itemid, c.parentid
from category c
join CTE on c.parentid = CTE.itemid
)
select count(*)
from ArticleAssignedCategories a
join CTE on CTE.itemid = a.categid
Here is the query. I hope this may help you
select b.artid,count(b.artid) from category a
inner join ArticleAssignedCategories b on a.itemid = b.artid
group by b.artid

Comparing 2 tables with Limited join options

I have this category group , which has 5 categories and Description(Display Text)of the categories . Fields(Category ID, Display Text)
And I have another view which has information about like Month,Gender,New(employee in Department),Transfer(Employee From another department) and Continuing(Same department) and Category ID .
Now I want to check if for each categoryID in the category table, if there are any New,transfer or Continuing according to the Gender and month.
For example, CategoryID =1 , Check in the view if there is any CategoryID=1 present then return all the details of the ID in the VIEW , If not just return 0 for every Gender and Month.
#EDIT:
select c.UniqueID,
c.DisplayText ,
s.Gender,
s.Term,
s.Status ,
s.NoofStatus
from Category c
left outer Join
Status_Count_View s on c.UniqueID=s.UniqueID
I want all the Records in Table A to be mapped on to Table B for every Term.. If no records in Table B are found for a particular Category in Table A still that Category has to be displayed with a value 0
select * from category c, cat_view cv where c.Cat_ID = cv.categoryID
union
select c.cat_id, c.DisplayText, 0 , 0 ,'',0,0,0
from category c
where c.Cat_ID not in (select distinct(categoryID) from cat_view)
Please edit column names according to your need. Key here is 'union'. First we get everything that matches. Then we get all category which doesn't match and add those into result (achieved by 'union' keyword).

SQL Query to select products from all categories of One Parent

I have a Product Table with this structure
id, title, slug, details, category(FK category.ID)
And a Category Table:
id, name, slug, parent
Categories have only 1 level
If there is no parent then parent field is 0 else id of parent category saved
Suppose I have categories structure like this:
FRUITS
|---- APPLE
|---- MANGO
|---- BANANA
I use a Category slug to query products from a category
category.php?cat=apple
category.php?cat=mango
1st query:
select id,name from category WHERE slug='$catslug'
After getting ID of category then use query to get results of that ID from products table
select * from products where category=$categoryid
What query is required if I want to fetch all products posted in FRUITS?
category.php?cat=fruits
I want to get all products posted in apple, mango, banana (all children of fruits)
Only the child IDs are saved in product table how do I link parent category apple with these?
You can look for categories linked to products where the parent category is the fruit category by using multiple joins. Here cc refers to the child category and cp refers to the parent category. We retrieve all products having a child category equal to the products category, and having a parent category to that child category equal to FRUITS:
select *
from products p
inner join categories cc on cc.category = p.category
inner join categories cp on cp.category = cc.parentcategory
where cp.category = 'FRUITS'
If this needs to be a generic solution that handles both parent and child categories seemlessly, you can check for a match at either level (assuming all category names are unique, and every product has a category):
select *
from products p
inner join categories cc on cc.category = p.category
left join categories cp on cp.category = cc.parentcategory
where cc.category = '$category' or cp.category = '$category'
1) You don't need to use two queries, you can use join:
SELECT p.id, p.title, p.slug ...
FROM products p
JOIN categories c ON c.id = p.category
WHERE c.slug = 'apple'
2) You can select all fruit products with this query:
SELECT id, title, slug ...
FROM products
WHERE category IN (
SELECT id
FROM categories
WHERE slug = 'fruits'
UNION
SELECT c.id
FROM categories c
JOIN categories c2 ON c2.id = c.parent
WHERE c2.slug = 'fruits'
)
I used 2nd query suggested by tarmaq
SELECT *
FROM products
WHERE category IN (
SELECT id
FROM category
WHERE slug = '$cats'
UNION
SELECT c.id
FROM category c
JOIN category c2 ON c2.id = c.parent
WHERE c2.slug = '$cats')";
Its showing results from products table only Not getting Category Name, Category Details from category table
I tried this:
SELECT *
FROM products
WHERE category IN (
SELECT *
FROM category
WHERE slug = '$cats'
UNION
SELECT *
FROM category c
JOIN category c2 ON c2.id = c.parent
WHERE c2.slug = '$cats')";
result: Error in Query.
also I want to JOIN users table in above query and to show author name(users.name) alongwith product (author id saved in product table which is FK from users table users.id is unique)
JOIN users on products.author = users.id
Where to put this Join statement in above query
EDIT - I joined user table with author name with this query
SELECT *
FROM products
JOIN users U ON U.id = products.author
WHERE category IN (
SELECT id
FROM category
WHERE slug = '$cats'
UNION
SELECT C.id
FROM category C
JOIN category C2 ON C2.id = C.parent
WHERE C2.slug = '$cats')
ORDER BY products.date DESC
now want to fetch data from category table catagory.name, category.details with this query