I have 3 tables:
products table
--------------
id
name
...
categories table
----------------
id
name
...
product_categories table
------------------------
product_id
category_id
And join them by this query:
select p.*
from products p
join product_categories pc on pc.product_id = p.id
join categories c on pc.category_id = c.id
This query return multiple records of a product per each category of that product, but I want to get only one product and multiple category of that product.
This is my output:
p.Id p.name --> cat_id cat_name
1 product_1 --> 1 cat1
1 product_1 --> 3 cat3
1 product_1 --> 2 cat2
1 product_1 --> 6 cat6
2 product_2 --> 5 cat5
2 product_2 --> 1 cat1
.
.
.
And desired output:
p.Id p.name --> cat_id cat_name,cat_id cat_name,...
1 product_1 --> 1 cat1,3 cat3,2 cat2,6 cat6
2 product_2 --> 5 cat5,1 cat1
.
.
.
How can I do that?
You should add WHERE clause to specify ID and in select clause maybe you want to use c.* instead of p.* to get all data from categories.
select p.name, c.*
from products p
join product_categories pc on pc.product_id = p.id
join categories c on pc.category_id = c.id
where p.id = --smth
If you don't want the redundancy of the product records, in other words you only want the category information and nothing else, then you don't need the join to the main products table in the first place (assuming you're using the product id).
However, you're problem is that unless you're planning to display a column for every possible category and whether the product has it or not then you're going to need to do a work around. My preferred approach would be to create a cursor that runs through each row and pulls the categories for a given product id into a single string and puts this string into a new table (product id, categories).
DECLARE #productId int
DECLARE #prevProductId int
SET #prevProductId = 0
DECLARE #cid int
DECLARE #cname nvarchar(255)
DECLARE #categoryList nvarchar(max)
SET #categoryList = ''
DECLARE #ProdCatTable TABLE
(
ProductId int,
Categories nvarchar(max)
)
DECLARE category_cursor CURSOR FOR
SELECT pc.product_id, c.id, c.name
FROM categories c
JOIN product_categories pc
ON pc.category_id = c.id
ORDER BY pc.product_id
OPEN category_cursor
FETCH NEXT FROM category_cursor
INTO #productId, #cid, #cname
WHILE ##FETCH_STATUS = 0
BEGIN
IF #prevProductId = 0
BEGIN
SET #categoryList = #cid + ' ' + #cname
SET #prevProductId = #productId
END
ELSE IF (#prevProductId <> #productId) AND #categoryList <> ''
INSERT INTO #ProdCatTable (ProductId, Categories)
VALUES (#prevProductId, #categoryList)
SET #prevProductId = #ProductId
SET #categoryList = ''
ELSE
BEGIN
SET #categoryList = #categoryList + ', ' + #cid + ' ' + #cname
END
FETCH NEXT FROM category_cursor
INTO #productId, #cid, #cname
END
CLOSE category_cursor
DEALLOCATE category_cursor
SELECT ProductId, Catgories
FROM #ProdCatTable
NOTE: This hasn't been tested, but I think it should work if you're happy to return a table with the product id as your identify and the categories as a string.
SELECT Tbl_Emp.EMPId, Tbl_Customer.First_Name, Tbl_Mail_IDs.MailId
FROM Tbl_Emp INNER JOIN
Tbl_Mail_IDs ON Tbl_Emp.EMPId = Tbl_Mail_IDs.Id INNER
JOIN
Tbl_Customer ON Tbl_Mail_IDs.Id = Tbl_Customer.Customer_Id
Related
I am having an issue trying to create a pivot table. I am joining some tables and need to pivot the car model column. For example my tables are:
Person
Id
FirstName
LastName
1
Mary
Ford
2
John
Murphy
3
Cathal
Gibsey
Cars
Id
Description
1
Toyota
2
Ford
3
BMW
4
Hyundaii
5
Volvo
Person-Car
Id
Car
1
1
1
2
1
5
2
3
3
4
3
5
My preferred output would be the description column pivoted as columns:
Id
FirstName
LastName
Toyota
Ford
BMW
Hyundaii
Volvo
1
Mary
Ford
TRUE
TRUE
TRUE
2
John
Murphy
TRUE
3
Cathal
Gibsey
TRUE
TRUE
My Query is:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX);
DECLARE #Columncars AS NVARCHAR(MAX);
SELECT #Columncars= ISNULL(#Columncars + ',','')
+ QUOTENAME([CDescription])
FROM (
select distinct Description [Columncars]
from Cars
) As Carsssss
select #Columncars
IF OBJECT_ID('tempdb.dbo.##CandidateCarsTable ', 'U') IS NOT NULL
DROP TABLE ##CandidateCarsTable ;
SET #DynamicPivotQuery =
N'Select distinct * into ##CandidateCarsTable
FROM (
select p.firstname, p.lastname, count(c.Id) as''carCount'',
case when c.Description is null then ''N/A'' + N'':car '' else c.Description + N'':car '' end as personCar
from person p
inner join Person-Car pc on pc.Id = p.Id
Inner join cars c on c.Id = pc.Car
PIVOT(MAX(carCount)
FOR [personCar] IN (' + #ColumnCars + ')) AS PVTTable1'
EXEC sp_executesql #DynamicPivotQuery
select * from ##CandidateCarsTable
I cannot seem to get it correct. Any help would be appreciated. Thanks
EDIT, My tables look perfectly find on preview and then change once saved.
This is a static sql. I quess it produces the output you want for example data. The query enumerates all possible person/car pairs and checks if the pair really exists. Change your dynamic sql building code accordingly
Select distinct *
FROM (
select firstname, lastname, [BMW],[Ford],[Hyundaii],[Toyota],[Volvo]
from (
select p.firstname, p.lastname, c.description, case when pc.car is not Null Then N'TRUE' end flag
from person p
cross join cars c
left join PersonCar pc on pc.Id = p.Id and c.Id = pc.Car
) t
PIVOT(MAX(flag) FOR [description] IN ([BMW],[Ford],[Hyundaii],[Toyota],[Volvo])) AS PVTTable1
) t;
Looks like the simpler version will do as unique person.id is included in your last edit.
select id, firstname, lastname, [BMW],[Ford],[Hyundaii],[Toyota],[Volvo]
from (
select p.id, p.firstname, p.lastname, c.description, case when pc.car is not Null Then N'TRUE' end flag
from person p
left join PersonCar pc on pc.Id = p.Id
left join cars c on c.Id = pc.Car
) t
PIVOT(MAX(flag) FOR [description] IN ([BMW],[Ford],[Hyundaii],[Toyota],[Volvo])) AS PVTTable1
db<>fiddle
BEGIN
DECLARE #SQLQuery AS NVARCHAR(MAX)
IF(#Search IS NOT NULL)
BEGIN
DECLARE #dyColumn sysname ;
IF(#Filter = 'IsNew')
BEGIN
SET #dyColumn = 'IsNew'
END
ELSE IF(#Filter = 'IsOnSale')
BEGIN
SET #dyColumn = 'IsOnSale'
END
ELSE IF(#Filter = 'IsFeatured')
BEGIN
SET #dyColumn = 'IsFeatured'
END
SET #SQLQuery = 'SELECT P.*, C.Id AS CategoryId, C.Name AS CategoryName, C.Logo AS CategoryLogo,
CO.Id AS CompanyId, CO.Name AS CompanyName, CO.Logo AS CompanyLogo, COUNT(*) OVER() TotalCount
FROM Products P
JOIN Categories C ON P.CategoryId = C.Id
JOIN Companies CO ON P.CompanyId = CO.Id
WHERE P.Name LIKE %'+#Search+'% AND '+#dyColumn+' = true
ORDER BY P.Name
OFFSET '+CAST(#PageSize AS nvarchar(100))+'*('+CAST(#PageNumber AS nvarchar(100)) +'- 1) ROWS
FETCH NEXT '+CAST(#PageSize AS nvarchar(100))+'ROWS ONLY OPTION (RECOMPILE);'
EXECUTE(#SQLQuery)
END
This is the query and its giving this error during run time
Incorrect syntax near '2'.
Invalid usage of the option NEXT in the FETCH statement.
which means query getting wrong after
WHERE P.Name LIKE %'+#Search+'%
you don't need dynamic sql for this just test for the value of the filter value in combination with the column in your WHERE expression:
SELECT
P.*
,C.Id AS CategoryId
,C.Name AS CategoryName
,C.Logo AS CategoryLogo
,CO.Id AS CompanyId
,CO.Name AS CompanyName
,CO.Logo AS CompanyLogo
,COUNT(*) OVER() TotalCount
FROM
Products P
JOIN Categories C
ON P.CategoryId = C.Id
JOIN Companies CO
ON P.CompanyId = CO.Id
WHERE
#Search IS NOT NULL
AND P.Name LIKE '%' + #Search + '%'
AND (
(#Filter= 'IsNew' AND IsNew = 1)
OR (#Filter= 'IsOnSale' AND IsOnSale = 1)
OR (#Filter= 'IsFeatured' AND IsFeatured = 1)
OR (#Filter NOT IN ('IsNew','IsOnSale','IsFeatured'))
)
ORDER BY
P.Name
OFFSET (#PageSize)*(#PageNumber)- 1 ROWS
FETCH NEXT (#PageSize) ROWS ONLY OPTION (RECOMPILE);
If you really want to use dynamic SQL instead of Executing it SELECT #SQLQuery and then look for the syntax issues by copying to another query window.
I need a query that select customer table with right cardId by applied the below cases.
If you have any suggestions, please share.
Possible cases are:
Only one records found - easy, use the Card_id found
No records found - leave blank
More than one record found - use the Card_id that starts with 2000 if available, otherwise pick the one with latest created date (in CustomerCards table)
Customer Table:
ID CardID
1 200132
2 263987
3 100789
..
CustomerCards table
CustomerId CardID CreatedOn
1 209890 12/11/2014
1 200132 12/12/2014
1 100732 11/10/2014
2 168902 12/11/2014
2 263987 15/01/2015
I've started with left join:
select ct.* from dbo.Customer ct
left join dbo.CustomerCard cc
on ct.id = cc.customerId
And a bit stuck after that.
A start
;with cte1 as
(
select cc.CustomerId, cc.CardID, cc.CreatedOn
from dbo.CustomerCard cc
group by cc.CustomerId, cc.CardID, cc.CreatedOn
having count(*) = 1
), cte200 as
(
select cc.CustomerId, cc.CardID, max(cc.CreatedOn)
from dbo.CustomerCard cc
group by cc.CustomerId, cc.CardID
where cc.CardID like '2000%'
)
select cte1
union
select cte2000
union
select ct.ID, ct.CardID, '1/1/1900' as CreatedOn
from dbo.Customer ct
left join dbo.CustomerCard cc
on ct.id = cc.customerId
where cc.customerId is null
union
select cc.ID, cc.CardID, max(cc.CreatedOn)
from dbo.CustomerCard cc
left join cte1
on cte1.customerId = cc.customerId
left join cte2000
on cte2000.customerId = cc.customerId
where cte1.customerId is null
and cte2000.customerId is null
group by cc.ID, cc.CardID
Hello I need to do the follow query in SQL Server to fill and Datatable.
In my case I have 3 tables:
1 - Users
2 - Process
3 - Status
Users
id, name
Process
id, cod_user, cod_status
Status
id, status
I need to make an query that return the follow table:
User.Name | Status.Created | Status.Opened | Status.Finalized
Tom 50 30 20
Roger 22 33 44
Kris 11 09 05
And then, I have to return this table to fill and datatable.
Thanks...
Looks like you are trying to PIVOT the data, you can use something like this if you know the values of status to transform:
select name, [Created], [Opened], [Finalized]
from
(
select u.name,
s.status
from users u
left join process p
on u.id = p.cod_user
left join status s
on p.cod_status = s.id
) src
pivot
(
count(status)
for status in ([Created], [Opened], [Finalized])
) piv
If you have an unknown number of statuses to turn into columns, then you can use dynamic sql:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(status)
from status
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT name, ' + #cols + ' from
(
select u.name,
s.status
from users u
left join process p
on u.id = p.cod_user
left join status s
on p.cod_status = s.id
) x
pivot
(
count(status)
for status in (' + #cols + ')
) p '
execute(#query)
If you don't have access to the PIVOT function, then you can replicate it using an aggregate function and a CASE statement:
select u.name,
sum(case when s.status = 'created' then 1 else 0 end) created,
sum(case when s.status = 'opened' then 1 else 0 end) opened,
sum(case when s.status = 'finalized' then 1 else 0 end) finalized
from users u
left join process p
on u.id = p.cod_user
left join status s
on p.cod_status = s.id
group by u.name
Looks like you're trying to show one record per User, with one column per Status, and the columns contain the count of records in the Process table with that status for that user?
If that's correct, then you want to use a Pivot Table.
if not exists(SELECT 1 FROM MYTABLE1 WHERE ID=#ID)
BEGIN
END
I want to check for this ID value in MYTABLE2 as well..how should I write the IF condition ?? i want to check that a certain ID doesnt exist in any of the two tables.
You could use an UNION ALL:
IF NOT EXISTS (SELECT 1 FROM
(SELECT ID FROM MyTable1
UNION ALL
SELECT ID FROM MyTable2) Table
WHERE ID = #ID)
BEGIN
...
END
You could do the following:
if (not exists(SELECT 1 FROM MYTABLE1 WHERE ID=#ID))
AND (not exists(SELECT 1 FROM MYTABLE2 WHERE ID=#ID))
BEGIN
END
Depends on what you want -
If you want to check that the ID exists in either ONE of the tables then use UNION ALL. you could use JNK's answer.
If you want to check that the ID exists in both tables then use INNER JOIN.
If not exists
(select top 1 from table1 a inner join
Table2 b on a.ID = b.ID where a.ID = #ID)
BEGIN
END
Hope this helps.
SELECT
blah.ID
FROM
MYTABLE1 as blah
WHERE
blah.ID IN (some range of ints)
If you get no results then you know it does not exist