I have a table called webqueries with a column named qQuestion of data type text(sql server 2008). I want to create a count on words used in qQuestion (excluding 'and', 'is' etc). My goal is to see how many times a person has asked a question about a specific product.
You could create a table-valued function to parse words and join it to your query against qQuestion. In your schema, I recommend using varchar(8000) or varchar(max) instead of text. Meanwhile, the following should get you started:
create function [dbo].[fnParseWords](#str varchar(max), #delimiter varchar(30)='%[^a-zA-Z0-9\_]%')
returns #result table(word varchar(max))
begin
if left(#delimiter,1)<>'%' set #delimiter='%'+#delimiter;
if right(#delimiter,1)<>'%' set #delimiter+='%';
set #str=rtrim(#str);
declare #pi int=PATINDEX(#delimiter,#str);
while #pi>0 begin
insert into #result select LEFT(#str,#pi-1) where #pi>1;
set #str=RIGHT(#str,len(#str)-#pi);
set #pi=PATINDEX(#delimiter,#str);
end
insert into #result select #str where LEN(#str)>0;
return;
end
go
select COUNT(*)
from webqueries q
cross apply dbo.fnParseWords(cast(q.qQuestion as varchar(max)),default) pw
where pw.word not in ('and','is','a','the'/* plus whatever else you need to exclude */)
Related
I have made a stored procedure. I want it to filter the data by different parameters. If I pass one parameter, it should be filtered by one; if I pass two, it should be filtered by two, and so on, but it is not working.
Can anyone help me please?
DROP PROCEDURE IF EXISTS medatabase.SP_rptProvince2;
CREATE PROCEDURE medatabase.`SP_rptProvince2`(
IN e_Region VARCHAR(45)
)
BEGIN
DECLARE strQuery VARCHAR(1024);
DECLARE stmtp VARCHAR(1024);
SET #strQuery = CONCAT('SELECT * FROM alldata where 1=1');
IF e_region IS NOT NULL THEN
SET #strQuery = CONCAT(#strQuery, ' AND (regionName)'=e_Region);
END IF;
PREPARE stmtp FROM #strQuery;
EXECUTE stmtp;
END;
AFAIK, you can't have a variable argument list like that. You can do one of a couple of things:
Take a fixed maximum number of parameters, and check them for null-ness before concatenating:
CREATE PROCEDURE SP_rptProvince2(a1 VARCHAR(45), a2 VARCHAR(45), ...)
...
IF a1 IS NOT NULL THEN
SET #strQuery = CONCAT(#strQuery, ' AND ', a2);
END IF;
If you need predetermined fields to which the criteria in the argument apply (like the e_Region parameter in your existing code), then you modify the CONCAT operation appropriately.
Possible invocation:
CALL SP_rptProvince2('''North''', 'column3 = ''South''')
Take a single parameter that is much bigger than just 45 characters, and simply append it to the query (assuming it is not null).
Clearly, this places the onus on the user to provide the correct SQL code.
Possible invocation:
CALL SP_rptProvince2('RegionName = ''North'' AND column3 = ''South''')
There's not a lot to choose between the two. Either can be made to work; neither is entirely satisfactory.
You might note that there was a need to protect the strings in the arguments with extra quotes; that is the sort of thing that makes this problematic.
I found a JSON-based approach which works with the latest MySQL/MariaDB systems. Check the link below (Original Author is Federico Razzoli): https://federico-razzoli.com/variable-number-of-parameters-and-optional-parameters-in-mysql-mariadb-procedures
Basically, you take a BLOB parameter which is actually a JSON object and then do JSON_UNQUOTE(JSON_EXTRACT(json object, key)) as appropriate.
Lifted an extract here:
CREATE FUNCTION table_exists(params BLOB)
RETURNS BOOL
NOT DETERMINISTIC
READS SQL DATA
COMMENT '
Return whether a table exists.
Parameters must be passed in a JSON document:
* schema (optional). : Schema that could contain the table.
By default, the schema containing this procedure.
* table : Name of the table to check.
'
BEGIN
DECLARE v_table VARCHAR(64)
DEFAULT JSON_UNQUOTE(JSON_EXTRACT(params, '$.table'));
DECLARE v_schema VARCHAR(64)
DEFAULT JSON_UNQUOTE(JSON_EXTRACT(params, '$.schema'));
IF v_schema IS NULL THEN
RETURN EXISTS (
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE
TABLE_SCHEMA = SCHEMA()
AND TABLE_NAME = v_table
);
ELSE
RETURN EXISTS (
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE
TABLE_SCHEMA = v_schema
AND TABLE_NAME = v_table
);
END IF;
END;
I have a question for You.
I need an idea to search items in long list of parameters in sql reporting services.
For example there is a houndred of values in list of parameters to select and i have to choose some of them. There exists problem with finding these values because list is too big.
Something searching by first couple letters would be great but probably it is impossible.
Now I really do not know how i could achieve smart method to find couple interested values from list of parameters.
Please help.
For your requirement, I have found an awesome article talking about this with detail solution:
Create a function in your database.
CREATE FUNCTION [dbo].[SplitParameterValues] (#InputString NVARCHAR(max), #SplitChar VARCHAR(5))
RETURNS #ValuesList TABLE
(
param NVARCHAR(255)
)
AS
BEGIN
DECLARE #ListValue NVARCHAR(max)
SET #InputString = #InputString + #SplitChar
WHILE #InputString!= #SplitChar
BEGIN
SELECT #ListValue = SUBSTRING(#InputString , 1, (CHARINDEX(#SplitChar, #InputString)-1))
IF (CHARINDEX(#SplitChar, #InputString) + len(#SplitChar))>(LEN(#InputString))
BEGIN
SET #InputString=#SplitChar
END
ELSE
BEGIN
SELECT #InputString = SUBSTRING(#InputString, (CHARINDEX(#SplitChar, #InputString) + len(#SplitChar)) , LEN(#InputString)-(CHARINDEX(#SplitChar, #InputString)+ len(#SplitChar)-1) )
END
INSERT INTO #ValuesList VALUES( #ListValue)
END
RETURN
END
Use a procedure the get the Available Values, refer to the query below:
create PROCEDURE sp (#keyword nvarchar(50))
AS
SELECT col
FROM table d
inner join (SELECT [param] FROM SplitParameterValues (#keyword,',')) s on d.col like (s.[param]+'%')
Then create a parameter for giving keywords. Then add another cascading parameter based on the key words. For detail steps, please read the source article from the link below:
[Forum FAQ]How do I add a search feature in the parameter with long drop down list?
Ok, this question involves one part of a complicated stored procedure which inserts new entities into several tables.
The part that I'm currently having difficulty with needs to work like so:
insert entity with original name
check if name of new entity contains any special characters listed in table A 'Characters'
if yes, than replace that character with a 'replacement character' from table A
EDIT: I've gotten this to partially work but still not finished. I'm still having a problem showing each combination of character replacements. Also in the case of a replacement character occurring more than once, such as the '.', the substitutions needs to happen independently of one another.
ex: #www.test&aol.com -> #wwwtest&aol.com, #www.test&aolcom
Here's a rough start, I know parts of this aren't going to work, but I thought it was a decent starting point:
declare #test varchar(50)
set #test = '#www.test&aol.com'
declare #len int, #ctr int
set #len = LEN(#test)
set #ctr = 1
declare #newName varchar(50)
declare #matchedChar table(match varchar(10),replaceChar varchar(10),processed int default(0))
declare #alternateEntities table(name varchar(50))
declare #repChar varchar(10)
declare #selectedChar varchar(1)
while #ctr<=#len
begin
--Insert matching characters and replacement characters into table variable,
--this is necessary for the # character, which has multiple replacement characters
insert into #matchedChar (match,replaceChar) select Character,ReplacementCharacter from tblTransliterations where Character = SUBSTRING(#test,#ctr,1)
--loop
while (select COUNT(*) from #matchedChar where processed = 0)>0
begin
--get the top character from table variable
set #selectedChar = (select top 1 match from #matchedChar where processed = 0)
--get replacement character
set #repChar = (select top 1 replaceChar from #matchedChar where processed = 0)
--replace character in name string
--set #newName = (select Replace(#test,#selectedChar,#repChar))
set #newName = (select STUFF(#test,CHARINDEX(#selectedChar,#test),1,#repChar))
--update table variable to move onto next character
update #matchedChar set processed = 1 where #repChar = replaceChar
--add name with replaced character to alternate entities table
insert into #alternateEntities (name) values (#newName)
end
set #ctr = #ctr+1
set #len = LEN(#test)
end
select * from #alternateEntities
Instead of looping, use set-based approach.
Create a temp table and populate column 'Words' of type NVARCHAR(100), call the temp table Invalid_Words
Create a column on Invalid_Words for each token and make the col type = bit
Update the temp table bit columns if a word contains the token through a series of update statements
You now have defined which tokens were matched for each word.
The next part is to replace.
I'm migrating from SqlServer 2008 to MySql and I have a lot of stored procedure that use a generic table-value function that split a varchar.
The sqlserver function declaration is:
CREATE FUNCTION [dbo].[fnSplit](
#sInputList VARCHAR(8000) -- List of delimited items
, #sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
) RETURNS #List TABLE (item varchar(50))
/* SAMPLE
select * from fnSplit('12 345 67',' ')
select * from fnSplit('12##34#5##67','##')
*/
BEGIN
DECLARE #sItem VARCHAR(8000)
WHILE CHARINDEX(#sDelimiter,#sInputList,0) <> 0
BEGIN
SELECT #sItem=RTRIM(LTRIM(SUBSTRING(#sInputList,1,CHARINDEX(#sDelimiter,#sInputList,0)-1))),
#sInputList=RTRIM(LTRIM(SUBSTRING(#sInputList,CHARINDEX(#sDelimiter,#sInputList,0)+LEN(#sDelimiter),LEN(#sInputList))))
IF LEN(#sItem) > 0
INSERT INTO #List SELECT #sItem
END
IF LEN(#sInputList) > 0
INSERT INTO #List SELECT #sInputList -- Put the last item in
RETURN
END
It is not possible to write Table-value stored function in my SQL server. MySQL stored function returns single values only. However, if the situation demands a function to return a set of data, you have only two choices. You may create a string using some separators with your result set and return it to the caller.
I am trying to create a stored procedure to achieve the following in the stored procedure
DECLARE #TBLNAME VARCHAR(128)
SET #TBLNAME = SELECT PAR_VALUE FROM DBO.PARAMETERS WHERE PAR_NAME='SALES_ORDERS_TABLE';
The PAR_VALUE column in the PARAMETERS table contains the name of the table of the Sales Order table.
I now want to use this table name in the stored procedure, and count the number of rows in this table.
DECLARE #SQL NVARCHAR(4000)
# SQL = SELECT COUNT(*) FROM '[#TBLNAME]'
However, when I try to run this, there are multiple errors.
Can you please help me by guiding on how to do this?
I just now tried this code:
CREATE PROCEDURE JCOUNT_SO
AS
DECLARE #TBLNAME NVARCHAR(512)
SELECT #TBLNAME=(SELECT PAR_VALUE FROM DBO.PARAMETERS WHERE PAR_NAME='SALES_ORDERS_TABLE')
DECLARE #SQL NVARCHAR(4000)
SELECT #SQL='SELECT COUNT(*) AS #_OF_RECORDS INTO SO_COUNT
FROM' '+QUOTENAME(#TBLNAME)''
EXEC SP_EXECUTESQL #SQL;
Error Message: Invalid Object Name: 'TEST.DBO.SO_MASTER'
Please help on this code.
Please read defination of sp_executesql for reference. Procedure below returns value as an output parameter from dynamic query rather than inserting into a table. You can manipulate query as per your requirement.
CREATE PROCEDURE JCOUNT_SO
AS
DECLARE #TBLNAME nvarchar(512)
--Obtain table name. Top 1 is used to pick first record rather than last record in case query returns more than one record.
SELECT TOP 1 #TBLNAME = PAR_VALUE FROM DBO.PARAMETERS WHERE PAR_NAME='SALES_ORDERS_TABLE'
DECLARE #SQL NVARCHAR(4000)
DECLARE #Count int
SET #SQL ='SELECT #Count = COUNT(*) FROM ' + #TBLNAME
--Define parameters to be passed i.e. #Count is being passed as output parameter
EXEC SP_EXECUTESQL #SQL, N'#Count int OUTPUT', #Count output
select #Count
end
Notes from MSDN
Query i.e. #SQL can contain parameters having the same form as a variable name and each parameter included in #SQLmust have a corresponding entry in both the #params parameter definition list and the parameter values list
1 point I can say is ... it should be SET #SQL = SELECT ...
and one more thing is you can try converting the result to NVARCHAR.
use SELECT Convert(NVARCHAR(4000),Count(*)) FROM ...