Декларация переменной Case Case и использование в MS SQL SERVER - PullRequest
0 голосов
/ 27 сентября 2018

Я использую MySQL для моего приложения Shiny.Я использую этот запрос для приложения, и он отлично работает.

Select
    concat(monthname(date_of_test), '-', year(date_of_test)) as 'Time',
    product_group AS 'ProductGroup',
    Pass,
    Case
        when pass='N' then @no:=count(distinct serial_number)
        when pass='Y' then count(distinct serial_number)-@no
    end as Count
from test_data 
where 
    year(date_of_test)=2018 
    and product_group='BHO'
    and month(date_of_test) between 3 and 4
group by
    product_group,
    month(date_of_test),
    pass

Но мне нужно изменить его в MS SQL Server.Я попытался объявить переменную и использовать ее как в SQL Server.

Моя попытка в SQL Server:

declare @no int;
set @no = 0;
Select
    CONCAT(datename(MM, date_of_test), '-', DATENAME(YY,date_of_test)) as 'Time',
    product_group AS 'ProductGroup',
    Pass,
    case
        when pass ='N' then  @no = count(distinct serial_number)    
        when pass ='Y' then count(distinct serial_number)- @no  
    end as 'Count'
from test_data 
where
    year(date_of_test)=2018 
    and product_group='BHO'
    and month(date_of_test) between 3 and 5
group by
    product_group,
    CONCAT(datename(MM, date_of_test),
    '-',
    DATENAME(YY,date_of_test)),
    pass    

Запрос без переменной выглядит так:

 Select
    CONCAT(datename(MM, date_of_test), '-', DATENAME(YY,date_of_test)) as 'Time',
    product_group AS 'ProductGroup',
    Pass,
    case
        when pass ='N' then count(distinct serial_number)    
        when pass ='Y' then count(distinct serial_number)
    end as 'Count'
from test_data 
where 
    year(date_of_test)=2018 and product_group='BHO'
    and month(date_of_test) between 3 and 4
group by
    product_group,
    CONCAT(datename(MM, date_of_test),
    '-',
    DATENAME(YY,date_of_test)),
    pass 

и он производит следующий вывод:

enter image description here

Требуемый вывод был похож на MySQL.пожалуйста, посмотрите, где Pass = Y, а затем вычтено значение Pass = N.

enter image description here

Показывает ошибку. Кто-нибудь может мне помочь?этот?Если потребуется дополнительная информация, я могу предоставить.Мое первоначальное предположение: в MySQL я могу инициализировать переменную в запросе и использовать ее в нем, но в MS SQL Server могут быть и другие правила.Мой синтаксис или процесс могут быть неверными.Спасибо заранее за помощь.

Select Count(distinct serial_number) from Test_Data where year(date_of_test)=2018 and product_group='BHO'and month(date_of_test)=4

503

Select Count(distinct serial_number) from Test_Data where year(date_of_test)=2018 and product_group='BHO' and PASS='Y' and month(date_of_test)=4

503

Select Count(distinct serial_number) from Test_Data where year(date_of_test)=2018 and product_group='BHO' and PASS='N'and month(date_of_test)=4

71

ТАК все 503 продукта (серийный номер) прошли многократное тестирование и получилиПроход = значение Y, но 71 продукт прошел тот же тест, где он потерпел неудачу в некоторых случаях, когда он отмечен как Проход = N.Так что, если я могу вычислить (отличный серийный номер с PASS = y) - (отличный серийный номер с PASS = N), то он даст количество продуктов, которые пройдут все тесты.

Я могу сделать это, и результат:

Select CONCAT(datename(MM, date_of_test),'-',DATENAME(YY,date_of_test)) as 'Time',product_group AS 'ProductGroup',
                    (Count(Distinct case when PASS='Y' then serial_number end)-Count(Distinct case when PASS='N' then serial_number end)) 
                 as ' All Test Passed',
                 Count(Distinct case when PASS='N' then serial_number end) as 'Min 1 Test Failed'
               from test_data 
               where 
               year(date_of_test)=2018 
               and 
               month(date_of_test) between 3 and 4
               and product_group='BHO'
               group by product_group,CONCAT(datename(MM, date_of_test),'-',DATENAME(YY,date_of_test))

И результат enter image description here

1 Ответ

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

Похоже, что запрос MySQL пытается эмулировать аналитические функции LEAD() или LAG(), представленные в MySQL 8. Они были доступны в SQL Server с 2012 года (я думаю).

Запрос MySQLпредполагается, что результаты будут возвращены в определенном порядке, даже если нет предложения ORDER BY.Также предполагается, что параллельной обработки не существует, по крайней мере, при обработке переменной.

Весь CASE может быть переписан как:

count(distinct serial_number) - 
LAG(count(distinct serial_number),1,0) OVER (
                        PARTITION BY product_group,month 
                        ORDER BY pass)

Это разделяет результаты GROUP BY на product_group,month, а затем заказывает их по pass.LAG затем возвращает предыдущий счет в этом разделе или 0, если предыдущей строки нет.Это означает, что LAG() вернет 0 для N и число N для Y

Полный запрос будет выглядеть так:

select 
    year(date_of_test),
    month(date_of_test),
    product_group,
    pass,
    count(distinct serial_number) - 
    LAG( COUNT(distinct serial_number),1,0) 
         OVER ( PARTITION BY product_group,month(date_of_test) 
                ORDER BY pass)
from test_data
where 
    year(date_of_test)=2018 
    and month(date_of_test) between 3 and 4
    and product_group='BHO'
group by 
    year(date_of_test),
    month(date_of_test),
    product_group,
    pass

Аналогичный запрос может работать с MySQL 8.

Производительность и сам запрос можно улучшить лот с помощью таблицы Календаря .Календарная таблица - это таблица, предварительно заполненная, например, датами на 20 лет, которая содержит дополнительные поля, такие как месяц, название месяца, номер недели, рабочий или праздничный день и т. Д. Это значительно упрощает написание запросов на основе дат, а результирующие запросы - намного быстрее.,

Предполагая, что существует таблица calendar только с несколькими основными полями, такими как дата, год, месяц, имя_монта, можно упростить запрос до следующего:

select 
    calendar.month_name + '-' + calendar.year,
    product_group,
    pass,
    count(distinct serial_number) - 
    LAG( COUNT(distinct serial_number),1,0) 
         OVER ( PARTITION BY product_group,calendar.month 
                ORDER BY pass)
from 
    test_data
    inner join calendar on date_of_test=date
where 
    calendar.year =2018 
    and calendar.month between 3 and 4
    and product_group='BHO'
group by 
    calendar.year,
    calendar.month,
    product_group,
    pass

Этот запрос может занятьпреимущество индексов в столбцах date_of_test, calendar.date, calendar.year и calendar.month для поиска результатов.

...