web-dev-qa-db-ja.com

フィールドで分割された頻度分布

一部の背景:サンプルの母集団データファイルがあります。データファイルの各レコードには、実際の母集団を取得するためにレコードを複製する必要がある回数を示す頻度の重み(フィールド名:wgt)があります。データはMicrosoft SQL 2008 R2で設定されています。通常、重みの頻度分布を生成して、特定のタイプのレコードが何らかの方法で過剰に表現されているかどうかを確認することをお勧めします。したがって、傾向/外れ値を特定するのに役立ちます。このタスクはSQLでは簡単です。

SELECT wgt, COUNT(*) FROM tablename 
GROUP BY wgt

Challenge:これらの頻度を他の値に基づいてさらに分離したい。世帯のサイズごとの重みの度数分布を考えてみましょう。これを実現する1つの方法は、上記のステートメントで異なるwhere条件を使用することです。

SELECT wgt, COUNT(*) FROM tablename 
WHERE household_size=x --x being the desired segment
GROUP BY wgt

しかし、すべての異なるセグメントを持つ単一のテーブルを作成する方法はありますか?このようなもの:

WGT |   SIZE1       SIZE2       SIZE3       SIZE4 
--------------------------------------------------
1   |    2,034      1,025       502         234 
2   |    215        253         142         23 
3   |    31         25          21          34 
4   |    7          1           3           7 
5   |    5          NULL        2           5 
6   |    1          1           NULL        NULL 
7   |    NULL       1           NULL        NULL 

私が探しているより洗練されたソリューション:変数(たとえば、世帯のサイズや世帯収入)を指定するだけのストアドプロシージャであり、コードはそのすべての個別の値に対して個別の度数分布を生成できるはずですビュー/テーブルとしての変数。

考えている人はいますか?

5
sriramn

最初の挑戦として、このようなものを探していますか?

_SELECT wgt, SUM(Case when household_size=1 then 1 else 0 end) AS SIZE1
    , SUM(Case when household_size=2 then 1 else 0 end) AS SIZE2
    , SUM(Case when household_size=3 then 1 else 0 end) AS SIZE3
    , SUM(Case when household_size=4 then 1 else 0 end) AS SIZE4
FROM tablename
GROUP BY wgt
_

ここで、@ columnがspパラメータになる、より洗練されたチャレンジについて説明します。

_DECLARE @column VARCHAR(100);
SET @column = 'household_size';
DECLARE @main_SQL VARCHAR(4000);

SET @main_SQL =
    'DECLARE dynamic_cursor CURSOR FOR 
    SELECT DISTINCT ' + @column + '
    FROM tablename 
    ORDER BY ' + @column + ' 

    --Now we will be using a cursor to iterate over 
    DECLARE @value INT; 
    OPEN dynamic_cursor 
    FETCH NEXT FROM dynamic_cursor INTO @value 

    DECLARE @sql VARCHAR(2000); 
    SET @sql = ''SELECT wgt''; 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
        SET @sql = @sql + '', SUM(Case when ' + @column + '='' + CAST(@value AS VARCHAR) + '' then 1 else 0 end) AS SIZE'' + CAST(@value AS VARCHAR) 
        FETCH NEXT FROM dynamic_cursor INTO @value 
    END 
    SET @sql = @sql + '' FROM tablename GROUP BY wgt'' 

    close dynamic_cursor 
    DEALLOCATE dynamic_cursor 

    EXEC(@sql) '

EXEC(@main_SQL)
_

この部分は、カーソルに受け取ったテーブル名の列の個別の値を選択します

_DECLARE dynamic_cursor CURSOR FOR 
SELECT DISTINCT ' + @column + '
FROM tablename 
ORDER BY ' + @column + ' 
_

次に、個別の値を反復処理して、投稿の上部にあるクエリと同じように見えるクエリを動的に構築します。そのため、以下がその基礎です。
選択を開始します:

_SET @sql = ''SELECT wgt''
_

連続する, SUM(Case when household_size=n then 1 else 0 end) AS SIZEnを動的に選択に追加する反復部分(@valueは、カーソルに選択された個別の値になることに注意してください):

_SET @sql = @sql + '', SUM(Case when ' + @column + '='' + CAST(@value AS VARCHAR) + '' then 1 else 0 end) AS SIZE'' + CAST(@value AS VARCHAR)
_

選択を終了します。

_SET @sql = @sql + '' FROM tablename GROUP BY wgt''
_
3
JoseTeixeira

PIVOT演算子を使用する必要があります:

SELECT wgt, 
[SIZE1] as Size_1, [SIZE2] as Size_2, [SIZE3] as Size_3, [SIZE4] as Size_4

FROM
(select wgt, household_size from tablename)

PIVOT (
    COUNT (household_size)
    FOR household_size in ([SIZE1], [SIZE2] , [SIZE3] , [SIZE4])
)

ORDER BY wgt

[SIZE1], [SIZE2] , [SIZE3] , [SIZE4]-列として表示するhousehold_size列の値です。

この列のフィルターでhousehold_sizeの入力値を使用できるため、1つの集計列(全体で2列)を生成するストアドプロシージャははるかに簡単です。 WHERE句とHAVING句を使用したクエリは、うまく機能します。

2
Stoleg