Вернуть процентный столбец, используя самостоятельное соединение с фильтрацией предложения WHERE только для числителя - PullRequest
0 голосов
/ 28 мая 2018

ОБНОВЛЕНИЕ 31 мая 2018: Включен SQLFiddle, в надежде, что кто-нибудь может найти решение.

Следующая функция содержит два CTE с именами QuirksCTE и SurplusCTE. Оба этих CTE должны фильтровать числитель дроби, тогда как знаменатель этой дроби должен наследовать только фильтрующий эффект QuirksCTE.Цель состоит в том, чтобы произвести процент (подмножество, разделенное на множество).Числитель и знаменатель упомянутой дроби связаны друг с другом посредством самосоединения.Суть проблемы заключается в следующем: я по-прежнему не могу выборочно применять 2 фильтра CTE к числителю этого САМОСОЕДИНЕНИЯ, применяя только один из этих фильтров CTE к знаменателю.До сих пор каждая попытка перегруппировать и реструктурировать оператор where и объединения приводил к тому, что знаменатель игнорировал все фильтры и собирал каждую строку данных (в примере базы данных есть 7 строк).Обратите внимание, что в конце я буду использовать функцию FORMAT для обработки преобразования дроби в процент, но сейчас я игнорирую эту более косметическую задачу.

Чтобы использовать скрипту, связанную с ниже, вы должны датьФункция входного параметра из этой маленькой таблицы.Мои ручные вычисления предсказывают связанный «правильный выходной параметр», к которому я до сих пор не могу прийти, используя SQL.

Input Parameter       Correct Output Parameter
     0                       0
     1                      .5
     2                      .666
     3                      .666

http://sqlfiddle.com/#!18/ae5a1/1 (Требуется вызов функции и входная переменная из диаграммыпоказано выше).

--This is a user defined function containing 2 CTE's and a SELECT 
--statement with 2 joins and a WHERE clause. I included that structural 
--detail in case it makes a difference.


CREATE FUNCTION [dbo].[ExampleOfQueryStructure] 
(
    @MyInputParameter int
)
RETURNS 
@MyOutputParameter TABLE 
(
    [MyPercentage] float          
)
AS
BEGIN
WITH    Quirks_CTE (AnimalDateTime, Quirks) 
        AS   
           (SELECT 
               AnimalDateTime,
               (COALESCE (Lion, 0) + COALESCE (Zebra, 0) 
               + COALESCE (Antelope, 0) + COALESCE (Giraffe, 0)) 
           FROM dbo.tblAnimals),

        Surplus_CTE 
        AS
           (SELECT 
               JobEntryDateTime,
               CASE 
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel5-BeginLevel
                  ELSE BeginLevel-ExitLevel5
               END AS [5_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel8-BeginLevel
                  ELSE BeginLevel-ExitLevel8
               END AS [8_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel20-BeginLevel
                  ELSE BeginLevel-ExitLevel20
               END AS [20_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevelStone-BeginLevel
                  ELSE BeginLevel-ExitLevelStone
               END AS [StoneProfit]

        FROM dbo.tblJobEntries)


INSERT INTO @MyOutputParameter ([MyPercentage])
   SELECT 
       COUNT(a.Quirks)/COUNT(b.Quirks)
       FROM QuirksCTE b
       LEFT OUTER JOIN QuirksCTE a 
           ON b.AnimalDateTime = a.AnimalDateTime
              where exists(select 1 from Surplus_CTE c
                           where a.AnimalDateTime = c.JobEntryDateTime
                           AND ([5_SURPLUS] > 0 OR [8_SURPLUS] > 0 
                                OR [20_SURPLUS] > 0 OR [StoneProfit] > 0)   
                           AND a.Quirks <= @MyInputParameter)

RETURN
END

1 Ответ

0 голосов
/ 31 мая 2018

Как я упоминал в комментариях, ваш WHERE делает ваш LEFT JOIN INNER JOIN (таким образом, оба значения одинаковы), так как вы заставляете записи совпадать на их дату.Это исправленная функция.

CREATE FUNCTION [dbo].[ExampleOfQueryStructure] 
(
    @MyInputParameter int
)
RETURNS 
@MyOutputParameter TABLE 
(
    [MyPercentage] float
)
AS
BEGIN
WITH    Quirks_CTE (AnimalDateTime, Quirks) 
        AS   
           (SELECT 
               AnimalDateTime,
               (COALESCE (Lion, 0) + COALESCE (Zebra, 0) 
               + COALESCE (Antelope, 0) + COALESCE (Giraffe, 0)) 
           FROM dbo.tblAnimals),

        Surplus_CTE 
        AS
           (SELECT 
               JobEntryDateTime,
               CASE 
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel5-BeginLevel
                  ELSE BeginLevel-ExitLevel5
               END AS [5_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel8-BeginLevel
                  ELSE BeginLevel-ExitLevel8
               END AS [8_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel20-BeginLevel
                  ELSE BeginLevel-ExitLevel20
               END AS [20_SURPLUS]
            FROM dbo.tblJobEntries)

INSERT INTO @MyOutputParameter ([MyPercentage])
   SELECT 
       COUNT(a.Quirks) * 1.0 /COUNT(b.Quirks)
       FROM Quirks_CTE b
       LEFT OUTER JOIN Quirks_CTE a 
           ON b.AnimalDateTime = a.AnimalDateTime
              AND exists(select 1 from Surplus_CTE c
                           where a.AnimalDateTime = c.JobEntryDateTime
                           AND ([5_SURPLUS] > 0 OR [8_SURPLUS] > 0 
                                OR [20_SURPLUS] > 0)   
                           AND a.Quirks <= @MyInputParameter)

RETURN
END

Я также изменил возвращаемое значение на число с плавающей запятой (целочисленное значение вернет только 0 или 1).


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

WITH    Quirks_CTE (AnimalDateTime, Quirks) 
        AS   
           (SELECT 
               AnimalDateTime,
               (COALESCE (Lion, 0) + COALESCE (Zebra, 0) 
               + COALESCE (Antelope, 0) + COALESCE (Giraffe, 0)) 
           FROM dbo.tblAnimals),

        Surplus_CTE 
        AS
           (SELECT 
               JobEntryDateTime,
               CASE 
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel5-BeginLevel
                  ELSE BeginLevel-ExitLevel5
               END AS [5_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel8-BeginLevel
                  ELSE BeginLevel-ExitLevel8
               END AS [8_SURPLUS],

               CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevel20-BeginLevel
                  ELSE BeginLevel-ExitLevel20
               END AS [20_SURPLUS],

              CASE
                  WHEN tblJobEntries.Stance = 1
                  THEN ExitLevelStone-BeginLevel
                  ELSE BeginLevel-ExitLevelStone
               END AS [StoneSurplus]            

            FROM dbo.tblJobEntries),
       AnimalSurplus AS
       (
         SELECT
           Q.AnimalDateTime,
           Q.Quirks,
           Surplus = CASE WHEN [5_SURPLUS] > 0 OR [8_SURPLUS] > 0 OR [20_SURPLUS] > 0 OR [StoneSurplus] > 0 THEN 1 END
         FROM
           Quirks_CTE AS Q
           LEFT JOIN Surplus_CTE AS S ON Q.AnimalDateTime = S.JobEntryDateTime
         )
   -- SELECT * FROM AnimalSurplus
   SELECT 
       COUNT(a.Quirks) * 1.0 /COUNT(b.Quirks)
       FROM AnimalSurplus b
       LEFT OUTER JOIN AnimalSurplus a 
           ON b.AnimalDateTime = a.AnimalDateTime AND a.Surplus = 1
       WHERE b.Quirks <= @MyInputParameter
...