Creating "Not Exists"/Insert Into Statements - Stumped by nothing (NULL) - sql

I need a script that generate insert statements but with check for if the data doesn't already exist, this because it should be periodically run on parallell systems where different dtata will be added to the systems but we want them tables to be in sync. I have the basic ides and borrowed parts of code but get a syntax error i have trouble solving.
I'm basing my code on the code Param Yadav showed at Converting Select results into Insert script - SQL Server but I need to check for data already in the table. (I need to add more "bells & whistles later, but take this step-by-step)
My own main addition is the #NOT_EXISTS part which should be in the WHERE clause of the NOT EXISTS check. If I replace that with a plain WHERE 0=1 I get no syntax error so it indicates the error is in my #NOT_EXISTS string.
Edit: Yesterday I thought I had an answer to my own question but when running on "real data" I saw that some lines are too long for QUOTENAME, I have to fix those quotation marks "manually" (concats in script) instead...
SET NOCOUNT ON
DECLARE #CSV_COLUMN VARCHAR(MAX),
#QUOTED_DATA VARCHAR(MAX),
#NOT_EXISTS VARCHAR(MAX),
#SQL_KOD VARCHAR(MAX),
#TABLE_NAME VARCHAR(MAX),
#FILTER_CONDITION VARCHAR(MAX)='',
#FIRST_COL INT,
#LAST_COL INT
/* INPUT DATA */
SELECT #TABLE_NAME = 'WorkflowError'
SELECT #FIRST_COL = 2
SELECT #LAST_COL = 4
/* */
SELECT #CSV_COLUMN=STUFF
(
(
SELECT ',['+ NAME +']' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
--SELECT #CSV_COLUMN
SELECT #QUOTED_DATA=STUFF
(
(
SELECT ' ISNULL(QUOTENAME('+NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+')+'','''+'+' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=SUBSTRING(#QUOTED_DATA,1,LEN(#QUOTED_DATA)-5)
SELECT #QUOTED_DATA
SELECT #NOT_EXISTS=STUFF
(
(
SELECT ' ['+ COLUMN_NAME +']=', 'ISNULL(QUOTENAME('+COLUMN_NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+') AND '
FROM information_schema.columns
WHERE table_name = #TABLE_NAME AND
ordinal_position BETWEEN #FIRST_COL AND #LAST_COL
FOR XML PATH('')
),1,1,''
)
SELECT #NOT_EXISTS=SUBSTRING(#NOT_EXISTS,1,LEN(#NOT_EXISTS)-4)
SELECT #NOT_EXISTS
--SELECT #NOT_EXISTS=' 0=1 '
SELECT #SQL_KOD='SELECT ''
IF NOT EXISTS(SELECT 1
FROM ' + #TABLE_NAME + ' WHERE ' + #NOT_EXISTS + ')
BEGIN
INSERT INTO '+#TABLE_NAME+'('+#CSV_COLUMN+')
VALUES('''+'+'+#QUOTED_DATA+'+'+''')
END
GO '''+' Insert_Scripts
FROM '+#TABLE_NAME + #FILTER_CONDITION
SELECT #SQL_KOD
EXECUTE (#SQL_KOD)
GO
[stackoverflow won't let me post code unless it's formatted, but then the strings below won't be as they are created in the script...]
When I do SELECT #NOT_EXISTS=' 0=1 ' I get an INSERT line for each row in my table:
IF NOT EXISTS(SELECT 1 FROM WorkflowError WHERE 0=1 )
BEGIN
INSERT INTO WorkflowError([TargetSystem],[ErrorCode],[ErrorText],[RetryMaxCount],[RetryStrategyName],[ErrorDescription])
VALUES('EttLiv','800','Value cannot be null. Parameter name: source','0',NULL,'Value cannot be null. Parameter name: source')
END
GO
With my #NOT_EXISTS code the #SQL_KOD string becomes this:
SELECT 'IF NOT EXISTS(SELECT 1 FROM WorkflowError
WHERE [TargetSystem]=ISNULL(QUOTENAME(TargetSystem,''''),'NULL'))
BEGIN
INSERT INTO WorkflowError([TargetSystem],[ErrorCode],[ErrorText],[RetryMaxCount],[RetryStrategyName],[ErrorDescription])
VALUES('+ISNULL(QUOTENAME(TargetSystem,''''),'NULL')+','
+ ISNULL(QUOTENAME(ErrorCode,''''),'NULL')+','
+ ISNULL(QUOTENAME(ErrorText,''''),'NULL')+','
+ ISNULL(QUOTENAME(RetryMaxCount,''''),'NULL')+','
+ ISNULL(QUOTENAME(RetryStrategyName,''''),'NULL')+','
+ ISNULL(QUOTENAME(ErrorDescription,''''),'NULL')+')
END
GO ' Insert_Scripts FROM WorkflowError
However, trying to execute that #SQL_KOD line just gives:
Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'NULL'.
...and I can't find out where I have done wrong, if it's in my thinking or if it's just a misplaced quotation mark...

Where do you expect #SQL_KOD to get its values from? Because if you are retrieving your values for TargetSystem / ErrorCode / ... / ErrorDescription from somewhere outside of your insert statement, I would expect a "from" statement. If you want to input variables, you are missing both the definition of the variables and the #-sign in front of the variable name.
As far as keeping quotes happy: try writing your code with QUOTED_IDENTIFIER OFF - you can create the entire #SQL_KOD variable by writing between double quotes ("), and single quotes would behave like normal quotation marks.
A very basic re-write of your code could be something as follows:
SET QUOTED_IDENTIFIER OFF
DECLARE #SQL_KOD VARCHAR(MAX)
SET #SQL_KOD =
"DECLARE #WorkFlowError TABLE ([TargetSystem] NVARCHAR(200),[ErrorCode] NVARCHAR(200))
IF NOT EXISTS ( SELECT 1 FROM #WorkFlowError )
BEGIN
INSERT INTO #WorkFlowError ([TargetSystem],[ErrorCode])
SELECT ISNULL(QUOTENAME([TargetSystem],''''),'NULL')
, ISNULL(QUOTENAME([ErrorCode],''''),'NULL')
FROM (
SELECT [TargetSystem]='Foo'
, [ErrorCode]='Bar'
) src
END";

I originally used QUOTENAME as in the Param Yadav script I borrowed from but that function can't handle long strings. It doesn't complain, just returns NULL if the string is too long. Now the script is less readable (long lines of quotation marks) but now works.
SET NOCOUNT ON
DECLARE #CSV_COLUMN VARCHAR(MAX),
#QUOTED_DATA VARCHAR(MAX),
#NOT_EXISTS VARCHAR(MAX),
#SQL_KOD VARCHAR(MAX),
#TABLE_NAME VARCHAR(MAX),
#FILTER_CONDITION VARCHAR(MAX),
#FIRST_COL INT,
#LAST_COL INT
/* INPUT DATA */
SELECT #TABLE_NAME = 'WorkflowError'
SELECT #FIRST_COL = 2
SELECT #LAST_COL = 4
SELECT #FILTER_CONDITION = ''
/* */
SELECT #CSV_COLUMN=STUFF
(
(
SELECT ',['+ NAME +']' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=STUFF
(
(
SELECT ' ISNULL('''''''' + REPLACE('+NAME+','''''''','''''''''''') + '''''''','''+'NULL'''+''+')+'',''+'
FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=SUBSTRING(#QUOTED_DATA,1,LEN(#QUOTED_DATA)-5)
SELECT #NOT_EXISTS=STUFF
(
(
SELECT ' ['+ COLUMN_NAME +']='' + ', 'ISNULL('''''''' + REPLACE('+COLUMN_NAME+','''''''','''''''''''') + '''''''','''+'NULL'''+''+')+'' AND '
FROM information_schema.columns
WHERE table_name = #TABLE_NAME AND
ordinal_position BETWEEN #FIRST_COL AND #LAST_COL
FOR XML PATH('')
),1,1,''
)
SELECT #NOT_EXISTS=SUBSTRING(#NOT_EXISTS,1,LEN(#NOT_EXISTS)-6)
SELECT #SQL_KOD='SELECT ''IF NOT EXISTS(SELECT 1 FROM ' + #TABLE_NAME + ' WHERE ' + #NOT_EXISTS + ' + ' + ''') BEGIN INSERT INTO '+#TABLE_NAME+'('+#CSV_COLUMN+')VALUES('''+'+'+#QUOTED_DATA+'+'+''') END '''+' Insert_Scripts FROM ' + #TABLE_NAME + ' ' + #FILTER_CONDITION
EXECUTE (#SQL_KOD)
SET NOCOUNT OFF

Related

how to find all strings in between commas in sql server

I want to display a string in a table format as shown below:
For a string like 'hi,is,1,question,thanks,.,.,n'
I need this result:
column1 column2 column3 column4 ..... column
hi is 1 question ..... n
DECLARE #string VARCHAR(MAX);
SET #string = 'hi,is,1,question,thanks,.,.,n';
DECLARE #SQL VARCHAR(MAX);
SET #SQL = 'SELECT ''' + REPLACE(#string, ',', ''',''') + '''';
EXEC (#SQL);
Result:
Add SELECT ' at beginning and ' at the end of string
Replace all , with ',' inside string
So string 'hi,is,1,question,thanks,.,.,n' is replace by 'SELECT 'hi','is','1','question','thanks','.','.','n''
Executed as SQL query
PS: If you want to use it on column you will have to combine it with CURSOR
Update
DECLARE #table TABLE
(
ID INT IDENTITY,
string VARCHAR(MAX)
);
INSERT INTO #table
VALUES
('This,is,a,string,,n,elements,..');
INSERT INTO #table
VALUES
('And,one,more');
INSERT INTO #table
VALUES
('Ugly,but,works,,,Yay!,..,,,10,11,12,13,14,15,16,17,18,19,..');
SELECT * FROM #table
DECLARE #string_to_split VARCHAR(MAX);
DECLARE #sql_query_to_execute VARCHAR(MAX);
DECLARE #max_elements INT, #id INT, #i INT;
SET #i = 1;
DECLARE string_cursor CURSOR FOR SELECT ID, string FROM #table;
SELECT #max_elements = MAX(LEN(string) - LEN(REPLACE(string, ',', ''))) + 1 -- Find max number of elements */
FROM #table;
IF OBJECT_ID('tempdb..##my_temp_table_for_splitted_columns') <> 0 -- Create new temp table with valid amount of columns
DROP TABLE ##my_temp_table_for_splited_columns;
SET #sql_query_to_execute = 'create table ##my_temp_table_for_splitted_columns ( ID int,';
WHILE #i <= #max_elements
BEGIN
SET #sql_query_to_execute = #sql_query_to_execute + ' Col' + CAST(#i AS VARCHAR(max)) + ' varchar(25), ';
SET #i = #i + 1;
END;
SELECT #sql_query_to_execute = SUBSTRING(#sql_query_to_execute, 1, LEN(#sql_query_to_execute) - 1) + ')';
EXEC (#sql_query_to_execute);
/* Split string for each row */
OPEN string_cursor;
FETCH NEXT FROM string_cursor
INTO #id,
#string_to_split
WHILE ##FETCH_STATUS = 0
BEGIN
SET #i = MAX(LEN(#string_to_split) - LEN(REPLACE(#string_to_split, ',', ''))) + 1; -- check amount of columns for current string
WHILE #i < #max_elements
BEGIN
SET #string_to_split = #string_to_split + ','; -- add missing columns
SET #i = #i + 1;
END;
SET #sql_query_to_execute = 'SELECT ' + CAST(#id AS VARCHAR(MAX)) + ',''' + REPLACE(#string_to_split, ',', ''',''') + '''';
INSERT INTO ##my_temp_table_for_splitted_columns --insert result to temp table
EXEC (#sql_query_to_execute);
FETCH NEXT FROM string_cursor
INTO #id,
#string_to_split;
END;
CLOSE string_cursor;
DEALLOCATE string_cursor;
SELECT *
FROM ##my_temp_table_for_splitted_columns;
This is not trivial. You will find a lot of examples how to split your string in a set of fragments. And you will find a lot of examples how to pivot a row set to a single row. But - adding quite some difficulty - you have an unknown count of columns. There are three approaches:
Split this and return your set with a known maximum of columns
Use a dynamically created statement and use EXEC. But this will not work in VIEWs or iTVFs, nor will it work against a table.
Instead of a column list you return a generic container like XML
with a known maximum of columns
One example for the first was this
DECLARE #str VARCHAR(1000)='This,is,a,string,with,n,elements,...';
SELECT p.*
FROM
(
SELECT A.[value]
,CONCAT('Column',A.[key]+1) AS ColumnName
FROM OPENJSON('["' + REPLACE(#str,',','","') + '"]') A
) t
PIVOT
(
MAX(t.[value]) FOR ColumnName IN(Column1,Column2,Column3,Column4,Column5,Column6,Column7,Column8,Column9 /*add as many as you need*/)
) p
Hint: My approach to split the string uses OPENJSON, not available before version 2016. But there are many other approaches you'll find easily. It's just an example to show you the combination of a splitter with PIVOT using a running index to build up a column name.
Unknown count of columns
And the same example with a dynamically created column list was this:
DECLARE #str VARCHAR(1000)='This,is,a,string,with,n,elements,...';
DECLARE #CountElements INT=LEN(#str)-LEN(REPLACE(#str,',',''))+1;
DECLARE #columnList NVARCHAR(MAX)=
STUFF((
SELECT TOP(#CountElements)
CONCAT(',Column',ROW_NUMBER() OVER(ORDER BY (SELECT 1)))
FROM master..spt_values /*has a lot of rows*/
FOR XML PATH('')
),1,1,'');
DECLARE #Command NVARCHAR(MAX)=
N'SELECT p.*
FROM
(
SELECT A.[value]
,CONCAT(''Column'',A.[key]+1) AS ColumnName
FROM OPENJSON(''["'' + REPLACE(''' + #str + ''','','',''","'') + ''"]'') A
) t
PIVOT
(
MAX(t.[value]) FOR ColumnName IN(' + #columnList + ')
) p;';
EXEC(#Command);
Hint: The statement created is exactly the same as above. But the column list in the pivot's IN is created dynamically. This will work with (almost) any count of words generically.
If you need more help, please use the edit option of your question and provide some more details.
An inlineable approach for a table returning a generic container
If you need this against a table, you might try something along this:
DECLARE #tbl TABLE(ID INT IDENTITY,YourList NVARCHAR(MAX));
INSERT INTO #tbl VALUES('This,is,a,string,with,n,elements,...')
,('And,one,more');
SELECT *
,CAST('<x>' + REPLACE((SELECT t.YourList AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML) AS Splitted
FROM #tbl t
This will return your list as an XML like
<x>This</x>
<x>is</x>
<x>a</x>
<x>string</x>
<x>with</x>
<x>n</x>
<x>elements</x>
<x>...</x>
You can grab - if needed - each element by its index like here
TheXml.value('/x[1]','nvarchar(max)') AS Element1

Error with Dynamic SQL statement cutting off with exec command

I am attempting to pivot a column with 400 or so unique values with the following code:
Declare #t VARCHAR(10)
Declare #A VARCHAR(1000)
Declare #B VARCHAR(1000)
set #A='SELECT Name, IRIS_ID__c'
SET #B='('
SELECT #A=#A+',['+Question_Concept_With_ImpactArea__c+'] as ['+Question_Concept_With_ImpactArea__c+']',#B=#B+'['+Question_Concept_With_ImpactArea__c+']'
FROM (SELECT DISTINCT Question_Concept_With_ImpactArea__c
FROM Company_Number_Response) cur
-- removing last ',' from both variables
SET #B=SUBSTRING(#B,1,LEN(#B)-1)
SET #A=#A+ + '
FROM
(SELECT NAME, IRIS_ID__c, Selected, Question_Concept_With_ImpactArea__c
FROM Company_Number_Response) s PIVOT (max(Unified_Response__c)
FOR Question_Concept_With_ImpactArea__c IN ' +#B+')) p ORDER BY [IRIS_ID__c];'
exec(#A);
Running this code throws an error that "Unclosed quotation mark after the character string 'CM_PcCOGSSup'
Incorrect Syntax near 'CM_PcCOGSSup'
When I change the last command from exec to print I can see that many of the values are being read, but the statement simply cuts off at the value in the above error. I checked the data and do not see any characters that would be causing this. Additionally, I thought the result might be too long and changed the max number for results to text to 8192.
Any help would be greatly appreciated.
Assuming you're using SQL Server 2005 or up, change your variable declarations to varchar(max). It's cutting off because you've only supplied varchar(1000), and string concatenation does not automatically lengthen char data types--they get truncated.
In SQL 2000 you can only use varchar(8000). If you need longer than that you will have to get creative--a pretty difficult task.
You also have SET #A=#A+ + '. If that's working, it's a surprise to me, but in any case there should only be one + there.
And, you should not just put square brackets around columns to make them a valid sysname data type. You should use the QuoteName function:
SELECT #A = #A + ',' + QuoteName(Question_Concept_With_ImpactArea__c) ...
Try this one -
DECLARE #Columns VARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
SELECT #Columns = STUFF((
SELECT DISTINCT ', ['+ Question_Concept_With_ImpactArea__c + ']'
FROM dbo.Company_Number_Response
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
SELECT #SQL = 'SELECT Name, IRIS_ID__c, ' + #Columns + '
FROM
(
SELECT NAME, IRIS_ID__c, Selected, Question_Concept_With_ImpactArea__c
FROM Company_Number_Response
) s
PIVOT (
max(Unified_Response__c)
FOR Question_Concept_With_ImpactArea__c IN (' + #Columns + ')
) p
ORDER BY [IRIS_ID__c];'
EXEC sys.sp_executesql #SQL

Improve SQL Server query to convert arbitrary table to JSON

After a lot of searching and piecing together the very excellent techniques for converting result sets using the FOR XML and .nodes() commands that are around the web, I was able to create this single query (not a stored procedure) which does a reasonably good job of converting any arbitrary SQL query to a JSON array.
The query will encode each data row as a single JSON object with a leading comma.
The data rows are wrapped by brackets and the whole result set is then expected to be exported to a file.
I'd like to see if anyone out there can see ways to improve its performance?
Here's the query with a sample table:
declare #xd table (col1 varchar(max), col2 int, col3 real, colNull int)
insert into #xd
select '', null, null, null
UNION ALL select 'ItemA', 123, 123.123, null
UNION ALL select 'ItemB', 456, 456.456, null
UNION ALL select '7890', 789, 789.789, null
select '[{}'
UNION ALL
select ',{' + STUFF((
(select ','
+ '"' + r.value('local-name(.)', 'varchar(max)') + '":'
+ case when r.value('./#xsi:nil', 'varchar(max)') = 'true' then 'null'
when isnumeric(r.value('.', 'varchar(max)')) = 1
then r.value('.', 'varchar(max)')
else '"' + r.value('.', 'varchar(max)') + '"'
end
from rows.nodes('/row/*') as x(r) for xml path(''))
), 1, 1, '') + '}'
from (
-- Arbitrary query goes here, (fields go where t.* is, table where #xd t is)
select (select t.* for xml raw,type,elements XSINIL) rows
from #xd t
) xd
UNION ALL
select ']'
My biggest critique of it, is that it's insanely slow.
It currently takes about 3:30 for ~42,000 rows.
My other big critique is that it currently assumes that everything that looks like a number is a number. It doesn't try to discover column type in the least (and I'm not even sure if it can).
A final minor critique is that the first data row will have a comma up front and technically it shouldn't. To compensate for that it requires that empty JSON object in the first row that starts the JSON array.
Other critiques (preferably with solutions) invited, the only real limitation I have is that the solution be decently repeatable on many arbitrary SQL queries without having to explicitly identify the column names.
I'm using SQL Server 2012.
Thanks and to anyone else like me who was looking for a generalized SQL Results -> JSON Array converter, ENJOY!
I say if you really want to kick up performance, use metaprogramming. The example below tries this with 40,000 rows and returns results in less than a second (not counting inserting the initial 40k rows, which in this example only takes about 2 seconds). It also takes into account your data types to not enclose numbers in quotes.
declare #xd table (col1 varchar(max), col2 int, col3 real, colDate datetime, colNull int);
declare #i int = 0;
while #i < 10000 begin
set #i += 1;
insert into #xd
select '', null, null, null, null
union all select 'ItemA', 123, 123.123, getDate(), null
union all select 'ItemB', 456, 456.456, getDate(), null
union all select '7890', 789, 789.789, getDate(), null;
end;
select *
into #json_base
from (
-- Insert SQL Statement here
select * from #xd
) t;
declare #columns table (
id int identity primary key,
name sysname,
datatype sysname,
is_number bit,
is_date bit);
insert into #columns(name, datatype, is_number, is_date)
select columns.name, types.name,
case when number_types.name is not NULL
then 1 else 0
end as is_number,
case when date_types.name is not NULL
then 1 else 0
end as is_date
from tempdb.sys.columns
join tempdb.sys.types
on (columns.system_type_id = types.system_type_id)
left join (values ('int'), ('real'), ('numeric'),
('decimal'), ('bigint'), ('tinyint')) as number_types(name)
on (types.name = number_types.name)
left join (values ('date'), ('datetime'), ('datetime2'),
('smalldatetime'), ('time'), ('datetimeoffset')) as date_types(name)
on (types.name = date_types.name)
where object_id = OBJECT_ID('tempdb..#json_base');
declare #field_list varchar(max) = STUFF((
select '+'',''+' + QUOTENAME(QUOTENAME(name, '"') + ':', '''')
+ '+' + case when is_number = 1
then 'COALESCE(LTRIM('
+ QUOTENAME(name) + '),''null'')'
when is_date = 1
then 'COALESCE(QUOTENAME(LTRIM(convert(varchar(max), '
+ QUOTENAME(name) + ', 126)),''"''),''null'')'
else 'COALESCE(QUOTENAME('
+ QUOTENAME(name) + ',''"''),''null'')'
end
from #columns
for xml path('')),
1, 5, '');
create table #json_result (
id int identity primary key,
line varchar(max));
declare #sql varchar(max) = REPLACE(
'insert into #json_result '
+ 'select '',{''+{f}+''}'' '
+ 'from #json_base', '{f}', #field_list);
exec(#sql);
update #json_result
set line = STUFF(line, 1, 1, '')
where id = 1;
select '['
UNION ALL
select line
from #json_result
UNION ALL
select ']';
drop table #json_base;
drop table #json_result;
From Firoz Ansari:
CREATE PROCEDURE [dbo].[GetJSON] (
#ParameterSQL AS VARCHAR(MAX)
)
AS
BEGIN
DECLARE #SQL NVARCHAR(MAX)
DECLARE #XMLString VARCHAR(MAX)
DECLARE #XML XML
DECLARE #Paramlist NVARCHAR(1000)
SET #Paramlist = N'#XML XML OUTPUT'
SET #SQL = 'WITH PrepareTable (XMLString) '
SET #SQL = #SQL + 'AS ( '
SET #SQL = #SQL + #ParameterSQL+ ' FOR XML RAW, TYPE, ELEMENTS '
SET #SQL = #SQL + ') '
SET #SQL = #SQL + 'SELECT #XML = XMLString FROM PrepareTable '
EXEC sp_executesql #SQL, #Paramlist, #XML=#XML OUTPUT
SET #XMLString = CAST(#XML AS VARCHAR(MAX))
DECLARE #JSON VARCHAR(MAX)
DECLARE #Row VARCHAR(MAX)
DECLARE #RowStart INT
DECLARE #RowEnd INT
DECLARE #FieldStart INT
DECLARE #FieldEnd INT
DECLARE #Key VARCHAR(MAX)
DECLARE #Value VARCHAR(MAX)
DECLARE #StartRoot VARCHAR(100); SET #StartRoot = ''
DECLARE #EndRoot VARCHAR(100); SET #EndRoot = ''
DECLARE #StartField VARCHAR(100); SET #StartField = ''
SET #RowStart = CharIndex(#StartRoot, #XMLString, 0)
SET #JSON = ''
WHILE #RowStart > 0
BEGIN
SET #RowStart = #RowStart+Len(#StartRoot)
SET #RowEnd = CharIndex(#EndRoot, #XMLString, #RowStart)
SET #Row = SubString(#XMLString, #RowStart, #RowEnd-#RowStart)
SET #JSON = #JSON+'{'
-- for each row
SET #FieldStart = CharIndex(#StartField, #Row, 0)
WHILE #FieldStart > 0
BEGIN
-- parse node key
SET #FieldStart = #FieldStart+Len(#StartField)
SET #FieldEnd = CharIndex(#EndField, #Row, #FieldStart)
SET #Key = SubString(#Row, #FieldStart, #FieldEnd-#FieldStart)
SET #JSON = #JSON+'"'+#Key+'":'
-- parse node value
SET #FieldStart = #FieldEnd+1
SET #FieldEnd = CharIndex('0 SET #JSON = SubString(#JSON, 0, LEN(#JSON))
SET #JSON = #JSON+'},'
--/ for each row
SET #RowStart = CharIndex(#StartRoot, #XMLString, #RowEnd)
END
IF LEN(#JSON) > 0 SET #JSON = SubString(#JSON, 0, LEN(#JSON))
SET #JSON = '[' + #JSON + ']'
SELECT #JSON
END

SQL create xml of Parameters dynamically

Is there a way to query the parameters passed into a stored procedure and return them as XML without creating a string of the parameters and then casting that as xml? I'm looking for something generic, that will work for most SPs without having to physicially code it each time?
I have a bunch of stored procedures that access and modify verify specific information. At the end of the SPs I want to insert into a logging table the name of the SP, and the parameters (in xml) that were used to invoke the SP. I know how to get the name of the SP, and I know how to get a list of the parameters for the SP. What I want is a way to mash it all into XML along the actual values of the parameters that were passed.
I'm looking for something that does this, without the manual coding of each parameter:
DECLARE #L_Data varchar(1500)
SET #L_Data = '<parms>' +
CASE WHEN #ParamRegStationID IS NULL THEN ''
ELSE ',#ParamRegStationID=''' + Convert(varchar, #ParamRegStationID) + '''' END +
CASE WHEN #ParamScheduleID IS NULL THEN ''
ELSE ',#ParamScheduleID=''' + Convert(varchar, #ParamScheduleID) + '''' END +
CASE WHEN #ParamPatientID IS NULL THEN ''
ELSE ',#ParamPatientID=''' + Convert(varchar, #ParamPatientID) + '''' END +
CASE WHEN #ParamHISPatientID IS NULL THEN ''
ELSE ',#ParamHISPatientID=''' + #ParamHISPatientID + '''' END +
CASE WHEN #ParamEvent IS NULL THEN ''
ELSE ',#ParamEvent=''' + #ParamEvent + '''' END +
'</parms>'
This doesn't work, and it isn't as elegant as what I'm hoping for. However, here is an example illustrating what I'm trying to ultimately get to. It creates the temp table, but doesn't add the parameters to it as columns, so I can later extract it as XML.
ALTER PROC uspTest
#ParamID as bigint=null,
#ParamXYZ as varchar(255)=null
as
-- PROC Does whatever it is going to do ....
DECLARE #ProcName varchar(128), #ParmName varchar(128), #ParmType varchar(128), #ParmLen int,
#ParmSQL varchar(1000)
select #ProcName=OBJECT_NAME(##PROCID)
--select * from INFORMATION_SCHEMA.ROUTINES where ROUTINE_TYPE='PROCEDURE' and ROUTINE_NAME=#ProcName
DECLARE csrParms CURSOR
FOR
select PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME=#ProcName and PARAMETER_MODE='IN'
ORDER BY ORDINAL_POSITION
FOR READ ONLY
OPEN csrParms
FETCH NEXT FROM csrParms
INTO #ParmName, #ParmType, #ParmLen
CREATE TABLE #Parms(ID int identity(1,1), Created DateTime)
INSERT INTO #Parms select GETDATE()
WHILE ##FETCH_STATUS = 0
BEGIN
-- GET Parm value and format as xml attribute to save parm
SET #ParmSQL = 'ALTER TABLE #Parms add ' + #ParmName + ' varchar(' + CAST(ISNULL(#ParmLen, 128) as varchar(128)) + ') NULL '
print #ParmSQL
EXEC (#ParmSQL)
SET #ParmSQL = 'UPDATE #Parms SET ' + #ParmName + ' = ''????'''
print #ParmSQL
--EXEC (#ParmSQL)
FETCH NEXT FROM csrParms
INTO #ParmName, #ParmType, #ParmLen
END
SET #ParmSQL = CAST((select * from #Parms FOR XML RAW) as varchar(1000))
select #ParmSQL
CLOSE csrParms
DEALLOCATE csrParms
This is close to what I'm looking for, I need to know how to replace the ??? with the current value of the parameter dynamically though.
ALTER PROC uspTest
#ParamID as bigint=null,
#ParamXYZ as varchar(255)=null
as
-- PROC Does whatever it is going to do ....
DECLARE #ProcName varchar(128), #ParmName varchar(128), #ParmType varchar(128), #ParmLen int,
#ParmSQL varchar(1000)
select #ProcName=OBJECT_NAME(##PROCID)
--select * from INFORMATION_SCHEMA.ROUTINES where ROUTINE_TYPE='PROCEDURE' and ROUTINE_NAME=#ProcName
set #ParmSQL =
' CREATE TABLE #Parms(ID int identity(1,1), Created DateTime, ' +
STUFF((select (', ' + REPLACE(PARAMETER_NAME,'#','') + ' varchar(' + CAST(ISNULL(CHARACTER_MAXIMUM_LENGTH, 128) as varchar(128)) + ') NULL ')
from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME='uspTest' and PARAMETER_MODE='IN'
order by ORDINAL_POSITION for XML path(''), type).value('.', 'varchar(max)'), 1, 2, '')
+ ');
' + 'INSERT INTO #Parms (Created) select GETDATE(); ' + STUFF((select (';
UPDATE #Parms SET ' + REPLACE(PARAMETER_NAME,'#','') + ' = ''???''')
from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME='uspTest' and PARAMETER_MODE='IN'
order by ORDINAL_POSITION for XML path(''), type).value('.', 'varchar(max)'), 1, 2, '')
+ ';
select CAST((select * from #Parms FOR XML RAW) as varchar(1000));'
print #ParmSQL
EXEC (#ParmSQL)
When I execute the proc as:
EXEC uspTest 1, 'test'
Returns:
<row ID="1" Created="2012-04-20T09:44:43.700" ParamID="???" ParamXYZ="???"/>
Prints out:
CREATE TABLE #Parms(ID int identity(1,1), Created DateTime, ParamID varchar(128) NULL , ParamXYZ varchar(255) NULL );
INSERT INTO #Parms (Created) select GETDATE();
UPDATE #Parms SET ParamID = '???';
UPDATE #Parms SET ParamXYZ = '???';
select CAST((select * from #Parms FOR XML RAW) as varchar(1000));
Is this SQL Server 2000 or later? If so you could use the FOR XML clause:
DECLARE #p1 varchar(100) = 'blah'
, #p2 int = 1
, #p3 datetime2(7) = '2011-01-01 13:41'
;
SELECT #p1 StringParm
, #p2 IntParm
, #p3 DateParm
FOR XML RAW
returns:
<row StringParm="blah" IntParm="1" DateParm="2011-01-01T13:41:00"/>
Edit
Ah, the problem there is that you need to parse out the parameter list as well as the values (which are local) into dynamic SQL (where they'd be out of scope).
I suppose you could use INFORMATION_SCHEMA.PARAMETERS to dynamically list the parameters and dbcc_inputbuffers to get the actual values passed. Something like:
create procedure junk
( #int INT
, #string VARCHAR(20)
, #date DATE
)
AS
BEGIN
DECLARE #tmp TABLE
( EventType NVARCHAR(30)
, PARMS INT
, Info NVARCHAR(2000)
);
DECLARE #object NVARCHAR(200);
INSERT INTO #tmp
EXEC('DBCC INPUTBUFFER(##SPID) WITH NO_INFOMSGS');
SELECT INFO
, 'Call' lType
FROM #tmp
UNION
SELECT STUFF(
( SELECT ', ' + parameter_name
FROM INFORMATION_SCHEMA.PARAMETERS
WHERE SPECIFIC_NAME = OBJECT_NAME(##procid)
ORDER BY ORDINAL_POSITION
FOR XML PATH('')
)
, 1
, 2
, ''
)
, 'Parms';
END
That now makes it so that:
exec dbo.junk #int = 3, #string = 'hoo', #date = '2/2/2002';
Returns:
exec dbo.junk #int = 3, #string = 'hoo', #date = '2/2/2002'; Call
#int, #string, #date Parms
Which should get you a ways along. The tricky bit is that DBCC_INPUTBUFFERS returns the EXACT call string. So you'd need to write code to parse out the call to match the input line to the parameter list. If you go that route, you'll likely want a stored function that does the parsing. It would likely take the call string and parameter list something like the return values above, match them, and use the FOR XML clause to return the format you want.
You could also parse call string in a cursor tied to the parameter list. Then you'd pull the parameters in order and look for the commas and #'s. You could still have trouble with parameter values that included those characters if you didn't take that into account.
IMHO, getting that squared away seems like a lot of work compared to a simple select which can almost be copied/pasted from the function header. Of course, if you're talking about a large volume of procedures then it might be worth it. Either way, good luck and thanks for a thought-provoking question.

Converting Select results into Insert script - SQL Server

I have SQL Server 2008, SQL Server Management Studio.
I need to select data from a table in one database and insert into another table in another database.
How can I convert the returned results from my select into INSERT INTO ...?
Clarification from comments: While I believe this could be solved by a INSERT INTO SELECT or SELECT INTO, I do need to generate INSERT INTO ....
Here is another method, which may be easier than installing plugins or external tools in some situations:
Do a select [whatever you need]INTO temp.table_namefrom [... etc ...].
Right-click on the database in the Object Explorer => Tasks => Generate Scripts
Select temp.table_name in the "Choose Objects" screen, click Next.
In the "Specify how scripts should be saved" screen:
Click Advanced, find the "Types of data to Script" property, select "Data only", close the advanced properties.
Select "Save to new query window" (unless you have thousands of records).
Click Next, wait for the job to complete, observe the resulting INSERT statements appear in a new query window.
Use Find & Replace to change all [temp.table_name] to [your_table_name].
drop table [temp.table_name].
In SSMS:
Right click on the database > Tasks > Generate Scripts
Next
Select "Select specific database objects" and check the table you want scripted, Next
Click Advanced > in the list of options, scroll down to the bottom and look for the "Types of data to script" and change it to "Data Only" > OK
Select "Save to new query window" > Next > Next > Finish
All 180 rows now written as 180 insert statements!
Native method:
for example if you have table
Users(Id, name)
You can do this:
select 'insert into Table values(Id=' + Id + ', name=' + name + ')' from Users
1- Explanation of Scripts
A)Syntax for inserting data in table is as below
Insert into table(col1,col2,col3,col4,col5)
-- To achieve this part i
--have used below variable
------#CSV_COLUMN-------
values(Col1 data in quote, Col2..quote,..Col5..quote)
-- To achieve this part
-- i.e column data in
--quote i have used
--below variable
----#QUOTED_DATA---
C)To get above data from existing
table we have to write the select
query in such way that the output
will be in form of as above scripts
D)Then Finally i have Concatenated
above variable to create
final script that's will
generate insert script on execution
E)
#TEXT='SELECT ''INSERT INTO
'+#TABLE_NAME+'('+#CSV_COLUMN+')VALUES('''+'+'+SUBSTRING(#QUOTED_DATA,1,LEN(#QUOTED_DATA)-5)+'+'+''')'''+' Insert_Scripts FROM '+#TABLE_NAME + #FILTER_CONDITION
F)And Finally Executed the above query EXECUTE(TEXT)
G)QUOTENAME() function is used to wrap
column data inside quote
H)ISNULL is used because if any row has NULL
data for any column the query fails
and return NULL thats why to avoid
that i have used ISNULL
I)And created the sp sp_generate_insertscripts
for same
1- Just put the table name for which you want insert script
2- Filter condition if you want specific results
----------Final Procedure To generate Script------
CREATE PROCEDURE sp_generate_insertscripts
(
#TABLE_NAME VARCHAR(MAX),
#FILTER_CONDITION VARCHAR(MAX)=''
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #CSV_COLUMN VARCHAR(MAX),
#QUOTED_DATA VARCHAR(MAX),
#TEXT VARCHAR(MAX)
SELECT #CSV_COLUMN=STUFF
(
(
SELECT ',['+ NAME +']' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #QUOTED_DATA=STUFF
(
(
SELECT ' ISNULL(QUOTENAME('+NAME+','+QUOTENAME('''','''''')+'),'+'''NULL'''+')+'','''+'+' FROM sys.all_columns
WHERE OBJECT_ID=OBJECT_ID(#TABLE_NAME) AND
is_identity!=1 FOR XML PATH('')
),1,1,''
)
SELECT #TEXT='SELECT ''INSERT INTO '+#TABLE_NAME+'('+#CSV_COLUMN+')VALUES('''+'+'+SUBSTRING(#QUOTED_DATA,1,LEN(#QUOTED_DATA)-5)+'+'+''')'''+' Insert_Scripts FROM '+#TABLE_NAME + #FILTER_CONDITION
--SELECT #CSV_COLUMN AS CSV_COLUMN,#QUOTED_DATA AS QUOTED_DATA,#TEXT TEXT
EXECUTE (#TEXT)
SET NOCOUNT OFF
END
SSMS Toolpack (which is FREE as in beer) has a variety of great features - including generating INSERT statements from tables.
Update: for SQL Server Management Studio 2012 (and newer), SSMS Toolpack is no longer free, but requires a modest licensing fee.
It's possible to do via Visual Studio SQL Server Object Explorer.
You can click "View Data" from context menu for necessary table, filter results and save result as script.
Using visual studio, do the following
Create a project of type SQL Server-->SQL Server Database Project
open the sql server explorer CTL-\ , CTL-S
add a SQL Server by right clicking on the SQL SERVER icon. Selcet ADD NEW SERVER
navigate down to the table you are interested in
right click--> VIEW DATA
Click the top left cell to highlight everything (ctl-A doesnt seem to work)
Right Click -->SCript
This is fabulous. I have tried everything listed above over the years. I know there is a tool out there that will do this and much more, cant think of the name of it. But it is very expensive.
Good luck. I just figured this out. Have not tested it extensively w/ text fields etc, but it looks like it gets you a long ways down the road.
Greg
Create a separate table using into statement
For example
Select * into Test_123 from [dbo].[Employee] where Name like '%Test%'
Go to the Database
Right Click the Database
Click on Generate Script
Select your table
Select advanace option and select the Attribute "Data Only"
Select the file "open in new query"
Sql will generate script for you
This is a more versatile solution (that can do a little more than the question asks), and can be used in a query window without having to create a new stored proc - useful in production databases for instance where you don't have write access.
To use the code, please modify according to the in line comments which explain its usage. You can then just run this query in a query window and it will print the INSERT statements you require.
SET NOCOUNT ON
-- Set the ID you wish to filter on here
DECLARE #id AS INT = 123
DECLARE #tables TABLE (Name NVARCHAR(128), IdField NVARCHAR(128), IdInsert BIT, Excluded NVARCHAR(128))
-- Add any tables you wish to generate INSERT statements for here. The fields are as thus:
-- Name: Your table name
-- IdField: The field on which to filter the dataset
-- IdInsert: If the primary key field is to be included in the INSERT statement
-- Excluded: Any fields you do not wish to include in the INSERT statement
INSERT INTO #tables (Name, IdField, IdInsert, Excluded) VALUES ('MyTable1', 'Id', 0, 'Created,Modified')
INSERT INTO #tables (Name, IdField, IdInsert, Excluded) VALUES ('MyTable2', 'Id', 1, 'Created,Modified')
DECLARE #numberTypes TABLE (sysId TINYINT)
-- This will ensure INT and BIT types are not surrounded with quotes in the
-- resultant INSERT statement, but you may need to add more (from sys.types)
INSERT #numberTypes(SysId) VALUES(56),(104)
DECLARE #rows INT = (SELECT COUNT(*) FROM #tables)
DECLARE #cnt INT = 1
DECLARE #results TABLE (Sql NVARCHAR(4000))
WHILE #cnt <= #rows
BEGIN
DECLARE #tablename AS NVARCHAR(128)
DECLARE #idField AS NVARCHAR(128)
DECLARE #idInsert AS BIT
DECLARE #excluded AS NVARCHAR(128)
SELECT
#tablename = Name,
#idField = IdField,
#idInsert = IdInsert,
#excluded = Excluded
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RowId FROM #tables) t WHERE t.RowId = #cnt
DECLARE #excludedFields TABLE (FieldName NVARCHAR(128))
DECLARE #xml AS XML = CAST(('<X>' + REPLACE(#excluded, ',', '</X><X>') + '</X>') AS XML)
INSERT INTO #excludedFields SELECT N.value('.', 'NVARCHAR(128)') FROM #xml.nodes('X') AS T(N)
DECLARE #setIdentity NVARCHAR(128) = 'SET IDENTITY_INSERT ' + #tablename
DECLARE #execsql AS NVARCHAR(4000) = 'SELECT ''' + CASE WHEN #idInsert = 1 THEN #setIdentity + ' ON' + CHAR(13) ELSE '' END + 'INSERT INTO ' + #tablename + ' ('
SELECT #execsql = #execsql +
STUFF
(
(
SELECT CASE WHEN NOT EXISTS(SELECT * FROM #excludedFields WHERE FieldName = name) THEN ', ' + name ELSE '' END
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.' + #tablename)
FOR XML PATH('')
), 1, 2, ''
) +
')' + CHAR(13) + 'VALUES (' +
STUFF
(
(
SELECT
CASE WHEN NOT EXISTS(SELECT * FROM #excludedFields WHERE FieldName = name) THEN
''', '' + ISNULL(' +
CASE WHEN EXISTS(SELECT * FROM #numberTypes WHERE SysId = system_type_id) THEN '' ELSE ''''''''' + ' END +
'CAST(' + name + ' AS VARCHAR)' +
CASE WHEN EXISTS(SELECT * FROM #numberTypes WHERE SysId = system_type_id) THEN '' ELSE ' + ''''''''' END +
', ''NULL'') + '
ELSE ''
END
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.' + #tablename)
FOR XML PATH('')
), 1, 3, ''
) +
''')' + CASE WHEN #idInsert = 1 THEN CHAR(13) + #setIdentity + ' OFF' ELSE '' END +
''' FROM ' + #tablename + ' WHERE ' + #idField + ' = ' + CAST(#id AS VARCHAR)
INSERT #results EXEC (#execsql)
DELETE #excludedFields
SET #cnt = #cnt + 1
END
DECLARE cur CURSOR FOR SELECT Sql FROM #results
OPEN cur
DECLARE #sql NVARCHAR(4000)
FETCH NEXT FROM cur INTO #sql
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #sql
FETCH NEXT FROM cur INTO #sql
END
CLOSE cur
DEALLOCATE cur
You can Choose 'Result to File' option in SSMS and export your select result to file and make your changes in result file and finally using BCP - Bulk copy you can insert in table 1 in database 2.
I think for bulk insert you have to convert .rpt file to .csv file
Hope it will help.
I had a similar problem, but I needed to be able to create an INSERT statement from a query (with filters etc.)
So I created following procedure:
CREATE PROCEDURE dbo.ConvertQueryToInsert (#input NVARCHAR(max), #target NVARCHAR(max)) AS BEGIN
DECLARE #fields NVARCHAR(max);
DECLARE #select NVARCHAR(max);
-- Get the defintion from sys.columns and assemble a string with the fields/transformations for the dynamic query
SELECT
#fields = COALESCE(#fields + ', ', '') + '[' + name +']',
#select = COALESCE(#select + ', ', '') + ''''''' + ISNULL(CAST([' + name + '] AS NVARCHAR(max)), ''NULL'')+'''''''
FROM tempdb.sys.columns
WHERE [object_id] = OBJECT_ID(N'tempdb..'+#input);
-- Run the a dynamic query with the fields from #select into a new temp table
CREATE TABLE #ConvertQueryToInsertTemp (strings nvarchar(max))
DECLARE #stmt NVARCHAR(max) = 'INSERT INTO #ConvertQueryToInsertTemp SELECT '''+ #select + ''' AS [strings] FROM '+#input
exec sp_executesql #stmt
-- Output the final insert statement
SELECT 'INSERT INTO ' + #target + ' (' + #fields + ') VALUES (' + REPLACE(strings, '''NULL''', 'NULL') +')' FROM #ConvertQueryToInsertTemp
-- Clean up temp tables
DROP TABLE #ConvertQueryToInsertTemp
SET #stmt = 'DROP TABLE ' + #input
exec sp_executesql #stmt
END
You can then use it by writing the output of your query into a temp table and running the procedure:
-- Example table
CREATE TABLE Dummy (Id INT, Comment NVARCHAR(50), TimeStamp DATETIME)
INSERT INTO Dummy VALUES (1 , 'Foo', GetDate()), (2, 'Bar', GetDate()), (3, 'Foo Bar', GetDate())
-- Run query and procedure
SELECT * INTO #TempTableForConvert FROM Dummy WHERE Id < 3
EXEC dbo.ConvertQueryToInsert '#TempTableForConvert', 'dbo.Dummy'
Note:
This procedure only casts the values to a string which can cause the data to look a bit different. With DATETIME for example the seconds will be lost.
I created the following procedure:
if object_id('tool.create_insert', 'P') is null
begin
exec('create procedure tool.create_insert as');
end;
go
alter procedure tool.create_insert(#schema varchar(200) = 'dbo',
#table varchar(200),
#where varchar(max) = null,
#top int = null,
#insert varchar(max) output)
as
begin
declare #insert_fields varchar(max),
#select varchar(max),
#error varchar(500),
#query varchar(max);
declare #values table(description varchar(max));
set nocount on;
-- Get columns
select #insert_fields = isnull(#insert_fields + ', ', '') + c.name,
#select = case type_name(c.system_type_id)
when 'varchar' then isnull(#select + ' + '', '' + ', '') + ' isnull('''''''' + cast(' + c.name + ' as varchar) + '''''''', ''null'')'
when 'datetime' then isnull(#select + ' + '', '' + ', '') + ' isnull('''''''' + convert(varchar, ' + c.name + ', 121) + '''''''', ''null'')'
else isnull(#select + ' + '', '' + ', '') + 'isnull(cast(' + c.name + ' as varchar), ''null'')'
end
from sys.columns c with(nolock)
inner join sys.tables t with(nolock) on t.object_id = c.object_id
inner join sys.schemas s with(nolock) on s.schema_id = t.schema_id
where s.name = #schema
and t.name = #table;
-- If there's no columns...
if #insert_fields is null or #select is null
begin
set #error = 'There''s no ' + #schema + '.' + #table + ' inside the target database.';
raiserror(#error, 16, 1);
return;
end;
set #insert_fields = 'insert into ' + #schema + '.' + #table + '(' + #insert_fields + ')';
if isnull(#where, '') <> '' and charindex('where', ltrim(rtrim(#where))) < 1
begin
set #where = 'where ' + #where;
end
else
begin
set #where = '';
end;
set #query = 'select ' + isnull('top(' + cast(#top as varchar) + ')', '') + #select + ' from ' + #schema + '.' + #table + ' with (nolock) ' + #where;
insert into #values(description)
exec(#query);
set #insert = isnull(#insert + char(10), '') + '--' + upper(#schema + '.' + #table);
select #insert = #insert + char(10) + #insert_fields + char(10) + 'values(' + v.description + ');' + char(10) + 'go' + char(10)
from #values v
where isnull(v.description, '') <> '';
end;
go
Then you can use it that way:
declare #insert varchar(max),
#part varchar(max),
#start int,
#end int;
set #start = 1;
exec tool.create_insert #schema = 'dbo',
#table = 'customer',
#where = 'id = 1',
#insert = #insert output;
-- Print one line to avoid the maximum 8000 characters problem
while len(#insert) > 0
begin
set #end = charindex(char(10), #insert);
if #end = 0
begin
set #end = len(#insert) + 1;
end;
print substring(#insert, #start, #end - 1);
set #insert = substring(#insert, #end + 1, len(#insert) - #end + 1);
end;
The output would be something like that:
--DBO.CUSTOMER
insert into dbo.customer(id, name, type)
values(1, 'CUSTOMER NAME', 'F');
go
If you just want to get a range of rows, use the #top parameter as bellow:
declare #insert varchar(max),
#part varchar(max),
#start int,
#end int;
set #start = 1;
exec tool.create_insert #schema = 'dbo',
#table = 'customer',
#top = 100,
#insert = #insert output;
-- Print one line to avoid the maximum 8000 characters problem
while len(#insert) > 0
begin
set #end = charindex(char(10), #insert);
if #end = 0
begin
set #end = len(#insert) + 1;
end;
print substring(#insert, #start, #end - 1);
set #insert = substring(#insert, #end + 1, len(#insert) - #end + 1);
end;
You can Use Sql Server Integration Service Packages specifically designed for Import and Export operation.
VS has a package for developing these packages if your fully install Sql Server.
Integration Services in Business Intelligence Development Studio
I think its also possible with adhoc queries
you can export result to excel file and then import that file into your datatable object or use it as it is and then import the excel file into the second database
have a look at this link
this can help u alot.
http://vscontrols.blogspot.com/2010/09/import-and-export-excel-to-sql-server.html
If you are using Oracle (or configure the application to the SQL Server) then Oracle SQL Developer does this for you. choose 'unload' for a table and follow the options through (untick DDL if you don't want all the table create stuff).
I found this SMSMS Boost addon, which is free and does exactly this among other things. You can right click on the results and select Script data as.
You can use this Q2C.SSMSPlugin, which is free and open source. You can right click and select "Execute Query To Command... -> Query To Insert...". Enjoy)
You can use an INSERT INTO SELECT statement, to insert the results of a select query into a table. http://www.w3schools.com/sql/sql_insert_into_select.asp
Example:
INSERT INTO Customers (CustomerName, Country)
SELECT SupplierName, Country
FROM Suppliers
WHERE Country='Germany'