Setting ANSI Padding OFF with ALTER - sql

I need to turn ANSI PADDING from ON to OFF on an existing field of a table without creating a new table. Is there a way to do this through an ALTER command?
Thanks!

No, there is no way to do this with just ALTER. Like the identity property, collation and some other bits, whether a column applies ANSI padding or not is not something that can be altered after the fact.
You can still do it without creating a new table altogether, but not without creating a new column:
BEGIN TRANSACTION;
SET ANSI_PADDING OFF;
ALTER TABLE T ADD C_badpad CHAR(16) NULL;
EXEC('UPDATE T SET C_badpad = C;')
EXEC sp_rename 'T.C', 'C_old';
EXEC sp_rename 'T.C_badpad', 'C';
EXEC('ALTER TABLE T DROP COLUMN C_old;')
ROLLBACK; -- COMMIT;
But, if you value your sanity, don't do this. Rewrite the client code that wants this so it does its own proper trimming, because the very ability to have ANSI_PADDING set to OFF is deprecated, with good reason. Almost everything expects ANSI_PADDING to be ON these days, so having it OFF for a specific column is likely to break clients that aren't expecting it. Even if you think you're solving a problem now, you're likely going to end up with bigger problems in the future.
ANSI_PADDING is only there as a compatibility tweak for very old software that just doesn't know any better (and will likely want the whole database to be created with ANSI_PADDING = OFF). Don't use it in new development, and certainly don't use it for just one column.

Related

How to modify index type in SQL Server? [duplicate]

This question already has answers here:
Can not drop UNIQUE index from table
(2 answers)
Closed 2 years ago.
I need to change the type of index from "Unique Key" to "index".
I`ve spent 2 days trying to drop and recreate it. Unfortunately, there are a lot of dependencies and the only way to fix my issue is to modify the existing index. SSMS visual editor allows me to change type however I ought to find out how to make it programmatically.
It is really bad idea to use something like UPDATE sys.key_constraints SET type = 'UQ' WHERE ...
Such a solution is not working properly.
I would appreciate any help!
To implement such change you will need to drop and recreate the index.
There is no alter statement that would change it.
It is possible to drop the index as a constant:
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.table_name
DROP CONSTRAINT IX_CONSTAINT_NAME
GO

SQL Server: Existing column and value incrementing

I'm trying to create and increment by one some values to put into an already existing (but empty) column. I'm currently using the identity function, but I wouldn't mind using a custom made function. Right now, SSMS is saying there's incorrect syntax near IDENTITY. Could anybody help me fix this syntax?
ALTER Table anthemID IDENTITY(1,1)
First, you can't make a column identity after the fact: it has to be set that way at creation time.
Second, I'm not quite sure what you mean by "increment the value of an already existing column by one." You can only increment the value of rows within a column--perform a DML (Data Modification Language) query. The script you suggested above is a DDL (Data Definition Language) query that actually modifies the structure of the table, affecting the entire column--all rows.
If you just want to increment all the rows by 1, you'd do this:
UPDATE dbo.YourTable SET anthemID = anthemID + 1;
On the other hand, if you want the anthemID column to acquire the identity property so that new inserts to the table receive unique, autoincrementing values, you can do that with some juggling:
Back up your database and confirm it is a good backup.
Script out your table including all constraints.
Drop all constraints on your table or other tables that involve anthemID.
ALTER TABLE dbo.YourTable DROP CONSTRAINT PK_YourTable -- if part of PK
ALTER TABLE dbo.AnotherTable DROP CONSTRAINT FK_AnotherTable_anthemID -- FKs
Rename your table
EXEC sp_rename 'dbo.YourTable', 'YourTableTemp';
Modify the script you generated above to make anthemID identity (add in identity(1,1) after int);
Run the modified script to create a new table with the same name as the original.
Insert the data from the old table to the new one:
SET IDENTITY_INSERT dbo.YourTable ON;
INSERT dbo.YourTable (anthemID, AnotherColumn, RestOfColumns)
SELECT anthemID, AnotherColumn, RestOfColumns
FROM dbo.YourTableTemp;
SET IDENTITY_INSERT dbo.YourTable OFF;
Re-add all constraints that were dropped.
Drop the original, renamed table after confirming you don't need the data any more.
You may be able to do this from SSMS's GUI table designer, and it will take care of moving the data over for you. However, this has bitten some people in the past and if you don't have a good database backup, well, don't do it because you might encounter some regret in the process.
UPDATE
Now that I know the column is blank, it's even easier.
ALTER TABLE dbo.YourTable DROP COLUMN anthemID;
ALTER TABLE dbo.YourTable ADD anthemID int identity(1,1) NOT NULL;
This does have the drawback of moving the column to the end of the table. If that's a problem, you can follow much the same procedure as I outlined above (to fix things yourself, or alternately use the designer in SQL Server Management Studio).
I recommend in the strongest terms possible that you use an identity column and do not try to create your own means of making new rows get an incremented value.
For emphasis, I'll quote #marc_s's comment above:
The SELECT MAX(ID)+1 approach is highly unsafe in a concurrent environment - in a system under some load, you will get duplicates. Don't do this yourself - don't try to reinvent the wheel - use the proper mechanisms (here: IDENTITY) that your database gives you and let the database handle all the nitty-gritty details!
I wholeheartedly agree with him.

Can I change a SQL Server table name in a way that is backwards compatible? E.g add a permanent alias?

I have a Sql Server 2008 database I inherited. A number of apps and SSIS packages work off that database. Not too long ago the scope of the database changed and a lot of new tables were added. As a result of this a lot of the table names (and even the database name itself) no longer make sense, resulting in a very confusing schema.
I could rename the tables straight away and change the apps and processes to use the new names but the chaos and downtime it would cause in the meantime would not be acceptable.
Is there a way I can add an alternate name for a table (like a permanent alias) that I could use to refer to either the new or old table name until all of my refactoring is complete?
Create a synonym first.
CREATE SYNONYM dbo.SensibleName FOR dbo.CrazyName;
Now find all the references to CrazyName in your codebase, and update them to reference SensibleName instead. Once you believe you have found them all, you can eventually run:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
DROP SYNONYM dbo.SensibleName;
EXEC sp_rename N'dbo.CrazyName', N'SensibleName', N'OBJECT';
COMMIT TRANSACTION;
If you need to make column names more sensible, you'll have to do so using a view, as synonyms only cover a subset of database-level objects.
Some other info here.
You can rename it with sp_rename and then add synonym:
CREATE SYNONYM OldTableName FOR NewTableName

SQL Server and Persisted computed field with Hashbytes

Before changes I had a persisted computed field which used Checksum function and index to use it.
alter table Softs add TitleHash AS (CHECKSUM([Title])) PERSISTED;
All were fine until we found that Checksum produces poor hash and duplicates might occur. So we decided to use Hashbytes.
I tried both with binary result and char result
alter table Softs add TitleHashCBin AS (CONVERT(BINARY(16),hashbytes('MD4',[Title]))) PERSISTED;
or
alter table Softs add TitleHashCChar AS (CONVERT(CHAR(32),hashbytes('MD4',[Title]),2)) PERSISTED;
Unfortunately we found that a simple SELECT request does not use index for new field.
SELECT id FROM Softs WHERE TitleHashCBin = 0xC29939F6149FD65100A66AF5FD958D8B
It scans primary index which is build on Id column.
After that we created binary column, copied data from TitleHashCBin and also created index for new column.
alter table Softs add TitleHashBin AS Binary(16)
And used similar select statement.
SELECT id FROM Softs WHERE TitleHashBin = 0xC29939F6149FD65100A66AF5FD958D8B
And this one uses index by TitleHashBin field.
What a hell is going with calculated fields. Can somebody explain what I'm doing wrong or is it a bug?
P.S. Sql Server 2008 10.0.3798
Edit
I just removed char column from the table to investigate what does SSMS generate. It generated actually the same as you described.
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
--DROP INDEXes here
--GO
ALTER TABLE dbo.Softs DROP COLUMN TitleHashCChar, TitleHashChar
GO
ALTER TABLE dbo.Softs SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
So I think we can assume that table options are correct.
After that I repeated select statements but with the same execution plan as before...
Edit
I resolved to task using simple binary fields and Insert/Update triggers to update them. Works like a charm. But it is still unclear why it has so strange behavior?..
Make sure your set options are correct, from BOL Link
SET Option Requirements
The ANSI_NULLS connection-level option must be set to ON when the CREATE TABLE or ALTER TABLE statement that defines the computed column is executed. The OBJECTPROPERTY function reports whether the option is on through the IsAnsiNullsOn property.
The connection on which the index is created, and all connections trying INSERT, UPDATE, or DELETE statements that will change values in the index, must have six SET options set to ON and one option set to OFF. The optimizer ignores an index on a computed column for any SELECT statement executed by a connection that does not have these same option settings.
The NUMERIC_ROUNDABORT option must be set to OFF, and the following options must be set to ON:
ANSI_NULLS
ANSI_PADDING
ANSI_WARNINGS
ARITHABORT
CONCAT_NULL_YIELDS_NULL
QUOTED_IDENTIFIER
Setting ANSI_WARNINGS to ON implicitly sets ARITHABORT to ON when the database compatibility level is set to 90. If the database compatibility level is set to 80 or earlier, the ARITHABORT option must explicitly be set to ON. For more information, see SET Options That Affect Results.

Varchar(255) to Varchar(MAX)

Is it possible to change a column type in a SQL Server 2008 database from varchar(255) to varchar(MAX) without having to drop the table and recreate?
SQL Server Management Studio throws me an error every time I try to do it using that - but to save myself a headache would be nice to know if I can change the type without having to DROP and CREATE.
Thanks
You should be able to do it using TSQL.
Something like
ALTER TABLE [table] ALTER COLUMN [column] VARCHAR(MAX)
'Saving changes is not permitted. The
changes you have made require the
following tables to be dropped and
re-created. You have either made
changes to a table that can't be
re-created or enabled the option
Prevent saving changes that require
table to be re-created.' Option
'Prevent saving changes' is not
enabled..
That's a new "feature" in SQL Server Management Studio 2008 which by default is turned on. Whenever you make a larger change, SSMS can only recreate the table by creating a new one and then moving over the data from the old one - all in the background (those changes include re-ordering of your columns amongst other things).
This option is turned off by default, since if your table has FK constraints and stuff, this way of re-doing the table might fail. But you can definitely turn that feature on!
It's under Tools > Options and once you uncheck that option you can do these kind of changes to table structure in the table designer again.
Be aware
with Something like
ALTER TABLE [table] ALTER COLUMN [column] VARCHAR(MAX)
https://dba.stackexchange.com/questions/15007/change-length-of-varchar-on-live-prod-table
Martin Smith's answare:
If you are increasing it to varchar(100 - 8000) (i.e. anything other than varchar(max)) and you are doing this through TSQL rather than the SSMS GUI ALTER TABLE YourTable ALTER COLUMN YourCol varchar(200) [NOT] NULL and not altering column nullability from NULL to NOT NULL (which would lock the table while all rows are validated and potentially written to or from NOT NULL to NULL in some circumstances then this is a quick metadata only change. It might need to wait for a SCH-M lock on the table but once it acquires that the change will be pretty much instant.
One caveat to be aware of is that during the wait for a SCH-M lock other queries will be blocked rather than jump the queue ahead of it so you might want to consider adding a SET LOCK_TIMEOUT first.
Also make sure in the ALTER TABLE statement you explicitly specify NOT NULL if that is the original column state as otherwise the column will be changed to allow NULL.