ハードウェアモデルと結果によってデータをグループ化する作業クエリがありますが、問題は多くの"results"があることです。これを"結果= 0の場合は0のままにし、それ以外の場合は1に設定"に減らすことを試みました。これは一般に機能しますが、最終的には次のようになります。
day | name | type | case | count
------------+----------------+------+------+-------
2013-11-06 | modelA | 1 | 0 | 972
2013-11-06 | modelA | 1 | 1 | 42
2013-11-06 | modelA | 1 | 1 | 2
2013-11-06 | modelA | 1 | 1 | 11
2013-11-06 | modelB | 1 | 0 | 456
2013-11-06 | modelB | 1 | 1 | 16
2013-11-06 | modelB | 1 | 1 | 8
2013-11-06 | modelB | 3 | 0 | 21518
2013-11-06 | modelB | 3 | 1 | 5
2013-11-06 | modelB | 3 | 1 | 7
2013-11-06 | modelB | 3 | 1 | 563
私が達成しようとしている集計の代わりに、タイプ/ケースのコンボごとに1行のみです。
day | name | type | case | count
------------+----------------+------+------+-------
2013-11-06 | modelA | 1 | 0 | 972
2013-11-06 | modelA | 1 | 1 | 55
2013-11-06 | modelB | 1 | 0 | 456
2013-11-06 | modelB | 1 | 1 | 24
2013-11-06 | modelB | 3 | 0 | 21518
2013-11-06 | modelB | 3 | 1 | 575
私のクエリは次のとおりです。
select CURRENT_DATE-1 AS day, model.name, attempt.type,
CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END,
count(*)
from attempt attempt, prod_hw_id prod_hw_id, model model
where time >= '2013-11-06 00:00:00'
AND time < '2013-11-07 00:00:00'
AND attempt.hard_id = prod_hw_id.hard_id
AND prod_hw_id.model_id = model.model_id
group by model.name, attempt.type, attempt.result
order by model.name, attempt.type, attempt.result;
これを達成するためのヒントは素晴らしいものです。
日は常にWHERE
句で定義されるため、変動しません。 name, type, result(case)
とcount
は異なります。つまり、特定のモデルでは、"type + case" comboごとに1行だけが必要です。最初の結果セットでわかるように、modelA
には3つの行があり、type=1
およびcase=1
があります(多くの"result"値があるため) = 0およびelse = 1)になりました。例のデータセット2のように集計された1行で表されるようにします。
クエリは既に機能しています-ただし、名前の競合が発生したり、出力列(CASE
式)をsource columnresult
、内容が異なります。
...
GROUP BY model.name, attempt.type, attempt.result
...
ソース列の代わりにCASE
式をGROUP BY
する必要があります。
...
GROUP BY model.name, attempt.type
, CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END
...
または、FROM
リストの列名とは異なるcolumn aliasを指定します-または、その列が優先されます:
SELECT ...
, CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END AS result1
...
GROUP BY model.name, attempt.type, result1
...
SQL標準は、この点でかなり独特です。 ここでマニュアルを引用:
出力列の名前は、
ORDER BY
句とGROUP BY
句で列の値を参照するために使用できますが、WHERE
句またはHAVING
句では使用できません。そこで、代わりに式を書き出す必要があります。
そして:
ORDER BY
式が出力列名と入力列名の両方に一致する単純な名前である場合、ORDER BY
はそれを出力列名として解釈します。 これは、GROUP BY
が同じ状況でにする選択の反対です。この不整合は、SQL標準との互換性を保つために行われます。
太字強調鉱山。
これらの競合は、GROUP BY
およびORDER BY
で位置参照(序数)を使用し、SELECT
リストの項目を左から右に参照することで回避できます。以下の解決策を参照してください。
欠点は、これが読みにくく、SELECT
リストの編集に対して脆弱である可能性があることです(それに応じて位置参照を調整することを忘れる可能性があります)。
ただし、定数値(GROUP BY
)を保持している限り、CURRENT_DATE-1
句に列day
を追加する必要はありませんnot。
適切なJOIN構文と位置参照を使用して書き直し簡略化すると、次のようになります。
SELECT m.name
, a.type
, CASE WHEN a.result = 0 THEN 0 ELSE 1 END AS result
, CURRENT_DATE - 1 AS day
, count(*) AS ct
FROM attempt a
JOIN prod_hw_id p USING (hard_id)
JOIN model m USING (model_id)
WHERE ts >= '2013-11-06 00:00:00'
AND ts < '2013-11-07 00:00:00'
GROUP BY 1,2,3
ORDER BY 1,2,3;
また、列名time
を避けていることに注意してください。これは 予約語 であり、識別子として使用しないでください。また、「時間」は明らかに timestamp
またはdate
であるため、かなり誤解を招く可能性があります。
これを試してみてください:caseステートメントを以下のものに置き換えてください
Sum(CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END) as Count,
他の2つの非COUNT列をGROUP BYに追加してみてください。
select CURRENT_DATE-1 AS day,
model.name,
attempt.type,
CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END,
count(*)
from attempt attempt, prod_hw_id prod_hw_id, model model
where time >= '2013-11-06 00:00:00'
AND time < '2013-11-07 00:00:00'
AND attempt.hard_id = prod_hw_id.hard_id
AND prod_hw_id.model_id = model.model_id
group by 1,2,3,4
order by model.name, attempt.type, attempt.result;
TSQLの場合、caseステートメントを外部適用にカプセル化します。これにより、caseステートメントを2回記述する必要がなくなり、将来の結合でエイリアスによるcaseステートメントへの参照が可能になり、位置参照の必要がなくなります。
select oa.day,
model.name,
attempt.type,
oa.result
COUNT(*) MyCount
FROM attempt attempt, prod_hw_id prod_hw_id, model model
WHERE time >= '2013-11-06 00:00:00'
AND time < '2013-11-07 00:00:00'
AND attempt.hard_id = prod_hw_id.hard_id
AND prod_hw_id.model_id = model.model_id
OUTER APPLY (
SELECT CURRENT_DATE-1 AS day,
CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END result
) oa
group by oa.day,
model.name,
attempt.type,
oa.result
order by model.name, attempt.type, oa.result;