Упрощение (искажения) Операторов выбора T-SQL. Какое-либо возможное улучшение?

Вот мой код, как решить вышеуказанную проблему (при нажатии на ссылку запрашивается браузер по умолчанию, чтобы открыть ссылку)

import android.os.Bundle;import android.annotation.SuppressLint;import android.app.Activity;
import android.view.Menu;import android.webkit.WebChromeClient;
import android.webkit.WebView;public class MainActivity extends Activity{
`@SuppressLint("SetJavaScriptEnabled")@Override protected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);String url="http://google.com";WebView Webview=(WebView) this.findViewById(R.id.webView1);     Webview.getSettings().setJavaScriptEnabled(true);Webview.loadUrl(url);}@Override    public boolean onCreateOptionsMenu(Menu menu){//Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu);return true;}`}
5
задан Vinko Vrsalovic 5 June 2009 в 05:55
поделиться

11 ответов

Q: как получить псевдоним для использования в предложении GROUP BY

Один из подходов - использовать встроенное представление. [РЕДАКТИРОВАТЬ] Ответ от Ремуса Русану (+1! ) дает пример общего табличного выражения, выполняющего то же самое. [/ EDIT]

Встроенное представление дает вам простой «псевдоним» для сложного выражения, на которое вы затем можете ссылаться в предложении 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

(Этого должно быть достаточно, чтобы ответить на ваш вопрос.


[ОБНОВЛЕНИЕ:] пример пользовательская функция (замена встроенного выражения CASE)

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 CASE нет пробелов, но оно ссылается на каждую «точку останова» дважды, я предпочитаю проверять только нижнюю границу. (CASE возвращается, когда условие выполнено. Выполнение тестов в обратном порядке позволяет необработанному случаю (<= 0 или NULL) не пройти без проверки, ELSE NULL не является обязательным, но может быть добавлено для полноты.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

(Не забудьте проверить производительность и план оптимизатора, чтобы убедиться, что он такой же (или ненамного хуже) оригинала. Раньше у меня были проблемы с переносом предикатов во встроенное представление, не похоже, что это будет проблемой в вашем случае.)

сохраненное представление

Обратите внимание, что встроенное представление также может быть сохранено как определение представления в базе данных. Но нет никаких причин для этого, кроме как «скрыть» сложное выражение от вашего оператора.

упрощение сложного выражения

Другой способ сделать сложное выражение «проще» - использовать пользовательскую функцию. Но функция, определяемая пользователем, имеет свой собственный набор проблем (включая снижение производительности).

добавить «справочную» таблицу базы данных

В некоторых ответах рекомендуется добавить «справочную» таблицу в базу данных. Не думаю, что это действительно необходимо. Конечно, это можно сделать, и может иметь смысл, если вы хотите получить различные значения для длительности из callDuration на лету, без необходимости изменять свой запрос и ] без необходимости запускать какие-либо операторы DDL (например, для изменения определения представления или изменения пользовательской функции).

С присоединением к «поисковой» таблице одно преимущество состоит в том, что вы можете заставить запрос возвращать разные наборы результатов, просто выполняя операции DML с «поисковой» таблицей.

Но это же преимущество может быть недостатком.

Тщательно подумайте, действительно ли выгода перевешивает обратную сторону. Рассмотрим влияние, которое новая таблица окажет на модульное тестирование, как проверить, что содержимое справочной таблицы является действительным и не изменено (есть ли перекрытия? Есть ли пробелы?), влияние на текущее обслуживание кода (из-за дополнительной сложности).

некоторые БОЛЬШИЕ предположения

Многие ответы, приведенные здесь, похоже, предполагают, что callDuration является типом данных INTEGER. Кажется, они упустили возможность того, что это не целое число, но, возможно, я пропустил этот самородок в вопросе.

Это довольно простой тестовый пример, чтобы продемонстрировать, что:

callDuration BETWEEN 0 AND 30

НЕ эквивалентно

callDuration > 0 AND callDuration < 30
]
9
ответ дан 18 December 2019 в 05:29
поделиться

Есть ли причина, по которой вы не используете между ? Сами утверждения кейса выглядят неплохо. Если вам это действительно не нравится, вы можете бросить все это в таблицу и сопоставить.

Durations
------------------
low   high   value
0     30     1
31    60     2

и т. Д.

(SELECT value FROM Durations WHERE callDuration BETWEEN low AND high) as Duration

РЕДАКТИРОВАТЬ: Или, в случае, когда используются числа с плавающей запятой, и между становится громоздким.

(SELECT value FROM Durations WHERE callDuration >= low AND callDuration <= high) as Duration
9
ответ дан 18 December 2019 в 05:29
поделиться

случай можно записать так:

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

Наличие не требуется, замените его на "where callduration> 0"

Мне нравится приведенный выше ответ таблицы перевода! это лучшее решение

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

Наличие не требуется, замените его на "where callduration> 0"

Мне нравится приведенный выше ответ таблицы перевода! это лучшее решение

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

Наличие не требуется, замените его на "where callduration> 0"

Мне нравится приведенный выше ответ таблицы перевода! это лучшее решение

5
ответ дан 18 December 2019 в 05:29
поделиться

Вам нужно переместить CASE дальше вниз по дереву запроса, чтобы его проекция была видна для GROUP BY. Этого можно достичь двумя способами:

  1. Использовать производную таблицу (как уже показали Спенсер, Адам и Джереми)
  2. Использовать общие табличные выражения

     с duration_case как (
    выберите callid,
    кейс
     если callDuration> 0 и callDuration <30, то 1
     если callDuration> = 30 и callDuration <60, то 2
     если callDuration> = 60 и callDuration <120, то 3
     если callDuration> = 120 и callDuration <180, то 4
     если callDuration> = 180 и callDuration <240, то 5
     если callDuration> = 240 и callDuration <300, то 6
     если callDuration> = 300 и callDuration <360, то 7
     если callDuration> = 360 и callDuration <420, то 8
     если callDuration> = 420 и callDuration <480, то 9
     если callDuration> = 480 и callDuration <540, то 10
     если callDuration> = 540 и callDuration <600, то 11
     если callDuration> = 600, то 12
    конец как продолжительность
    из callmetatbl
    где programid = 1001 и callDuration> 0)
     выберите количество (callid), продолжительность
     from duration_case
     группировать по продолжительности
    

Оба решения эквивалентны во всех отношениях. Я считаю CTE более читаемыми, некоторые предпочитают производные таблицы как более переносимые.

4
ответ дан 18 December 2019 в 05:29
поделиться

Разделите callDuration на 60:

case
        when callDuration between 1 AND 29 then 1
        when callDuration > 600 then 12
        else (callDuration /60) + 2  end
end as duration

Обратите внимание, что между включает границы, и я предполагаю, что 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
2
ответ дан 18 December 2019 в 05:29
поделиться
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
1
ответ дан 18 December 2019 в 05:29
поделиться

Непроверено:

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
1
ответ дан 18 December 2019 в 05:29
поделиться

Добавьте все наблюдения в переменную таблицы и выполните внешнее соединение

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
1
ответ дан 18 December 2019 в 05:29
поделиться

Что плохого здесь в функции, определяемой пользователем? Таким образом можно было как визуально очистить код, так и централизовать функциональность. С точки зрения производительности, я не вижу, чтобы результат был слишком ужасным, если вы не делаете что-то действительно отсталое в указанном UDF.

1
ответ дан 18 December 2019 в 05:29
поделиться

Here's my shot at it. All of the components you need can be done in straight 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

Here's the SQL I used for testing. (I don't have my own personal 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

The SQL output is shown below, as 2 records counted for each duration (bucket) 1 through 12.

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

Here are the results from the "foo" sub-query:

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

Cheers.

1
ответ дан 18 December 2019 в 05:29
поделиться

Создание таблицы поиска на длительность
Использование таблицы поиска также ускорит выполнение оператора 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
1
ответ дан 18 December 2019 в 05:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: