I have 1.6 million rows in a table. there are 100,000 rows which has some information missing. To locate that information without duplicate references. I have written a SQL CLR procedure.
It is executing at very slower speed. Only 5000 Rows are processed out on 100,000 in 30 minutes time.
Can below code can be replaced with Inline SQL.
var paymentSql =String.Format("select PaymodeId,StdLedgerId,BaseAmount,RegNo/*,REfInstno,RefStdLedgerId,RefPaymodeId*/ from vw_Payment_Ledger_Matching_Other {0} {1}" ,(condition.Equals("") ? "" : " where " + condition) ," order by CenterId,Ledgerdate,RecptKey ");
var payment = new SqlCommand(paymentSql, conn1) { CommandTimeout = 600 };
using (SqlDataReader payments = payment.ExecuteReader())
{
while (payments.Read())
{
var paymentPaymodeId = payments["PaymodeId"];
var paymentStdLedgerId = payments["StdLedgerId"];
var paymentAmount = payments["BaseAmount"];
var paymentRegNo = payments["RegNo"];
//var paymentRefInstNo = payments["RefInstNo"];
//var paymentRefStdLedgerId = payments["RefStdLedgerId"];
//var paymentRefPayModeId = payments["RefPayModeId"];
//if (Convert.ToInt32(paymentRefInstNo) == 0 && Convert.ToInt32(paymentRefStdLedgerId) == 0 && paymentRefPayModeId.Equals("0"))
{
var ledgerSql = String.Format("select paymodeId,StdLedgerId,Instno,Concession,LumpSump,ConcessionDtl,LumpSumpDtl from vw_Payment_Ledger_Matching_inst a where a.regno='{0}' and abs(a.BaseAmount) between abs({1})-5 and abs({1})+5 and Isnull(a.refInstno,0)=0 and a.insttype<>'O'" +
"and (cast(a.StdLedgerID as varchar(10))+cast(InstNo as varchar(1))) not in ( select cast(b.refStdLedgerID as varchar(10))+cast(b.refInstNo as varchar(1)) from vw_Payment_Ledger_Matching_inst b"
+" where b.regno='{0}' and (b.BaseAmount) between ({1})-5 and ({1})+5 and b.Insttype='O' )"
+" order by a.CenterId,a.RecptKey,a.LedgerDate ",paymentRegNo,paymentAmount );
var Ledger = new SqlCommand(ledgerSql, conn2) { CommandTimeout = 600 };
SqlDataReader ledger = Ledger.ExecuteReader();
if (ledger.Read())
{
var ledgerPayModeId = ledger["PayModeID"];
var ledgerStdLedgerId = ledger["StdLedgerId"];
var ledgerInstNo = ledger["InstNo"];
var ledgerConcession = ledger["Concession"];
var ledgerLumpsump = ledger["Lumpsump"];
var ledgerConcessionDtl = ledger["ConcessionDtl"];
var ledgerLumpsumpDtl = ledger["LumpsumpDtl"];
var updatesql = "update " + updateTable + " set RefInstno=" + ledgerInstNo
+ ", RefStdLedgerId=" + ledgerStdLedgerId + ""
+ ", RefPayModeId='" + ledgerPayModeId + "'"
+ ", RefConcession=" + ledgerConcession
+ ", RefLumpsump=" + ledgerLumpsump
+ ", RefConcessionDtl=" + ledgerConcessionDtl
+ ", RefLumpsumpDtl=" + ledgerLumpsumpDtl
+ " where stdLedgerId=" + paymentStdLedgerId
+ " and PayModeId='" + paymentPaymodeId + "'";
var ledgerUpdate = new SqlCommand(updatesql, conn3);
ledgerUpdate.ExecuteNonQuery();
}
}
}
}
The problem here is not SQLCLR. The problem is that SQLCLR is being used when there is absolutely no reason for doing so. Unless I am missing something, this operation is just a simple cursor, doing the SELECT FROM vw_Payment_Ledger_Matching_inst and the UPDATE {updateTable} per every row returned from the SELECT FROM vw_Payment_Ledger_Matching_Other query. And even if the 3 SqlConnections are using Context Connect = true;, it is still executing a non-parameterized query (as pointed out by #usr in a comment on the Question) and creating a new SqlDataReader (i.e. ledger) that is not being closed for each of those 100,000 rows. But again, there is no reason to use SQLCLR here.
Let's look at what this operation is trying to do. It is saying:
For each record in Query A
{
Get a row from Query B
Update a table via Query C, using the row from Query B
}
What you have in C# is semantically / operationally equivalent to the following T-SQL:
CREATE PROCEDURE DoStuffBetter
(
#Condition NVARCHAR(500),
#UpdateTable NVARCHAR(500)
)
AS
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N'
DECLARE #PaymentPayModeId NVARCHAR(50),
#PaymentStdLedgerId INT,
#PaymentAmount MONEY,
#PaymentRegNo NVARCHAR(50);
DECLARE payment CURSOR FOR
SELECT PayModeId, StdLedgerId, BaseAmount, RegNo
/*, RefInstNo, RefStdLedgerId, RefPayModeId*/
FROM vw_Payment_Ledger_Matching_Other
' + CASE WHEN #Condition <> '' THEN N' WHERE ' + #Condition ELSE '' END + N'
ORDER BY CenterId, LedgerDate, RecptKey;
OPEN payment;
FETCH NEXT
FROM payment
INTO #PaymentPayModeId, #PaymentStdLedgerId, #PaymentAmount, #PaymentRegNo;
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE #LedgerPayModeId NVARCHAR(50),
#LedgerStdLedgerId INT,
#LedgerInstNo INT,
#LedgerConcession MONEY,
#LedgerLumpSump MONEY,
#LedgerConcessionDtl MONEY,
#LedgerLumpsumpDtl MONEY;
SELECT TOP 1
#LedgerPayModeId = PayModeId,
#LedgerStdLedgerId = StdLedgerId,
#LedgerInstNo = InstNo,
#LedgerConcession = Concession,
#LedgerLumpSump = LumpSump,
#LedgerConcessionDtl = ConcessionDtl,
#LedgerLumpsumpDtl = LumpSumpDtl
FROM vw_Payment_Ledger_Matching_inst a
WHERE a.RegNo = #PaymentRegNo
AND ABS(a.BaseAmount) BETWEEN ABS(#PaymentAmount) - 5
AND ABS(#PaymentAmount) + 5
AND ISNULL(a.RefInstNo, 0) = 0
AND a.InstType <> ''O''
AND (CAST(a.StdLedgerID AS VARCHAR(10)) + CAST(a.InstNo AS VARCHAR(1)))
NOT IN (
SELECT CAST(b.RefStdLedgerID AS VARCHAR(10)) +
CAST(b.RefInstNo AS VARCHAR(1))
FROM vw_Payment_Ledger_Matching_inst b
WHERE b.RegNo = #PaymentRegNo
AND (b.BaseAmount) BETWEEN (#PaymentAmount) - 5
AND (#PaymentAmount) + 5
AND b.InstType = ''O''
)
ORDER BY a.CenterId, a.RecptKey, a.LedgerDate;
IF (##ROWCOUNT > 0)
BEGIN
UPDATE ' + #UpdateTable + N'
SET RefInstNo = #LedgerInstNo,
RefStdLedgerId = #LedgerStdLedgerId,
RefPayModeId = #LedgerPayModeId,
RefConcession = #LedgerConcession,
RefLumpsump = #LedgerLumpSump,
RefConcessionDtl = #LedgerConcessionDtl,
RefLumpsumpDtl = #LedgerLumpsumpDtl
WHERE StdLedgerId = #PaymentStdLedgerId
AND PayModeId = #PaymentPayModeId;
END;
FETCH NEXT
FROM payment
INTO #PaymentPayModeId, #PaymentStdLedgerId, #PaymentAmount, #PaymentRegNo;
END;
CLOSE payment;
DEALLOCATE payment;
';
EXEC (#SQL);
The above should be much more efficient than the C# version, but it can still be improved upon to remove the CURSOR. The following set-based approach should be logically equivalent, but all done in a single query:
CREATE PROCEDURE DoStuffBest
(
#Condition NVARCHAR(500),
#UpdateTable NVARCHAR(500)
)
AS
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N'
;WITH Payment AS
(
SELECT PayModeId, StdLedgerId, BaseAmount, RegNo
/*, RefInstNo, RefStdLedgerId, RefPayModeId*/
FROM vw_Payment_Ledger_Matching_Other
' + CASE WHEN #Condition <> '' THEN N' WHERE ' + #Condition ELSE '' END + N'
ORDER BY CenterId, LedgerDate, RecptKey
), Ledger AS
(
SELECT
a.PayModeId,
a.StdLedgerId,
a.InstNo,
a.Concession,
a.LumpSump,
a.ConcessionDtl,
a.LumpSumpDtl,
Payment.PayModeId AS [PaymentPayModeId], -- passthrough for UPDATE
Payment.StdLedgerId AS [PaymentStdLedgerId], -- passthrough for UPDATE
ROW_NUMBER() OVER (PARTITION BY a.RegNo
ORDER BY a.CenterId, a.RecptKey, a.LedgerDate) AS [RowNumInGroup]
FROM vw_Payment_Ledger_Matching_inst a
INNER JOIN Payment
ON Payment.RegNo = a.RegNo
WHERE ABS(a.BaseAmount) BETWEEN ABS(Payment.BaseAmount) - 5
AND ABS(Payment.BaseAmount) + 5
AND ISNULL(a.RefInstNo, 0) = 0
AND a.InstType <> ''O''
AND (CAST(a.StdLedgerID AS VARCHAR(10)) + CAST(a.InstNo AS VARCHAR(1)))
NOT IN (
SELECT CAST(b.RefStdLedgerID AS VARCHAR(10)) +
CAST(b.RefInstNo AS VARCHAR(1))
FROM vw_Payment_Ledger_Matching_inst b
WHERE b.RegNo = Payment.RegNo
AND (b.BaseAmount) BETWEEN (Payment.BaseAmount) - 5
AND (Payment.BaseAmount) + 5
AND b.InstType = ''O''
)
ORDER BY a.CenterId, a.RecptKey, a.LedgerDate
)
UPDATE upd
SET upd.RefInstNo = Ledger.InstNo,
upd.RefStdLedgerId = Ledger.StdLedgerId,
upd.RefPayModeId = Ledger.PayModeId,
upd.RefConcession = Ledger.Concession,
upd.RefLumpsump = Ledger.LumpSump,
upd.RefConcessionDtl = Ledger.ConcessionDtl,
upd.RefLumpsumpDtl = Ledger.LumpsumpDtl
FROM ' + #UpdateTable + N' upd
INNER JOIN Ledger
ON Ledger.PaymentStdLedgerId = upd.StdLedgerId
AND Ledger.PaymentPayModeId = upd.PayModeId
WHERE Ledger.[RowNumInGroup] = 1; --ensure same behavior as TOP 1 within the CURSOR
';
EXEC (#SQL);
Related
My SQL statement in SQL Server looks like this:
DECLARE #forecastYear AS varchar(5)
SET #forecastYear = '2020'
DECLARE #versionName AS varchar(25)
SET #versionName = '20201113_wk'
DECLARE #currentMonth AS varchar(2)
SET #currentMonth = (SELECT current_fc_month FROM tbl_current_month)
SELECT f.record_id
, u.it_ops_j_level_abbr_nm
, f.owner_nm
, f.unit_cd
, f.tbm_cd
, f.tower_nm
, f.description_txt
, f.comment_txt
, f.cost_pool_nm
, f.glac_nr
, f.glac_nm
, f.initiative_nm
, f.priority_nm
, f.growth_nm
, f.it_vendor_nm
, f.jan_amt
, f.feb_amt
, f.mar_amt
, f.apr_amt
, f.may_amt
, f.jun_amt
, f.jul_amt
, f.aug_amt
, f.sep_amt
, f.oct_amt
, f.nov_amt
, f.dec_amt
FROM tbl_new_forecast f
INNER JOIN tbl_unit_tree u
ON f.unit_cd = u.dept_id
WHERE f.version_nm = #versionName
AND f.status_cd = 'Approved'
AND f.entry_type = 'Forecast'
AND f.forecast_yr_id = #forecastYear
AND ABS(f.nov_amt)+ABS(f.dec_amt) <> 0
What I want to do is change the last statement in the WHERE clause based on the value in #currentMonth.
Therefore, if #currentMonth = '3' then the last statement would read
AND ABS(f.mar_amt)+ABS(f.apr_amt)+ABS(f.may_amt) <> 0
If #currentMonth = '7' then it would read
AND ABS(f.jul_amt)+ABS(f.aug_amt)+ABS(f.sep_amt) <> 0
I'm having a hard time figuring out how to accomplish this, because I get a SQL error with this syntax:
AND CASE
WHEN #currentMonth = '10' THEN ABS(f.oct_amt)+ABS(f.nov_amt)+ABS(f.dec_amt) <> 0
END
Any help is appreciated!
If you need a solution, a complex WHERE clause is an option. Note, that in T-SQL CASE is an expression, not a statement:
AND (
((#currentMonth = 1) AND (ABS(f.jan_amt) + ABS(f.feb_amt) + ABS(f.mar_amt) <> 0)) OR
((#currentMonth = 2) AND (ABS(f.feb_amt) + ABS(f.mar_amt) + ABS(f.apr_amt) <> 0)) OR
...
((#currentMonth = 10) AND (ABS(f.oct_amt) + ABS(f.nov_amt) + ABS(f.dec_amt) <> 0)) OR
((#currentMonth = 11) AND (ABS(f.nov_amt) + ABS(f.dec_amt) <> 0)) OR
((#currentMonth = 12) AND (ABS(f.dec_amt) <> 0))
)
Use dynamic SQL
DECLARE #month_dependent varchar (500)=' ';
DECLARE #main_query varchar(1000)=' ';
DECLARE #forecastYear AS varchar(5)
SET #forecastYear = '2020'
DECLARE #versionName AS varchar(25)
SET #versionName = '20201113_wk'
DECLARE #currentMonth char(2)
SET #currentMonth = (SELECT current_fc_month FROM tbl_current_month)
If #currentMonth = '3'
BEGIN set #month_dependent=' AND ABS(f.mar_amt)+ABS(f.apr_amt)+ABS(f.may_amt) <> 0 '; END
If #currentMonth = '7'
BEGIN set #month_dependent=' AND ABS(f.jul_amt)+ABS(f.aug_amt)+ABS(f.sep_amt) <> 0 '; END
set #main_query varchar(1000)=' SELECT f.record_id' +
' , u.it_ops_j_level_abbr_nm ' +
-- ' and all the rest of it! ' +
' FROM tbl_new_forecast f '+
' INNER JOIN tbl_unit_tree u '+
' ON f.unit_cd = u.dept_id ' +
' WHERE f.version_nm = '''+ #versionName + ''' '+
' AND f.status_cd = ''Approved'' '+
' AND f.entry_type = ''Forecast'' '+
' AND f.forecast_yr_id = ''' + #forecastYear + ''' '+
#month_dependent
EXECUTE sp_executesql #main_query ;
You can make this really complex by using a WHERE clause with a lot of ors in it:
AND ({first month condition} OR {Second month condition} OR {third month condition})
Etc. Another option is to place this into a stored procedure and use the month as the trigger to determine which statement to run. Depending on how you are running this, it might be a preferred method, as it can abstract out the details from the application (something you will want if you ever decide to normalize this data).
As for trying to use CASE in a WHERE clause, you have it wrong. The CASE WHEN has to equal something. The correct syntax is like:
AND SomeValue = CASE WHEN ...
You cannot simply use case, as a where is looking for equality (=), inequality (<>), and fuzzy values (LIKE). Thus, this does not work.
AND CASE WHEN ...
As an example, this shows something that fires back 1 to get equivalent rows. But you would need all of your conditions in here, which means the WHEN on month and the ABS() would be the entire condition. You then return 1 to indicate "found it". But you are running this as a monthly query, so filtering by the month and then determining the CASE ... WHEN is where you go.
I have the following code in linq:
(from emp in db.EMPLOYEES
from tab in db.CATEGORY.Where(o => o.Id == 19).DefaultIfEmpty()
on emp.Id = tab.EMP_ID
let url = (!tab.PAGE.StartsWith("/") && !tab.PAGE.StartsWith("#"))
? tab.PAGE + "(" + emp.EMP_VALUE + ")"
: tab.PAGE.Contains("?")
? tab.PAGE + "&Id=" + emp.EMP_VALUE + "&fromSSR=" + BooleanStr.True
: tab.PAGE + "?Id=" + emp.EMP_VALUE + "&fromSSR=" + BooleanStr.True
select new EmployyeModel
{
Id = emp.Id,
RedirectURL = tab.NOT_CH_APPROVAL == BooleanStr.True ? url + "&userCanApprove=1" : url,
}
I need to write the above query in sql server and need help concerning the "let url" part.
How do I translate let in sql server and use it in the select?
Thanks for any help.
Create a user-defined function:
CREATE FUNCTION fnBuildUrl (
#page varchar(100),
#emp_value varchar(100)
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #url varchar(1000)
SELECT #url = CASE WHEN LEFT(#page, 1) = '/' THEN
#page + '(' + #emp_value + ')'
ELSE
CASE WHEN CHARINDEX('?', #page) > 0 THEN
#page + '&Id=' + #emp_value + '&fromSSR=T'
ELSE #page + '?Id=' + #emp_value + '&fromSSR=T' END
END
RETURN #url
END
GO
Then call it in your SELECT:
SELECT emp.Id,
CASE WHEN tab.NOT_CH_APPROVAL = 'T' THEN dbo.fnBuildUrl(tab.PAGE, emp.EMP_VALUE) + '&userCanApprove=1'
ELSE dbo.fnBuildUrl(tab.PAGE, emp.EMP_VALUE) END AS RedirectURL
FROM EMPLOYEES emp
LEFT OUTER JOIN CATEGORY tab
ON tab.EMP_ID = emp.Id
AND tab.Id = 19
Using the following two queries
Query 1:
DECLARE #ContentColumnNamesSRC NVARCHAR(4000) = NULL,
SELECT
#ContentColumnNamesSRC = COALESCE(#ContentColumnNamesSRC + ', ', '') + '[' + name + ']'
FROM
tempdb.sys.columns
WHERE
1 = 1
AND object_id = OBJECT_ID('tempdb..#tempTable')
AND column_id < 9 -- First 8 columns are ID data, which is what I am after
Query 2:
DECLARE #ContentColumnNamesDST NVARCHAR(4000) = NULL,
SELECT
#ContentColumnNamesDST = COALESCE(#ContentColumnNamesDST + ', ', '') + '[' + name + ']'
FROM
tempdb.sys.columns
WHERE
1 = 1
AND object_id = OBJECT_ID('Import.dbo.ContentTable')
AND column_id < 9 -- First 8 columns are ID data, which is what I am after
I can get the first 8 columns from each table into a variable.
What I would like to do is find a way to get the values out of the variable, such that I can match the column names.
They should be identical in each table, and I need it to be able to create a dynamic merge statement, such that the columnsnames from each variable
#ContentColumnNamesSRC
and
#ContentColumnNamesDST
line up, so I can use it in a merge statement.
The point of this is to be able to use it in a loop, and all i would have to do is change which tables it looks at and the merge statements would still work.
Ideally, id like to end up with something like the following:
SELECT #StageSQLCore = N'USE Staging;
BEGIN TRANSACTION
MERGE '+#StageTableCore+' AS DST
USING '+#ImportTableCore+' AS SRC
ON (SRC.[Key] = DST.[Key])
WHEN NOT MATCHED THEN
INSERT ('+#StageTableCoreColumns+')
VALUES (
'+#ImportTableCoreColumns+',GETDATE())
WHEN MATCHED
THEN UPDATE
SET
DST.'+#ContentColumnNamesDST[i]' = SRC.'+#ContentColumnNamesSRC[i] +'
,DST.'+#ContentColumnNamesDST[i]' = SRC.'+#ContentColumnNamesSRC[i] +'
,DST.'+#ContentColumnNamesDST[i]' = SRC.'+#ContentColumnNamesSRC[i] +'
,DST.'+#ContentColumnNamesDST[i]' = SRC.'+#ContentColumnNamesSRC[i] +'
,DST.[ETLDate] = GETDATE()
;
COMMIT'
EXEC (#StageSQLCore)
You can generate Merge SQL like this if both the ordinal are matching
DECLARE #MergeSQL NVARCHAR(4000) = NULL
SELECT --*--,
#MergeSQL = COALESCE(#MergeSQL + ', DST.=', '') + QUOTENAME(bc.column_name) + ' = SRC.' + QUOTENAME(bc.COLUMN_NAME) + char(13)
FROM
test.INFORMATION_SCHEMA.COLUMNS tc
inner join testb.INFORMATION_SCHEMA.COLUMNS bc
on tc.TABLE_NAME = bc.TABLE_NAME
and tc.ORDINAL_POSITION = bc.ORDINAL_POSITION
and tc.TABLE_NAME = 'History'
WHERE
tc.ORDINAL_POSITION < 5 -- First 8 columns are ID data, which is what I am after
and bc.ORDINAL_POSITION < 5
select #MergeSQL
How can I update 13 million rows in stages by using a cursor or something?
Updating with the current script runs for days and still haven't finished.
There is a row_id field. 1 - 13m
Only one field needs to be updated.
UPDATE
[CIPC].[dbo].[tbldirector]
SET
[CIPC].[dbo].[tbldirector].ENT_NUM = REG.Ent_Number
FROM
[CIPC].[dbo].[tbldirector] DIR
INNER JOIN
[Cipc].[dbo].[tblregister] REG
ON
DIR.ENT_LONGNAME = REG.ENT_NAME
in this case you don't need cursor. You can do it with a loop like this.
DECLARE #indx int, #StepSize INT
SET #indx = 1
SET #StepSize = 100000
BEGIN TRAN
WHILE (EXISTS(SELECT 0 FROM [CIPC].[dbo].[tbldirector] WHERE row_id >= #indx))
BEGIN
PRINT 'Going to update indx ' + REPLICATE(CONVERT(VARCHAR, #indx) + ' -- ' + CONVERT(VARCHAR, #indx + #StepSize) + ' | ', 200)
UPDATE [CIPC].[dbo].[tbldirector]
SET [CIPC].[dbo].[tbldirector].ENT_NUM = REG.Ent_Number
FROM [CIPC].[dbo].[tbldirector] DIR
INNER JOIN [Cipc].[dbo].[tblregister] REG
ON DIR.ENT_LONGNAME = REG.ENT_NAME
WHERE row_id BETWEEN #indx AND #indx + #StepSize
SELECT #indx = #indx + #StepSize
SELECT REPLICATE(LEFT(CONVERT(VARCHAR, #indx) + ' | ', 10), 200)
END
COMMIT
This below link have three methods to do the needed,
http://ksadba.wordpress.com/2008/06/16/updating-millions-of-rows-merge-vs-bulk-collect/
I want to check if all given word fragments exist in any order in a given text.
The fragments are supplied by a web application user in a single string separated by spaces like 'abc xyz kj'. They exist in 'mn kj qabc pc xyzw' but do not exist in 'mn kj qabc pc xyw'.
I wrote the following function which works but it looks quite convoluted so I must be doing it wrong. Any ideas on different approaches or how to make it perform?
BTW the database is read only for me so I can't full-text index it and the owners will not do it.
create function dbo.tem_fragmentos(
#texto varchar(max),
#fragmentos varchar(max)
)
returns bit as
begin
declare
#inicio integer = 1,
#fim integer,
#fragmento varchar(max);
set #fragmentos = ltrim(rtrim(#fragmentos));
while charindex(' ', #fragmentos) > 0
set #fragmentos = replace(#fragmentos, ' ', ' ');
while #inicio <= len(#fragmentos) begin
set #fim = charindex(' ', #fragmentos, #inicio + 1);
if #fim = 0 set #fim = len(#fragmentos) + 1;
set #fragmento = substring(#fragmentos, #inicio, #fim - #inicio);
if charindex(#fragmento, #texto) = 0 return 0;
set #inicio = #fim + 1;
end -- while
return 1;
end;
select dbo.tem_fragmentos('clodoaldo pinto neto', ' clo cl nto pinto');
This is how I would do it. Not sure it's any less convoluted...
Create Function dbo.tem_fragmentos
(
#texto varchar(max),
#fragmentos varchar(max)
)
Returns Bit As
Begin
Declare #table Table (fragmentos Varchar(Max))
Set #fragmentos = Ltrim(Rtrim(#fragmentos))
While #fragmentos <> ''
Begin
Insert #table (fragmentos)
Select Left(#fragmentos,Charindex(' ',#fragmentos+' ')-1)
Set #fragmentos = Ltrim(Rtrim(Right(#fragmentos,Len(#fragmentos)-(Charindex(' ',#fragmentos+' ')-1))));
end
If Exists (Select 1
From #table t
Where #texto Not Like '%' + fragmentos + '%')
Begin
Return 0;
End
Return 1;
End;
Select dbo.tem_fragmentos('clodoaldo pinto neto', ' clo cl nto pinto');
I'm assuming your text exists in a db table, else you wouldn't have the db server doing the work. So, why not have your app break the string on spaces and build dynamic SQL like:
select *
from MyTable
where charindex('abc', MyColumn) > 0
and charindex('xyz', MyColumn) > 0
and charindex('kj', MyColumn) > 0
Update:
If you don't want to use dynamic SQL, I would split the input into words in my application, and then pass the list of words in to the query using a table valued parameter (TVP). Then it is a simple left join to determine whether they all match or not.
Sounds like a wildcarded LIKE search should work for you:
declare #texto varchar(max) = 'mn kj q abc pc xyzw',
#fragmentos varchar(max) = 'abc xyz kj'
/*
yes = 'mn kj qabc pc xyzw'
no = 'mn kj qabc pc xyw'
*/
--use your own number table
declare #number table (n int identity(1,1) primary key clustered, x char(1) null);
insert into #number(x)
select top 1000 null from master..spt_values
select [IsMatch] = min(case when #texto like '%'+substring(#fragmentos, n, charindex(' ', #fragmentos + ' ', n) - n)+'%' then 1 else 0 end)
from #number
where n <= datalength(#fragmentos)+1 and
substring(' ' + #fragmentos, N, 1) = ' ';