I have to change all the columns in a database in all the tables (SQL Server) that are Date and convert them to DateTime.
How do I accomplish that? Is it a command?
I think this can help you :
Execute the script you will see the update list in the messages tab.
DECLARE #SQLString VARCHAR(MAX)=''
SELECT #SQLString = #SQLString +CHAR(13)+'ALTER TABLE '+T.TABLE_SCHEMA+'.'+T.TABLE_NAME+' ALTER COLUMN '+C.COLUMN_NAME+' DATETIME'
FROM INFORMATION_SCHEMA.TABLES T
INNER JOIN INFORMATION_SCHEMA.COLUMNS C ON T.TABLE_SCHEMA=C.TABLE_SCHEMA
AND T.TABLE_NAME=C.TABLE_NAME
WHERE C.DATA_TYPE='date'
AND T.TABLE_TYPE='BASE TABLE'
PRINT(#SQLString)
you can use this query to get collection of alter queries for your columns which are date type.
SELECT
CONCAT('alter table ', TABLE_SCHEMA, '.', TABLE_NAME, ' ALTER COLUMN ', COLUMN_NAME, ' DATETIME;')
FROM INFORMATION_SCHEMA.COLUMNS
Where DATA_TYPE = 'date' and TABLE_SCHEMA not in ('information_schema', 'sys');
then by executing generated results your table columns will be converted to DateTime
The command for altering a column, which must be called to change a datatype, is --> ALTER COLUMN. The ALTER COLUMN command can only be called from within the context of an ALTER TABLE command. You are lucky because the datatype you want to convert to is conversion compatible and only widens the column. If you attempt to convert to a incompatible datatype or a datatype that requires less storage then you could not use the simple command below.
ALTER TABLE YourTableName
ALTER COLUMN YouDateField DATETIME
Generate dynamic statement using sys.columns and sys.types and execute generated statement.
This statement also checks for nullability of each column.
ALTER TABLE ... ALTER COLUMN is not always a working solution. In some cases you'll probably need to drop the table and recreate it, or add new column, then copy the values for old column to the new one, and then drop the original column.
When you alter a column, consider at least the following:
the previous data type must be implicitly convertible to the new data type
new type cannot be timestamp.
ANSI_NULL defaults are always on for ALTER COLUMN; if not specified, the column is nullable.
T-SQL:
DECLARE
#stm nvarchar(max),
#err int
SELECT #stm = (
SELECT CONCAT(
'ALTER TABLE ', OBJECT_NAME(c.OBJECT_ID),
' ALTER COLUMN ',
c.name,
' datetime',
CASE
WHEN c.is_nullable = 1 THEN ' NULL '
ELSE ' NOT NULL '
END,
'; '
)
FROM sys.columns AS c
JOIN sys.types AS t ON c.user_type_id = t.user_type_id
WHERE t.name = 'date'
ORDER BY c.OBJECT_ID
FOR XML PATH('')
)
PRINT #stm
EXEC #err = sp_executesql #stm
IF #err = 0
PRINT 'OK'
ELSE
PRINT 'Error'
Related
There is this query that I keep using over and over:
SELECT column_name, count(column_name) FROM table_name GROUP by column_name ORDER BY COUNT(column_name) DESC
I use this to check which different values there are in a column and how often they occur.
Because I use this query so often and it's repeating the same 4 times: column_name, I was like: why not make a stored procedure:
CREATE PROCEDURE countcv #table_name VARCHAR(50),#column_name VARCHAR(50)
AS
BEGIN
SELECT #column_name,COUNT(#column_name) FROM #table_name GROUP BY #column_name ORDER BY COUNT(#column_name)
END
Here is where I get stuck, I can not manage to get a variable tablename:
Must declare the table variable "#table_name"
I believe that #Julien Vavasseur and #Dark Knight has already addressed to your question.
However, I would like to add here that, Sql Server 2008 introduced Table-Valued Parameter by using which we can pass table type variable to the stored procedures. e.g.
Assuming you have a table by the name tblTest with the below columns
ID INT,
Name VARCHAR(50)
Step 1: Declare a new table User Defined Type
CREATE TYPE tblTestType AS TABLE
(
ID INT,
Name VARCHAR(50)
)
Step 2: Create a STORED PROCEDURE that has tblTestType as parameter
CREATE PROCEDURE countcv
(
#tblName tblTestType readonly
)
AS
INSERT INTO tblTest (ID, Name)
SELECT ID, Name
FROM
#tblName;
Then you can use DataTable (if you are using C#) and pass this data table as a parameter to the Stored Procedure.(you can find an example in the link I provided).
There is no way to do it directly. You need to use dynamicSQL approach. Assuming you pass correct table and column names. Below one should work.
CREATE PROCEDURE countcv #table_name VARCHAR(50),#column_name VARCHAR(50)
AS
BEGIN
declare #SQL nvarchar(max)
set #SQL = 'SELECT '+#column_name+',COUNT('+#column_name+')
FROM '+#table_name+'
GROUP BY '+#column_name+'
ORDER BY COUNT('+#column_name+')'
EXEC sp_executesql #SQL
END
If you want to do something like this, you must use dynamic SQL:
CREATE PROCEDURE countcv #table_name sysname, #column_name sysname
AS
BEGIN
Declare #sql nvarchar(max)
Set #sql = 'SELECT ' + QUOTENAME(#column_name)+', COUNT(' + QUOTENAME(#column_name)+')
FROM ' + QUOTENAME(#table_name)+'
GROUP BY ' + QUOTENAME(#column_name)+' ORDER BY COUNT(' + QUOTENAME(#column_name)+')'
EXEC sp_executesql #sql
END
Use sysname for data type for column and table names (buitin datatype for object names, alias to nvarchar(128))
Use QUOTENAME to add delimeter to column and table names
Using SQL Server 2008, I've created a database where every table has a datetime column called "CreatedDt". What I'd like to do is create a trigger for each table so that when a value is inserted, the CreatedDt column is populated with the current date and time.
If you'll pardon my pseudocode, what I'm after is the T-SQL equivalent of:
foreach (Table in MyDatabase)
{
create trigger CreatedDtTrigger
{
on insert createddt = datetime.now;
}
}
If anyone would care to help out, I'd greatly appreciate it. Thanks!
As #EricZ says, the best thing to do is bind a default for the column. Here's how you'd add it to every table using a cursor and dynamic SQL:
Sure, You can do it with a cursor:
declare #table sysname, #cmd nvarchar(max)
declare c cursor for
select name from sys.tables where is_ms_shipped = 0 order by name
open c; fetch next from c into #table
while ##fetch_status = 0
begin
set #cmd = 'ALTER TABLE ' + #table + ' ADD CONSTRAINT DF_' + #table + '_CreateDt DEFAULT GETDATE() FOR CreateDt'
exec sp_executesql #cmd
fetch next from c into #table
end
close c; deallocate c
No need to go for Cursors. Just copy the result of below Query and Execute.
select distinct 'ALTER TABLE '+ t.name +
' ADD CONSTRAINT DF_'+t.name+'_crdt DEFAULT getdate() FOR '+ c.name
from sys.tables t
inner join sys.columns c on t.object_id=c.object_id
where c.name like '%your column name%'
Here's another method:
DECLARE #SQL nvarchar(max);
SELECT #SQL = Coalesce(#SQL + '
', '')
+ 'ALTER TABLE ' + QuoteName(T.TABLE_SCHEMA) + '.' + QuoteName(T.TABLE_NAME)
+ ' ADD CONSTRAINT ' + QuoteName('DF_'
+ CASE WHEN T.TABLE_SCHEMA <> 'dbo' THEN T.Table_Schema + '_' ELSE '' END
+ C.COLUMN_NAME) + ' DEFAULT (GetDate()) FOR ' + QuoteName(C.COLUMN_NAME)
+ ';'
FROM
INFORMATION_SCHEMA.TABLES T
INNER JOIN INFORMATION_SCHEMA.COLUMNS C
ON T.TABLE_SCHEMA = C.TABLE_SCHEMA
AND T.TABLE_NAME = C.TABLE_NAME
WHERE
C.COLUMN_NAME = 'CreatedDt'
;
EXEC (#SQL);
This yields, and runs, a series of statements similar to the following:
ALTER TABLE [schema].[TableName] -- (line break added)
ADD CONSTRAINT [DF_schema_TableName] DEFAULT (GetDate()) FOR [ColumnName];
Some notes:
This uses the INFORMATION_SCHEMA views. It is best practice to use these where possible instead of the system tables because they are guaranteed to not change between versions of SQL Server (and moreover are supported on many DBMSes, so all things being equal it's best to use standards-compliant/portable code).
In a database with a case-sensitive default collation, one MUST use upper case for the INFORMATION_SCHEMA view names and column names.
When creating script it's important to pay attention to schema names and proper escaping (using QuoteName). Not doing so will break in someone's system some day.
I think it is best practice to put the DEFAULT expression inside parentheses. While no error is received without it in this case, with it, if the function GetDate() is parameterized and/or ever changed to a more complex expression, nothing will break.
If you decide that column defaults are not going to work for you, then the triggers you imagined are still possible. But it will take some serious work to manage whether the trigger already exists and alter or create it appropriately, JOIN to the inserted meta-table inside the trigger, and do it based on the full list of primary key columns for the table (if they exist, and if they don't, then you're out of luck). It is quite possible, but extremely difficult--you could end up with nested, nested, nested dynamic SQL. I have such automated object-creating script that contains 13 quote marks in a row...
For SSIS, I need to create a TSQL update workflow to overwrite the current table records in case of an import error.
I already have a set up for the whole SSIS process but I'm missing the SQL update statement.
So if something goes wrong during the import the current records (all rows) in the table should be updated with a short message - "Error DB Import" for example.
Since I have multiple tables to deal with I also get different column names and data types.
I would use this stmt to get the column names
SELECT COLUMN_NAME , *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'myTable'
but how can I set a string message for the char types and NULL for numeric and date types. Using a CASE stmt?
In pseudo-code it's probably just a loop through the columns: if column_name is of data_type "char" then...
I also need to ignore the first 4 columns of each table so that I don't overwrite ID, Date, etc.
If you can help me set up a static test update stmt I'm sure I will be able to transfer this to my SSIS project.
Thank you.
Sounds like you're looking for something like this:
SELECT
CASE DATA_TYPE
WHEN 'int' THEN NULL
WHEN 'varchar' THEN 'STRING MSG GOES HERE'
END,
COLUMN_NAME , *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'myTable'
AND ORDINAL_POSITION > 4
SQL Fiddle Demo
You can add as many WHEN clauses to the CASE statement as needed. Also, you want to use the ORDINAL_POSITION column to exclude the first 4 columns.
If you need to use this information to create an UPDATE statement, then you'll need to do that with Dynamic SQL.
EDIT -- Dynamic SQL:
create procedure updateMyTable
as
begin
declare #sql varchar(max)
SELECT #sql = 'UPDATE myTable SET ' +
STUFF(
(SELECT ', ' + COLUMN_NAME + ' = ' +
CASE DATA_TYPE
WHEN 'int' THEN 'NULL'
WHEN 'varchar' THEN '''STRING MSG GOES HERE'''
END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'myTable'
for xml path(''))
,1,1,'')
exec(#sql)
end
SQL Fiddle Demo
I have a database which current collation is French_CI_AS, which means that searches are case insensitive, but accent sensitive. I had the impression that changing the collation of the database to French_CI_AI would solve my problem so I did it. However, I still can't make a simple search work Accent-Insensitive. I check and the table collation is French_CI_AI, which is probably because it was changed along with the database.
Is there some way to make the search possible with Accent insensitive on all database ? Or is there any way to make a single seach that way ? I only have one or two Stored procedures that would need that so I could go that way to.
In case it makes any differences, the datatype I look for are all nvarchar(n)s.
Thanks
You can make the search use whatever collation you want, e.g.
WHERE column COLLATE FRENCH_CI_AI LIKE '%something%' COLLATE FRENCH_CI_AI
However I suspect it will work better if you actually fix the column (which didn't happen when you changed the database collation). Leaving out any constraints and other dependencies, the short answer of how to fix this:
ALTER TABLE dbo.foo ADD newcol NVARCHAR(32) COLLATE FRENCH_CI_AI;
UPDATE dbo.foo SET newcol = oldcol;
ALTER TABLE dbo.foo DROP COLUMN oldcol;
EXEC sp_rename N'dbo.foo.newcol', N'oldcol', 'COLUMN';
First, chaging the database collation does not impact existing column in table but will affect newly created table and column. It's the default collation to use when creating new object in the database.
So, what you have to do is to find all existing column and updating current collation.
You can do it with a sql cursor and query all table and column and update collation for specific type or column name.
By example :
1) you change the collation for future object
USE master;
GO
ALTER DATABASE databasename COLLATE French_CI_AI ;
GO
2) change manually the column collation for specific column
ALTER TABLE tablenameX ALTER COLUMN LastName varchar(100) COLLATE French_CI_AI NULL
ALTER TABLE tablenameY ALTER COLUMN FirstName varchar(100) COLLATE French_CI_AI NULL
3) generate a sql script with cursor
You need to decide what column to change collation. It can be by type, name or specific table.
You can start by looking wich type of caracter type you have and replace them in the example, see the column cursor.
SELECT distinct DATA_TYPE from information_schema.columns
you can refer to this post :
http://www.codeproject.com/Articles/302405/The-Easy-way-of-changing-Collation-of-all-Database
declare #CollationName as nvarchar = 'Latin1_General_CI_AS'
declare #tablename as nvarchar(100) = ''
declare #sqltext as nvarchar(100) = ''
declare #columnname as nvarchar(200) = ''
declare #DataType as nvarchar(100) = ''
declare #CharacterMaxLen as int = 0
declare #IsNullable as bit = 0
DECLARE MyTableCursor Cursor
FOR
SELECT * from information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
OPEN MyTableCursor
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE MyColumnCursor Cursor
FOR
SELECT COLUMN_NAME,DATA_TYPE, CHARACTER_MAXIMUM_LENGTH,
IS_NULLABLE from information_schema.columns
WHERE table_name = #TableName AND (Data_Type LIKE '%char%'
OR Data_Type LIKE '%text%') AND COLLATION_NAME <> #CollationName
ORDER BY ordinal_position
Open MyColumnCursor
FETCH NEXT FROM MyColumnCursor INTO #ColumnName, #DataType,
#CharacterMaxLen, #IsNullable
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLText = 'ALTER TABLE ' + #TableName + ' ALTER COLUMN [' + #ColumnName + '] ' +
#DataType + '(' + CASE WHEN #CharacterMaxLen = -1 THEN 'MAX' ELSE #CharacterMaxLen END +
') COLLATE ' + #CollationName + ' ' +
CASE WHEN #IsNullable = 'NO' THEN 'NOT NULL' ELSE 'NULL' END
PRINT #SQLText
FETCH NEXT FROM MyColumnCursor INTO #ColumnName, #DataType,
#CharacterMaxLen, #IsNullable
END
CLOSE MyColumnCursor
DEALLOCATE MyColumnCursor
FETCH NEXT FROM MyTableCursor INTO #TableName
END
CLOSE MyTableCursor
DEALLOCATE MyTableCursor
I have a SQL Server table which has 625 columns created with different datatypes like int, varchar(25), decimal(18, 2), etc...
Now am interested in changing datatype of all columns to varchar(255). Instead of executing below query for all the columns one by one, is there a single SQL Server query to change datatypes of all columns in a table at one shot?
ALTER TABLE dbo.Employee
ALTER COLUMN FirstName VARCHAR(255) NOT NULL
Looking forward for your response.
There is no one single "magic" bullet to do this - it's an operation that's rather unusual, so it's not supported natively.
What you can do is iterate over the columns of your table from the system catalog views, create such an ALTER statement on the fly, and also execute it - something like this:
DECLARE AlterTableCursor CURSOR FAST_FORWARD
FOR
SELECT
AlterCmd = 'ALTER TABLE dbo.YourTableNameHere ALTER COLUMN ' + name + ' VARCHAR(255) NULL'
FROM
sys.columns
WHERE
object_id = OBJECT_ID('dbo.YourTableNameHere')
DECLARE #AlterTableCmd NVARCHAR(200)
OPEN AlterTableCursor
FETCH NEXT FROM AlterTableCursor INTO #AlterTableCmd
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#AlterTableCmd)
FETCH NEXT FROM AlterTableCursor INTO #AlterTableCmd
END
CLOSE AlterTableCursor
DEALLOCATE AlterTableCursor
Replace the YourTableNameHere with your actual table name - and you should be good to go! Test this on a copy of your live data first !
is not possible. You will need to do this one by one. You can do following things -
You can create a Temporary Table with your desired columns and type.
copy the data from original table to temporary table.
delete original table
Rename you Temporary Table to your original name
I would say that it's not a good design to have 625 columns in one table, but you do what ever you have been asked to do.
You could generate a SQL string that contains multiple ALTER statements and execute it with EXEC. You have to be careful with the data conversion though. This is why it's probably better to do it in a cursor, because you can catch possible exceptions for the columns that cannot be altered. Here is a simple code which does it in two steps:
generate the SQL string;
execute it using EXEC
Code sample:
SELECT * FROM sys.columns WHERE OBJECT_NAME(object_id) = 'Employee'
DECLARE #SQL VARCHAR(MAX)
SET #SQL = (
SELECT '
ALTER TABLE dbo.Employee ALTER COLUMN ' + c.name + ' VARCHAR(255) NULL;
'
FROM sys.columns c WHERE OBJECT_NAME(object_id) = 'Employee'
FOR XML PATH(''), TYPE
).value('text()[1]', 'VARCHAR(MAX)')
PRINT #SQL
EXEC(#SQL)
SELECT * FROM sys.columns WHERE OBJECT_NAME(object_id) = 'Employee'