T-SQL CREATE TABLE での FOREIGN KEY の指定で、ドキュメントに載ってない方法で出来た。。

CREATE TABLE (Transact-SQL) | Microsoft Docs

ドキュメントでは、CREATE TABLE での FOREIGN KEY 指定はテーブルで指定する方法と列で指定する方法の2パターンあります。

テーブル

< table_constraint > ::=  
 [ CONSTRAINT constraint_name ]  
{    
   { PRIMARY KEY | UNIQUE }  
     {   
       NONCLUSTERED (column [ ASC | DESC ] [ ,... n ])  
       | NONCLUSTERED HASH (column [ ,... n ] ) WITH ( BUCKET_COUNT = bucket_count )   
                    }   
    | FOREIGN KEY   
        ( column [ ,...n ] )   
        REFERENCES referenced_table_name [ ( ref_column [ ,...n ] ) ]   
    | CHECK ( logical_expression )   
}  

列(通常の列と計算列)

<column_constraint> ::=   
[ CONSTRAINT constraint_name ]   
{     { PRIMARY KEY | UNIQUE }   
        [ CLUSTERED | NONCLUSTERED ]   
        [   
            WITH FILLFACTOR = fillfactor    
          | WITH ( < index_option > [ , ...n ] )   
        ]   
        [ ON { partition_scheme_name ( partition_column_name )   
            | filegroup | "default" } ]  

  | [ FOREIGN KEY ]   
        REFERENCES [ schema_name . ] referenced_table_name [ ( ref_column ) ]   
        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]   
        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]   
        [ NOT FOR REPLICATION ]   

  | CHECK [ NOT FOR REPLICATION ] ( logical_expression )   
}

<computed_column_definition> ::=  
column_name AS computed_column_expression   
[ PERSISTED [ NOT NULL ] ]  
[   
    [ CONSTRAINT constraint_name ]  
    { PRIMARY KEY | UNIQUE }  
        [ CLUSTERED | NONCLUSTERED ]  
        [   
            WITH FILLFACTOR = fillfactor   
          | WITH ( <index_option> [ , ...n ] )  
        ]  
        [ ON { partition_scheme_name ( partition_column_name )   
        | filegroup | "default" } ]  

    | [ FOREIGN KEY ]   
        REFERENCES referenced_table_name [ ( ref_column ) ]   
        [ ON DELETE { NO ACTION | CASCADE } ]   
        [ ON UPDATE { NO ACTION } ]   
        [ NOT FOR REPLICATION ]   

    | CHECK [ NOT FOR REPLICATION ] ( logical_expression )   
]   

テーブルで指定するときは、自分の列と相手の列を指定する、
列で指定するときは、相手の列を指定する感じです。

ところで次の3つのクエリは全部同じ結果になります。

1: table_constraint で指定した場合

drop table if exists [Child]
drop table if exists [Parent]

create table [Parent] (
  [Id] int not null primary key
)
create table [Child] (
  [Id] int not null primary key, 
  [ParentId] int not null, 
  [Remark] nvarchar(max), 
  foreign key ([ParentId]) references [Parent]([Id])
)

2: column_constraint で指定した場合

drop table if exists [Child]
drop table if exists [Parent]

create table [Parent] (
  [Id] int not null primary key
)
create table [Child] (
  [Id] int not null primary key, 
  [ParentId] int not null foreign key references [Parent]([Id]),  
  [Remark] nvarchar(max)
)

3: column_constraint で指定した場合(他の列で指定している!)

drop table if exists [Child]
drop table if exists [Parent]

create table [Parent] (
  [Id] int not null primary key
)
create table [Child] (
  [Id] int not null primary key foreign key([ParentId]) references [Parent]([Id]), 
  [ParentId] int not null,   
  [Remark] nvarchar(max)
)

3: のパターンは、ドキュメントでは指定出来ないはずなんだけどどうなんですかね?
バグだったとしても実害はないでしょうけど。

.NET Core 2.0 の TransactionScope + SqlClient でハマってる。。

まだ対応してない?

using System;
using System.Data.SqlClient;
using System.Transactions;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            var connstr = @"~";
            using (var tran = new TransactionScope())
            using (var conn = new SqlConnection(connstr))
            {
                conn.Open(); // 例外発生!
            }
        }
    }
}
System.NotSupportedException: 'Enlisting in Ambient transactions is not supported.'

ScriptDom に Azure SQL DB / (DW?) 用に使えそうなオプションが増えてました

久々に ScriptDom のバージョンを上げてみたら、SqlEngineType が追加されてました。
NuGet Gallery | Microsoft.SqlServer.TransactSql.ScriptDom 14.0.3660.1

TSql130Parser, TSql140Parser に SqlEnginType が渡せるようです。

namespace Microsoft.SqlServer.TransactSql.ScriptDom
{
    public enum SqlEngineType
    {
        All = 0,
        Standalone = 1,
        SqlAzure = 2
    }
}

未だちゃんと動かなそうでしたが。

var azure = new TSql140Parser(false, SqlEngineType.SqlAzure);
IList<ParseError> azureErrors;
using (var sr = new StringReader(@"CREATE DATABASE hito 
COLLATE Japanese_Bushu_Kakusu_100_CS_AS_KS_WS   
( MAXSIZE = 500 MB, EDITION = 'standard', SERVICE_OBJECTIVE = 'S1' );")) {
  azure.Parse(sr, out azureErrors);
}
Console.WriteLine(azureErrors.Count); // 1
Console.WriteLine(azureErrors[0].Message); // Incorrect syntax near MAXSIZE.

SQL DB では使える CREATE DATABASE のオプションがエラーになってしまいました。。

T-SQL に TRANSLATE 文字列関数が追加されてた

たまたまドキュメントを眺めてて見つけたのでメモ
TRANSLATE (Transact-SQL) | Microsoft Docs

Oracle にはあったので追加されるのは助かりますね。

ちなみに Oracle でのよくある例

-- ぱぴぷぴぽぴぴぴ となる
select translate('パピプペポ', 'パピプペポ', 'ぱぴぷぺぽ') 
from dual

は、エラーになりました。

select translate('パピプペポ', 'パピプペポ', 'ぱぴぷぺぽ')
The second and third arguments of the TRANSLATE built-in function must contain an equal number of characters.

ちゃんと文字数が一致していないとダメなようです。

9/9(土) 第6回 関西DB勉強会 開催します!

今回も色んな DB の話しを用意しています!
kansaidbstudy.connpass.com

SQL Server は 2017 の Linux 絡みのお話しをして頂きます!

懇親会は勉強会会場でケータリングの予定です、こちらも是非宜しくお願いします。
kansaidbstudy.connpass.com

是非ご参加を~