substring in sqlserver with casual format - sql-server

I have these rows
14-L-100-10008-G03S-N
1-DR-100-20057-G48-N
2-CL-100-12133-B12-P
2-FG-100-12202-B01-N
2-G-100-15520-B48-N
2-GM-100-10024-B01-N
2-HC-100-10022-G03S-N
2-HC-100-10023-G03S-N
2-HC-100-20023-G03S-N
32-G-100-15518-F03P2-N
32-G-100-15518-F03P2-N
I just need these parts .how can i get these parts using sql server code :
result:G03S,G48,B12,B01,B48,B12 and ...

You can as the below:
;WITH CTE
AS
(
select '14-L-100-10008-G03S-N' Val UNION ALL
select '1-DR-100-20057-G48-N' Val UNION ALL
select '2-CL-100-12133-B12-P' Val UNION ALL
select '2-FG-100-12202-B01-N' Val UNION ALL
select '2-G-100-15520-B48-N' Val UNION ALL
select '2-GM-100-10024-B01-N' Val UNION ALL
select '2-HC-100-10022-G03S-N' Val UNION ALL
select '2-HC-100-10023-G03S-N' Val UNION ALL
select '2-HC-100-20023-G03S-N' Val UNION ALL
select '32-G-100-15518-F03P2-N' Val UNION ALL
select '32-G-100-15518-F03P2-N'
)
SELECT REVERSE(SUBSTRING(REVERSE(Val), CHARINDEX('-', REVERSE(Val), 0) + 1, CHARINDEX('-', REVERSE(Val), CHARINDEX('-', REVERSE(Val), 0) + 1) - CHARINDEX('-', REVERSE(Val)) - 1))
FROM
CTE
Edit:
SELECT
(
SELECT REVERSE(SUBSTRING(REVERSE(Val), CHARINDEX('-', REVERSE(Val), 0) + 1, CHARINDEX('-', REVERSE(Val), CHARINDEX('-', REVERSE(Val), 0) + 1) - CHARINDEX('-', REVERSE(Val)) - 1)) + ' ,'
FROM
CTE
FOR XML PATH ('')
) Result
Result: G03S ,G48 ,B12 ,B01 ,B48 ,B01 ,G03S ,G03S ,G03S ,F03P2 ,F03P2 ,
SELECT LEFT(A.Result, LEN(A.Result) -1) FROM
(SELECT (SELECT REVERSE(SUBSTRING(REVERSE(Val), CHARINDEX('-', REVERSE(Val), 0) + 1, CHARINDEX('-', REVERSE(Val), CHARINDEX('-', REVERSE(Val), 0) + 1) - CHARINDEX('-', REVERSE(Val)) - 1)) + ' ,' FROM CTE FOR XML PATH ('') ) Result) A
Result: G03S ,G48 ,B12 ,B01 ,B48 ,B01 ,G03S ,G03S ,G03S ,F03P2 ,F03P2

Using one of the splitstring functions from here..
create table #t
(
id varchar(max)
)
insert into #t
select '14-L-100-10008-G03S-N'
union all
select '1-DR-100-20057-G48-N'
select item
from #t t1
cross apply
(select * ,row_number() over (partition by t1.id order by t1.id) as rn from [dbo].[SplitStrings_Numbers](t1.id,'-')
) b
where rn=5

Related

Convert PostgreSQL query to SQL Server query

I need to convert my query
select
unnest(string_to_array(names, ',')) as "Admin Name",
unnest(string_to_array(phones, ',')) as "Admin Phone",
unnest(string_to_array(emails, ',')) as "Admin Emails"
from
metadata_Table
to an equivalent SQL Server query.
Any suggestions?
You cannot exactly this easily in SL Server. There is no "string_split() with ordinality". And, the ordering is not guaranteed with string_split().
Until Microsoft enhances this functions, my suggestion is a recursive subquery:
with cte as (
select convert(varchar(max), null) as name, convert(varchar(max), null) as phone, convert(varchar(max), null) as email,
convert(varchar(max), names + ',') as names_rest,
convert(varchar(max), phones + ',') as phones_rest,
convert(varchar(max), emails + ',') as emails_rest,
0 as lev
from metadata_Table
union all
select left(names_rest, charindex(',', names_rest) - 1),
left(phones_rest, charindex(',', phones_rest) - 1),
left(emails_rest, charindex(',', emails_rest) - 1),
stuff(names_rest, 1, charindex(',', names_rest), ''),
stuff(phones_rest, 1, charindex(',', phones_rest), ''),
stuff(emails_rest, 1, charindex(',', emails_rest), ''),
lev + 1
from cte
where emails_rest like '%,%'
)
select *
from cte
where lev > 0;

How to shred a XML being passed into a stored procedure?

I have an XML being passed into a stored procedure in the following format. I'm struggling with how to shred it in SQL Server 2017:
declare #xml xml = convert(xml, N'<SearchQuery>
<DealTypeDesc>Deal</DealTypeDesc>
<VendorNum>1</VendorNum>
<VendorName>Vendor1</VendorName>
<VendorNum>2</VendorNum>
<VendorName>Vendor2</VendorName>
<VendorNum>3</VendorNum>
<VendorName>Vendor3</VendorName>
<VendorNum>4</VendorNum>
<VendorName>Vendor4</VendorName>
<VendorNum>5</VendorNum>
<VendorName>Vendor5</VendorName>
</SearchQuery>')
-- this is how it is being consumed now. 1 element at a time
SELECT
t.c.value('text()[1]', 'NVARCHAR(MAX)') AS LookupValue
FROM
#xml.nodes('//SearchQuery/VendorNum') AS t(c)
-- I want the results to look like this where I can use the node name as a column and the value as a lookup.
-- I wanted to do this in one pass without having to union all and select from the XML variable every time.
-- I can't change the XML structure since it's coming from a third party, so that option is out.
SELECT
'VendorName' ColumnName,
t.c.value('text()[1]', 'NVARCHAR(MAX)') AS LookupValue
FROM
#xml.nodes('//SearchQuery/VendorName') AS t(c)
UNION ALL
SELECT
'VendorNum' ColumnName,
t.c.value('text()[1]', 'NVARCHAR(MAX)') AS LookupValue
FROM
#xml.nodes('//SearchQuery/VendorNum') AS t(c)
Two options here. The first is a simple query. The second is a helper function which will shred virtually any XML without having to know anything about it. I'll often use this during the Discovery Phase.
First Option
Select ColumnName = a.value('local-name(.)','varchar(100)')
,LookupValue = a.value('.','varchar(max)')
From #XML.nodes('SearchQuery') as C1(n)
Cross Apply C1.n.nodes('*') as C2(a)
Where a.value('local-name(.)','varchar(100)') like 'Vendor%'
Returns
ColumnName LookupValue
VendorNum 1
VendorName Vendor1
VendorNum 2
VendorName Vendor2
VendorNum 3
VendorName Vendor3
VendorNum 4
VendorName Vendor4
VendorNum 5
VendorName Vendor5
The Second Option
Select * from [dbo].[tvf-XML-Hier](#xml) Order by R1
Returns
Perhaps more than you want, but it is easy to trim down
The TVF if Interested
CREATE FUNCTION [dbo].[tvf-XML-Hier](#XML xml)
Returns Table
As Return
with cte0 as (
Select Lvl = 1
,ID = Cast(1 as int)
,Pt = Cast(NULL as int)
,Element = x.value('local-name(.)','varchar(150)')
,Attribute = cast('' as varchar(150))
,Value = x.value('text()[1]','varchar(max)')
,XPath = cast(concat(x.value('local-name(.)','varchar(max)'),'[' ,cast(Row_Number() Over(Order By (Select 1)) as int),']') as varchar(max))
,Seq = cast(1000000+Row_Number() over(Order By (Select 1)) as varchar(max))
,AttData = x.query('.')
,XMLData = x.query('*')
From #XML.nodes('/*') a(x)
Union All
Select Lvl = p.Lvl + 1
,ID = Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10
,Pt = p.ID
,Element = c.value('local-name(.)','varchar(150)')
,Attribute = cast('' as varchar(150))
,Value = cast( c.value('text()[1]','varchar(max)') as varchar(max) )
,XPath = cast(concat(p.XPath,'/',c.value('local-name(.)','varchar(max)'),'[',cast(Row_Number() Over(PARTITION BY c.value('local-name(.)','varchar(max)') Order By (Select 1)) as int),']') as varchar(max) )
,Seq = cast(concat(p.Seq,' ',10000000+Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10) as varchar(max))
,AttData = c.query('.')
,XMLData = c.query('*')
From cte0 p
Cross Apply p.XMLData.nodes('*') b(c)
)
, cte1 as (
Select R1 = Row_Number() over (Order By Seq),A.*
From (
Select Lvl,ID,Pt,Element,Attribute,Value,XPath,Seq From cte0
Union All
Select Lvl = p.Lvl+1
,ID = p.ID + Row_Number() over (Order By (Select NULL))
,Pt = p.ID
,Element = p.Element
,Attribute = x.value('local-name(.)','varchar(150)')
,Value = x.value('.','varchar(max)')
,XPath = p.XPath + '/#' + x.value('local-name(.)','varchar(max)')
,Seq = cast(concat(p.Seq,' ',10000000+p.ID + Row_Number() over (Order By (Select NULL)) ) as varchar(max))
From cte0 p
Cross Apply AttData.nodes('/*/#*') a(x)
) A
)
Select A.R1
,R2 = IsNull((Select max(R1) From cte1 Where Seq Like A.Seq+'%'),A.R1)
,A.Lvl
,A.ID
,A.Pt
,A.Element
,A.Attribute
,A.XPath
,Title = Replicate('|---',Lvl-1)+Element+IIF(Attribute='','','#'+Attribute)
,A.Value
From cte1 A
/*
Source: http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx
Declare #XML xml='<person><firstname preferred="Annie" nickname="BeBe">Annabelle</firstname><lastname>Smith</lastname></person>'
Select * from [dbo].[tvf-XML-Hier](#XML) Order by R1
*/
You could query the two columns separately then join as follows:
select VendorNum, VendorName
from
(
SELECT
n = ROW_NUMBER() OVER (Order by t.vendor.value('text()[1]','NVARCHAR(MAX)')),
VendorNum= t.vendor.value('text()[1]','NVARCHAR(MAX)')
FROM #xml.nodes('SearchQuery/VendorNum') AS t(vendor)
) N
join
(
SELECT
n = ROW_NUMBER() OVER (Order by t.vendor.value('text()[1]','NVARCHAR(MAX)')),
VendorName = t.vendor.value('text()[1]','NVARCHAR(MAX)')
FROM #xml.nodes('SearchQuery/VendorName') AS t(vendor)
) V on V.n =N.n

SQL 2000 INCORECT SYNTAX NEAR WITH

I'm using this code:
WITH cte AS(SELECT panelname FROM inventorypanelcaptions UNION ALL SELECT CAST(0 AS VARCHAR(50)) FROM INVENTORYPANELCAPTIONS) SELECT CASE WHEN cast(min(right(panelname, 2) + 1) as varchar(50)) < 10 THEN 'o0' ELSE 'o' END + cast(min(right(panelname, 2) + 1) as varchar(50)) FROM cte WHERE NOT EXISTS ( SELECT panelname FROM inventorypanelcaptions WHERE right(inventorypanelcaptions.panelname, 2)= right(cte.panelname, 2)+1) ", con);
I'm getting incorrect syntax near 'With'
To make it work in SQL 2000, you can move it to a subquery
SELECT CASE WHEN cast(min(right(panelname, 2) + 1) as varchar(50)) < 10 THEN 'o0' ELSE 'o' END + cast(min(right(panelname, 2) + 1) as varchar(50))
FROM (
SELECT panelname FROM inventorypanelcaptions UNION ALL SELECT CAST(0 AS VARCHAR(50))
FROM INVENTORYPANELCAPTIONS
) cte
WHERE NOT EXISTS ( SELECT panelname
FROM inventorypanelcaptions
WHERE right(inventorypanelcaptions.panelname, 2)= right(cte.panelname, 2)+1
) ", con);

how to use order by clause using Stuff in sql

stuff(( select distinct ',',Convert(varchar(256),y.RoomPlanID)
from(
select x.RoomPlanID ,x.RoomPlanHierarchy from (select utblConfigDestRoomRates.RoomPlanID,utblMstRoomPlans.RoomPlanHierarchy
FROM utblConfigDestRoomRates inner
JOIN utblMstRoomPlans on utblConfigDestRoomRates.RoomPlanID=utblMstRoomPlans.RoomPlanId
WHERE PropertyTypeID=1
AND BusinessID='AAAA'
AND('25-Aug-2015' BETWEEN DateEffective AND DateEnd)
AND StarRank=3 group by RoomPlanHierarchy order by RoomPlanHierarchy asc
) x
--order by
-- x.RoomPlanHierarchy
)y
FOR XML PATH('')), 1, 1, '')
You can use ROW_NUMBER (Transact-SQL) function. I assume that order to x.RoomPlanHierarchy like this
stuff(( select distinct ',',Convert(varchar(256),y.RoomPlanID)
from(
select x.RoomPlanID ,x.RoomPlanHierarchy,ROW_NUMBER() OVER(ORDER BY x.RoomPlanHierarchy asc) AS Row from (select utblConfigDestRoomRates.RoomPlanID,utblMstRoomPlans.RoomPlanHierarchy
FROM utblConfigDestRoomRates inner
JOIN utblMstRoomPlans on utblConfigDestRoomRates.RoomPlanID=utblMstRoomPlans.RoomPlanId
WHERE PropertyTypeID=1
AND BusinessID='AAAA'
AND('25-Aug-2015' BETWEEN DateEffective AND DateEnd)
AND StarRank=3 group by RoomPlanHierarchy
) x
--order by
-- x.RoomPlanHierarchy
)y
FOR XML PATH('')), 1, 1, '')
--Format it in SQL
(
SELECT
stuff(
(
SELECT
'' + a.col_name ,
'' + Replace(CAST(a.pos as VARCHAR), a.pos, '') + '"'
FROM
(
SELECT
CAST (',' + db_column_name + ' AS "' + REPLACE(label_tag, '.', '_') AS nvarchar (4000) ) AS col_name,
row_number() over (partition BY RIGHT(entity, CHARINDEX('.', (REVERSE(entity)) ) - 1) ORDER BY db_column_name) AS pos
FROM
table1 AS ex
JOIN
table2 AS ef
ON
ef.col1 = ex.col1
WHERE
entity LIKE '%string%')a FOR xml path('')) , 1, 1, '' ) )

split a string by commas (,) SQL SERVER

I would like to split a string by commas (,) or pipe (|) to each character in SQL SERVER. Example 'APPLE'. Expected result: 'A|P|P|L|E'. Preferably without creating function.
You can do it with CTE:
DECLARE #s NVARCHAR(MAX) = 'APPLE'
DECLARE #result NVARCHAR(MAX)
;WITH cte(N, S) AS
(
SELECT 1 AS N, SUBSTRING(#s, 1, 1)
UNION ALL
SELECT N + 1, SUBSTRING(#s, N + 1, 1)
FROM cte
WHERE N < LEN(#s)
)
SELECT #result = COALESCE(#result + '|', '') + S FROM cte
SELECT #result
Output:
A|P|P|L|E
Or even shorter version:
DECLARE #s NVARCHAR(MAX) = 'APPLE'
;WITH cte(N, S, D) AS
(
SELECT 1 AS N, SUBSTRING(#s, 1, 1), D = SUBSTRING(#s, 1, 1)
UNION ALL
SELECT N + 1, SUBSTRING(#s, N + 1, 1), D = D + '|' + SUBSTRING(#s, N + 1, 1)
FROM cte
WHERE N < LEN(#s)
)
SELECT TOP 1 D FROM cte
ORDER BY N DESC
You could use a concept like the "Tally Table String Splitter" to achieve what you want.
http://www.sqlservercentral.com/articles/Tally+Table/72993/
DECLARE #txt varchar(50) ='APPLE'
;WITH cte(x) as
(
SELECT top (len(#txt)) ';'
+ substring(#txt, row_number() over (order by (select 1)), 1)
FROM master..spt_values x1
cross join
master..spt_values x2
FOR XML PATH('')
)
SELECT stuff(x, 1, 1, '')
FROM CTE
Result
A;P;P;L;E

Resources