sql query with substring charindex - sql

table1
::::::::::::::::::::::::::::::::::
id | id_data | id_t | value
1 | 43 | 1 |
2 | 46 | 1 | 111,112,113
3 | 43 | 2 |
4 | 46 | 2 | 90,5
table2
:::::::::::::::::::::::::::::::::::
id_value | cat
112 | cat1
5 | cat2
Hi, I need some help here if possible, please.
I need to update table1.value where id_data is 43 with table2.cat where id_value = the digits after value's ',' 'till the next ',' if there is any for each group in 'id_t'
I tried with a simple query but it's returning some null but 'value' can't be null
update table1
set value = (select cat from table2
where convert(nvarchar,id_value) = substring(value,5,3))
where id_data='43'
I've been trying to incorporate CHARINDEX to take from the ',' but i just can't figure it out how it works.
Ideally it should look like this:
::::::::::::::::::::::::::::::::::
id | id_data | id_t | value
1 | 43 | 1 | cat1
2 | 46 | 1 | 111,112,113
3 | 43 | 2 | cat2
4 | 46 | 2 | 90,5
Can anyone point me on the right direction, please?
I guess it's simple.. but I'm still learning...
thanks in advance.
::::::::::::::::
UPDATE1
WITH UpdateableCTE AS
(
SELECT t1.id
,t1.id_data
,t1.id_t
,SecondNr
,(
SELECT t2.cat
FROM #table2 AS t2 WHERE t2.id_value=SecondNr
) AS NewCat
,t1.value
FROM #table1 AS t1
OUTER APPLY(SELECT CAST('<x>' + REPLACE(x.value,',','</x><x>') + '</x>' AS XML).value('/x[2]','int')
FROM #table1 AS x
WHERE x.id_t=t1.id_t AND x.value IS NOT NULL AND id_data='46') AS ID(SecondNr)
WHERE t1.value IS NULL
)
UPDATE UpdateableCTE SET value=NewCat;
--somehow where id_data='43'
I'll leave here one table that looks a little more to the real one with all the id_data and fields:
17974492 1 999251 somevalue
17974493 2 999251 somevalue
17974494 3 999251 somevalue
17974495 4 999251 somevalue
17974496 5 999251 somevalue
17974497 43 999251 (thishsouldbeupdated)
17974498 6 999251 somevalue
17974499 7 999251 somevalue
17974500 46 999251 111,311
17974501 8 999251 somevalue
17974502 9 999251 somevalue
17974503 10 999251 somevalue
17974504 11 999251 somevalue
17974505 12 999251 somevalue
17974506 13 999251 somevalue
17974507 1 999252 somevalue
17974508 2 999252 somevalue
17974509 3 999252 somevalue
17974510 4 999252 somevalue
17974511 5 999252 somevalue
17974512 43 999252 (thisshouldbeupdated)
17974513 6 999252 somevalue
17974514 7 999252 somevalue
17974515 46 999252 98,98
17974516 8 999252 somevalue
17974517 9 999252 somevalue
17974518 10 999252 somevalue
17974519 11 999252 somevalue
17974520 12 999252 somevalue
17974521 13 999252 somevalue

This is not clean, nor is it something I'd recommend, but you might find some help:
DECLARE #table1 TABLE(id INT,id_data INT,id_t INT,value VARCHAR(100));
INSERT INTO #table1 VALUES
(1,43,1,NULL)
,(2,46,1,'111,112,113')
,(3,43,2,NULL)
,(4,46,2,'90,5')
DECLARE #table2 TABLE(id_value INT,cat VARCHAR(100));
INSERT INTO #table2 VALUES
(112,'cat1')
,(5,'cat2');
SELECT t1.id
,t1.id_data
,t1.id_t
,ID.List
,(
SELECT t2.cat
FROM #table2 AS t2 WHERE CHARINDEX(',' + CAST(t2.id_value AS VARCHAR(100)) + ',',',' + ID.List + ',')>0
)
FROM #table1 AS t1
OUTER APPLY(SELECT x.value FROM #table1 AS x WHERE x.id_t=t1.id_t AND x.value IS NOT NULL) AS ID(List)
WHERE t1.value IS NULL
UPDATE: Your explanation about use the second number as update
Try this
DECLARE #table1 TABLE(id INT,id_data INT,id_t INT,value VARCHAR(100));
INSERT INTO #table1 VALUES
(1,43,1,NULL)
,(2,46,1,'111,112,113')
,(3,43,2,NULL)
,(4,46,2,'90,5')
DECLARE #table2 TABLE(id_value INT,cat VARCHAR(100));
INSERT INTO #table2 VALUES
(112,'cat1')
,(5,'cat2');
WITH UpdateableCTE AS
(
SELECT t1.id
,t1.id_data
,t1.id_t
,SecondNr
,(
SELECT t2.cat
FROM #table2 AS t2 WHERE t2.id_value=SecondNr
) AS NewCat
,t1.value
FROM #table1 AS t1
OUTER APPLY(SELECT CAST('<x>' + REPLACE(x.value,',','</x><x>') + '</x>' AS XML).value('/x[2]','int')
FROM #table1 AS x
WHERE x.id_t=t1.id_t AND x.value IS NOT NULL) AS ID(SecondNr)
WHERE t1.value IS NULL
)
UPDATE UpdateableCTE SET value=NewCat;
SELECT * FROM #table1
The concept is the updateable CTE, where you can use a normal SELECT to get the values you need. You then can update the derived table (as long as there are only columns of one single table affected) directly.
The OUTER APPLY uses a trick with XML to split the CSV list in order to read the second number.
UPDATE 2: Use your new sample data
The following will use the new sample data and work with the IDs:
DECLARE #table1 TABLE(id INT,id_data INT,id_t INT,value VARCHAR(100));
INSERT INTO #table1 VALUES
(17974492,1,999251,'somevalue')
,(17974493,2,999251,'somevalue')
,(17974494,3,999251,'somevalue')
,(17974495,4,999251,'somevalue')
,(17974496,5,999251,'somevalue')
,(17974497,43,999251,'(thishsouldbeupdated)')
,(17974498,6,999251,'somevalue')
,(17974499,7,999251,'somevalue')
,(17974500,46,999251,'111,311')
,(17974501,8,999251,'somevalue')
,(17974502,9,999251,'somevalue')
,(17974503,10,999251,'somevalue')
,(17974504,11,999251,'somevalue')
,(17974505,12,999251,'somevalue')
,(17974506,13,999251,'somevalue')
,(17974507,1,999252,'somevalue')
,(17974508,2,999252,'somevalue')
,(17974509,3,999252,'somevalue')
,(17974510,4,999252,'somevalue')
,(17974511,5,999252,'somevalue')
,(17974512,43,999252,'(thisshouldbeupdated)')
,(17974513,6,999252,'somevalue')
,(17974514,7,999252,'somevalue')
,(17974515,46,999252,'98,98')
,(17974516,8,999252,'somevalue')
,(17974517,9,999252,'somevalue')
,(17974518,10,999252,'somevalue')
,(17974519,11,999252,'somevalue')
,(17974520,12,999252,'somevalue')
,(17974521,13,999252,'somevalue');
DECLARE #table2 TABLE(id_value INT,cat VARCHAR(100));
INSERT INTO #table2 VALUES
(311,'cat1')
,(98,'cat2');
WITH UpdateableCTE AS
(
SELECT t1.id
,t1.id_data
,t1.id_t
,SecondNr
,(
SELECT t2.cat
FROM #table2 AS t2 WHERE t2.id_value=SecondNr
) AS NewCat
,t1.value
FROM #table1 AS t1
OUTER APPLY(SELECT CAST('<x>' + REPLACE(x.value,',','</x><x>') + '</x>' AS XML).value('/x[2]','int')
FROM #table1 AS x
WHERE x.id_t=t1.id_t AND x.id_data=46) AS ID(SecondNr)
WHERE t1.id_data=43
)
UPDATE UpdateableCTE SET value=NewCat;
SELECT * FROM #table1;

Related

Joining tables containing comma delimited values

I have three excel sheet I push them into tables in SQL server and I need to join these table. However, I believe - as I have tried already - normal join wouldn't work. I have programming background but not that much with SQL.
Table1
ID Data_column reference_number
1 some data 1528,ss-456
2 some data 9523
3 some data ss-952
4 some data null
Table2
ID Data_column
ss-456 some data
ss-952 some data
Table3
ID Data_column
1528 some data
9523 some data
In the case below How I will be able to join this raw on both table.
Table1
ID Data_column reference_number
1 some data 1528,ss-456
declare #t1 as table(
id int
,data_column varchar(20)
,reference_number varchar(20)
)
declare #t2 as table(
id varchar(20)
,data_column varchar(20)
)
declare #t3 as table(
id varchar(20)
,data_column varchar(20)
)
insert into #t1 values(1,'some data','1528,ss-456'),(2,'some data','9523'),(3,'some data','ss-952'),(4,'some data',null);
insert into #t2 values('ss-456','some data'),('ss-952','some data');
insert into #t3 values(1528,'some data'),(9523,'some data');
Quick solution
select * from #t1 t1
left outer join #t2 t2 on t1.reference_number like '%'+t2.id or t1.reference_number like t2.id+'%'
left outer join #t3 t3 on t1.reference_number like '%'+t3.id or t1.reference_number like t3.id+'%'
Result (left join):
id data_column reference_number id data_column id data_column
1 some data 1528,ss-456 ss-456 some data 1528 some data
2 some data 9523 NULL NULL 9523 some data
3 some data ss-952 ss-952 some data NULL NULL
4 some data NULL NULL NULL NULL NULL
You can change 'left outer join' to 'inner join' for exact match.
Clumsy design, clumsy solution:
SELECT *
FROM Table1
INNER JOIN Table2 ON ',' + Table1.reference_number + ',' LIKE '%,' + Table2.ID + ',%'
INNER JOIN Table3 ON ',' + Table1.reference_number + ',' LIKE '%,' + Table3.ID + ',%'
You must append leading and trailing commas to make sure that, for example, 1528,ss-456asdf does not match %ss-456%.
I see two problems here. First is the inconsistent type of ID in table 2 and 3 and aggregation of referenced keys in table 1. Here is an example how to solve both problems. To split REFERENCE_NUMBER column I used STRING_SPLIT function.
Update:
I added the solution which should work with SQL Server 2012.
I assumed that you wish to join data from table 1 with 2 or 3 depending in existence of this data. This is just my idea what you wanted to achive.
-- data preparing
declare #t1 as table(
id int
,data_column varchar(20)
,reference_number varchar(20)
)
declare #t2 as table(
id varchar(20)
,data_column varchar(20)
)
declare #t3 as table(
id int
,data_column varchar(20)
)
insert into #t1 values(1,'some data','1528,ss-456'),(2,'some data','9523'),(3,'some data','ss-952'),(4,'some data',null);
insert into #t2 values('ss-456','some data'),('ss-952','some data');
insert into #t3 values(1528,'some data'),(9523,'some data');
-- Solution example version >= 2016
with base as (
select t1.id,t1.data_column,f1.value from #t1 t1 outer apply string_split(t1.reference_number,',') f1)
select b.id,b.data_column,b.value,t2.data_column from base b join #t2 t2 on b.value = t2.id
union all
select b.id,b.data_column,b.value,t3.data_column from base b join #t3 t3 on try_cast(b.value as int ) = t3.id
union all
select b.id,b.data_column,b.value,null from base b where b.value is null;
-- Solution for SQL Version < 2016
with base as (
select t1.id,t1.data_column,f1.value from #t1 t1 outer apply(
SELECT Split.a.value('.', 'NVARCHAR(MAX)') value
FROM
(
SELECT CAST('<X>'+REPLACE(t1.reference_number, ',', '</X><X>')+'</X>' AS XML) AS String
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)
) f1)
select b.id,b.data_column,b.value,t2.data_column from base b join #t2 t2 on b.value = t2.id
union all
select b.id,b.data_column,b.value,t3.data_column from base b join #t3 t3 on try_cast(b.value as int ) = t3.id
union all
select b.id,b.data_column,b.value,null from base b where b.value is null;
You will require a function to divide the comma separated sting into rows. If you don't have access to thr inbuilt string_split() function (as of mssql 2017 with compatibility of 130) there are several to choose from here
CREATE TABLE table1(
ID INTEGER NOT NULL PRIMARY KEY
,Data_column VARCHAR(10) NOT NULL
,reference_number VARCHAR(11)
);
INSERT INTO table1(ID,Data_column,reference_number) VALUES
(1,'t1somedata','1528,ss-456')
, (2,'t1somedata','9523')
, (3,'t1somedata','ss-952')
, (4,'t1somedata',NULL);
CREATE TABLE table2(
ID VARCHAR(6) NOT NULL PRIMARY KEY
,Data_column VARCHAR(10) NOT NULL
);
INSERT INTO table2(ID,Data_column) VALUES
('ss-456','t2somedata'),
('ss-952','t2somedata');
CREATE TABLE table3(
ID VARCHAR(6) NOT NULL PRIMARY KEY
,Data_column VARCHAR(10) NOT NULL
);
INSERT INTO table3(ID,Data_column) VALUES
('1528','t3somedata'),
('9523','t3somedata');
I have used this splistring function, but you can use almost any of the many freely available.
CREATE FUNCTION dbo.SplitStrings_Moden
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
E2(N) AS (SELECT 1 FROM E1 a, E1 b),
E4(N) AS (SELECT 1 FROM E2 a, E2 b),
E42(N) AS (SELECT 1 FROM E4 a, E2 b),
cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(#List,1)))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
WHERE (SUBSTRING(#List,t.N,1) = #Delimiter OR t.N = 0))
SELECT Item = SUBSTRING(#List, s.N1, ISNULL(NULLIF(CHARINDEX(#Delimiter,#List,s.N1),0)-s.N1,8000))
FROM cteStart s;
This is what the data looks like using the splitstring function:
select *
from table1
cross apply SplitStrings_Moden(reference_number,',')
ID | Data_column | reference_number | Item
-: | :---------- | :--------------- | :-----
1 | t1somedata | 1528,ss-456 | 1528
1 | t1somedata | 1528,ss-456 | ss-456
2 | t1somedata | 9523 | 9523
3 | t1somedata | ss-952 | ss-952
4 | t1somedata | null | null
and now joining to the other tables:
select
*
from (
select *
from table1
cross apply SplitStrings_Moden(reference_number,',')
) t1
left join table2 on t1.item = table2.id
left join table3 on t1.item = table3.id
where t1.item is not null
GO
ID | Data_column | reference_number | Item | ID | Data_column | ID | Data_column
-: | :---------- | :--------------- | :----- | :----- | :---------- | :--- | :----------
1 | t1somedata | 1528,ss-456 | 1528 | null | null | 1528 | t3somedata
1 | t1somedata | 1528,ss-456 | ss-456 | ss-456 | t2somedata | null | null
2 | t1somedata | 9523 | 9523 | null | null | 9523 | t3somedata
3 | t1somedata | ss-952 | ss-952 | ss-952 | t2somedata | null | null
db<>fiddle here
TRY THIS: If your reference_number is fixed and always stored IDs upto 2 only then you can go with the below approach
SELECT *
FROM(
SELECT ID,
data_column,
CASE WHEN PATINDEX ( '%,%', reference_number) > 0 THEN
SUBSTRING(reference_number, PATINDEX ( '%,%', reference_number)+1, LEN(reference_number))
ELSE reference_number END AS ref_col
FROM #table1
UNION
SELECT ID,
data_column,
CASE WHEN PATINDEX ( '%,%', reference_number) > 0 THEN
SUBSTRING(reference_number, 0, PATINDEX ( '%,%', reference_number))
END
FROM #table1) t1
LEFT JOIN #table2 t2 ON t2.id = t1.ref_col
LEFT JOIN #table3 t3 ON t3.id = t1.ref_col
WHERE t1.ref_col IS NOT NULL
OUTPUT:
ID data_column ref_col ID Data_column ID Data_column
1 some data 1528 NULL NULL 1528 some data
1 some data ss-456 ss-456 some data NULL NULL
2 some data 9523 NULL NULL 9523 some data
3 some data ss-952 ss-952 some data NULL NULL
4 some data null NULL NULL NULL NULL
You can Implement and get desired result using Substring and charIndex functions on the reference_number.
I upvoted an answer of 'is_oz' since i used his ready made schema to test and build a query for you.
below is the final query i build after several tries i made here:
select * from abc
left join abc2 on abc2.id = case when charindex(',',abc.reference_number) > 0
then substring(abc.reference_number
,charindex(',',abc.reference_number)+1
,len(abc.reference_number)-(charindex(',',abc.reference_number)-1)
)
else abc.reference_number
end
left join abc3 on abc3.id = case when charindex(',',abc.reference_number) > 0
then substring(abc.reference_number
,0
,(charindex(',',abc.reference_number))
)
else abc.reference_number
end
As per your requirement as much as i understand, it is returning all the matched rows from 2 other tables but still i hope this fulfills all the requirements you seek in your question. :)

SQL server and STUFF with two tables

I'm facing a problem. I have two tables as below.
table 1
+----+------+
| ks | keys |
+----+------+
| 11 | 1122|
+----+------+
| 12 | 2211|
+----+------+
| 13 | 2233|
+----+------+
| 14 | 3322|
+----+------+
table 2
+----+--+-------+
| Id | ks|codes|
+----+-----------+
| 1 | 11 |aaaaa|
+----+-----------+
| 2 | 11 |bbbbb|
+----+-----------+
| 3 | 12 |aaaaa|
+----+-----------+
| 3 | 13 |ccccc|
+----+-----------+
| 4 | 12 |bbbbb|
+----+-----------+
I tried to implement a following query in order to get my required output but did not work:
SELECT ks,
STUFF (
(SELECT ', ' + t2.codes as [text()]
from table2 as t2 where t1.ks = t2.ks FOR XML PATH('')
),1,1,''
) as "codes"
from table1 t1
group by ks;
I get this table as result:
+----+------+
| ks | codes|
+----+------+
| 11 | aaaa |
+----+------+
| 11 | bbbb |
+----+------+
| 12 | cccc |
+----+------+
| 12 | dddd |
+----+------+
then this image below shows my required output:
required result
I did something wrong but I do not know what could be. Any chance someone help me? Thanks!
Try this. I think you posted the wrong output.
Create table #tbl (ks int , codes varchar(10))
Insert into #tbl values
(11 ,'aaaa'),
(12 ,'bbbb'),
(13 ,'cccc'),
(14 ,'dddd')
Create table #tbl2 (id int, ks int , codes varchar(10))
Insert into #tbl2 values
( 1 ,11 ,'aaaaa'),
( 2 ,11 ,'bbbbb'),
( 3 ,12 ,'aaaaa'),
( 3 ,13 ,'ccccc'),
( 4 ,12 ,'bbbbb')
with cte as
(Select t1.ks, t2.codes
from #tbl t1 join #tbl2 t2 on t1.ks = t2.ks)
Select ks, STUFF(
(SELECT ',' + codes FROM cte c1
where c1.ks = c2.ks FOR XML PATH ('')), 1, 1, ''
)
from cte c2
group by ks
Output:
ks
11 aaaaa,bbbbb
12 aaaaa,bbbbb
13 ccccc
I cannot say that I fully understand what is going on in your tables--especially given your output image appears to have no relation to your sample tables--but it looks like you want a comma-delimited list of sub-values from table2 that are associated with table1.
Here's a working example that I think addresses your need. You can use CROSS APPLY in these situations. Doing so allows you to return all values from table1 regardless of a matching record in table2.
DECLARE #table1 TABLE ( [ks] INT, [code] VARCHAR(10) );
DECLARE #table2 TABLE ( [id] INT, [ks] INT, [code] VARCHAR(10) );
-- populate table1 --
INSERT INTO #table1 (
[ks], [code]
)
VALUES
( 11, 'aaaa' )
, ( 12, 'bbbb' )
, ( 13, 'cccc' )
, ( 14, 'dddd' );
-- populate table two --
INSERT INTO #table2 (
[id], [ks], [code]
)
VALUES
( 1, 11, 'aaaaa' )
, ( 2, 11, 'bbbbb' )
, ( 3, 12, 'aaaaa' )
, ( 3, 13, 'ccccc' )
, ( 4, 12, 'bbbbb' );
SELECT
t1.ks, codes.codes
FROM #table1 t1
CROSS APPLY (
SELECT (
STUFF(
( SELECT ', ' + t2.code AS "text()" FROM #table2 t2 WHERE t2.ks = t1.ks FOR XML PATH ( '' ) )
, 1, 2, ''
)
) AS [codes]
) AS codes
ORDER BY
t1.ks;
Resulting Output:
ks codes
11 aaaaa, bbbbb
12 aaaaa, bbbbb
13 ccccc
14 NULL

SQL Server 2008 Select all columns of a table + a column from the same table based on a column value

I have a table VERSION with composite keys docId, verId:
docId verId apprvDt old_verId
------ ------ ----------- ----------
A 3 03/20/2017 2
A 2 03/18/2017 1
A 1 03/16/2017 null
B 1 03/18/2017 null
C 2 03/20/2017 1
C 1 03/16/2017 null
Say I select docId=A, verId=3, query should return
docId verId apprvDt old_verId old_apprvDt
------ ------ ----------- ---------- ------------
A 3 03/20/2017 2 03/18/2017
that is to retrieve the apprvDt of the old_verId.
I tried like this
select a.docId, a.verId, a.apprvDt, a.old_verId, b.old_apprvDt
from VERSION as a left join
(select x.docId, x.verId, x.apprvDt as old_apprvDt from REVISN as x
where x.docId = 'A' and x.verId = a.old_verId) as b
on b.docId = a.docId and b.verId = a.old_verId
but I am getting a multi-part binding error.
I want to select a row from VERSION including the apprvDt (old_apprvDt) of old_verId
Solution to your problem is as given below :
DECLARE #tbl TABLE(docId varchar(100), verId int, apprvDt datetime, old_verId int)
insert into #tbl values('A', 3 , '03/20/2017', 2)
insert into #tbl values('A', 2 , '03/18/2017', 1)
insert into #tbl values('A', 1 , '03/16/2017', NULL)
insert into #tbl values('B', 1 , '03/18/2017', NULL)
insert into #tbl values('C', 2 , '03/20/2017', 1)
insert into #tbl values('C', 1 , '03/16/2017', NULL)
select * from #tbl
;with data_table
as
(
select docId,verId,apprvDt,old_verId,
(select apprvDt from #tbl T2 where T2.docId=t1.docid and T2.verId=t1.old_verId)
old_apprvDt from #tbl t1
)
select * from data_table where docId='A' and verId=3
Result is as below :
-------------------------------------------------------------------------------------
docId verId apprvDt old_verId old_apprvDt
-------------------------------------------------------------------------------------
A 3 2017-03-20 00:00:00.000 2 2017-03-18 00:00:00.000
select t1.*,
b.apprvdt as old_apprvdt
from table1 t1
cross apply
(
select apprvdt from table1 t2 where t1.docid=t2.docid
and t2.old_verid =t1.verid ) b

SQL Server split string with delimiter

I have an input string
100|2|3,101|2|1,103|2|3.
I would like to parse and add this in table having 3 columns so it should go f.x
col1 col2 col3
100 2 3
similar other data separated by comma as record and | as column.
Thanks
nik
Or this way:
SELECT
LEFT(value, Charindex('|', value) - 1),
SUBSTRING(value, Charindex('|', value) + 1,Len(value) - Charindex('|', Reverse(value)) - Charindex('|', value)),
RIGHT(value, Charindex('|', Reverse(value)) - 1)
FROM
string_split('100|2|3,101|2|1,103|2|3',',')
Try this way
DECLARE #TAB TABLE(COLUMN1 INT, COLUMN2 INT, COLUMN3 INT)
DECLARE #STRING VARCHAR(MAX)='100|2|3,101|2|1,103|2|3,'
SELECT #STRING = 'SELECT ' + REPLACE( REPLACE (#STRING, ',','
UNION ALL
SELECT '),'|',',')
SELECT #STRING = SUBSTRING(#STRING,1,LEN(#STRING)-18)
INSERT INTO #TAB
EXEC(#STRING)
SELECT * FROM #TAB
And the result will be
+---------+---------+---------+
| COLUMN1 | COLUMN2 | COLUMN3 |
+---------+---------+---------+
| 100 | 2 | 3 |
| 101 | 2 | 1 |
| 103 | 2 | 3 |
+---------+---------+---------+
Declare #temp table(col1 int,col2 int ,col3 int)
Declare #pos int,#str nvarchar(max),#len int
Set #str='100|2|3'
Set #pos=1
Select #len=len(#str)
Insert into #temp
Select substring(#str,#pos,charindex('|',#str,#pos)-1),
substring(#str,charindex('|',#str,#pos)+1,charindex('|',#str,#pos)-3),
substring(#str,charindex('|',#str,charindex('|',#str,#pos)+1)+1,#len)
Select * from #temp
;WITH tb(s)AS(
SELECT '100|2|3' UNION
SELECT '101|2|1' UNION
SELECT '103|2|3'
)
SELECT PARSENAME(REPLACE(s,'|','.'),3)
,PARSENAME(REPLACE(s,'|','.'),2)
,PARSENAME(REPLACE(s,'|','.'),1)
FROM tb
(No column name) (No column name) (No column name)
100 2 3
101 2 1
103 2 3

divide one record into multiple ones

I need a query to change this:
col1 col2 col3
1 2 abc
3 4 cd
4 5 null
To this
col1 col2 col3
1 2 a
1 2 b
1 2 c
3 4 c
3 4 d
4 5 NULL
Thank you.
Try it like this
EDIT shorter syntax for the running numbers
EDIT2 JamieD77's comment to include the TOP into the creation of the numbers
CREATE FUNCTION dbo.SingleChars(#SomeText NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH nr10 AS
(
SELECT * FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tbl(A)
)
,RunningNumbers AS
(
SELECT TOP (ISNULL(LEN(#SomeText),0)) ROW_NUMBER() OVER(ORDER BY (SELECT(NULL))) AS Nmbr FROM nr10,nr10 AS a,nr10 AS b,nr10 AS c,nr10 AS d,nr10 AS e,nr10 AS f,nr10 AS g
)
SELECT SUBSTRING(#SomeText,Nmbr,1) AS TheCharacter
,ASCII(SUBSTRING(#SomeText,Nmbr,1)) AS ASCII_Code
FROM RunningNumbers;
A test
SELECT * FROM dbo.SingleChars('This is a test');
The result
T 84
h 104
i 105
s 115
32
i 105
s 115
32
a 97
32
t 116
e 101
s 115
t 116
Now your problem
DECLARE #tbl TABLE(col1 INT, col2 INT, col3 VARCHAR(100));
INSERT INTO #tbl VALUES(1,2,'abc'),(3,4,'cd'),(4,5,NULL);
SELECT col1,col2,sc.TheCharacter
FROM #tbl
OUTER APPLY dbo.SingleChars(col3) AS sc;
The result
1 2 a
1 2 b
1 2 c
3 4 c
3 4 d
4 5 NULL
In MSSQL you can use recursive CTE. Just take one left letter on each step:
WITH T1 as
(
SELECT col1,col2,LEFT(col3,1) as col4, SUBSTRING(col3,2,10000) as col3
FROM Table1
UNION ALL
SELECT col1,col2,LEFT(col3,1) as col4, SUBSTRING(col3,2,10000) as col3
FROM T1 WHERE Col3 <> ''
)
SELECT col1,col2,col4 FROM T1 ORDER BY col1,col2;
one more query:
WITH T1 as
(
SELECT col1,col2,LEFT(col3,1) as col4, col3, 2 as nextPoint
FROM Table1
UNION ALL
SELECT col1,col2,SUBSTRING(col3,nextPoint,1) as col4, col3,
nextPoint+1 as nextPoint
FROM T1 WHERE LEN(col3)>=nextPoint
)
SELECT col1,col2,col4 FROM T1 ORDER BY col1,col2;