の簡素化(アンチエイリアス)T-SQL場合には記述です。改善可能ですか?
-
11-09-2019 - |
質問
ご覧の通り、この吸い込みます。他の代替?たってのカラムの別名のグループによる条項が無い.
select count(callid) ,
case
when callDuration > 0 and callDuration < 30 then 1
when callDuration >= 30 and callDuration < 60 then 2
when callDuration >= 60 and callDuration < 120 then 3
when callDuration >= 120 and callDuration < 180 then 4
when callDuration >= 180 and callDuration < 240 then 5
when callDuration >= 240 and callDuration < 300 then 6
when callDuration >= 300 and callDuration < 360 then 7
when callDuration >= 360 and callDuration < 420 then 8
when callDuration >= 420 and callDuration < 480 then 9
when callDuration >= 480 and callDuration < 540 then 10
when callDuration >= 540 and callDuration < 600 then 11
when callDuration >= 600 then 12
end as duration
from callmetatbl
where programid = 1001 and callDuration > 0
group by case
when callDuration > 0 and callDuration < 30 then 1
when callDuration >= 30 and callDuration < 60 then 2
when callDuration >= 60 and callDuration < 120 then 3
when callDuration >= 120 and callDuration < 180 then 4
when callDuration >= 180 and callDuration < 240 then 5
when callDuration >= 240 and callDuration < 300 then 6
when callDuration >= 300 and callDuration < 360 then 7
when callDuration >= 360 and callDuration < 420 then 8
when callDuration >= 420 and callDuration < 480 then 9
when callDuration >= 480 and callDuration < 540 then 10
when callDuration >= 540 and callDuration < 600 then 11
when callDuration >= 600 then 12
end
編集:私たい方にはシングルの場合のソースの場合の修正おねが少ないので、参考になったと考える間隔であろうと変更されるかもしれは自動的にする。
していることができれば一人callDurationであることからfloat一部上場の解決に有効で私用の場合、値の間隔とします。
授
見のためのパターンの表現の動きをタイムリーかつ可能であればやりがいのある
case when callDuration > 0 AND callDuration < 30 then 1 when callDuration > 600 then 12 else floor(callDuration/60) + 2 end end as duration
使用インラインビューシングルソースの場合
select count(d.callid), d.duration from ( select callid , case when callDuration > 0 AND callDuration < 30 then 1 when callDuration > 600 then 12 else floor(callDuration/60) + 2 end end as duration from callmetatbl where programid = 1001 and callDuration > 0 ) d group by d.duration
利用共通のテーブル表現
with duration_case as ( select callid , case when callDuration > 0 AND callDuration < 30 then 1 when callDuration > 600 then 12 else floor(callDuration/60) + 2 end end as duration from callmetatbl where programid = 1001 and callDuration > 0 ) select count(callid), duration from duration_case group by duration
利用ユーザ定義関数(えい:-))
またはルックアップテーブルおよび参加
DECLARE @t TABLE(durationFrom float, durationTo float, result INT) --populate table with values so the query works select count(callid) , COALESCE(t.result, 12) from callmetatbl JOIN @t AS t ON callDuration >= t.durationFrom AND callDuration < t.durationTo where programid = 1001 and callDuration > 0
おかげさまで、私はとても難しい時間を選択受け答えとして多くの対象の異なる部品の問題としたい考えで簡単な質問とを素直に答え:-)、申し訳ありませんの混乱).
解決
Q: これからのエイリアスでの、GROUP BY節の
その際の一つのアプローチは、インラインビュー。[編集]その答えらRemus Rusanu(+1!) たとえば共通のテーブル表現の達成に同じことをしているのです。[編集]
のインラインビューが簡単な"エイリアス"は、複雑な表現できるその参照によって、GROUP by条項の外側のクエリ:
select count(d.callid)
, d.duration
from (select callid
, case
when callDuration >= 600 then 12
when callDuration >= 540 then 11
when callDuration >= 480 then 10
when callDuration >= 420 then 9
when callDuration >= 360 then 8
when callDuration >= 300 then 7
when callDuration >= 240 then 6
when callDuration >= 180 then 5
when callDuration >= 120 then 4
when callDuration >= 60 then 3
when callDuration >= 30 then 2
when callDuration > 0 then 1
--else null
end as duration
from callmetatbl
where programid = 1001
and callDuration > 0
) d
group by d.duration
みを開梱します。
- 内(インデント)クエリーとも呼ばれ、 インラインビュー (まさかの別名
d
) - 外側のクエリーまで参考のエイリアス
duration
からd
するのに十分お答えします。今までと同等の交換用表情を一から tekBlues (+1 ! の正解では境界および非整数です。)
の交換用表情からtekBlues(+1!):
select count(d.callid)
, d.duration
from (select callid
, case
when callduration >=30 and callduration<600
then floor(callduration/60)+2
when callduration>0 and callduration< 30
then 1
when callduration>=600
then 12
end as duration
from callmetatbl
where programid = 1001
and callDuration > 0
) d
group by d.duration
(これは十分にお答えします。)
[更新]サンプル ユーザー定義の関数 (交換のためのインラインの場合に表現)
CREATE FUNCTION [dev].[udf_duration](@cd FLOAT)
RETURNS SMALLINT
AS
BEGIN
DECLARE @bucket SMALLINT
SET @bucket =
CASE
WHEN @cd >= 600 THEN 12
WHEN @cd >= 540 THEN 11
WHEN @cd >= 480 THEN 10
WHEN @cd >= 420 THEN 9
WHEN @cd >= 360 THEN 8
WHEN @cd >= 300 THEN 7
WHEN @cd >= 240 THEN 6
WHEN @cd >= 180 THEN 5
WHEN @cd >= 120 THEN 4
WHEN @cd >= 60 THEN 3
WHEN @cd >= 30 THEN 2
WHEN @cd > 0 THEN 1
--ELSE NULL
END
RETURN @bucket
END
select count(callid)
, [dev].[udf_duration](callDuration)
from callmetatbl
where programid = 1001
and callDuration > 0
group by [dev].[udf_duration](callDuration)
注記: こともできますユーザ定義関数の追加オーバーヘッド(コース)追加の依存関係が別のデータベース上のオブジェクトです。
この例では、機能は同等の表現です。OPの場合表現を持たない隙間では参考にそれぞれの"ブレークポイント"など、う検査(けいぶけんさ)のみを下行します。(ケースを返しますが、条件を満足しています。この試験は逆で、独自のレンダリングメカニズムの場合(<=0またはNULL)から抜け落ちなく、 ELSE NULL
必要はなくなり、追加するためにご提供しています。
詳細はこちらから
(必ず確認してください性能とバージョンのオプティマイザのプランは、してください同じではないが大幅に悪化している、オリジナルです。過去においしく述語に押され、インラインビュー、見せていないが問題になるケースがあるようです。
保ビュー
ことに注意 インライン ビューが蓄積することもできるビュー定義のデータベースです。がないこと以外は"非表示"の複雑な表現からです。
簡素化し、複雑な表現
他に複雑な表現が"簡単"ではユーザー定義機能です。ユーザが定義され機能が付属し、独自の設定の問題を含むが劣化します。)
追加データベース"のルックアップテーブル"
その答えをお勧めしを追加する"ルックアップテーブルのデータベースです。いることが必要です。ですがもちろん、意味だしていきたいと考えている異なった値 duration
から callDuration
, は、フライ、 なし を変更検索すると、 なし ることを実行で異例変更は、ビュー定義は変更するユーザー定義機能)。
と共にルックアップテーブルで、利用するクエリを異なる結果セットだけを行うDMLの"ルックアップ"。
でもこの利点が実際に欠点です。
を十分考慮した場合に実際に比して著しくは下記です。-に与える影響を考慮した新しいテーブルにおいてユニット検査方法を確認する内容のルックアップテーブルを有効とな変更(いず重複?みず?), 影響の継続的なメンテナンスのコードにより追加の複雑性).
一部の大前提
多くの答えがここに掲載されていることによる callDuration
整数であるdatatype.どうやって見るのではない整数、からだったので買ってきたことを含有の問題をもたらしていました。
かなり簡単なテストケースと:
callDuration BETWEEN 0 AND 30
は ない 相当
callDuration > 0 AND callDuration < 30
他のヒント
あなたはbetween
を使用していない何らかの理由はありますか? case文自体はそれほど悪くは見えません。あなたが本当にそれを嫌う場合は、テーブルにこのすべてを投げ、それをマップすることができます。
Durations
------------------
low high value
0 30 1
31 60 2
など...
(SELECT value FROM Durations WHERE callDuration BETWEEN low AND high) as Duration
編集:または、フロートが使用されているとbetween
が煩雑になった場合に
(SELECT value FROM Durations WHERE callDuration >= low AND callDuration <= high) as Duration
の場合は、次のように書くことができます:
case
when callduration >=30 and callduration<600 then floor(callduration/60)+2
when callduration>0 and callduration< 30 then 1
when callduration>=600 then 12
end
、必要に応じてそれを交換しないでされた "どこcallduration> 0"
私は前に与えられた変換テーブルの答えが好き!それが最善の解決策だ。
必要なものを押し込む場合はさらに下のクエリのツリーその投影が見える、グループです。このときの達成には二つの方法:
- 利用派生テーブル(スペンサーは、アダムとジェレミー-ラウ)
共用ステーブル式
with duration_case as ( select callid , case when callDuration > 0 and callDuration < 30 then 1 when callDuration >= 30 and callDuration < 60 then 2 when callDuration >= 60 and callDuration < 120 then 3 when callDuration >= 120 and callDuration < 180 then 4 when callDuration >= 180 and callDuration < 240 then 5 when callDuration >= 240 and callDuration < 300 then 6 when callDuration >= 300 and callDuration < 360 then 7 when callDuration >= 360 and callDuration < 420 then 8 when callDuration >= 420 and callDuration < 480 then 9 when callDuration >= 480 and callDuration < 540 then 10 when callDuration >= 540 and callDuration < 600 then 11 when callDuration >= 600 then 12 end as duration from callmetatbl where programid = 1001 and callDuration > 0 ) select count(callid), duration from duration_case group by duration
両方の解に相当。見CTEsは、読みやすくするためにも好由来表しています。
分割 callDuration
60:
case
when callDuration between 1 AND 29 then 1
when callDuration > 600 then 12
else (callDuration /60) + 2 end
end as duration
ご注意 between
ここでは境界がないと思うのを想定しcallDurationとすることとなる整数です。
更新:
せることその他の回答するまで、全体のクエリをこの:
select count(d.callid), d.duration
from (
select callid
, case
when callDuration between 1 AND 29 then 1
when callDuration > 600 then 12
else (callDuration /60) + 2 end
end as duration
from callmetatbl
where programid = 1001
and callDuration > 0
) d
group by d.duration
select count(callid), duration from
(
select callid ,
case
when callDuration > 0 and callDuration < 30 then 1
when callDuration >= 30 and callDuration < 60 then 2
when callDuration >= 60 and callDuration < 120 then 3
when callDuration >= 120 and callDuration < 180 then 4
when callDuration >= 180 and callDuration < 240 then 5
when callDuration >= 240 and callDuration < 300 then 6
when callDuration >= 300 and callDuration < 360 then 7
when callDuration >= 360 and callDuration < 420 then 8
when callDuration >= 420 and callDuration < 480 then 9
when callDuration >= 480 and callDuration < 540 then 10
when callDuration >= 540 and callDuration < 600 then 11
when callDuration >= 600 then 12
end as duration
from callmetatbl
where programid = 1001 and callDuration > 0
) source
group by duration
未テスト:
select count(callid) , duracion
from
(select
callid,
case
when callDuration > 0 and callDuration < 30 then 1
when callDuration >= 30 and callDuration < 60 then 2
when callDuration >= 60 and callDuration < 120 then 3
when callDuration >= 120 and callDuration < 180 then 4
when callDuration >= 180 and callDuration < 240 then 5
when callDuration >= 240 and callDuration < 300 then 6
when callDuration >= 300 and callDuration < 360 then 7
when callDuration >= 360 and callDuration < 420 then 8
when callDuration >= 420 and callDuration < 480 then 9
when callDuration >= 480 and callDuration < 540 then 10
when callDuration >= 540 and callDuration < 600 then 11
when callDuration >= 600 then 12
else 0
end as duracion
from callmetatbl
where programid = 1001) GRP
where duracion > 0
group by duracion
テーブル変数にすべてのケースを追加し、外部結合を行う
DECLARE @t TABLE(durationFrom INT, durationTo INT, result INT)
-- when callDuration > 0 and callDuration < 30 then 1
INSERT INTO @t VALUES(1, 30, 1);
-- when callDuration >= 30 and callDuration < 60 then 2
INSERT INTO @t VALUES(30, 60, 2);
select count(callid) , COALESCE(t.result, 12)
from callmetatbl JOIN @t AS t ON callDuration >= t.durationFrom AND callDuration < t.durationTo
where programid = 1001 and callDuration > 0
ここでの私のショットです。必要なコンポーネントのすべてがストレートSQLで行うことができます。
select
count(1) as total
,(fixedDuration / divisor) + adder as duration
from
(
select
case/*(30s_increments_else_60s)*/when(callDuration<60)then(120)else(60)end as divisor
,case/*(increment_by_1_else_2)*/when(callDuration<30)then(1)else(2)end as adder
,(/*duration_capped@600*/callDuration+600-ABS(callDuration-600))/2 as fixedDuration
,callDuration
from
callmetatbl
where
programid = 1001
and
callDuration > 0
) as foo
group by
(fixedDuration / divisor) + adder
ここで私がテストに使用されるSQLです。 の(私は私自身の個人callmetatblを持っていません。)の
select
count(1) as total
,(fixedDuration / divisor) + adder as duration
from
(
select
case/*(30s_increments_else_60s)*/when(callDuration<60)then(120)else(60)end as divisor
,case/*(increment_by_1_else_2)*/when(callDuration<30)then(1)else(2)end as adder
,(/*duration_capped@600*/callDuration+600-ABS(callDuration-600))/2 as fixedDuration
,callDuration
from -- callmetatbl -- using test view below
(
select 1001 as programid, 0 as callDuration union
select 1001 as programid, 1 as callDuration union
select 1001 as programid, 29 as callDuration union
select 1001 as programid, 30 as callDuration union
select 1001 as programid, 59 as callDuration union
select 1001 as programid, 60 as callDuration union
select 1001 as programid, 119 as callDuration union
select 1001 as programid, 120 as callDuration union
select 1001 as programid, 179 as callDuration union
select 1001 as programid, 180 as callDuration union
select 1001 as programid, 239 as callDuration union
select 1001 as programid, 240 as callDuration union
select 1001 as programid, 299 as callDuration union
select 1001 as programid, 300 as callDuration union
select 1001 as programid, 359 as callDuration union
select 1001 as programid, 360 as callDuration union
select 1001 as programid, 419 as callDuration union
select 1001 as programid, 420 as callDuration union
select 1001 as programid, 479 as callDuration union
select 1001 as programid, 480 as callDuration union
select 1001 as programid, 539 as callDuration union
select 1001 as programid, 540 as callDuration union
select 1001 as programid, 599 as callDuration union
select 1001 as programid, 600 as callDuration union
select 1001 as programid,1000 as callDuration
) as callmetatbl
where
programid = 1001
and
callDuration > 0
) as foo
group by
(fixedDuration / divisor) + adder
2つのレコード12を介して各期間(バケット)1について数えてSQL出力は、以下に示されている。
total duration
2 1
2 2
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 12
ここで「foo」というサブクエリから結果があります
divisor adder fixedDuration callDuration
120 1 1 1
120 1 29 29
120 2 30 30
120 2 59 59
60 2 60 60
60 2 119 119
60 2 120 120
60 2 179 179
60 2 180 180
60 2 239 239
60 2 240 240
60 2 299 299
60 2 300 300
60 2 359 359
60 2 360 360
60 2 419 419
60 2 420 420
60 2 479 479
60 2 480 480
60 2 539 539
60 2 540 540
60 2 599 599
60 2 600 600
60 2 600 1000
乾杯ます。
ここでユーザー定義関数を持つので、間違っているのですか?あなたは、両方の視覚的コードをクリーンアップし、そのような機能を一元化できます。性能面では、私はあなたが本当に遅く何かをやっている場合を除きヒットがあまりにも恐ろしいものを見ることができないと述べた内UDFます。
duration
のためのルックアップテーブルを作成します。
ルックアップテーブルを使用することで、同様SELECT
文をスピードアップします。
ここでは、ルックアップテーブルでどのように見えるかの最終的な結果がある。
select count(a.callid), b.ID as duration
from callmetatbl a
inner join DurationMap b
on a.callDuration >= b.Minimum
and a.callDuration < IsNUll(b.Maximum, a.CallDuration + 1)
group by b.ID
ここでルックアップテーブルです。
create table DurationMap (
ID int identity(1,1) primary key,
Minimum int not null,
Maximum int
)
insert DurationMap(Minimum, Maximum) select 0,30
insert DurationMap(Minimum, Maximum) select 30,60
insert DurationMap(Minimum, Maximum) select 60,120
insert DurationMap(Minimum, Maximum) select 120,180
insert DurationMap(Minimum, Maximum) select 180,240
insert DurationMap(Minimum, Maximum) select 240,300
insert DurationMap(Minimum, Maximum) select 300,360
insert DurationMap(Minimum, Maximum) select 360,420
insert DurationMap(Minimum, Maximum) select 420,480
insert DurationMap(Minimum, Maximum) select 480,540
insert DurationMap(Minimum, Maximum) select 540,600
insert DurationMap(Minimum) select 600