[SQL Server] datetime 型は、なぜ 1753 年が下限なのか。

SQL Server の datetime 型は、1753 年 1 月 1 日から 9999 年 12 月 31 日までの日付範囲を持つ。従って、以下のような変換はエラーとなる。
DECLARE @d DATETIME = CONVERT(DATETIME,'1752')
-- varchar データ型から datetime データ型への変換の結果、範囲外の値になりました。
では、なぜ 1753 年から開始なのか。
それは datetime 型が「グレゴリオ暦」であることに起因している。

当時のイギリス帝国 (とその植民地) でグレゴリオ暦を採用した年が 1752 年であり、
通年としてグレゴリオ暦が始まったのが 1753 年からだからである。

グレゴリオ暦 (Wikipedia)

SQL Server 2008 からは dateime2 型が導入され、この型は 「西暦 1 年 1 月 1 日から西暦 9999 年 12 月 31 日 」の範囲となる。

歴史的な背景を知るとなかなか興味深い。

[SQL Server] IN 句にパラメータを指定する (ユーザー定義テーブル型)

IN 句をパラメータで指定させたいという要望はたまにあるが、動的に SQL 文を組み立てるくらいしか対処方法がなかった。しかし、SQL Server 2008 から追加された ユーザー定義テーブル型 によって似たような動きをさせることができる。
CREATE TABLE #HOGE
(
 USER_NO INT PRIMARY KEY IDENTITY
 ,NAME VARCHAR(40)
)
INSERT INTO
 #HOGE (NAME)
VALUES
 ('John')
 ,('David')
 ,('Jeffrey')
 ,('Sarrah')
 ,('Mary')

IF TYPE_ID(N'USERLIST') IS NULL
 CREATE TYPE USERLIST AS TABLE
 (
  NUM INT
 )
 GO

-- 削除する場合は以下のように記述。
-- DROP TYPE USERLIST

DECLARE @val AS USERLIST
INSERT INTO
 @val (NUM)
VALUES
 (1)
 ,(3)
SELECT * FROM #HOGE
-- USER_NO フィールドが 1 or 3 のデータを抽出する。
SELECT * FROM #HOGE WHERE USER_NO IN (SELECT NUM FROM @val)
ただ、上記のような要望がある場合は、カンマ区切りの文字列を展開したいという場合が多いだろう。カンマ区切りのデータを展開したいのなら、以下のような関数を定義するといい。

How to split a string according to a delimiter in Ms SQL Server 2008
http://howucando.com/2013/03/21/how-to-split-a-string-according-to-a-delimiter-in-ms-sql-server-2008/

[Excel 2007] フォームを表示する

  1. Office ボタンから、Excel のオプションを開く。
  2. [基本設定] - [Excel の使用に関する基本オプション] の [開発] タブをリボンに表示するにチェックオン。
オブジェクト自体を右クリックしてプロパティを表示させれば名称などの項目を設定できる。

[SQL Server] 同じ行に対して UPDATE または DELETE が複数回試行されました。

MERGE ステートメントで、同じ行に対して UPDATE または DELETE が複数回試行されました。これは、対象の行が基になる複数の行と一致する場合に発生します。MERGE ステートメントでは対象のテーブルの同じ行で複数回 UPDATE/DELETE を実行することはできません。対象の行と一致する基になる行が 1 つだけになるように ON 句を修正するか、GROUP BY 句を使用して基になる行をグループ化してください。

ややわかりづらいエラーメッセージ。
更新元レコードが複数あり、抽出条件を追加するか、グループ化することで一対になるようにしろということらしい。

TEST1

TEST2

このようなテーブルがあった際に、以下の MERGE 文を発行するとエラーとなる。
MERGE
 TEST1
USING
 TEST2
ON (TEST1.KEY1 = TEST2.KEY1)
WHEN MATCHED THEN
 UPDATE SET TEST1.SCORE = TEST2.SCORE
WHEN NOT MATCHED THEN
 INSERT (KEY1, NAME, SCORE) VALUES (KEY1, NAME, SCORE);
TEST2 テーブルのスコアを合算してマージする場合、以下のようにグループ化する。
MERGE
 TEST1
USING
 (
  SELECT
   KEY1
   ,NAME
   ,SUM(SCORE) AS SCORE
  FROM
   TEST2
  GROUP BY
   KEY1
   ,NAME 
 ) AS TEST2
ON (TEST1.KEY1 = TEST2.KEY1)
WHEN MATCHED THEN
 UPDATE SET TEST1.SCORE = TEST2.SCORE
WHEN NOT MATCHED THEN
 INSERT (KEY1, NAME, SCORE) VALUES (KEY1, NAME, SCORE);

結果は以下の通りになる。

TEST1

[Excel VBA] 先頭にシートを追加する

Worksheets.Add Before:=Worksheets(1)
先頭にあるシートをアクティブ状態にしてからシートを追加する方法もある。
Worksheets(1).Activate
Worksheets.Add
Range("A1").Activate