I need suggestions on how to re-factor my SQL Server query to improve performance. As you can see I am repeating Joins and would like to avoid it. This is just a snippet of my code so I am not including the JOIN ON, WHERE etc.
The task is to display all houses owned by a person in a single row as a concatenated string instead of 1 row for each house owned by a person. the database schema is organized this way that requires me to do multiple joins to get the info I need and unfortunately schema wont change.
select
distinct View1_outer.ID as PersonID
, stuff
(
(select ', ' + Name
from View1 View1_inner
inner join View2 View2_inner
inner join View3 View3_inner
inner join View4 View4_inner
where View1_inner.ID = View1_outer.ID
for XML path('')
)
,1,2,' ') as Houses
from View1 View1_outer
inner join View2 View2_outer
inner join View3 View3_outer
inner join View4 View4_outer
where View1_outer.ID = 'XXX'
This is one way of rewriting my initial query. I don't think I need to repeat the joins in my outer query.
select
distinct View1_outer.ID as PersonID
, stuff
(
(select ', ' + Name
from View1 View1_inner
inner join View2 View2_inner
inner join View3 View3_inner
inner join View4 View4_inner
where View1_inner.ID = View1_outer.ID
for XML path('')
)
,1,2,' ') as Houses
from View1 View1_outer
where View1_outer.ID = 'XXX'
Related
I am creating a stored procedure and would like to inner join between 4 different tables. The tables are names:
Category, SubCategory, Project, VisUser
SubCategory depends on Category and VisUser while Project depends on SubCategory.
When I run my stored procedure with the 3 inner joins, it returns the correct information - just duplicated 3 times.
I tried using distinct in the beginning and it does work to filter the records correctly however it may still run slow when running with a large amount of data with it outputting 3x the records.
Stored procedure:
DROP PROCEDURE IF EXISTS GetAllProjects
GO
CREATE PROCEDURE GetAllProjects
(#UserId INT)
AS
BEGIN
SELECT DISTINCT
proj.ProjectName, proj.ProjectDescription, sub.SubCategoryName
FROM
SubCategory AS sub
INNER JOIN
VisUser AS vis ON #UserId = sub.UserId
INNER JOIN
Category AS cat ON cat.CategoryId = sub.CategoryId
INNER JOIN
Project AS proj ON proj.SubCategoryId = sub.SubCategoryId
END
What part am I doing wrong here? I have a feeling it is because I am using 'sub' 3x in the inner joins. Is there a better approach for this?
INNER JOIN VisUser AS vis ON #UserId = sub.UserId
Will join on all VisUsers because you don't reference the table in the join condition.
As you don't actually use the VisUsers table just remove it as follows:
SELECT
DISTINCT proj.ProjectName, proj.ProjectDescription, sub.SubCategoryName
FROM SubCategory AS sub
INNER JOIN Category AS cat ON cat.CategoryId = sub.CategoryId
INNER JOIN Project AS proj ON proj.SubCategoryId = sub.SubCategoryId
WHERE sub.UserId = #UserId;
And if you do need the VisUsers table you can join on like this:
SELECT
DISTINCT proj.ProjectName, proj.ProjectDescription, sub.SubCategoryName
FROM SubCategory AS sub
INNER JOIN VisUser AS vis ON vis.UserId = sub.UserId
INNER JOIN Category AS cat ON cat.CategoryId = sub.CategoryId
INNER JOIN Project AS proj ON proj.SubCategoryId = sub.SubCategoryId
WHERE sub.UserId = #UserId;
when I run my query I get the result I'm after, however when I try to input that into a new table (INTO new_table_name) and review it after, the order of the original query is scrambled.
This is my query. Is it because the INTO-statment is before the ORDER BY-statment?
SELECT t.TABLE_SCHEMA AS [Parent],
t.TABLE_NAME AS [Object],
t.COLUMN_NAME AS [Type],
cd.value AS [Description]
FROM INFORMATION_SCHEMA.COLUMNS t
INTO new_table_name
INNER JOIN syscolumns c
ON c.name = t.COLUMN_NAME
LEFT OUTER JOIN sys.extended_properties cd
ON cd.major_id = c.id
AND cd.minor_id = c.colid
AND cd.name = 'MS_Description'
ORDER BY t.TABLE_NAME
If you want to see the data in order then use Order by while selecting the new table.
Though you used order by while inserting records into table that doesn't mean the records are stored in the data pages in same order or will be retrieved in that order.
Use Order by while selecting to see the result in order
select * from new_table_name
Order by Object
I have the following tables.
Customer Customer_id, Customer_name
Customer_details Customer_id,Phone_no,Address
Order_details Order_id,Customer_id,Order_type
I have created a view as following
Create view Orders_Analysis
Select c.Customer_id,cd.phone_no,od.order_id
From customer c
inner join order_details od
on c. Customer_id=od. Customer_id
Inner join Where c. Customer_id=cd. Customer_id
cd. Customer_id=c.Customer_id
Now using the above view and pre mentioned tables I have to extract only those records in the view which are of a particular order_type.
Can you guys suggest me a method.
First of all, You have some mistake in View, This is the correct View after fix mistakes
Create view Orders_Analysis
Select c.Customer_id,cd.phone_no,od.order_id
From customer c
INNER JOIN order_details od
ON c.Customer_id = od.Customer_id
INNER JOIN Customer_details CD
ON c.Customer_id = cd.Customer_id
Now You want to extract only those records in the view which are of a particular order_type.
Solution One:- Because you dont have column order_type in View then use INNER JOIN
SELECT *
FROM Orders_Analysis OA
INNER JOIN Order_details OD
ON OA.order_id = OD.order_id
WHERE OD.Order_type = your value here
Solution Two:-
Otherwise Add Order-Type column in View
Create view Orders_Analysis
Select c.Customer_id,cd.phone_no,od.order_id,od.order_type
From customer c
INNER JOIN order_details od
ON c.Customer_id = od.Customer_id
INNER JOIN Customer_details CD
ON c.Customer_id = cd.Customer_id
and use
Select * from Orders_Analysis where Order_Type = your value here
You need to add the field, od.order_type, to the Select statement results set in your view definition:
SELECT c.Customer_id,cd.phone_no,od.order_id,od.Order_type
Then, if you run a select against the view, specify a WHERE clause on the order_type field for the value you are looking for.
Update your view and select also order type
Select c.Customer_id,cd.phone_no,od.order_id, od.Order_type
You can now execute select query using the view you created
Select * from Orders_Analysis where Order_Type = "any value"
i want to create a Index View for full text search.
the only problem i,m facing with subquery, because index views does not allow subquery.
below is my query
ALTER VIEW [dbo].[Demo] with SCHEMABINDING AS
select distinct a.ID,a.Title, a.Description ,b.Name as Recipe, c.Name as Taste , d.Name as CuisineType,
STUFF((SELECT ',' + Name FROM dbo.Ingredients where ID in (select IngredientID from dbo.listingIngredients
where listingid = a.ID ) FOR XML PATH('')), 1, 1, '') as Ingredients
from dbo.Listing as a
inner join dbo.RecipeType b on a.RecipeTypeID = b.ID
inner join dbo.taste c on a.tasteID = c.ID
inner join dbo.CuisineType d on a.CuisineTypeID = d.ID
inner join dbo.listingIngredients e on a.ID = e.listingID
GO
I,m using subquery to get ingredients as concatenate string from Ingredients table using STUFF.
can some one please let me know how can i remove this subquery and have ingredients as contented string.
please let me know
regards
manish
The XML part of the query will cause problems, even if you did manage to remove the sub-selected.
However, all is not lost. You could rewrite the view into a part that can be indexed and another part that is cheaper, but can't. For example, you could write:
ALTER VIEW [dbo].[Demo_Part] with SCHEMABINDING AS
select a.ID,a.Title
, a.Description
, b.Name as Recipe
, c.Name as Taste
, d.Name as CuisineType
, e.name
from dbo.Listing as a
inner join dbo.RecipeType b on a.RecipeTypeID = b.ID
inner join dbo.taste c on a.tasteID = c.ID
inner join dbo.CuisineType d on a.CuisineTypeID = d.ID
inner join dbo.listingIngredients e on a.ID = e.listingID
GROUP BY a.ID,a.Title
, a.Description
, b.Name as Recipe
, c.Name as Taste
, d.Name as CuisineType
, e.name
Depending on your data model, you may not even need the group by. This view can be indexed
And then write another view that is not indexed, but which replaces your original view
CREATE VIEW [dbo].[Demo]
SELECT ...
STUFF (...)
FROM [dbo].[Demo_Part]
As a meta-answer I would add that if you need to index a view like this (and use the DISTINCT), chances are that your data modeller made a pretty big mistake with the data model or that your data access code is very inefficient. Everything about this smells like you are trying to work around poor coding and modelling practices.
I'm using an stored procedure in SQL server, but it is giving me some duplicate records, of course I don't have duplicate records in my database, but my stored procedure is giving me two instances of a same record, what can be wrong? how can I prevent my query from giving duplicate records?
it is my SP select clause:
select (ROW_NUMBER() OVER (ORDER BY Review.Point desc) ) as rownumber,
Business.BusinessId,Business.BName,Business.BAddress1
,Business.BAddress2,Business.BCity,Business.BState,Business.BZipCode,Business.countryCode,Business.BPhone1,Business.BPhone2,Business.BEmail,Business.Keyword
,Business.BWebAddress,Business.BCatId,Business.BSubCatId,Business.BDetail,Business.bImage,Business.UCId,Business.UCConfirm
,Business.UOId,Business.UOConfirm,Business.x,Business.y,Cat.CatName,SubCat1.SubCatName
from Business left outer join
Review on business.BusinessId=Review.BusinessId left outer join
Cat on business.BCatid=Cat.CatId left outer join
SubCat1 on business.BSubCatid=SubCat1.SubCatId '+#sql2+'
) as tbl
where rownumber between '+CONVERT(varchar, #lbound)+' and '+CONVERT(varchar, #ubound);
I don't know your data to dig in to your join logic, but if it duplicating across BusinessID, you could add another ROW_NUMBER() for the duplicates:
select (ROW_NUMBER() OVER (ORDER BY Review.Point desc) ) as rownumber,
r = ROW_NUMBER()OVER(PARTITION BY Business.BusinessId ORDER BY Business.BusinessId)
Business.BusinessId,Business.BName,Business.BAddress1
,Business.BAddress2,Business.BCity,Business.BState,Business.BZipCode,Business.countryCode,Business.BPhone1,Business.BPhone2,Business.BEmail,Business.Keyword
,Business.BWebAddress,Business.BCatId,Business.BSubCatId,Business.BDetail,Business.bImage,Business.UCId,Business.UCConfirm
,Business.UOId,Business.UOConfirm,Business.x,Business.y,Cat.CatName,SubCat1.SubCatName
from Business left outer join
Review on business.BusinessId=Review.BusinessId left outer join
Cat on business.BCatid=Cat.CatId left outer join
SubCat1 on business.BSubCatid=SubCat1.SubCatId '+#sql2+'
) as tbl
where rownumber between '+CONVERT(varchar, #lbound)+' and '+CONVERT(varchar, #ubound)
AND r = 1;
Include the reserved word DISTINCT in your query.
eg
select distinct
*
from
students s
inner join enrollments e on e.StudentId = s.Id
inner join courses c on c.Id = e.CourseId
However, unexpected duplicates in a result table is often (but not always) a clue that you have a badly formed query or a badly designed database.
Try to remove this left join
Review on business.BusinessId=Review.BusinessId left outer join
seems not needed in your query and if there are more than one review for one business ...