SQL Server 2008 select with regular expression - sql

I have an SQL Server 2008 database with a table called "page_data" that contains a NVARCHAR column called "path"
The path column will contain data like the follwoing:
/aaa/bbb
/aaa/bbb/zzz
/aaa/ccc
/aaa/ccc/xxx
/aaa/ddd
/aaa/ddd/yyy
I want to select rows where the path data only contains two slashes. So I should get the following data returned:
/aaa/bbb
/aaa/ccc
/aaa/ddd
I can't think of how to do this. Can anyone help?

Please try:
;with T as (
select 0 as row, CHARINDEX('/', Col) pos, Col from page_data
union all
select row + 1, CHARINDEX('/', Col, pos + 1), Col
from T
where pos > 0
)
select distinct MIN(Col1) Col
from(
select
row,
Col,
(case when row=2 then SUBSTRING(Col, 1, pos-1) else Col end) Col1
from T
where pos > 0 and row<3
)x
group by Col
SQL Fiddle demo

Related

Segregate column values in SQL Server

I have a table with 2 columns (Col1 & Col2) and values are stores like below:
Col1 Col2
A/B/C Red/Orange/Green
D/E Red/Orange
I want the output like below.
Col1 Col2
A Red
B Orange
C Green
D Red
E Orange
Did you try CROSS APPLY? Please replace 'your_table_name' with the name of your table. It should work, just copy and paste.
SELECT Col1, value AS Col2 INTO Table_2
FROM your_table_name
CROSS APPLY STRING_SPLIT(Col2, '/');
SELECT Col2, value AS Col1 INTO Table_3
FROM Table_2
CROSS APPLY STRING_SPLIT(Col1, '/');
SELECT * FROM Table_3;
Not easy, but doable.
I would do it by "flattening" the table:
SELECT (left bit of column 1), (left bit of column2)
UNION ALL
SELECT (middle bit of column 1), (middle bit of column 2)
where [column 1] like '%/%'
UNION ALL
SELECT (last bit of column 1), (last bit of column 2)
where [column 1] like '%/%/%'
If you have the possibility of more slashes and data, you need to add further UNIONs.
Use CHARINDEX to find the slash and SUBSTRING to extract the bits.
Maybe String split can help?
https://learn.microsoft.com/it-it/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15
look at the example D and E
Unfortunately, the built-in string split function in SQL Server does NOT return the position in the string. In my opinion, this is a significant oversight.
Assuming your strings have no duplicate values, you can use row_number() and charindex() to add an enumeration:
select t.*, ss.*
from t cross apply
(select s1.value as value1, s2.value as value2
from (select s1.value,
row_number() over (order by charindex('/' + s1.value + '/', '/' + t.col1 + '/')) as pos
from string_split(t.col1, '/') s1
) s1 join
(select s2.value,
row_number() over (order by charindex('/' + s2.value + '/', '/' + t.col2 + '/')) as pos
from string_split(t.col2, '/') s2
) s2
on s1.pos = s2.pos
) ss;
Here is a db<>fiddle.

How to combine return results of query in one row

I have a table that save personnel code.
When I select from this table I get 3 rows result such as:
2129,3394,3508,3534
2129,3508
4056
I want when create select result combine in one row such as:
2129,3394,3508,3534,2129,3508,4056
or distinct value such as:
2129,3394,3508,3534,4056
You should ideally avoid storing CSV data at all in your tables. That being said, for your first result set we can try using STRING_AGG:
SELECT STRING_AGG(col, ',') AS output
FROM yourTable;
Your second requirement is more tricky, and we can try going through a table to remove duplicates:
WITH cte AS (
SELECT DISTINCT VALUE AS col
FROM yourTable t
CROSS APPLY STRING_SPLIT(t.col, ',')
)
SELECT STRING_AGG(col, ',') WITHIN GROUP (ORDER BY CAST(col AS INT)) AS output
FROM cte;
Demo
I solved this by using STUFF and FOR XML PATH:
SELECT
STUFF((SELECT ',' + US.remain_uncompleted
FROM Table_request US
WHERE exclusive = 0 AND reqact = 1 AND reqend = 0
FOR XML PATH('')), 1, 1, '')
Thank you Tim

Possible to Search Partial Matched Strings from same table?

I have a table and lets say the table has items with the item numbers:
12345
12345_DDM
345653
2345664
45567
45567_DDM
I am having trouble creating a query that will get all of the _DDM and the corresponding item that has the same prefix digits.
So in this case I'd want both 12345 and 12345_DDM etc to be returned
Use like to find rows with _DDM.
Use EXISTS to find rows with numbers also having a _DDM row.
working demo
select *
from tablename t1
where columnname LIKE '%_DDM'
or exists (select 1 from tablename t2
where t1.columnname + '_DDM' = t2.columnname)
Try this query:
--sample data
;with tbl as (
select col from (values ('12345'),('12345_DDM'),('345653'),('2345664'), ('45567'),('45567_DDM')) A(col)
)
--select query
select col from (
select col,
prefix,
max(case when charindex('_DDM', col) > 0 then 1 else 0 end) over (partition by prefix) [prefixGroupWith_DDM]
from (
select col,
case when charindex('_DDM', col) - 1 > 0 then substring(col, 1, charindex('_DDM', col) - 1) else col end [prefix]
from tbl
) a
) a where [prefixGroupWith_DDM] = 1

Index like sql order

I have a column with a string value, something like 1, 1.1, 1.1.2, 1.2, 2, 2.1, 1.3, 1.1.3, one for record, of course, and i want a sentence that returns the records ordered by this field, like a book index
1
1.1
1.1.2
1.1.3
1.2
1.3
2
2.1
Thanks
Use ORDER BY:
CREATE TABLE #tab(col VARCHAR(1000));
INSERT INTO #tab(col)
SELECT '1'
UNION ALL SELECT '1.1'
UNION ALL SELECT '1.1.2'
UNION ALL SELECT '1.1.3'
UNION ALL SELECT '1.2'
UNION ALL SELECT '1.3'
UNION ALL SELECT '2'
UNION ALL SELECT '2.1';
SELECT *
FROM #tab
ORDER BY col;
LiveDemo
EDIT:
Just for fun and experiment solution for SQL Server 2012+:
WITH cte AS (
SELECT col,
CASE LEN(col) - LEN(REPLACE(col, '.', ''))
WHEN 0 THEN col + '.0.0.0'
WHEN 1 THEN col + '.0.0'
WHEN 2 THEN col + '.0'
ELSE col
END AS col_alt
FROM #tab
)
SELECT col
FROM cte
ORDER BY
LEN(PARSENAME(col_alt,4)),
PARSENAME(col_alt,4),
LEN(PARSENAME(col_alt,3)),
PARSENAME(col_alt,3),
LEN(PARSENAME(col_alt,2)),
PARSENAME(col_alt,2),
LEN(PARSENAME(col_alt,1)),
PARSENAME(col_alt,1);
LiveDemo2
If the values between the dots are all single characters (as in the question), then the easiest way is to order by the length of the string and then the string:
order by len(col), col
(In some databases, len might be spelled length.)
Note: this only works when single digits separate the dots. A more general solution requires some knowledge of the database.

remove duplicate values from a oracle sql query's output

I have a situation where I want to remove the duplicated record from the result by using sql query in oracle 10g. I am using regular expression to remove the alphabets from the result
Original value = 1A,1B,2C,2F,4A,4z,11A,11B
Current Sql query
select REGEXP_REPLACE( tablex.column, '[A-Za-z]' , '' )
from db1
gives me the following output
1,1,2,3,4,4,11,11
how can i remove duplicate from the output to just show unique values
i.e.
1,2,3,4,11
Assuming that your table contains strings with values separated with commas.
You can try something like this:
Here is a sqlfiddle demo
select rtrim(xmltype('<r><n>' ||
replace(REGEXP_REPLACE( col, '[A-Za-z]' , '' ), ',', ',</n><n>')||',</n></r>'
).extract('//n[not(preceding::n = .)]/text()').getstringval(), ',')
from tablex;
What it does is after using your regexp_replace it makes a xmltype from it and then uses XPATH to get the desired output.
If you also want to sort the values (and still use the xml approach) then you need XSL
select rtrim(xmltype('<r><n>' ||
replace(REGEXP_REPLACE( col, '[A-Za-z]' , '' ), ',', '</n><n>')||'</n></r>'
).extract('//n[not(preceding::n = .)]')
.transform(xmltype('<?xml version="1.0" ?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><xsl:for-each select="//n[not(preceding::n = .)]"><xsl:sort select="." data-type="number"/><xsl:value-of select="."/>,</xsl:for-each></xsl:template></xsl:stylesheet>'))
.getstringval(), ',')
from tablex;
But you can also try different approaches, such as splitting the tokens to rows and then recollecting them
select rtrim(xmlagg(xmlelement(e, n || ',') order by to_number(n))
.extract('//text()'), ',')
from(
SELECT distinct rn, trim(regexp_substr(col, '[^,]+', 1, level)) n
FROM (select row_number() over (order by col) rn ,
REGEXP_REPLACE( col, '[A-Za-z]' , '' ) col
from tablex) t
CONNECT BY instr(col, ',', 1, level - 1) > 0
)
group by rn;