SQL Server : how to remove consecutive duplicate words in a string - sql-server

Currently I have a dynamic query, generated in the stored procedure, that has a bug. Somehow there is a consecutive duplicate 'AND' generated in it.
Wondering if there is a way to delete the CONSECUTIVE DUPLICATE 'AND' from the dynamic query string.
For eg:
var str = 'Select * from employee A where A.age > 30 AND AND A.role = ''developer'''
Update
The replace as suggested below doesnt work
Please see the below query:
DECLARE
#str NVARCHAR(MAX)
SET #str = 'fasdf asdfasf asfasdfasafsdf AND AND asdfasdfasd AND dfasdfa'
SET #str = REPLACE(#str, 'AND AND', 'AND')
PRINT #str
Thanks!

Something like this?
/****** Object: StoredProcedure [dbo].[RemoveConsecutiveDuplicateTokens] Script Date: 30/06/2016 09:30:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE procedure [dbo].[RemoveConsecutiveDuplicateTokens]
#instr varchar(max) ,
#outstr varchar(max) OUTPUT
as
declare #workstr varchar(max) = ltrim(#instr),
#newstr varchar(max),
#oldtoken varchar(max),
#newtoken varchar(max)
while #workstr is not null
begin
if #oldtoken is null
begin
set #oldtoken = SUBSTRING(#workstr,1,charindex(' ',#workstr))
set #workstr = ltrim(Stuff(#workstr, CharIndex(#oldtoken,#workstr), Len(#oldtoken), ''))
set #newstr = #oldtoken + ' '
end
set #newtoken = SUBSTRING(#workstr,1,charindex(' ',#workstr))
if #newtoken <> #oldtoken
begin
if #newtoken <> char(39)
begin
set #oldtoken = #newtoken
set #newstr = #newstr + #newtoken + ' '
set #workstr = ltrim(Stuff(#workstr, CharIndex(#newtoken,#workstr), Len(#newtoken), ''))
end
end
else
begin
set #workstr = ltrim(Stuff(#workstr, CharIndex(#newtoken,#workstr), Len(#newtoken), ''))
end
if charindex(' ',#workstr) = 0
break
end
set #newtoken = SUBSTRING(#workstr,1,len(#workstr))
if #newtoken <> #oldtoken
begin
if #newtoken <> char(39)
begin
set #oldtoken = #newtoken
set #newstr = #newstr + #newtoken + ' '
set #workstr = ltrim(Stuff(#workstr, CharIndex(#newtoken,#workstr), Len(#newtoken), ''))
end
end
else
begin
set #workstr = ltrim(Stuff(#workstr, CharIndex(#newtoken,#workstr), Len(#newtoken), ''))
end
select #outstr = #newstr
return

First of all, you are doing it wrong. Fix the logic that generates this incorrect sql.
But for research/learning purposes, this is how you do.
REPLACE ( str , 'AND AND' , 'AND')

I forgot how much I dislike SUBSTRING, but then that has been my struggle to read <starting_position> as truly the position the value begins with.
However, the real beast was how string manipulations are implemented in SQL Server under the context of the ##TRANCOUNT.
Consider the statement
PRINT QUOTE_NAME(REPLACE('My____Table', '__', '_'))
We wish to use proper naming standards, but the function returns:
`[My__Table]`
Why? Because REPLACE jumps ahead the length of the duplicates. To prove it, lets add one more '_' CHAR(95) and we get this in return:
`[My___Table]`
So then simply embedding this with a WHILE statement, for example, will be quite sufficient for our needs. Note I replaced the spaces with '_' for readability
DECLARE #instr varchar(max)
SET #instr = 'SELECT * from employee A where A.age > 30 AND AND A.role = ''developer'''
DECLARE #workstr varchar(max) = REPLACE(LTRIM(#instr), ' ', '_'),
#tokenque VARCHAR(MAX),
#newstr INT = 0,
#token varchar(max),
#flag_break INT = 0
-- removes the extra "spaces"
WHILE CHARINDEX('__', #workstr) <> 0
BEGIN
SET #workstr = REPLACE(#workstr, '__' , '_')
END
SET #tokenque = #workstr
WHILE (CHARINDEX('_', #tokenque) <> 0)
BEGIN
SET #token = SUBSTRING(#tokenque, 1, CHARINDEX('_', #Tokenque) - 1 )
IF #token <> '''' -- (') delimiter skipped
BEGIN
WHILE CHARINDEX(#token + '_' + #token, #workstr) <> 0
BEGIN
SET #workstr = REPLACE(#workstr, #token + '_' + #token, #token)
END
SET #tokenque = SUBSTRING(#tokenque, LEN(#token) + 2, LEN(#tokenque) )
END
ELSE SET #tokenque = SUBSTRING(#tokenque, LEN(#token) + 2, LEN(#tokenque) )
PRINT #tokenque --if you want to see the progression
END
PRINT REPLACE(#workstr, '_', ' ')
RESULT:
'SELECT * from employee A where A.age > 30 AND A.role = 'developer'

use the REPLACE function and replace 'AND AND' by 'AND'. example
SELECT REPLACE('Select * from employee A where A.age > 30 AND AND A.role = ''developer'' ','AND AND','AND');

Related

Iterating through columns with conditionals

I'm currently trying to iterate through 38 columns titled 'Switch 1, Switch 2, ....' in order to update them based on a condition.
Here's my code:
DECLARE #i int
DECLARE #selec nvarchar(max)
SET #i = 1
WHILE # i <= 38
BEGIN
SET #selec = 'UPDATE 'Catalog v4'' + '
SET 'Switch' + LTRIM(STR(#i+1)) = ' + CASE
WHEN ( 'Switch' + LTRIM(STR(#i+1))= [Switch Check String] ) THEN ( '' )
ELSE ( 'Switch' + LTRIM(STR(#i+1)))
SET #i = #i+1
EXEC(#selec)
END
I keep getting an error
Must declare scalar variable #, incorrect syntax near Recipe
Any help would be very much appreciated, thanks!
WHILE # i <= 38
Should Be:
WHILE #i <= 38
Assuming you are trying to update table [Catalog 4], following might help:
DECLARE #i int
DECLARE #selec nvarchar(max)
SET #i = 1
WHILE #i <= 38
BEGIN
SET #selec = 'UPDATE '+QUOTENAME('Catalog v4')+'
SET '+QUOTENAME('Switch ' + LTRIM(STR(#i+1)))+' = CASE
WHEN ('+QUOTENAME('Switch '+ LTRIM(STR(#i+1)))+' = ''[Switch Check String]'' ) THEN ( '''' )
ELSE ('+QUOTENAME('Switch ' + LTRIM(STR(#i+1)))+') END'
PRINT #selec --please check the printed messages before executing those.
SET #i = #i+1
--EXEC(#selec)
END
Quotename helps in defining object names correctly if there are spaces in them.
Please replace the [Switch check string] accordingly.
The following code creates a template statement, then updates it each time through the loop rather than trying to assemble it from bits'n'pieces each time.
declare #SQLTemplate as VarChar(256) =
'update [Catalog V4] set Switch# = '' where Switch# = [Switch Check String];'
declare #SQL as VarChar(256);
declare #Index as Int = 1;
while #Index <= 38
begin
set #SQL = Replace( #SQLTemplate, '#', Cast( #Index as VarChar(3) ) );
execute ( #SQL );
set #Index += 1;
end
Note that the update statement has been simplified to avoid updating every row on every pass, regardless of whether the value actually changes.
Another approach (requires thorough testing) is to use the Information.Schema.Columns View instead of a loop.
declare #select varchar(4000) = ''
select
#select = #select
+ 'update YourTableName set ' + COLUMN_NAME + ' = ' + ' CASE WHEN ' + COLUMN_NAME
+ ' = ''[Switch Check String]'' THEN '''' ELSE ' + COLUMN_NAME + 'END ; '
FROM
INFORMATION_SCHEMA.COLUMNS
where
TABLE_NAME = 'YourTableName'
and COLUMN_NAME like 'YourCondition'
print #select
--exec #select

I am getting an error saying Msg 137, Level 15, State 2, Line 8 Must declare the scalar variable "#UtilityID"

IF EXISTS (SELECT * FROM SYSOBJECTS WHERE [Type] = 'P' AND [Name] = 'GetSiteSetupPagedList')
BEGIN
DROP PROCEDURE [GetSiteSetupPagedList]
END
GO
CREATE PROCEDURE [GetSiteSetupPagedList]
(#UtilityID VARCHAR(6),
#ActiveOnly BIT = 1,
--#UtilityID VARCHAR(6),
-- Table Search Parameters
#PageSize INT = 10,
#RequestedPage INT = 0, -- 0-indexed
#SearchText VARCHAR(MAX) = '',
#UseSelectedIDs BIT = 0,
#SelectedIDs IntList READONLY ,
#OrderBy VARCHAR(MAX) = NULL,
#TotalPages INT OUT)
AS
BEGIN
SET #TotalPages = -1; -- -1 shall be interpreted as "use current value"
IF #UseSelectedIDs = 1
BEGIN
SELECT
[SiteID],
[Site].[Name],
[Site].[DefaultUtilityID],
[Utility].[Name] AS 'DefaultUtilityName'
FROM
#SelectedIDs
JOIN [Site] ON [Int] = [Site].[SiteID] AND [Site].AmendedTime IS NULL
JOIN [Utility] ON [Utility].[UtilityID] = [Site].[DefaultUtilityID] AND [Utility].AmendedTime IS NULL
RETURN
END
DECLARE #SQL NVARCHAR(MAX),
#From VARCHAR(MAX),
#Where VARCHAR(MAX),
#RowsToSkip INT,
#TotalRecords INT
-- Set the default order by
IF ISNULL(#OrderBy, '') = ''
SET #OrderBy = '[Site].[Name], [Site].[CreatedTime]'
-- Calculate Rows to Skip for paging
SET #RowsToSkip = #PageSize * #RequestedPage
-- Create the WHERE clause
SET #Where = ' WHERE [Site].AmendedTime IS NULL
AND [Utility].AmendedTime IS NULL
'
-- Active filter
IF #ActiveOnly = 1
BEGIN
SET #Where = #Where + ' AND [Site].[Active] = 1
AND [Utility].[UtilityID] = #UtilityID
'
END
-- Generic search filter
IF LEN(#SearchText) > 0
BEGIN
SET #Where = #Where + ' AND
convert(varchar(10), [SiteID]) +
[Site].[Name] +
ISNULL([Site].[DefaultUtilityID], '''') +
[Utility].[Name]
LIKE ''%'' + #SearchText + ''%''
'
END
-- Create combined FROM/WHERE clause
SET #From = ' FROM [Site]
JOIN [Utility] ON [Utility].[UtilityID] = [Site].[DefaultUtilityID]
'
+ #Where
-- Calculate total pages if we're loading the first page and not grabbing specific IDs
IF #RequestedPage = 0
BEGIN
SET #SQL = 'SELECT #TotalRecords = COUNT(*) ' + #From + ' '
--print #SQL
EXEC SP_EXECUTESQL #SQL,
N'#TotalRecords INT OUT, #SearchText VARCHAR(MAX)',
#TotalRecords = #TotalRecords OUT, #SearchText = #SearchText
SET #TotalPages = CEILING(CONVERT(DEC(10,2), #TotalRecords) / CONVERT(DEC(10,2), #PageSize))
END
-- Final select
SET #SQL = 'SELECT
[SiteID],
[Site].[Name],
[Site].[DefaultUtilityID],
[Utility].[Name] AS ''DefaultUtilityName''
' + #From + '
ORDER BY ' + #OrderBy + '
OFFSET ' + CONVERT(VARCHAR, #RowsToSkip) + ' ROWS
FETCH NEXT ' + CONVERT(VARCHAR, #PageSize) + ' ROWS ONLY
'
--print #SQL
EXEC SP_EXECUTESQL #SQL,
N'#SearchText VARCHAR(MAX)',
#SearchText = #SearchText
END
`
When I was using:
`
EXECUTE SP_EXECUTESQL #SQL,
N'#UtilityID varchar(6)', -- this is an argument #1 with 1 parameter
N'#SearchText VARCHAR(MAX)', -- this is an argument #2 with 1 parameter
-- that's why we get an error saying too
-- many arguments
#UtilityID = #UtilityID,
#SearchText = #SearchText
`
`
I get the message saying:
Msg 137, Level 15, State 2, Line 8
Must declare the scalar variable "#UtilityID".
Msg 8144, Level 16, State 2, Line 2
Procedure or function has too many arguments specified.
It took me awhile to figure out but this is the correct syntax:
`
`
`
EXECUTE SP_EXECUTESQL #SQL,
N'#UtilityID varchar(6),
#SearchText VARCHAR(MAX)',
`
#UtilityID = #UtilityID,
#SearchText = #SearchText
`

An OLE DB error has occurred. Error code: 0x80040E14, Invalid column name

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.

Transform text in SQL Server

I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here

SQL WHILE loop inside WHERE clause

Can I put a WHILE loop inside WHERE clause? I have a stored procedure where I'm trying to put in text searching capability. I have it working for an exact match like this:
AND (#exactString = ''
OR (CHARINDEX(#exactString, [Short Description]) > 0
OR CHARINDEX(#exactString, [Description]) > 0
OR CHARINDEX(#exactString, [Manufacturer]) > 0))
Next I'm trying to do a "any word" match and an "all words" match. I can get the search string I want to search for with the following WHILE loop:
DECLARE #searchString varchar(max)
DECLARE #endIndex int
SET #allString = LTRIM(RTRIM(#allString))
WHILE LEN(#allString) > 0
BEGIN
SET #endIndex = CHARINDEX(' ', #allString) > 0
IF #endIndex > 0
BEGIN
SET #searchString = LEFT(#allString, #endIndex)
SET #allString = LTRIM(RTRIM(RIGHT(#allString, #endIndex)))
END
ELSE
BEGIN
SET #searchString = #allString
SET #allString = ''
END
END
Now I want to use the #searchString variable like I used #exactString above. Is there a way to do this inside my loop or is there some other technique I'm missing that would work here?
Thanks for your help,
Dan
I have used a table value function to perform this task using a query such as the following:
SELECT I.*
FROM #info AS I
INNER JOIN dbo.funcSplitToTable( ' ', #allString ) AS S
ON I.[Manufacturer] LIKE '%' + S.result + '%'
OR I.[Description] LIKE '%' + S.result + '%'
OR I.[Short Description] LIKE '%' + S.result + '%'
This table value function is defined as follows:
CREATE FUNCTION dbo.funcSplitToTable
/*
Split a string into parts base on a separation character to produce
a table that has one column containing the results of the split.
EXAMPLE:
SELECT * FROM dbo.funcSplitToTable( '~', 'MAINT~12221~10001~10/25/2004~CANCELLED~1' )
SELECT * FROM dbo.funcSplitToTable( '~', '' )
SELECT * FROM dbo.funcSplitToTable( '~', NULL )
SELECT * FROM dbo.funcSplitToTable( NULL, 'MAINT~12221~10001~10/25/2004~CANCELLED~1' )
SELECT * FROM dbo.funcSplitToTable( '', 'MAINT~12221~10001~10/25/2004~CANCELLED~1' )
RETURN:
Table with one column containing resulting strings.
*/
(
#strSearch AS varchar(255) -- String to search for.
,#strText AS varchar(MAX ) -- Text to search for string.
)
RETURNS #tblResult TABLE (
result varchar(MAX) NOT NULL
)
WITH SCHEMABINDING
AS
BEGIN
DECLARE #iLastPos int
DECLARE #iPos int
DECLARE #strResult varchar(MAX)
IF #strText IS NULL RETURN ;
IF #strSearch IS NULL SET #strSearch = '' ;
SET #strResult = NULL ;
SET #iLastPos = 1 ;
SET #iPos = CHARINDEX( #strSearch, #strText ) ;
WHILE #iPos > 0
BEGIN
IF (#iPos - #iLastPos) > 0
INSERT INTO #tblResult
SELECT SUBSTRING( #strText, #iLastPos, (#iPos - #iLastPos) ) AS result
;
SET #iLastPos = #iPos + 1 ;
SET #iPos = CHARINDEX( #strSearch, #strText, #iLastPos ) ;
END
IF (1 + LEN(#strText) - #iLastPos) > 0
INSERT INTO #tblResult
SELECT SUBSTRING( #strText, #iLastPos, (1 + LEN(#strText) - #iLastPos) ) AS result
;
RETURN ;
END
I got a great answer from Michael Erickson that totally works for the "any" search. For the "all" search. I built up an sql string with the entire query. The "all" search section is here:
IF LEN(#allString) > 0
BEGIN
DECLARE #searchString varchar(max)
DECLARE #endIndex int
DECLARE #isFirstString bit
SET #isFirstString = 0
SET #allString = LTRIM(RTRIM(#allString))
WHILE LEN(#allString) > 0
BEGIN
SET #endIndex = CHARINDEX(' ', #allString)
IF #endIndex > 0
BEGIN
SET #searchString = LTRIM(RTRIM(LEFT(#allString, #endIndex)))
SET #allString = LTRIM(RTRIM(RIGHT(#allString, LEN(#allString) - #endIndex)))
END
ELSE
BEGIN
SET #searchString = #allString
SET #allString = ''
END
SET #sql = #sql + ' AND ((CHARINDEX(''' + cast(#searchString as varchar(max)) + ''', [Short Description]) > 0
OR CHARINDEX(''' + cast(#searchString as varchar(max)) + ''', [Description]) > 0
OR CHARINDEX(''' + cast(#searchString as varchar(max)) + ''', [Manufacturer]) > 0))'
END
END
EXEC (#sql)
Thanks again,
Dan

Resources