I have a table which contains some commercial Short text such as 'PVT, LTD' etc as in figure.
Secondly we have a new title received from another side every time such as 'Taha Zubair' and 'Taha PVT Ltd'.
Now i need to find just that if title contains a keyword, after scanning from database i need to return count only. If count is zero (0) means that title is simple as 'Taha Zubair' else return > 1 if title is some thing like that 'Taha PVT Ltd' or 'Taha Trust'
Image: http://social.msdn.microsoft.com/Forums/getfile/195838
Furthermore i need to do it some thing like that it would be adjust in stored Procedure, using whole query in programming application(Inline query) would affect the performance.
if you have any question ask it without any hesitation........
as function
Create Function F_GetNonIndividual(#SearchStr nVarchar(100)) Returns int
as -- use Select dbo.F_GetNonIndividual('Abc Solutions PVT LTD')
begin
Declare #Result int
Select #Result = Count(*)
from NonIndividualTitle
where #SearchStr Like ('%'+NonIndivTitle+'%')
Return #Result
end
as procedure
Create Procedure P_GetNonIndividual(#SearchStr nVarchar(100))
as -- use EXEC P_GetNonIndividual 'Abc Solutions PVT LTD'
begin
Select Count(*)
from NonIndividualTitle
where #SearchStr Like ('%'+NonIndivTitle+'%')
end
as procedure with out param
Create Procedure P_GetNonIndividualOut(#SearchStr nVarchar(100), #OutValue int out)
as
begin
Select #OutValue=Count(*)
from NonIndividualTitle
where #SearchStr Like ('%'+NonIndivTitle+'%')
end
with query example
Declare #OutValue int
exec P_GetNonIndividualOut 'Abc Solutions PVT LTD',#OutValue out
print #OutValue
Related
I have a quoting system where we are cleaning the data read in from a imported file, and in the for each of the read line in the file, we hit SQL to see if the item exist, or if it is a typo / not found / etc to get the fuzzy found results back for each on. That way afterwards, and the end user can then correct the bad / not found items, to the correct ones we found in the fuzzy search.
That being said, this scrub tool is used by importing a CSV file that could be anywhere from 500 records to 10k records.
When i do it per line, im hitting SQL many many times quickly causing a lack in efficiency and speed.
I was hoping to try the following to handle one call to SQL, and do it all on the SQL server to test difference in speeds.
This is currently a small snippet to get to the point of this question, of how it looks up if the item is existing currently in our pricing central DB, or if we need to run a fuzzy search and return a few items for the end user to select correct price.
This is how i reading the file since its large, and is blazing fast:
using (BufferedStream bs = new BufferedStream(uploadedFile.InputStream))
{
using (StreamReader sr = new StreamReader(bs))
{
// store in array here... for later looping to the SQL lookups
}
}
// After I read the entire file, then placed into array of rows,
// the next is how i loop to lookup each match, por find best matches using fuzzy
foreach (var baseQuoteItem in quoteDataRows)
{
hubContext.Clients.Client(connectionId).SendMessage(connectionId, String.Format("Reading record {0} of {1} ", callCounter.ToString(), fullRecords.ToString()));
// service away
var searches = _quoteEntityService.GetAssetsFromFuzzySearch(baseQuoteItem.Manufacturer, baseQuoteItem.Model, baseQuoteItem.Description).ToList();
int totalFoundResults = searches.Count();
baseQuoteItem.SuggestionsList = new List<QuoteEntityItemVM>();
}
What I would like to try is build all the objects, then send it with delimiter of properties by a comma, then each object by a ^. That way the stored procedure parameter would have data like below:
obj.P1, obj.P2, obj.P3 ^ obj2.P!1, obj2.P2, obj2.P3 ^
and so on. Then I could send thousands of objects with the properties I need in the query in as a string, and loop through each entity between ^ and then do the lookup on them using the values of that entity by splitting the properties by comma.
Example in SQL (I know syntax here is wrong it is for demonstration purposes only":
#OBJECTS = split(#ITEMS on ","); //now i have rows or array of all items.
then
foreach(var i in #OBJECTS)
BEGIN
do fuzzy search here for i
END
Is this possible and how would I set this up?
Here is the current SQL Server stored procedure I am using:
ALTER PROCEDURE [dbo].[DATA_FuzzyAssetMacth]
#Mfr AS VARCHAR(100),
#Model AS VARCHAR(100),
#Desc AS VARCHAR(150)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #s1 VARCHAR(100);
DECLARE #_MFRFIND INT;
DECLARE #_MDNUMBER INT;
DECLARE #MDDESC VARCHAR(150);
DECLARE #_SEARCH VARCHAR(150);
IF OBJECT_ID('tempdb..#TEMPPMFR') IS NOT NULL
DROP TABLE #TEMP
IF OBJECT_ID('tmpdb..#TEMPPMFRMODEL') IS NOT NULL
DROP TABLE #TEMPPMFRMODEL
IF((SELECT COUNT(*) FROM Products_OurProducts_Products AS POP
WHERE POP.Manufacturer = #Mfr
AND POP.ManufacturerPartNumber = #Model) > 0)
BEGIN
--DIG DONE AND RETURN
SELECT
POP.Manufacturer, POP.ManufacturerPartNumber,
POP.Description AS ManufacturerDescription,
CONVERT(money, POP.Price) AS Price, POP.ItemType,
CAST('1' AS BIT) AS MfrFound, CAST('1' AS BIT) AS ModelFound,
CAST('-1' AS int) AS Score
FROM
Products_OurProducts_Products AS POP
WHERE
POP.Manufacturer = #Mfr
AND POP.ManufacturerPartNumber = #Model
END
ELSE
-- CHECK IF WE HAVE MATCH AT MFR LEVEL, THEN MODEL, THEN DESCRIPTION
-- IF WE DO NOT HAVE IT AT ONE LEVEL, APPLY SELECT TO BASE LEVELS, THEN FUZZY SEARCH NEXT LEVEL
IF((SELECT COUNT(*) FROM Products_OurProducts_Products AS POP
WHERE POP.Manufacturer = #Mfr) > 0)
BEGIN
IF((SELECT COUNT(*) FROM Products_OurProducts_Products AS POP
WHERE POP.Manufacturer = #Mfr
AND POP.ManufacturerPartNumber = #Model) > 0)
--DIG DONE AND RETURN
SELECT
POP.Manufacturer, POP.ManufacturerPartNumber,
POP.Description AS ManufacturerDescription,
CONVERT(money, POP.Price) AS Price, POP.ItemType,
CAST('1' AS BIT) AS MfrFound, CAST('1' AS BIT) AS ModelFound,
CAST('-1' AS int) AS Score
FROM
Products_OurProducts_Products AS POP
WHERE
POP.Manufacturer = #Mfr
AND POP.ManufacturerPartNumber = #Model
ELSE
-- WE NEED TO USE FUZZY ON MODEL NUMBER
BEGIN
SELECT
PMFR.Manufacturer, PMFR.ManufacturerPartNumber,
PMFR.Description AS ManufacturerDescription,
CONVERT(money, PMFR.Price) AS Price,
PMFR.ItemType, CAST('1' AS BIT) AS MfrFound,
CAST('0' AS BIT) AS ModelFound
INTO
#TEMPPMFR
FROM
Products_OurProducts_Products AS PMFR
WHERE
PMFR.Manufacturer = #Mfr;
SELECT TOP 5
P.Manufacturer, P.ManufacturerPartNumber,
P.ManufacturerDescription, P.Price, P.ItemType,
P.MfrFound, P.ModelFound, fms.score AS Score
FROM
#TEMPPMFR AS P
CROSS APPLY
(SELECT
dbo.FuzzyControlMatch(#Model, P.ManufacturerPartNumber) AS score) AS fms
ORDER BY
fms.score DESC
END
END
ELSE
-- IF HAVE A FUZZY AT MFR, THEN WE NEED TO GRAB BEST CHOICE AND GO DOWN.
-- WE COULD HAVE POSSIBLY CANDIDATES FOR THIS SO WHEN TO STOP RECURSIVENESS AND SAY ADDING NEW ENTRY?
BEGIN
--AT MOMENT JUST RETURN TOP FOUND MFR THEN SELECT FROM THAT TO SEE RESULT TESTS
DECLARE #TEMP_MFRNAME VARCHAR(100);
--FIRST LETS SEE IF SENT MODEL EXIST AND IF SO, PULL THAT THEN RANK AGAINST MFR FOR IT
IF((SELECT COUNT(*) FROM Products_OurProducts_Products AS POP WHERE POP.ManufacturerPartNumber = #Model) > 0)
BEGIN
--DIG DONE AND RETURN
SELECT PMFR.Manufacturer, PMFR.ManufacturerPartNumber, PMFR.Description AS ManufacturerDescription, CONVERT(money,PMFR.Price) AS Price, PMFR.ItemType, CAST('0' AS BIT) AS MfrFound, CAST('1' AS BIT) AS ModelFound
INTO #TEMPPMFRMODEL
FROM Products_OurProducts_Products AS PMFR
WHERE PMFR.ManufacturerPartNumber = #Model;
SELECT top 5 P.Manufacturer, P.ManufacturerPartNumber,P.ManufacturerDescription, P.Price, P.ItemType, P.MfrFound, P.ModelFound, fms.score as Score
FROM #TEMPPMFRMODEL AS P
CROSS APPLY (select dbo.FuzzyControlMatch(#Mfr, P.Manufacturer) AS score) AS fms
ORDER by fms.score desc
END
--THEN SEE IF EXIST USING FUZZY FOUND MFR, TO SEEK MODEL NUMBER ETC.
END
IF OBJECT_ID('tempdb..#TEMPPMFR') IS NOT NULL
DROP TABLE #TEMP
IF OBJECT_ID('tmpdb..#TEMPPMFRMODEL') IS NOT NULL
DROP TABLE #TEMPPMFRMODEL
END
I have a stored procedure which looks like following:
alter procedure [dbo].[zsp_deleteEndedItems]
(
#ItemIDList nvarchar(max)
)
as
delete from
SearchedUserItems
WHERE EXISTS (SELECT 1 FROM dbo.SplitStringProduction(#ItemIDList,',') S1 WHERE ItemID=S1.val)
The parameter IDList is passed like following:
124125125,125125125...etc etc
And the split string function look like following:
ALTER FUNCTION [dbo].[SplitStringProduction]
(
#string nvarchar(max),
#delimiter nvarchar(5)
) RETURNS #t TABLE
(
val nvarchar(500)
)
AS
BEGIN
declare #xml xml
set #xml = N'<root><r>' + replace(#string,#delimiter,'</r><r>') + '</r></root>'
insert into #t(val)
select
r.value('.','varchar(500)') as item
from #xml.nodes('//root/r') as records(r)
RETURN
END
This is supposed to delete all items from table "SearcheduserItems" under the IDs:
124125125 and 125125125
But for some reason after I do a select to check it out:
select * from SearchedUserItems
where itemid in('124125125','125125125')
The records are still there...
What am I doing wrong here? Can someone help me out?
As mentioned in the comments, a different option would be to use a table type parameter. This makes a couple of assumptions (some commented), however, should get you on the right path:
CREATE TYPE dbo.IDList AS TABLE (ItemID int NOT NULL); --Assumed int datatype;
GO
ALTER PROC dbo.zsp_deleteEndedItems #ItemIDList dbo.IDList READONLY AS
DELETE SUI
FROM dbo.SearchedUserItems SUI
JOIN #ItemIDList IDL ON SUI.ItemID = IDL.ItemID;
GO
--Example of usage
DECLARE #ItemList dbo.IDList;
INSERT INTO #ItemList
VALUES(123456),(123457),(123458);
EXEC dbo.zsp_deleteEndedItems #ItemList;
GO
In regards to the question of an inline table value function, one such example is the below, which I quickly wrote up, that provides a tally table of the next 1000 numbers:
CREATE FUNCTION dbo.NextThousand (#Start int)
RETURNS TABLE
AS RETURN
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)
)
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 + #Start AS I
FROM N N1 --10
CROSS JOIN N N2 --100
CROSS JOIN N N3; --1,000
GO
The important thing about an iTVF is that it has only one statement, and that is the RETURN statement. Declaring the table as a return type variable, inserting data into it, and returning that variable turns it into a multi-line TVF; which perform far slower.
I have function for combobox.
ALTER FUNCTION [FN.USERNew]
(
#USER_ID INT
)
RETURNS TABLE
AS
RETURN
(
Select [USER_NAME] , username_Id From USER
WHERE USER_ID=#USER_ID
)
GO
I try to use above function in my stored procedure like below.
However, I get an error
Cannot Find either column"dbo" or the user -defined function or aggregate "dbo.FN.USERNew", or name is ambigous."
ALTER PROCEDURE DBO.[MY_STORED_PROCEDURE]
(
#USER_ID INT,
#PRODUCT_ID INT
)
AS
BEGIN
SELECT
PRODUCT_ID,
PRODUCT_NAME
DBO.FN.USERNew(USER_ID) AS PROBLEMHERE
FROM PRODUCT_TABLE
WHERE PRODUCT_ID=#PRODUCT_ID
END
So why i can not use my function in my stored procedure ?
You have to continue to quote the name using [] or "" because . is used to separate name parts:
ALTER PROCEDURE DBO.[MY_STORED_PROCEDURE]
(
#USER_ID INT,
#PRODUCT_ID INT
)
AS
BEGIN
SELECT
PRODUCT_ID,
PRODUCT_NAME
DBO.[FN.USERNew](USER_ID) AS PROBLEMHERE
FROM PRODUCT_TABLE
WHERE PRODUCT_ID=#PRODUCT_ID
END
See Database Identifiers.
However, this is a table valued function - which would more normally be used in the FROM clause (possibly via APPLY) - I'm not sure that SQL Server will let you use it in the SELECT clause since it can return multiple columns and rows. I think you may want:
ALTER PROCEDURE DBO.[MY_STORED_PROCEDURE]
(
#USER_ID INT,
#PRODUCT_ID INT
)
AS
BEGIN
SELECT
PRODUCT_ID,
PRODUCT_NAME
ft.* AS PROBLEMHERE
FROM PRODUCT_TABLE pt
CROSS APPLY DBO.[FN.USERNew](pt.USER_ID) ft
WHERE pt.PRODUCT_ID=#PRODUCT_ID
END
I have an application right now that has special user roles hardwired into the executable. It is tamper proof, but is a bit of a mess when it comes to new hires, role changes, etc.
So, I want to create a stored procedure that can return the appropriate employee badge numbers for any given operation.
My expertise is in C# development, but I am also the guy who works on the SQL Server (2000) database.
Here is what I'm starting out with, but T-SQL does not like this at all!
CREATE PROCEDURE sp1_GetApprovalBadges(#operation varchar(50)) as
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
declare #op varchar(50);
declare #num varchar(50);
declare #table table (NUM varchar(50) null);
select #op=upper(#operation);
case
when #op='CLERK' then
insert into #table (NUM) values (#num) where #num in ('000988','001508','003790','007912') end
when #op='HRMANAGER' then
insert into #table (NUM) values (#num) where #num in ('003035') end
when #op='HUMANRESOURCES' then
insert into #table (NUM) values (#num) where #num in ('002864','005491') end
when #op='INFORMATIONTECHNOLOGY' then
insert into #table (NUM) values (#num) where #num in ('001258','003423','007135','007546') end
end;
SELECT NUM from #table order by NUM;
END
GO
I realize this is very much like code that I write and is not database related, but having the database there affords me a great way to store and execute some scripts that I can modify as needed to keep my application working.
I see at least two issues
Replace case with if elses
execute table variables using dynamic sql
for example
if #op='CLERK'
begin
exec 'insert into ' + #table + '(NUM) values (' + #num + ') where' + #num + 'in (''000988'',''001508',''003790',''007912'')'
end
else if #op='HRMANAGER'
begin
i-- see above
end
else if #op='HUMANRESOURCES'
begin
-- see above
end
else if #op='INFORMATIONTECHNOLOGY'
begin
-- see above
end
exec 'SELECT NUM from' + #table + 'order by NUM;'
Syntax may not be exact, but the idea will work
CASE is an EXPRESSION that returns a single value. You can't use it for control-of-flow logic like you're attempting. Based on the conditions (hard-coded sets of strings) you probably meant something like this (quietly glazing over several other problems with the syntax you've attempted):
...
SELECT #op=upper(#operation);
IF #op = 'CLERK'
BEGIN
INSERT #table (NUM)
SELECT '000988'
UNION ALL SELECT '001508'
UNION ALL SELECT '003790'
UNION ALL SELECT '007912';
END
IF #op = 'HRMANAGER'
BEGIN
INSERT #table (NUM)
SELECT '003035';
END
IF #op = 'HUMANRESOURCES'
BEGIN
INSERT #table (NUM)
SELECT '002864'
UNION ALL SELECT '005491';
END
IF #op = 'INFORMATIONTECHNOLOGY'
BEGIN
INSERT #table (NUM)
SELECT '001258'
UNION ALL SELECT '003423'
UNION ALL SELECT '007135'
UNION ALL SELECT '007546'
END
SELECT NUM from #table order by NUM;
...
I have a int array of ID's (a lot of checkboxes I can choose from) which I want to get in one database call though a stored procedure.
Is there a way to work with an array of these ID's in SQL Server? I believe it should be something with splitting the array and then loop it (in sql). I just don't know how?
SQL Server 2008
There are many ways to do this:
Pass in a varchar parameter of the values separated by commas and parse that out (not very efficient, but for a small amount of data, not too bad except for the parsing bit)
Pass in XML and use the built in XML functions (SQL Server 2005+ has better support for this than earlier versions)
Use table value parameters (SQL Server 2008+)
Since you are using SQL Server 2008, use table value parameters.
EDIT: Example below
As #Oded mentioned, table valued parameters is the best option.
However, if for some reason you can't use these (perhaps your calling framework's limitations), you can use the following to perform the split to table:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[SplitToTable]
(
#List varchar(max), #Delim varchar(1)
)
RETURNS TABLE
AS
RETURN
(
WITH csvtbl(Start, [Stop]) AS (
SELECT Start = convert(bigint, 1), [Stop] =
charindex(#Delim COLLATE Slovenian_BIN2, #list + #Delim)
UNION ALL
SELECT Start = [Stop] + 1, [Stop] = charindex(#Delim
COLLATE Slovenian_BIN2, #list + #Delim, [Stop] + 1)
FROM csvtbl
WHERE ([Stop] > 0)
)
SELECT substring(#list, Start, CASE WHEN [Stop] > 0 THEN [Stop] -
Start ELSE 0 END) AS Value
FROM csvtbl
WHERE ([Stop] > 0)
)
You need to be aware of the default recursion depth of 100. If this isn't enough, increase it by adding the following to your outer calling query:
OPTION (MAXRECURSION 1000) -- or 0 for unlimited
EXAMPLE
SELECT *
FROM MyTable as t
WHERE t.ID IN (
SELECT *
FROM dbo.SplitToTable('1,2,12,34,101', ',')
)
It can be used on joins, etc., too.
I think you need something like...
Declare #query as varchar(500)
Declare #valuesList as varchar(100)
set #valuesList = '1,2,3'
set #query = 'select * From tableName where id in ( ' + #valuesList + ')'
exec(#query)
TO REVERSE THE PROCESS
DECLARE #t TABLE
(
ID int
)
INSERT INTO #t
VALUES (1), (3), (5), (7), (9)
SELECT STUFF(
(
SELECT ',' + CAST(t.ID AS VARCHAR(10))
FROM #t t
FOR XML PATH('')
), 1, 1, '') AS CSV
Courtesy SQLAuthority.