Split the String on condition based, but not splitting the word and result should appear in column wise - substring

I have a table which has 3 addresses (address1, address2, address3, address4) If LEN (address1) < 30 then move the rest of the string to address2 and do same check in address2 and address3 columns. For example,
IF address1='FLAT K 17TH FLOOR NO 100 NUDONG NORTH', address2='ROAD INDIA (MAANGHAI) PILOT FREE TRADE', address3='ZONE THE PRD', address4='ITALY'
from my testable I want my solution as Len(Address1,2,3,4) < 30 and words should be separated using space and not in between.
address1='FLAT K 17TH FLOOR NO 100', address2='NUDONG NORTH ROAD Italy', address3='(MAANGHAI) PILOT FREE TRADE', address4='ZONE THE PRD ITALY'
I tried SUBSTRING and CHARINDEX, but it is cutting my words in between.

After a long try, find this solution to separate the address with each column with length of 30 and not splitting the word. There may be many easy other solutions, If anyone have other solutions, please feel free to share
DECLARE #Address1 VARCHAR(MAX)
DECLARE #TempAddress2 VARCHAR(MAX)
DECLARE #TempAddress3 VARCHAR(MAX)
DECLARE #Address2 VARCHAR(MAX)
DECLARE #Address3 VARCHAR(MAX)
DECLARE #Address4 VARCHAR(MAX)
SET #Address1 ='FLAT K 17TH FLOOR NO 100 NUDONG NORTH'
SET #Address2 = 'ROAD INDIA (MAANGHAI) PILOT FREE TRADE'
SET #Address3 = 'ZONE THE PRD'
SET #Address4 = 'ITALY'
SET #TempAddress2 = SUBSTRING(#Address1,LEN(REVERSE(SUBSTRING(REVERSE(LEFT( #Address1, 30)),CHARINDEX(' ',REVERSE(LEFT( #Address1, 30))),30)))+2,LEN(#Address1)) +' '+ #Address2
SET #TempAddress3 = SUBSTRING(#TempAddress2 + ' ' + #Address3,LEN(REVERSE(SUBSTRING(REVERSE(LEFT( #TempAddress2 + ' ' + #Address3, 30)),CHARINDEX(' ',REVERSE(LEFT( #TempAddress2 + ' ' + #Address3, 30))),30)))+2,LEN(#TempAddress2 + ' ' + #Address3))
SELECT REVERSE(SUBSTRING(REVERSE(LEFT(#Address1, 30)),CHARINDEX(' ',REVERSE(LEFT(#Address1, 30))),30)) AS Address1
,SUBSTRING(#Address1,LEN(REVERSE(SUBSTRING(REVERSE(LEFT( #Address1, 30)),CHARINDEX(' ',REVERSE(LEFT( #Address1, 30))),30)))+2,LEN(#Address1)) as Left_Address1
,REVERSE(SUBSTRING(REVERSE(LEFT( #TempAddress2, 30)),CHARINDEX(' ',REVERSE(LEFT( #TempAddress2, 30))),30)) AS Address2
, SUBSTRING(#TempAddress2,LEN(REVERSE(SUBSTRING(REVERSE(LEFT( #TempAddress2, 30)),CHARINDEX(' ',REVERSE(LEFT( #TempAddress2, 30))),30)))+2,LEN(#TempAddress2)) as Address3
, SUBSTRING(#TempAddress3,LEN(REVERSE(SUBSTRING(REVERSE(LEFT( #TempAddress3, 30)),CHARINDEX(' ',REVERSE(LEFT( #TempAddress3, 30))),30)))+2,LEN(#TempAddress3)) as Address4

Related

Extract string with multiple criteria - sql

We have a column of varying string values like below. How to extract part of the string and return the desired result in Redshift?
Example
Remove last part that starts with an underscore and number (_1_MN, number can be 1-1000)
Remove leading part (Ed_)
Replace any remaining underscore with a space
String:
Ed_Westside Ind School District 94_Williams Elementary School_1_MN
Desired result:
Westside Ind School District 94 Williams Elementary School
MySQL
UPDATE products
SET col = SUBSTRING(col FROM 3)
WHERE col LIKE ('Ed_%')
UPDATE products
SET col = SUBSTRING(col FROM -5 )
WHERE col LIKE ('%_1_MN')
UPDATE products
SET col = REPLACE(col, '_', ' ')
While not very elegant, this worked.
REGEXP_REPLACE(LEFT(RIGHT(name, LEN(name) - 3), LEN(name) -8) , '_', ' ')

Extract data from sql string

I have the following data in a column. I want to extract the 'matching details' score just showing as 542. The problem is the matching score can also be more than 3 characters long. Can someone help?
MatchingDetails score="542" maxScore="-96" matchRule="abcdef"><rule name="Person_Forename" score="279" /><rule name="Person_Surname" score="263"
One way is to use a combination of charindex, patindex, and substring:
DECLARE #S varchar(100) = 'MatchingDetails score="542" maxScore="-96" matchRule="abcdef">'
SELECT SUBSTRING(#S,
patindex('% score="%', #S) + 8,
charindex('"', #S, patindex('% score="%', #S) + 9) - patindex('% score="%', #S) - 8)
Result:
542
If your data is an XML string, perhaps something like this
Example (corrected xml)
Declare #S varchar(max) = '
<MatchingDetails score="542" maxScore="-96" matchRule="abcdef" >
<rule name="Person_Forename" score="279"></rule>
<rule name="Person_Surname" score="263"></rule>
</MatchingDetails>
'
Select convert(xml,#S).value('MatchingDetails[1]/#score','int')
Returns
542

Nested SELECT statement in a CASE expression

Greetings,
Here is my problem.
I need to get data from multiple rows and return them as a single result in a larger query.
I already posted a similar question here.
Return multiple values in one column within a main query but I suspect my lack of SQL knowledge made the question too vague because the answers did not work.
I am using Microsoft SQL 2005.
Here is what I have.
Multiple tables with CaseID as the PK, CaseID is unique.
One table (tblKIN) with CaseID and ItemNum(AutoInc) as the combined PK.
Because each person in the database will likely have more than one relative.
If I run the following, in a SQL query window, it works.
DECLARE #KINList varchar(1000)
SELECT #KINList = coalesce(#KINList + ', ','') + KINRel from tblKIN
WHERE CaseID = 'xxx' and Address = 'yyy'
ORDER BY KINRel
SELECT #KINList
This will return the relation of all people who live at the same address. the results look like this...
Father, Niece, Sister, Son
Now, the problem for me is how do I add that to my main query?
Shortened to relevant information, the main query looks like this.
SELECT DISTINCT
c.CaseID,
c.Name,
c.Address,
Relatives=CASE WHEN exists(select k.CaseID from tblKIN k where c.CaseID = k.CaseID)
THEN DECLARE #KINList varchar(1000)
SELECT #KINList = coalesce(#KINList + ', ','') + KINRel from tblKIN
WHERE CaseID = 'xxx' and Address = 'yyy'
ORDER BY KINRel
SELECT #KINList
ELSE ''
END
FROM tblCase c
ORDER BY c.CaseID
The errors I receive are.
Server: Msg 156, Level 15, State 1, Line 13
Incorrect syntax near the keyword 'DECLARE'.
Server: Msg 156, Level 15, State 1, Line 18
Incorrect syntax near the keyword 'ELSE'.
I tried nesting inside parenthesis from the DECLARE to the end of the SELECT #KINList.
I tried adding a BEGIN and END to the THEN section of the CASE statement.
Neither worked.
The source table data looks something like this. (periods added for readability)
tblCase
CaseID Name Address
10-001 Jim......100 Main St.
10-002 Tom....150 Elm St.
10-003 Abe.....200 1st St.
tblKIN
CaseID ItemNum Name Relation Address
10-001 00001 Steve...Son........100 Main St.
10-002 00002 James..Father....150 Elm St.
10-002 00003 Betty....Niece......150 Elm St.
10-002 00004 Greta...Sister.....150 Elm St.
10-002 00005 Davey..Son........150 Elm St.
10-003 00006 Edgar...Brother...200 1st St.
If I run the query for CaseID = 10-002, it needs to return the following.
CaseID Name Address.......Relatives
10-002 Tom...150 Elm St. ..Father, Niece, Sister, Son
I am sure this is probably a simple fix, but I just don't know how to do it.
Thank you for your time, and I apologize for the length of the question, but I wanted to be clear.
Thanks !!!
When I did something similar I had to create a scalar function to do the coalesce that returns the varchar result. Then just call it in the select.
CREATE FUNCTION GetRelatives
(
#CaseID varchar(10)
)
RETURNS varchar(1000)
AS
BEGIN
DECLARE #KINList varchar(1000)
SELECT #KINList = coalesce(#KINList + ', ','') + KINRel from tblKIN
WHERE CaseID = #CaseID
ORDER BY KINRel
RETURN #KINList
END
Then your select
SELECT DISTINCT
c.CaseID,
c.Name,
c.Address,
database.dbo.GetRelatives(c.CaseID) AS Relatives
FROM tblCase c
ORDER BY c.CaseID
You can create a FUNCTION which takes in the caseID as the arguement and returns true or false.
Since you are calling the nested query multiple times, its definitely a performance hit. A better solution is to execute the query and store the results in a temporary table.
Then pass this temporary table and the caseID to the FUNCTION and check for containment.

DESCENDING/ASCENDING Parameter to a stored procedure

I have the following SP
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = #webRegionID)
ORDER BY
CASE UPPER(#sortBy)
when 'CASE_NO' then case_no
when 'AREA' then area
when 'FURNISHED' then furnished
when 'TYPE' then [type]
when 'SQUAREFEETS' then squarefeets
when 'BEDROOMS' then bedrooms
when 'LIVINGROOMS' then livingrooms
when 'BATHROOMS' then bathrooms
when 'LEASE_FROM' then lease_from
when 'RENT' then rent
else case_no
END
END
GO
Now everything in that SP works but I want to be able to choose whether I want to sort ASCENDING or DESCENDING.
I really can't fint no solution for that using SQL and can't find anything in google.
As you can see I have the parameter sortDirection and I have tried using it in multiple ways but always with errors... Tried Case Statements, IF statements and so on but it is complicated by the fact that I want to insert a keyword.
Help will be very much appriciated, I have tried must of the things that comes into mind but haven't been able to get it right.
You could use two order by fields:
CASE #sortDir WHEN 'ASC' THEN
CASE UPPER(#sortBy)
...
END
END ASC,
CASE #sortDir WHEN 'DESC' THEN
CASE UPPER(#sortBy)
...
END
END DESC
A CASE will evaluate as NULL if none of the WHEN clauses match, so that causes one of the two fields to evaluate to NULL for every row (not affecting the sort order) and the other has the appropriate direction.
One drawback, though, is that you'd need to duplicate your #sortBy CASE statement. You could achieve the same thing using dynamic SQL with sp_executesql and writing a 'ASC' or 'DESC' literal depending on the parameter.
That code is going to get very unmanageable very quickly as you'll need to double nest your CASE WHEN's... one set for the Column to order by, and nested set for whethers it's ASC or DESC
Might be better to consider using Dynamic SQL here...
DECLARE #sql nvarchar(max)
SET #sql = '
Select
tbl_houses.*
from tbl_houses
where
postal in (select zipcode from crm_zipcodes where web_region_id = ' + #webRegionID + ') ORDER BY '
SET #sql = #sql + ' ' + #sortBy + ' ' + #sortDirection
EXEC (#sql)
You could do it with some dynamic SQL and calling it with an EXEC. Beware SQL injection though if the user has any control over the parameters.
CREATE PROCEDURE GetAllHouses
set #webRegionID = 2
set #sortBy = 'case_no'
set #sortDirection = 'ASC'
AS
BEGIN
DECLARE #dynamicSQL NVARCHAR(MAX)
SET #dynamicSQL =
'
SELECT
tbl_houses.*
FROM
tbl_houses
WHERE
postal
IN
(
SELECT
zipcode
FROM
crm_zipcodes
WHERE
web_region_id = ' + CONVERT(nvarchar(10), #webRegionID) + '
)
ORDER BY
' + #sortBy + ' ' + #sortDirection
EXEC(#dynamicSQL)
END
GO

Extract the first word of a string in a SQL Server query

What's the best way to extract the first word of a string in sql server query?
SELECT CASE CHARINDEX(' ', #Foo, 1)
WHEN 0 THEN #Foo -- empty or single word
ELSE SUBSTRING(#Foo, 1, CHARINDEX(' ', #Foo, 1) - 1) -- multi-word
END
You could perhaps use this in a UDF:
CREATE FUNCTION [dbo].[FirstWord] (#value varchar(max))
RETURNS varchar(max)
AS
BEGIN
RETURN CASE CHARINDEX(' ', #value, 1)
WHEN 0 THEN #value
ELSE SUBSTRING(#value, 1, CHARINDEX(' ', #value, 1) - 1) END
END
GO -- test:
SELECT dbo.FirstWord(NULL)
SELECT dbo.FirstWord('')
SELECT dbo.FirstWord('abc')
SELECT dbo.FirstWord('abc def')
SELECT dbo.FirstWord('abc def ghi')
I wanted to do something like this without making a separate function, and came up with this simple one-line approach:
DECLARE #test NVARCHAR(255)
SET #test = 'First Second'
SELECT SUBSTRING(#test,1,(CHARINDEX(' ',#test + ' ')-1))
This would return the result "First"
It's short, just not as robust, as it assumes your string doesn't start with a space. It will handle one-word inputs, multi-word inputs, and empty string inputs.
Enhancement of Ben Brandt's answer to compensate even if the string starts with space by applying LTRIM(). Tried to edit his answer but rejected, so I am now posting it here separately.
DECLARE #test NVARCHAR(255)
SET #test = 'First Second'
SELECT SUBSTRING(LTRIM(#test),1,(CHARINDEX(' ',LTRIM(#test) + ' ')-1))
Adding the following before the RETURN statement would solve for the cases where a leading space was included in the field:
SET #Value = LTRIM(RTRIM(#Value))
Marc's answer got me most of the way to what I needed, but I had to go with patIndex rather than charIndex because sometimes characters other than spaces mark the ends of my data's words. Here I'm using '%[ /-]%' to look for space, slash, or dash.
Select race_id, race_description
, Case patIndex ('%[ /-]%', LTrim (race_description))
When 0 Then LTrim (race_description)
Else substring (LTrim (race_description), 1, patIndex ('%[ /-]%', LTrim (race_description)) - 1)
End race_abbreviation
from tbl_races
Results...
race_id race_description race_abbreviation
------- ------------------------- -----------------
1 White White
2 Black or African American Black
3 Hispanic/Latino Hispanic
Caveat: this is for a small data set (US federal race reporting categories); I don't know what would happen to performance when scaled up to huge numbers.
DECLARE #string NVARCHAR(50)
SET #string = 'CUT STRING'
SELECT LEFT(#string,(PATINDEX('% %',#string)))
Extract the first word from the indicated field:
SELECT SUBSTRING(field1, 1, CHARINDEX(' ', field1)) FROM table1;
Extract the second and successive words from the indicated field:
SELECT SUBSTRING(field1, CHARINDEX(' ', field1)+1, LEN (field1)-CHARINDEX(' ', field1)) FROM table1;
A slight tweak to the function returns the next word from a start point in the entry
CREATE FUNCTION [dbo].[GetWord]
(
#value varchar(max)
, #startLocation int
)
RETURNS varchar(max)
AS
BEGIN
SET #value = LTRIM(RTRIM(#Value))
SELECT #startLocation =
CASE
WHEN #startLocation > Len(#value) THEN LEN(#value)
ELSE #startLocation
END
SELECT #value =
CASE
WHEN #startLocation > 1
THEN LTRIM(RTRIM(RIGHT(#value, LEN(#value) - #startLocation)))
ELSE #value
END
RETURN CASE CHARINDEX(' ', #value, 1)
WHEN 0 THEN #value
ELSE SUBSTRING(#value, 1, CHARINDEX(' ', #value, 1) - 1)
END
END
GO
SELECT dbo.GetWord(NULL, 1)
SELECT dbo.GetWord('', 1)
SELECT dbo.GetWord('abc', 1)
SELECT dbo.GetWord('abc def', 4)
SELECT dbo.GetWord('abc def ghi', 20)
Try This:
Select race_id, race_description
, Case patIndex ('%[ /-]%', LTrim (race_description))
When 0 Then LTrim (race_description)
Else substring (LTrim (race_description), 1, patIndex ('%[ /-]%', LTrim (race_description)) - 1)
End race_abbreviation
from tbl_races