How to get the "CREATE TABLE" query? - sql

When I right-click on my view and click on "Script View As", I get the following error:
Property TextHeader is not available for View '[dbo].[TableName]'. This
property may not exist for this object, or may not be retrievable due
to insufficient access rights. The text is encrypted.
(Microsoft.SqlServer.Smo)
I was able to use bcp to get a dump of the table and also create a format file as given here. The table has about 60 columns and I do not want to manually write the CREATE TABLE query. Is there a way to do this automatically?
I was hoping that
BULK INSERT DB.dbo.TableName
FROM 'E:\Databases\TableName'
WITH (FORMATFILE = 'E:\Databases\TableName.Fmt');
GO
would do the trick but it looks like the table itself should be present in the database before I can execute the above query. Any suggestions?

You can construct the create table statement from INFORMATION_SCHEMA.Columns. Something like:
select (column_name + ' ' + data_type +
(case when character_maximum_length is not null
then '('+character_maximum_length+')'
else ''
end) + ','
) as ColumnDef
from Information_Schema.columns
order by ordinal_position
This is probably good enough. You can make it more complicated if you have to deal with numerics, for instance, or want "is null" to be accurate.
Copy the results into a new window, add the create table statement, remove the final comma and add the final closing paren.
You can do all the last step in a more complex SQL statement, but it is easier to do manually for a one-time effort.

Related

why all columns are invalid after table rename?

I renamed a table and since, in evry 'select' I get the 'Invalid object name' for all columns.
I get from my select the output I need, but why I get an error too ?
this is my simple select...
SELECT [Importance]
,[Color]
,[NotificationName]
FROM [dbo].[Alerts]
It looks like you're using SQL Server Management Studio. I suspect your query will run if you try it, it's just that the intellisense doesn't know that the table name has changed.
Try Ctrl+Shift+R to refresh the cache or alternatively Edit -> Intellisense -> Refresh Local Cache.
You need to do this every time you perform schema changes.
Run below query to confirm that your table has been renamed and has the exact column names specified in your select query:
select * from sys.all_columns where object_id = OBJECT_ID('Alerts')
Alternatively you can execute below query to confirm that the Alerts table exists
IF (EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Alerts'))
BEGIN
PRINT 'Alerts exists'
END
Also make sure you are in the correct database, run below query to find out the database to which Alerts belong :
SELECT TABLE_CATALOG
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Alerts'
Once you got the database name add USE DATABASENAME at the beginning of your query or you can use DATABASENAME.dbo.Alerts.

Converting data types from one database table to another

I did a bulk insert on a large text file that was an update for an existing database that I had. I ran into all kinds of trouble with truncation errors so I just set everything to varchar(max). Now that everything is in SQL Server I'd like to convert the data types from database b, to those of database a. If both databases had the same table and field names, what are some methods of getting this done? Or would it be best to have a pre-existing script you run after import that's 'hardcoded'
Try something like this and modify the result and execute it
declare #sql varchar(max)
set #sql=''
select
#sql=#sql+'Alter table '+table_name+' alter column '+column_name+' '+cast(data_type as varchar(100))+
case when data_type like '%char%' then '(' else '' end +cast(coalesce(CHARACTER_MAXIMUM_LENGTH,'' ) as varchar(100))+
case when data_type like '%char%' then ')' else '' end+';'
from
information_schema.columns
where
table_name='test'
print #sql
You could create a view of the table your looking to pull from and just cast() the columns you need to change to the data types you need to change them to. Then you can just do all of your inserts off of that View in the appropriate data type. Hope that helps.
If you are moving data from one sql server database to another you could use Atlantis Interactive Data Inspector. If you don't want to do that, you can script out the table in database a then paste ALTER TABLE [table] ALTER COLUMN before every column and run in on database b.

replace sql injection script

I have this sql query to try and remove some sql injection script from my database. When i execute this it runs fine and tells me that all rows have been affected, but I don't see any changes. I have checked the table names and the column names, I have changed the varchar value to the value the columns are set to but still nothing.
I have copied the injected script directly from the database
UPDATE table_name
SET column_name = REPLACE(CAST(column_name AS VARCHAR(max)), '"></title><script src="http://www1.mainglobilisi.com/sl.php"></script><!--', '')
Could someone please explain why the script runs fine but no updates are done on the database.
The REPLACE function is probably not finding the string you're searching for.
Try doing a select to see if you get any rows:
select
column_name
from
table_name
where
CAST(column_name AS VARCHAR(max)) like '%"></title><script src="http://www1[dot]mainglobilisi[dot]com/sl.php"></script><!--%'
(I obfuscated to the URL incase its malicious).

Drop all temporary tables for an instance

I was wondering how / if it's possible to have a query which drops all temporary tables?
I've been trying to work something out using the tempdb.sys.tables, but am struggling to format the name column to make it something that can then be dropped - another factor making things a bit trickier is that often the temp table names contain a '_' which means doing a replace becomes a bit more fiddly (for me at least!)
Is there anything I can use that will drop all temp tables (local or global) without having to drop them all individually on a named basis?
Thanks!
The point of temporary tables is that they are.. temporary. As soon as they go out of scope
#temp create in stored proc : stored proc exits
#temp created in session : session disconnects
##temp : session that created it disconnects
The query disappears. If you find that you need to remove temporary tables manually, you need to revisit how you are using them.
For the global ones, this will generate and execute the statement to drop them all.
declare #sql nvarchar(max)
select #sql = isnull(#sql+';', '') + 'drop table ' + quotename(name)
from tempdb..sysobjects
where name like '##%'
exec (#sql)
It is a bad idea to drop other sessions' [global] temp tables though.
For the local (to this session) temp tables, just disconnect and reconnect again.
The version below avoids all of the hassles of dealing with the '_'s. I just wanted to get rid of non-global temp tables, hence the '#[^#]%' in my WHERE clause, drop the [^#] if you want to drop global temp tables as well, or use a '##%' if you only want to drop global temp tables.
The DROP statement seems happy to take the full name with the '_', etc., so we don't need to manipulate and edit these. The OBJECT_ID(...) NOT NULL allows me to avoid tables that were not created by my session, presumably since these tables should not be 'visible' to me, they come back with NULL from this call. The QUOTENAME is needed to make sure the name is correctly quoted / escaped. If you have no temp tables, #d_sql will be the empty string still, so we check for that before printing / executing.
DECLARE #d_sql NVARCHAR(MAX)
SET #d_sql = ''
SELECT #d_sql = #d_sql + 'DROP TABLE ' + QUOTENAME(name) + ';
'
FROM tempdb..sysobjects
WHERE name like '#[^#]%'
AND OBJECT_ID('tempdb..'+QUOTENAME(name)) IS NOT NULL
IF #d_sql <> ''
BEGIN
PRINT #d_sql
-- EXEC( #d_sql )
END
In a stored procedure they are dropped automatically when the execution of the proc completes.
I normally come across the desire for this when I copy code out of a stored procedure to debug part of it and the stored proc does not contain the drop table commands.
Closing and reopening the connection works as stated in the accepted answer. Rather than doing this manually after each execution you can enable SQLCMD mode on the Query menu in SSMS
And then use the :connect command (adjust to your server/instance name)
:connect (local)\SQL2014
create table #foo(x int)
create table #bar(x int)
select *
from #foo
Can be run multiple times without problems. The messages tab shows
Connecting to (local)\SQL2014...
(0 row(s) affected)
Disconnecting connection from (local)\SQL2014...

SQL clone record with a unique index

Is there a clean way of cloning a record in SQL that has an index(auto increment). I want to clone all the fields except the index. I currently have to enumerate every field, and use that in an insert select, and I would rather not explicitly list all of the fields, as they may change over time.
Not unless you want to get into dynamic SQL. Since you wrote "clean", I'll assume not.
Edit: Since he asked for a dynamic SQL example, I'll take a stab at it. I'm not connected to any databases at the moment, so this is off the top of my head and will almost certainly need revision. But hopefully it captures the spirit of things:
-- Get list of columns in table
SELECT INTO #t
EXEC sp_columns #table_name = N'TargetTable'
-- Create a comma-delimited string excluding the identity column
DECLARE #cols varchar(MAX)
SELECT #cols = COALESCE(#cols+',' ,'') + COLUMN_NAME FROM #t WHERE COLUMN_NAME <> 'id'
-- Construct dynamic SQL statement
DECLARE #sql varchar(MAX)
SET #sql = 'INSERT INTO TargetTable (' + #cols + ') ' +
'SELECT ' + #cols + ' FROM TargetTable WHERE SomeCondition'
PRINT #sql -- for debugging
EXEC(#sql)
There's no easy and clean way that I can think of off the top of my head, but from a few items in your question I'd be concerned about your underlying architecture. Maybe you have an absolutely legitimate reason for wanting to do this, but usually you want to try to avoid duplicates in a database, not make them easier to cause. Also, explicitly naming columns is usually a good idea. If you're linking to outside code, it makes sure that you don't break that link when you add a new column. If you're not (and it sounds like you probably aren't in this scenario) I still prefer to have the columns listed out because it forces me to review the effects of the change/new column - even if it's just to look at the code and decide that adding the new column is not a problem.
DROP TABLE #tmp_MyTable
SELECT * INTO #tmp_MyTable
FROM MyTable
WHERE MyIndentID = 165
ALTER TABLE #tmp_MyTable
DROP Column MyIndentID
INSERT INTO MyTable
SELECT *
FROM #tmp_MyTable
This also deals with a unique key projectnum as well as the primary key.
CREATE TEMPORARY TABLE projecttemp SELECT * FROM project WHERE projectid='6';
ALTER TABLE projecttemp DROP COLUMN projectid;
UPDATE projecttemp SET projectnum = CONCAT(projectnum, ' CLONED');
INSERT INTO project SELECT NULL,projecttemp.* FROM projecttemp;
You could create an insert trigger to do this, however, you would lose the ability to do an insert with an explicit ID. It would, instead, always use the value from the sequence.
You could create a trigger to do it for you. To make sure that trigger only works for cloning, you could create a separate username CLONE and log in with it. Or, even better, if your DBMS supports it, create a role named CLONE and any user can log in using that role and do the cloning. The trigger code would be something like:
if (CURRENT_ROLE = 'CLONE') then
new.ID = assign new id from generator/sequence
Of course, you would grant that role only to the users who are allowed to clone records.