Рефакторинг SQL-запроса - PullRequest
       1

Рефакторинг SQL-запроса

0 голосов
/ 15 сентября 2018

У меня есть приведенный ниже SQL-запрос, и я хотел бы изменить его. Я довольно новичок в SQL, но я узнал кое-что, что я не должен повторять в запросах.

SELECT id,
(​SELECT​ ​COUNT​(*)​ ​FROM​ Table_1 ​
WHERE​ T3.​Id ​=​ randomID)​ ​AS​ ​'Column One Count'​,

(​SELECT​ ​COUNT​(*)​ ​FROM​ Table_2 ​
WHERE​ T3.​Id ​=​ randomID)​ ​AS​ ​'Column Two Count'​,

((​SELECT​ ​COUNT​(*)​ ​FROM​ Table_2 
​WHERE​ T3.​Id ​=​ randomID)​ ​/​

(​SELECT COUNT​(*)​ ​FROM​ Table_1 ​
WHERE​ T3.​Id ​=​ randomID))​ ​*​ 100 ​AS​ 'Column Three Percentage' 
FROM Table_3 T3

Мне посоветовали не использовать SELECT * часто, поэтому я заменил каждое вхождение на:

SELECT COUNT(randomID)

Это дает мне тот же результат. Я все еще думаю, что могу объединить повторяющиеся элементы в более сжатый запрос, но мой уровень SQL просто недостаточно хорош.

Как можно реорганизовать этот код, чтобы избежать повторения похожих запросов?

Ответы [ 3 ]

0 голосов
/ 15 сентября 2018

Простой подход использует apply:

select t3.id, t1.col1_cnt, t2.col2_cnt,
       t2.col2_cnt * 100.0 / t1.col1_cnt as col3_percentage
from Table_3 t3 outer apply
     (select count(*) as col1_cnt
      from table_1 t1
      where t3.id = t1.randomid
     ) t1 outer apply
     (select count(*) as col2_cnt
      from table_2 t2
      where t3.id = t2.randomid
     ) t2;

apply, по существу, позволяет перемещать коррелированные подзапросы в предложение from.Как только они появятся, вы можете ссылаться на столбцы, которые они генерируют более одного раза.

РЕДАКТИРОВАТЬ:

Если вас беспокоит деление на ноль, используйте nullif():

select t3.id, t1.col1_cnt, t2.col2_cnt,
       t2.col2_cnt * 100.0 / nullif(t1.col1_cnt, 0) as col3_percentage
0 голосов
/ 15 сентября 2018

Мое предложение:

With CountT1 as (
select f1.randomID, count(*) NbT1
from Table_1 f1 inner join Table_3 f3 on f3.Id=f1.randomID
group by f1.randomID
),
CountT2 as (
select f1.randomID, count(*) NbT2
from Table_2 f1 inner join Table_3 f3 on f3.Id=f1.randomID
group by f1.randomID
)
select T3.Id, 
isnull(T1.NbT1, 0) as ​'Column One Count', 
isnull(T2.NbT2, 0) as ​'Column Two Count', 
case when T1.NbT1=0 then null else (T2.NbT2 /  T1.NbT1) * 100.0 end  as 'Column Three Percentage'
from Table_3 T3
left outer join CountT1 T1 on T3.Id=T1.randomID
left outer join CountT2 T2 on T3.Id=T2.randomID
0 голосов
/ 15 сентября 2018

для подсчета, вы можете просто объединить таблицы; как то так:

select Ct = count(1)
from table_1
where Id = @RandomId
union 
select count(1)
from table_2
where Id = @RandomId'

Я не выделил все столбцы, но, надеюсь, общая идея имеет смысл.

Что касается вещи select *, в общем, вы правы, избегая по ряду причин (включая то, что это просто больше данных, чем вам, вероятно, нужно, уязвимые для изменений в схеме и в значительной степени стреляющие некластеризованные индексы в наколенниках). В старых версиях SQL это распространялось на такие вещи, как count(*). Однако, пока вы используете SQL 2008+, count() (и несколько других предложений, таких как EXISTS) достаточно умен, чтобы фактически не выделять какие-либо столбцы. Итак, если вы просто хотите посчитать каждую строку (даже нули), все это эквивалентно

select 
    count(1),
    count(*),  
    count(primarykeycolumn) -- guaranteed not to be null
from myTable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...