string_agg と for xml path

before Sqlserver2017
select
replace((select Column as [data()] from Table for xml path()),’ ‘,’,’) as CSVcolumn

Sqlserver2017
select
string_agg(Column,’,’) as CSVcolumn from Table

before Sqlserver2017
select
Z.PKcolumn
,Z.columnA
,Z.columnB
,row_number() over (order by Z.columnB asc) Seq
,replace((select Z.columnD as [data()] from Table where Z.PKcolumn=PKcolumn for xml path(”)),’ ‘,’,’) Member
from Table as Z
group by PKcolumn,columnA,columnB

Sqlserver2017
select
Z.PKcolumn
,Z.columnA
,Z.columnB
,row_number() over (order by Z.columnB asc) Seq
,string_agg(Z.columnD,’,’) Member
from Table as Z
group by PKcolumn,columnA,columnB

Null 空文字列

Null でよく勘違いする
SQLserverテーブルでもMYSQLテーブルでも 数値型のカラムにnullを入れることはできる
テーブル設計でnullを許可にすれば良いだけの話

変数にnullを代入するのは不可能な場合もある

VBAでは
dim Var as long
var=null
は不可能、stringはOK stringもだめです
variantだけ可能

ではSQLserverでも同じだろうと思ったら
declare @Var int
set @Var=null
select @Var
とクエリを発行したらNullが返ってきた

では宣言のみで代入なしは?(=初期値?)
SQLserver
declare @Var int
select @Var
は Null
nvarcharでも同様

VBAは複雑
dim Var as long
debug.print Var
はなんと 0

dim Var as string
debug.print Var
は 空白
調べるとこれNullではなく ”” つまり空文字列

役立ちそうにない知識でしょうが一応書き留めておきます

また日付

今日 2018-10-19 の日付で

select case when current_timestamp>’2018-10-18′ then ‘true’ else ‘false’ end;
はSQLserverでもMYSQLでもtrue

select case when current_timestamp>’2018-10-20′ then ‘true’ else ‘false’ end;
はSQLserverでもMYSQLでもfalse

でもVBAでは
debug.print iif(now>”2018-10-18”,true,false)
はfalseとなってしまう
debug.print iif(now>cdate(“2018-10-18”),true,false)
としないとだめ

日付は型宣言や型変換するようにしないといけないですかね

VBAからselect into #table できることもある

Dim Parm As Long
Param= **
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.ConnectionString = “接続文字列”
cn.Open

cn.Execute “drop table if exists #table”
cn.Execute “select * into #table from Other where column=” & Param
cn.execute “update #table set ・・・”
以下略

シンプルにこれだけならば#テーブルは作成されますが

Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
cn.ConnectionString = “接続文字列”
Set rs = New ADODB.Recordset
cn.Open

rs.open “SQL文”,cn,・・・
以下略

cn.Execute “drop table if exists #table”
cn.Execute “select * into #table from Other where column=” & Param
cn.execute “update #table set ・・・”
以下略

と複雑になるとオブジェクトは無効ですとエラーです。

なぜかはわかりませんがレコードセットが必要ならprivate sub を別に作って
callにしたらうまくいきます。

Nullには要注意 と Alterカラムデータ型


カラム2が数値型の場合
select * from Table where カラム2<>8
ではカラム2がnullを選択しない nullを選びたいときは別に条件を明示の必要ありか


似ているけど
カラム2は文字型
select * from Table where カラム2<>‘8’
では空文字列のカラム2を選択する
空文字列とNullが混在するテーブルがあるときは要注意

mysqlもSQLserverも同じ

あとカラムデータ型変更
SQLserverは
alter Table TableA alter Column ColumnA nvarchar(255) null;
Mysqlは
alter table TableA modify Column ColumnA varchar(255) null;

CursorLocation CursorType LockType

recordsetプロパティが意図通りにならないことがあるのはわかりました。

https://blogs.msdn.microsoft.com/nakama/2008/10/16/ado/
の下の方に表が出ています。
SQLserverの場合だと思います。

同じようにMysql5.7で調べてみると

結果がSQLserverと少し違います。

赤文字は意図と結果が違う
斜めはSQLserverと結果が違う

aduseclientにした時点でstatic決定は同じでした。
aduseserverでstaticになってますがrecordset.countは-1でした。

CursorLocation CursorType

前回の続き vbaからsqlserverへ
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
 cn.ConnectionString = “SQLserver接続文字列”
 cn.open
Set rs = New ADODB.Recordset
 rs.CursorLocation = adUseClient ’前回はcnにしたけど今回はrs

rs.open “select・・・・”,cn,adopendynamic,adlockoptmistic
debug.print rs.recordcount
debug.print rs.cursortype

で返らないと思ったrecordcountがちゃんと返るのですが
rs.cursortypeを見るとどうもadopendynamicになってない

でこういうサイト見つけました
http://d.hatena.ne.jp/replication/20090312/1236866953
マイクロソフトのヘルプはリンク切れ

カーソル位置でカーソルタイプが決まる?のようです
adopendynamic adopenforwardonly がサーバサイド
adopenstatic adopenkeyset がクライアントサイド

adUseClientを明示したらadopenstaticが決定するのかな?

では今までほとんど明示していないのでデフォルトのサーバーサイドカーソルでadopenkeysetも矛盾あり?実はdynamicになっていた?
MysqlとSQLserverでも挙動に違いがありそうです。

カーソル位置とカーソルタイプとロックタイプは齟齬がないように組み合わせないと意図したようになってない可能性ありですか

難しいですrecordset

identityのあるテーブルのMERGE

以前identityのIDのテーブルにmergeはだめと書いた件

いちいちidendityを解除してmergeして再設定していたけど面倒くさいし元に戻すのを忘れると大変なことになる
identityはそのままにmergeさせる方法
mergeのクエリの前後に

set identity_insert TABLE on
MERGE・・・・略
set identity_insert TABLE off

identityのあるテーブルのMERGE
つまり
identity設定があるテーブルのIDに任意の値の入力を可能にする
任意と言ってももちろん一意である必要あり

データベース複製とTRUNCATE@SQLserver

SQLserverのデータベース複製で躓く
SSMSのデータベースコピーウィザードはなぜかエラーで使えない
エクスポートウィザードでできるが主キーの設定やトリガーなどはコピーしてくれない

データベースTESTDBを一度バックアップ
復元をクリック 復元先のデータベースをTESTDBcopyに書き換えて復元
その後TESTDBは復元中になって使えなくなっているのでこちらもあらためて復元しておく

さらにコピーしたデータベースのテーブルのレコード全削除とidendityのリセット(=truncate)する
CTEで全テーブルの一括truncateを試みたがCTEはselect update delete insertしか使えないようだ
exec sp_MSforeachtable @command1=”truncate table TESTDBcopy.?”
でOK

ダメでした

クエリ強制終了

MySQLで終わらないクエリ、ループなどを強制終了するには
show processlist;
をよく見て該当のクエリを見つけて
kill クエリのid;

SQLserverでは
exec sp_who
でクエリを見つけて
kill spid