TSQL

2011-02-03 9 views
1

といくつかの統計私はいくつかのクラスに属することができる書類を持っているし、いくつかのトークン(言葉)を含めることができますを決定します。TSQL

create table Tokens (
     Id INT not null, 
     Text NVARCHAR(255) null, 
     primary key (Id) 
    ) 

create table DocumentClassTokens (
     Id INT not null, 
     DocumentFk INT null, 
     ClassFk INT null, 
     TokenFk INT null, 
     primary key (Id) 
    ) 

私は(クラス与えられたすべてのトークンのため)これらの統計情報を決定したいと思います:

  • A =トークン含むクラスに属する異なるドキュメントの数
  • B =トークン含むクラスに属していない別個のドキュメントの数
  • C =トークン含まれていない明確な文書の数と種類に属する
  • D =トークン含まれていませんし、クラス

に属していない明確な文書の数は、私は、現時点ではこれを使用していますが、それは正しく見えません(私はAとBの計算が正しいと確信しています)。

declare @class int; 

select @class = id from dbo.Classes where text = 'bla' 

;with A as 
(
    select 
     a.text as token, 
     count(distinct DocumentFk) as A 
    from dbo.Tokens as a 
    inner join dbo.DocumentClassTokens as b on a.id = b.TokenFk and b.ClassFk = @class 
    group by a.text 
) 
,B as 
(
    select 
     a.text as token, 
     count(distinct DocumentFk) as B 
    from dbo.Tokens as a 
    inner join dbo.DocumentClassTokens as b on a.id = b.TokenFk and b.ClassFk != @class 
    group by a.text 
) 
,C as 
(
    select 
     a.text as token, 
     count(distinct DocumentFk) as C 
    from dbo.Tokens as a 
    inner join dbo.DocumentClassTokens as b on a.id != b.TokenFk and b.ClassFk = @class 
    group by a.text 
) 
,D as 
(
    select 
     a.text as token, 
     count(distinct DocumentFk) as D 
    from dbo.Tokens as a 
    inner join dbo.DocumentClassTokens as b on a.id != b.TokenFk and b.ClassFk != @class 
    group by a.text 
) 
select 
    case when A is null then 0 else A end as A, 
    case when B is null then 0 else B end as B, 
    case when C is null then 0 else C end as C, 
    case when D is null then 0 else D end as D, 
    t.Text, 
    t.id 
from dbo.Tokens as t 
left outer join A as a on t.text = a.token 
left outer join B as b on t.text = b.token 
left outer join C as c on t.text = c.token 
left outer join D as d on t.text = d.token 
order by t.text 

フィードバックは非常に高く評価されるでしょう。どうもありがとう!

幸運を祈り、

クリスチャン

PS:

いくつかのテストデータ:

use play; 

drop table tokens 
create table Tokens 
(
    Id INT not null, 
    Text NVARCHAR(255) null, 
    primary key (Id) 
) 

insert into Tokens (id, text) values (1,'1') 
insert into Tokens (id, text) values (2,'2') 

drop table DocumentClassTokens 
create table DocumentClassTokens (
     Id INT not null, 
     DocumentFk INT null, 
     ClassFk INT null, 
     TokenFk INT null, 
     primary key (Id) 
    ) 

insert into DocumentClassTokens (Id,documentfk,ClassFk,TokenFk) values (1,1,1,1) 
insert into DocumentClassTokens (Id,documentfk,ClassFk,TokenFk) values (2,1,1,2) 
insert into DocumentClassTokens (Id,documentfk,ClassFk,TokenFk) values (3,2,1,1) 
insert into DocumentClassTokens (Id,documentfk,ClassFk,TokenFk) values (4,2,2,1) 
insert into DocumentClassTokens (Id,documentfk,ClassFk,TokenFk) values (5,3,2,1) 
insert into DocumentClassTokens (Id,documentfk,ClassFk,TokenFk) values (6,3,2,3) 
+0

あなたの説明では、(特定の?)トークンを含む、または含まないドキュメントに属しています。さて、あなたが私たちに提示したスクリプトでは、あなたは間違いなく '@ class'パラメータを宣言しています。したがって、それは確かに比較される*特定のクラスです。あなたの説明に従うと、あなたのスクリプトに '@ token'パラメータが宣言されていなければなりません。あるいは、「トークン*を含んでいますか?」(つまり、トークンを含んでいますか?)実際に何をすべきかを明確にしてください。 –

+0

@ Andriy M返事をありがとう。スクリプトは、4つの列トークンA、B、C、Dを持つテーブルを返す必要があります。クラスに与えられたすべてのトークンの統計を取得したいと思います。 – cs0815

答えて

1

あなたの質問は今より明確ようで、私が何かを見落としていない場合は、ここにあなたがあなたのデータに対して実行しようとするかもしれないクエリがあります。

DECLARE @class int; 
SET @class = 1; 

SELECT 
    TokenFk, 
    TokenClassDocs      AS A, 
    TokenNonClassDocs      AS B, 
    TotalClassDocs - TokenClassDocs AS C, 
    TotalNonClassDocs - TokenNonClassDocs AS D 
FROM (
    SELECT 
    TokenFk, 
    COUNT(DISTINCT CASE ClassFk WHEN @class THEN DocumentFk ELSE NULL END) AS TokenClassDocs, 
    COUNT(DISTINCT CASE ClassFk WHEN @class THEN NULL ELSE DocumentFk END) AS TokenNonClassDocs 
    FROM DocumentClassTokens dct 
    GROUP BY dct.TokenFk 
) AS bytoken 
    CROSS JOIN (
    SELECT 
     COUNT(DISTINCT CASE ClassFk WHEN @class THEN DocumentFk ELSE NULL END) AS TotalClassDocs, 
     COUNT(DISTINCT CASE ClassFk WHEN @class THEN NULL ELSE DocumentFk END) AS TotalNonClassDocs 
    FROM DocumentClassTokens 
) AS totals 

大丈夫であればお知らせください。


EDIT

上記溶液が間違っています。ここには固定されたものがありますが、間違ったバージョン(何が皮肉なのか...)と同じくらい私はそれを好きではありません。

DECLARE @class int; 
SET @class = 1; 

SELECT 
    TokenFk, 
    TokenClassDocs      AS A, 
    TokenNonClassDocs      AS B, 
    TotalClassDocs - TokenClassDocs AS C, 
    TotalNonClassDocs - TokenNonClassDocs AS D 
FROM (
    SELECT 
    TokenFk, 
    COUNT(DISTINCT cls.DocumentFk) AS TokenClassDocs, 
    COUNT(DISTINCT CASE WHEN cls.DocumentFk IS NULL THEN dct.DocumentFk END) AS TokenNonClassDocs 
    FROM DocumentClassTokens dct 
    LEFT JOIN (
     SELECT DISTINCT DocumentFk 
     FROM DocumentClassTokens 
     WHERE ClassFk = @class 
    ) cls ON dct.DocumentFk = cls.DocumentFk 
    GROUP BY dct.TokenFk 
) AS bytoken 
    CROSS JOIN (
    SELECT 
     COUNT(DISTINCT cls.DocumentFk) AS TotalClassDocs, 
     COUNT(DISTINCT CASE WHEN cls.DocumentFk IS NULL THEN dct.DocumentFk END) AS TotalNonClassDocs 
    FROM DocumentClassTokens dct 
     LEFT JOIN (
     SELECT DISTINCT DocumentFk 
     FROM DocumentClassTokens 
     WHERE ClassFk = @class 
    ) cls ON dct.DocumentFk = cls.DocumentFk 
) AS totals 

注:私は数字が間違っているかどうかをチェックする方法を今見ることができると思います。(つまり、すべてのトークンのための)すべての行ではA、B、C、Dの合計が合計に等しくなければなりませんすべての文書が1を満たし、4つのケースのうち1つしか探索されないので、驚くべきことではないはずの文書数。行の合計が総文書数と異なる場合、その行のいくつかの数字は確かに間違っています。

+0

ありがとうございます、月曜日にそれを見てください。 – cs0815

+0

申し訳ありません、何か間違っています。私は、3つのドキュメントと2つのトークンを含むテストデータベースでそれをテストしました。これは3行で応答します(トークンが2つしかないため、2行にしてください)。 – cs0815

+0

@csetzkorn:ここにサンプルデータを掲載し、その結果を作成するように頼んだら、あまりにも大きすぎますか? –

1

これはあなたの説明により、あなたがやりたい縫い目。あなたのコードを見ると、私はあまりよく分かりません。

編集1行の代わりに列を使用し、フィルターとして@ClassIDを使用します。

declare @ClassID int 
set @ClassID = 1 

;with cte(DokumentFk, TokenFk, ClassFk) as 
(
    select DocumentFk, max(TokenFK), max(ClassFk) 
    from DocumentClassTokens 
    where ClassFK = @ClassID 
    group by DocumentFK 
) 
select 
(select count(*) 
from cte 
where 
    TokenFk is not null and 
    ClassFk is not null) as A, 
(select count(*) 
from cte 
where 
    TokenFk is not null and 
    ClassFk is null) as B, 
(select count(*) 
from cte 
where 
    TokenFk is null and 
    ClassFk is not null) as C, 
(select count(*) 
from cte 
where 
    TokenFk is null and 
    ClassFk is null) as D 
+0

@Mikael Eriksson:AFAIK、集計は常に値を返します。おそらく、NULLチェックをゼロ比較で置き換えるべきです。 (私はまだスクリプトのロジックを分析していない。) –

+0

@Mikael Eriksson:私は正しかった。集約されたカラムがすべてNULLを持つ場合、もちろん 'MAX'もNULLを返さなければなりません。グループ化*を使って集計*を使用するときの微妙なことです。申し訳ありませんが、私は他の誰かの養成のために私のコメントを両方残しています。 –

+0

@Mikael Eriksson申し訳ありませんが、これは間違いなく動作しています – cs0815