I came up with the following script to dynamically create INSERT statements for a given table.
CREATE TABLE Employee ([Id] int, [Name] NVARCHAR(25))
INSERT INTO Employee VALUES (1, 'Vyas')
INSERT INTO Employee VALUES (2, 'Nandhini')
select 'Insert into employee (' +
STUFF ((
SELECT ', [' + name + ']'
FROM syscolumns
WHERE id = OBJECT_ID('employee')
FOR XML PATH('')), 1, 1, '') +
') values(' +
stuff((select +',' + cast([id] as varchar(2)) +','''+ [name] + '''' from Employee e1 where e1.id = e2.id for xml path('')),1,1,'') +
')'
from employee e2
The script creates insert statements as required.
Insert into employee ( [Id], [Name]) values(1,'Vyas')
Insert into employee ( [Id], [Name]) values(2,'Nandhini')
However, I need
The value SQL statement to be dynamic as the first
Only selected columns with common SQL Server datatypes to be handled & quoted correctly (int, [n]varchar, uniqueidentifier and bit)
What's the best way to accomplish this?
Related
I have the following schema and sample data.
create table MyTable
(
Id int,
Year int,
Channel varchar(10),
Payments int
)
insert into MyTable values
(1,2012,'HV',100),
(1,2014,'HV',56),
(2,2012,'NL',17000)
(2,2012,'HV',495),
(3,2013,'HV',565)
Now I want to create and insert dynamic pivot data in a temporary table. I am able to create the pivot data as the demo here.
But I want to store this data into a temporary table. What I have tried is as below.
Declare #SQL varchar(max) = '
if object_id(''tempdb..##TempTable'') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TempTable
Select *
From (
Select A.Id
,B.*
From [dbo].[MyTable] A
Cross Apply ( values ( Id, Channel + CONVERT(Varchar(4), Year)
)) B (Item,Value)
) S
Pivot (sum([Payments]) For Channel + CONVERT(Varchar(4), Year) in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'') + ') ) p'
select #SQL
Exec(#SQL);
SELECT * FROM ##TempTable
It is giving me the following error.
Msg 102, Level 15, State 1, Line 18 Incorrect syntax near '+'.
When printing the dynamic query it is giving the following result.
if object_id('tempdb..##TempTable') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, [HV2012] Varchar(20) null,[HV2013] Varchar(20) null,[HV2014] Varchar(20) null,[NL2012] Varchar(20) null)
INSERT INTO ##TempTable
Select * From ( Select A.Id ,B.* From [dbo].[MyTable] A
Cross Apply ( values ( Id, Channel + CONVERT(Varchar(4), Year) )) B (Item,Value) ) S
Pivot (sum([Payments]) For Channel + CONVERT(Varchar(4), Year) in ([HV2012],[HV2013],[HV2014],[NL2012]) ) p
If you are using apply then why you need further same logic in PIVOT (i.e. Channel + CONVERT(Varchar(4), Year)) which is already available in apply.
So, i would use Value instead in PIVOT :
. . .
Pivot (sum([Payments]) For [Value] in ([HV2012],[HV2013],[HV2014],[NL2012]) ) p,
So, your updated Dynamic SQL would be :
Declare #SQL varchar(max) = '
if object_id(''tempdb..##TempTable'') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TempTable
Select *
From (
Select A.ID, A.Payments
,B.*
From [dbo].MyTable a
Cross Apply ( values ( Channel + CONVERT(Varchar(4), Year)
)) B ([Value])
) S
Pivot (sum([Payments]) For [Value] in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From #tm
Order By 1
For XML Path('')),1,1,'') + ') ) p'
print #sql
Exec(#SQL)
SELECT * FROM ##TempTable
I have made no of changes as there are many correction needs to be done prior to execution.
I have a table with around 10 rows. I want to pivot on all values in one column to a one-row multi column result. It looks as though there is no way to get around the "For ContactTypeID in ([1],[2])" syntax.
ContactTypeID int
ContactType varchar(20)
Sample data:
1 Customer
2 Vendor
...
5 BillTo
I want to return a single row with
Customer Vendor BillTo, etc
1 2 5
But like I said, I don't want to have to specify each ContactTypeID by number. Is there way to specify "for all"?
Thank you.
You need a dynamic pivot.
Here's the code, for your reference. Hope it helps.
CREATE TABLE tablename (ContactTypeID int, ContactType varchar(20));
INSERT INTO tablename VALUES (1, 'Customer'), (2, 'Vendor'), (5, 'BillTo');
DECLARE #cols NVARCHAR (MAX);
SELECT #cols = COALESCE (#cols + ',[' + ContactType + ']',
'[' + ContactType + ']')
FROM (SELECT DISTINCT [ContactType] FROM tablename) PV
ORDER BY [ContactType]
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT * FROM tablename
) x
PIVOT
(
MIN(ContactTypeID)
FOR [ContactType] IN (' + #cols + ')
) p
'
EXEC SP_EXECUTESQL #query;
I have a table of variables and values of which i will know which parametercodes to select. This table would change dynamically.
CREATE TABLE #TreatmentTableVariables (ParameterCode VARCHAR(64), Value varchar(64))
INSERT #TreatmentTableVariables VALUES ('TripOriginLocationCode','BGY')
I then have another table called AnalyticsDW.Treatment, where there is a column called TripOriginLocationCode and I want to select those rows from AnalyticsDW.Treatment where TripOriginLocationCode = the value from #TreatmentTableVariables.
AnalyticsDW.Treatment has primarykey of TreatmentID.
So i was originally using dynamic SQL to select the columns of TreatmentID that are contained in the temp table
SELECT #Columns = SubString ( ( SELECT + ', ' +'t.' + QUOTENAME(Column_name)
from INFORMATION_SCHEMA.columns c
JOIN #TreatmentTableVariables t ON c.COLUMN_NAME=t.ParameterCode
WHERE Table_name IN ('Treatment','TreatmentProduct') AND TABLE_SCHEMA='AnalyticsDW'
FOR XML PATH ( '' ) ), 1, 1000)
but I am struggling on how to do the same thing to only select the rows of AnalyticsDW.Treatment where the dynamic column equals the parmetercode from #TreatmentTableVariables and the Value from #TreatmentTableVariables equals the value of the observation for that particular column.
Sample AnalyticsDW.Treatment data:
Declare AnalyticsDW.Treatment table
(
TreatmentID varchar(100),
TripOriginLocationCode varchar(100),
TripDestinationLocationCode varchar(100)
)
insert into AnalyticsDW.Treatment values
('1','BRG','SLC'),
('2','AHO','BRG')
Goal dataset:
Declare #goal table
(
TripOriginLocationCode varchar(100)
)
insert into #goal values
('BRG')
Example on how I was selecting from a goal dataset (within a dynamic sql query):
declare #dynamicquery varchar(200)
set #dynamicquery='
select a.*, '+#Columns+' into #CompletePricingtypes2 from #somedataset a
join AnalyticsDW.Treatment t on a.TreatmentID=t.TreatmentID '
Edit: additional info
declare
#whereConditions nvarchar(max) = stuff((
-- here we create where conditions as
-- paramCode in (itsValues)
-- or anotherParamCode in (anotherItsValues) etc.
select
'or ' + 'where ' +'t.' +ParameterCode + ' in ('+''''+ltrim([Values]) +''''+') '
from (
-- here we create output with two columns: parameter code and
-- all values associated with that code separated by comma
select
t.ParameterCode,
stuff((
select
', ' + [Value]
from #TreatmentTableVariables
where
ParameterCode in (t.ParameterCode)
FOR XML PATH ('')
), 1, 1, '') as [Values]
from #TreatmentTableVariables t
where ParameterCode in (select COLUMN_name from INFORMATION_SCHEMA.columns where Table_name IN ('Treatment') AND TABLE_SCHEMA='AnalyticsDW')
) conditions
), 1, 3, '')
print #whereconditions
edit: this works
select
'or ' + ParameterCode + ' in('+ [Values] +')
'
from (
select distinct
t.ParameterCode,
(
select
', ''' + [Value] + ''''
from #TreatmentTableVariables
where
ParameterCode in (t.ParameterCode)
) as [Values]
from #TreatmentTableVariables t
where ParameterCode in (select
COLUMN_name
from INFORMATION_SCHEMA.columns
where Table_name IN ('Treatment') AND TABLE_SCHEMA='AnalyticsDW')
) conditions
UPD. First, I forgot distinct in inner select.
Second, you're still trying to wrap whole in condition with single quotes. You need
or ParameterCode in ('value1', 'value2', 'value3')
, but you do it as
or ParameterCode in ('value1, value2, value3') -- look at quotes
Third, you put where to every or condition as
where ParameterCode1 in (...)
or where ParameterCode2 in (...)
or where ParameterCode3 in (...)
Remove it from #whereCondition string construction and complete your query as I do further in #selectQuery variable.
I think you can use real dynamic sql queries, i.e. build query dynamically and then execute it (look at comments in code snippet below for more info):
declare
#whereConditions nvarchar(max) = stuff((
-- here we create where conditions as
-- paramCode in (itsValues)
-- or anotherParamCode in (anotherItsValues) etc.
select
'or ' + ParameterCode + ' in (' + [Values] + ')
'
from (
-- here we create output with two columns: parameter code and
-- all values associated with that code separated by comma
select distinct
t.ParameterCode,
stuff((
select
', ''' + [Value] + ''''
from #TreatmentTableVariables
where
ParameterCode in (t.ParameterCode)
FOR XML PATH ('')
), 1, 1, '') as [Values]
from #TreatmentTableVariables t
where ParameterCode in (
select
COLUMN_name
from INFORMATION_SCHEMA.columns
where
table_name = 'Treatment'
and table_schema ='AnalyticsDW'
)
) conditions
FOR XML PATH ('') -- !!! this one
), 1, 3, '')
declare
#selectQuery nvarchar(max) = N'
select
*
from AnalyticsDW.Treatment
where
' + #whereConditions
print #selectQuery
exec sp_executesql #selectQuery
I have a dynamic single row Table like:
PersonId|FirstName|LastName|Address|PhoneNumber
-----------------------------------------------
1 Anuj Tamrakar NY +525418
I want to pivot this table and want an output in temp table like:
PersonalDetails|Value
----------------------
PersonId 1
FirstName Anuj
LastName Tamrakar
Address NY
PhoneNumber +525418
The first Table is a dynamic single row temp table. For this example, I have 5 columns. I may have more or less columns depending on my criteria
You actually want to UNPIVOT:
SELECT PersonalDetails, Value
FROM
(SELECT CAST([PersonId] AS VARCHAR(MAX)) AS [PersonId],
CAST([FirstName] AS VARCHAR(MAX)) AS [FirstName],
CAST([LastName] AS VARCHAR(MAX)) AS [LastName],
CAST([Address] AS VARCHAR(MAX)) AS [Address],
CAST([PhoneNumber] AS VARCHAR(MAX)) AS [PhoneNumber]
FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN
([PersonId], [FirstName], [LastName], [Address], [PhoneNumber])
) AS unpvt;
All 'to-be-unpivoted' fields have to be of the same type, hence the use of CAST.
Demo here
For a dynamic number of columns you have to use dynamic sql:
DECLARE #cols VARCHAR(MAX) = ''
DECLARE #cast_cols VARCHAR(MAX) = ''
DECLARE #qry VARCHAR(MAX)
SELECT #cols = #cols + ',[' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SELECT #cast_cols = #cast_cols + ',CAST([' + COLUMN_NAME + '] AS VARCHAR(MAX)) AS [' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SET #cols = STUFF(#cols, 1, 1, '')
SET #cast_cols = STUFF(#cast_cols, 1, 1, '')
SET #qry = 'SELECT PersonalDetails, Value FROM ('
+ #cast_cols +
'FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN (' + #cols + ')
) AS unpvt'
EXEC (#qry)
If you really have a single row in the original table, then you can use a series of UNION operations to get your output:
SELECT 'PersonId' AS PersonalDetails, PersonId AS Value
FROM yourTable
UNION ALL
SELECT 'FirstName' AS PersonalDetails, FirstName AS Value
FROM yourTable
UNION ALL
SELECT 'LastName' AS PersonalDetails, LastName AS Value
FROM yourTable
UNION ALL
SELECT 'Address' AS PersonalDetails, Address AS Value
FROM yourTable
UNION ALL
SELECT 'PhoneNumber' AS PersonalDetails, PhoneNumber AS Value
FROM yourTable
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.yourTableName')
This gives you your column names. You simply insert the column names in your new table and use ``, insert into temp(PersonalDetails, Value) values(column1,select column1 from SingleRowTable
I have the following table:
CREATE TABLE TEMP (ID INT, SEGMENT CHAR(1), SEGOFF INT, CHECKED SMALLDATETIME)
INSERT INTO TEMP VALUES (1,'A',0,'2009-05-01')
INSERT INTO TEMP VALUES (2,'B',1,'2009-05-01')
INSERT INTO TEMP VALUES (3,'C',0,'2009-05-01')
INSERT INTO TEMP VALUES (4,'A',0,'2009-05-02')
INSERT INTO TEMP VALUES (5,'B',2,'2009-05-02')
INSERT INTO TEMP VALUES (6,'C',1,'2009-05-02')
INSERT INTO TEMP VALUES (7,'A',1,'2009-05-03')
INSERT INTO TEMP VALUES (8,'B',0,'2009-05-03')
INSERT INTO TEMP VALUES (9,'C',2,'2009-05-03')
I would like to show distinct SEGMENT in Single row separated by comma (e.g: A,B,C)
I try as follows:
DECLARE #SEGMENTList varchar(100)
SELECT #SEGMENTList = COALESCE(#SEGMENTList + ', ', '') +
SEGMENT
FROM TEST
SELECT #SEGMENTList
It shows A, B, C, A, B, C, A, B, C
What do I need to change my query? Thanks all!
You can add a GROUP BY Segment to your select, and it might work.
Like this:
DECLARE #SEGMENTList varchar(100)
SELECT #SEGMENTList = COALESCE(#SEGMENTList + ', ', '') +
SEGMENT
FROM TEMP
GROUP BY SEGMENT
SELECT #SEGMENTList
add a group by clause
group by segment
SELECT #SEGMENTList = COALESCE(#SEGMENTList + ', ', '') +
SEGMENT
FROM
(SELECT DISTINCT Segment FROM #TEMP) AS #Test
Look at this
or
/*
CREATE TABLE [dbo].[TableA](
[id] [int] NULL,
[type] [nvarchar](10) NULL
) ON [PRIMARY]
*/
declare #temp table
(
[type] [nvarchar](10) NULL
)
insert into #temp
select distinct type from TableA
declare #s1 varchar(8000)
update t
set
#s1 = ISNULL(#s1 + ',', '') + '''' + REPLACE(t.Type, '''', '''''') + ''''
from #temp t
select #s1