I have a table called Keywords that 100's of keywords ranging from one word to several, all separated by commas. For example:
change of name, asb, repair, reporting violence
These keywords are grouped into categories.
We have users who can enter any text into a free text field. Example:
Caller rang to to speak to ASB about violence
How do I use SQL to read the words in the free text field to check for any matches in the keyword table? So in the example above I want it to pick up that ASB and Violence was stored in the Keyword table.
I would also want it bring back a result if only one word was used like ASB.
It's important to note that any words could be entered into the free text field.
I'm using Microsoft SQL Server 2014 SP2.
Thanks
As you have not specified your table names; I will create some. Please run this:
create table dbWords (id int not null identity, words varchar(100), primary key (id))
insert into dbWords (words) values ('change of name, asb, repair, reporting violence')
CREATE FUNCTION [dbo].[fnSplitString]
(
#string NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE(splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE #start INT, #end INT
SELECT #start = 1, #end = CHARINDEX(#delimiter, #string)
WHILE #start < LEN(#string) + 1 BEGIN
IF #end = 0
SET #end = LEN(#string) + 1
INSERT INTO #output (splitdata)
VALUES(SUBSTRING(#string, #start, #end - #start))
SET #start = #end + 1
SET #end = CHARINDEX(#delimiter, #string, #start)
END
RETURN
ENd
Then run this:
select * from dbWords inner join (
select * from dbo.fnSplitString('change of name, change of dob', ',')
) as splitdatatable on dbwords.words like '%,' + splitdata+ ',%'
or dbwords.words like '%,' + splitdata
or dbwords.words like splitdata + ',%'
The text passed to the function in the SQL statement above is the text entered by the user.
Related
I have some data which I bulk import into this table structure:
CREATE TABLE #Temp
(
WellKnownText NVARCHAR(MAX)
)
Some of the entries are not valid. So something like this:
SELECT geometry::STPolyFromText(WellKnownText,4326) FROM #Temp
does not work for all rows and thus falls over.
What is the best way to detect which WellKnownText are not valid? I have used MakeValid in the past - so ideally I would like to fix entries as much as possible.
PS:
This does not work:
SELECT * FROM #Temp
WHERE geometry::STPolyFromText(WellKnownText,4326).STIsValid() = 0
PPS:
I chose a loop based approach in the end along those lines:
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp;
IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL DROP TABLE #Temp1;
DECLARE #LoopCounter INT = 1;
DECLARE #MaxCounter INT;
DECLARE #Valid BIT;
DECLARE #ValidCounter INT;
DECLARE #WellKnownText NVARCHAR(MAX);
CREATE TABLE #Temp
(
Guid UNIQUEIDENTIFIER,
PostcodeFraction NVARCHAR(50),
WellKnownText NVARCHAR(MAX),
GeoJson NVARCHAR(MAX)
);
CREATE TABLE #Temp1
(
Guid UNIQUEIDENTIFIER,
PostcodeFraction NVARCHAR(50),
WellKnownText NVARCHAR(MAX),
GeoJson NVARCHAR(MAX)
);
BULK INSERT #Temp FROM 'D:\PolygonData.txt' WITH (FIELDTERMINATOR = '\t', FIRSTROW = 2, ROWTERMINATOR = '\n');
ALTER TABLE #Temp ADD Id INT IDENTITY(1,1);
SELECT #MaxCounter = MAX(Id) FROM #Temp
SET #ValidCounter = 0;
WHILE(#LoopCounter <= #MaxCounter)
BEGIN
BEGIN TRY
SELECT #WellKnownText = WellKnownText FROM #Temp WHERE Id = #LoopCounter;
SET #Valid = GEOMETRY::STGeomFromText(#WellKnownText,4326).STIsValid();
SET #ValidCounter = #ValidCounter + 1;
END TRY
BEGIN CATCH
SET #Valid = 0;
END CATCH
IF(#Valid = 1)
BEGIN
INSERT INTO #TEMP1
SELECT Guid, PostcodeFraction, WellKnownText, GeoJson FROM #Temp WHERE Id = #LoopCounter;
END
SET #LoopCounter = #LoopCounter + 1;
END
PRINT #ValidCounter;
SELECT * FROM #TEMP1;
As requested in the comments, some possible solutions
I guess you're really looking for a function that can be CROSS APPLYed, something like
SELECT * FROM #Temp T
CROSS APPLY IsWKTValidFunc(T.WellKnownText, 4326) F
WHERE F.IsValid = <somecondition>
(Or even added to as computed column to give you a flag that's set on inserting your WKT)
Stored Proc
https://gis.stackexchange.com/questions/66642/detecting-invalid-wkt-in-text-column-in-sql-server has a simple SP that wraps GEOMETREY::STGeomFromText in a try catch block.
However, stored procs cannot be CROSS APPLYed (or called from a UDF that can be) so this would result in a cursor based solution.
UDF
A UDF can be cross applied, but can't have a TRY-CATCH block. You also can't call the above SP from a UDF. So not much use there.
CLR UDF
Wrap the GEOMETREY::STGeomFromText call in a CLR UDF that can be CROSS APPLIED, can have try catch and other error checking, rules etc, and return a flag indicating valid text. I haven't tried this one out but this sounds like the best option if CLR is enabled in your environment.
Hope this gives you some ideas. Feedback in the comments to these suggestions appreciated.
Let's say I have data:
heloo
cuube
triniity
How to write script that will replace those "doubled" characters with only one? So the result from the above data set would be:
helo
cube
trinity
Usually I post some script where I tried to achieve this, but this time I can't think of any.
This should work:
CREATE PROCEDURE remove_duplicate_characters(#string VARCHAR(100))
AS
DECLARE #result VARCHAR(100)
SET #result=''
SELECT #result=#result+MIN(SUBSTRING(#string ,number,1)) FROM
(
SELECT number FROM master..spt_values WHERE type='p' AND number BETWEEN 1 AND len(#string )) AS t GROUP BY SUBSTRING(#string,number,1) ORDER BY MIN(number)
)
SELECT #result
GO
You then call it like this:
EXEC remove_duplicate_characters 'heloo'
Source
This script does not depend on having access to master functions, and just relies on t-sql string functions.
declare #word varchar(100) = 'aaaacuuuuuubeeeee', #result varchar(100) = ''
declare #letter char, #idx int = 0, #lastletter char = ''
while(#idx <= len(#word))
begin
select #letter = substring(#word,#idx,1)
if (#letter != #lastletter)
begin
select #result = concat(#result,#letter)
end
select #lastletter = #letter,#idx = #idx + 1
end
select #result
I am working on C# project which needs a stored procedure which will take two table names as inputs.
First table will copy data to a temp table which has two columns URL & channelID. This URL column is then matched with other input table's URL column & if match is found then it will update channel id from temp table to other tables channel ID.
I have written stored procedure as
CREATE PROCEDURE [dbo].[UpdateTables]
#excelTable NVARCHAR(128) ,
#TableName NVARCHAR(128)
AS
Declare #channel_Id nvarchar(50)
Declare #url varchar(400)
BEGIN
Select *
Into #Temp
From QUOTENAME(#excelTable)
END
While EXISTS(SELECT * From #Temp ) > 0
Begin
Select Top 1
#channel_Id = channel_Id, #url = url
From #Temp
update QUOTENAME(#TableName)
set channelid = #channelid
where pagefullurl like '%'+ #url + '%'
Delete #Temp
Where channelid = #channelid
End
I don't have much knowledge in TSQL and my above code has errors.
Incorrect syntax near '>'.
Msg 137, Level 15, State 2, Procedure UpdateTables, Line 20
Must declare the scalar variable "#channelid".
Msg 137, Level 15, State 2, Procedure UpdateTables, Line 22
Must declare the scalar variable "#channelid".
Please suggest what changes needs to done
I don't have MS SQL server handy to test it, but you declare your variable as #channel_Id, and later try to use it as #channelid (without the underscore) so you get errors about the undeclared variable.
I've corrected your SP and this is how it should look
CREATE PROCEDURE [dbo].[UpdateTables]
#excelTable NVARCHAR(128) ,
#TableName NVARCHAR(128)
AS
Declare #channel_Id nvarchar(50)
Declare #url varchar(400)
BEGIN
Select *
Into #Temp
From QUOTENAME(#excelTable)
While EXISTS(SELECT * From #Temp )
Begin
Select Top 1
#channel_Id = channel_Id, #url = url
From #Temp
update QUOTENAME(#TableName)
set channelid = #channel_Id
where pagefullurl like '%'+ #url + '%'
Delete #Temp
Where channelid = #channel_Id
End
END
In SQL Server 2008 (TSQL), I've created a stored procedure like this:
CREATE PROCEDURE SP_1_10_2
AS
declare #mostValuableBook nvarchar(255)
SELECT #mostValuableBook = Name
FROM books
WHERE price =
( SELECT MAX(price)
FROM books
WHERE izd LIKE '%BHV%' );
return #mostValuableBook
GO
But, when I'm trying to execute it:
declare #x nvarchar(255)
EXECUTE #x = SP_1_10_2;
SELECT 'The most expensive BHV book:', #x AS 'Name'
GO
I'm getting an error:
Conversion failed when converting the nvarchar value 'Internet
Explorer 3 original' to data type int.
It seems like the problem is in the line
EXECUTE #x = SP_1_10_2;
Can you please tell me what's wrong? Why is it trying to convert to int?
RETURN cannot be used to return nvarchar / varchar such as you have. RETURN is used to return an integer, this can be expressed as some sort of status code 1=True / 0=False. Read more about return here: http://msdn.microsoft.com/en-us/library/ms174998.aspx
In your case, you simply need to use OUTPUT variables which is similiar to pass-by-ref in C# or C++. You pass the variable to the sproc, the sproc modifies it, and you get the expected results after a SELECT....
Change it so that your parameters becomes an output parameter:
CREATE PROCEDURE SP_1_10_2
#mostValueableBook nvarchar(255) output
AS
SELECT #mostValuableBook = Name
FROM books
WHERE price =
( SELECT MAX(price)
FROM books
WHERE izd LIKE '%BHV%' );
SELECT #mostValuableBook
GO
Call it like so:
DECLARE #theValBook nvarchar(255)
EXECUTE SP_1_10_2 #mostValuableBook = #theValBook output
Then you can say:
SELECT 'Most expensive book is', #theValBook
You can also create a function to return the value you desire instead of relying on numeric return codes. SQL Functions come in quite handy. See example below which returns the last name with the highest client id using the LIKE operator
Use MYDB
GO
CREATE Function fn_LastClientIdByName
(
#nameLike NVARCHAR(10)
)
RETURNS NVARCHAR(100)
AS
BEGIN
DECLARE #result nvarchar(100)
DECLARE #clientName NVARCHAR(100)
SELECT top 1 #clientName = [clientLast] + ' ' + [clientFirst]
FROM [dbo].[duiClientOnly]
WHERE clientLast like #nameLike + '%'
order by clid desc
select #result = #clientName
return #result
END
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Cannot find either column “dbo” or the user-defined function or aggregate “dbo.Splitfn”, or the name is ambiguous
--function that parses an array based on any delimiter
CREATE FUNCTION valuedfunction
(
#string VARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE(
data VARCHAR(256)
)
BEGIN
DECLARE #start INT, #end INT
SELECT #start = 1, #end = CHARINDEX(#delimiter, #string)
WHILE #start < LEN(#string) + 1 BEGIN
IF #end = 0
SET #end = LEN(#string) + 1
INSERT INTO #output (data)
VALUES(SUBSTRING(#string, #start, #end - #start))
SET #start = #end + 1
SET #end = CHARINDEX(#delimiter, #string, #start)
END
RETURN
END
--stored procedure that supports a comma separated value list of employee IDs. I use the function ---(valuedfunction) to get the employee data.
CREATE PROCEDURE commaseparated
#keyList varchar(40)
AS
SELECT Title, Birthdate
FROM HumanResources.Employee WITH (NOLOCK)
WHERE EmployeeID IN (dbo.valuedfunction(#keyList))
--This is the problem: I am getting errors below: What am I missing
exec commaseparated '10,11,12,13';
--ERROR MESSAGE:
Msg 4121, Level 16, State 1, Procedure commaseparated, Line 4
Cannot find either column "dbo" or the user-defined function or aggregate "dbo.valuedfunction", or the name is ambiguous.
Write
WHERE EmployeeID IN (select data from dbo.valuedfunction(#keyList))