Writing a dynamic SQL function - sql

I am having a few problems trying to return a table from a SQL function, where the SQL to create the table is written dynamically.
So far I have:
CREATE FUNCTION dbo.SEL_PCD
(
#COBDate AS DATETIME,
#FileName AS VARCHAR(50),
#PC AS VARCHAR(50),
#MyList AS VARCHAR(max),
DECLARE #SQL VARCHAR(max)
SET #SQL = 'SELECT * FROM
(SELECT tab1.TID FROM
(SELECT TID FROM dbo.SEL_RT('+#COBDate+','+#FileName+') WHERE BID IN ('+ #MyList +')) tab1
JOIN
(SELECT TID FROM CT WHERE (Col_Name LIKE %' + #PC + '% OR Bk LIKE %' + #PC + '%) AND FileName = ' + #FileName + ' AND COBDate = #COBDate) tab2
ON tab1.TID = tab2.TID) tab3
JOIN
(SELECT TID, Value FROM CR WHERE BID IN (' + #MyList + ') AND COBDate = ' + #COBDate + ' AND FileName = ' + #FileName + 'AND ScenID = 266) tab7
ON tab3.TID = tab7.TID'
)
RETURNS TABLE AS
RETURN
(
EXEC sp_executesql #SQL
)
GO
I am getting errors declaring the SQL variable. Am I ok to return the table via the execute command?

Have a try with this one:
CREATE PROCEDURE dbo.SEL_PCD
(
#COBDate DATETIME,
#FileName VARCHAR(50),
#PC VARCHAR(50),
#MyList VARCHAR(max)
) AS
DECLARE #SQL VARCHAR(max)
SELECT #SQL = 'SELECT * FROM
(SELECT tab1.TID FROM
(SELECT TID FROM dbo.SEL_RT('+#COBDate+','+#FileName+') WHERE BID IN ('+ #MyList +')) tab1
JOIN
(SELECT TID FROM CT WHERE (Col_Name LIKE %' + #PC + '% OR Bk LIKE %' + #PC + '%) AND FileName = ' + #FileName + ' AND COBDate = #COBDate) tab2
ON tab1.TID = tab2.TID) tab3
JOIN
(SELECT TID, Value FROM CR WHERE BID IN (' + #MyList + ') AND COBDate = ' + #COBDate + ' AND FileName = ' + #FileName + 'AND ScenID = 266) tab7
ON tab3.TID = tab7.TID'
EXEC(#SQL)
Functions
can be used with Select statement
Not returning output parameter but returns Table variables
You can join UDF
Cannot be used to change server configuration
Cannot be used with XML FOR clause
Cannot have transaction within function
Stored Procedure
have to use EXEC or EXECUTE
return output parameter
can create table but won’t return Table Variables
you can not join SP
can be used to change server configuration
can be used with XML FOR Clause
can have transaction within SP

You can't call stored procedures from within a function, including the stored procedures EXECUTE or SP_EXECUTESQL. This means that you can't have dynamic sql embedded within a function.
The reason you can't call stored procedures is because functions are not allowed to have side-effects (calling them can't in itself change any data - they can't insert, update or delete). But stored procedures can. This means that a function that calls a stored procedure would suddenly become able to have side-effects.
SP's can call Functions, not the other way around.
Also, SQL is compiled to an execution plan. At that time the tables and indexes that are being used all become fixed. If a function includes dynamic sql that would be possible; the tables, etc, that are to be used are not known at compile time, and SQL does not have that capability.
In your case the only part of your query that seems to need Dynamic SQL is that you are passing a comma delimited list as the #myList parameter. There is, however, an alternative approach.
Look for one of the many dbo.fn_split() functions that are available on line (and many on SO). Then use that function to join on the data...
CREATE FUNCTION dbo.SEL_PCD( #COBDate AS DATETIME,
#FileName AS VARCHAR(50),
#PC AS VARCHAR(50),
#MyList AS VARCHAR(max)
)
RETURNS TABLE
AS
RETURN
SELECT
CR.TID,
CR.Value
FROM
dbo.SEL_RT(#COBDate, #FileName) AS RT
INNER JOIN
CT
ON CT.TID = RT.TID
INNER JOIN
CR
ON CR.TID = RT.TID
WHERE
(CT.Col_Name LIKE '%'+#PC+'%' OR CT.Bk LIKE '%'+#PC+'%')
AND CT.FileName = #FileName
AND CT.COBDate = #COBDate
AND CR.FileName = #FileName
AND CR.COBDate = #COBDate
AND CR.ScenID = 266
AND RT.BID IN (SELECT id FROM dbo.fn_split(#myList, ',') AS my_list)
AND CR.BID IN (SELECT id FROM dbo.fn_split(#myList, ',') AS my_list)

you cannot use execute command in function
CREATE PROCEDURE dbo.SEL_PCD4
(
#COBDate AS DATETIME,
#FileName AS VARCHAR(50),
#PC AS VARCHAR(50),
#MyList AS VARCHAR(max)
) AS
DECLARE #SQL VARCHAR(max)
SET #SQL = 'SELECT * FROM
(SELECT tab1.TID FROM
(SELECT TID FROM dbo.SEL_RT('+#COBDate+','+#FileName+') WHERE BID IN ('+ #MyList +')) tab1
JOIN
(SELECT TID FROM CT WHERE (Col_Name LIKE %' + #PC + '% OR Bk LIKE %' + #PC + '%) AND FileName = ' + #FileName + ' AND COBDate = #COBDate) tab2
ON tab1.TID = tab2.TID) tab3
JOIN
(SELECT TID, Value FROM CR WHERE BID IN (' + #MyList + ') AND COBDate = ' + #COBDate + ' AND FileName = ' + #FileName + 'AND ScenID = 266) tab7
ON tab3.TID = tab7.TID'
EXEC sp_executesql #SQL
GO

Related

Dynamic SQL - Use declared VARCHAR in SET SQL string

How to use the declared variable #CodeID inside the SQL string? When I run following statement I get the "Invalid object name (..)" error.
WHILE #FolderID <= #FolderMaxID
BEGIN
SELECT #Db = Db
FROM #Folders
WHERE ID = #FolderID
SET #Sql = N'
DECLARE #CodeID NVARCHAR(256)
SELECT TOP(1) #CodeID=CodeType
FROM ' + #Db + '.bla.Field
WHERE Name= ''Example''
SELECT DISTINCT C.Name
FROM ' + #Db + '.Document
INNER JOIN ' + #Db + '.bla.Code_#CodeID C ON D.ID = C.ID'
EXEC ( #Sql )
SET #FolderID = #FolderID + 1
END
It looks to me that you need two levels of dynamic SQL, with the first level inserting the database name (from #folders), and the second level inserting a constructed table name (based on the CodeType column of the database-local bla.Field table).
I do not know of any way to parameterize database names or table names using sp_executesql, so I'm sticking with build-up dynamic SQL and EXEC (). (If someone makes a case for preferring sp_executesql over EXEC when not useing parameters, then it may be worth the switch.)
Try something like:
WHILE #FolderID <= #FolderMaxID
BEGIN
SELECT #Db = Db
FROM #Folders
WHERE ID = #FolderID
SET #Sql = N'
DECLARE #CodeID NVARCHAR(256)
SELECT TOP(1) #CodeID=CodeType
FROM ' + QUOTENAME(#Db) + '.bla.Field
WHERE Name= ''Example''
DECLARE #Sql2 NVARCHAR(MAX) = N''
SELECT DISTINCT C.Name
FROM ' + QUOTENAME(#Db) + '.bla.Document D
INNER JOIN ' + QUOTENAME(#Db) + '.bla.'' + QUOTENAME(''Code_'' + #CodeID) + '' C ON D.ID = C.ID
''
EXEC #sql2
'
EXEC ( #Sql )
SET #FolderID = #FolderID + 1
END
This implements dynamic SQL within dynamic SQL. Doubled quotes in the outer sql template become single quotes in the inner sql. The original posted code seemed to be missing a schema qualifier and alias for the Document table, so I inserted them ("bla" and "D"). I also added QUOTENAME around the injected names as suggested by Larnu.
The first level of dynamic sql would generate something like:
SELECT TOP(1) #CodeID=CodeType
FROM [db1].bla.Field
WHERE Name= 'Example'
DECLARE #Sql2 NVARCHAR(MAX) = N'
SELECT DISTINCT C.Name
FROM [db1].bla.Document D
INNER JOIN [db1].bla.' + QUOTENAME('Code_' + #CodeID) + ' C ON D.ID = C.ID
'
EXEC #sql2
The second level would generate something like:
SELECT DISTINCT C.Name
FROM [db1].bla.Document D
INNER JOIN [db1].bla.[Code_Table1] C ON D.ID = C.ID
Note that each loop iteration will generate a separate result. If you wish to combine results, you will need to define a #temp table, insert the individual results into that table, and then select the combined results at the end of your script.
Note that I haven't tested the specific code above, so it might need some debugging (add "PRINT #sql2" before the EXEC) if it doesn't work straight out.
ADDENDUM
Per #trenton-ftw comments below, an out parameter can be used to capture the result of the first query so that it may be included in the second query without the need for nesting. Two executions are still required. Below is a revised example.
DECLARE #Folders TABLE (ID INT IDENTITY(1,1), Db sysname)
INSERT #Folders VALUES ('db1'), ('db2')
DECLARE #SearchName NVARCHAR(256) = 'Example'
DECLARE #Db sysname
DECLARE #Sql NVARCHAR(MAX)
DECLARE #CodeID NVARCHAR(256)
DECLARE #FolderMaxID INT = (SELECT MAX(ID) FROM #Folders)
DECLARE #FolderID INT = 1
WHILE #FolderID <= #FolderMaxID
BEGIN
SELECT #Db = Db
FROM #Folders
WHERE ID = #FolderID
SET #Sql = N'
SET #CodeID = #SearchName + ''-Test''
--SELECT TOP(1) #CodeID = CodeType
--FROM ' + QUOTENAME(#Db) + '.bla.Field
--WHERE Name = #SearchName'
PRINT #Sql
EXEC sp_executesql #Sql,
N'#SearchName NVARCHAR(256), #CodeID NVARCHAR(256) OUTPUT',
#SearchName, #CodeID OUTPUT
SET #Sql = N'
--SELECT DISTINCT C.Name
--FROM ' + QUOTENAME(#Db) + '.bla.Document D
-- INNER JOIN ' + QUOTENAME(#Db) + '.bla.' + QUOTENAME('Code_' + #CodeID) + ' C ON D.ID = C.ID'
PRINT #Sql
EXEC sp_executesql #sql
SET #FolderID = #FolderID + 1
END
For demo purposes, I also parameterized the search name as an input parameter and added some temporary code to make it stand-alone testable. A final version would uncomment the actual sql, and remove the print statements and the test #CodeID assignemnt.

Passing parameter to stored procedure using dynamic SQL into pivot data

I am trying to pass a parameter into Stored procedure to filter data in my select statement but when i use the parameter it gives error Message: Invalid column name 'SessionId2075'. when I use static value in the where clause the procedure works fine. Can you please give me fix the issue. I checked all the previous answers and could not find the working solution.
Alter PROCEDURE [dbo].GetPivotFeeReport
(
#SessionId varchar(50)
)
as
begin
DECLARE #SQL as VARCHAR(MAX)
DECLARE #Columns as VARCHAR(MAX)
SET NOCOUNT ON;
SELECT #Columns =
COALESCE(#Columns + ', ','') + QUOTENAME(GroupHeaderValue)
FROM
(SELECT DISTINCT mgh.GroupHeaderValue
FROM StudentFeeDetail sf
INNER JOIN MasterGroupHeaderValue mgh
ON mgh.GroupHeaderValueId = sf.FeeForId
) AS B
ORDER BY B.GroupHeaderValue
SET #SQL = 'SELECT ClassName,' + #Columns + ',TOTAL
FROM
(
SELECT
distinct mc.className,
sf.FinalAmount,
mgh.GroupHeaderValue,
Sum (isnull(sf.FinalAmount,0)) over (partition by ClassName) AS TOTAL
--0 AS TOTAL
FROM StudentFeeDetail sf
INNER JOIN StudentAdmission sa
ON sa.AdmissionId = sf.AdmissionId
INNER JOIN MasterClass mc
ON mc.ClassId = sa.ClassId
INNER JOIN MasterGroupHeaderValue mgh
ON mgh.GroupHeaderValueId = sf.FeeForId
WHERE sa.SessionId = (' + #SessionId + ') -- this is where I am trying to use the parameter when used static value like this ''SessionId2075'' the procedure works fine
and sf.FeeAmt >0
GROUP BY className, FinalAmount, GroupHeaderValue
) as PivotData
PIVOT
(
sum(FinalAmount)
FOR GroupHeaderValue IN (' + #Columns + ')
) AS PivotResult
ORDER BY (ClassName)
'
EXEC ( #sql)
end

SQL Server : Duplicate row in table while changing some values with select *

I need to insert an almost duplicated row into table, while changing few values.
For example insert duplicated row with new id (I don't want automatic id) and different name but all other values the same.
The problem is that I need to make a select *
I know that there is a way to insert from select and changing values this way :
insert into Table1(id,name,surname) select newid(),'David',surname from Table1 where id=1
but I don't want to enlist all fields ,instead I want to use select *, so if fields added I won't have to change my stored procedure.
I want something like :
insert into Table1 (
update (SELECT *
FROM Table1
WHERE id= 1 ) t
set t.id= newid(),name='David')
Is there a way to do it ?
You can use temp hash table to accomplish this.
SELECT *
INTO #temp
FROM Table1
WHERE id= 1;
UPDATE #temp
SET ID = newid(),
Name='David'
INSERT INTO Table1 SELECT * FROM #temp;
Note that the #temp table is automatically dropped when the client disconnect from the DB server.
Also, as previously noted, I prefer to use column names separately instead of *.
Example: SQL Fiddle
The code I use:
declare #table sysname
declare #excludecols nvarchar(max)
declare #uniqueWhereToCopy nvarchar(max)
declare #valuesToChange nvarchar(max)
--copy settings
set #table = 'orsrg' --the tablename
set #excludecols='' --columnnames to exclude from the copy, seperated by commas
set #uniqueWhereToCopy = 'ID=1188'
set #valuesToChange = 'regel='' 4''' --columnName=<value>,columnName2=<value2>, .... (needed for unique indexes)
set #excludecols=#excludecols + ','
set #valuesToChange=#valuesToChange + ','
--get the columnnames to copy
declare #sqlcolumns nvarchar(max)
set #sqlcolumns = ''
SELECT #sqlcolumns = #sqlcolumns + name from
(select '[' + c.name + '], ' as name FROM sys.COLUMNS c inner join sys.objects o
on c.object_id = o.object_id
WHERE o.name = #table
and is_identity = 0 /*exclude identity*/
and is_rowguidcol = 0 /*exclude rowguids*/
and is_computed = 0 /*exclude computed columns*/
and system_type_id <> 189 /*exclude timestamp*/
and charindex(c.name, #excludecols,1) = 0 /*exclude user specified columns*/)q
--get the select columns and values
declare #sqlselectvalues nvarchar(max)
set #sqlselectvalues = #sqlcolumns
while len(#valuesToChange)>1
begin
declare #colValueSet nvarchar(max)
declare #colname sysname
declare #value nvarchar(max)
set #colValueSet = left(#valuesToChange,charindex(',',#valuesToChange,1)-1)
set #valuesToChange = substring(#valuesToChange,charindex(',',#valuesToChange,1)+1,len(#valuesToChange))
set #colname = '[' + left(#colValueSet,charindex('=',#colValueSet,1)-1) +']'
set #value = substring(#colValueSet,charindex('=',#colValueSet,1)+1,len(#colValueSet))
set #sqlselectvalues = REPLACE(#sqlselectvalues,#colname,#value)
end
--remove the last comma
set #sqlcolumns = left(#sqlcolumns, len(#sqlcolumns)-1)
set #sqlselectvalues = left(#sqlselectvalues, len(#sqlselectvalues)-1)
--create the statement
declare #stmt nvarchar(max)
set #stmt = 'Insert into ' + #table + '(' + #sqlcolumns + ') select ' + #sqlselectvalues + ' from ' + #table + ' with (nolock) where ' + #uniqueWhereToCopy
--copy the row
exec sp_executesql #stmt
No, because a SELECT * will always contain the id column.
Generally, you should avoid SELECT * anywhere except when querying interactively. When the stored procedure is compiled, the query text will be parsed and replaced with the correct columns, rendering your stored procedure invalid on every change to the structure anyway.

Using Dynamic SQL in User Defined Function to return string (not modify data)

Our document storage application has a unique database for each of our clients which are almost identical to each other, but one table DocumentIndexes is unique for each client and can have any number of columns and types.
I am trying to create a generic function (within our "master" database called MYAPP_MASTER) that I can call and simply pass in a database name and a document ID value and get back the column names and values from from the specified database's DocumentIndexes table. Because I have to pass in the database name, I have to generate the selection SQL dynamically and call sp_executesql.
I have the following code which polls the INFORMATION_SCHEMA.COLUMNS table to determine the columns needed and it works just fine in a stored procedure, but I hate having to copy all this code in every stored procedure that needs these to retrieve these dynamic column values. I would rather have one function that returns the string value of these columns regardless of database and have the function exist once in our MYAPP_MASTER database. Again, this code works, but SQL won't allow me to put it into a function. Is there anyway around this?
USE MYAPP_MASTER
GO
DECLARE #DatabaseName varchar(255)
DECLARE #DocumentId int
SET #DatabaseName = 'SAMPLE_CLIENT_DB'
SET #DocumentId = 1234
DECLARE #DynamicIndexes nvarchar(max)
DECLARE #DynamicIndexesParam nvarchar(max)
DECLARE #DynamicIndexesSql nvarchar(max)
SET #DynamicIndexesParam = '#Indexes varchar(max) OUTPUT'
SET #DynamicIndexesSql = 'SELECT #Indexes = COALESCE(#Indexes + ''+ '''', '', '''') + CAST(COLUMN_NAME as varchar(max)) + '': '''''' + '' + CASE WHEN DI.'' + COLUMN_NAME + '' IS NOT NULL THEN CAST(DI.'' + COLUMN_NAME + '' as varchar(max)) ELSE '''''''' END '' FROM ' + #DatabaseName + '.INFORMATION_SCHEMA.COLUMNS WHERE table_name = ''DocumentIndexes'' AND COLUMN_NAME <> ''DocumentID''; '
EXEC sp_executesql #DynamicIndexesSql, #DynamicIndexesParam, #Indexes = #DynamicIndexes OUTPUT
SET #DynamicIndexes = '''' + #DynamicIndexes
DECLARE #SelectionSql nvarchar(max)
SET #SelectionSql = 'SELECT ' + #DynamicIndexes + ' as DocumentIndexes FROM ' + #DatabaseName + '..Document D LEFT OUTER JOIN ' + #DatabaseName + '..DocumentIndexes DI ON D.DocumentId = DI.DocumentId WHERE D.DocumentID = ' + CAST(#DocumentId as varchar(10))
EXEC sp_executesql #SelectionSql
If the SAMPLE_CLIENT_DB datababase DocumentIndexes table has columns for Name, Office and Classification, this code will return a simple string that looks like the following:
Name: Foo, Office: Bar, Classification: 123
You can't run an Exec command inside a SQL function, but you could use a stored procedure with an output variable assuming the DocumentIndexes table is unique at the DocumentID level.
Create Proc DocID_DocIndexes #retval Varchar(Max) Output
As
...
(Your code logic minus last two lines)
...
-- Populate your dynamic SQL into a variable to assign it to the output variable
SET #SelectionSql = 'SELECT #result = ' + #DynamicIndexes + ' as DocumentIndexes FROM ' + #DatabaseName + '..Document D LEFT OUTER JOIN ' + #DatabaseName + '..DocumentIndexes DI ON D.DocumentId = DI.DocumentId WHERE D.DocumentID = ' + CAST(#DocumentId as varchar(10))
EXEC sp_executesql #SelectionSql, N'#result Varchar(Max) Output', #result = #retval Output
Return

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'