I have below table structure :
Table1
╔═════╦══════╦═════════════╦═════════════╗
║Col1 ║ Col2 ║ TableName ║ ColumnName ║
╠═════╬══════╬═════════════╬═════════════╣
║ 1 ║ abc ║ Table2 ║ column2 ║
║ 2 ║ xyz ║ ║ ║
║ 3 ║ pqr ║ Table1 ║ column1 ║
║ 4 ║ jbn ║ ║ ║
╚═════╩════════════════════╩═════════════╝
Table2 :
╔════════╦═════════╗
║Column1 ║ Column2 ║
╠════════╬═════════╣
║ 1 ║ A ║
║ 2 ║ B ║
║ 3 ║ C ║
║ 4 ║ D ║
╚════════╩═════════╝
Table3
╔════════╦═════════╗
║Column1 ║ Column2 ║
╠════════╬═════════╣
║ 1 ║ X ║
║ 2 ║ Y ║
║ 3 ║ Z ║
║ 4 ║ A ║
╚════════╩═════════╝
I want to write stored procedure which will select data from Table1 and data from another table depending upon value of column tableName and columnName in Table1.
I want data in following format:
╔═════╦═════╦════════╗
║Col1 ║ Col2║ List ║
╠═════╬═════╬════════╣
║ 1 ║ abc ║A,B,C,D ║
║ 2 ║ xyz ║ ║
║ 3 ║ pqr ║1,2,3,4 ║
║ 4 ║ jbn ║ ║
╚═════╩═════╩════════╝
Try temporary table .
look at here : http://www.sqlteam.com/article/temporary-tables
You will need a dynamic sql to get such a select. Check out the link http://www.mssqltips.com/sqlservertip/1160/execute-dynamic-sql-commands-in-sql-server/
EDIT:
The following code should do the trick.
I have assumed that the column Col1 in Table1 is of type int.
I have used Temp table to generate the required table. You can replace it will your table as per your convenience. Also I have used #table1 which you can replace with your Table1.
Also this might not be very good in terms of performance but this is the best I could come up with right now.
declare #count int, #Query VARCHAR(5000), #counter int, #tableName VARCHAR(50), #ColumnName VARCHAR(50), #Col1 INT, #Col2 VARCHAR(50)
select #count = count(0) from #table1
SET #counter = 1
CREATE TABLE #table4
(
Col1 INT,
Col2 VARCHAR(50),
List VARCHAR(50)
)
WHILE #counter <= #count
BEGIN
SELECT #tableName = TableName, #ColumnName = columnName, #Col1 = Col1, #Col2 = Col2 FROM #Table1 WHERE Col1 = #counter
SELECT #Query = 'INSERT INTO #table4 (Col1 , Col2) VALUES (' + CONVERT(varchar(50),#Col1) + ', ''' + #Col2 + ''')'
EXEC (#Query)
SELECT #Query = ''
IF ISNULL(#tableName, '') != '' AND ISNULL(#ColumnName, '') != ''
BEGIN
SELECT #Query = 'UPDATE #table4 SET LIST = STUFF((SELECT '','' + CONVERT(VARCHAR(50), ' + #ColumnName + ') FROM ' + #tableName + ' FOR XML PATH('''')),1,1,'''') WHERE Col1 = ' + CONVERT(varchar(50),#Col1)
EXEC (#Query)
END
SET #counter = #counter + 1
END
SELECT * FROM #table4
Hope this helps
Answer edited for incorporating n no of rows
CODE
drop table #temp1
declare #tabletemp as varchar (10)
declare #columntemp as varchar (10)
Declare #sqlTemp NVARCHAR(400)
declare #counter1 as int
declare #counter2 as int
select #counter2 = 1
select name,cname into #temp1 from test1
select #counter1 = COUNT(*) from #temp1
while (#counter2<= #counter1)
begin
SET #tabletemp = (SELECT MIN(name) FROM #temp1)
select #columntemp = (select min(cname) from #temp1 where #temp1.name = #tabletemp)
set #sqlTemp='select '+#columntemp +' from '+#tabletemp
exec(#sqlTemp)
delete from #temp1 where name = #tabletemp and cname = #columntemp
select #counter1 = COUNT(*) from #temp1
end
RESULT
select * from test1
name cname
table1 column1
test2 colname
table1 test
test2 name
select column1 from table1
column1
qwer
asdff
zxcvb
qwer
asdff
zxcvb
select colname from test2
colname
testing
wer
ewrth
sfsf
testing
wer
ewrth
sfsf
select test from table1
--got error message inavlid column nae 'test' as this column does not exist
select name from test2
name
table1
table1
table3
table2
table1
table1
table3
table2
Related
I am trying to solve a problem. I want to change the rows into columns but I am not sure on how to do this. Pivot is a solution but the columns are not being fetched as I want them to. Here is an example.
The table above is the one that I want to use and convert it into something similar to the below one
Basicaly the quaters needs to be distributed in years on the same row for the same request ID. I had tried CASE but that seems to be an overkill for something like this.
Here is a fiddle to start with.
Thanks.
To get fully elastic solution you should search for dynamic pivot. If you know years in advance you could use:
;WITH cte AS
(
SELECT ReqId,quater1,quater2,quater3,quater4
,[q1] = CONCAT('Q1_',[year])
,[q2] = CONCAT('Q2_',[year])
,[q3] = CONCAT('Q3_',[year])
,[q4] = CONCAT('Q4_',[year])
FROM #forecast
)
SELECT ReqId
,[Q1_2014] = MAX([Q1_2014])
,[Q2_2014] = MAX([Q2_2014])
,[Q3_2014] = MAX([Q3_2014])
,[Q4_2014] = MAX([Q4_2014])
,[Q1_2015] = MAX([Q1_2015])
,[Q2_2015] = MAX([Q2_2015])
,[Q3_2015] = MAX([Q3_2015])
,[Q4_2015] = MAX([Q4_2015])
,[Q1_2016] = MAX([Q1_2016])
,[Q2_2016] = MAX([Q2_2016])
,[Q3_2016] = MAX([Q3_2016])
,[Q4_2016] = MAX([Q4_2016])
,[Q1_2017] = MAX([Q1_2017])
,[Q2_2017] = MAX([Q2_2017])
,[Q3_2017] = MAX([Q3_2017])
,[Q4_2017] = MAX([Q4_2017])
FROM cte
PIVOT (MAX(quater1) FOR [q1] IN ([Q1_2014],[Q1_2015],[Q1_2016],[Q1_2017])) AS pvt1
PIVOT (MAX(quater2) FOR [q2] IN ([Q2_2014],[Q2_2015],[Q2_2016],[Q2_2017])) AS pvt2
PIVOT (MAX(quater3) FOR [q3] IN ([Q3_2014],[Q3_2015],[Q3_2016],[Q3_2017])) AS pvt3
PIVOT (MAX(quater4) FOR [q4] IN ([Q4_2014],[Q4_2015],[Q4_2016],[Q4_2017])) AS pvt4
GROUP BY ReqId
LiveDemo
Output:
╔════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦══════════╦═════════╗
║ ReqId ║ Q1_2014 ║ Q2_2014 ║ Q3_2014 ║ Q4_2014 ║ Q1_2015 ║ Q2_2015 ║ Q3_2015 ║ Q4_2015 ║ Q1_2016 ║ Q2_2016 ║ Q3_2016 ║ Q4_2016 ║ Q1_2017 ║ Q2_2017 ║ Q3_2017 ║ Q4_2017 ║
╠════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬══════════╬═════════╣
║ 1 ║ 10 ║ 20 ║ 30 ║ 40 ║ 50 ║ 60 ║ 70 ║ 80 ║ 90 ║ 100 ║ 110 ║ 120 ║ (null) ║ (null) ║ (null) ║ (null) ║
║ 2 ║ 10 ║ 20 ║ 30 ║ 40 ║ 50 ║ 60 ║ 70 ║ 80 ║ 90 ║ 100 ║ 110 ║ 120 ║ 130 ║ 140 ║ 150 ║ 160 ║
╚════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩══════════╩═════════╝
Addendum 1
Alternatively:
;WITH cte AS (
SELECT ReqId, [q] ='Q1_' + CAST([year] AS CHAR(4)), quater = quater1 FROM #forecast
UNION ALL SELECT ReqId, [q] ='Q2_' + CAST([year] AS CHAR(4)), quater2 FROM #forecast
UNION ALL SELECT ReqId, [q] ='Q3_' + CAST([year] AS CHAR(4)), quater3 FROM #forecast
UNION ALL SELECT ReqId, [q] ='Q4_' + CAST([year] AS CHAR(4)), quater4 FROM #forecast
)
SELECT *
FROM cte
PIVOT (MAX(quater) FOR q IN (Q1_2014,Q2_2014,Q3_2014,Q4_2014,
Q1_2015,Q2_2015,Q3_2015,Q4_2015,
Q1_2016,Q2_2016,Q3_2016,Q4_2016,
Q1_2017,Q2_2017,Q3_2017,Q4_2017)
) AS pvt;
LiveDemo2
Addendum 2
Dynamic Pivot (you don't need to know years in advance):
DECLARE #sql NVARCHAR(MAX) = N'
WITH cte AS (
SELECT ReqId,[q] =''Q1_'' + CAST([year] AS CHAR(4)),quater = quater1 FROM #forecast
UNION ALL SELECT ReqId,[q] =''Q2_'' + CAST([year] AS CHAR(4)),quater2 FROM #forecast
UNION ALL SELECT ReqId,[q] =''Q3_'' + CAST([year] AS CHAR(4)),quater3 FROM #forecast
UNION ALL SELECT ReqId,[q] =''Q4_'' + CAST([year] AS CHAR(4)),quater4 FROM #forecast
)
SELECT *
FROM cte
PIVOT (MAX(quater) FOR q IN (<placeholder>)
) AS pvt;';
DECLARE #cols NVARCHAR(MAX) =
STUFF((SELECT ',' + QUOTENAME('Q1_' + CAST([year] AS CHAR(4))) +
',' + QUOTENAME('Q2_' + CAST([year] AS CHAR(4))) +
',' + QUOTENAME('Q3_' + CAST([year] AS CHAR(4))) +
',' + QUOTENAME('Q4_' + CAST([year] AS CHAR(4)))
FROM (SELECT DISTINCT [year] FROM #forecast) cte
ORDER BY [year]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '');
SET #sql = REPLACE(#sql, '<placeholder>', #cols);
EXEC [dbo].[sp_executesql] #sql;
LiveDemo3
Look That:
Concatenate Rows
Maybe give you a way.
I have tried looking for a solution to my problem using things such as Pivot, but they do not seem to give the output for which I am looking as they appear to map specific values in a row to a column.
I have two columns, the first which contains a "key" field and the second which is changing data. e.g.
╔══════════╦══════════════════╗
║ Project ║ Location ║
╠══════════╬══════════════════╣
║ ProjectA ║ \\Server1\Share1 ║
║ ProjectA ║ \\Server2\Share1 ║
║ ProjectB ║ \\Server6\Share2 ║
║ ProjectB ║ \\Server1\Share2 ║
║ ProjectB ║ \\Server2\Share3 ║
║ ProjectC ║ \\Server8\Share2 ║
║ ProjectD ║ \\Server5\Share9 ║
║ ProjectD ║ \\ServerX\ShareY ║
╚══════════╩══════════════════╝
The output that I am trying to achieve is as follows:
╔══════════╦══════════════════╦══════════════════╦══════════════════╦═════════╦══════════╦═════════╗
║ Project ║ Column1 ║ Column2 ║ Column3 ║ Column4 ║ Column5 ║ ColumnX ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬═════════╬══════════╬═════════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ ║
║ ProjectD ║ \\Server5\Share9 ║ \\ServerX\ShareY ║ NULL ║ NULL ║ NULL ║ ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩═════════╩══════════╩═════════╝
If there is no data for the column then it will be NULL.
The number of distinct values in the location column is dynamic and the desired output is a generic column name, with the distinct location value beside the corresponding Project value.
Hopefully someone can help me with this problem as it is driving me mad!
Thanks in advance.
Ninja
Warning:
This solution assume that it will be max 6 column, you can add more for example up to 20.
LiveDemo
Data:
CREATE TABLE #mytable(
Project VARCHAR(80) NOT NULL
,Location VARCHAR(160) NOT NULL
);
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server1\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server2\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server6\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server1\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server2\Share3');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectC','\\Server8\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\Server5\Share9');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
Query:
WITH cte AS
(
SELECT Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
FROM #mytable
)
SELECT
Project
,Column1 = MAX(CASE WHEN rn = 1 THEN Location ELSE NULL END)
,Column2 = MAX(CASE WHEN rn = 2 THEN Location ELSE NULL END)
,Column3 = MAX(CASE WHEN rn = 3 THEN Location ELSE NULL END)
,Column4 = MAX(CASE WHEN rn = 4 THEN Location ELSE NULL END)
,Column5 = MAX(CASE WHEN rn = 5 THEN Location ELSE NULL END)
,Column6 = MAX(CASE WHEN rn = 6 THEN Location ELSE NULL END)
-- ....
-- ,ColumnX = MAX(CASE WHEN rn = X THEN Location ELSE NULL END)
FROM cte
GROUP BY Project;
EDIT:
Truly generic solution that uses Dynamic-SQL and generates Pivoted column list:
LiveDemo2
DECLARE #cols NVARCHAR(MAX),
#cols_piv NVARCHAR(MAX),
#query NVARCHAR(MAX)
,#max INT = 0;
SELECT #max = MAX(c)
FROM (
SELECT Project, COUNT(DISTINCT Location) AS c
FROM #mytable
GROUP BY Project) AS s;
SET #cols = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] AS Column',c.n, ' ')
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= #max
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET #cols_piv = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] ')
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= #max
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
-- SELECT #cols;
set #query = N'SELECT Project, ' + #cols + ' from
(
select Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
from #mytable
) x
pivot
(
max(Location)
for rn in (' + #cols_piv + ')
) p ';
-- SELECT #query;
EXEC [dbo].[sp_executesql]
#query;
Credit goes to #lad2025.
I am using Server2005 so these are the modifications that I had to make to get this to work for me:
Couldn't declare and assign a variable in the same line. #max INT = 0;
CONCAT function doesn't exist so replaced with + between the parameters. ', ' + '[' + convert(varchar, c.n) + '] AS Column' + c.n
c.n is of type bigint so I had to CONVERT it to VARCHAR - CONVERT(VARCHAR, c.n)
When generating the table on which to pivot, a GROUP BY needs to be provided otherwise the data appears in a strange column number.
Without GROUP BY
Without the GROUP BY as more data is in the initial #mytable the results display in columns that are not sequential.
╔══════════╦══════════════════╦══════════════════╦══════════════════╦══════╦══════════════════╦══════╗
║ Project ║ Col1 ║ Col2 ║ Col3 ║ Col4 ║ Col5 ║ Col6 ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬══════╬══════════════════╬══════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ NULL ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectD ║ NULL ║ \\Server5\Share9 ║ NULL ║ NULL ║ \\ServerX\ShareY ║ NULL ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩══════╩══════════════════╩══════╝
With GROUP BY As it should be.
╔══════════╦══════════════════╦══════════════════╦══════════════════╦══════╦══════╦══════╗
║ Project ║ Col1 ║ Col2 ║ Col3 ║ Col4 ║ Col5 ║ Col6 ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬══════╬══════╬══════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ NULL ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectD ║ \\Server5\Share9 ║ \\ServerX\ShareY ║ NULL ║ NULL ║ NULL ║ NULL ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩══════╩══════╩══════╝
Data:
CREATE TABLE #mytable(
Project VARCHAR(80) NOT NULL
,Location VARCHAR(160) NOT NULL
);
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server1\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server2\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server6\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server1\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server2\Share3');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectC','\\Server8\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\Server5\Share9');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
Query:
DECLARE #cols NVARCHAR(MAX),
#cols_piv NVARCHAR(MAX),
#query NVARCHAR(MAX)
,#max INT;
SELECT #max = MAX(c)
FROM (
SELECT Project, COUNT(DISTINCT Location) AS c
FROM #mytable
GROUP BY Project) AS s;
SET #cols = STUFF(
(SELECT ', ' + '[' + convert(varchar, c.n) + '] AS Column' + convert(varchar, c.n)
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= #max
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET #cols_piv = STUFF(
(SELECT ',' + '[' + convert(varchar, c.n) + ']'
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= #max
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set #query = N'SELECT Project, ' + #cols + ' from
(
select Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
from #mytable
GROUP BY Project, Location
) x
pivot
(
max(Location)
for rn in (' + #cols_piv + ')
) p ';
EXEC [dbo].[sp_executesql]
#query;
Good Day,
I am busy creating a tax document for discount entries out of our debtors transaction table. One of the requirements is that the discount amount must indicate to which transaction it relates. This information is available but I do not know how to use it because it is in a single delimited text field. The table looks as follows.
╔═════════╦════════════╦══════╦════════╦═══════════╦══════════════════════════════════════════╗
║ AutoIdx ║ TxDate ║ Id ║ Amount ║ Reference ║ cAllocs ║
╠═════════╬════════════╬══════╬════════╬═══════════╬══════════════════════════════════════════╣
║ 1 ║ 30-07-2014 ║ OInv ║ 100 ║ IN543 ║ I=4;A=99;D=20140730|I=3;A=1;D=20140730 ║
║ 2 ║ 30-07-2014 ║ OInv ║ 200 ║ IN544 ║ I=4;A=198;D=20140730|I=3;A=2;D=20140730 ║
║ 3 ║ 30-07-2014 ║ DS ║ 3 ║ DISC ║ I=1;A=1;D=20140730|I=2;A=2;D=20140730 ║
║ 4 ║ 30-07-2014 ║ Pmnt ║ 297 ║ PMNT ║ I=1;A=99;D=20140730|I=2;A=198;D=20140730 ║
╚═════════╩════════════╩══════╩════════╩═══════════╩══════════════════════════════════════════╝
In the column cAllocs you have the information that links the lines with each other. It has three indicators
I - the line in this table that it links to
A - the amount of the link transaction
D - the date of the transaction
It can have only one set of these or many sets delimited with a pipe character.
I want to end up with a table that has only the entries with Id "DS" but giving me the reference column value of the lines it links to in a single column (they can be delimited by comma)
So from the above table I would like to get this result.
╔════════════╦════╦════════╦═══════════╦═════════════╗
║ TxDate ║ Id ║ Amount ║ Reference ║ MatchedTo ║
╠════════════╬════╬════════╬═══════════╬═════════════╣
║ 30-07-2014 ║ DS ║ 3 ║ DISC ║ IN543,IN544 ║
╚════════════╩════╩════════╩═══════════╩═════════════╝
Thanks for any replies
You can create a function that handles string manipulation and retrieves the data at the same time. Try this one below:
CREATE FUNCTION [dbo].[GetReferenceFromCAllocs](#cAllocs VARCHAR(MAX))RETURNS VARCHAR(MAX)AS
BEGIN
DECLARE #val AS VARCHAR(MAX)
DECLARE #ch AS CHAR(1)
DECLARE #result AS VARCHAR(MAX)
DECLARE #returnValue AS VARCHAR(MAX)
SET #val = #cAllocs
SET #result = ''
SET #returnValue = ''
DECLARE #idx INT
SET #idx = 1
WHILE #idx < LEN(#val)
BEGIN
SET #ch = SUBSTRING(#val,#idx,1)
IF(#ch = 'I')
BEGIN
DECLARE #idx2 INT
DECLARE #temp VARCHAR(5)
SET #temp = #ch
SET #idx2 = #idx + 1
SET #ch = SUBSTRING(#val,#idx2,1)
WHILE #ch <> ';'
BEGIN
SET #temp = #temp + #ch
SET #idx2 = #idx2 + 1
SET #ch = SUBSTRING(#val,#idx2,1)
END
SET #idx = #idx2
SET #result = #result + #temp + ';'
END
ELSE
SET #idx = #idx + 1
END
SET #idx = 1
WHILE #idx < LEN(#result)
BEGIN
SET #ch = SUBSTRING(#val,#idx,1)
IF(#ch = '=')
BEGIN
SET #temp = ''
SET #idx2 = #idx + 1
SET #ch = SUBSTRING(#result,#idx2,1)
WHILE #ch <> ';'
BEGIN
SET #temp = #temp + #ch
SET #idx2 = #idx2 + 1
SET #ch = SUBSTRING(#result,#idx2,1)
END
SET #idx = #idx2
DECLARE #tempValue AS VARCHAR(10)
SET #tempValue = ''
SELECT #tempValue = Reference FROM YOUR_TABLE
WHERE AutoIdx = #temp
SET #returnValue = #returnValue + #tempValue + ','
END
ELSE
SET #idx = #idx + 1
END
RETURN SUBSTRING(#returnValue,1, LEN(#returnValue)-1)
END
--EDIT: The function above will get all data with I as it's prefix:
E.g:
Passed Value: I=4;A=99;D=20140730|I=3;A=1;D=20140730
Result Value: I=4;I=3;
After that, it queries the corresponding Reference with AutoIdx 4 and 3; then returns it in a format as specified in your question.
Then, run this sql:
SELECT
yt.TxDate,
yt.Id,
yt.Amount,
yt.Reference,
dbo.GetReferenceFromCAllocs(yt.cAllocs) AS MatchedTo
FROM YOUR_TABLE yt
WHERE yt.Id = 'DS'
Hope this would work. Just adjust the SQL codes to optimize it. I'm in a hurry so I used safest values (such as VARCHAR(MAX)).
I have a table which must be with next structure:
╔════╦═══════╦════╦═════╗
║ id ║ a ║ c ║ b ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║ ║ P25 ║
║ 56 ║ ║ 56 ║ 25 ║
║ 57 ║ ║ 57 ║ 25 ║
╚════╩═══════╩════╩═════╝
where:
1) record with id=55 is a parent record and
2) records with id=56, id=57 (listed in a column and separated with semicolon) are child records
At first table is next
╔════╦═══════╦════╦═════╗
║ id ║ a ║ c ║ b ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║ ║ ║
║ 56 ║ ║ 56 ║ ║
║ 57 ║ ║ 57 ║ ║
╚════╩═══════╩════╩═════╝
so I must to update table such as first table
For this purpose I created next CTE
with My_CTE(PId, a, c, b, newC, inde) as
(
select
ST.PID, ST.a, ST.c, ST.b, res.C,
ind = case
when ST.a != ''
then (dense_rank() over(order by ST.a))
end
from STable as ST
outer APPLY
fnSplit(ST.a) as res
where (not(ST.a = '') or not(ST.c = ''))
)
UPDATE STable
Set b =
cte.inde
From STable as st
Join My_CTE as cte on st.PID = cte.PId;
GO
As a result I have table with next values
╔════╦═══════╦════╦═════╗
║ id ║ a ║ c ║ b ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║ ║ 25 ║
║ 56 ║ ║ 56 ║ ║
║ 57 ║ ║ 57 ║ ║
╚════╩═══════╩════╩═════╝
So I need to set values in column b for children records.
Maybe it could be established in select statement of MyCTE?
Help please
I am not entirely sure if I understand your request correctly so apologies if I have misunderstood.
So you have already managed to get the result set to here
╔════╦═══════╦════╦═════╗
║ id ║ a ║ c ║ b ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║ ║ 25 ║
║ 56 ║ ║ 56 ║ ║
║ 57 ║ ║ 57 ║ ║
╚════╩═══════╩════╩═════╝
Now you want this to look like this
╔════╦═══════╦════╦═════╗
║ id ║ a ║ c ║ b ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║ ║ P25 ║
║ 56 ║ ║ 56 ║ 25 ║
║ 57 ║ ║ 57 ║ 25 ║
╚════╩═══════╩════╩═════╝
Please see if this script works for you.
IF OBJECT_ID(N'tempdb..#temp')>0
DROP TABLE #temp
IF OBJECT_ID(N'tempdb..#temp1')>0
DROP TABLE #temp1
CREATE TABLE #temp (id int, a varchar(100),c varchar(100),b varchar(100))
INSERT INTO #temp VALUES ('55','56;57',' ','25')
INSERT INTO #temp VALUES ('56',' ','56',' ')
INSERT INTO #temp VALUES ('57',' ','57',' ')
SELECT * FROM #temp t
SELECT y.id, fn.string AS a,y.b
INTO #temp1
FROM #temp AS y
CROSS APPLY dbo.fnParseStringTSQL(y.a, ';') AS fn
--SELECT * FROM #temp1
UPDATE t
SET t.b=CASE WHEN CHARINDEX(';',t.a)>0 THEN 'P'+t.b ELSE t1.b END
FROM #temp t
LEFT JOIN #temp1 t1
ON t.id = t1.a
--DROP TABLE #temp
SELECT * FROM #temp t
IF OBJECT_ID(N'tempdb..#temp')>0
DROP TABLE #temp
IF OBJECT_ID(N'tempdb..#temp1')>0
DROP TABLE #temp1
Function borrowed from this link
CREATE FUNCTION [dbo].[fnParseStringTSQL]
(
#string NVARCHAR(MAX),
#separator NCHAR(1)
)
RETURNS #parsedString TABLE (string NVARCHAR(MAX))
AS
BEGIN
DECLARE #position INT
SET #position = 1
SET #string = #string + #separator
WHILE CHARINDEX(#separator, #string, #position) <> 0
BEGIN
INSERT INTO #parsedString
SELECT SUBSTRING(
#string,
#position,
CHARINDEX(#separator, #string, #position) - #position
)
SET #position = CHARINDEX(#separator, #string, #position) + 1
END
RETURN
END
This is really not an ideal data structure, but the following will do it...
CREATE TABLE #STable
(
id int primary key clustered
, a varchar(500)
, c varchar(500)
, b varchar(500)
)
INSERT INTO #STable
(id, a, c, b)
VALUES (55, '56;57', '', '25')
, (56, '', '56', '')
, (57, '', '57', '')
/* >>>>> Get all parents <<<<< */
CREATE TABLE #folks
(
sno int identity(1,1)
, id int
, a varchar(500)
)
CREATE TABLE #family
(
parent int
, child int
)
INSERT INTO #folks
(id, a)
SELECT id, a
FROM #STable
WHERE a <> ''
DECLARE #NID int
, #XID int
, #parent int
, #Children varchar(500)
, #Child int
SELECT #NID = MIN(sno), #XID = MAX(sno)
FROM #folks
/* >>>>> Loop to figure out the children <<<<< */
WHILE #NID <= #XID
BEGIN
SELECT #parent = id, #Children = a
FROM #folks
WHERE sno = #NID
WHILE LEN(#Children) > 0
BEGIN
IF CHARINDEX(';', #Children) > 0
BEGIN
SET #Child = CAST(LEFT(#Children, CHARINDEX(';', #Children) -1) as int)
SET #Children = RIGHT(#Children, LEN(#Children) - CHARINDEX(';', #Children))
INSERT INTO #family
(parent, child)
VALUES (#parent, #Child)
END
ELSE
BEGIN
SET #Child = CAST(#Children AS INT)
SET #Children = ''
INSERT INTO #family
(parent, child)
VALUES (#parent, #Child)
END
END
SET #NID = #NID + 1
END
/* >>>>> Update <<<<< */
UPDATE c
SET b = p.b
FROM #family f
INNER JOIN #STable p
on f.parent = p.id
INNER JOIN #STable c
on f.child = c.id
SELECT *
FROM #STable
DROP TABLE #STable
DROP TABLE #folks
DROP TABLE #family
I'm having some problems replacing my ROLLUP NULL with a string value because my column data type is an Integer.
SELECT CASE
WHEN GROUPING(Column1) = 1 THEN 'Total'
ELSE Column1
END Column1, SUM(Column2) AS MySum
FROM MyTable
GROUP BY Column1 WITH ROLLUP;
I can put a numeric value in:
WHEN GROUPING(Column1) = 1 THEN '9999'
but I can't figure out how to convert to varchar if value is NULL and then replace with 'Total'.
Test Data
DECLARE #MyTable TABLE (Column1 INT,Column2 INT)
INSERT INTO #MyTable VALUES
(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)
SELECT CASE
WHEN GROUPING(Column1) = 1 THEN 'Total'
ELSE CAST(Column1 AS VARCHAR(10)) --<-- Cast as Varchar
END Column1
, SUM(Column2) AS MySum
FROM #MyTable
GROUP BY Column1
WITH ROLLUP;
Result Set
╔═════════╦═══════╗
║ Column1 ║ MySum ║
╠═════════╬═══════╣
║ 1 ║ 6 ║
║ 2 ║ 6 ║
║ 3 ║ 6 ║
║ Total ║ 18 ║
╚═════════╩═══════╝
Note
The reason you couldnt do what you were trying to do is because when you use a CASE statement in each case the returned datatype should be the same.
In above query I have just CAST the colum1 to varchar and it worked.