update table with values in related records - sql

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

Related

Converting rows to column using SQL

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.

Concatenating numbers from a single numeric column in SQL without using concat function

I have the following code for a single column table that has values from 0 to 9:
create table number(
value int
)
truncate table number
insert into number values(0);
insert into number values(1);
insert into number values(2);
insert into number values(3);
insert into number values(4);
insert into number values(5);
insert into number values(6);
insert into number values(7);
insert into number values(8);
insert into number values(9);
What I want is a query which should join the numbers without using concat (or any builtin function) function and gives me the following output in a tabular form:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.
.
.
.
.
999
Really having a hard time doing it for the past 5 days. Need sincere help.
You could use CROSS JOIN and simple Math formula:
SELECT [num] = n1.value * 100 + n2.value * 10 + n3.value
FROM number n1, number n2, number n3
ORDER BY num
LiveDemo
Output:
╔═════╗
║ num ║
╠═════╣
║ 0 ║
║ 1 ║
║ 2 ║
║ 3 ║
║ 4 ║
║ 5 ║
║ 6 ║
║ 7 ║
║ ... ║
║ 999 ║
╚═════╝
EDIT:
Cross join will return records(tuples) (0,0,0), (0,0,1),(0,0,2), ...,(9,9,9) then you need to apply Positional Number System formula:
example:
Images from https://en.wikipedia.org/wiki/Positional_notation
╔════════════╦═══════════╦══════════╦════════════════════╗
║ 10^2 = 100 ║ 10^1 = 10 ║ 10^0 = 1 ║ num ║
╠════════════╬═══════════╬══════════╬════════════════════╣
║ 0 * 100 ║ 0 * 10 ║ 0 * 1 ║ 0 + 0 + 0 = 0 ║
║ 0 * 100 ║ 0 * 10 ║ 1 * 1 ║ 0 + 0 + 1 = 1 ║
║ 0 * 100 ║ 0 * 10 ║ 2 * 1 ║ 0 + 0 + 2 = 2 ║
║ ... ║ ... ║ ... ║ ... ║
║ 9 * 100 ║ 9 * 10 ║ 9 * 1 ║ 900 + 90 + 9 = 999 ║
╚════════════╩═══════════╩══════════╩════════════════════╝
While #lad2025 query is good based on certain formula.It uses 3 cross join.
Simpler way (not sure,if this is best)
Declare #number table(
value int
)
insert into #number values(0);
insert into #number values(1);
insert into #number values(2);
insert into #number values(3);
insert into #number values(4);
insert into #number values(5);
insert into #number values(6);
insert into #number values(7);
insert into #number values(8);
insert into #number values(9);
Declare #MaxLimit int=999
;
WITH CTE
AS (
SELECT value
FROM #number A
UNION ALL
SELECT a.value + 10
FROM CTE A
WHERE A.value < #MaxLimit-9
)
SELECT value
FROM cte
--WHERE value <= 999
ORDER BY value

SQL: Convert Data For One Column To Multiple Columns

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;

How to sort a column based on length of data in it in SQL server

As we all know general sorting is using order by. The sort I want to perform is different. I want the smallest length value in middle of table n the largest ones in top and bottom of it. One half should be descending and another half should be ascending. Can you guys help. It was an interview question.
This is one way:
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(ORDER BY LEN(YourColumn))
FROM dbo.YourTable
)
SELECT *
FROM CTE
ORDER BY RN%2, (CASE WHEN RN%2 = 0 THEN 1 ELSE -1 END)*RN DESC
Test Data
DECLARE #Table TABLE
(ID INT, Value VARCHAR(10))
INSERT INTO #Table VALUES
(1 , 'A'),
(2 , 'AB'),
(3 , 'ABC'),
(4 , 'ABCD'),
(5 , 'ABCDE'),
(6 , 'ABCDEF'),
(7 , 'ABCDEFG'),
(8 , 'ABCDEFGI'),
(9 , 'ABCDEFGIJ'),
(10 ,'ABCDEFGIJK')
Query
;WITH CTE AS (
SELECT *
,NTILE(2) OVER (ORDER BY LEN(Value) DESC) rn
FROM #Table )
SELECT *
FROM CTE
ORDER BY CASE WHEN rn = 1 THEN LEN(Value) END DESC
,CASE WHEN rn = 2 THEN LEN(Value) END ASC
Result
╔════╦════════════╦════╗
║ ID ║ Value ║ rn ║
╠════╬════════════╬════╣
║ 10 ║ ABCDEFGIJK ║ 1 ║
║ 9 ║ ABCDEFGIJ ║ 1 ║
║ 8 ║ ABCDEFGI ║ 1 ║
║ 7 ║ ABCDEFG ║ 1 ║
║ 6 ║ ABCDEF ║ 1 ║
║ 1 ║ A ║ 2 ║
║ 2 ║ AB ║ 2 ║
║ 3 ║ ABC ║ 2 ║
║ 4 ║ ABCD ║ 2 ║
║ 5 ║ ABCDE ║ 2 ║
╚════╩════════════╩════╝
Here's a short approach that would ge t you started:
WITH cte AS
(
SELECT TOP 1000 number
FROM master..spt_values
WHERE type = 'P' and number >0
)
SELECT number, row_number() OVER(ORDER BY CASE WHEN number %2 = 1 THEN number ELSE -(number) END) pos
FROM cte

Use result of one query in another sql query

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