how to create a table structure from column values of another table in MSSQL - sql

I have a scenario where i have the entries in a column of a table with CSV ( these are dynamic values). I need to generate the tables with those values in sqlserver(MSSQL)
Input Table
Value
FirstName,LastName,SSN
Address1,City,Zip
HomePhone,CellPhone
Output Table1
FirstName LastName SSN
Output Table2
Address1 City Zip
Output Table3
HomePhone CellPhone
Can some one please help me.

You need dynamic SQL for this, such as:
declare #sql nvarchar(max);
with t as (
select 'FirstName,LastName,SSN' as value union all
select 'Address1,City,Zip' union all
select 'HomePhone,CellPhone'
)
select #sql = (select 'create table'+CAST(seqnum as varchar(255))+' ('+REPLACE(value, ',', ' varchar(255),') + ' varchar(255)); '
from (select t.*, ROW_NUMBER() over (order by (select null)) as seqnum
from t
) t
for xml path ('')
)
exec sp_executesql #sql;

Try This,
Select FirstName,LastName,SSN into Table1 from #InputTable
Select Address1,City,Zip into Table2 from #InputTable
Select HomePhone,CellPhone into Table1 from #InputTable

Related

Execute create table query from column in SQL server

I have two select statements which are to create table and insert values into table. How to execute all the queries inside the column at one go? Below is my code and the output:
select n.*
into #norm
from specNormalization n
select n.*
into #raw
from rawdata n
select distinct 'CREATE TABLE raw' + c.desttablename + ' (' + STUFF(
(select ','+QUOTENAME( c.[destfieldname] ) + c.datatype
from #norm c
group by c.destfieldname, c.datatype
for xml path ('')),1,1,'') as createTableSQL
select distinct 'INSERT INTO raw' + c.desttablename +
select d.contents
from #raw d join #norm c on d.tablename = c.desttablename
as insertTableSQL
rawdata table
desttablename
destfieldname
datatype
rawtable
SbjNum
int
rawtable
Surveyor
nvarchar(20)
rawtable
Location
nvarchar(20)
rawtable2
SbjNum
int
rawtable2
Name
nvarchar(20)
rawtable2
Address
nvarchar(20)
specnomalization table
tablename
destfieldname
contents
rawtable
SbjNum
1
rawtable
Surveyor
Alex
rawtable
Location
Georgia
rawtable2
SbjNum
1
rawtable2
Name
Sandra
rawtable2
Address
Portland
createTableSQL
CREATE TABLE rawtable ([Sbjnum])int, ([Surveyor])nvarchar(200), ([Location])nvarchar(200)
CREATE TABLE rawtable2 ([Sbjnum])int, ([Name])nvarchar(200), ([Address])nvarchar(200)
insertTableSQL
INSERT INTO rawtable SELECT [Sbjnum], [Surveyor], [Location] from #raw
INSERT INTO rawtable2 SELECT [Sbjnum], [Name], [Address] from #raw
You can create the create query by using stuff. Since you would have multiple tables so you have to group by the query to return multiple table names and it's columns separately. So the result query you can set into a variable and can execute by using
EXEC sp_executesql
So you can easily create as much as tables based on your table data.
The following query will help you to create multiple tables. This you can optimize if needed, but this will give you the insight to do the same for inserting values to the tables respectively.
Declare #sql nvarchar(MAX) = ( SELECT ' CREATE TABLE '+ desttablename +' (' + STUFF((SELECT ', ' + sn.[destfieldname] + ' ' +datatype
FROM dbo.specNormalization As sn
ORDER BY sn.destfieldname
FOR XML PATH(''), TYPE).value('.[1]', 'varchar(max)'), 1, 2, '') + ' )'
FROM dbo.specNormalization as P2
GROUP BY P2.desttablename FOR XML PATH('') )
-- Uncomment to see the created query
-- SELECT #sql
-- To execute the created query. This will create the tables with column and datatype
EXEC sp_executesql #sql
Hope this helps. Happy coding :)
Too long for a comment. Try to generate SELECT .. INTO .. FROM to create and populate a target table. Kind of
SELECT cast([Sbjnum] as int) [Sbjnum], cast([Surveyor] as nvarchar(200)) [Surveyor], cast([Location] as nvarchar(200)) [Location]
INTO rawtable
FROM #raw
If the source types are the same as target, skip cast functions. Can't tell what is the query to generate it as no sample data are provided.

create one row from two columns sql

How to create one row from two columns?
Example:
id description
------------------
1 one
2 two
3 three
In result:
1: one, 2: two, 3: three
I use follow statment:
select Id,
stuff((SELECT distinct ', ' + cast(Description as varchar(10))
FROM dbo.tbl t2
where t2.Id = t1.Id
FOR XML PATH('')),1,1,'')
from dbo.tbl t1
group by Id
But in result I have two columns. I need one such as string
You can try this query.
CREATE TABLE T (
id int,
description varchar(50)
);
INSERT INTO T VALUES (1,'one');
INSERT INTO T VALUES (2,'two');
INSERT INTO T VALUES (3,'three');
Query 1:
select
stuff((SELECT ', ' + CAST(t2.ID AS VARCHAR(5)) + ':'+ t2.description
FROM t t2
FOR XML PATH('')),1,1,'')
Results:
| |
|------------------------|
| 1:one, 2:two, 3:three |
i think you are asking for this
select stuff((SELECT ', ' + CAST(tbl.id AS varchar) + ':' + tbl.description
FROM tablename tbl FOR XML PATH('')), 1, 1, '') as Columnname
You were close..
declare #T TABLE (
id int,
description varchar(50)
);
INSERT INTO #T VALUES (1,'one');
INSERT INTO #T VALUES (2,'two');
INSERT INTO #T VALUES (3,'three');
select Id,
stuff((SELECT distinct ', ' + +cast(id as nvarchar) +':'+description
FROM #T t2
where t2.Id = t1.Id
FOR XML PATH('')),1,1,'')
from #T t1
group by Id
OR If you want all the ids in a sing row use the below query
select stuff((select ',' +cast(id as nvarchar) +':'+description
from #T for xml path('')),1,1,'')
select statement is like a for loop or an iterator and you you need a space to save you data and it's not possible with select only because in the moment select statement only access to a row not previous row and not next row so
please use a scaler-value function
create function test()
return
nvarchar(max)
as
begin
declare #s nvarchar(max)
select #s = concate(#s, id, description)
from yourTable
return #s
end

Concatenate results in select

I am trying to insert values into a table that come from an other (lookup) table.
The first 3 results from the table are selected and need to be concatenated before they are inserted into an other table.
How can I alter the following insert to first concatenates them with no separation characters between the 3 names (example: JohnMaxLouise)?
INSERT INTO Table 2 VALUES ((SELECT TOP 3 names FROM Table1 ORDER BY NEWID()))
I am using SQL Server 2016 so string_agg is not available.
Personally, I think this is simplest with conditional aggregation:
INSERT INTO Table2
SELECT (MAX(CASE WHEN seqnum = 1 THEN name ELSE '' END) +
MAX(CASE WHEN seqnum = 2 THEN name ELSE '' END) +
MAX(CASE WHEN seqnum = 3 THEN name ELSE '' END)
)
FROM (SELECT name, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as seqnum
FROM (SELECT TOP 3 name
FROM Table1
ORDER BY NEWID()
) t
) t;
An alternative is an XML approach, but if you know you want three, then conditional aggregation (or pivot) works fine.
try the following:
declare #tab table (names varchar(max))
declare #tab1 table ([name] varchar(100))
insert into #tab1
select 'John' union select 'Max' union select 'Louise' union select 'xxx'
insert into #tab select (select top 3 [name] + '' from #tab1 for xml path(''))
select * from #tab
Thanks.
This will return '1,2,3,4'
DECLARE #x TABLE (i INTEGER)
DECLARE #r VARCHAR(255)
INSERT INTO #x VALUES (1),(3),(2),(4)
SELECT #r= STUFF(( SELECT ',' + CAST(i AS VARCHAR(max))
FROM #x
ORDER BY i
FOR XML PATH(''), type
).value('.','varchar(255)'), 1, 1, '')
SELECT #r
Solution Overview
You can use FOR XML PATH('') to achieve this, just use the following command:
SELECT '' + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T
FOR XML PATH('')
Or simple concatenation
SELECT #x = #x + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T1
Detailed Solution
SQLFiddle Demo
First i created the test environment using the following query
CREATE TABLE TBL_1 (NAME Varchar(50))
CREATE TABLE TBL_2 (NAME Varchar(50))
INSERT INTO TBL_1 (Name) VALUES ('John'),('Max'),('Louise'),('Mark'),('Peter')
Then i Used the following command
DECLARE #x varchar(255)
SELECT #x = (SELECT '' + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T1
FOR XML PATH('') )
INSERT INTO TBL_2(NAME) SELECT #x;
SELECT * FROM TBL_2
And the Result is JohnLouiseMax
Or you can use simple concatenation to achieve this
SQLFiddle Demo
DECLARE #x varchar(255)
SET #x = ''
SELECT #x = #x + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T1
INSERT INTO TBL_2(NAME) SELECT #x;
SELECT * FROM TBL_2

convert rows as column (like PIVOT) is not working if the number of values increases in SQL Server

I want to convert rows as column (like PIVOT) and i am unable to get if the number of values increases.
Below is my table.
i want the output like this.
I have used the following queries to acheive this but no luck.
Query1
Create table #temp(instanceid int, submissionid int, name1 varchar(20), value1 varchar(20))
insert into #temp(instanceid,submissionid,name1,value1)
Select 5151,5532,'Question_1','Y'
union
Select 5151,5532,'First','Mujda'
union
Select 5151,5532,'Last','Zhublawar'
union
Select 5151,5532,'Question_1','Y'
union
Select 5151,5532,'First','Mujda1'
union
Select 5151,5532,'Last','Zhublawar1'
union
Select 5151,5532,'Question_1','Y'
union
Select 5152,5533,'First','Muthu'
union
Select 5151,5533,'Last','Kumar'
union
Select 5152,5533,'Question_1','Y'
union
Select 5152,5533,'First','Muthu1'
union
Select 5152,5533,'Last','Kumar1'
GO
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
DECLARE #PivotValues AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(seq)
FROM (
select (cast(row_number() over(partition by name1 order by name1) as varchar(10)) + name1) as seq
from #temp group by value1,name1,instanceid
) AS PivotExample
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT instanceid,submissionid, ' + #PivotColumns + '
FROM #temp
PIVOT( MAX(value1)
FOR name1 IN (' + #PivotColumns + ')) AS P'
--Execute dynamic query
EXEC sp_executesql #SQLQuery
DROP TABLE #temp
Query2:
Create table #temp(instanceid int, submissionid int, name1 varchar(20), value1 varchar(20))
insert into #temp(instanceid,submissionid,name1,value1)
Select 5151,5532,'Question_1','Y'
union
Select 5151,5532,'First','Mujda'
union
Select 5151,5532,'Last','Zhublawar'
union
Select 5151,5532,'Interest','100'
select * from(
Select
instanceid,
submissionid,
[1st Ownership First Name] = Case when name1='First' then value1 end,
[1st Ownership Last Name] = Case when name1='Last' then value1 end,
[1st Ownership Question] = Case when name1='Question_1' then value1 end
from #temp
group by instanceid,submissionid,name1,value1
) P where p.[1st Ownership First Name] is not null or p.[1st Ownership Last Name] is not null or p.[1st Ownership Question] is not null
drop table #temp
You need an extra field to get some order in that data with all the duplicates.
For example a primary key.
Then you can use a pivot with a row_number that uses that extra field in the order by.
Then concat the row_number with the name1, and Pivot on those.
For example :
create table #temp (id int identity(1,1), instanceid int, submissionid int, name1 varchar(20), value1 varchar(20));
insert into #temp(instanceid,submissionid,name1,value1) values
(5151,5532,'First','Mujda'),
(5151,5532,'Last','Zhublawar'),
(5151,5532,'Question_1','Y'),
(5151,5532,'First','Mujda1'),
(5151,5532,'Last','Zhublawar1'),
(5151,5532,'Question_1','Y'),
(5151,5532,'First','Mujda1'),
(5151,5532,'Last','Zhublawar1'),
(5151,5532,'Question_1','Y'),
(5151,5533,'First','Muthu'),
(5151,5533,'Last','Kumar'),
(5151,5533,'Question_1','Y'),
(5151,5534,'First','Suresh'),
(5151,5534,'Last','Kumar'),
(5151,5534,'Question_1','Y'),
(5151,5534,'First','Suresh1'),
(5151,5534,'Last','Kumar1'),
(5151,5534,'Question_1','Y');
SELECT
instanceid,
submissionid,
[First1] as [1st First], [Last1] as [1st Last], [Question_11] as [1st Question_1],
[First2] as [2nd First], [Last2] as [2nd Last], [Question_12] as [2nd Question_1],
[First3] as [3rd First], [Last3] as [3rd Last], [Question_13] as [3rd Question_1]
FROM (
select
instanceid,
submissionid,
concat(name1, row_number() over (partition by instanceid, submissionid, name1 order by id)) as name_rn, value1
from #temp
where name1 in ('First','Last','Question_1')
) t
PIVOT( MAX(value1)
FOR name_rn IN (
[First1], [Last1], [Question_11],
[First2], [Last2], [Question_12],
[First3], [Last3], [Question_13]
)
) AS Pvt;
To do it the dynamic way, here's some SQL to generate a #SQL variable.
declare #T table (name1 varchar(20));
insert into #T select name1 from #temp group by name1 order by name1;
declare #SQL nvarchar(max);
declare #Fields1 nvarchar(max);
declare #Fields2 nvarchar(max);
SELECT #Fields2 = STUFF((select ', ' + quotename(name1) from #T order by name1 FOR XML PATH('')),1,1,'');
SET #Fields2 = replace(#Fields2,']','1]')+','+char(13)+replace(#Fields2,']','2]')+','+char(13)+replace(#Fields2,']','3]');
SELECT #Fields1 = STUFF((select ',$' + quotename(name1+n)+' as '+quotename(nx+' '+name1) from (
select '1' as n, '1st' as nx, name1 from #T union all
select '2', '2nd' as nx, name1 from #T union all
select '3', '3rd' as nx, name1 from #T
) q order by n, name1 FOR XML PATH('')),1,1,'');
SET #Fields1 = replace(#Fields1,'$',char(13));
SET #SQL =
'SELECT
instanceid,
submissionid,'+#Fields1+'
FROM (
select
instanceid,
submissionid,
concat(name1, row_number() over (partition by instanceid, submissionid, name1 order by id)) as name_rn, value1
from #temp
) t
PIVOT( MAX(value1)
FOR name_rn IN ('+char(13)+#Fields2+')
) AS Pvt';
select #SQL;
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(seq)
FROM (
select DISTINCT (name1) as seq
from #temp group by value1,name1,instanceid
) AS PivotExample
This are is your problem you are concatenating a row_number into the name1 value which would always be null. Your column list needs to be the DISTINCT values in name1 NOT what you want them to be in the end. If you want to rename columns you would alias them after the pivot or change the value in name1 prior to running the pivot.
So in the above code I removed the ROW_NUMBER() and added DISTINCT to the derived table.
Also note the test data you included has some instanceid & submissionid combinations that are missing certain fields like first name, or question. It looks like when copying and pasting you just didn't correct the correlations.

Combine two rows into one row. like average function but instead it will concat

I'm using SQL Server 2000.
What I want to do is like average function but instead it will concat.
Is there a way that I can do that?
For example I have this data.
Name | Score
Name1 | 50
Name1 | 70
and the output should be like this.
Name | Score
Name1 | 50,70
Use below query for your reference.
Query
Select main.doctorID,
Left(Main.submain,Len(Main.submain)-1) As 'Title'
From
(
Select distinct ST2.doctorID,
(
Select convert(varchar,ST1.encounterid) + ',' AS [text()]
From dbo.enc ST1
Where ST1.doctorID = ST2.doctorID
ORDER BY ST1.doctorID
For XML PATH ('')
) submain
From dbo.enc ST2
) [Main]
If you can use CLR, look at this example :
https://msdn.microsoft.com/en-us/library/ms165055%28v=vs.90%29.aspx
It provides a custom aggregate that concatenates values, which results in very clean code.
You can do it by this simple query.
Select Name, (Select SUBSTRING((SELECT ', '+Score from TableName for XML
Path('')) ,2,8000)) from TableName
You will have result like
ColumnName | val1, val2, ....
check this.
INSERT INTO #T VALUES
('name1', 50),
('name1', 70)
SELECT * FROM #T
Select name ,
STUFF((SELECT ',' + cast( score as varchar(50)) FROM #T WHERE (
name=Result.name) FOR XML PATH ('')),1,1,'') AS BATCHNOLIST
From #T AS Result
GROUP BY name
Can I Comma Delimit Multiple Rows Into One Column?
Query
SELECT Name,
(SELECT SUBSTRING((SELECT ', '+CAST(Score AS VARCHAR(MAX)) FROM my_table FOR XML Path('')) ,2,1000)) AS Score
FROM my_table
GROUP BY name;
Fiddle for reference
If you are using SQL Server 2000, then try to create a function as follows.
CREATE TABLE my_table(name VARCHAR(50),score INT);
INSERT INTO my_table VALUES('Name1',50);
INSERT INTO my_table VALUES('Name1',70);
Function
CREATE FUNCTION commaseparated(#name VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #score VARCHAR(MAX)
SELECT #score = COALESCE(#score + ', ', '') + CAST(score AS VARCHAR(MAX))
FROM my_table
WHERE name = #name
RETURN #score
END
SELECT
name,
score = dbo.commaseparated(name)
FROM my_table
GROUP BY name;