Home > database >  SQL: how to get counts from two groups that falls into one set of ranges
SQL: how to get counts from two groups that falls into one set of ranges

Time:09-07

I have been struggling on how I can achieve the below output:

Background: Range is the number of items within ProductA and ProductB. They both have two different number of items. ProductA usually falls into different range category then ProductB. I need to get one range for ProductA and ProductB.

ProductA ProductB Ranges
14 16 0-10
45 40 10-20
16 18 20-30
23 1 30-40
4 5 40-50
34 67 50-60
4 12 60-70
5 7 70-80
44 56 80-90
5 7 90-100

Table should be read as : e.g. ProductA has 34 number of items and falls into range 30-40, but ProductB (67 number of items) falls into different range in this case 60-70.

Here is the code - I need to find a way to get one range category(currently I have two separately: for ProductA and ProductB) that will be assigned for ProductA and ProductB and will give me one range for both:

WITH ProductA AS (
    select
        distinct m.ProductA as product_count_A,
        case
            when utilizationA <= 10 THEN '0-10'
            when utilizationA <= 20
            AND utilizationA > 10 THEN '10-20'
            when utilizationA <= 30
            AND utilizationA > 20 THEN '20-30'
            when utilizationA <= 40
            AND utilizationA > 30 THEN '30-40'
            when utilizationA <= 50
            AND utilizationA > 40 THEN '40-50'
            when utilizationA <= 60
            AND utilizationA > 50 THEN '50-60'
            when utilizationA <= 70
            AND utilizationA > 60 THEN '60-70'
            when utilizationA <= 80
            AND utilizationA > 70 THEN '70-80'
            when utilizationA <= 90
            AND utilizationA > 80 THEN '80-90'
            when utilizationA <= 100
            AND utilizationA > 90 THEN '90-100'
        END "UtilizationA"
    from
        PRODUCTS_TABLE
),
ProductB AS (
    Select
        distinct ProductB as product_count_B,
        CASE
            when utilizationB <= 10 THEN '0-10'
            when utilizationB <= 20
            AND utilizationB > 10 THEN '10-20'
            when utilizationB <= 30
            AND utilizationB > 20 THEN '20-30'
            when utilizationB <= 40
            AND utilizationB > 30 THEN '30-40'
            when utilizationB <= 50
            AND utilizationB > 40 THEN '40-50'
            when utilizationB <= 60
            AND utilizationB > 50 THEN '50-60'
            when utilizationB <= 70
            AND utilizationB > 60 THEN '60-70'
            when utilizationB <= 80
            AND utilizationB > 70 THEN '70-80'
            when utilizationB <= 90
            AND utilizationB > 80 THEN '80-90'
            when utilizationB <= 100
            AND utilizationB > 90 THEN '90-100'
        END "UtilizationB"
    from
        PRODUCTS_TABLE
)
SELECT
    DISTINCT "UtilizationA",
    "UtilizationB",
    COUNT(ProductB.product_count_B) as ProductB_RES,
    COUNT(ProductA.product_count_A) as ProductA_RES
from
    ProductB,
    ProductA
GROUP BY
    "UtilizationA",
    "UtilizationB";

CodePudding user response:

UNPIVOT the columns to rows and convert the utilization to ranges and then PIVOT back from rows to columns:

SELECT a_product AS productA,
       b_product AS productB,
       utilization
FROM   (
  SELECT type,
         CASE
         WHEN utilization <= 10 THEN '0-10'
         WHEN utilization <= 20 THEN '10-20'
         WHEN utilization <= 30 THEN '20-30'
         WHEN utilization <= 40 THEN '30-40'
         WHEN utilization <= 50 THEN '40-50'
         WHEN utilization <= 60 THEN '50-60'
         WHEN utilization <= 70 THEN '60-70'
         WHEN utilization <= 80 THEN '70-80'
         WHEN utilization <= 90 THEN '80-90'
         ELSE '90-100'
         END AS utilization,
         product
  FROM   products_table
  UNPIVOT (
    (product, utilization) FOR type IN (
      (producta, utilizationa) AS 'A',
      (productb, utilizationb) AS 'B'
    )
  )
)
PIVOT (
  COUNT(DISTINCT product) AS product
  FOR type IN (
    'A' AS a,
    'B' AS b
  )
)

Which, for the sample data:

CREATE TABLE products_table(producta, utilizationa, productb, utilizationb) AS
SELECT 1,  1, 1,  1 FROM DUAL UNION ALL
SELECT 1, 11, 2,  1 FROM DUAL UNION ALL
SELECT 1, 21, 1, 11 FROM DUAL UNION ALL
SELECT 1, 31, 1, 21 FROM DUAL UNION ALL
SELECT 1, 41, 1, 21 FROM DUAL UNION ALL
SELECT 1, 51, 1, 51 FROM DUAL UNION ALL
SELECT 1, 61, 1, 71 FROM DUAL UNION ALL
SELECT 1, 71, 1, 81 FROM DUAL;

Outputs:

PRODUCTA PRODUCTB UTILIZATION
1 2 0-10
1 1 10-20
1 1 20-30
1 0 30-40
1 0 40-50
1 1 50-60
1 0 60-70
1 1 70-80
0 1 80-90

db<>fiddle here

CodePudding user response:

As I have some background on Business Intelligence this looks similarly to problem I sometimes had on my reports: we tried to merge cpu p95 with cpu_max utilization to count how many hosts are eligible to one group/range set by p95 and separate count, but the same grouping, for cpu_max in other column.

Here's my take on this: http://sqlfiddle.com/#!18/babfb/1/0

Simply I am preparing two sets of counts and their assignements to appropriate ranges to finally JOIN them by the rank on the resulting query.

  • Related