So I am trying to create a way for users to search through data on my SQL Database. Right now I've been getting away with using a single view using a lot of Joins:
CREATE VIEW PartsData AS
SELECT
p.part_id AS [Part_ID],
p.part_number AS [Part_Number],
p.part_description AS [Description],
p.information AS [Information],
m.manufacturer_name AS [Manufacturer],
ca.category_description AS [Category],
su.subcategory_description AS [Subcategory],
cu.currency_type AS [Currency],
pl.cost_per_unit AS [Price],
pl.discount_percentage AS [Discount]
FROM
dbo.parts AS P INNER JOIN
dbo.subcategories AS su ON p.subcategory_id = su.subcategory_id INNER JOIN
dbo.price_logs AS pl ON p.part_id = pl.part_id AND pl.log_date = (SELECT MAX(log_date) FROM price_logs WHERE part_id = pl.part_id) INNER JOIN
dbo.manufacturers AS m ON p.manufacturer_id = m.manufacturer_id INNER JOIN
dbo.categories AS ca ON su.category_id = ca.category_id INNER JOIN
dbo.currencies AS cu ON pl.currency_id = cu.currency_id
GO
And a rather crude 'kitchen sink' stored procedure:
CREATE PROCEDURE dbo.PartSearch(
@PartID INT = NULL,
@PartNum VARCHAR(50) = NULL,
@Description VARCHAR(MAX) = NULL,
@Information VARCHAR(MAX) = NULL,
@Supplier VARCHAR(75) = NULL,
@Manufacturer VARCHAR(50) = NULL,
@Category VARCHAR(50) = NULL,
@Subcategory VARCHAR(50) = NULL,
@JobNum VARCHAR(20) = NULL
) AS
BEGIN
SET NOCOUNT ON
DECLARE @SQL NVARCHAR(MAX) = N'
SELECT DISTINCT * FROM PartsData WHERE 1=1'
+ CASE WHEN @PartID IS NOT NULL THEN
N' AND [Part_ID] = @PartID' ELSE N'' END
+ CASE WHEN @PartNum IS NOT NULL THEN
N' AND [Part_Number] LIKE @PartNum' ELSE N'' END
+ CASE WHEN @Description IS NOT NULL THEN
N' AND [Description] LIKE @Description' ELSE N'' END
+ CASE WHEN @Information IS NOT NULL THEN
N' AND [Information] LIKE @Information' ELSE N'' END
+ CASE WHEN @Supplier IS NOT NULL THEN
N' AND [Supplier] LIKE @Supplier' ELSE N'' END
+ CASE WHEN @Manufacturer IS NOT NULL THEN
N' AND [Manufacturer] LIKE @Manufacturer' ELSE N'' END
+ CASE WHEN @Category IS NOT NULL THEN
N' AND [Category] LIKE @Category' ELSE N'' END
+ CASE WHEN @Subcategory IS NOT NULL THEN
N' AND [Subcategory] LIKE @Subcategory' ELSE N'' END
+ CASE WHEN @JobNum IS NOT NULL THEN
N' AND [Part_ID] IN (SELECT jp.part_id FROM job_parts AS jp INNER JOIN jobs AS j ON jp.job_id = j.job_id WHERE j.job_number = '''
+ @JobNum + ''')' ELSE N'' END
DECLARE @params NVARCHAR(MAX) = N'
@PartID INT,
@PartNum VARCHAR(50),
@Description VARCHAR(MAX),
@Information VARCHAR(MAX),
@Supplier VARCHAR(75),
@Manufacturer VARCHAR(50),
@Category VARCHAR(50),
@Subcategory VARCHAR(50)';
EXEC sys.sp_executesql @SQL, @params,
@PartID,
@PartNum,
@Description,
@Information,
@Supplier,
@Manufacturer,
@Category,
@Subcategory
END
GO
However this doesn't exactly work all that well for me anymore. I'm at the point where I need to add more tables to the view, and more searches to the kitchen sink, and the 'default' table is just a mess of endless repeat entries that makes the whole thing look a mess.
This is essentially what I need to do:
-
Have a default View that shows a clean table, where each single Part Number is only shown once.
-
Be able to have one (or more) stored procedures that let me look through all the entries that could be on the table (including the repeat ones I don't want shown) in order to show specific search data.
-
Have it set up in a way where I could expand on it further in the future without it being a gigantic headache.
To give an example of what I want, I'll give you a small example data set.
Part Number | Job Number | Price
AA.445 P0001 $100.00
AA.445 P0002 $100.00
AB.123 P0001 $75.00
AB.123 P0001 $50.00
AC.999 P0002 $25.00
I'd want the default table to appear as follows:
Part Number | Job Number | Price
AA.445 P0002 $100.00
AB.123 P0001 $50.00
AC.999 P0002 $25.00
If I were to search by all parts for the P0002
Job Number, I'd want the table to appear like so:
Part Number | Job Number | Price
AA.445 P0002 $100.00
AC.999 P0002 $25.00
The sample size is probably too small to get across what I am trying to do. Hopefully I've conveyed what it is I am trying to do though.
Now I am not asking someone to give me a full on SQL setup for all of this, but I am not sure how I am suppose to be formatting something like this, or even where to get started with giving this a better setup. That's mainly what I am looking for a little bit of help on.
Best Answer
First thing... Nice job! Most people make a complete mess of this sort of thing. What you have is actually impressive.
There are a few things that you can do to make life a little easier.
1) lose the view. It's an unnecessary layer of abstraction at best and a good way to trick the optimizer into a bad plan at worst.
2) add a "@DeBug" parameter that allows you the option to print the generated sql rather than executing it. You'll be glad you have it the next time you need to track down an odd-ball error caused by a misplaced comma in a sea of red dynamic text. (I recommend this for all dynamic sql)
3) dynamic sql can end up being fairly complex and difficult to debug. Do yourself (and anyone else who may need to alter this proc in the future) and format the code so that the @DeBug output is properly formatted and easy to read.
So... Based on the above, here's how I'd do it... (Note that my own formatting preferences are reflected to some degree... You should change based on your own standards.)
Hope this helps. Let me know if you have any follow up questions...