わかりました、タイトルが紛らわしいことは知っていますが、ここにあります。ところで、私はSQL Server2008を使用しています
ストレージコンテナとして使用しようとしているテーブルがあります。 3つの列があります。
reportID integer,
dataLabel varchar(50),
dataValue sql_variant
これを使用する方法は、reportID
を関数に渡し、正確に型指定されたテーブル変数を関数に返すことです。正確に入力されたパーツを除いて、プロセスがダウンしています。
以下は、一時テーブルを作成し、いくつかの値を挿入し、使用したいテーブル変数に値をピボットするスクリプトです。問題は、各列に返される値のタイプがsql_variant
であり、それらをbaseTypeに変換する方法がわからないことです。 sql_variant_property
を使用しようとしましたが(失敗しました)、理解できません。
たとえば、ファイナルテーブルでは、myDate
列をsql_variant
タイプではなくdateTime
タイプにします。
私を正しい方向に推し進めることができるSQLの達人はいますか?
create table #rStorage
(
reportID bigint not null
, dataLabel varchar (50) null
, dataValue sql_variant null
)
go
insert into #rStorage (reportID, datalabel, datavalue)
values (1, 'myInt', convert(int,5621))
insert into #rStorage (reportID, datalabel, datavalue)
values (1, 'mydate', convert(smalldatetime,getdate()))
insert into #rStorage (reportID, datalabel, datavalue)
values (1, 'myvarchar', convert(varchar(200),'testing Varchar'))
insert into #rStorage (reportID, datalabel, datavalue)
values (1, 'mydateNoTconverted', getDate())
select reportID
, dataLabel
, dataValue
into #tmp
from #rStorage
declare @QuestionList nvarchar(max)
, @qry nvarchar(max)
SELECT @QuestionList = STUFF(
(SELECT ', ' + quotename(dataLabel)
FROM #tmp
GROUP BY dataLabel
ORDER BY dataLabel
FOR XML PATH(''))
, 1, 2, '');
select @qry = '
select *
from #tmp
pivot
(
max(dataValue)
for dataLabel in ('+@QuestionList+')
) as q
'
print @qry
exec sp_executesql @qry;
drop table #tmp
drop table #rStorage
ストアドプロシージャはテーブル変数を返すことができないため、最終的な目標はudfです。だから私はカーソルといくつかの動的SQLでこれを試しました。私は近いと思いますが、以下の関数でエラーが発生します
関数と一部の拡張ストアドプロシージャのみを関数内から実行できます。重大度16状態2
コード:
if exists (select * from sysobjects where name = N'fn_pivotReportStorage')
drop function fn_pivotReportStorage
go
create function fn_pivotReportStorage
(@reportID bigint)
returns @result table (reportID bigint)
as
begin
declare @dataLabel sql_variant
, @dataValue sql_variant
, @dataType sql_variant
, @alterTableStr nvarchar(max)
declare thisCursor Cursor fast_forward for
select dataLabel
, dataValue
, dataType = case SQL_VARIANT_PROPERTY(dataValue,'BaseType')
when 'varchar' then convert(varchar(50),SQL_VARIANT_PROPERTY(dataValue,'BaseType'))+'('+convert(varchar(50),SQL_VARIANT_PROPERTY(dataValue,'maxLength'))+')'
else SQL_VARIANT_PROPERTY(dataValue,'BaseType') end
FROM reportStorage
where reportID = @reportID
insert into @result (reportID) values (@reportID)
open thisCursor
fetch next from thisCursor into @dataLabel,@dataValue,@dataType
while @@fetch_status = 0
begin
select @alterTableStr = 'alter table @result add '+ convert(varchar(2000),@dataLabel)+' '+ convert(varchar(2000),@dataType)
exec sp_executesql @alterTableStr;
select @alterTableStr = 'update @result set '+ convert(varchar(2000),@dataLabel)+' = ''' +convert(varchar(2000),@dataValue)+''''
exec sp_executesql @alterTableStr;
fetch next from thisCursor into @dataLabel,@dataValue,@dataType
end
close thisCursor
deallocate thisCursor
return
end
go
あなたが試みていることに多くの問題があり、この特定のアプローチがうまくいくとは思わない(目標は興味深いと思う):
returns @result table (reportID bigint)
-これは基本的にスキーマにバインドされています。返されたテーブルのスキーマを変更することはできません。後で、この変数を「ALTER」しようとしますが、それは起こりません。
できたとしても、この部分:
select @alterTableStr = 'alter table @result add '+ convert(varchar(2000),@dataLabel)+' '+ convert(varchar(2000),@dataType) ;
exec sp_executesql @alterTableStr;
外側の部分の@resultに影響を与えることはありません-これらの動的SQL部分には独自のスコープがあり、この方法で呼び出し側の部分の変数にアクセスすることはできません
そして、それは本当にあなたが現在得ているエラーに帰着します-それはとにかく関数内で実行できないsp_executesqlです。
とにかく、少し進歩するのを助けるために、CSVとJSONデータの解析に関して接線方向に関連している(そして私は最近使用した)次の2つの記事を読むことをお勧めします。どちらも彼の階層のアイデア(ピボットされていない名前/値のもの)とリピボットを使用しており、そこでいくつかの便利なテクニックを見つけることができます。
http://www.simple-talk.com/sql/t-sql-programming/the-tsql-of-csv-comma-delimited-of-errors/
http://www.simple-talk.com/sql/t-sql-programming/sumption-json-strings-in-sql-server/
CLRを使用できる場合は、公開されたこの記事も役立つ可能性があります。