Строки группы SQL по Top 3 и другие. (Выручка по тройке городов по штатам, а затем по другим) - PullRequest
0 голосов
/ 01 июля 2019

поэтому у меня есть запрос, в котором указывается каждый мой город, соответствующий штат и стоимость, которую мои клиенты потратили в этом городе.

Я бы хотел определить топ-3 по TotalCustomerValue для каждого города.

Запрос немного сложнее, но суть его:

    SELECT DISTINCT
    --*
    LTRIM(RTRIM(cs.City)) City
    ,LTRIM(RTRIM(cs.State)) State

    ,SUM(cs.TotalCustomerValueOverBase) over (partition by  cs.City, cs.State) TotalCustomerValue
    ,SUM(cs.TotalOrdersBase) over (partition by  cs.City, cs.State) TotalOrders

    FROM ( -- This table gives full customer information per customer.
    )CSS

То, что я хочу сделать, - это создать таблицу, в которой будут находиться 3 верхние города каждого штата, а затем другая строка (которая будет обрабатываться как любая другая строка), которая будет суммой всех других городов. Таким образом, общая таблица будет иметь 200 строк (50 * 4).

Я пытаюсь что-то сделать с номером строки, но я не могу сработать

        ,ROW_NUMBER() over (partition by  cs.City, cs.State Order by sum(CS.TotalCustomerValueOverBase)) rowNr

Тогда я мог бы попытаться сложить все числа больше 3.

У кого-нибудь есть идеи?

А затем я предполагаю, что SSRS, когда я хочу создать визуалы с этими данными, я могу просто создать как фильтр для всех строк с ключевым словом Other, верно?

Вот мой полный запрос (с попыткой реализовать решение Гордона)

SELECT 
(case when CSS.seqnum <= 3 then city else 'Others' end) as city,
(case when seqnum <= 3 then state end) as state
sum(TotalCustomerValue) as TotalCustomerValue,
sum(TotalOrders) as TotalOrders

FROM
(
    SELECT DISTINCT
    --*
    LTRIM(RTRIM(cs.City)) City
    ,LTRIM(RTRIM(cs.State)) State

    ,right(left(lat, len(lat) -1),len(lat) -2) lat -- the lat and long are wrapped in quotes
    ,right(left(lng, len(lng) -1),len(lng) -2) lng -- so i have to do the left right to get rid of them. 

    ,SUM(cs.TotalCustomerValueOverBase) over (partition by  cs.City, cs.State) TotalCustomerValue
    ,SUM(cs.TotalOrdersBase) over (partition by  cs.City, cs.State) TotalOrders
    --,SUM(cs.TotalQuantityOverBase) over (partition by  cs.City, cs.State) TotalQuantity

    ,CONVERT(float, right(left(population_proper, len(population_proper) -1),len(population_proper) -2)) population_proper

    ,CAST(
        SUM(cs.TotalOrdersBase) over (partition by  cs.City, cs.State) 
        /
        NULLIF(convert(float, right(left(population_proper, len(population_proper) -1),len(population_proper) -2)),0)--*100 
    as decimal(10,4)) AS OrderDensityPercent

    ,SUM(cs.BrandNewCustomer) over (partition by     cs.City, cs.State) BrandNewCustomers
    ,SUM(cs.RecurringCustomer) over (partition by    cs.City, cs.State) RecurringCustomers
    ,SUM(cs.ReactivatedCustomer) over (partition by  cs.City, cs.State) ReactivatedCustomers

    ,row_number() over (partition by ltrim(rtrim(cs.State)) order by sum(cs.TotalCustomerValueOverBase) desc) as seqnum

    FROM ( -- This table gives full customer information per customer.
        SELECT 
        CC.CustomerEmail
        ,CC.Month Month
        ,CONCAT(CC.Year, '-', CASE WHEN CC.Month < 10 then '0' else '' end, CC.Month) Date


        ,CASE WHEN  
            (   ISNULL(CC.TotalOrdersCustomerBase,0) >= 1
            AND ISNULL(RC.TotalOrdersRecurringBase,0) = 0
            AND ISNULL(LC.TotalOrdersLifetimeBase,0) = 0) 
        THEN 1 ELSE 0 END BrandNewCustomer

        ,CASE WHEN  
            (   ISNULL(CC.TotalOrdersCustomerBase,0)  >= 1 
            AND ISNULL(RC.TotalOrdersRecurringBase,0) >= 1)
        THEN 1 ELSE 0 END RecurringCustomer

        ,CASE WHEN  
            (   ISNULL(CC.TotalOrdersCustomerBase,0) >= 1 
            AND ISNULL(RC.TotalOrdersRecurringBase,0) = 0
            AND ISNULL(LC.TotalOrdersLifetimeBase,0) >= 1) 
        THEN 1 ELSE 0 END ReactivatedCustomer

        ,ISNULL(CC.TotalCustomerValueOverCustomerBase,0) TotalCustomerValueOverCustomerBase
        ,ISNULL(CC.TotalOrdersCustomerBase,0) TotalOrdersCustomerBase
        ,ISNULL(CC.TotalQuantityOverCustomerBase,0) TotalQuantityOverCustomerBase

        ,ISNULL(RC.TotalCustomerValueOverRecurringBase,0) TotalCustomerValueOverRecurringBase
        ,ISNULL(RC.TotalOrdersRecurringBase,0) TotalOrdersRecurringBase
        ,ISNULL(RC.TotalQuantityOverRecurringBase,0) TotalQuantityOverRecurringBase

        ,ISNULL(LC.TotalCustomerValueOverLifetimeBase,0) TotalCustomerValueOverLifetimeBase
        ,ISNULL(LC.TotalOrdersLifetimeBase,0) TotalOrdersLifetimeBase
        ,ISNULL(LC.TotalQuantityOverLifetimeBase,0) TotalQuantityOverLifetimeBase

        ,ISNULL(FC.TotalCustomerValueOverBase,0) TotalCustomerValueOverBase
        ,ISNULL(FC.TotalOrdersBase,0) TotalOrdersBase
        ,ISNULL(FC.TotalQuantityOverBase,0) TotalQuantityOverBase

        ,ISNULL(CC.TotalCustomersOverCustomerBase,0) TotalCustomersOverCustomerBase
        ,ISNULL(RC.TotalCustomersOverRecurringBase,0) TotalCustomersOverRecurringBase
        ,ISNULL(LC.TotalCustomersOverLifetimeBase,0) TotalCustomersOverLifetimeBase
        ,ISNULL(FC.TotalCustomersOverBase,0) TotalCustomersOverBase

        ,CC.City
        ,CC.State
        ,CC.CountryCode

        From
        (
            SELECT 
            C.CustomerEmail
            ,C.Month
            ,C.Year
            ,C.TotalCustomersOverCustomerBase
            ,C.TotalCustomerValueOverCustomerBase
            ,C.TotalOrdersCustomerBase
            ,C.TotalQuantityOverCustomerBase
            ,C.City
            ,C.State
            ,C.CountryCode
            FROM
            #CustomerBase C
            WHERE C.OrderCountCustomerBase = 1 -- This makes it return only the first row of a customer with multiple purchases.
            --and  TotalOrdersCustomerBase = TotalQuantityOverCustomerBase 
        ) CC

        LEFT JOIN 
        (
            SELECT
            R.CustomerEmail
            ,R.TotalCustomersOverRecurringBase
            ,R.TotalCustomerValueOverRecurringBase
            ,R.TotalOrdersRecurringBase
            ,R.TotalQuantityOverRecurringBase
            FROM
            #RecurringBase R
            WHERE R.OrderCountRecurringBase = 1
        ) RC ON CC.CustomerEmail = RC.CustomerEmail

        LEFT JOIN 
        (
            SELECT 
            L.CustomerEmail
            ,L.TotalCustomersOverLifetimeBase
            ,L.TotalCustomerValueOverLifetimeBase
            ,L.TotalOrdersLifetimeBase
            ,L.TotalQuantityOverLifetimeBase
            FROM
            #LifetimeBase L
            WHERE L.OrderCountLifetimeBase = 1
        ) LC ON CC.CustomerEmail = LC.CustomerEmail

        LEFT JOIN 
        (
            SELECT 
            F.CustomerEmail
            ,F.TotalCustomersOverBase
            ,F.TotalCustomerValueOverBase
            ,F.TotalOrdersBase
            ,F.TotalQuantityOverBase
            FROM
            #FullBase F
            WHERE F.OrderCountBase = 1
        ) FC ON CC.CustomerEmail = FC.CustomerEmail

    ) Cs --Customers

    LEFT JOIN [A1Warehouse].[dbo].[uscities] Ci ON cs.City = right(left(ci.city_ascii, len(ci.city_ascii) -1),len(ci.city_ascii) -2) and cs.State = right(left(ci.state_id, len(ci.state_id) -1),len(ci.state_id) -2)

    WHERE 
    LAT IS NOT NULL 
    AND LNG IS NOT NULL

    group by ltrim(rtrim(cs.City)), ltrim(rtrim(cs.State))


)CSS


Where CAST(CSS.LAT AS FLOAT) > 20 AND CAST(CSS.LNG AS FLOAT) > -120

group by (case when seqnum <= 3 then city else 'Others' end),
(case when seqnum <= 3 then state end)

ORDER BY TotalCustomerValue DESC

1 Ответ

0 голосов
/ 01 июля 2019

Вы можете использовать два уровня агрегации и некоторую условную логику:

select (case when seqnum <= 3 then city else 'Others' end) as city,
       state,
       sum(TotalCustomerValue) as TotalCustomerValue,
       sum(TotalOrders) as TotalOrders
from (select ltrim(rtrim(cs.City)) as City, ltrim(rtrim(cs.State)) as State,
             sum(cs.TotalCustomerValueOverBase) as TotalCustomerValue,
             sum(cs.TotalOrdersBase) as TotalOrders,
             row_number() over (partition by ltrim(rtrim(cs.State)) order by sum(cs.TotalCustomerValueOverBase) desc) as seqnum
      from . . . cs
      group by ltrim(rtrim(cs.City)), ltrim(rtrim(cs.State))
     ) cs
group by (case when seqnum <= 3 then city else 'Others' end),
         (case when seqnum <= 3 then state end)

EDIT:

На основании комментария вы можете сделать:

select (case when seqnum <= 3 then city else 'Others' end) as city,
       (case when seqnum <= 3 then state end) as state,
       sum(TotalCustomerValue) as TotalCustomerValue,
       sum(TotalOrders) as TotalOrders
from (select ltrim(rtrim(cs.City)) as City, ltrim(rtrim(cs.State)) as State,
             sum(cs.TotalCustomerValueOverBase) as TotalCustomerValue,
             sum(cs.TotalOrdersBase) as TotalOrders,
             row_number() over (partition by ltrim(rtrim(cs.State)) order by sum(cs.TotalCustomerValueOverBase) desc) as seqnum
      from . . . cs
      group by ltrim(rtrim(cs.City)), ltrim(rtrim(cs.State))
     ) cs
group by (case when seqnum <= 3 then city else 'Others' end),
         state
...