I'm trying to write a stored procedure in SQL Server that gets the columns as parameters. The user will select the column name from a combo box and will write the searched value for that column on a textbox.
I've been searching how to do this and so far i have this:
ALTER PROCEDURE [dbo].[SP_Select_TBL_Folio]
#cant int,
#Column1 nvarchar(50),
#Value1 nvarchar(50),
#Column2 nvarchar(50),
#Value2 nvarchar(50),
#Column3 nvarchar(50),
#Value3 nvarchar(50)
AS
BEGIN
declare #query nvarchar (max)
SET NOCOUNT ON;
if #cant = 1
BEGIN
set #query = 'SELECT * FROM TBL_Folio WHERE ' + #Column1 + ' LIKE '+ #Value1 + ' ORDER BY 1 DESC';
exec sp_executesql #query, N' '
END
else
BEGIN
if #cant = 2
BEGIN
set #query = 'SELECT * FROM TBL_Folio WHERE ' + #Column1 + ' LIKE '+ #Value1 + ' AND ' + #Column2 + ' LIKE '+ #Value2 + ' ORDER BY 1 DESC';
exec sp_executesql #query, N' '
END
ELSE
if #cant = 3
BEGIN
set #query = 'SELECT * FROM TBL_Folio WHERE ' + #Column1 + ' LIKE '+ #Value1 + ' AND ' + #Column2 + ' LIKE '+ #Value2 + ' AND ' + #Column3 + ' LIKE '+ #Value3 + ' ORDER BY 1 DESC';
exec sp_executesql #query, N' '
END
END
END
The user can send 1 to 3 values, for that I have the parameter #cant, this code works but I want to know if there is a better way to do this or how can I improve this stored procedure.
I think what you have is fine if you need to do it in an SP rather than client side. I would probabably initialize the query to the 'select * from TBL_Folio" and then append the LIKES after each if. I would also caution against using SELECT * so your client side doesn't blow up if a field gets added to the table.
If you have a need to check a variable number of fields rather than just up to 3, you can do a table-valued parameter and build up your query by looping through. Here is an example:
ALTER PROCEDURE [dbo].[GetFilteredInvoices]
#FilterColumns ColumnValueType READONLY
AS
BEGIN
SET NOCOUNT ON;
declare #columnName varchar(50), #columnValue varchar(MAX), #query nvarchar(MAX), #count int
set #query='SELECT InvoiceNumber, InvoiceDate, Customer from Invoices '
set #count=0
set #columnName=''
while exists(select * from #FilterColumns where ColumnName>#ColumnName)
begin
set #columnName=(select min(ColumnName) from #FilterColumns where ColumnName>#columnName)
if #count=0
set #query=#query+'WHERE '
else
set #query=#query+'AND '
set #query=#query+ (select ColumnName+' Like ''%'+ColumnValue+'%'' ' from #filterColumns where ColumnName=#columnName)
set #count=#count+1
end
exec sp_executesql #query
END
Here is the table valued type I used:
CREATE TYPE [dbo].[ColumnValueType] AS TABLE(
[ColumnName] [varchar](50) NULL,
[ColumnValue] [varchar](max) NULL
)
GO
Now this will take any number of columns and values to apply the filter.
Here is an example call to the procedure:
DECLARE #RC int
DECLARE #FilterColumns [dbo].[ColumnValueType]
insert into #filterColumns
Values('InvoiceNumber','345')
,('Customer','67')
EXECUTE #RC = [dbo].[GetFilteredInvoices]
#FilterColumns
I think you can perhaps improve the way that you handle your input parameters by getting rid of the #cant parameter. You can also improve the way that you build up the conditions, at the moment you are not handling the situations where only #Column2 and #Value2 or only #Column3 and #Value3 is set (perhaps it is not needed in your case, but it is still good practice to handle these types of scenarios)
CREATE PROCEDURE SP_Select_TBL_Folio
#Column1 NVARCHAR(50) = NULL,
#Value1 NVARCHAR(50) = NULL,
#Column2 NVARCHAR(50) = NULL,
#Value2 NVARCHAR(50) = NULL,
#Column3 NVARCHAR(50) = NULL,
#Value3 NVARCHAR(50) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE
#P1 NVARCHAR(500),
#P2 NVARCHAR(500),
#P3 NVARCHAR(500),
#SQL NVARCHAR(MAX)
IF (#Column1 IS NULL OR #Column1 = '') AND (#Value1 IS NULL OR #Value1 = '')
BEGIN
-- This will build up dynamic SQL to always select records even if #Column1
-- and #Value1 is not set. This obvisously all depends on your requirements
-- and if you still need to select records if the parameters are not set, otherwise
-- it can be changed to ' WHERE ThePrimaryKeyColumn = 0'
SET #P1 = ' WHERE ThePrimaryKeyColumn > 0'
END
ELSE
BEGIN
SET #P1 = 'WHERE ' + #Column1 + ' LIKE ' + '''' + #Value1 + ''''
END
IF (#Column2 IS NULL OR #Column2 = '') AND (#Value2 IS NULL OR #Value2 = '')
BEGIN
SET #P2 = ''
END
ELSE
BEGIN
SET #P2 = ' AND ' + #Column2 + ' LIKE ' + '''' + #Value2 + ''''
END
IF (#Column3 IS NULL OR #Column3 = '') AND (#Value3 IS NULL OR #Value3 = '')
BEGIN
SET #P3 = ''
END
ELSE
BEGIN
SET #P3 = ' AND ' + #Column3 + ' LIKE ' + '''' + #Value3 + ''''
END
SET #SQL = 'SELECT * FROM TBL_Folio
[P1]
[P2]
[P3]'
-- Here we set all the conditions
SET #SQL = REPLACE(#SQL, '[P1]', #P1);
SET #SQL = REPLACE(#SQL, '[P2]', #P2);
SET #SQL = REPLACE(#SQL, '[P3]', #P3);
-- This will be replaced by EXEC(#SQL)
PRINT #SQL
END
So now you can for instance execute
EXEC SP_Select_TBL_Folio
which will give you
SELECT * FROM TBL_Folio
WHERE ThePrimaryKeyColumn > 0
or you can execute
EXEC SP_Select_TBL_Folio 'Column1','Value1'
which will give you
SELECT * FROM TBL_Folio
WHERE Column1 LIKE 'Value1'
or you can execute
EXEC SP_Select_TBL_Folio NULL,NULL,'Column2','Value2'
which will give you
SELECT * FROM TBL_Folio
WHERE ThePrimaryKeyColumn > 0
AND Column2 LIKE 'Value2'
I'm not going to list all the permutations, I'm sure you get my point.
Related
I have an ETL package built in SSIS that I'm trying to run but I'm getting this error, mainly the third one:
The part in the package that is giving the error is built like this:
The specific component that is causing the error is the call to the SP and this are the parameters:
The parameters are translated to:
The parameters come from the query done at the start of the data flow:
The error mentions invalid column 'P2' the only column that takes this value is SG_PLANO_CTB.
This is the SP that's being used:
USE [SISF_DW_REPORTING]
GO
/****** Object: StoredProcedure [dbo].[SP_INSERT_EAF_MEMBER] Script Date: 8/10/2018 11:22:07 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- Batch submitted through debugger: SQLQuery64.sql|7|0|C:\Users\SQL_AD~1.CMC\AppData\Local\Temp\3\~vs4CBB.sql
-- Batch submitted through debugger: SQLQuery29.sql|7|0|C:\Users\SQL_AD~1.CMC\AppData\Local\Temp\3\~vs8A81.sql
-- =============================================
-- Author:
-- Create date:
-- Description: This stored procedure creates the Early Arriving Fact for a given reference table
-- =============================================
ALTER PROCEDURE [dbo].[SP_INSERT_EAF_MEMBER]
#TABLE NVARCHAR(50)
,#CD_REF NVARCHAR(50)
,#LOG_ID INT
,#ID_SK_COMPOSITE NVARCHAR(50) = NULL
,#COL_SK_COMPOSITE NVARCHAR(50) = NULL
,#DT_LOAD_DATE INT = NULL
,#TABLE_FCT NVARCHAR(50) = NULL
,#DEBUG BIT = 0
AS
BEGIN
SET NOCOUNT ON
IF 1=2
BEGIN
SELECT CAST(NULL AS INT) AS ID_REF
,CAST(NULL AS NVARCHAR(50)) AS DS_TBL_NAME
,CAST(NULL AS NVARCHAR(50)) AS CD_SRCE_SYTM
,CAST(NULL AS INT) AS LOG_ID
,CAST(NULL AS INT) AS DT_LOAD_DATE
,CAST(NULL AS NVARCHAR(50)) AS DS_TBL_FCT_NAME
END
--****************************************************
SET #TABLE = LTRIM(RTRIM(#TABLE))
SET #CD_REF = LTRIM(RTRIM(#CD_REF))
SET #TABLE_FCT = LTRIM(RTRIM(#TABLE_FCT))
--****************************************************
DECLARE #ID_INT_EAF INT
DECLARE #ID_EAF NVARCHAR(100)
DECLARE #DS_EAF NVARCHAR(100)
DECLARE #DT_INT_EAF NVARCHAR(100)
DECLARE #DT_DAT_EAF NVARCHAR(100)
DECLARE #CD_INT_EAF NVARCHAR(100)
DECLARE #CD_VAR_EAF NVARCHAR(100)
DECLARE #FL_EAF NVARCHAR(4)
DECLARE #NR_INT_EAF NVARCHAR(100)
DECLARE #NR_VAR_EAF NVARCHAR(100)
DECLARE #QT_EAF NVARCHAR(100)
DECLARE #VL_EAF NVARCHAR(100)
DECLARE #DMS_EAF NVARCHAR(100)
DECLARE #GPS_EAF NVARCHAR(100)
DECLARE #WGS_EAF NVARCHAR(100)
DECLARE #DT_CRTN NVARCHAR(100)
DECLARE #QUERY_FCT_LOAD_EAF VARCHAR(7000)
DECLARE #QUERY_REF_EAF VARCHAR(7000)
DECLARE #SG_EAF NVARCHAR(100)
DECLARE #HR_EAF NVARCHAR(100)
SET #ID_EAF = '-1'
SET #DS_EAF = '''EAF Member ('+#CD_REF+')'''
SET #DT_INT_EAF = '-1'
SET #DT_DAT_EAF = '''1900-01-01'''
SET #CD_VAR_EAF = ''''+#CD_REF+''''
SET #CD_INT_EAF = '-1'
SET #FL_EAF = '''-1'''
SET #NR_INT_EAF = '0'
SET #NR_VAR_EAF = '''EAF Member'''
SET #QT_EAF = '''0'''
SET #VL_EAF = '''0'''
SET #DMS_EAF = '''EAF Member'''
SET #GPS_EAF = '''EAF Member'''
SET #WGS_EAF = '-1'
SET #DT_CRTN = CONVERT(NVARCHAR(8),GETDATE(),112)
SET #SG_EAF = '''EAF'''
SET #HR_EAF = '''00:00:00'''
-- Declare auxiliary variables
DECLARE #TABLE_NAME NVARCHAR(50), #COLUMN_NAME NVARCHAR(100), #EAF_VALUE NVARCHAR(100)
DECLARE #INSERT NVARCHAR(3000), #VALUES NVARCHAR(3000), #WHERE NVARCHAR(1000), #IDENTITY_ON NVARCHAR(1000), #IDENTITY_OFF NVARCHAR(1000)
DECLARE #STATEMENT VARCHAR(7000)
SET #IDENTITY_ON = 'SET IDENTITY_INSERT ' + #TABLE + ' ON;'
SET #IDENTITY_OFF = 'SET IDENTITY_INSERT ' + #TABLE + ' OFF;'
SET #INSERT = 'INSERT INTO ' + #TABLE + ' ('
SET #VALUES = ' SELECT '
BEGIN
IF #COL_SK_COMPOSITE IS NULL
SET #WHERE = ' WHERE NOT EXISTS (SELECT 1 FROM ' + #TABLE + ' WHERE CD_' + SUBSTRING(#TABLE,9,LEN(#TABLE)) + ' = '''+#CD_REF+''');'
ELSE
SET #WHERE = ' WHERE NOT EXISTS (SELECT 1 FROM ' + #TABLE + ' WHERE CD_' + SUBSTRING(#TABLE,9,LEN(#TABLE)) + ' = '''+#CD_REF+''' AND ' + #COL_SK_COMPOSITE + ' = ' + #ID_SK_COMPOSITE + ');'
END
DECLARE TABLE_COLUMNS CURSOR FOR
SELECT
C.TABLE_NAME
,C.COLUMN_NAME
,CASE
WHEN #COL_SK_COMPOSITE IS NOT NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'ID' AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,5,LEN(C.TABLE_NAME)) AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,9,LEN(C.TABLE_NAME))
THEN #ID_SK_COMPOSITE
WHEN #COL_SK_COMPOSITE IS NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'ID' AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,5,LEN(C.TABLE_NAME)) AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,9,LEN(C.TABLE_NAME))
THEN #ID_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'DS'
THEN #DS_EAF
WHEN C.NEW_COLUMN_NAME = 'DT_START' THEN '''1900-01-01'''
WHEN C.NEW_COLUMN_NAME = 'DT_END' THEN '''9999-12-31'''
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'DT' THEN
CASE
WHEN C.NEW_COLUMN_NAME LIKE 'DT_CRTN' THEN #DT_CRTN
WHEN C.DATA_TYPE LIKE 'int' THEN #DT_INT_EAF
ELSE #DT_DAT_EAF END
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'CD' THEN
CASE WHEN C.DATA_TYPE LIKE 'int' THEN #CD_INT_EAF ELSE #CD_VAR_EAF END
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'FL'
THEN #FL_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'NR' THEN
CASE
WHEN C.DATA_TYPE LIKE 'int' THEN #NR_INT_EAF
WHEN C.DATA_TYPE LIKE 'numeric' THEN #NR_INT_EAF
ELSE #NR_VAR_EAF END
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'QT'
THEN #QT_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'VL'
THEN #VL_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,3) LIKE 'DMS'
THEN #DMS_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,3) LIKE 'GPS'
THEN #GPS_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,3) LIKE 'WGS'
THEN #WGS_EAF
WHEN C.NEW_COLUMN_NAME = 'CTL_LOG_EAF'
THEN '1'
WHEN LEFT(C.NEW_COLUMN_NAME,7) LIKE 'CTL_LOG'
THEN CAST(#LOG_ID AS NVARCHAR(50))
WHEN #COL_SK_COMPOSITE IS NOT NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'SG'
THEN #ID_SK_COMPOSITE
WHEN #COL_SK_COMPOSITE IS NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'SG'
THEN #SG_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'HR'
THEN #HR_EAF
ELSE ''
END EAF_VALUE
FROM
(
SELECT
TABLE_NAME
,COLUMN_NAME
,CASE WHEN LEFT(COLUMN_NAME,2) LIKE 'X_' THEN SUBSTRING(COLUMN_NAME,3,LEN(COLUMN_NAME)) ELSE COLUMN_NAME END AS NEW_COLUMN_NAME
,DATA_TYPE
,ORDINAL_POSITION
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(TABLE_NAME,9,LEN(TABLE_NAME))
) C
INNER JOIN
INFORMATION_SCHEMA.TABLES T
ON C.TABLE_NAME = T.TABLE_NAME
WHERE
T.TABLE_TYPE LIKE 'BASE TABLE'
AND T.TABLE_NAME LIKE #TABLE
ORDER BY
TABLE_NAME, ORDINAL_POSITION
OPEN TABLE_COLUMNS
FETCH NEXT FROM TABLE_COLUMNS INTO #TABLE_NAME, #COLUMN_NAME, #EAF_VALUE;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #COLUMN_NAME <> ''
BEGIN
SET #INSERT = #INSERT + #COLUMN_NAME + ', '
END
IF #EAF_VALUE <> ''
BEGIN
SET #VALUES = #VALUES + #EAF_VALUE + ', '
END
FETCH NEXT FROM TABLE_COLUMNS INTO #TABLE_NAME, #COLUMN_NAME, #EAF_VALUE;
END
CLOSE TABLE_COLUMNS
DEALLOCATE TABLE_COLUMNS
-- Final columns
SET #INSERT = LEFT(#INSERT,LEN(#INSERT)-1) + ')'
SET #VALUES = LEFT(#VALUES,LEN(#VALUES)-1)
SET #QUERY_FCT_LOAD_EAF = 'INSERT INTO FCT_LOAD_EAF (ID_LOAD_DATE, ID_CRTN_DATE, DS_REF_TABLE_NAME, DS_FCT_TABLE_NAME, CD_SRCE_SYTM,CTL_LOG_INSERT) SELECT '+CAST(#DT_LOAD_DATE AS NVARCHAR(8))+', '+#DT_CRTN+', '''+#TABLE+''', '''+#TABLE_FCT+''', '''+#CD_REF+''', '+CAST(#LOG_ID AS NVARCHAR(50))+' '+#WHERE
IF #DEBUG = 1 BEGIN SELECT #QUERY_FCT_LOAD_EAF END ELSE BEGIN EXECUTE(#QUERY_FCT_LOAD_EAF) END
PRINT #QUERY_FCT_LOAD_EAF
SET #STATEMENT = #INSERT + #VALUES + #WHERE
IF #DEBUG = 1 BEGIN SELECT #STATEMENT END ELSE BEGIN EXECUTE(#STATEMENT) END
PRINT #STATEMENT
IF LEFT(#TABLE,2) = 'X_'
BEGIN
SET #QUERY_REF_EAF = 'SELECT X_ID_'+SUBSTRING(#TABLE,7,LEN(#TABLE))+' AS ID_REF, ''' + #TABLE + ''' AS DS_TBL_NAME, CAST(X_CD_SRCE_SYTM AS NVARCHAR(50)) AS CD_SRCE_SYTM, '+CAST(#LOG_ID AS NVARCHAR(50))+' AS LOG_ID, '+CAST(#DT_LOAD_DATE AS NVARCHAR(8))+' AS DT_LOAD_DATE , ''' + #TABLE_FCT + ''' AS DS_TBL_FCT_NAME FROM '+#TABLE+' WHERE X_CD_SRCE_SYTM LIKE '''+#CD_REF+''''
IF #DEBUG = 1 BEGIN SELECT #QUERY_REF_EAF END ELSE BEGIN EXECUTE(#QUERY_REF_EAF) END
PRINT #QUERY_REF_EAF
END
ELSE
BEGIN
SET #QUERY_REF_EAF = 'SELECT ID_'+SUBSTRING(#TABLE,5,LEN(#TABLE))+' AS ID_REF, ''' + #TABLE + ''' AS DS_TBL_NAME, CAST(CD_SRCE_SYTM AS NVARCHAR(50)) AS CD_SRCE_SYTM, '+CAST(#LOG_ID AS NVARCHAR(50))+' AS LOG_ID, '+CAST(#DT_LOAD_DATE AS NVARCHAR(8))+' AS DT_LOAD_DATE, ''' + #TABLE_FCT + ''' AS DS_TBL_FCT_NAME FROM '+#TABLE+' WHERE CD_SRCE_SYTM LIKE '''+#CD_REF+''''
IF #DEBUG = 1 BEGIN SELECT #QUERY_REF_EAF END ELSE BEGIN EXECUTE(#QUERY_REF_EAF) END
PRINT #QUERY_REF_EAF
END
SET NOCOUNT OFF
END
I tried debugging the SP but I can't figure out where he builds the query that uses 'P2' as a column and not as value of the column SG_PLANO_CTB
Edit: I decided to log the parameters that were being used. Found out that the one causing the call causing the error is
exec SISF_DW_REPORTING..SP_INSERT_EAF_MEMBER 'REF_FIN_RUBRICA','11.1.1', 210999, 'P2', 'SG_PLANO_CTB'
And the query that's causing the error is
INSERT INTO REF_FIN_RUBRICA (CD_RUBRICA, DS_RUBRICA, CD_KEY, CD_PARENT, SG_PLANO_CTB, DT_START, DT_END, CTL_LOG_UPDATE, CTL_LOG_EAF) SELECT '11.1.1', 'EAF Member (11.1.1)', '11.1.1', '11.1.1', P2, '1900-01-01', '9999-12-31', 210999, 1 WHERE NOT EXISTS (SELECT 1 FROM REF_FIN_RUBRICA WHERE CD_RUBRICA = '11.1.1' AND SG_PLANO_CTB = P2);
I would guess the string delimitators aren't being added in the cursor somewhere. Can't see where though.
I tried to step through your generated proc logically, and I think I see where the issue lies. The call that's causing the error, exec SISF_DW_REPORTING..SP_INSERT_EAF_MEMBER 'REF_FIN_RUBRICA','11.1.1', 210999, 'P2', 'SG_PLANO_CTB' should probably be changed to:
exec SISF_DW_REPORTING..SP_INSERT_EAF_MEMBER 'REF_FIN_RUBRICA','11.1.1', 210999, '''P2''', 'SG_PLANO_CTB'
It looks like the dynamic sql generation takes the value of one of your input variables and uses that in the query string it builds. If your query needs a string value, you have to additionally double delimit it.
Below store procedure gives following error
com.microsoft.sqlserver.jdbc.SQLServerException: Ambiguous column name 'Incident_id'
USE [FusionSysLive]
GO
/****** Object: StoredProcedure [dbo].[RCPT_Search_Reports] Script ****/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[RCPT_Search_Reports]
#pagesize int = 10,
#pagestart int= 0,
#querysrting varchar(20) = '',
#orderBy varchar(40)= '',
#incident_id numeric(9) =null,
#searchdate varchar(20) =null ,
#search_string varchar(40) =null ,
#action_type varchar(40) =null ,
#security_grp_id numeric(10),
#company_id numeric(10)
as
set nocount on
set quoted_identifier off
CREATE TABLE #Temp (
Row numeric(10, 0) ,
Incident_id numeric(10, 0) null,
Description varchar(50),
Creation_timestamp varchar(100) null,
)
set nocount on
set quoted_identifier off
declare #query varchar(max)
set #query = 'select ROW_NUMBER() OVER (order by '+#orderBy +') AS Row,inc.Incident_id, inc.Description, inc.Creation_timestamp from Incident inc, Incident_list incl where inc.Incident_id = incl.Incident_id '
If(#security_grp_id = 1)
Begin
Set #query = #query + 'and (inc.Company_id ='+cast(#company_id as varchar)+' or inc.Company_id is null) '
End
Else
Begin
Set #query = #query + 'and inc.Company_id ='+cast(#company_id as varchar)
End
If ( ( #incident_id<>0 and #incident_id is not null) or ( (#action_type = 'byGroupID' or #action_type = 'byGroupName' ) and #incident_id=0 and #search_string='' and #searchdate='' ))
Begin
Set #query = #query + ' and inc.Incident_id=' + cast(#incident_id as varchar)
End
If (#action_type is not null and #search_string is not null and #action_type!='' and #search_string!='' )
Begin
If (#action_type = 'byGroupID')
Begin
Set #query = #query + ' and incl.Recipient_list_id in (select Group_id from Contact_group where Group_id like '''+ #search_string + '%'') '
End
Else If (#action_type = 'byGroupName')
Begin
Set #query = #query + ' and incl.Recipient_list_id in (select Group_id from Contact_group where Group_name like '''+ #search_string + '%'') '
End
End
If (#searchdate is not null and #searchdate!='' )
Begin
Set #query = #query + ' and CONVERT(datetime, FLOOR(CONVERT(float(24), Creation_timestamp))) =''' + #searchdate + ''''
End
set #query = #query + ' order by inc.Incident_id';
print #query
insert into #Temp exec(#query)
select row ,Incident_id , Description , Creation_timestamp
from #Temp where Row > #pagestart and row <= (#pagestart + #pagesize)
select count(*) as total_count from #Temp
drop table #Temp
I am trying to insert ID values in stored procedure from .net and the int value for ID is inserting negative value in the stored procedure.
But when a negative value is passed its giving me an error incorrect syntax near '*'.
Please help me.
Here is my stored procedure
ALTER PROCEDURE [dbo].[HotlinePlusAdministration_ArticleMigrator]
#Id AS INT,
--#CategoryID AS INT,
--#Title AS Varchar(200),
--#ArticleDate AS datetime,
#DestLinkServer AS VARCHAR(50),
#UserID AS VARCHAR(8),
#ReturnMsg AS VARCHAR(1000) OUTPUT
AS
BEGIN
DECLARE #Query AS NVARCHAR(4000)
DECLARE #Log AS VARCHAR(8000)
DECLARE #ArticleID as int
DECLARE #NewArticleID as int
DECLARE #ArticleKeyExists as int
DECLARE #Title as varchar(200)
DECLARE #CategoryID as INT
DECLARE #ArticleDate as varchar(30)
DECLARE #ParmDefinition nvarchar(500);
SET XACT_ABORT ON -- Required for nested transaction
BEGIN TRAN
-- Check if ArticleID exists in Destination Server
SET #Query = N' SELECT #ArticleKeyExists = COUNT(*)
FROM ' + #DestLinkServer + '.HL2_61.dbo.Article' + ' where ArticleKey = ' + str(#Id)
SET #ParmDefinition = N' #ID int, #ArticleKeyExists int OUTPUT';
EXECUTE sp_executesql #Query , #ParmDefinition, #ID, #ArticleKeyExists OUTPUT;
--EXECUTE sp_executesql 1234,'BRHLSQL8','BRWSQLDC',#return = retnmsg
IF ##ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
SET #ReturnMsg = #Log + '<span style="color:red;">ERROR: <br></span>'
RETURN -1
END
--Delete existing Articles for select page
set #Query = 'DELETE FROM ' + #DestLinkServer +
'.HL2_61.dbo.Article ' +
'WHERE ArticleKey = ' + CONVERT(VARCHAR, #Id)
--'WHERE CategoryID = ' + CONVERT(VARCHAR, #CategoryID) + ' and Title = ''' + #Title + ''' and ArticleDate = ''' + #ArticleDate + ''''
Print #Query
EXEC(#Query)
When I am executing the code as below I am getting the error.
DECLARE #return_value int,
#ReturnMsg varchar(1000)
EXEC #return_value = [dbo].[Migrator]
#Id = -1591276581,
#DestLinkServer = N'SQLDC',
#UserID = N'10c1',
#ReturnMsg = #ReturnMsg OUTPUT
SELECT #ReturnMsg as N'#ReturnMsg'
SELECT 'Return Value' = #return_value
GO
Please someone help me..
Thanks
When you convert an int to a varchar, you have to specify the size:
Try this:
CONVERT(VARCHAR(50), #Id)
and avoid using str(#Id)
I was trying to execute one of my Stored procedure but i am getting an syntax error and i am unable to understand why.
here is the sproc:
ALTER PROCEDURE [dbo].[HotlinePlusAdministration_ArticleMigrator]
#ArticleKey AS INT,
--#CategoryID AS INT,
--#Title AS Varchar(200),
--#ArticleDate AS datetime,
#DestLinkServer AS VARCHAR(50),
#UserID AS VARCHAR(8),
#ReturnMsg AS VARCHAR(1000) OUTPUT
AS
BEGIN
DECLARE #Query AS NVARCHAR(4000)
DECLARE #Log AS VARCHAR(8000)
DECLARE #ArticleID as int
DECLARE #NewArticleID as int
DECLARE #ArticleKeyExists as int
DECLARE #Title as varchar(200)
DECLARE #CategoryID as INT
DECLARE #ArticleDate as varchar(30)
DECLARE #ParmDefinition nvarchar(500);
SET XACT_ABORT ON -- Required for nested transaction
BEGIN TRAN
-- Check if ArticleID exists in Destination Server
SET #Query = N' SELECT #ArticleKeyExists = COUNT(*)
FROM ' + #DestLinkServer + '.HL2_61.dbo.Article' + ' where ArticleKey = ' + str(#ArticleKey)
SET #ParmDefinition = N'#ArticleKey int, #ArticleKeyExists int OUTPUT';
EXECUTE sp_executesql #Query , #ParmDefinition, #ArticleKey , #ArticleKeyExists OUTPUT;
IF ##ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
SET #ReturnMsg = #Log + '<span style="color:red;">ERROR: <br></span>'
RETURN -1
END
--Delete existing Articles for select page
set #Query = 'DELETE FROM ' + #DestLinkServer +
'.HL2_61.dbo.Article ' +
'WHERE ArticleKey = ' + CONVERT(VARCHAR, #ArticleKey)
--'WHERE CategoryID = ' + CONVERT(VARCHAR, #CategoryID) + ' and Title = ''' + #Title + ''' and ArticleDate = ''' + #ArticleDate + ''''
Print #Query
EXEC(#Query)
when i am trying to execute it i am getting an error here:
SELECT #ArticleKeyExists = COUNT(*)
FROM BRWSQLDC.HL2_61.dbo.Article where ArticleKey = 1591276581
Can some body please help me on this,
Thanks.
SET #ArticleKeyExists = (SELECT COUNT(*) FROM BRWSQLDC.HL2_61.dbo.Article where ArticleKey = 1591276581)
The following stored procedure works correctly execpt when I pass in the #NameSubstring parameter. I know I am not dynamically building the like clause properly. How can I build the like clause when this parameter also needs to be passed as a parameter in the EXEC sp_executesql call near the bottom of the procedure?
ALTER PROCEDURE [dbo].[spGetAutoCompleteList]
(
#AutoCompleteID int,
#StatusFlag int,
#NameSubstring varchar(100),
#CompanyID int,
#ReturnMappings bit,
#ReturnData bit
)
AS
DECLARE #ErrorCode int,
#GetMappings nvarchar(500),
#Debug bit,
#Select AS NVARCHAR(4000),
#From AS NVARCHAR(4000),
#Where AS NVARCHAR(4000),
#Sql AS NVARCHAR(4000),
#Parms AS NVARCHAR(4000)
SET #ErrorCode = 0
SET #Debug = 1
BEGIN TRAN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF #AutoCompleteID IS NOT NULL OR #StatusFlag IS NOT NULL OR #NameSubstring IS NOT NULL
BEGIN
SET #Select = '
SELECT ac.AutoCompleteID,
ac.AutoCompleteName,
ac.CompanyID,
ac.StatusFlag,
ac.OwnerOperID,
ac.CreateDT,
ac.CreateOperID,
ac.UpdateDT,
ac.UpdateOperID,
ac.SubmitOperID,
ac.SubmitDT,
ac.ReviewComments'
SET #GetMappings = '
Select ac.AutoCompleteID'
IF #ReturnData = 1
BEGIN
SET #Select = #Select + '
, ac.AutoCompleteData'
END
SET #From = '
FROM tbAutoComplete ac'
SET #Where = '
WHERE 1=1'
IF #AutoCompleteID IS NOT NULL
BEGIN
SET #Where = #Where + '
AND ac.AutoCompleteID = CAST(#AutoCompleteID AS nvarchar)'
END
IF #StatusFlag IS NOT NULL
BEGIN
SET #Where = #Where + '
AND ac.StatusFlag = CAST(#StatusFlag AS nvarchar)'
END
IF #NameSubstring IS NOT NULL
BEGIN
SET #Where = #Where + '
AND ac.AutoCompleteName like #NameSubstring' + '%'
END
SET #Where = #Where + '
AND ac.CompanyID = + CAST(#CompanyID AS nvarchar)'
SET #Sql = #Select + #From + #Where
SET #Parms = '
#AutoCompleteID int,
#StatusFlag int,
#NameSubstring varchar(100),
#CompanyID int'
EXEC sp_executesql #Sql,
#Parms,
#AutoCompleteID,
#StatusFlag,
#NameSubstring,
#CompanyID
IF #ReturnMappings = 1
BEGIN
SET #GetMappings = 'Select * FROM tbAutoCompleteMap acm WHERE acm.AutoCompleteID IN(' + #GetMappings + #From + #Where + ')'
--EXEC sp_executesql #GetMappings
END
IF #Debug = 1
BEGIN
PRINT #GetMappings
PRINT #Sql
END
END
SELECT #ErrorCode = #ErrorCode + ##ERROR
IF #ErrorCode <> 0
BEGIN
SELECT '<FaultClass>1</FaultClass><FaultCode>1</FaultCode>'
+ '<FaultDesc>Internal Database Error.</FaultDesc>'
+ '<FaultDebugInfo>(spGetAutoCompleteList): There was an error while trying to SELECT from tbAutoComplete.</FaultDebugInfo>'
ROLLBACK TRAN
RETURN
END
COMMIT TRAN
#NameString needs to be outside of the quotes. To get #NameString% enclosed in quotes, you use two single quotes to escape the quote character as a literal.
SET #Where = #Where + '
AND ac.AutoCompleteName like ''' + #NameSubstring + '%'''
To avoid SQL injection, do not use concatenation when adding the parameter to your SQL statement. I strongly recommend that you use this format:
IF #NameSubstring IS NOT NULL BEGIN
SET #Where += 'AND ac.AutoCompleteName LIKE #NameSubstring + char(37)'
END
By using char(37) instead of '%' you avoid having to escape the apostrophes around the string literal
If you wanted to put a wildcard at either side, then you would use
IF #NameSubstring IS NOT NULL BEGIN
SET #Where += 'AND ac.AutoCompleteName LIKE char(37) + #NameSubstring + char(37)'
END
-----------------------------------------------------------------------------
In case someone believes I am wrong, here's proof that concatenation is a risk.
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestInjection]') AND type in (N'U')) BEGIN
create table TestInjection(ID int, Value nvarchar(10))
insert into TestInjection (ID,Value)
Values
(1,'Tom'),
(2,'Fred'),
(3,'Betty'),
(4,'Betty2'),
(5,'Betty3'),
(6,'George')
END
declare #NameSubstring nvarchar(1000) = 'Bet'
--declare #NameSubstring nvarchar(1000) = 'Bet%'';delete from TestInjection;select * from TestInjection where value = ''x'
declare #ID int = 2
Declare #sql nvarchar(1000) = 'select * from TestInjection where ID > #ID '
SET #sql +=' AND [Value] like ''' + #NameSubstring + '%'''
Declare #params nvarchar(100) = '#ID int'
exec sp_executesql #sql, #params, #ID
select * from TestInjection
Run it the first time and you will get a resultset with 3 records, and another with all 6 records.
Now swap the declaration of #NameSubstring to the alternative, and re-run. All data in the table has been deleted.
If on the other hand you write your code like:
declare #NameSubstring nvarchar(1000) = 'Bet'
--declare #NameSubstring nvarchar(1000) = 'Bet%'';delete from TestInjection;select * from TestInjection where value = ''x'
declare #ID int = 2
Declare #sql nvarchar(1000) = 'select * from TestInjection where ID > #ID '
SET #sql +=' AND [Value] LIKE #NameSubstring + char(37)'
Declare #params nvarchar(100) = '#ID int, #NameSubstring nvarchar(1000)'
exec sp_executesql #sql, #params, #ID, #NameSubstring
select * from TestInjection
Then you still get the 3 records returned the first time, but you don't lose your data when you change the declaration.
SET #Where = #Where + 'AND ac.AutoCompleteName like ''%' + #NameSubstring + '%'''
So, you are asking how to specify parameters when you use dynamic queries and sp_executesql ?
It can be done, like this:
DECLARE /* ... */
SET #SQLString = N'SELECT #LastlnameOUT = max(lname) FROM pubs.dbo.employee WHERE job_lvl = #level'
SET #ParmDefinition = N'#level tinyint, #LastlnameOUT varchar(30) OUTPUT'
SET #IntVariable = 35
EXECUTE sp_executesql #SQLString, #ParmDefinition, #level = #IntVariable, #LastlnameOUT=#Lastlname OUTPUT
You can read more about it here: http://support.microsoft.com/kb/262499
Perhaps this wouldn't be an issue if you weren't using dynamic SQL. It looks to me like a vanilla query would work just as well and be much more straightforward to read and debug. Consider the following:
SELECT ac.AutoCompleteID,
ac.AutoCompleteName,
ac.CompanyID,
ac.StatusFlag,
ac.OwnerOperID,
ac.CreateDT,
ac.CreateOperID,
ac.UpdateDT,
ac.UpdateOperID,
ac.SubmitOperID,
ac.SubmitDT,
ac.ReviewComments
FROM tbAutoComplete ac
WHERE ((ac.AutoCompleteID = CAST(#AutoCompleteID AS nvarchar) OR (#AutoCompleteID IS NULL))
AND ((ac.StatusFlag = CAST(#StatusFlag AS nvarchar)) OR (#StatusFlag IS NULL))
AND ((ac.AutoCompleteName like #NameSubstring + '%') OR (#NameSubstring IS NULL))
AND ((ac.CompanyID = CAST(#CompanyID AS nvarchar)) OR (#CompanyID IS NULL))
This is much simpler, clearer etc. Good luck!