首页 > 解决方案 > SQL按频率对ypositions进行分组

问题描述

我正在升级一个建模系统,并且模型在节点之间绘制矩形的三个边时遇到问题,而不是直线。我已经确定我可以通过将 yposition 更新为全部在一条线上来解决这个问题,并且软件将正确地重新绘制模型。但是两条平行线之间的距离可能因模型而异。如果在下面的 SQL 中我将范围变大,我将下一行的项目带到这一行。如果我把它做得太小,我不会把这条线上的所有物品都放在一条线上。所以我需要一种方法来自动找到 yposition 的分组。

例如,在大多数情况下,我可以运行以下代码来改善情况

update hewlett_22.gm_object_point t1
     set t1.yposition = (select case
           when yposition between -500 and -401 then -450 
           when yposition between -400 and -301 then -350 
           when yposition between -300 and -201 then -250 
           when yposition between -200 and -101 then -150 
           when yposition between -100 and -1 then -50
           when yposition = 0  then 0            
           when yposition between 1 and 100 then 50 
           when yposition between 101 and 200 then 150
           when yposition between 201 and 300 then 250
           when yposition between 301 and 400 then 350
           when yposition between 401 and 500 then 450
           when yposition between 501 and 600 then 550
           else yposition
         end as row_group 
    from hewlett_22.gm_object_point op  
    where op.csmver = (select max(csmver) from hewlett_22.gm_object_point op2 where op2.CSMMRID = op.CSMMRID)
       and op.CSMMRID = t1.CSMMRID
       and op.sequencenumber = t1.sequencenumber)

但是在某些模型中,我的范围太大而在其他模型中太小。如果我确定一个 ypositions 聚集在 50 范围内的图表(当 yposition 介于 1 和 50 之间,然后是 25)并更新 case ... between 以具有更窄的范围,这些模型是好的。如果我再采用另一个模型并将范围增加到 200(当 yposition 在 1 到 200 之间时,则为 100)这些模型很好。

我相信,如果我对数学有更多的了解,我可以编写一个在其范围内更具动态性的查询,但我做不到。有人可以提供如何重写它的建议吗?

E.g. model 1

              |---|
X--|    |--X--|   |--X
   |----|

X--|  |--X
   |--|

Model 2

X--|    |--X--|     |--
   |    |     |--X--|
   |----|

X--X--|  |--X--|
      |--|     |     |--X
               |--X--|

在这两种情况下,想法都是在一行中结束所有元素,例如上面的列表行。

X--X--------X----X----X

标签: sqloraclemath

解决方案


为了概括您的 CASE 语句,您似乎想要使用

set t1.yposition = (TRUNC(ABS(YPOSITION)-1, -2) + 50) * SIGN(YPOSITION)

更一般的形式是

WITH cteInterval_width AS (SELECT 25 AS INTERVAL_WIDTH FROM DUAL),
     cteConstants AS (SELECT INTERVAL_WIDTH,
                             100 / INTERVAL_WIDTH AS INTERVAL_DIVISOR
                        FROM cteInterval_width),
     ctePositions AS (SELECT LEVEL AS LVL,
                             DBMS_RANDOM.VALUE(-1000, 1000) AS YPOSITION FROM DUAL
                        CONNECT BY LEVEL <= 25)
SELECT LVL,
       YPOSITION,
       (TRUNC(ABS(YPOSITION*INTERVAL_DIVISOR)-1, -2)/INTERVAL_DIVISOR) AS TRUNC_TO_WIDTH,
       ((TRUNC(ABS(YPOSITION*INTERVAL_DIVISOR)-1, -2)/INTERVAL_DIVISOR) + (INTERVAL_WIDTH/2)) * SIGN(YPOSITION) AS HALF_INTERVAL
  FROM ctePositions
  CROSS JOIN cteConstants

在这里,您唯一需要更改的是INTERVAL_WIDTH第一个公用表表达式中的值,其他所有内容都由此确定。

dbfiddle在这里


推荐阅读