Related
CREATE TABLE [dbo].[review]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[uID] [varchar](6) NOT NULL,
[pID] [int] NOT NULL,
[email] [nvarchar](255) NOT NULL,
[review] [nvarchar](3000) NULL,
[refURL] [nvarchar](2083) NOT NULL,
[refID] [nvarchar](100) NOT NULL,
[cDate] [datetime] NOT NULL,
CONSTRAINT [PK_review]
PRIMARY KEY CLUSTERED ([id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[review]
ADD CONSTRAINT [DF_review_uID] DEFAULT (LEFT(NEWID(), (6))) FOR [uID]
GO
ALTER TABLE [dbo].[review]
ADD CONSTRAINT [DF_review_cDate] DEFAULT (GETDATE()) FOR [cDate]
GO
I wrote this stored procedure:
ALTER PROCEDURE [dbo].[spReview]
#id INT = 0,
#uID VARCHAR(6),
#pID INT = 0,
#email NVARCHAR(255),
#review NVARCHAR(3000),
#refURL NVARCHAR(2083),
#refID NVARCHAR(100),
#cDate DATETME = NULL,
#OPERATION NVARCHAR(50) = ''
AS
IF #OPERATION = 'Insert'
BEGIN
DECLARE #inserted TABLE ([uID] VARCHAR(6));
INSERT INTO review ([pID], [email], [review], [refURL], [refID])
OUTPUT INSERTED.[uID] INTO #inserted
VALUES (#pID, #email, #review, #refURL, #refID)
SELECT *
FROM #inserted
END
ELSE IF #OPERATION = 'Delete'
BEGIN
DELETE FROM review
WHERE id = #id
END
ELSE IF #OPERATION = 'Update'
BEGIN
UPDATE review
SET pID = #pID,
email = #email,
review = #review,
refURL = #refURL,
refID = #refID
WHERE id = #id
END
uID : left(newid(),(6)) and cDate : getdate() set default value
DECLARE #return_value int
EXEC #return_value = [dbo].[spReview]
#id = N'29',
#OPERATION = N'Delete'
SELECT 'Return Value' = #return_value
GO
I get this error when I execute the delete query:
Procedure or function 'spReview' expects parameter '#uID', which was not supplied
I tried debugging, I can't figure out where I made a mistake. Where did I make a mistake?
ELSE IF #OPERATION = 'Delete'
BEGIN
DELETE FROM review
WHERE id = #id
END
Just waiting for '#id' parameter, it doesn't need '#uID'
This is your code:
ALTER PROCEDURE [dbo].[spReview]
#id INT = 0,
#uID VARCHAR(6),
#pID INT = 0,
#email NVARCHAR(255),
#review NVARCHAR(3000),
#refURL NVARCHAR(2083),
#refID NVARCHAR(100),
#cDate DATETME = NULL,
#OPERATION NVARCHAR(50) = ''
For every parameter without an "=" sign, you need to provide a value. In your case, it means that you need to provide at least the following parameters:
#uID VARCHAR(6),
#email NVARCHAR(255),
#review NVARCHAR(3000),
#refURL NVARCHAR(2083),
#refID NVARCHAR(100),
So either you provide these parameters when calling the procedure, or you rewrite your procedure such that you don't need these parameters.
As mentioned, multiple times, this should be 3 separate SPs, this way you only need the parameters you need for that operation:
CREATE PROC dbo.Review_Delete #id int AS
BEGIN
DELETE FROM dbo.review
WHERE id = #id;
END;
GO
CREATE PROC dbo.Review_Insert #pID int, #email nvarchar(255), #review nvarchar(3000), #RefURL nvarchar(2083), #RefID nvarchar(100) AS
BEGIN
INSERT INTO dbo.review(pID, email, review, refURL, refID)
OUTPUT inserted.uID --This seems like an OUTPUT parameter might be better, as you insert a single row
VALUES(#pID, #Email, #review, #RefURL, #RefID);
END;
GO
CREATE PROC dbo.Review_Update #id int, #pID int, #email nvarchar(255), #review nvarchar(3000), #RefURL nvarchar(2083), #RefID nvarchar(100) AS
BEGIN
UPDATE dbo.review
SET pID = #pID,
email = #email,
review = #review,
refURL = #refURL,
refID = #refID
WHERE ID = #ID;
END;
GO
Notice I never declare the parameter #cDate, as you don't use it once in your SP.
If, for some really odd reason, you really need to have one SP, then create the others and call them dynamically; only passing the parameters you passed to the "master" SP to the "children". I, however, don't recommend this one and you should just call them correct one in the first place:
CREATE PROC Review_Operation #Operation char(6), --No need for this to be an nvarchar, or 50 characters, delete, insert and update are all 6 characters in length and contain no unicode characters
#ID int = NULL, #pID int = NULL, #email nvarchar(255) = NULL, #review nvarchar(3000) = NULL, #RefURL nvarchar(2083) = NULL, #RefID nvarchar(100) = NULL AS
BEGIN
--Because they are all NULL we're going to use Dynamic SQKL to only pass parameters will a value to force the error
DECLARE #SQL nvarchar(MAX),
#Params nvarchar(MAX);
IF #Operation = 'Delete' BEGIN
SET #SQL = N'EXEC Review_Delete ' + CASE WHEN #ID IS NOT NULL THEN N'#id' ELSE N'' END + N';';
SET #Params = N'#ID int';
EXEC sp_executesql #SQL, #Params, #ID;
END ELSE IF #Operation = 'Insert' BEGIN
SET #SQL = N'EXEC Review_Insert ' + STUFF(CASE WHEN #pID IS NOT NULL THEN N',#pID = #pID' ELSE N'' END +
CASE WHEN #email IS NOT NULL THEN N',#email = #email' ELSE N'' END +
CASE WHEN #review IS NOT NULL THEN N',#review = #review' ELSE N'' END +
CASE WHEN #RefURL IS NOT NULL THEN N',#RefURL = #RefURL' ELSE N'' END +
CASE WHEN #RefID IS NOT NULL THEN N',#RefID = #RefID' ELSE N'' END,1,1,N'') + N';';
SET #Params = N'#pID int, #email nvarchar(255), #review nvarchar(3000), #RefURL nvarchar(2083), #RefID nvarchar(100)';
EXEC sp_executesql #SQL, #Params, #pID, #email, #review, #RefURL, #RefID;
END ELSE IF #Operation = 'Update' BEGIN
SET #SQL = N'EXEC Review_Update ' + STUFF(CASE WHEN #ID IS NOT NULL THEN N',#ID = #ID' ELSE N'' END +
CASE WHEN #pID IS NOT NULL THEN N',#pID = #pID' ELSE N'' END +
CASE WHEN #email IS NOT NULL THEN N',#email = #email' ELSE N'' END +
CASE WHEN #review IS NOT NULL THEN N',#review = #review' ELSE N'' END +
CASE WHEN #RefURL IS NOT NULL THEN N',#RefURL = #RefURL' ELSE N'' END +
CASE WHEN #RefID IS NOT NULL THEN N',#RefID = #RefID' ELSE N'' END,1,1,N'') + N';';
SET #Params = N'#id int,#pID int, #email nvarchar(255), #review nvarchar(3000), #RefURL nvarchar(2083), #RefID nvarchar(100)';
EXEC sp_executesql #SQL, #Params, #ID, #pID, #email, #review, #RefURL, #RefID;
END;
END;
GO
Procedure or function 'spReview' expects parameter '#uID', which was
not supplie
This means you are not passing a value to #uID when you are calling the stored procedure. You need to pass a valid parameter during SP execution.
You have couple of issues with your procedure creation and calling.
Creation: You declared a parameter #uID VARCHAR(6) with no use in the Procedure. You can remove the line #uID VARCHAR(6) from the procedur's parameter definition section.
Calling: you defined parameter - #email, #review, #refURL, #refID in the procedure but not providing values to them while calling the procedure. You should call the procedure as below-
DECLARE #return_value int
EXEC #return_value = [dbo].[spReview]
#id = N'29',
#email = N'abc#yahoo.com',
#OPERATION = N'Delete',
#email = 'test#yahoo.com',
#review = 'abc',
#refURL = 'xyz',
#refID = '1' -- ID should be a INT but declared as NVARCHAR
SELECT 'Return Value' = #return_value
GO
Though not really recommended as stated above, you can provide default values, and in fact you have default values set for #id, #pID, and #OPERATION.
Of course, if you default #uID to null, you MUST account for that in the actual procedure to make sure a null #uID won't cause other errors.
create proc [dbo].[spReview]
#id INT = 0,
#uID VARCHAR(6) = null,
#pID INT = 0,
#email NVARCHAR(255),
#review NVARCHAR(3000),
#refURL NVARCHAR(2083),
#refID NVARCHAR(100),
#cDate DATETME = NULL,
#OPERATION NVARCHAR(50) = ''
AS
if #uID is null
begin
-- do something here when #uID is null.
end
I am trying to write a query that needs to call a stored procedure. But it always throws an error:
Unknown object type 'TABLEIXICHistoricalData' used in a CREATE, DROP, or ALTER statement.
This is query:
USE ETLCourse
DECLARE #LOOP TABLE
(
ID INT IDENTITY(1,1),
TableName NVARCHAR(100)
)
INSERT INTO #LOOP (TableName)
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%_Stocks%'
DECLARE #b INT = 1, #m INT, #t NVARCHAR(100)
SELECT #m = MAX(ID) FROM #LOOP
WHILE #b <= #m
BEGIN
SELECT #t = TableName
FROM #LOOP
WHERE ID = #b
EXECUTE [dbo].[stp_BuildNormalizedTable] #t
SET #b = #b + 1
END
and here is the procedure:
ALTER PROCEDURE [dbo].[stp_BuildNormalizedTable]
#table NVARCHAR(100)
AS
BEGIN
DECLARE #cleanTable NVARCHAR(100),
#s NVARCHAR(MAX)
SET #cleanTable = REPLACE(#table, '_Stocks', 'HistoricalData')
SET #s = 'CREATE TABLE' + #cleanTable + '(ID INT IDENTITY(1,1), Price DECIMAL(13, 4), PriceDate DATE)
INSERT INTO' + #cleanTable + '(Price,PriceDate) SELECT [Adj Close],[Date] FROM'
+ #table + ' ORDER BY Date ASC'
--PRINT #s
EXECUTE sp_executesql #s
END
It should copy two specific column and create a new table by using #Loop table and procedure
You need to add 'space' after 'create table' and 'insert into' and 'from'
declare #s nvarchar(max)
declare #cleantable nvarchar(100)
declare #table nvarchar(100)
set #cleantable = 'aaa'
set #table = 'bbb'
SET #s = 'CREATE TABLE' + #cleanTable + '(ID INT IDENTITY(1,1),Price Decimal(13,4),PriceDate DATE)
Insert into' + #cleanTable
+ '(Price,PriceDate) SELECT [Adj Close],[Date] FROM'
+ #table + ' ORDER BY Date ASC'
print #s
Output:
CREATE TABLEaaa(ID INT IDENTITY(1,1),Price Decimal(13,4),PriceDate DATE)
Insert intoaaa(Price,PriceDate) SELECT [Adj Close],[Date] FROMbbb ORDER BY Date ASC
Use 'print' to check your query.
I broke this query down to the most basic. I need to add an OR statement dynamically, which includes a variable. I need to get any id and its corresponding id with an underscore. So, my resulting #SQL to execute would be:
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
--
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
SET #SQL = #SQL + ' AND OrigID in (''' + #OriginId + ''') '
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = '_%'
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10))) + #Origin
SET #SQL_2 = N' OR OrigID LIKE ''' + #Origin + ''' '
SET #SQL_2 = #SQL + #SQL_2
print(#SQL_2)
SET #counter = #counter + 1
END
EXEC sp_executesql #SQL_2,#ParamDefinition,#OrganizationId,#OriginId
drop table #inVars
drop table #Test
Here is how my query is executing now:
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '31_%'
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '33_%'
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '25_%'
This is my desired result:
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '31_%'
OR OrigID LIKE '33_%'
OR OrigID LIKE '25_%'
A few problems: You can't concatenate a NULL with a string EVER; the result is always NULL (please look at the IF #Origin IS NOT NULL line). In your loop, you should be updating #SQL, not #SQL_2. Lastly, you should wrap ORs in parens so the logic is always explicit.
SET NOCOUNT ON
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
SET #SQL = #SQL + ' AND (OrigID in (''' + #OriginId + ''') '
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = '_%'
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10))) + #Origin
IF #Origin IS NOT NULL
BEGIN
SET #SQL_2 = N' OR OrigID LIKE ''' + #Origin + ''' '
SET #SQL = #SQL + #SQL_2
END
SET #counter = #counter + 1
END
SET #SQL=#SQL+')'
print #SQL
drop table #inVars
drop table #Test
It is not very clear what you want here but I think you are making it harder on yourself than you need to. There is no need to use the IN because you are also finding all values that begin with the same value. And you have hard coded the same values into your temp table. Using a string splitter this is about a million times less complicated. Just split your #OriginID on the commas and use LIKE in the join.
I am using the DelimitedSplit8k which you can find here
I am pretty sure this should get you the information you are looking for. I would recommend avoiding loops whenever possible.
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
select *
from #Test t
join DelimitedSplit8K(#OriginID, ',') x on t.OrigID like x.Item + '%'
drop table #Test
I solved this.Thanks all who replied.
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
BEGIN
SET #SQL = #SQL +' AND (OrigID in (''' + #OriginId + ''')) '
END
IF ISNULL(#OriginId,'') <> ''
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10)))
SET #Origin = #Origin+'_%'
SET #SQL_2 = N' OR (OrigID LIKE ''' + #Origin + ''') '
SET #SQL = #SQL + #SQL_2
SET #counter = #counter + 1
END
print(#SQL)
EXEC sp_executesql #SQL,#ParamDefinition,#OrganizationId,#OriginId
drop table #inVars
drop table #Test
I have a simple table:
CREATE TABLE [dbo].[test]
(
[eins] [varchar](50) NOT NULL,
[zwei] [varchar](50) NULL,
CONSTRAINT [PK_test]
PRIMARY KEY CLUSTERED ([eins] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
with two columns eins und zwei, both varchar(50)
with the values
insert into test(eins, zwei) values(1,2)
1 and 2 in the corresponding columns.
The query
select eins from test
gives the correct result of 1
the following code also gives the correct result of 1 in the results window:
declare
#in varchar(50),
#sql nvarchar(500)
set #in = 'eins'
set #sql = 'select ' + #in + ' from test'
Exec(#sql)
However, it doesn't make use of an output parameter and I need the result for further processing.
So, I try:
exec sp_executesql N' Select #1 from test where zwei = #2',N'#1 nvarchar(100),#2 nvarchar(100)',#1=N'eins',#2=N'2'
with an expected result of 1. However: the result is eins, i.e., the column name, not the value.
How can I query for something like Select #Variable from #Variable2 where #variabel3 = #Variable4?
The table and columns can be non-variable, if need be, what's primarily important is, the Select #Variable. I need this value for further processing.
Try something like this
DECLARE #result int
exec sp_executesql
N'Select #1=eins from test where zwei = #2',
N'#1 nvarchar(100) OUTPUT,#2 nvarchar(100)',
#1=#result OUTPUT,#2=N'2'
SELECT #result
What that does is say that the #1 is an OUTPUT variable inside the EXECed query string. Then it binds #result to the #1, so you can retrieve it. I've never found OUTPUT parameters very intuitive to use.
The Code from DWright in the last post has the correct result, but the main problem isn't solved.
I dont know the name of the column while writing the code. The following code seems to be correct:
Declare #result int
Declare #sql nvarchar(500)
Declare #columnname nvarchar(50)
set #columnname = 'eins'
set #sql= N'Select #1= ' + #columnname +' from test1 where zwei = #2'
exec sp_executesql
#sql,
N'#1 nvarchar(100) OUTPUT,#2 nvarchar(100)',
#1=#result OUTPUT,#2=N'2'
SELECT #result
And the result is the expectet 1
Thank you for helping
Let's say I have two tables Company (almost 60K records) and Position (almost 600K records)
Company table:
CompanyID INT --PRIMARY KEY
CompanyName NVARCHAR(100)
CompanyType INT --Just can be (1,2,3,4,5,6)
Position table:
PositionID INT --Primary key
PositionName NVARCHAR(100)
CompanyID INT --FK point to Company Table
WorkExperience INT --Just can be (1,2,3,4,5,6,7,8)
WorkType INT --Just can be (1,2)
CreateTime datetime
UpdateTime datetime
I have created a NONCLUSTERED INDEX on the Company table:
CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[Company]
(
[CompanyKind] ASC
)
INCLUDE ( [CompanyName]) ON [PRIMARY]
GO
And I have created two NONCLUSTERED INDICES ON the Position table also:
CREATE NONCLUSTERED INDEX [IX_6] ON [dbo].[Position]
(
[CompanyID] ASC
)ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_8] ON [dbo].[Position]
(
[UpdateTime] ASC
) ON [PRIMARY]
My paging stored procedure looks like this:
ALTER PROC [dbo].[spIndexJobList]
#KeyWord NVARCHAR(50) ,
#WorkExperience INT ,
#WorkType INT ,
#CompanyType INT ,
#PageSize INT ,
#PageNumber INT
--#RowCount INT OUTPUT
AS
DECLARE #RowStart INT
DECLARE #RowEnd INT
DECLARE #SQL NVARCHAR(4000)
DECLARE #ParamDefinition NVARCHAR(2000)
SET #SQL = N'SELECT C.CompanyID,C.CompanyName,P.PositionName,P.PositionID,P.UpdateTime, Row_number() OVER (ORDER BY P.UpdateTime DESC) AS RowNumber FROM Company C INNER JOIN Position P ON C.CompanyID=P.CompanyID WHERE 1=1 '
IF #KeyWord!=''
SET #SQL = #SQL + ' AND PositionName LIKE #KeyWord'
IF #WorkExperience !=0
SET #SQL = #SQL + ' AND P.WorkExperience=#WorkExperience'
IF #CompanyType != 0
SET #SQL = #SQL + ' AND C.CompanyType=#CompanyType'
IF #WorkType !=0
SET #SQL = #SQL + ' AND P.WorkType=#WorkType'
SET #ParamDefinition = ' #KeyWord NVarchar(50),
#WorkExperience INT,
#WorkType INT,
#CompanyType INT,
#PageSize INT,
#PageNumber INT'
IF #PageNumber > 0
BEGIN
SET #PageNumber = #PageNumber - 1
SET #RowStart = #PageSize * #PageNumber + 1 ;
SET #RowEnd = #RowStart + #PageSize - 1 ;
SET #SQL = '
WITH AllJobs
AS (' + #SQL
+ ')
SELECT *,(SELECT Count(RowNumber) FROM AllJobs) AS TotalRows FROM AllJobs WHERE RowNumber >='
+ STR(#RowStart) + ' AND RowNumber <= ' + STR(#RowEnd) + ''
EXECUTE sp_Executesql #SQL, #ParamDefinition,
#KeyWord, #WorkExperience,#WorkType,
#CompanyType, #PageSize, #PageNumber
END
My call statement is this:
SET STATISTICS IO ON
DECLARE #return_value int
EXEC #return_value = [dbo].[spIndexJobList]
#KeyWord='',
#WorkExperience = 3,
#CompanyType = 2,
#WorkType =1,
#PageSize = 30,
#PageNumber =2000
SELECT 'Return Value' = #return_value
GO
SET STATISTICS IO OFF
//-----------------------------------------------------------------------
(30 row(s) affected)
Table 'Company'. Scan count 3, logical reads 632, physical reads 0
Table 'Position'. Scan count 3, logical reads 4865, physical reads 0
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0
//-----------------------------------------------------------------------
The execute plan prompt missing index on(WorkExperience,WorkType).
But after created index on (WorkExperience,WorkType) query slower.
Anyone give me some suggestions will very appreciate. Sorry for my bad english!
DDL:
Company table:
CompanyID INT NOT NULL PK
CompanyName NVARCHAR(100) NOT NULL
CompanyType TINYINT NOT NULL
Position table:
PositionID INT NOT NULL PK
PositionName NVARCHAR(100) NOT NULL
CompanyID INT NOT NULL
WorkExperience TINYINT NOT NULL
WorkType TINYINT NOT NULL
CreateTime SMALLDATETIME
UpdateTime SMALLDATETIME
Index:
CREATE NONCLUSTERED INDEX IX_Position
ON Position (WorkExperience, WorkType, PositionName)
INCLUDE (UpdateTime)
SP:
ALTER PROC [dbo].[spIndexJobList]
#KeyWord NVARCHAR(50)
, #WorkExperience TINYINT
, #WorkType TINYINT
, #CompanyType INT
, #PageSize INT
, #PageNumber INT
AS BEGIN
SET NOCOUNT ON;
IF #PageNumber > 0 BEGIN
DECLARE
#RowStart INT
, #RowEnd INT
, #SQL NVARCHAR(4000)
, #ParamDefinition NVARCHAR(500)
SELECT #SQL = N'
SELECT
c.CompanyID
, c.CompanyName
, p.PositionName
, p.PositionID
, p.UpdateTime
, RowNumber = ROW_NUMBER() OVER (ORDER BY p.UpdateTime DESC)
FROM dbo.Company c
JOIN dbo.Position p ON c.CompanyID = p.CompanyID
WHERE 1=1 '
+ CASE WHEN #KeyWord != '' THEN ' AND PositionName LIKE #KeyWord' ELSE '' END
+ CASE WHEN #WorkExperience != 0 THEN ' AND p.WorkExperience = #WorkExperience' ELSE '' END
+ CASE WHEN #CompanyType != 0 THEN ' AND c.CompanyType = #CompanyType' ELSE '' END
+ CASE WHEN #WorkType != 0 THEN ' AND p.WorkType = #WorkType' ELSE '' END
SET #ParamDefinition = '#KeyWord NVARCHAR(50),
#WorkExperience INT,
#WorkType INT,
#CompanyType INT,
#PageSize INT,
#PageNumber INT'
SELECT
#PageNumber = #PageNumber - 1
, #RowStart = #PageSize * #PageNumber + 1
, #RowEnd = #RowStart + #PageSize - 1
, #SQL = '
WITH AllJobs AS (' + #SQL + ')
SELECT *
FROM AllJobs a
CROSS JOIN (
SELECT TotalRows = Count(RowNumber)
FROM AllJobs
) t
WHERE a.RowNumber BETWEEN ' + STR(#RowStart) + ' AND ' + STR(#RowEnd)
EXEC sys.sp_executesql
#SQL,
#ParamDefinition,
#KeyWord,
#WorkExperience,
#WorkType,
#CompanyType,
#PageSize,
#PageNumber
END
END
Manual:
Bad habits to kick : choosing the wrong data type
I would create a nonclustered index on Position like so:
CREATE NONCLUSTERED INDEX IX_Position_WorkExperienceWorkTypePositionName
ON Position (WorkExperience, WorkType, PositionName)
INCLUDE (PositionID, UpdateTime)
Also I would create another non-clustered index on Company like below:
CREATE NONCLUSTERED INDEX IX_Company_CompanyId_Type
ON Company(CompanyId,CompanyType)
Because the where clause include "C.CompanyType=#CompanyType", without this index, this condition caused the table scan Company.
With this index, it's index seek.
Company.CompanyID and Position.CompanyID should be indexed, and you might as well take advantage of CLUSTER indexing these two columns so that the rows get physically ordered in sync with their indexes. This should provide significant performance improvement.