2

SQL Server seems to go out of its way to remove a COLLATE restriction on a nvarchar column if the collation is the DB default. My DB default is SQL_Latin1_General_CP1_CI_AS. If I create a table thus:

CREATE TABLE [dbo].[UserActive](
    [Id] [uniqueidentifier] NOT NULL,
    [DateCreated] [datetimeoffset](7) NOT NULL,
    [Username] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [Password] [nvarchar](max) NULL,
    [Email] [nvarchar](254) NOT NULL,
 CONSTRAINT [PK_UserActive] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

... then ask SQL Server Management Studio to script the table as a CREATE statement, I get the following:

CREATE TABLE [dbo].[UserActive](
    [Id] [uniqueidentifier] NOT NULL,
    [DateCreated] [datetimeoffset](7) NOT NULL,
    [Username] [nvarchar](50) NOT NULL,
    [Password] [nvarchar](max) NULL,
    [Email] [nvarchar](254) NOT NULL,
 CONSTRAINT [PK_UserActive] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Is there any way I can retain the explicit COLLATE even if it's the DB default? I want to be explicit about the fact that any unique index I add on the Username column will have that case-insensitive collation, even if the DB default is changed for some reason. It's nice and self-documenting, which is lost without the explicit collation as part of the table definition.

5
  • Side note: plain-text passwords are a real bad idea. You should salt-and-hash them, and store them in a varbinary column. I also can't imagine why it would be null. Mar 28 at 20:58
  • 1
    How do you know I'm storing them in plaintext?
    – Jez
    Mar 28 at 21:58
  • Because they are in an nvarchar(max) field. Surely you wouldn't store a binary hash in a Unicode text field? Also the name is a bit telltale, you would normally call it PasswordHash or similar to make it more obvious. Mar 28 at 22:04
  • .NET's PasswordHasher simply returns a string containing the salted hash.
    – Jez
    Mar 28 at 22:06
  • Probably because it's used in HTTP headers and the like (where binary values can be a bit weird) so it returns a Base64 of the hash. You can still un-base64 it on the database side to store it. But either way it certainly doesn't need max. Mar 28 at 22:11

1 Answer 1

5

SSMS scripting options (Tools-->Options-->SQL Server Object Explorer-->Scripting-->Table and view options) allow you to include the COLLATE clause (or not) when scripting objects:

SSMS Scripting options

9
  • That goes from one extreme to the other, scripting all of them, though. Also, I suspect it's deriving those default collections from the DB default and the fact that there's no explicit collation on the column. Is SQL Server actually storing those collations explicitly internally? Would they all magically change if the DB default were changed?
    – Jez
    Mar 28 at 14:23
  • @Jez, true but consider that without the collation, the script could be run against a database with a different default collation. The resultant column collation would differ in that case.
    – Dan Guzman
    Mar 28 at 14:27
  • Yeah but I guess I'm thinking that for certain columns that'd be ok, but for others I want the colation to explicitly stay the same.
    – Jez
    Mar 28 at 14:32
  • 3
    @Jez, seems you should keep the source code (scripts) in a version control system rather than reverse-engineering. That would provide full control over the collation clauses.
    – Dan Guzman
    Mar 28 at 14:44
  • 1
    @Jez re: "Is SQL Server actually storing those collations explicitly internally?" Yes, every string column (XML excluded) has an explicitly specified collation. The only times the collation is inferred from the database default is: 1) when creating tables and adding/altering columns, and 2) in queries when COLLATE DATABASE_DEFAULT is specified. re: "Would they all magically change if the DB default were changed?" No, once the column exists, you would need to explicitly ALTER TABLE ... ALTER COLUMN in order to change its collation. Mar 28 at 16:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.