SQL smart search possible? - sql

I am trying to pull a list from a large repository. And if there are spaces in this search, I separate the spaces and search separately. So far everything is working fine. And I am sending a list to the JS side to highlight the searched words. The word in the example search is 'paston'. I need to search for it as 'piston' or 'peston', is it possible? The only way I could think of was to change each letter of the words coming from the search in SQL to _ respectively and add them to the end with or, like '_iston' or 'p_ston' or 'pi_ton'. but I'm not sure if this works slow. Does anyone have any suggestions or know of a ready-made structure in SQL?
My SQL code is like this:
ALTER PROCEDURE [dbo].[GetStoklar]
#PageIndex nvarchar(15)
,#PageSize nvarchar(15)
,#Ara nvarchar(max)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
DECLARE #NAME VARCHAR(100);
SET #sql = '
Select STOK_KODU,STOK_ADI,GRUP_KODU from TBLSTSABIT where 1=1'
DECLARE CUR CURSOR FOR
SELECT Deger FROM dbo.splitstring(''+#Ara+'')
OPEN CUR
FETCH NEXT FROM CUR INTO #NAME
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql=#sql+' AND STOK_ADI+STOK_KODU+GRUP_KODU LIKE ''%'+#NAME+'%'''
FETCH NEXT FROM CUR INTO #NAME
END
CLOSE CUR
DEALLOCATE CUR
SET #sql = #sql + ' order by STOK_KODU asc offset (CAST('+#PageIndex+' as int)*CAST('+#PageSize+' as int)) Rows fetch next CAST('+#PageSize+' as int) rows only
'
EXEC sp_executesql #sql;
PRINT #SQL;
RETURN
END
on the C# side like this
StringBuilder test = new StringBuilder();
JsonModel jsonmodel = new JsonModel();
if (Arama != "")
{
foreach (var item in Arama.Split(' '))
{
test.Append(item + "~");
}
}
test.Remove(test.ToString().Length - 1, 1);
jsonmodel.Filtre = test.ToString();
int pagesize = 15;
var tbrow = isStatic.GetStokListesi(pageindex, pagesize, Arama);
jsonmodel.NoMoredata = tbrow.Count < pagesize;
jsonmodel.HTMLString = isStatic.RenderToString(PartialView("_partial", tbrow));
return Json(jsonmodel);
This is the search function.
public static List<Stoklar> GetStokListesi(int pageindex, int pagesize, string Arama)
{
using (blabla db = new blabla())
{
return db.Database.SqlQuery<Stoklar>("[GetStoklar] #PageIndex,#PageSize,#Ara",
new SqlParameter("#PageIndex", pageindex.ToString()), new SqlParameter("#PageSize", pagesize.ToString()), new SqlParameter("#Ara", Arama)).ToList();
}
}
Is there a way to use this more meaningfully on the SQL side?

You can replace all single characters in a word by an '_', and then use these results in a LIKE
For replacing all single characters in a word, see: DBFIDDLE

Related

Iterate over two loops (CURSOR and WHILE) and print the records grouped by location

I want to print the records grouped by each location (in this case they are 2), duly ordered.
I'm testing with a cursor but it prints the same location twice.
How can I fix this?
DECLARE #DateMovementsTopWorst AS DATE;
DECLARE #InventoryOnSiteTopWorst AS NUMERIC;
DECLARE #FamilyTopWorst AS VARCHAR(50)
DECLARE #BufferTopWorst AS NUMERIC;
DECLARE #SkuTopWorst AS VARCHAR(50);
DECLARE #LocationTopWorst AS VARCHAR(50);
DECLARE #Counter3 AS INT = 1;
DECLARE #Location AS VARCHAR(50);
DECLARE #Temporal2 AS INT = 10;
DECLARE ExternCursor CURSOR
FOR SELECT DISTINCT(LOCATION) FROM TFSCM_CLI_BUFFER
OPEN ExternCursor
FETCH NEXT FROM ExternCursor INTO #Location;
WHILE ##FETCH_STATUS = 0
--WHILE #Counter3 < #Temporal+1
BEGIN
DECLARE #Counter2 AS INT = 1;
--SET ROWCOUNT #Counter3;
PRINT ' SKU: '
+ ' Size: '
+ ' Family: '
+ ' Inventory: '
+ ' Movement Date: '
WHILE #Counter2 < 6
BEGIN
SET ROWCOUNT #Counter2;
SELECT #SkuTopWorst= SKU,
#BufferTopWorst= BUFFER,
#FamilyTopWorst = FAMILY,
#InventoryOnSiteTopWorst = TOTAL_INVENTORY_ON_SITE,
#DateMovementsTopWorst = UPDATE_MOVEMENTS,
#LocationTopWorst = LOCATION,
#Temporal2 = COUNT(*) OVER ()
FROM TFSCM_CLI_BUFFER
WHERE LOCATION = #Location
ORDER BY TOTAL_INVENTORY_ON_SITE ASC;
PRINT #SkuTopWorst
+ ' '
+ CONVERT(VARCHAR(100), #BufferTopWorst)
+ ' '
+ #FamilyTopWorst
+ ' '
+ CONVERT(VARCHAR(100), #InventoryOnSiteTopWorst)
+ ' '
+ CONVERT(VARCHAR(100), #DateMovementsTopWorst);
SET #Counter2 = #Counter2+1;
END
PRINT 'This is: ' + #Location;
--SET #Counter3 = #Counter3+1;
FETCH NEXT FROM ExternCursor;
END
CLOSE ExternCursor
DEALLOCATE ExternCursor
Edited with suggestions from users. But we have the same results
You're not using the cursor data for anything - therefore you inner query gets all your locations. You need to obtain the value from the cursor and then use it to filter your inner query. The following changes are required:
Add DECLARE #Location AS VARCHAR(50); near the start.
Modify your fetch's to be FETCH NEXT FROM ExternCursor INTO #Location;
Modify your inner where to be WHERE [LOCATION] = #Location
In the WHILE loop you have the SQL with this statement:
WHERE LOCATION IN (SELECT DISTINCT(LOCATION)
FROM TFSCM_CLI_BUFFER)
So the WHILE loop get all the location,
you need to change both:
FETCH NEXT FROM ExternCursor;
into
FETCH NEXT FROM ExternCursor INTO #location;
and then the WHERE statement in
WHERE LOCATION = #location
So for each Distinct location in TFSCM_CLI_BUFFER the WHILE loop will take care of one at a time.
P.S. Declare #location with the other var before the cursor.

Why are the scalar variables undeclared inside cursor?

I wrote a code snippet that is supposed to read a mapping table (BcwmWDConfig) and insert/update values of an outdated table (Items) in an old database (BCWM99) to a newer table in another database (WebDET99.dbo.Items).
I am getting errors that my supposedly declared (at least I thought so) variables are not declared.
DECLARE #v_bcwm_id INT = 0,
#v_wd_guid VARCHAR = '';
DECLARE bcwm_config_read_cursor CURSOR FOR
SELECT c.id, c.guid
FROM BcwmWDConfig c
WHERE c.guid IS NOT NULL;
PRINT '----READING CONFIG----';
OPEN bcwm_config_read_cursor
FETCH NEXT FROM bcwm_config_read_cursor INTO #v_bcwm_id, #v_wd_guid
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT '----READ CONFIG FOR ID: '+#v_bcwm_id+' AS GUID '+#v_wd_guid+'----'
PRINT '----INSERTING ITEMS WITH PARENT GUID: '+#v_wd_guid+'----'
INSERT INTO WebDET99.dbo.Items
SELECT
i.Id, i.Text,
CAST(#v_wd_guid AS VARCHAR(50)),
CAST(i.Linked_Feld AS VARCHAR(50)),
i.Linked_Item, i.Order
FROM
BCWM99.dbo.Items i
WHERE
i.Parent_Feld = #v_bcwm_id
PRINT '----INSERTED ITEMS WITH PARENT GUID: '+#v_wd_guid+'-----'
FETCH NEXT FROM bcwm_config_read_cursor INTO #v_bcwm_id, #v_wd_guid
END
CLOSE bcwm_config_read_cursor;
DEALLOCATE bcwm_config_read_cursor;
SET #v_bcwm_id = 0, #v_wd_guid = '';
OPEN bcwm_config_read_cursor
FETCH NEXT FROM bcwm_config_read_cursor
INTO #v_bcwm_id, #v_wd_guid
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT '----READ CONFIG FOR ID: '+#v_bcwm_id+' AS GUID '+#v_wd_guid+'----'
PRINT '----UPDATING ITEMS WITH LINKED FIELD: '+#v_wd_guid+'----'
UPDATE WebDET99.dbo.Items i
SET i.Linked_Feld = #v_wd_guid
WHERE i.Parent_Feld = CAST(#v_bcwm_id AS VARCHAR(50))
PRINT '----UPDATED ITEMS WITH LINKED FIELD: '+#v_wd_guid+'-----'
FETCH NEXT FROM bcwm_config_read_cursor
INTO #v_bcwm_id, #v_wd_guid
END
CLOSE bcwm_config_read_cursor;
DEALLOCATE bcwm_config_read_cursor;
SET #v_bcwm_id = 0,
#v_wd_guid = '';
Why are they undeclared inside the cursors? Also I am pretty sure I have some smaller syntax errors in my code, I am not used to SQL Server, maybe someone finds some other issues with this procedure.
Your code is sysntactically incorrect.
The first error: you cannot use Order (reserved word) without square brackets:
SELECT
i.Id, i.Text,
CAST(#v_wd_guid AS VARCHAR(50)),
CAST(i.Linked_Feld AS VARCHAR(50)),
i.Linked_Item, i.[Order] -----------------------------square brackets!
Second error:
SET #v_bcwm_id = 0, #v_wd_guid = '';
Should be:
SET #v_bcwm_id = 0; set #v_wd_guid = ''; ------------the same in the last row
The last error: get rid of "i":
UPDATE WebDET99.dbo.Items
SET Linked_Feld = #v_wd_guid
WHERE Parent_Feld = CAST(#v_bcwm_id AS VARCHAR(50))
Only then your code can be compiled.

How to insert a Null Value to a column if there is no data provided from source file in ASP.NET

I am inserting data from a Text file to table.
and the SPROC is as follows
ALTER PROCEDURE [dbo].[SPROC]
-- Add the parameters for the stored procedure here
#DBName VARCHAR(30),
#FirstLine VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #InsertQuery NVARCHAR(MAX), #Summary_ID INT
SET #InsertQuery = 'INSERT INTO ' + #DBName + '.[dbo].[Summary] VALUES ( ' + #FirstLine + '); SELECT SCOPE_IDENTITY()'
EXEC SP_EXECUTESQL #InsertQuery
END
Now the thing is, if it has 8 values it will get inserted. If 8 th Value is not there in the text file it is throwing Error column name or number of supplied values does not match table definition
How can i handle this error and If there is no value for 8th column it should insert the value as NULL.
Reading File code:
public static String[] ReadSummary_Into_Array(string filepath)
{
StreamReader sreader = null;
int counter = 0;
try
{
sreader = new StreamReader(filepath);
string line = sreader.ReadLine();
//condition to hanlde empty file
if (line == null) return null;
//condition to hanlde empty first line file
if (line == "") return new String[0];
FirstLine = line;
string cleaned_line = line.Replace("''", "'-'").Replace("','", "''");
string word = "";
List<string> data = new List<string>();
MatchCollection matches = Regex.Matches(cleaned_line, #"'([^']*)");
//String[] words = null;
foreach (Match match in matches)
{
word = match.ToString();
string word_edited = word.Replace("\'", "");
if (word_edited != string.Empty)
{
data.Add(word_edited);
counter++;
}
}
Summary = new String[counter];
Summary = data.ToArray(); //The Summary Line is reconstructed into a String array
return Summary;
}
If you dont have value then you must specify the column names.
Try like this
ALTER PROCEDURE [dbo].[SPROC]
-- Add the parameters for the stored procedure here
#DBName VARCHAR(30),
#FirstLine VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #InsertQuery NVARCHAR(MAX), #Summary_ID INT, #CountS INT
SET #CountS = len(#FirstLine) - len(replace(#FirstLine, ',', ''))
IF #CountS >= 7 THEN
SET #InsertQuery = 'INSERT INTO ' + #DBName + '.[dbo].[Summary] VALUES ( ' + #FirstLine + '); SELECT SCOPE_IDENTITY()'
ELSE
SET #InsertQuery = 'INSERT INTO ' + #DBName + '.[dbo].[Summary](SerialNumber,AssetNumber,SoftwareRev,TechName,StartTime,StopTime,Status) VALUES ( ' + #FirstLine + '); SELECT SCOPE_IDENTITY()'
END IF
EXEC SP_EXECUTESQL #InsertQuery
END
Similar as Vignesh, but in your C# code
if ( Regex.Matches( strLine, "," ).Count == 7)
{
strLine = strLine + ', null';
}

Parametrize query in t-sql

SELECT TOP #columnCount #columnName
FROM #tableName
I get the following error
Incorrect syntax near '#columnCount'.
What could be wrong?
If I change to
SELECT TOP (#columnCount) #columnName
FROM #tableName
I get the following error
Must declare the table variable "#tableName".
I run it from C#
A safe and secure way would be
DECLARE #columnCount INT = 100
DECLARE #columnName NVARCHAR(128) = 'YourColumnName'
DECLARE #tableName NVARCHAR(128) = 'YourTableName'
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT TOP (#columnCount) ' + QUOTENAME(#columnName) + N'
FROM ' + QUOTENAME(#tableName)
EXECUTE sp_executesql #Sql
,N'#columnCount INT'
,#columnCount
You need dynamic SQL to accomplish what you're trying to do.
DECLARE #sql VARCHAR(max);
SET #sql = 'SELECT TOP ' + #columnCount + ' ' + #columnName + ' FROM ' + #tableName;
EXEC(#sql);
The variables used need to be converted appropriately.
Read more in the documentation
Column lists and Table names cannot be parameters. However, since you are running this from C# you are technically already using Dynamic SQL (unless you are calling a stored procedure with those params but there is no mention here of stored procedures being used so for now I will assume not). When building the SQL in C#, you need to concatenate the Column List and Table Name into the query but you can still use a parameter for the value used by the TOP() operator:
SqlConnection _Connection = new SqlConnection("connection string");
SqlCommand _Command = new SqlCommand();
SqlDataReader _Reader = null;
string _Query;
string _TableName = "dbo.MyTable";
string _ColumnList = "Field1, Field2 AS [AliasedName], Field3";
int _NumberOfRows = 12;
_Query = String.Concat("SELECT TOP (#NumberOfRows) ",
_ColumnList, " FROM ", _TableName);
SqlParameter _NumRows = new SqlParameter("#NumberOfRows", SqlDbType.Int);
_NumRows.Value = _NumberOfRows;
try
{
_Connection.Open();
_Reader = _Command.ExecuteReader();
// do stuff
}
finally
{
_Reader.Close();
_Connection.Close();
}
Of course, you could also just concatenate the #NumberOfRows value directly into the query as well, but keeping it as a parameter will allow for Query Plan re-use if running this query multiple times with the same values for ColumnList and TableName but changing the #NumberOfRows value.

Replacing a string in a text field

I have a column in my database table which has lows of text and lows of rows. In the text, a url needs to be changed for every row. In each row the url can exist more than once.
Can I use the replace function to change all the urls in the text field in my database table without affecting the rest of the text in that same column?
Thanks
Use REPLACE()
UPDATE table SET text = REPLACE(text, 'from', 'to')
Make precise from: like with http://url_from.com/ to http://url_to.com/
Based on article posted at https://web.archive.org/web/20150521050102/http://sqlserver2000.databases.aspfaq.com:80/how-do-i-handle-replace-within-an-ntext-column-in-sql-server.html
I needed to write a find and replace for CHAR(146) ` in a text field. Above article for fort nText and the same solution for text worked with nText with the following changes:
- VARCHAR(32) from nVARCHAR(32)
- use #lenOldString = DATALENGTH(#oldString) instead of SET #lenOldString = DATALENGTH(#oldString)/2.
DECLARE
#TextPointer BINARY(16),
#TextIndex INT,
#oldString VARCHAR(32),
#newString VARCHAR(32),
#lenOldString INT,
#currentDataID INT;
SET #oldString = '’';
SET #newString = '''';
IF CHARINDEX(#oldString, #newString) > 0
BEGIN
PRINT 'Quitting to avoid infinite loop.';
END
ELSE
BEGIN
--Need the for nText fields
--SET #lenOldString = DATALENGTH(#oldString)/2
--Use this for text fields
SET #lenOldString = DATALENGTH(#oldString)
DECLARE irows CURSOR
LOCAL FORWARD_ONLY STATIC READ_ONLY FOR
SELECT
DataID
FROM
dbo.tbData
WHERE
PATINDEX('%'+#oldString+'%', TextData) > 0;
OPEN irows;
FETCH NEXT FROM irows INTO #currentDataID;
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT
#TextPointer = TEXTPTR(TextData),
#TextIndex = PATINDEX('%'+#oldString+'%', TextData)
FROM
dbo.tbData
WHERE
DataID = #currentDataID;
SELECT #TextPointer, #TextIndex
WHILE
(
SELECT
PATINDEX('%'+#oldString+'%', TextData)
FROM
dbo.tbData
WHERE
DataID = #currentDataID
) > 0
BEGIN
SELECT
#TextIndex = PATINDEX('%'+#oldString+'%', TextData)-1
FROM
dbo.tbData
WHERE
DataID = #currentDataID;
UPDATETEXT dbo.tbData.TextData #TextPointer #TextIndex #lenOldString #newString;
END
FETCH NEXT FROM irows INTO #currentDataID;
END
CLOSE irows;
DEALLOCATE irows;
END