SQL Server equivalent to DBMS_METADATA.GET_DDL - sql-server

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.)

Related

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.

Dynamic SQL- slow string concatenation

I am running a dynamic sql query which loops over all tables in a large dB (1600 tables) and creates the query I need to run afterwards. After the string is created i save the string and run it. However the string concatenation is extremely slow . I need to add a lot more boilerplate code for each table but in the example below I've omitted the boilerplate code to keep it simple.
My question is how can I speed up this process of building queries via concatenation of NVARCHAR? When I run this query it gets significantly slower the more text and parameter concatenations are added. It takes over 30 mins currently but the CTE executes in 1 sec.
DECLARE #UpdateColumnsSql NVARCHAR(MAX) = '';
WITH TableColumns AS
(
SELECT
QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) +
'.' + QUOTENAME(t.name) AS TableName
,LOWER(c.name) AS ColumnName
,ty.name AS TypeName
,c.max_length AS ColLength
FROM
sys.tables AS t
INNER JOIN
sys.columns AS c
ON
t.object_id = c.object_id
INNER JOIN
sys.types AS ty
ON
c.system_type_id = ty.system_type_id
WHERE
c.name IN
( 'Company_ID', 'Facility_ID', 'Premises_ID' )
)
SELECT
#UpdateColumnsSql = #UpdateColumnsSql +
'ALTER TABLE ' + TableColumns.TableName +
' ADD [' + TableColumns.ColumnName + '_New] ' + TypeName +
'(' + CONVERT(VARCHAR(4), ColLength) + ')' + ' NULL
SET #sql =
'''' UPDATE T
SET T.[' + TableColumns.ColumnName + '_New] = S.[NewValue]
from ' + TableColumns.TableName + ' T
inner join NewIDList S
on Company = Company_ID
where T.[' + TableColumns.ColumnName + '] = S.OldValue
AND S.[OldColumnName] = ''''''''' + TableColumns.ColumnName + ''''''''' ''''
exec(#sql);
'
FROM
TableColumns;

Exporting to Excel from SQL Server

I am stuck at a problem for which I cannot find any reason or solution.
I am running a SQL script to export some data to an Excel sheet. There is an application running on the other end which reads and processes the Excel sheet.
Problem: The column headers are being displayed at the bottom and the application is expecting them to be on the top row. I cannot change the functioning of the application.
This was working fine in SQL 2005, but we recently updated to SQL 2012 and this started happening.
I have not found anything over the internet to solve this issue.
This is the SQL script that I am executing
SELECT
#columnNames = COALESCE( #columnNames + ',', '') + '['+ column_name + ']',
#columnConvert = COALESCE( #columnConvert + ',', '') + 'convert(nvarchar(4000),'
+ '['+ column_name + ']' +
case
when data_type in ('datetime', 'smalldatetime') then ',121'
when data_type in ('numeric', 'decimal') then ',128'
when data_type in ('float', 'real', 'money', 'smallmoney') then ',2'
when data_type in ('datetime', 'smalldatetime') then ',120'
else ''
end + ') as ' + '['+ column_name + ']'
FROM tempdb.INFORMATION_SCHEMA.Columns
WHERE table_name = '##TempExportData'
-- execute select query to insert data and column names into new temp table
SELECT #sql = 'select ' + #columnNames + ' into ##TempExportData2 from (select ' + #columnConvert + ', ''2'' as [temp##SortID] from ##TempExportData union all select ''' + replace(replace(replace(#columnNames, ',', ''', '''),'[',''),']','') + ''', ''1'') t order by [temp##SortID]'
exec (#sql)
-- build full BCP query
DECLARE #bcpCommand VARCHAR(8000)
SET #bcpCommand = 'bcp " SELECT * from ##TempExportData2" queryout'
SET #bcpCommand = #bcpCommand + ' ' + #fullFileName + ' -T -w -S' + #serverInstance
EXEC master..xp_cmdshell #bcpCommand
Where TempExportData2 holds the data that along with column headers
I think I understand the problem: You are using the order by in the select into instead of in the final select statement.
You should know that data inside tables is considered unorderd and Sql Server (and any other rdbms I know, actually) does not guarantee the order of rows selected if the select statement does not contain an order by clause.
Therefor, you should add the [temp##SortID] column to your ##TempExportData2 table and use it to sort the last select statement:
SET #bcpCommand = 'bcp " SELECT * from ##TempExportData2 ORDER BY [temp##SortID]" queryout'
Since you don't need that column in the output query, so you might want to specify the column names in that select statement. However, if it's not causing damage to your application that reads the excel file or to the data it produces, I would suggest keeping the select * to make the query more readable.

Creating a dynamic sql query

Please see this SQL code:
DECLARE #MyQuery nvarchar(max)
set #MyQuery = 'SELECT TOP 1 #TranslatedMessageOutput =
' + #LanguageName + ' FROM local_translation WHERE English =
'+CHAR(39)+CHAR(39)+Convert(nvarchar(50),
(select English from inserted))
+CHAR(39)+CHAR(39)+CHAR(39)+
' AND [' + #LanguageDateName + '] NOT LIKE ''%1900%'''
If I type abc for English this query works just fine.
But if I type 'abc' for English the query is throwing an error:
Unclosed quotation mark after the character string "". Incorrect syntax near "."
How do I solve this?
I suspect you will need to escape the output of this query:
(select English from inserted)
As in
(select replace(English, '''', '''''') from inserted)
The above will replace ' by '' before concatenating the outcome to your dynamic SQL statement. But with any dynamic SQL, I strongly suggest you make use of bind values to prevent such SQL syntax errors and SQL injection! I.e. you should be able to write something like this:
declare #English;
select #English = English from inserted;
set #MyQuery = 'SELECT TOP 1 #TranslatedMessageOutput =
' + #LanguageName +
' FROM local_translation WHERE English = #English'
' AND [' + #LanguageDateName + '] NOT LIKE ''%1900%''';
-- ...
In Dynamic sql queries in order to avoid confusion ,use Char(39) instead of '.
Eg :
SET #T='SELECT '+CHAR(39)+'NAME'+CHAR(39)
returns
SELECT 'NAME'

Equivalent of sp_helptext for tables in SQL Server

When we need the query of stored procedures we use 'Sp_Helptext procedurename'
Can something similar be done for tables?
Use Alt+F1 while table name selected in a query window.
Pretty Simple :
sp_help YourTable
Please use followig query
select * from information_Schema.columns where table_name = 'TableName'
There does not appear to be a direct equivalent of sp_helptext that will work with tables.
The two methods that seem to be common on various message boards are:
Use Information_Schema.Columns and concatenate the results into the create statement.
Use SQL-DMO script
There is an article on the second method here
Try with this SP. It doesn't have all the notations required for a table like primary keys and foreign keys but is a start.
CREATE PROCEDURE [dbo].[GeneradorTablas]
#Tabla AS VARCHAR(100)
AS
BEGIN
DECLARE #Script AS VARCHAR(MAX) ='CREATE TABLE [dbo].[' + #Tabla + '](' + CHAR(13)
DECLARE #Columnas As TABLE(indice INT, Columna VARCHAR(1000))
INSERT INTO #Columnas
SELECT
ROW_NUMBER()OVER(ORDER BY C.column_id),
' [' + C.name + '] [' + TY.name + ']' +
CASE WHEN
TY.name='nvarchar' OR
TY.name='nchar' OR
TY.name='char' OR
TY.name='varbinary' OR
TY.name='varchar' OR
TY.name='text' THEN
'(' + CASE WHEN C.max_length>0 THEN CAST(C.max_length AS VARCHAR(10)) ELSE 'MAX' END + ')' ELSE ''
END +
CASE WHEN C.is_identity=1 THEN ' IDENTITY(1,1)' ELSE '' END +
' ' + CASE WHEN C.is_nullable=1 THEN 'NULL' ELSE 'NOT NULL' END + ','
FROM SYS.COLUMNS AS C
INNER JOIN SYS.TYPES AS TY ON C.system_type_id=TY.system_type_id
INNER JOIN SYS.TABLES AS T ON C.object_id=T.object_id
WHERE T.name=#Tabla
DECLARE #i AS INT
SELECT #i=MIN(indice) FROM #Columnas
WHILE #i IS NOT NULL
BEGIN
SELECT #Script+=Columna+CHAR(13) FROM #Columnas WHERE indice=#i
SELECT #i=MIN(indice) FROM #Columnas WHERE indice>#i
END
SET #Script=SUBSTRING(#Script,0,LEN(#Script)-1) + CHAR(13) + ')'
PRINT #Script
END
GO
review dba tools which can be installed as add on in powershell https://docs.dbatools.io/Get-DbaDbTable
will give you results in line like this
enter image description here

Resources