SSMS: Create a table script from results of a procedure - sql-server

I have a piece of dynamic sql query. I'd like to keep the result in a temp table. But the query returns +100 fields so I'd prefer not to type the Create table script manually.
Is it possible in Sql Server Management Studio to script out the results returned by the procedure into a create table script.
So let's say that in a new query panel I execute my script. Below I get the returned results. Option I'm looking for is something like e.g. right clicking the results and selecting "Script into a table". Or something similar to what you get when you select "Edit top 200 rows" on a table and then in the returned results when you right click -> Pane -> SQL you can edit the SQL that generated the results.
Is anything like that possible in SSMS for results of a procedure? If external tools are required are there any that are free? I'm using SQL Server 2012 and SSMS 2012. Some tools that where available for previous versions are licensed for 2012.
Below some mocked version of the core code in the procedure:
exec dbo.spDynamic
#ID ,
#ID2 ,
#Parameters ,
#prefixLogic,
#selectprefix,
#selectsuffix,
#Table_1,
#Function_1,
#SelectExtra_1,
#Where_1,
#Function_2,
#SelectExtra_2,
#Where_2,
#On,
#finalWhere
#tempSchema
#tempTable
#tempWhere
And here's the essential part of the spDynamic:
Declare #sql nvarchar(max)
set #sql =
+ #parameterLogic
+ ' ' + #prefixlogic
+ #selectprefix
+ ' SELECT ' + #DeltaLogic
+ ' FROM ( Select * ' + Case When #ID < 0 Then Replace(#SelectExtra_1, '<ID>', CAST(#ID AS nvarchar))
When #ID = 0 Then Replace(#SelectExtra_2, '<ID>', CAST(#ID AS nvarchar))
Else Replace(#Table_1, '<ID>', CAST(#ID AS nvarchar)) End
+ ' From ' + Case When #ID < 0 Then #Function_1 + ' ' + #Where_1
When #ID = 0 Then #Function_2 + ' ' + #Where_2
Else #tempSchema + #tempTable
+ ' ' + Replace(#tempWhere, '<ID>', CAST(#ID AS nvarchar)) End
+ ' ) A '
+ ' FULL OUTER JOIN '
+ ' ( Select * ' + Case When #ID2 < 0 Then Replace(#SelectExtra_1, '<ID>', CAST(#ID2 AS nvarchar))
When #ID2 = 0 Then Replace(#SelectExtra_2, '<ID>', CAST(#ID2 AS nvarchar))
Else Replace(#Table_1, '<ID>', CAST(#ID2 AS nvarchar)) End
+ ' From ' + Case When #ID2 < 0 Then #Function_1 + ' ' + #Where_1
When #ID2 = 0 Then #Function_2 + ' ' + #Where_2
Else #tempSchema + #tempTable
+ ' ' + Replace(#tempWhere, '<ID>', CAST(#ID2 AS nvarchar)) End
+ ' ) B ' + #on
+ #finalWhere
+ #selectsuffix
exec sp_sqlexec #sql

One solution could be to execute the stored procedure inside an OPENROWSET function as described here.
This allows you to create the table on-the-fly, for example by writing:
SELECT * INTO MyTempTable
FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes',
'EXEC myStoredProc')
If you don't want actual data into MyTempTable, you could add WHERE 1 = 0 at the end. Afterwards, you can then script out MyTempTable just like any other table.

If you use SSMSBoost tool bar then it has a "script grid data" option:

This will create a table called NewTable
SELECT *
INTO NewTable
FROM AnotherTable
Can you could alter your dynamic SQL to do this?

Related

How to use while loop to iterate through each table name in SQL Server?

I'm working with Dynamic SQL (still in the learning phase) and I'm stuck at a part where I need to use a WHILE loop:
SET #tableName = (SELECT DISTINCT TableName FROM #dataStructure)
Here basically I want to make sure that the operations inside the while loop should occur for all the tables in the #tableName (defined above). I don't know how I can give this condition as an input for the while loop.
WHILE() #HOW CAN I PUT THE CONDITION HERE????
BEGIN
SET #str = ''
SET #sqlstr = ''
SELECT #table = TableName FROM #dataStructure
SET #str = 'UPDATE a0' + char(13) + char(10)
+ ' SET a0.Mjolnir_Source_ID = CONCAT( '
SELECT #str = #str + IIF(ReferenceTable IS NULL, 'a0.' + columnName , alias + '.Mjolnir_Source_ID') + ','
FROM #dataStructure
WHERE TableName = #tableName AND ReferenceTable IS NOT NULL
ORDER BY columnName
SELECT #str = #str + ') FROM ' + #table + ' a0'
SELECT #sqlstr = #sqlstr + +
+ ' INNER JOIN ' + QUOTENAME(#U4SM_db_name) + '.dbo.' + QUOTENAME(ReferenceTable) + ' ' + alias + char(13) + char(10)
+ ' ON a0.' + columnName + ' = ' + alias + '.' + ReferenceColumn + char(13) + char(10)
FROM #dataStructure
WHERE TableName = #tableName AND ReferenceTable IS NOT NULL
ORDER BY columnPosition
select #str + #sqlstr
select #sqlstr
SET #tableName = #tableName + 1
END
Can anyone please help me out here?
Here's an example of a WHILE loop. Basically, you get the first TableName, then if it's NOT NULL, you do your functions. Then get the next table name, and repeat as necessary.
DECLARE #CurrentTableName nvarchar(100)
DECLARE #CustomSQL nvarchar(4000)
SET #CurrentTableName = (SELECT TOP 1 TableName FROM #dataStructure ORDER BY TableName)
WHILE #CurrentTableName IS NOT NULL
BEGIN
SET #CustomSQL = 'SELECT TOP 10 * FROM ' + #CurrentTableName
EXEC (#CustomSQL)
SET #CurrentTableName = (SELECT TOP 1 TableName FROM #dataStructure WHERE TableName > #CurrentTableName ORDER BY TableName)
END
Note that SQL commands often cannot contain variable names in key spots (e.g., SELECT * FROM #tableName). Instead, you save it as an SQL string (what I've called #CustomSQL above) and then EXEC it (put brackets around the variable name though).
Edit: Do this on a test site first before production, and know where the 'cancel query' button is. It's not often, but it's also not unknown, that the 'getting the next row' part isn't properly written and it just runs in a perpetual loop.
FETCH CURSOR with WHILE. Example:
DECLARE myCursor CURSOR FOR
SELECT DISTINCT TableName FROM #dataStructure;
OPEN myCursor;
FETCH NEXT FROM myCursor INTO #table:Name;
WHILE ##FETCH_STATUS = 0
BEGIN
Print ' ' + #TableName
FETCH NEXT FROM myCursor INTO #TableName;
END;
CLOSE myCursor;
DEALLOCATE myCursor;
GO
Don't recreate the wheel unless you need a better wheel:
sp_MSforeachtable
https://www.sqlshack.com/an-introduction-to-sp_msforeachtable-run-commands-iteratively-through-all-tables-in-a-database/
If you are worried about using an undocumented procedure in production that might change in the future, simply script it out and create your own custom named version.

How to find the list of tables which has new set of records impacted in SQL?

I am working on exporting data from one environment to another environment. I want to select the list of tables which has new set of records either inserted or modified.
Database has around 200 tables and only if 10 table records are impacted since yesterday, i want to filter only those tables. Some of these tables does not have createdate table column. It is harder to identify the record difference based on plain select query to the table.
How to find the list of tables which has new set of records impacted in SQL?
And if possible only those newly impacted records from the identified tables.
I tried with this query, however this query is not returning actual tables.
select * from sysobjects where id in (
select object_id
FROM sys.dm_db_index_usage_stats
WHERE last_user_update > getdate() - 1 )
If you've not got a timestamp or something to identify newly changed records such as auditing, utilising triggers or Change Data Capture enabled on those tables, it's quiet impossible to do.
However, reading your scenario is it not possible to ignore what has changed or been modified and just simply export those 200 tables from one environment to the other and override it on the destination location?
If not, then you might be only interested in comparing data rather than identifying newly changed records to identify which tables did not match. You can do that using EXCEPT
See below example of comparing two databases with the same table names and schema creating a dynamic SQL statement column using EXCEPT from both databases on the fly and running them in a while loop; inserting each table name that was effected into a temp table.
DECLARE #Counter AS INT
, #Query AS NVARCHAR(MAX)
IF OBJECT_ID('tempdb..#CompareRecords') IS NOT NULL DROP TABLE #CompareRecords
IF OBJECT_ID('tempdb..#TablesNotMatched') IS NOT NULL DROP TABLE #TablesNotMatched
CREATE TABLE #TablesNotMatched (ObjectName NVARCHAR(200))
SELECT
ROW_NUMBER() OVER( ORDER BY (SELECT 1)) AS RowNr
, t.TABLE_CATALOG
, t.TABLE_SCHEMA
, t.TABLE_NAME
, Query = 'IF' + CHAR(13)
+ '(' + CHAR(13)
+ ' SELECT' + CHAR(13)
+ ' COUNT(*) + 1' + CHAR(13)
+ ' FROM' + CHAR(13)
+ ' (' + CHAR(13)
+ ' SELECT ' + QUOTENAME(t.TABLE_NAME, '''''') + ' AS TableName, * FROM ' + QUOTENAME(t.TABLE_CATALOG) + '.' + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME) + CHAR(13)
+ ' EXCEPT' + CHAR(13)
+ ' SELECT ' + QUOTENAME(t.TABLE_NAME, '''''') + ' AS TableName, * FROM ' + QUOTENAME(t2.TABLE_CATALOG) + '.' + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME) + CHAR(13)
+ ' ) AS sq' + CHAR(13)
+ ') > 1' + CHAR(13)
+ 'SELECT ' + QUOTENAME(QUOTENAME(t.TABLE_CATALOG) + '.' + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME), '''''') + ' AS TableNameRecordsNotMatched'
INTO #CompareRecords
FROM <UAT_DATABASE>.INFORMATION_SCHEMA.TABLES AS t
LEFT JOIN <PROD_DATABASE>.INFORMATION_SCHEMA.TABLES AS t2 ON t.TABLE_SCHEMA = t2.TABLE_SCHEMA
AND t.TABLE_NAME = t2.TABLE_NAME
WHERE t.TABLE_TYPE = 'BASE TABLE'
SET #Counter = (SELECT MAX(RowNr) FROM #CompareRecords)
WHILE #Counter > 0
BEGIN
SET #Query = (SELECT cr.Query FROM #CompareRecords AS cr WHERE cr.RowNr = #Counter)
INSERT INTO #TablesNotMatched
EXECUTE sp_executesql #Query
SET #Counter = #Counter - 1
END
SELECT
*
FROM #TablesNotMatched
Note when using EXCEPT both tables have to have the exact same column count and type.
I hope this slightly helps.

SQL Server global temp table - Invalid object error

SELECT #SqlCmdEnd =',Member_Cd as x_Member_Cd,
LOD.Val_Seq as x_GroupSort,
vs.Member_RCID as x_Org_Key,
LOD.Val_Cd as x_Level_Text,
Type_RCID as x_Type_RCID
into ##VS_Wide'+#l_Random+'
We have a dynamic query inside a stored procedure which uses a global temp table as shown above. It is working fine for normal scenarios but during load, concurrency test we are getting an error:
Invalid object ##VS_Wide12345
12345 is a random number generated using the below script.
So what could be the possible reason for this error? Any help on this will be appreciated.
select #l_Random = replace(right(rand(), 5), '.', '')
Try this one -
DECLARE #l_Random CHAR(32) = REPLACE(NEWID(), '-', '')
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = '
IF OBJECT_ID(''##VS_Wide' + #l_Random + ''') IS NOT NULL
DROP TABLE ##VS_Wide' + #l_Random + '
SELECT 1 AS a
INTO ##VS_Wide' + #l_Random + '
SELECT * FROM ##VS_Wide' + #l_Random + '
'
PRINT #SQL
EXEC sys.sp_executesql #SQL
Output -
IF OBJECT_ID('##VS_WideC016ADF003FD4254B6BBFB5053E9C956') IS NOT NULL
DROP TABLE ##VS_WideC016ADF003FD4254B6BBFB5053E9C956
SELECT 1 AS a
INTO ##VS_WideC016ADF003FD4254B6BBFB5053E9C956
SELECT * FROM ##VS_WideC016ADF003FD4254B6BBFB5053E9C956

SQL Server special characters significance in fetch sp

In the following fetch sp of sql server 2008R2, what does-> /^/ these characters symbolise in the column names in the select statement in #object?
CREATE Proc Pr_FetchPatientIssueItemsMis
As
Begin
Declare #Object varchar(MAX)
SET NOCOUNT ON
Set #Object= '(Select '
+ 'ISD.[' + /*v*/'SalesID'/*v*/ + '] SalesID,'
+ 'ISD.[' + /*v*/'ItemID'/*v*/ + '] ItemID,'
+ 'V.DisplayName ItemName,'
+ 'V.ItemCode ItemCode,'
+ 'v.CategoryID CategoryID,'
+ 'v.Category Category'
+ ' From Dbo.[' + /*v*/'V_ItemPatientIssues'/*v*/ + ']ISD'
+ ' Inner Join Dbo.[v_items]V ON ISD.[' + /*v*/'ItemID'/*v*/ + ']= V.ItemID'
+ ')OBJ'
EXEC('Select * from (Select * From ' + #Object +')XYZ')
Return 0
End
They are in-line comments. They don't do anything. The only thing that they could symbolize would be some documentary meaning that was totally up to whoever wrote it.
My off-hand guess would be that whoever wrote this uses this procedure as a template to generate other procedures by doing searches on pairs of the /*v*/ and replacing whatever's between them with different table/column names.

SQL Server equivalent to DBMS_METADATA.GET_DDL

I was wondering if there is an equivalent in SQL Server 2008 to Oracle's DBMS_METADATA.GET_DDL Function? You can pass this function a table name and it will return the ddl for that table so that you can use it to build a script for a schema.
I know I can go into SSMS and use that, but I would prefer to have a t-sql script that would generate the ddl for me.
Thanks,
S
I using this query for generate query but this work for 1 table :
declare #vsSQL varchar(8000)
declare #vsTableName varchar(50)
select #vsTableName = 'Customers'
select #vsSQL = 'CREATE TABLE ' + #vsTableName + char(10) + '(' + char(10)
select #vsSQL = #vsSQL + ' ' + sc.Name + ' ' +
st.Name +
case when st.Name in ('varchar','varchar','char','nchar') then '(' + cast(sc.Length as varchar) + ') ' else ' ' end +
case when sc.IsNullable = 1 then 'NULL' else 'NOT NULL' end + ',' + char(10)
from sysobjects so
join syscolumns sc on sc.id = so.id
join systypes st on st.xusertype = sc.xusertype
where so.name = #vsTableName
order by
sc.ColID
select substring(#vsSQL,1,len(#vsSQL) - 2) + char(10) + ')'
If you are looking for a TSQL solution, it is quite verbose, as [this example]¹ shows.
A shorter alternative would be using the SMO library (example)
¹ Link for this example deleted. The way Internet Archive Wayback Machine displayed an error saying that they could not display the content. And following the link to the original went someplace malicious. (Grave errors, instruction to call some number, etc.)

Resources