Получить ближайшее значение к функции AVG TSQL - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть такой выбор:

SELECT
    FORMAT(AVG([DC].[ContractedAmount]) , '$###,###,###,###.##') AS [AverageContractedAmount]
FROM 
    [DesignCustomer] AS [DC]
INNER JOIN 
    [Design] AS [D] ON [DC].[DesignKey] = [D].[DesignKey]
INNER JOIN 
    [Task] AS [T] ON [D].[DesignKey] = [t].[DesignKey]
INNER JOIN 
    [ProjectDesign] AS [PD] ON [D].[DesignKey] = [PD].[DesignKey]
INNER JOIN 
    [Project] AS [P] ON [PD].[ProjectKey] = [P].[ProjectKey]
INNER JOIN 
    [Address] AS [A] ON [A].[AddressGuid] = [P].[ProjectGuid]

Как видите, я получаю Average Контрактной суммы.Я получаю что-то вроде этого:

+---------------------------+
| [AverageContractedAmount] |
+---------------------------+
| $1,000.00                 |
+---------------------------+

Теперь я хочу получить проект, который ближе к этому значению

Например, если у меня есть 5 проектов в таблице проектов, как:

+----------------+
|  ProjectName   |
+----------------+
| First Project  |
| Second Project |
| Third Project  |
| Four Project   |
| Five Project   |
+----------------+

Отношение [DC] к проекту выглядит примерно так:

+----------------+------------------+
|  ProjectName   | ContractedAmount |
+----------------+------------------+
| First Project  |              500 |
| Second Project |              700 |
| Third Project  |              300 |
| Four Project   |              950 |
| Five Project   |              800 |
+----------------+------------------+

Я хочу, чтобы запрос возвратил Four Project Name, поскольку его значение ContractedAmount ближе всего к AVGзначение.Как мне этого добиться?Привет

Ответы [ 4 ]

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

Похоже, что вы уже выяснили, как получить среднее значение, поэтому, взяв примерные таблицы, но утешительные, чтобы получить среднее значение в 1000 долларов, я написал один оператор выбора, используя среднее значение, чтобы получить ваш ответ.Для этого ответа я только что вычислил среднее значение из таблицы, а не из вашего кода, чтобы получить переменную @ AVERAGE.

    CREATE TABLE #Amts (Project VARCHAR(20), Amount INT);

    INSERT INTO #Amts 
    VALUES

    ('One Project', 500),
    ('Two Project', 1500),
    ('Three Project', 300),
    ('Four Project', 1700),
    ('Five Project', 1100),
    ('Six Project', 900)        ;

    DECLARE @AVERAGE INT = (SELECT AVG(Amount) FROM #Amts) -- $1000

    SELECT    TOP 1 Project -- Since you said whichever project is suitable, this should be fine. 
    FROM      #Amts AS A
    WHERE     ABS(A.Amount - @AVERAGE) = (SELECT MIN(ABS(Amin.Amount - @AVERAGE)) FROM #Amts AS Amin)
    ORDER BY  Project

    DROP TABLE #Amts

Это дает вам ответ «Пять проектов».

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

Строго ближе всего будет:

; WITH AvgAmt AS (
    SELECT AVG([DC].[ContractedAmount]) AS [AverageContractedAmount]
    FROM [DesignCustomer] AS [DC]
        INNER JOIN [Design] AS [D] ON [DC].[DesignKey] = [D].[DesignKey]
        INNER JOIN [Task] AS [T] ON [D].[DesignKey] = [t].[DesignKey]
        INNER JOIN [ProjectDesign] AS [PD] ON [D].[DesignKey] = [PD].[DesignKey]
        INNER JOIN [Project] AS [P] ON [PD].[ProjectKey] = [P].[ProjectKey]
        INNER JOIN [Address] AS [A] ON [A].[AddressGuid] = [P].[ProjectGuid]
)
SELECT TOP(1) P.ProjectName, DC.ContractedAmount
FROM [DesignCustomer] AS [DC]
    INNER JOIN [Design] AS [D] ON [DC].[DesignKey] = [D].[DesignKey]
    INNER JOIN [ProjectDesign] AS [PD] ON [D].[DesignKey] = [PD].[DesignKey]
    INNER JOIN [Project] AS [P] ON [PD].[ProjectKey] = [P].[ProjectKey]
ORDER BY ABS(AvgAmt.[AverageContractedAmount] - ContractedAmount);

В зависимости от ваших данных, вы можете исключить несколько INNER JOIN из самого CTE просто для повышения производительности, если данные не требуют этого.

Решение также может быть легко параметризовано для выбора ближайших @n контрактных сумм вместо ближайших (преобразование SELECT TOP(1) в SELECT TOP(@n)).

Кроме того, если есть несколько проектов с одинаковой разницей в средней контрактной сумме, вы можете добавить несколько других столбцов в ORDER BY, чтобы разорвать связь. Это то, что вы можете выбрать как тот, который знает, что представляют данные и что вы ожидаете от них.

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

с использованием DENSE_RANK:

WITH getavg AS (
SELECT AVG([DC].[ContractedAmount]) OVER() AS [AverageContractedAmount]
, p.projectname, p.contractedamount
 FROM [DesignCustomer] AS [DC]
                     INNER JOIN [Design] AS [D] ON [DC].[DesignKey] = [D].[DesignKey]
                     INNER JOIN [Task] AS [T] ON [D].[DesignKey] = [t].[DesignKey]
                     INNER JOIN [ProjectDesign] AS [PD] ON [D].[DesignKey] = [PD].[DesignKey]
                     INNER JOIN [Project] AS [P] ON [PD].[ProjectKey] = [P].[ProjectKey]
                     INNER JOIN [Address] AS [A] ON [A].[AddressGuid] = [P].[ProjectGuid]

),

ranked as (
SELECT projectname, contractedamount
DENSE_RANK() OVER(ORDER BY ABS([AverageContractedAmount]-contractedamount)) AS dr
FROM getavg)

SELECT * FROM ranked
WHERE dr <= 5
0 голосов
/ 12 сентября 2018

Не задумываясь об этом, вы можете просто свалить это в подзапрос и вычесть, отсортировать по разнице и сохранить лучший результат:

SELECT TOP 1
    project_name,

FROM Project
ORDER BY Abs(ContractedAmount - 
        (
            SELECT
            AVG([DC].[ContractedAmount]) AS [AverageContractedAmount]
             FROM [DesignCustomer] AS [DC]
                             INNER JOIN [Design] AS [D] ON [DC].[DesignKey] = [D].[DesignKey]
                             INNER JOIN [Task] AS [T] ON [D].[DesignKey] = [t].[DesignKey]
                             INNER JOIN [ProjectDesign] AS [PD] ON [D].[DesignKey] = [PD].[DesignKey]
                             INNER JOIN [Project] AS [P] ON [PD].[ProjectKey] = [P].[ProjectKey]
                             INNER JOIN [Address] AS [A] ON [A].[AddressGuid] = [P].[ProjectGuid]
        )) ASC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...