查询以根据设置的规则对指标进行分类

时间:2020-03-31 06:33:31

标签: sql sql-server

请考虑以下表格

Metric_Threshold 该表包含每个指标的阈值范围

+----------+--------------------+--------+---------+
| MetricId | Threshold_Category | Symbol | Values1 |
+----------+--------------------+--------+---------+
| Met1     | In SLA             | >      | 80      |
| Met1     | Mature             | >=     | 70      |
| Met1     | Satisfactory       | >=     | 60      |
| Met1     | Needs Improvement  | <      | 60      |
| Met2     | In SLA             | =      | Y       |
| Met2     | Out of SLA         | =      | N       |
| Met3     | Mature             | =      | 0       |
| Met3     | Needs Improvement  | =      | 1       |
| Met4     | In SLA             | >      | 80      |
| Met4     | Mature             | >=     | 70      |
| Met4     | Satisfactory       | <      | 60      |
| Met4     | Needs Improvement  | <      | 50      |
+----------+--------------------+--------+---------+

Metric_Report (该表包含每个月针对这些指标报告的值)。

+----------+----------------+---------------+
| MetricId | reporting_date | report_values |
+----------+----------------+---------------+
| Met1     | 2020-01-01     | 72.15         |
| Met2     | 2020-01-01     | Y             |
| Met3     | 2020-01-01     | 0             |
| Met1     | 2020-02-01     | 80            |
| Met2     | 2020-02-01     | Y             |
| Met3     | 2020-02-01     | 1             |
| Met1     | 2020-03-01     | 60            |
| Met2     | 2020-03-01     | Y             |
| Met3     | 2020-03-01     | 1             |
| Met4     | 2020-03-01     | 50            |
+----------+----------------+---------------+

我正在尝试获取一个视图/查询,以将metric_report值归类到相应的范围内。

预期输出

+----------+----------------+---------------+-------------------+
| MetricId | reporting_date | report_values |       Range       |
+----------+----------------+---------------+-------------------+
| Met1     | 2020-01-01     | 72.15         | Mature            |
| Met2     | 2020-01-01     | Y             | In SLA            |
| Met3     | 2020-01-01     | 0             | Mature            |
| Met1     | 2020-02-01     | 80            | Mature            |
| Met2     | 2020-02-01     | Y             | In SLA            |
| Met3     | 2020-02-01     | 1             | Needs Improvement |
| Met1     | 2020-03-01     | 60            | Needs Improvement |
| Met2     | 2020-03-01     | Y             | In SLA            |
| Met3     | 2020-03-01     | 1             | Mature            |
| Met4     | 2020-03-01     | 50            | Satisfactory      |
+----------+----------------+---------------+-------------------+

我面临的困难是我无法对每个指标的范围进行硬编码,因为这些值很可能会被用户修改

我可以使用动态sql来构造查询,然后将结果推送到临时表,然后按metric_report值显示类别

但是我想检查是否有一个选项可以在静态视图/查询本身中获取它。

更新的数据库小提琴链接 https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=43c39a4f88cd410f91e94f721ee7e75e

脚本

create table metric_threshold
                  (  metric_id varchar(10)
                  , threshold_category varchar(30)
                  , symbol varchar(50)
                  , values1 varchar(20)
                  )


insert into metric_threshold values('Met1','In SLA','>','80')
insert into metric_threshold values('Met1','Mature','>=','70')
insert into metric_threshold values('Met1','Satisfactory','>=','60')
insert into metric_threshold values('Met1','Needs Improvement','<','60')
insert into metric_threshold values('Met2','In SLA','=','Y')
insert into metric_threshold values('Met2','Out of SLA','=','N')
insert into metric_threshold values('Met3','Mature','=','0')
insert into metric_threshold values('Met3','Needs Improvement','=','1')
insert into metric_threshold values('Met4','In SLA','>','80');
insert into metric_threshold values('Met4','Mature','>=','70');
insert into metric_threshold values('Met4','Satisfactory','<','60');
insert into metric_threshold values('Met4','Needs Improvement','<','50');

create table metric_report
              (  metric_id varchar(10)
              , reporting_date date
              , report_values varchar(20)
              )           


insert into metric_report values('Met1','2020-01-01','72.15')
insert into metric_report values('Met2','2020-01-01','Y')
insert into metric_report values('Met3','2020-01-01','0')
insert into metric_report values('Met1','2020-02-01','80')
insert into metric_report values('Met2','2020-02-01','Y')
insert into metric_report values('Met3','2020-02-01','1')
insert into metric_report values('Met1','2020-03-01','60')
insert into metric_report values('Met2','2020-03-01','Y')
insert into metric_report values('Met3','2020-03-01','1')
insert into metric_report values('Met4','2020-03-01','50');

2 个答案:

答案 0 :(得分:1)

这是一种方法-可能不是最漂亮的方法,但是在不更改当前表结构的情况下似乎可以工作。正如我的评论中所提到的那样,这个想法是基于给定vor Met1的评价来评估“实际”阈值,并将所有其他度量作为“简单”标志来处理。可以根据需要进行调整:

WITH cteFlagsOnly AS(
SELECT metric_id, COUNT(DISTINCT symbol) cnt
  FROM metric_threshold
  WHERE symbol != N'='
  GROUP BY metric_id
),
cteNoRange AS(
  SELECT DISTINCT metric_id
    FROM metric_threshold
    WHERE TRY_CONVERT(decimal(19,4), values1) IS NULL
  UNION
  SELECT DISTINCT t.metric_id
    FROM metric_threshold t
    LEFT JOIN cteFlagsOnly f ON f.metric_id = t.metric_id
    WHERE f.metric_id IS NULL
),
cte AS(
SELECT t.*
      ,ROW_NUMBER() OVER (PARTITION BY t.metric_id ORDER BY values1 , CASE
                                                                             WHEN symbol = N'>' THEN 1
                                                                             WHEN symbol = N'>=' THEN 2
                                                                             WHEN symbol = N'=' THEN 3
                                                                             WHEN symbol = N'<=' THEN 4
                                                                             WHEN symbol = N'<' THEN 5
                                                                             ELSE 99
                                                                           END DESC) AS rn
  FROM metric_threshold t
  LEFT JOIN cteNoRange cn ON cn.metric_id = t.metric_id
  WHERE cn.metric_id IS NULL
),
cte2 AS(
SELECT *
      ,CAST(LAG(values1) OVER (PARTITION BY metric_id ORDER BY rn) AS DECIMAL(19,4)) AS valuesLag
      ,LAG(symbol) OVER (PARTITION BY metric_id ORDER BY rn) AS symbolLag
      ,CAST(LEAD(values1) OVER (PARTITION BY metric_id ORDER BY rn) AS DECIMAL(19,4)) AS valuesLead
      ,LEAD(symbol) OVER (PARTITION BY metric_id ORDER BY rn) AS symbolLead
  FROM cte c
),
cteThrashholds AS(
SELECT *
      ,CASE
         WHEN symbol IN (N'<', N'<=') THEN 0.0
         WHEN symbol = N'>' THEN CAST(values1 AS decimal(19,4)) + 0.000000001
         WHEN symbol = N'>=' THEN CAST(values1 AS decimal(19,4))
         ELSE NULL
       END AS ValFrom
      ,CASE
         WHEN symbol = N'<' THEN CAST(values1 AS decimal(19,4)) - 0.000000001
         WHEN symbol = N'<=' THEN CAST(values1 AS decimal(19,4))
         WHEN symbolLead = N'>=' THEN ISNULL(valuesLead - 0.000000001, 9999999.99)
         WHEN symbolLead = N'>' THEN ISNULL(valuesLead, 9999999.99)
         ELSE ISNULL(valuesLead, 9999999.99)
       END AS ValTo
  FROM cte2
)
SELECT mr.*, ct.threshold_category
  FROM metric_report mr
  LEFT JOIN cteNoRange cn ON cn.metric_id = mr.metric_id
  LEFT JOIN cteThrashholds ct ON ct.metric_id = mr.metric_id AND mr.report_values BETWEEN ct.ValFrom AND ct.ValTo
  WHERE cn.metric_id IS NULL
UNION ALL
SELECT mr.*, ct.threshold_category
  FROM metric_report mr
  INNER JOIN cteNoRange cn ON cn.metric_id = mr.metric_id
  LEFT JOIN metric_threshold ct ON ct.metric_id = mr.metric_id AND mr.report_values = ct.values1
ORDER BY mr.metric_ID

答案 1 :(得分:0)

enter image description here

请仔细阅读sql脚本。

SELECT metric_id, 
       reporting_date, 
       report_values, 
       range 
FROM   (SELECT mth.metric_id, 
               rpt.reporting_date, 
               rpt.report_values, 
               mth.threshold_category AS Range, 
               CASE mth.symbol 
                 WHEN '>' THEN 
                   CASE 
                     WHEN Isnumeric(rpt.report_values) <> 0 THEN 
                       CASE 
                         WHEN rpt.report_values > mth.values1 THEN 
                         rpt.report_values + '>=' + mth.values1 
                         ELSE 'N' 
                       END 
                     ELSE 'N' 
                   END 
                 WHEN '>=' THEN 
                   CASE 
                     WHEN Isnumeric(rpt.report_values) <> 0 THEN 
                       CASE 
                         WHEN rpt.report_values >= mth.values1 THEN 
                         rpt.report_values + '>=' + mth.values1 
                         ELSE 'N' 
                       END 
                     ELSE 'N' 
                   END 
                 WHEN '<' THEN 
                   CASE 
                     WHEN Isnumeric(rpt.report_values) <> 0 THEN 
                       CASE 
                         WHEN rpt.report_values < mth.values1 THEN 
                         rpt.report_values + '>=' + mth.values1 
                         ELSE 'N' 
                       END 
                     ELSE 'N' 
                   END 
                 WHEN '=' THEN 
                   CASE 
                     WHEN Isnumeric(rpt.report_values) <> 0 THEN 
                       CASE 
                         WHEN rpt.report_values = mth.values1 THEN 
                         rpt.report_values + '>=' + mth.values1 
                         ELSE 'N' 
                       END 
                     ELSE 'N' 
                   END  
               END  AS Valid 
        FROM   metric_threshold mth, 
               metric_report rpt) AS x 
WHERE  x.valid <> 'N'